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

Tue, 09 Oct 2012 19:10:00 -0700

author
jjg
date
Tue, 09 Oct 2012 19:10:00 -0700
changeset 1357
c75be5bc5283
parent 1348
573ceb23beeb
child 1366
12cf6bfd8c05
permissions
-rw-r--r--

8000663: clean up langtools imports
Reviewed-by: darcy

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

mercurial