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

Mon, 21 Jan 2013 20:13:56 +0000

author
mcimadamore
date
Mon, 21 Jan 2013 20:13:56 +0000
changeset 1510
7873d37f5b37
parent 1486
7d2f628f04f1
child 1521
71f35e4b93a5
permissions
-rw-r--r--

8005244: Implement overload resolution as per latest spec EDR
Summary: Add support for stuck expressions and provisional applicability
Reviewed-by: jjg

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

mercurial