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

Wed, 20 Jun 2012 13:23:26 -0700

author
jjg
date
Wed, 20 Jun 2012 13:23:26 -0700
changeset 1280
5c0b3faeb0b0
parent 1143
ec59a2ce9114
child 1326
30c36e23f154
permissions
-rw-r--r--

7174143: encapsulate doc comment table
Reviewed-by: ksrini, mcimadamore

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

mercurial