src/share/classes/com/sun/tools/javac/tree/Pretty.java

Fri, 05 Oct 2012 14:35:24 +0100

author
mcimadamore
date
Fri, 05 Oct 2012 14:35:24 +0100
changeset 1348
573ceb23beeb
parent 1347
1408af4cd8b0
child 1357
c75be5bc5283
permissions
-rw-r--r--

7177385: Add attribution support for lambda expressions
Summary: Add support for function descriptor lookup, functional interface inference and lambda expression type-checking
Reviewed-by: jjg, dlsmith

     1 /*
     2  * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.tree;
    28 import java.io.*;
    29 import java.util.*;
    31 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    32 import com.sun.tools.javac.code.*;
    33 import com.sun.tools.javac.code.Symbol.*;
    34 import com.sun.tools.javac.parser.Tokens.Comment;
    35 import com.sun.tools.javac.tree.JCTree.*;
    36 import com.sun.tools.javac.util.*;
    37 import com.sun.tools.javac.util.List;
    38 import static com.sun.tools.javac.code.Flags.*;
    39 import static com.sun.tools.javac.code.Flags.ANNOTATION;
    40 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    42 /** Prints out a tree as an indented Java source program.
    43  *
    44  *  <p><b>This is NOT part of any supported API.
    45  *  If you write code that depends on this, you do so at your own risk.
    46  *  This code and its internal interfaces are subject to change or
    47  *  deletion without notice.</b>
    48  */
    49 public class Pretty extends JCTree.Visitor {
    51     public Pretty(Writer out, boolean sourceOutput) {
    52         this.out = out;
    53         this.sourceOutput = sourceOutput;
    54     }
    56     /** Set when we are producing source output.  If we're not
    57      *  producing source output, we can sometimes give more detail in
    58      *  the output even though that detail would not be valid java
    59      *  source.
    60      */
    61     private final boolean sourceOutput;
    63     /** The output stream on which trees are printed.
    64      */
    65     Writer out;
    67     /** Indentation width (can be reassigned from outside).
    68      */
    69     public int width = 4;
    71     /** The current left margin.
    72      */
    73     int lmargin = 0;
    75     /** The enclosing class name.
    76      */
    77     Name enclClassName;
    79     /** A table mapping trees to their documentation comments
    80      *  (can be null)
    81      */
    82     DocCommentTable docComments = null;
    84     /**
    85      * A string sequence to be used when Pretty output should be constrained
    86      * to fit into a given size
    87      */
    88     private final static String trimSequence = "[...]";
    90     /**
    91      * Max number of chars to be generated when output should fit into a single line
    92      */
    93     private final static int PREFERRED_LENGTH = 20;
    95     /** Align code to be indented to left margin.
    96      */
    97     void align() throws IOException {
    98         for (int i = 0; i < lmargin; i++) out.write(" ");
    99     }
   101     /** Increase left margin by indentation width.
   102      */
   103     void indent() {
   104         lmargin = lmargin + width;
   105     }
   107     /** Decrease left margin by indentation width.
   108      */
   109     void undent() {
   110         lmargin = lmargin - width;
   111     }
   113     /** Enter a new precedence level. Emit a `(' if new precedence level
   114      *  is less than precedence level so far.
   115      *  @param contextPrec    The precedence level in force so far.
   116      *  @param ownPrec        The new precedence level.
   117      */
   118     void open(int contextPrec, int ownPrec) throws IOException {
   119         if (ownPrec < contextPrec) out.write("(");
   120     }
   122     /** Leave precedence level. Emit a `(' if inner precedence level
   123      *  is less than precedence level we revert to.
   124      *  @param contextPrec    The precedence level we revert to.
   125      *  @param ownPrec        The inner precedence level.
   126      */
   127     void close(int contextPrec, int ownPrec) throws IOException {
   128         if (ownPrec < contextPrec) out.write(")");
   129     }
   131     /** Print string, replacing all non-ascii character with unicode escapes.
   132      */
   133     public void print(Object s) throws IOException {
   134         out.write(Convert.escapeUnicode(s.toString()));
   135     }
   137     /** Print new line.
   138      */
   139     public void println() throws IOException {
   140         out.write(lineSep);
   141     }
   143     public static String toSimpleString(JCTree tree) {
   144         return toSimpleString(tree, PREFERRED_LENGTH);
   145     }
   147     public static String toSimpleString(JCTree tree, int maxLength) {
   148         StringWriter s = new StringWriter();
   149         try {
   150             new Pretty(s, false).printExpr(tree);
   151         }
   152         catch (IOException e) {
   153             // should never happen, because StringWriter is defined
   154             // never to throw any IOExceptions
   155             throw new AssertionError(e);
   156         }
   157         //we need to (i) replace all line terminators with a space and (ii) remove
   158         //occurrences of 'missing' in the Pretty output (generated when types are missing)
   159         String res = s.toString().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", "");
   160         if (res.length() < maxLength) {
   161             return res;
   162         } else {
   163             int split = (maxLength - trimSequence.length()) * 2 / 3;
   164             return res.substring(0, split) + trimSequence + res.substring(split);
   165         }
   166     }
   168     String lineSep = System.getProperty("line.separator");
   170     /**************************************************************************
   171      * Traversal methods
   172      *************************************************************************/
   174     /** Exception to propogate IOException through visitXXX methods */
   175     private static class UncheckedIOException extends Error {
   176         static final long serialVersionUID = -4032692679158424751L;
   177         UncheckedIOException(IOException e) {
   178             super(e.getMessage(), e);
   179         }
   180     }
   182     /** Visitor argument: the current precedence level.
   183      */
   184     int prec;
   186     /** Visitor method: print expression tree.
   187      *  @param prec  The current precedence level.
   188      */
   189     public void printExpr(JCTree tree, int prec) throws IOException {
   190         int prevPrec = this.prec;
   191         try {
   192             this.prec = prec;
   193             if (tree == null) print("/*missing*/");
   194             else {
   195                 tree.accept(this);
   196             }
   197         } catch (UncheckedIOException ex) {
   198             IOException e = new IOException(ex.getMessage());
   199             e.initCause(ex);
   200             throw e;
   201         } finally {
   202             this.prec = prevPrec;
   203         }
   204     }
   206     /** Derived visitor method: print expression tree at minimum precedence level
   207      *  for expression.
   208      */
   209     public void printExpr(JCTree tree) throws IOException {
   210         printExpr(tree, TreeInfo.noPrec);
   211     }
   213     /** Derived visitor method: print statement tree.
   214      */
   215     public void printStat(JCTree tree) throws IOException {
   216         printExpr(tree, TreeInfo.notExpression);
   217     }
   219     /** Derived visitor method: print list of expression trees, separated by given string.
   220      *  @param sep the separator string
   221      */
   222     public <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException {
   223         if (trees.nonEmpty()) {
   224             printExpr(trees.head);
   225             for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) {
   226                 print(sep);
   227                 printExpr(l.head);
   228             }
   229         }
   230     }
   232     /** Derived visitor method: print list of expression trees, separated by commas.
   233      */
   234     public <T extends JCTree> void printExprs(List<T> trees) throws IOException {
   235         printExprs(trees, ", ");
   236     }
   238     /** Derived visitor method: print list of statements, each on a separate line.
   239      */
   240     public void printStats(List<? extends JCTree> trees) throws IOException {
   241         for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
   242             align();
   243             printStat(l.head);
   244             println();
   245         }
   246     }
   248     /** Print a set of modifiers.
   249      */
   250     public void printFlags(long flags) throws IOException {
   251         if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ ");
   252         print(TreeInfo.flagNames(flags));
   253         if ((flags & StandardFlags) != 0) print(" ");
   254         if ((flags & ANNOTATION) != 0) print("@");
   255     }
   257     public void printAnnotations(List<JCAnnotation> trees) throws IOException {
   258         for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
   259             printStat(l.head);
   260             println();
   261             align();
   262         }
   263     }
   265     /** Print documentation comment, if it exists
   266      *  @param tree    The tree for which a documentation comment should be printed.
   267      */
   268     public void printDocComment(JCTree tree) throws IOException {
   269         if (docComments != null) {
   270             String dc = docComments.getCommentText(tree);
   271             if (dc != null) {
   272                 print("/**"); println();
   273                 int pos = 0;
   274                 int endpos = lineEndPos(dc, pos);
   275                 while (pos < dc.length()) {
   276                     align();
   277                     print(" *");
   278                     if (pos < dc.length() && dc.charAt(pos) > ' ') print(" ");
   279                     print(dc.substring(pos, endpos)); println();
   280                     pos = endpos + 1;
   281                     endpos = lineEndPos(dc, pos);
   282                 }
   283                 align(); print(" */"); println();
   284                 align();
   285             }
   286         }
   287     }
   288 //where
   289     static int lineEndPos(String s, int start) {
   290         int pos = s.indexOf('\n', start);
   291         if (pos < 0) pos = s.length();
   292         return pos;
   293     }
   295     /** If type parameter list is non-empty, print it enclosed in
   296      *  {@literal "<...>"} brackets.
   297      */
   298     public void printTypeParameters(List<JCTypeParameter> trees) throws IOException {
   299         if (trees.nonEmpty()) {
   300             print("<");
   301             printExprs(trees);
   302             print(">");
   303         }
   304     }
   306     /** Print a block.
   307      */
   308     public void printBlock(List<? extends JCTree> stats) throws IOException {
   309         print("{");
   310         println();
   311         indent();
   312         printStats(stats);
   313         undent();
   314         align();
   315         print("}");
   316     }
   318     /** Print a block.
   319      */
   320     public void printEnumBody(List<JCTree> stats) throws IOException {
   321         print("{");
   322         println();
   323         indent();
   324         boolean first = true;
   325         for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
   326             if (isEnumerator(l.head)) {
   327                 if (!first) {
   328                     print(",");
   329                     println();
   330                 }
   331                 align();
   332                 printStat(l.head);
   333                 first = false;
   334             }
   335         }
   336         print(";");
   337         println();
   338         for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
   339             if (!isEnumerator(l.head)) {
   340                 align();
   341                 printStat(l.head);
   342                 println();
   343             }
   344         }
   345         undent();
   346         align();
   347         print("}");
   348     }
   350     /** Is the given tree an enumerator definition? */
   351     boolean isEnumerator(JCTree t) {
   352         return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0;
   353     }
   355     /** Print unit consisting of package clause and import statements in toplevel,
   356      *  followed by class definition. if class definition == null,
   357      *  print all definitions in toplevel.
   358      *  @param tree     The toplevel tree
   359      *  @param cdef     The class definition, which is assumed to be part of the
   360      *                  toplevel tree.
   361      */
   362     public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
   363         docComments = tree.docComments;
   364         printDocComment(tree);
   365         if (tree.pid != null) {
   366             print("package ");
   367             printExpr(tree.pid);
   368             print(";");
   369             println();
   370         }
   371         boolean firstImport = true;
   372         for (List<JCTree> l = tree.defs;
   373         l.nonEmpty() && (cdef == null || l.head.hasTag(IMPORT));
   374         l = l.tail) {
   375             if (l.head.hasTag(IMPORT)) {
   376                 JCImport imp = (JCImport)l.head;
   377                 Name name = TreeInfo.name(imp.qualid);
   378                 if (name == name.table.names.asterisk ||
   379                         cdef == null ||
   380                         isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
   381                     if (firstImport) {
   382                         firstImport = false;
   383                         println();
   384                     }
   385                     printStat(imp);
   386                 }
   387             } else {
   388                 printStat(l.head);
   389             }
   390         }
   391         if (cdef != null) {
   392             printStat(cdef);
   393             println();
   394         }
   395     }
   396     // where
   397     boolean isUsed(final Symbol t, JCTree cdef) {
   398         class UsedVisitor extends TreeScanner {
   399             public void scan(JCTree tree) {
   400                 if (tree!=null && !result) tree.accept(this);
   401             }
   402             boolean result = false;
   403             public void visitIdent(JCIdent tree) {
   404                 if (tree.sym == t) result = true;
   405             }
   406         }
   407         UsedVisitor v = new UsedVisitor();
   408         v.scan(cdef);
   409         return v.result;
   410     }
   412     /**************************************************************************
   413      * Visitor methods
   414      *************************************************************************/
   416     public void visitTopLevel(JCCompilationUnit tree) {
   417         try {
   418             printUnit(tree, null);
   419         } catch (IOException e) {
   420             throw new UncheckedIOException(e);
   421         }
   422     }
   424     public void visitImport(JCImport tree) {
   425         try {
   426             print("import ");
   427             if (tree.staticImport) print("static ");
   428             printExpr(tree.qualid);
   429             print(";");
   430             println();
   431         } catch (IOException e) {
   432             throw new UncheckedIOException(e);
   433         }
   434     }
   436     public void visitClassDef(JCClassDecl tree) {
   437         try {
   438             println(); align();
   439             printDocComment(tree);
   440             printAnnotations(tree.mods.annotations);
   441             printFlags(tree.mods.flags & ~INTERFACE);
   442             Name enclClassNamePrev = enclClassName;
   443             enclClassName = tree.name;
   444             if ((tree.mods.flags & INTERFACE) != 0) {
   445                 print("interface " + tree.name);
   446                 printTypeParameters(tree.typarams);
   447                 if (tree.implementing.nonEmpty()) {
   448                     print(" extends ");
   449                     printExprs(tree.implementing);
   450                 }
   451             } else {
   452                 if ((tree.mods.flags & ENUM) != 0)
   453                     print("enum " + tree.name);
   454                 else
   455                     print("class " + tree.name);
   456                 printTypeParameters(tree.typarams);
   457                 if (tree.extending != null) {
   458                     print(" extends ");
   459                     printExpr(tree.extending);
   460                 }
   461                 if (tree.implementing.nonEmpty()) {
   462                     print(" implements ");
   463                     printExprs(tree.implementing);
   464                 }
   465             }
   466             print(" ");
   467             if ((tree.mods.flags & ENUM) != 0) {
   468                 printEnumBody(tree.defs);
   469             } else {
   470                 printBlock(tree.defs);
   471             }
   472             enclClassName = enclClassNamePrev;
   473         } catch (IOException e) {
   474             throw new UncheckedIOException(e);
   475         }
   476     }
   478     public void visitMethodDef(JCMethodDecl tree) {
   479         try {
   480             // when producing source output, omit anonymous constructors
   481             if (tree.name == tree.name.table.names.init &&
   482                     enclClassName == null &&
   483                     sourceOutput) return;
   484             println(); align();
   485             printDocComment(tree);
   486             printExpr(tree.mods);
   487             printTypeParameters(tree.typarams);
   488             if (tree.name == tree.name.table.names.init) {
   489                 print(enclClassName != null ? enclClassName : tree.name);
   490             } else {
   491                 printExpr(tree.restype);
   492                 print(" " + tree.name);
   493             }
   494             print("(");
   495             printExprs(tree.params);
   496             print(")");
   497             if (tree.thrown.nonEmpty()) {
   498                 print(" throws ");
   499                 printExprs(tree.thrown);
   500             }
   501             if (tree.defaultValue != null) {
   502                 print(" default ");
   503                 printExpr(tree.defaultValue);
   504             }
   505             if (tree.body != null) {
   506                 print(" ");
   507                 printStat(tree.body);
   508             } else {
   509                 print(";");
   510             }
   511         } catch (IOException e) {
   512             throw new UncheckedIOException(e);
   513         }
   514     }
   516     public void visitVarDef(JCVariableDecl tree) {
   517         try {
   518             if (docComments != null && docComments.hasComment(tree)) {
   519                 println(); align();
   520             }
   521             printDocComment(tree);
   522             if ((tree.mods.flags & ENUM) != 0) {
   523                 print("/*public static final*/ ");
   524                 print(tree.name);
   525                 if (tree.init != null) {
   526                     if (sourceOutput && tree.init.hasTag(NEWCLASS)) {
   527                         print(" /*enum*/ ");
   528                         JCNewClass init = (JCNewClass) tree.init;
   529                         if (init.args != null && init.args.nonEmpty()) {
   530                             print("(");
   531                             print(init.args);
   532                             print(")");
   533                         }
   534                         if (init.def != null && init.def.defs != null) {
   535                             print(" ");
   536                             printBlock(init.def.defs);
   537                         }
   538                         return;
   539                     }
   540                     print(" /* = ");
   541                     printExpr(tree.init);
   542                     print(" */");
   543                 }
   544             } else {
   545                 printExpr(tree.mods);
   546                 if ((tree.mods.flags & VARARGS) != 0) {
   547                     printExpr(((JCArrayTypeTree) tree.vartype).elemtype);
   548                     print("... " + tree.name);
   549                 } else {
   550                     printExpr(tree.vartype);
   551                     print(" " + tree.name);
   552                 }
   553                 if (tree.init != null) {
   554                     print(" = ");
   555                     printExpr(tree.init);
   556                 }
   557                 if (prec == TreeInfo.notExpression) print(";");
   558             }
   559         } catch (IOException e) {
   560             throw new UncheckedIOException(e);
   561         }
   562     }
   564     public void visitSkip(JCSkip tree) {
   565         try {
   566             print(";");
   567         } catch (IOException e) {
   568             throw new UncheckedIOException(e);
   569         }
   570     }
   572     public void visitBlock(JCBlock tree) {
   573         try {
   574             printFlags(tree.flags);
   575             printBlock(tree.stats);
   576         } catch (IOException e) {
   577             throw new UncheckedIOException(e);
   578         }
   579     }
   581     public void visitDoLoop(JCDoWhileLoop tree) {
   582         try {
   583             print("do ");
   584             printStat(tree.body);
   585             align();
   586             print(" while ");
   587             if (tree.cond.hasTag(PARENS)) {
   588                 printExpr(tree.cond);
   589             } else {
   590                 print("(");
   591                 printExpr(tree.cond);
   592                 print(")");
   593             }
   594             print(";");
   595         } catch (IOException e) {
   596             throw new UncheckedIOException(e);
   597         }
   598     }
   600     public void visitWhileLoop(JCWhileLoop tree) {
   601         try {
   602             print("while ");
   603             if (tree.cond.hasTag(PARENS)) {
   604                 printExpr(tree.cond);
   605             } else {
   606                 print("(");
   607                 printExpr(tree.cond);
   608                 print(")");
   609             }
   610             print(" ");
   611             printStat(tree.body);
   612         } catch (IOException e) {
   613             throw new UncheckedIOException(e);
   614         }
   615     }
   617     public void visitForLoop(JCForLoop tree) {
   618         try {
   619             print("for (");
   620             if (tree.init.nonEmpty()) {
   621                 if (tree.init.head.hasTag(VARDEF)) {
   622                     printExpr(tree.init.head);
   623                     for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
   624                         JCVariableDecl vdef = (JCVariableDecl)l.head;
   625                         print(", " + vdef.name + " = ");
   626                         printExpr(vdef.init);
   627                     }
   628                 } else {
   629                     printExprs(tree.init);
   630                 }
   631             }
   632             print("; ");
   633             if (tree.cond != null) printExpr(tree.cond);
   634             print("; ");
   635             printExprs(tree.step);
   636             print(") ");
   637             printStat(tree.body);
   638         } catch (IOException e) {
   639             throw new UncheckedIOException(e);
   640         }
   641     }
   643     public void visitForeachLoop(JCEnhancedForLoop tree) {
   644         try {
   645             print("for (");
   646             printExpr(tree.var);
   647             print(" : ");
   648             printExpr(tree.expr);
   649             print(") ");
   650             printStat(tree.body);
   651         } catch (IOException e) {
   652             throw new UncheckedIOException(e);
   653         }
   654     }
   656     public void visitLabelled(JCLabeledStatement tree) {
   657         try {
   658             print(tree.label + ": ");
   659             printStat(tree.body);
   660         } catch (IOException e) {
   661             throw new UncheckedIOException(e);
   662         }
   663     }
   665     public void visitSwitch(JCSwitch tree) {
   666         try {
   667             print("switch ");
   668             if (tree.selector.hasTag(PARENS)) {
   669                 printExpr(tree.selector);
   670             } else {
   671                 print("(");
   672                 printExpr(tree.selector);
   673                 print(")");
   674             }
   675             print(" {");
   676             println();
   677             printStats(tree.cases);
   678             align();
   679             print("}");
   680         } catch (IOException e) {
   681             throw new UncheckedIOException(e);
   682         }
   683     }
   685     public void visitCase(JCCase tree) {
   686         try {
   687             if (tree.pat == null) {
   688                 print("default");
   689             } else {
   690                 print("case ");
   691                 printExpr(tree.pat);
   692             }
   693             print(": ");
   694             println();
   695             indent();
   696             printStats(tree.stats);
   697             undent();
   698             align();
   699         } catch (IOException e) {
   700             throw new UncheckedIOException(e);
   701         }
   702     }
   704     public void visitSynchronized(JCSynchronized tree) {
   705         try {
   706             print("synchronized ");
   707             if (tree.lock.hasTag(PARENS)) {
   708                 printExpr(tree.lock);
   709             } else {
   710                 print("(");
   711                 printExpr(tree.lock);
   712                 print(")");
   713             }
   714             print(" ");
   715             printStat(tree.body);
   716         } catch (IOException e) {
   717             throw new UncheckedIOException(e);
   718         }
   719     }
   721     public void visitTry(JCTry tree) {
   722         try {
   723             print("try ");
   724             if (tree.resources.nonEmpty()) {
   725                 print("(");
   726                 boolean first = true;
   727                 for (JCTree var : tree.resources) {
   728                     if (!first) {
   729                         println();
   730                         indent();
   731                     }
   732                     printStat(var);
   733                     first = false;
   734                 }
   735                 print(") ");
   736             }
   737             printStat(tree.body);
   738             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   739                 printStat(l.head);
   740             }
   741             if (tree.finalizer != null) {
   742                 print(" finally ");
   743                 printStat(tree.finalizer);
   744             }
   745         } catch (IOException e) {
   746             throw new UncheckedIOException(e);
   747         }
   748     }
   750     public void visitCatch(JCCatch tree) {
   751         try {
   752             print(" catch (");
   753             printExpr(tree.param);
   754             print(") ");
   755             printStat(tree.body);
   756         } catch (IOException e) {
   757             throw new UncheckedIOException(e);
   758         }
   759     }
   761     public void visitConditional(JCConditional tree) {
   762         try {
   763             open(prec, TreeInfo.condPrec);
   764             printExpr(tree.cond, TreeInfo.condPrec);
   765             print(" ? ");
   766             printExpr(tree.truepart, TreeInfo.condPrec);
   767             print(" : ");
   768             printExpr(tree.falsepart, TreeInfo.condPrec);
   769             close(prec, TreeInfo.condPrec);
   770         } catch (IOException e) {
   771             throw new UncheckedIOException(e);
   772         }
   773     }
   775     public void visitIf(JCIf tree) {
   776         try {
   777             print("if ");
   778             if (tree.cond.hasTag(PARENS)) {
   779                 printExpr(tree.cond);
   780             } else {
   781                 print("(");
   782                 printExpr(tree.cond);
   783                 print(")");
   784             }
   785             print(" ");
   786             printStat(tree.thenpart);
   787             if (tree.elsepart != null) {
   788                 print(" else ");
   789                 printStat(tree.elsepart);
   790             }
   791         } catch (IOException e) {
   792             throw new UncheckedIOException(e);
   793         }
   794     }
   796     public void visitExec(JCExpressionStatement tree) {
   797         try {
   798             printExpr(tree.expr);
   799             if (prec == TreeInfo.notExpression) print(";");
   800         } catch (IOException e) {
   801             throw new UncheckedIOException(e);
   802         }
   803     }
   805     public void visitBreak(JCBreak tree) {
   806         try {
   807             print("break");
   808             if (tree.label != null) print(" " + tree.label);
   809             print(";");
   810         } catch (IOException e) {
   811             throw new UncheckedIOException(e);
   812         }
   813     }
   815     public void visitContinue(JCContinue tree) {
   816         try {
   817             print("continue");
   818             if (tree.label != null) print(" " + tree.label);
   819             print(";");
   820         } catch (IOException e) {
   821             throw new UncheckedIOException(e);
   822         }
   823     }
   825     public void visitReturn(JCReturn tree) {
   826         try {
   827             print("return");
   828             if (tree.expr != null) {
   829                 print(" ");
   830                 printExpr(tree.expr);
   831             }
   832             print(";");
   833         } catch (IOException e) {
   834             throw new UncheckedIOException(e);
   835         }
   836     }
   838     public void visitThrow(JCThrow tree) {
   839         try {
   840             print("throw ");
   841             printExpr(tree.expr);
   842             print(";");
   843         } catch (IOException e) {
   844             throw new UncheckedIOException(e);
   845         }
   846     }
   848     public void visitAssert(JCAssert tree) {
   849         try {
   850             print("assert ");
   851             printExpr(tree.cond);
   852             if (tree.detail != null) {
   853                 print(" : ");
   854                 printExpr(tree.detail);
   855             }
   856             print(";");
   857         } catch (IOException e) {
   858             throw new UncheckedIOException(e);
   859         }
   860     }
   862     public void visitApply(JCMethodInvocation tree) {
   863         try {
   864             if (!tree.typeargs.isEmpty()) {
   865                 if (tree.meth.hasTag(SELECT)) {
   866                     JCFieldAccess left = (JCFieldAccess)tree.meth;
   867                     printExpr(left.selected);
   868                     print(".<");
   869                     printExprs(tree.typeargs);
   870                     print(">" + left.name);
   871                 } else {
   872                     print("<");
   873                     printExprs(tree.typeargs);
   874                     print(">");
   875                     printExpr(tree.meth);
   876                 }
   877             } else {
   878                 printExpr(tree.meth);
   879             }
   880             print("(");
   881             printExprs(tree.args);
   882             print(")");
   883         } catch (IOException e) {
   884             throw new UncheckedIOException(e);
   885         }
   886     }
   888     public void visitNewClass(JCNewClass tree) {
   889         try {
   890             if (tree.encl != null) {
   891                 printExpr(tree.encl);
   892                 print(".");
   893             }
   894             print("new ");
   895             if (!tree.typeargs.isEmpty()) {
   896                 print("<");
   897                 printExprs(tree.typeargs);
   898                 print(">");
   899             }
   900             printExpr(tree.clazz);
   901             print("(");
   902             printExprs(tree.args);
   903             print(")");
   904             if (tree.def != null) {
   905                 Name enclClassNamePrev = enclClassName;
   906                 enclClassName =
   907                         tree.def.name != null ? tree.def.name :
   908                             tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty
   909                                 ? tree.type.tsym.name : null;
   910                 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
   911                 printBlock(tree.def.defs);
   912                 enclClassName = enclClassNamePrev;
   913             }
   914         } catch (IOException e) {
   915             throw new UncheckedIOException(e);
   916         }
   917     }
   919     public void visitNewArray(JCNewArray tree) {
   920         try {
   921             if (tree.elemtype != null) {
   922                 print("new ");
   923                 JCTree elem = tree.elemtype;
   924                 if (elem.hasTag(TYPEARRAY))
   925                     printBaseElementType((JCArrayTypeTree) elem);
   926                 else
   927                     printExpr(elem);
   928                 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
   929                     print("[");
   930                     printExpr(l.head);
   931                     print("]");
   932                 }
   933                 if (elem instanceof JCArrayTypeTree)
   934                     printBrackets((JCArrayTypeTree) elem);
   935             }
   936             if (tree.elems != null) {
   937                 if (tree.elemtype != null) print("[]");
   938                 print("{");
   939                 printExprs(tree.elems);
   940                 print("}");
   941             }
   942         } catch (IOException e) {
   943             throw new UncheckedIOException(e);
   944         }
   945     }
   947     public void visitLambda(JCLambda tree) {
   948         try {
   949             print("(");
   950             if (TreeInfo.isExplicitLambda(tree)) {
   951                 printExprs(tree.params);
   952             } else {
   953                 String sep = "";
   954                 for (JCVariableDecl param : tree.params) {
   955                     print(sep);
   956                     print(param.name);
   957                     sep = ",";
   958                 }
   959             }
   960             print(")->");
   961             printExpr(tree.body);
   962         } catch (IOException e) {
   963             throw new UncheckedIOException(e);
   964         }
   965     }
   967     public void visitParens(JCParens tree) {
   968         try {
   969             print("(");
   970             printExpr(tree.expr);
   971             print(")");
   972         } catch (IOException e) {
   973             throw new UncheckedIOException(e);
   974         }
   975     }
   977     public void visitAssign(JCAssign tree) {
   978         try {
   979             open(prec, TreeInfo.assignPrec);
   980             printExpr(tree.lhs, TreeInfo.assignPrec + 1);
   981             print(" = ");
   982             printExpr(tree.rhs, TreeInfo.assignPrec);
   983             close(prec, TreeInfo.assignPrec);
   984         } catch (IOException e) {
   985             throw new UncheckedIOException(e);
   986         }
   987     }
   989     public String operatorName(JCTree.Tag tag) {
   990         switch(tag) {
   991             case POS:     return "+";
   992             case NEG:     return "-";
   993             case NOT:     return "!";
   994             case COMPL:   return "~";
   995             case PREINC:  return "++";
   996             case PREDEC:  return "--";
   997             case POSTINC: return "++";
   998             case POSTDEC: return "--";
   999             case NULLCHK: return "<*nullchk*>";
  1000             case OR:      return "||";
  1001             case AND:     return "&&";
  1002             case EQ:      return "==";
  1003             case NE:      return "!=";
  1004             case LT:      return "<";
  1005             case GT:      return ">";
  1006             case LE:      return "<=";
  1007             case GE:      return ">=";
  1008             case BITOR:   return "|";
  1009             case BITXOR:  return "^";
  1010             case BITAND:  return "&";
  1011             case SL:      return "<<";
  1012             case SR:      return ">>";
  1013             case USR:     return ">>>";
  1014             case PLUS:    return "+";
  1015             case MINUS:   return "-";
  1016             case MUL:     return "*";
  1017             case DIV:     return "/";
  1018             case MOD:     return "%";
  1019             default: throw new Error();
  1023     public void visitAssignop(JCAssignOp tree) {
  1024         try {
  1025             open(prec, TreeInfo.assignopPrec);
  1026             printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
  1027             print(" " + operatorName(tree.getTag().noAssignOp()) + "= ");
  1028             printExpr(tree.rhs, TreeInfo.assignopPrec);
  1029             close(prec, TreeInfo.assignopPrec);
  1030         } catch (IOException e) {
  1031             throw new UncheckedIOException(e);
  1035     public void visitUnary(JCUnary tree) {
  1036         try {
  1037             int ownprec = TreeInfo.opPrec(tree.getTag());
  1038             String opname = operatorName(tree.getTag());
  1039             open(prec, ownprec);
  1040             if (!tree.getTag().isPostUnaryOp()) {
  1041                 print(opname);
  1042                 printExpr(tree.arg, ownprec);
  1043             } else {
  1044                 printExpr(tree.arg, ownprec);
  1045                 print(opname);
  1047             close(prec, ownprec);
  1048         } catch (IOException e) {
  1049             throw new UncheckedIOException(e);
  1053     public void visitBinary(JCBinary tree) {
  1054         try {
  1055             int ownprec = TreeInfo.opPrec(tree.getTag());
  1056             String opname = operatorName(tree.getTag());
  1057             open(prec, ownprec);
  1058             printExpr(tree.lhs, ownprec);
  1059             print(" " + opname + " ");
  1060             printExpr(tree.rhs, ownprec + 1);
  1061             close(prec, ownprec);
  1062         } catch (IOException e) {
  1063             throw new UncheckedIOException(e);
  1067     public void visitTypeCast(JCTypeCast tree) {
  1068         try {
  1069             open(prec, TreeInfo.prefixPrec);
  1070             print("(");
  1071             printExpr(tree.clazz);
  1072             print(")");
  1073             printExpr(tree.expr, TreeInfo.prefixPrec);
  1074             close(prec, TreeInfo.prefixPrec);
  1075         } catch (IOException e) {
  1076             throw new UncheckedIOException(e);
  1080     public void visitTypeTest(JCInstanceOf tree) {
  1081         try {
  1082             open(prec, TreeInfo.ordPrec);
  1083             printExpr(tree.expr, TreeInfo.ordPrec);
  1084             print(" instanceof ");
  1085             printExpr(tree.clazz, TreeInfo.ordPrec + 1);
  1086             close(prec, TreeInfo.ordPrec);
  1087         } catch (IOException e) {
  1088             throw new UncheckedIOException(e);
  1092     public void visitIndexed(JCArrayAccess tree) {
  1093         try {
  1094             printExpr(tree.indexed, TreeInfo.postfixPrec);
  1095             print("[");
  1096             printExpr(tree.index);
  1097             print("]");
  1098         } catch (IOException e) {
  1099             throw new UncheckedIOException(e);
  1103     public void visitSelect(JCFieldAccess tree) {
  1104         try {
  1105             printExpr(tree.selected, TreeInfo.postfixPrec);
  1106             print("." + tree.name);
  1107         } catch (IOException e) {
  1108             throw new UncheckedIOException(e);
  1112     public void visitReference(JCMemberReference tree) {
  1113         try {
  1114             printExpr(tree.expr);
  1115             print("#");
  1116             if (tree.typeargs != null) {
  1117                 print("<");
  1118                 printExprs(tree.typeargs);
  1119                 print(">");
  1121             print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
  1122         } catch (IOException e) {
  1123             throw new UncheckedIOException(e);
  1127     public void visitIdent(JCIdent tree) {
  1128         try {
  1129             print(tree.name);
  1130         } catch (IOException e) {
  1131             throw new UncheckedIOException(e);
  1135     public void visitLiteral(JCLiteral tree) {
  1136         try {
  1137             switch (tree.typetag) {
  1138                 case TypeTags.INT:
  1139                     print(tree.value.toString());
  1140                     break;
  1141                 case TypeTags.LONG:
  1142                     print(tree.value + "L");
  1143                     break;
  1144                 case TypeTags.FLOAT:
  1145                     print(tree.value + "F");
  1146                     break;
  1147                 case TypeTags.DOUBLE:
  1148                     print(tree.value.toString());
  1149                     break;
  1150                 case TypeTags.CHAR:
  1151                     print("\'" +
  1152                             Convert.quote(
  1153                             String.valueOf((char)((Number)tree.value).intValue())) +
  1154                             "\'");
  1155                     break;
  1156                 case TypeTags.BOOLEAN:
  1157                     print(((Number)tree.value).intValue() == 1 ? "true" : "false");
  1158                     break;
  1159                 case TypeTags.BOT:
  1160                     print("null");
  1161                     break;
  1162                 default:
  1163                     print("\"" + Convert.quote(tree.value.toString()) + "\"");
  1164                     break;
  1166         } catch (IOException e) {
  1167             throw new UncheckedIOException(e);
  1171     public void visitTypeIdent(JCPrimitiveTypeTree tree) {
  1172         try {
  1173             switch(tree.typetag) {
  1174                 case TypeTags.BYTE:
  1175                     print("byte");
  1176                     break;
  1177                 case TypeTags.CHAR:
  1178                     print("char");
  1179                     break;
  1180                 case TypeTags.SHORT:
  1181                     print("short");
  1182                     break;
  1183                 case TypeTags.INT:
  1184                     print("int");
  1185                     break;
  1186                 case TypeTags.LONG:
  1187                     print("long");
  1188                     break;
  1189                 case TypeTags.FLOAT:
  1190                     print("float");
  1191                     break;
  1192                 case TypeTags.DOUBLE:
  1193                     print("double");
  1194                     break;
  1195                 case TypeTags.BOOLEAN:
  1196                     print("boolean");
  1197                     break;
  1198                 case TypeTags.VOID:
  1199                     print("void");
  1200                     break;
  1201                 default:
  1202                     print("error");
  1203                     break;
  1205         } catch (IOException e) {
  1206             throw new UncheckedIOException(e);
  1210     public void visitTypeArray(JCArrayTypeTree tree) {
  1211         try {
  1212             printBaseElementType(tree);
  1213             printBrackets(tree);
  1214         } catch (IOException e) {
  1215             throw new UncheckedIOException(e);
  1219     // Prints the inner element type of a nested array
  1220     private void printBaseElementType(JCTree tree) throws IOException {
  1221         printExpr(TreeInfo.innermostType(tree));
  1224     // prints the brackets of a nested array in reverse order
  1225     private void printBrackets(JCArrayTypeTree tree) throws IOException {
  1226         JCTree elem;
  1227         while (true) {
  1228             elem = tree.elemtype;
  1229             print("[]");
  1230             if (!elem.hasTag(TYPEARRAY)) break;
  1231             tree = (JCArrayTypeTree) elem;
  1235     public void visitTypeApply(JCTypeApply tree) {
  1236         try {
  1237             printExpr(tree.clazz);
  1238             print("<");
  1239             printExprs(tree.arguments);
  1240             print(">");
  1241         } catch (IOException e) {
  1242             throw new UncheckedIOException(e);
  1246     public void visitTypeUnion(JCTypeUnion tree) {
  1247         try {
  1248             printExprs(tree.alternatives, " | ");
  1249         } catch (IOException e) {
  1250             throw new UncheckedIOException(e);
  1254     public void visitTypeParameter(JCTypeParameter tree) {
  1255         try {
  1256             print(tree.name);
  1257             if (tree.bounds.nonEmpty()) {
  1258                 print(" extends ");
  1259                 printExprs(tree.bounds, " & ");
  1261         } catch (IOException e) {
  1262             throw new UncheckedIOException(e);
  1266     @Override
  1267     public void visitWildcard(JCWildcard tree) {
  1268         try {
  1269             print(tree.kind);
  1270             if (tree.kind.kind != BoundKind.UNBOUND)
  1271                 printExpr(tree.inner);
  1272         } catch (IOException e) {
  1273             throw new UncheckedIOException(e);
  1277     @Override
  1278     public void visitTypeBoundKind(TypeBoundKind tree) {
  1279         try {
  1280             print(String.valueOf(tree.kind));
  1281         } catch (IOException e) {
  1282             throw new UncheckedIOException(e);
  1286     public void visitErroneous(JCErroneous tree) {
  1287         try {
  1288             print("(ERROR)");
  1289         } catch (IOException e) {
  1290             throw new UncheckedIOException(e);
  1294     public void visitLetExpr(LetExpr tree) {
  1295         try {
  1296             print("(let " + tree.defs + " in " + tree.expr + ")");
  1297         } catch (IOException e) {
  1298             throw new UncheckedIOException(e);
  1302     public void visitModifiers(JCModifiers mods) {
  1303         try {
  1304             printAnnotations(mods.annotations);
  1305             printFlags(mods.flags);
  1306         } catch (IOException e) {
  1307             throw new UncheckedIOException(e);
  1311     public void visitAnnotation(JCAnnotation tree) {
  1312         try {
  1313             print("@");
  1314             printExpr(tree.annotationType);
  1315             print("(");
  1316             printExprs(tree.args);
  1317             print(")");
  1318         } catch (IOException e) {
  1319             throw new UncheckedIOException(e);
  1323     public void visitTree(JCTree tree) {
  1324         try {
  1325             print("(UNKNOWN: " + tree + ")");
  1326             println();
  1327         } catch (IOException e) {
  1328             throw new UncheckedIOException(e);

mercurial