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

Thu, 24 Nov 2011 13:38:40 +0000

author
mcimadamore
date
Thu, 24 Nov 2011 13:38:40 +0000
changeset 1143
ec59a2ce9114
parent 1142
c896d95e7469
child 1280
5c0b3faeb0b0
permissions
-rw-r--r--

7115049: Add AST node for method references
Summary: Add tree nodes for representing method/constructor references and update relevant visitors interfaces
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1999, 2011, 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;
    33 import com.sun.tools.javac.util.*;
    34 import com.sun.tools.javac.util.List;
    35 import com.sun.tools.javac.code.*;
    37 import com.sun.tools.javac.code.Symbol.*;
    38 import com.sun.tools.javac.tree.JCTree.*;
    40 import static com.sun.tools.javac.code.Flags.*;
    41 import static com.sun.tools.javac.code.Flags.ANNOTATION;
    42 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    44 /** Prints out a tree as an indented Java source program.
    45  *
    46  *  <p><b>This is NOT part of any supported API.
    47  *  If you write code that depends on this, you do so at your own risk.
    48  *  This code and its internal interfaces are subject to change or
    49  *  deletion without notice.</b>
    50  */
    51 public class Pretty extends JCTree.Visitor {
    53     public Pretty(Writer out, boolean sourceOutput) {
    54         this.out = out;
    55         this.sourceOutput = sourceOutput;
    56     }
    58     /** Set when we are producing source output.  If we're not
    59      *  producing source output, we can sometimes give more detail in
    60      *  the output even though that detail would not be valid java
    61      *  source.
    62      */
    63     private final boolean sourceOutput;
    65     /** The output stream on which trees are printed.
    66      */
    67     Writer out;
    69     /** Indentation width (can be reassigned from outside).
    70      */
    71     public int width = 4;
    73     /** The current left margin.
    74      */
    75     int lmargin = 0;
    77     /** The enclosing class name.
    78      */
    79     Name enclClassName;
    81     /** A hashtable mapping trees to their documentation comments
    82      *  (can be null)
    83      */
    84     Map<JCTree, String> docComments = null;
    86     /** Align code to be indented to left margin.
    87      */
    88     void align() throws IOException {
    89         for (int i = 0; i < lmargin; i++) out.write(" ");
    90     }
    92     /** Increase left margin by indentation width.
    93      */
    94     void indent() {
    95         lmargin = lmargin + width;
    96     }
    98     /** Decrease left margin by indentation width.
    99      */
   100     void undent() {
   101         lmargin = lmargin - width;
   102     }
   104     /** Enter a new precedence level. Emit a `(' if new precedence level
   105      *  is less than precedence level so far.
   106      *  @param contextPrec    The precedence level in force so far.
   107      *  @param ownPrec        The new precedence level.
   108      */
   109     void open(int contextPrec, int ownPrec) throws IOException {
   110         if (ownPrec < contextPrec) out.write("(");
   111     }
   113     /** Leave precedence level. Emit a `(' if inner precedence level
   114      *  is less than precedence level we revert to.
   115      *  @param contextPrec    The precedence level we revert to.
   116      *  @param ownPrec        The inner precedence level.
   117      */
   118     void close(int contextPrec, int ownPrec) throws IOException {
   119         if (ownPrec < contextPrec) out.write(")");
   120     }
   122     /** Print string, replacing all non-ascii character with unicode escapes.
   123      */
   124     public void print(Object s) throws IOException {
   125         out.write(Convert.escapeUnicode(s.toString()));
   126     }
   128     /** Print new line.
   129      */
   130     public void println() throws IOException {
   131         out.write(lineSep);
   132     }
   134     String lineSep = System.getProperty("line.separator");
   136     /**************************************************************************
   137      * Traversal methods
   138      *************************************************************************/
   140     /** Exception to propogate IOException through visitXXX methods */
   141     private static class UncheckedIOException extends Error {
   142         static final long serialVersionUID = -4032692679158424751L;
   143         UncheckedIOException(IOException e) {
   144             super(e.getMessage(), e);
   145         }
   146     }
   148     /** Visitor argument: the current precedence level.
   149      */
   150     int prec;
   152     /** Visitor method: print expression tree.
   153      *  @param prec  The current precedence level.
   154      */
   155     public void printExpr(JCTree tree, int prec) throws IOException {
   156         int prevPrec = this.prec;
   157         try {
   158             this.prec = prec;
   159             if (tree == null) print("/*missing*/");
   160             else {
   161                 tree.accept(this);
   162             }
   163         } catch (UncheckedIOException ex) {
   164             IOException e = new IOException(ex.getMessage());
   165             e.initCause(ex);
   166             throw e;
   167         } finally {
   168             this.prec = prevPrec;
   169         }
   170     }
   172     /** Derived visitor method: print expression tree at minimum precedence level
   173      *  for expression.
   174      */
   175     public void printExpr(JCTree tree) throws IOException {
   176         printExpr(tree, TreeInfo.noPrec);
   177     }
   179     /** Derived visitor method: print statement tree.
   180      */
   181     public void printStat(JCTree tree) throws IOException {
   182         printExpr(tree, TreeInfo.notExpression);
   183     }
   185     /** Derived visitor method: print list of expression trees, separated by given string.
   186      *  @param sep the separator string
   187      */
   188     public <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException {
   189         if (trees.nonEmpty()) {
   190             printExpr(trees.head);
   191             for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) {
   192                 print(sep);
   193                 printExpr(l.head);
   194             }
   195         }
   196     }
   198     /** Derived visitor method: print list of expression trees, separated by commas.
   199      */
   200     public <T extends JCTree> void printExprs(List<T> trees) throws IOException {
   201         printExprs(trees, ", ");
   202     }
   204     /** Derived visitor method: print list of statements, each on a separate line.
   205      */
   206     public void printStats(List<? extends JCTree> trees) throws IOException {
   207         for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
   208             align();
   209             printStat(l.head);
   210             println();
   211         }
   212     }
   214     /** Print a set of modifiers.
   215      */
   216     public void printFlags(long flags) throws IOException {
   217         if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ ");
   218         print(TreeInfo.flagNames(flags));
   219         if ((flags & StandardFlags) != 0) print(" ");
   220         if ((flags & ANNOTATION) != 0) print("@");
   221     }
   223     public void printAnnotations(List<JCAnnotation> trees) throws IOException {
   224         for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
   225             printStat(l.head);
   226             println();
   227             align();
   228         }
   229     }
   231     /** Print documentation comment, if it exists
   232      *  @param tree    The tree for which a documentation comment should be printed.
   233      */
   234     public void printDocComment(JCTree tree) throws IOException {
   235         if (docComments != null) {
   236             String dc = docComments.get(tree);
   237             if (dc != null) {
   238                 print("/**"); println();
   239                 int pos = 0;
   240                 int endpos = lineEndPos(dc, pos);
   241                 while (pos < dc.length()) {
   242                     align();
   243                     print(" *");
   244                     if (pos < dc.length() && dc.charAt(pos) > ' ') print(" ");
   245                     print(dc.substring(pos, endpos)); println();
   246                     pos = endpos + 1;
   247                     endpos = lineEndPos(dc, pos);
   248                 }
   249                 align(); print(" */"); println();
   250                 align();
   251             }
   252         }
   253     }
   254 //where
   255     static int lineEndPos(String s, int start) {
   256         int pos = s.indexOf('\n', start);
   257         if (pos < 0) pos = s.length();
   258         return pos;
   259     }
   261     /** If type parameter list is non-empty, print it enclosed in "<...>" brackets.
   262      */
   263     public void printTypeParameters(List<JCTypeParameter> trees) throws IOException {
   264         if (trees.nonEmpty()) {
   265             print("<");
   266             printExprs(trees);
   267             print(">");
   268         }
   269     }
   271     /** Print a block.
   272      */
   273     public void printBlock(List<? extends JCTree> stats) throws IOException {
   274         print("{");
   275         println();
   276         indent();
   277         printStats(stats);
   278         undent();
   279         align();
   280         print("}");
   281     }
   283     /** Print a block.
   284      */
   285     public void printEnumBody(List<JCTree> stats) throws IOException {
   286         print("{");
   287         println();
   288         indent();
   289         boolean first = true;
   290         for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
   291             if (isEnumerator(l.head)) {
   292                 if (!first) {
   293                     print(",");
   294                     println();
   295                 }
   296                 align();
   297                 printStat(l.head);
   298                 first = false;
   299             }
   300         }
   301         print(";");
   302         println();
   303         for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
   304             if (!isEnumerator(l.head)) {
   305                 align();
   306                 printStat(l.head);
   307                 println();
   308             }
   309         }
   310         undent();
   311         align();
   312         print("}");
   313     }
   315     /** Is the given tree an enumerator definition? */
   316     boolean isEnumerator(JCTree t) {
   317         return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0;
   318     }
   320     /** Print unit consisting of package clause and import statements in toplevel,
   321      *  followed by class definition. if class definition == null,
   322      *  print all definitions in toplevel.
   323      *  @param tree     The toplevel tree
   324      *  @param cdef     The class definition, which is assumed to be part of the
   325      *                  toplevel tree.
   326      */
   327     public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
   328         docComments = tree.docComments;
   329         printDocComment(tree);
   330         if (tree.pid != null) {
   331             print("package ");
   332             printExpr(tree.pid);
   333             print(";");
   334             println();
   335         }
   336         boolean firstImport = true;
   337         for (List<JCTree> l = tree.defs;
   338         l.nonEmpty() && (cdef == null || l.head.hasTag(IMPORT));
   339         l = l.tail) {
   340             if (l.head.hasTag(IMPORT)) {
   341                 JCImport imp = (JCImport)l.head;
   342                 Name name = TreeInfo.name(imp.qualid);
   343                 if (name == name.table.names.asterisk ||
   344                         cdef == null ||
   345                         isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
   346                     if (firstImport) {
   347                         firstImport = false;
   348                         println();
   349                     }
   350                     printStat(imp);
   351                 }
   352             } else {
   353                 printStat(l.head);
   354             }
   355         }
   356         if (cdef != null) {
   357             printStat(cdef);
   358             println();
   359         }
   360     }
   361     // where
   362     boolean isUsed(final Symbol t, JCTree cdef) {
   363         class UsedVisitor extends TreeScanner {
   364             public void scan(JCTree tree) {
   365                 if (tree!=null && !result) tree.accept(this);
   366             }
   367             boolean result = false;
   368             public void visitIdent(JCIdent tree) {
   369                 if (tree.sym == t) result = true;
   370             }
   371         }
   372         UsedVisitor v = new UsedVisitor();
   373         v.scan(cdef);
   374         return v.result;
   375     }
   377     /**************************************************************************
   378      * Visitor methods
   379      *************************************************************************/
   381     public void visitTopLevel(JCCompilationUnit tree) {
   382         try {
   383             printUnit(tree, null);
   384         } catch (IOException e) {
   385             throw new UncheckedIOException(e);
   386         }
   387     }
   389     public void visitImport(JCImport tree) {
   390         try {
   391             print("import ");
   392             if (tree.staticImport) print("static ");
   393             printExpr(tree.qualid);
   394             print(";");
   395             println();
   396         } catch (IOException e) {
   397             throw new UncheckedIOException(e);
   398         }
   399     }
   401     public void visitClassDef(JCClassDecl tree) {
   402         try {
   403             println(); align();
   404             printDocComment(tree);
   405             printAnnotations(tree.mods.annotations);
   406             printFlags(tree.mods.flags & ~INTERFACE);
   407             Name enclClassNamePrev = enclClassName;
   408             enclClassName = tree.name;
   409             if ((tree.mods.flags & INTERFACE) != 0) {
   410                 print("interface " + tree.name);
   411                 printTypeParameters(tree.typarams);
   412                 if (tree.implementing.nonEmpty()) {
   413                     print(" extends ");
   414                     printExprs(tree.implementing);
   415                 }
   416             } else {
   417                 if ((tree.mods.flags & ENUM) != 0)
   418                     print("enum " + tree.name);
   419                 else
   420                     print("class " + tree.name);
   421                 printTypeParameters(tree.typarams);
   422                 if (tree.extending != null) {
   423                     print(" extends ");
   424                     printExpr(tree.extending);
   425                 }
   426                 if (tree.implementing.nonEmpty()) {
   427                     print(" implements ");
   428                     printExprs(tree.implementing);
   429                 }
   430             }
   431             print(" ");
   432             if ((tree.mods.flags & ENUM) != 0) {
   433                 printEnumBody(tree.defs);
   434             } else {
   435                 printBlock(tree.defs);
   436             }
   437             enclClassName = enclClassNamePrev;
   438         } catch (IOException e) {
   439             throw new UncheckedIOException(e);
   440         }
   441     }
   443     public void visitMethodDef(JCMethodDecl tree) {
   444         try {
   445             // when producing source output, omit anonymous constructors
   446             if (tree.name == tree.name.table.names.init &&
   447                     enclClassName == null &&
   448                     sourceOutput) return;
   449             println(); align();
   450             printDocComment(tree);
   451             printExpr(tree.mods);
   452             printTypeParameters(tree.typarams);
   453             if (tree.name == tree.name.table.names.init) {
   454                 print(enclClassName != null ? enclClassName : tree.name);
   455             } else {
   456                 printExpr(tree.restype);
   457                 print(" " + tree.name);
   458             }
   459             print("(");
   460             printExprs(tree.params);
   461             print(")");
   462             if (tree.thrown.nonEmpty()) {
   463                 print(" throws ");
   464                 printExprs(tree.thrown);
   465             }
   466             if (tree.defaultValue != null) {
   467                 print(" default ");
   468                 printExpr(tree.defaultValue);
   469             }
   470             if (tree.body != null) {
   471                 print(" ");
   472                 printStat(tree.body);
   473             } else {
   474                 print(";");
   475             }
   476         } catch (IOException e) {
   477             throw new UncheckedIOException(e);
   478         }
   479     }
   481     public void visitVarDef(JCVariableDecl tree) {
   482         try {
   483             if (docComments != null && docComments.get(tree) != null) {
   484                 println(); align();
   485             }
   486             printDocComment(tree);
   487             if ((tree.mods.flags & ENUM) != 0) {
   488                 print("/*public static final*/ ");
   489                 print(tree.name);
   490                 if (tree.init != null) {
   491                     if (sourceOutput && tree.init.hasTag(NEWCLASS)) {
   492                         print(" /*enum*/ ");
   493                         JCNewClass init = (JCNewClass) tree.init;
   494                         if (init.args != null && init.args.nonEmpty()) {
   495                             print("(");
   496                             print(init.args);
   497                             print(")");
   498                         }
   499                         if (init.def != null && init.def.defs != null) {
   500                             print(" ");
   501                             printBlock(init.def.defs);
   502                         }
   503                         return;
   504                     }
   505                     print(" /* = ");
   506                     printExpr(tree.init);
   507                     print(" */");
   508                 }
   509             } else {
   510                 printExpr(tree.mods);
   511                 if ((tree.mods.flags & VARARGS) != 0) {
   512                     printExpr(((JCArrayTypeTree) tree.vartype).elemtype);
   513                     print("... " + tree.name);
   514                 } else {
   515                     printExpr(tree.vartype);
   516                     print(" " + tree.name);
   517                 }
   518                 if (tree.init != null) {
   519                     print(" = ");
   520                     printExpr(tree.init);
   521                 }
   522                 if (prec == TreeInfo.notExpression) print(";");
   523             }
   524         } catch (IOException e) {
   525             throw new UncheckedIOException(e);
   526         }
   527     }
   529     public void visitSkip(JCSkip tree) {
   530         try {
   531             print(";");
   532         } catch (IOException e) {
   533             throw new UncheckedIOException(e);
   534         }
   535     }
   537     public void visitBlock(JCBlock tree) {
   538         try {
   539             printFlags(tree.flags);
   540             printBlock(tree.stats);
   541         } catch (IOException e) {
   542             throw new UncheckedIOException(e);
   543         }
   544     }
   546     public void visitDoLoop(JCDoWhileLoop tree) {
   547         try {
   548             print("do ");
   549             printStat(tree.body);
   550             align();
   551             print(" while ");
   552             if (tree.cond.hasTag(PARENS)) {
   553                 printExpr(tree.cond);
   554             } else {
   555                 print("(");
   556                 printExpr(tree.cond);
   557                 print(")");
   558             }
   559             print(";");
   560         } catch (IOException e) {
   561             throw new UncheckedIOException(e);
   562         }
   563     }
   565     public void visitWhileLoop(JCWhileLoop tree) {
   566         try {
   567             print("while ");
   568             if (tree.cond.hasTag(PARENS)) {
   569                 printExpr(tree.cond);
   570             } else {
   571                 print("(");
   572                 printExpr(tree.cond);
   573                 print(")");
   574             }
   575             print(" ");
   576             printStat(tree.body);
   577         } catch (IOException e) {
   578             throw new UncheckedIOException(e);
   579         }
   580     }
   582     public void visitForLoop(JCForLoop tree) {
   583         try {
   584             print("for (");
   585             if (tree.init.nonEmpty()) {
   586                 if (tree.init.head.hasTag(VARDEF)) {
   587                     printExpr(tree.init.head);
   588                     for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
   589                         JCVariableDecl vdef = (JCVariableDecl)l.head;
   590                         print(", " + vdef.name + " = ");
   591                         printExpr(vdef.init);
   592                     }
   593                 } else {
   594                     printExprs(tree.init);
   595                 }
   596             }
   597             print("; ");
   598             if (tree.cond != null) printExpr(tree.cond);
   599             print("; ");
   600             printExprs(tree.step);
   601             print(") ");
   602             printStat(tree.body);
   603         } catch (IOException e) {
   604             throw new UncheckedIOException(e);
   605         }
   606     }
   608     public void visitForeachLoop(JCEnhancedForLoop tree) {
   609         try {
   610             print("for (");
   611             printExpr(tree.var);
   612             print(" : ");
   613             printExpr(tree.expr);
   614             print(") ");
   615             printStat(tree.body);
   616         } catch (IOException e) {
   617             throw new UncheckedIOException(e);
   618         }
   619     }
   621     public void visitLabelled(JCLabeledStatement tree) {
   622         try {
   623             print(tree.label + ": ");
   624             printStat(tree.body);
   625         } catch (IOException e) {
   626             throw new UncheckedIOException(e);
   627         }
   628     }
   630     public void visitSwitch(JCSwitch tree) {
   631         try {
   632             print("switch ");
   633             if (tree.selector.hasTag(PARENS)) {
   634                 printExpr(tree.selector);
   635             } else {
   636                 print("(");
   637                 printExpr(tree.selector);
   638                 print(")");
   639             }
   640             print(" {");
   641             println();
   642             printStats(tree.cases);
   643             align();
   644             print("}");
   645         } catch (IOException e) {
   646             throw new UncheckedIOException(e);
   647         }
   648     }
   650     public void visitCase(JCCase tree) {
   651         try {
   652             if (tree.pat == null) {
   653                 print("default");
   654             } else {
   655                 print("case ");
   656                 printExpr(tree.pat);
   657             }
   658             print(": ");
   659             println();
   660             indent();
   661             printStats(tree.stats);
   662             undent();
   663             align();
   664         } catch (IOException e) {
   665             throw new UncheckedIOException(e);
   666         }
   667     }
   669     public void visitSynchronized(JCSynchronized tree) {
   670         try {
   671             print("synchronized ");
   672             if (tree.lock.hasTag(PARENS)) {
   673                 printExpr(tree.lock);
   674             } else {
   675                 print("(");
   676                 printExpr(tree.lock);
   677                 print(")");
   678             }
   679             print(" ");
   680             printStat(tree.body);
   681         } catch (IOException e) {
   682             throw new UncheckedIOException(e);
   683         }
   684     }
   686     public void visitTry(JCTry tree) {
   687         try {
   688             print("try ");
   689             if (tree.resources.nonEmpty()) {
   690                 print("(");
   691                 boolean first = true;
   692                 for (JCTree var : tree.resources) {
   693                     if (!first) {
   694                         println();
   695                         indent();
   696                     }
   697                     printStat(var);
   698                     first = false;
   699                 }
   700                 print(") ");
   701             }
   702             printStat(tree.body);
   703             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   704                 printStat(l.head);
   705             }
   706             if (tree.finalizer != null) {
   707                 print(" finally ");
   708                 printStat(tree.finalizer);
   709             }
   710         } catch (IOException e) {
   711             throw new UncheckedIOException(e);
   712         }
   713     }
   715     public void visitCatch(JCCatch tree) {
   716         try {
   717             print(" catch (");
   718             printExpr(tree.param);
   719             print(") ");
   720             printStat(tree.body);
   721         } catch (IOException e) {
   722             throw new UncheckedIOException(e);
   723         }
   724     }
   726     public void visitConditional(JCConditional tree) {
   727         try {
   728             open(prec, TreeInfo.condPrec);
   729             printExpr(tree.cond, TreeInfo.condPrec);
   730             print(" ? ");
   731             printExpr(tree.truepart, TreeInfo.condPrec);
   732             print(" : ");
   733             printExpr(tree.falsepart, TreeInfo.condPrec);
   734             close(prec, TreeInfo.condPrec);
   735         } catch (IOException e) {
   736             throw new UncheckedIOException(e);
   737         }
   738     }
   740     public void visitIf(JCIf tree) {
   741         try {
   742             print("if ");
   743             if (tree.cond.hasTag(PARENS)) {
   744                 printExpr(tree.cond);
   745             } else {
   746                 print("(");
   747                 printExpr(tree.cond);
   748                 print(")");
   749             }
   750             print(" ");
   751             printStat(tree.thenpart);
   752             if (tree.elsepart != null) {
   753                 print(" else ");
   754                 printStat(tree.elsepart);
   755             }
   756         } catch (IOException e) {
   757             throw new UncheckedIOException(e);
   758         }
   759     }
   761     public void visitExec(JCExpressionStatement tree) {
   762         try {
   763             printExpr(tree.expr);
   764             if (prec == TreeInfo.notExpression) print(";");
   765         } catch (IOException e) {
   766             throw new UncheckedIOException(e);
   767         }
   768     }
   770     public void visitBreak(JCBreak tree) {
   771         try {
   772             print("break");
   773             if (tree.label != null) print(" " + tree.label);
   774             print(";");
   775         } catch (IOException e) {
   776             throw new UncheckedIOException(e);
   777         }
   778     }
   780     public void visitContinue(JCContinue tree) {
   781         try {
   782             print("continue");
   783             if (tree.label != null) print(" " + tree.label);
   784             print(";");
   785         } catch (IOException e) {
   786             throw new UncheckedIOException(e);
   787         }
   788     }
   790     public void visitReturn(JCReturn tree) {
   791         try {
   792             print("return");
   793             if (tree.expr != null) {
   794                 print(" ");
   795                 printExpr(tree.expr);
   796             }
   797             print(";");
   798         } catch (IOException e) {
   799             throw new UncheckedIOException(e);
   800         }
   801     }
   803     public void visitThrow(JCThrow tree) {
   804         try {
   805             print("throw ");
   806             printExpr(tree.expr);
   807             print(";");
   808         } catch (IOException e) {
   809             throw new UncheckedIOException(e);
   810         }
   811     }
   813     public void visitAssert(JCAssert tree) {
   814         try {
   815             print("assert ");
   816             printExpr(tree.cond);
   817             if (tree.detail != null) {
   818                 print(" : ");
   819                 printExpr(tree.detail);
   820             }
   821             print(";");
   822         } catch (IOException e) {
   823             throw new UncheckedIOException(e);
   824         }
   825     }
   827     public void visitApply(JCMethodInvocation tree) {
   828         try {
   829             if (!tree.typeargs.isEmpty()) {
   830                 if (tree.meth.hasTag(SELECT)) {
   831                     JCFieldAccess left = (JCFieldAccess)tree.meth;
   832                     printExpr(left.selected);
   833                     print(".<");
   834                     printExprs(tree.typeargs);
   835                     print(">" + left.name);
   836                 } else {
   837                     print("<");
   838                     printExprs(tree.typeargs);
   839                     print(">");
   840                     printExpr(tree.meth);
   841                 }
   842             } else {
   843                 printExpr(tree.meth);
   844             }
   845             print("(");
   846             printExprs(tree.args);
   847             print(")");
   848         } catch (IOException e) {
   849             throw new UncheckedIOException(e);
   850         }
   851     }
   853     public void visitNewClass(JCNewClass tree) {
   854         try {
   855             if (tree.encl != null) {
   856                 printExpr(tree.encl);
   857                 print(".");
   858             }
   859             print("new ");
   860             if (!tree.typeargs.isEmpty()) {
   861                 print("<");
   862                 printExprs(tree.typeargs);
   863                 print(">");
   864             }
   865             printExpr(tree.clazz);
   866             print("(");
   867             printExprs(tree.args);
   868             print(")");
   869             if (tree.def != null) {
   870                 Name enclClassNamePrev = enclClassName;
   871                 enclClassName =
   872                         tree.def.name != null ? tree.def.name :
   873                             tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty
   874                                 ? tree.type.tsym.name : null;
   875                 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
   876                 printBlock(tree.def.defs);
   877                 enclClassName = enclClassNamePrev;
   878             }
   879         } catch (IOException e) {
   880             throw new UncheckedIOException(e);
   881         }
   882     }
   884     public void visitNewArray(JCNewArray tree) {
   885         try {
   886             if (tree.elemtype != null) {
   887                 print("new ");
   888                 JCTree elem = tree.elemtype;
   889                 if (elem.hasTag(TYPEARRAY))
   890                     printBaseElementType((JCArrayTypeTree) elem);
   891                 else
   892                     printExpr(elem);
   893                 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
   894                     print("[");
   895                     printExpr(l.head);
   896                     print("]");
   897                 }
   898                 if (elem instanceof JCArrayTypeTree)
   899                     printBrackets((JCArrayTypeTree) elem);
   900             }
   901             if (tree.elems != null) {
   902                 if (tree.elemtype != null) print("[]");
   903                 print("{");
   904                 printExprs(tree.elems);
   905                 print("}");
   906             }
   907         } catch (IOException e) {
   908             throw new UncheckedIOException(e);
   909         }
   910     }
   912     public void visitLambda(JCLambda tree) {
   913         try {
   914             print("(");
   915             printExprs(tree.params);
   916             print(")->");
   917             printExpr(tree.body);
   918         } catch (IOException e) {
   919             throw new UncheckedIOException(e);
   920         }
   921     }
   923     public void visitParens(JCParens tree) {
   924         try {
   925             print("(");
   926             printExpr(tree.expr);
   927             print(")");
   928         } catch (IOException e) {
   929             throw new UncheckedIOException(e);
   930         }
   931     }
   933     public void visitAssign(JCAssign tree) {
   934         try {
   935             open(prec, TreeInfo.assignPrec);
   936             printExpr(tree.lhs, TreeInfo.assignPrec + 1);
   937             print(" = ");
   938             printExpr(tree.rhs, TreeInfo.assignPrec);
   939             close(prec, TreeInfo.assignPrec);
   940         } catch (IOException e) {
   941             throw new UncheckedIOException(e);
   942         }
   943     }
   945     public String operatorName(JCTree.Tag tag) {
   946         switch(tag) {
   947             case POS:     return "+";
   948             case NEG:     return "-";
   949             case NOT:     return "!";
   950             case COMPL:   return "~";
   951             case PREINC:  return "++";
   952             case PREDEC:  return "--";
   953             case POSTINC: return "++";
   954             case POSTDEC: return "--";
   955             case NULLCHK: return "<*nullchk*>";
   956             case OR:      return "||";
   957             case AND:     return "&&";
   958             case EQ:      return "==";
   959             case NE:      return "!=";
   960             case LT:      return "<";
   961             case GT:      return ">";
   962             case LE:      return "<=";
   963             case GE:      return ">=";
   964             case BITOR:   return "|";
   965             case BITXOR:  return "^";
   966             case BITAND:  return "&";
   967             case SL:      return "<<";
   968             case SR:      return ">>";
   969             case USR:     return ">>>";
   970             case PLUS:    return "+";
   971             case MINUS:   return "-";
   972             case MUL:     return "*";
   973             case DIV:     return "/";
   974             case MOD:     return "%";
   975             default: throw new Error();
   976         }
   977     }
   979     public void visitAssignop(JCAssignOp tree) {
   980         try {
   981             open(prec, TreeInfo.assignopPrec);
   982             printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
   983             print(" " + operatorName(tree.getTag().noAssignOp()) + "= ");
   984             printExpr(tree.rhs, TreeInfo.assignopPrec);
   985             close(prec, TreeInfo.assignopPrec);
   986         } catch (IOException e) {
   987             throw new UncheckedIOException(e);
   988         }
   989     }
   991     public void visitUnary(JCUnary tree) {
   992         try {
   993             int ownprec = TreeInfo.opPrec(tree.getTag());
   994             String opname = operatorName(tree.getTag());
   995             open(prec, ownprec);
   996             if (!tree.getTag().isPostUnaryOp()) {
   997                 print(opname);
   998                 printExpr(tree.arg, ownprec);
   999             } else {
  1000                 printExpr(tree.arg, ownprec);
  1001                 print(opname);
  1003             close(prec, ownprec);
  1004         } catch (IOException e) {
  1005             throw new UncheckedIOException(e);
  1009     public void visitBinary(JCBinary tree) {
  1010         try {
  1011             int ownprec = TreeInfo.opPrec(tree.getTag());
  1012             String opname = operatorName(tree.getTag());
  1013             open(prec, ownprec);
  1014             printExpr(tree.lhs, ownprec);
  1015             print(" " + opname + " ");
  1016             printExpr(tree.rhs, ownprec + 1);
  1017             close(prec, ownprec);
  1018         } catch (IOException e) {
  1019             throw new UncheckedIOException(e);
  1023     public void visitTypeCast(JCTypeCast tree) {
  1024         try {
  1025             open(prec, TreeInfo.prefixPrec);
  1026             print("(");
  1027             printExpr(tree.clazz);
  1028             print(")");
  1029             printExpr(tree.expr, TreeInfo.prefixPrec);
  1030             close(prec, TreeInfo.prefixPrec);
  1031         } catch (IOException e) {
  1032             throw new UncheckedIOException(e);
  1036     public void visitTypeTest(JCInstanceOf tree) {
  1037         try {
  1038             open(prec, TreeInfo.ordPrec);
  1039             printExpr(tree.expr, TreeInfo.ordPrec);
  1040             print(" instanceof ");
  1041             printExpr(tree.clazz, TreeInfo.ordPrec + 1);
  1042             close(prec, TreeInfo.ordPrec);
  1043         } catch (IOException e) {
  1044             throw new UncheckedIOException(e);
  1048     public void visitIndexed(JCArrayAccess tree) {
  1049         try {
  1050             printExpr(tree.indexed, TreeInfo.postfixPrec);
  1051             print("[");
  1052             printExpr(tree.index);
  1053             print("]");
  1054         } catch (IOException e) {
  1055             throw new UncheckedIOException(e);
  1059     public void visitSelect(JCFieldAccess tree) {
  1060         try {
  1061             printExpr(tree.selected, TreeInfo.postfixPrec);
  1062             print("." + tree.name);
  1063         } catch (IOException e) {
  1064             throw new UncheckedIOException(e);
  1068     public void visitReference(JCMemberReference tree) {
  1069         try {
  1070             printExpr(tree.expr);
  1071             print("#");
  1072             if (tree.typeargs != null) {
  1073                 print("<");
  1074                 printExprs(tree.typeargs);
  1075                 print(">");
  1077             print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
  1078         } catch (IOException e) {
  1079             throw new UncheckedIOException(e);
  1083     public void visitIdent(JCIdent tree) {
  1084         try {
  1085             print(tree.name);
  1086         } catch (IOException e) {
  1087             throw new UncheckedIOException(e);
  1091     public void visitLiteral(JCLiteral tree) {
  1092         try {
  1093             switch (tree.typetag) {
  1094                 case TypeTags.INT:
  1095                     print(tree.value.toString());
  1096                     break;
  1097                 case TypeTags.LONG:
  1098                     print(tree.value + "L");
  1099                     break;
  1100                 case TypeTags.FLOAT:
  1101                     print(tree.value + "F");
  1102                     break;
  1103                 case TypeTags.DOUBLE:
  1104                     print(tree.value.toString());
  1105                     break;
  1106                 case TypeTags.CHAR:
  1107                     print("\'" +
  1108                             Convert.quote(
  1109                             String.valueOf((char)((Number)tree.value).intValue())) +
  1110                             "\'");
  1111                     break;
  1112                 case TypeTags.BOOLEAN:
  1113                     print(((Number)tree.value).intValue() == 1 ? "true" : "false");
  1114                     break;
  1115                 case TypeTags.BOT:
  1116                     print("null");
  1117                     break;
  1118                 default:
  1119                     print("\"" + Convert.quote(tree.value.toString()) + "\"");
  1120                     break;
  1122         } catch (IOException e) {
  1123             throw new UncheckedIOException(e);
  1127     public void visitTypeIdent(JCPrimitiveTypeTree tree) {
  1128         try {
  1129             switch(tree.typetag) {
  1130                 case TypeTags.BYTE:
  1131                     print("byte");
  1132                     break;
  1133                 case TypeTags.CHAR:
  1134                     print("char");
  1135                     break;
  1136                 case TypeTags.SHORT:
  1137                     print("short");
  1138                     break;
  1139                 case TypeTags.INT:
  1140                     print("int");
  1141                     break;
  1142                 case TypeTags.LONG:
  1143                     print("long");
  1144                     break;
  1145                 case TypeTags.FLOAT:
  1146                     print("float");
  1147                     break;
  1148                 case TypeTags.DOUBLE:
  1149                     print("double");
  1150                     break;
  1151                 case TypeTags.BOOLEAN:
  1152                     print("boolean");
  1153                     break;
  1154                 case TypeTags.VOID:
  1155                     print("void");
  1156                     break;
  1157                 default:
  1158                     print("error");
  1159                     break;
  1161         } catch (IOException e) {
  1162             throw new UncheckedIOException(e);
  1166     public void visitTypeArray(JCArrayTypeTree tree) {
  1167         try {
  1168             printBaseElementType(tree);
  1169             printBrackets(tree);
  1170         } catch (IOException e) {
  1171             throw new UncheckedIOException(e);
  1175     // Prints the inner element type of a nested array
  1176     private void printBaseElementType(JCTree tree) throws IOException {
  1177         printExpr(TreeInfo.innermostType(tree));
  1180     // prints the brackets of a nested array in reverse order
  1181     private void printBrackets(JCArrayTypeTree tree) throws IOException {
  1182         JCTree elem;
  1183         while (true) {
  1184             elem = tree.elemtype;
  1185             print("[]");
  1186             if (!elem.hasTag(TYPEARRAY)) break;
  1187             tree = (JCArrayTypeTree) elem;
  1191     public void visitTypeApply(JCTypeApply tree) {
  1192         try {
  1193             printExpr(tree.clazz);
  1194             print("<");
  1195             printExprs(tree.arguments);
  1196             print(">");
  1197         } catch (IOException e) {
  1198             throw new UncheckedIOException(e);
  1202     public void visitTypeUnion(JCTypeUnion tree) {
  1203         try {
  1204             printExprs(tree.alternatives, " | ");
  1205         } catch (IOException e) {
  1206             throw new UncheckedIOException(e);
  1210     public void visitTypeParameter(JCTypeParameter tree) {
  1211         try {
  1212             print(tree.name);
  1213             if (tree.bounds.nonEmpty()) {
  1214                 print(" extends ");
  1215                 printExprs(tree.bounds, " & ");
  1217         } catch (IOException e) {
  1218             throw new UncheckedIOException(e);
  1222     @Override
  1223     public void visitWildcard(JCWildcard tree) {
  1224         try {
  1225             print(tree.kind);
  1226             if (tree.kind.kind != BoundKind.UNBOUND)
  1227                 printExpr(tree.inner);
  1228         } catch (IOException e) {
  1229             throw new UncheckedIOException(e);
  1233     @Override
  1234     public void visitTypeBoundKind(TypeBoundKind tree) {
  1235         try {
  1236             print(String.valueOf(tree.kind));
  1237         } catch (IOException e) {
  1238             throw new UncheckedIOException(e);
  1242     public void visitErroneous(JCErroneous tree) {
  1243         try {
  1244             print("(ERROR)");
  1245         } catch (IOException e) {
  1246             throw new UncheckedIOException(e);
  1250     public void visitLetExpr(LetExpr tree) {
  1251         try {
  1252             print("(let " + tree.defs + " in " + tree.expr + ")");
  1253         } catch (IOException e) {
  1254             throw new UncheckedIOException(e);
  1258     public void visitModifiers(JCModifiers mods) {
  1259         try {
  1260             printAnnotations(mods.annotations);
  1261             printFlags(mods.flags);
  1262         } catch (IOException e) {
  1263             throw new UncheckedIOException(e);
  1267     public void visitAnnotation(JCAnnotation tree) {
  1268         try {
  1269             print("@");
  1270             printExpr(tree.annotationType);
  1271             print("(");
  1272             printExprs(tree.args);
  1273             print(")");
  1274         } catch (IOException e) {
  1275             throw new UncheckedIOException(e);
  1279     public void visitTree(JCTree tree) {
  1280         try {
  1281             print("(UNKNOWN: " + tree + ")");
  1282             println();
  1283         } catch (IOException e) {
  1284             throw new UncheckedIOException(e);

mercurial