Wed, 23 Jan 2013 13:27:24 -0800
8006775: JSR 308: Compiler changes in JDK8
Reviewed-by: jjg
Contributed-by: mernst@cs.washington.edu, wmdietl@cs.washington.edu, mpapi@csail.mit.edu, mahmood@notnoop.com
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.tree.JCTree.*;
33 import com.sun.tools.javac.util.*;
34 import com.sun.tools.javac.util.List;
35 import static com.sun.tools.javac.code.Flags.*;
36 import static com.sun.tools.javac.code.Flags.ANNOTATION;
37 import static com.sun.tools.javac.tree.JCTree.Tag.*;
39 /** Prints out a tree as an indented Java source program.
40 *
41 * <p><b>This is NOT part of any supported API.
42 * If you write code that depends on this, you do so at your own risk.
43 * This code and its internal interfaces are subject to change or
44 * deletion without notice.</b>
45 */
46 public class Pretty extends JCTree.Visitor {
48 public Pretty(Writer out, boolean sourceOutput) {
49 this.out = out;
50 this.sourceOutput = sourceOutput;
51 }
53 /** Set when we are producing source output. If we're not
54 * producing source output, we can sometimes give more detail in
55 * the output even though that detail would not be valid java
56 * source.
57 */
58 private final boolean sourceOutput;
60 /** The output stream on which trees are printed.
61 */
62 Writer out;
64 /** Indentation width (can be reassigned from outside).
65 */
66 public int width = 4;
68 /** The current left margin.
69 */
70 int lmargin = 0;
72 /** The enclosing class name.
73 */
74 Name enclClassName;
76 /** A table mapping trees to their documentation comments
77 * (can be null)
78 */
79 DocCommentTable docComments = null;
81 /**
82 * A string sequence to be used when Pretty output should be constrained
83 * to fit into a given size
84 */
85 private final static String trimSequence = "[...]";
87 /**
88 * Max number of chars to be generated when output should fit into a single line
89 */
90 private final static int PREFERRED_LENGTH = 20;
92 /** Align code to be indented to left margin.
93 */
94 void align() throws IOException {
95 for (int i = 0; i < lmargin; i++) out.write(" ");
96 }
98 /** Increase left margin by indentation width.
99 */
100 void indent() {
101 lmargin = lmargin + width;
102 }
104 /** Decrease left margin by indentation width.
105 */
106 void undent() {
107 lmargin = lmargin - width;
108 }
110 /** Enter a new precedence level. Emit a `(' if new precedence level
111 * is less than precedence level so far.
112 * @param contextPrec The precedence level in force so far.
113 * @param ownPrec The new precedence level.
114 */
115 void open(int contextPrec, int ownPrec) throws IOException {
116 if (ownPrec < contextPrec) out.write("(");
117 }
119 /** Leave precedence level. Emit a `(' if inner precedence level
120 * is less than precedence level we revert to.
121 * @param contextPrec The precedence level we revert to.
122 * @param ownPrec The inner precedence level.
123 */
124 void close(int contextPrec, int ownPrec) throws IOException {
125 if (ownPrec < contextPrec) out.write(")");
126 }
128 /** Print string, replacing all non-ascii character with unicode escapes.
129 */
130 public void print(Object s) throws IOException {
131 out.write(Convert.escapeUnicode(s.toString()));
132 }
134 /** Print new line.
135 */
136 public void println() throws IOException {
137 out.write(lineSep);
138 }
140 public static String toSimpleString(JCTree tree) {
141 return toSimpleString(tree, PREFERRED_LENGTH);
142 }
144 public static String toSimpleString(JCTree tree, int maxLength) {
145 StringWriter s = new StringWriter();
146 try {
147 new Pretty(s, false).printExpr(tree);
148 }
149 catch (IOException e) {
150 // should never happen, because StringWriter is defined
151 // never to throw any IOExceptions
152 throw new AssertionError(e);
153 }
154 //we need to (i) replace all line terminators with a space and (ii) remove
155 //occurrences of 'missing' in the Pretty output (generated when types are missing)
156 String res = s.toString().trim().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", "");
157 if (res.length() < maxLength) {
158 return res;
159 } else {
160 int head = (maxLength - trimSequence.length()) * 2 / 3;
161 int tail = maxLength - trimSequence.length() - head;
162 return res.substring(0, head) + trimSequence + res.substring(res.length() - tail);
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 & ExtendedStandardFlags) != 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 public void printTypeAnnotations(List<JCAnnotation> trees) throws IOException {
264 if (trees.nonEmpty())
265 print(" ");
266 for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
267 printExpr(l.head);
268 print(" ");
269 }
270 }
272 /** Print documentation comment, if it exists
273 * @param tree The tree for which a documentation comment should be printed.
274 */
275 public void printDocComment(JCTree tree) throws IOException {
276 if (docComments != null) {
277 String dc = docComments.getCommentText(tree);
278 if (dc != null) {
279 print("/**"); println();
280 int pos = 0;
281 int endpos = lineEndPos(dc, pos);
282 while (pos < dc.length()) {
283 align();
284 print(" *");
285 if (pos < dc.length() && dc.charAt(pos) > ' ') print(" ");
286 print(dc.substring(pos, endpos)); println();
287 pos = endpos + 1;
288 endpos = lineEndPos(dc, pos);
289 }
290 align(); print(" */"); println();
291 align();
292 }
293 }
294 }
295 //where
296 static int lineEndPos(String s, int start) {
297 int pos = s.indexOf('\n', start);
298 if (pos < 0) pos = s.length();
299 return pos;
300 }
302 /** If type parameter list is non-empty, print it enclosed in
303 * {@literal "<...>"} brackets.
304 */
305 public void printTypeParameters(List<JCTypeParameter> trees) throws IOException {
306 if (trees.nonEmpty()) {
307 print("<");
308 printExprs(trees);
309 print(">");
310 }
311 }
313 /** Print a block.
314 */
315 public void printBlock(List<? extends JCTree> stats) throws IOException {
316 print("{");
317 println();
318 indent();
319 printStats(stats);
320 undent();
321 align();
322 print("}");
323 }
325 /** Print a block.
326 */
327 public void printEnumBody(List<JCTree> stats) throws IOException {
328 print("{");
329 println();
330 indent();
331 boolean first = true;
332 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
333 if (isEnumerator(l.head)) {
334 if (!first) {
335 print(",");
336 println();
337 }
338 align();
339 printStat(l.head);
340 first = false;
341 }
342 }
343 print(";");
344 println();
345 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
346 if (!isEnumerator(l.head)) {
347 align();
348 printStat(l.head);
349 println();
350 }
351 }
352 undent();
353 align();
354 print("}");
355 }
357 /** Is the given tree an enumerator definition? */
358 boolean isEnumerator(JCTree t) {
359 return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0;
360 }
362 /** Print unit consisting of package clause and import statements in toplevel,
363 * followed by class definition. if class definition == null,
364 * print all definitions in toplevel.
365 * @param tree The toplevel tree
366 * @param cdef The class definition, which is assumed to be part of the
367 * toplevel tree.
368 */
369 public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
370 docComments = tree.docComments;
371 printDocComment(tree);
372 if (tree.pid != null) {
373 print("package ");
374 printExpr(tree.pid);
375 print(";");
376 println();
377 }
378 boolean firstImport = true;
379 for (List<JCTree> l = tree.defs;
380 l.nonEmpty() && (cdef == null || l.head.hasTag(IMPORT));
381 l = l.tail) {
382 if (l.head.hasTag(IMPORT)) {
383 JCImport imp = (JCImport)l.head;
384 Name name = TreeInfo.name(imp.qualid);
385 if (name == name.table.names.asterisk ||
386 cdef == null ||
387 isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
388 if (firstImport) {
389 firstImport = false;
390 println();
391 }
392 printStat(imp);
393 }
394 } else {
395 printStat(l.head);
396 }
397 }
398 if (cdef != null) {
399 printStat(cdef);
400 println();
401 }
402 }
403 // where
404 boolean isUsed(final Symbol t, JCTree cdef) {
405 class UsedVisitor extends TreeScanner {
406 public void scan(JCTree tree) {
407 if (tree!=null && !result) tree.accept(this);
408 }
409 boolean result = false;
410 public void visitIdent(JCIdent tree) {
411 if (tree.sym == t) result = true;
412 }
413 }
414 UsedVisitor v = new UsedVisitor();
415 v.scan(cdef);
416 return v.result;
417 }
419 /**************************************************************************
420 * Visitor methods
421 *************************************************************************/
423 public void visitTopLevel(JCCompilationUnit tree) {
424 try {
425 printUnit(tree, null);
426 } catch (IOException e) {
427 throw new UncheckedIOException(e);
428 }
429 }
431 public void visitImport(JCImport tree) {
432 try {
433 print("import ");
434 if (tree.staticImport) print("static ");
435 printExpr(tree.qualid);
436 print(";");
437 println();
438 } catch (IOException e) {
439 throw new UncheckedIOException(e);
440 }
441 }
443 public void visitClassDef(JCClassDecl tree) {
444 try {
445 println(); align();
446 printDocComment(tree);
447 printAnnotations(tree.mods.annotations);
448 printFlags(tree.mods.flags & ~INTERFACE);
449 Name enclClassNamePrev = enclClassName;
450 enclClassName = tree.name;
451 if ((tree.mods.flags & INTERFACE) != 0) {
452 print("interface " + tree.name);
453 printTypeParameters(tree.typarams);
454 if (tree.implementing.nonEmpty()) {
455 print(" extends ");
456 printExprs(tree.implementing);
457 }
458 } else {
459 if ((tree.mods.flags & ENUM) != 0)
460 print("enum " + tree.name);
461 else
462 print("class " + tree.name);
463 printTypeParameters(tree.typarams);
464 if (tree.extending != null) {
465 print(" extends ");
466 printExpr(tree.extending);
467 }
468 if (tree.implementing.nonEmpty()) {
469 print(" implements ");
470 printExprs(tree.implementing);
471 }
472 }
473 print(" ");
474 if ((tree.mods.flags & ENUM) != 0) {
475 printEnumBody(tree.defs);
476 } else {
477 printBlock(tree.defs);
478 }
479 enclClassName = enclClassNamePrev;
480 } catch (IOException e) {
481 throw new UncheckedIOException(e);
482 }
483 }
485 public void visitMethodDef(JCMethodDecl tree) {
486 try {
487 // when producing source output, omit anonymous constructors
488 if (tree.name == tree.name.table.names.init &&
489 enclClassName == null &&
490 sourceOutput) return;
491 println(); align();
492 printDocComment(tree);
493 printExpr(tree.mods);
494 printTypeParameters(tree.typarams);
495 if (tree.name == tree.name.table.names.init) {
496 print(enclClassName != null ? enclClassName : tree.name);
497 } else {
498 printExpr(tree.restype);
499 print(" " + tree.name);
500 }
501 print("(");
502 if (tree.recvparam!=null) {
503 printExpr(tree.recvparam);
504 if (tree.params.size() > 0) {
505 print(", ");
506 }
507 }
508 printExprs(tree.params);
509 print(")");
510 if (tree.thrown.nonEmpty()) {
511 print(" throws ");
512 printExprs(tree.thrown);
513 }
514 if (tree.defaultValue != null) {
515 print(" default ");
516 printExpr(tree.defaultValue);
517 }
518 if (tree.body != null) {
519 print(" ");
520 printStat(tree.body);
521 } else {
522 print(";");
523 }
524 } catch (IOException e) {
525 throw new UncheckedIOException(e);
526 }
527 }
529 public void visitVarDef(JCVariableDecl tree) {
530 try {
531 if (docComments != null && docComments.hasComment(tree)) {
532 println(); align();
533 }
534 printDocComment(tree);
535 if ((tree.mods.flags & ENUM) != 0) {
536 print("/*public static final*/ ");
537 print(tree.name);
538 if (tree.init != null) {
539 if (sourceOutput && tree.init.hasTag(NEWCLASS)) {
540 print(" /*enum*/ ");
541 JCNewClass init = (JCNewClass) tree.init;
542 if (init.args != null && init.args.nonEmpty()) {
543 print("(");
544 print(init.args);
545 print(")");
546 }
547 if (init.def != null && init.def.defs != null) {
548 print(" ");
549 printBlock(init.def.defs);
550 }
551 return;
552 }
553 print(" /* = ");
554 printExpr(tree.init);
555 print(" */");
556 }
557 } else {
558 printExpr(tree.mods);
559 if ((tree.mods.flags & VARARGS) != 0) {
560 JCTree vartype = tree.vartype;
561 List<JCAnnotation> tas = null;
562 if (vartype instanceof JCAnnotatedType) {
563 tas = ((JCAnnotatedType)vartype).annotations;
564 vartype = ((JCAnnotatedType)vartype).underlyingType;
565 }
566 printExpr(((JCArrayTypeTree) vartype).elemtype);
567 if (tas != null)
568 printTypeAnnotations(tas);
569 print("... " + tree.name);
570 } else {
571 printExpr(tree.vartype);
572 print(" " + tree.name);
573 }
574 if (tree.init != null) {
575 print(" = ");
576 printExpr(tree.init);
577 }
578 if (prec == TreeInfo.notExpression) print(";");
579 }
580 } catch (IOException e) {
581 throw new UncheckedIOException(e);
582 }
583 }
585 public void visitSkip(JCSkip tree) {
586 try {
587 print(";");
588 } catch (IOException e) {
589 throw new UncheckedIOException(e);
590 }
591 }
593 public void visitBlock(JCBlock tree) {
594 try {
595 printFlags(tree.flags);
596 printBlock(tree.stats);
597 } catch (IOException e) {
598 throw new UncheckedIOException(e);
599 }
600 }
602 public void visitDoLoop(JCDoWhileLoop tree) {
603 try {
604 print("do ");
605 printStat(tree.body);
606 align();
607 print(" while ");
608 if (tree.cond.hasTag(PARENS)) {
609 printExpr(tree.cond);
610 } else {
611 print("(");
612 printExpr(tree.cond);
613 print(")");
614 }
615 print(";");
616 } catch (IOException e) {
617 throw new UncheckedIOException(e);
618 }
619 }
621 public void visitWhileLoop(JCWhileLoop tree) {
622 try {
623 print("while ");
624 if (tree.cond.hasTag(PARENS)) {
625 printExpr(tree.cond);
626 } else {
627 print("(");
628 printExpr(tree.cond);
629 print(")");
630 }
631 print(" ");
632 printStat(tree.body);
633 } catch (IOException e) {
634 throw new UncheckedIOException(e);
635 }
636 }
638 public void visitForLoop(JCForLoop tree) {
639 try {
640 print("for (");
641 if (tree.init.nonEmpty()) {
642 if (tree.init.head.hasTag(VARDEF)) {
643 printExpr(tree.init.head);
644 for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
645 JCVariableDecl vdef = (JCVariableDecl)l.head;
646 print(", " + vdef.name + " = ");
647 printExpr(vdef.init);
648 }
649 } else {
650 printExprs(tree.init);
651 }
652 }
653 print("; ");
654 if (tree.cond != null) printExpr(tree.cond);
655 print("; ");
656 printExprs(tree.step);
657 print(") ");
658 printStat(tree.body);
659 } catch (IOException e) {
660 throw new UncheckedIOException(e);
661 }
662 }
664 public void visitForeachLoop(JCEnhancedForLoop tree) {
665 try {
666 print("for (");
667 printExpr(tree.var);
668 print(" : ");
669 printExpr(tree.expr);
670 print(") ");
671 printStat(tree.body);
672 } catch (IOException e) {
673 throw new UncheckedIOException(e);
674 }
675 }
677 public void visitLabelled(JCLabeledStatement tree) {
678 try {
679 print(tree.label + ": ");
680 printStat(tree.body);
681 } catch (IOException e) {
682 throw new UncheckedIOException(e);
683 }
684 }
686 public void visitSwitch(JCSwitch tree) {
687 try {
688 print("switch ");
689 if (tree.selector.hasTag(PARENS)) {
690 printExpr(tree.selector);
691 } else {
692 print("(");
693 printExpr(tree.selector);
694 print(")");
695 }
696 print(" {");
697 println();
698 printStats(tree.cases);
699 align();
700 print("}");
701 } catch (IOException e) {
702 throw new UncheckedIOException(e);
703 }
704 }
706 public void visitCase(JCCase tree) {
707 try {
708 if (tree.pat == null) {
709 print("default");
710 } else {
711 print("case ");
712 printExpr(tree.pat);
713 }
714 print(": ");
715 println();
716 indent();
717 printStats(tree.stats);
718 undent();
719 align();
720 } catch (IOException e) {
721 throw new UncheckedIOException(e);
722 }
723 }
725 public void visitSynchronized(JCSynchronized tree) {
726 try {
727 print("synchronized ");
728 if (tree.lock.hasTag(PARENS)) {
729 printExpr(tree.lock);
730 } else {
731 print("(");
732 printExpr(tree.lock);
733 print(")");
734 }
735 print(" ");
736 printStat(tree.body);
737 } catch (IOException e) {
738 throw new UncheckedIOException(e);
739 }
740 }
742 public void visitTry(JCTry tree) {
743 try {
744 print("try ");
745 if (tree.resources.nonEmpty()) {
746 print("(");
747 boolean first = true;
748 for (JCTree var : tree.resources) {
749 if (!first) {
750 println();
751 indent();
752 }
753 printStat(var);
754 first = false;
755 }
756 print(") ");
757 }
758 printStat(tree.body);
759 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
760 printStat(l.head);
761 }
762 if (tree.finalizer != null) {
763 print(" finally ");
764 printStat(tree.finalizer);
765 }
766 } catch (IOException e) {
767 throw new UncheckedIOException(e);
768 }
769 }
771 public void visitCatch(JCCatch tree) {
772 try {
773 print(" catch (");
774 printExpr(tree.param);
775 print(") ");
776 printStat(tree.body);
777 } catch (IOException e) {
778 throw new UncheckedIOException(e);
779 }
780 }
782 public void visitConditional(JCConditional tree) {
783 try {
784 open(prec, TreeInfo.condPrec);
785 printExpr(tree.cond, TreeInfo.condPrec);
786 print(" ? ");
787 printExpr(tree.truepart, TreeInfo.condPrec);
788 print(" : ");
789 printExpr(tree.falsepart, TreeInfo.condPrec);
790 close(prec, TreeInfo.condPrec);
791 } catch (IOException e) {
792 throw new UncheckedIOException(e);
793 }
794 }
796 public void visitIf(JCIf tree) {
797 try {
798 print("if ");
799 if (tree.cond.hasTag(PARENS)) {
800 printExpr(tree.cond);
801 } else {
802 print("(");
803 printExpr(tree.cond);
804 print(")");
805 }
806 print(" ");
807 printStat(tree.thenpart);
808 if (tree.elsepart != null) {
809 print(" else ");
810 printStat(tree.elsepart);
811 }
812 } catch (IOException e) {
813 throw new UncheckedIOException(e);
814 }
815 }
817 public void visitExec(JCExpressionStatement tree) {
818 try {
819 printExpr(tree.expr);
820 if (prec == TreeInfo.notExpression) print(";");
821 } catch (IOException e) {
822 throw new UncheckedIOException(e);
823 }
824 }
826 public void visitBreak(JCBreak tree) {
827 try {
828 print("break");
829 if (tree.label != null) print(" " + tree.label);
830 print(";");
831 } catch (IOException e) {
832 throw new UncheckedIOException(e);
833 }
834 }
836 public void visitContinue(JCContinue tree) {
837 try {
838 print("continue");
839 if (tree.label != null) print(" " + tree.label);
840 print(";");
841 } catch (IOException e) {
842 throw new UncheckedIOException(e);
843 }
844 }
846 public void visitReturn(JCReturn tree) {
847 try {
848 print("return");
849 if (tree.expr != null) {
850 print(" ");
851 printExpr(tree.expr);
852 }
853 print(";");
854 } catch (IOException e) {
855 throw new UncheckedIOException(e);
856 }
857 }
859 public void visitThrow(JCThrow tree) {
860 try {
861 print("throw ");
862 printExpr(tree.expr);
863 print(";");
864 } catch (IOException e) {
865 throw new UncheckedIOException(e);
866 }
867 }
869 public void visitAssert(JCAssert tree) {
870 try {
871 print("assert ");
872 printExpr(tree.cond);
873 if (tree.detail != null) {
874 print(" : ");
875 printExpr(tree.detail);
876 }
877 print(";");
878 } catch (IOException e) {
879 throw new UncheckedIOException(e);
880 }
881 }
883 public void visitApply(JCMethodInvocation tree) {
884 try {
885 if (!tree.typeargs.isEmpty()) {
886 if (tree.meth.hasTag(SELECT)) {
887 JCFieldAccess left = (JCFieldAccess)tree.meth;
888 printExpr(left.selected);
889 print(".<");
890 printExprs(tree.typeargs);
891 print(">" + left.name);
892 } else {
893 print("<");
894 printExprs(tree.typeargs);
895 print(">");
896 printExpr(tree.meth);
897 }
898 } else {
899 printExpr(tree.meth);
900 }
901 print("(");
902 printExprs(tree.args);
903 print(")");
904 } catch (IOException e) {
905 throw new UncheckedIOException(e);
906 }
907 }
909 public void visitNewClass(JCNewClass tree) {
910 try {
911 if (tree.encl != null) {
912 printExpr(tree.encl);
913 print(".");
914 }
915 print("new ");
916 if (!tree.typeargs.isEmpty()) {
917 print("<");
918 printExprs(tree.typeargs);
919 print(">");
920 }
921 printExpr(tree.clazz);
922 print("(");
923 printExprs(tree.args);
924 print(")");
925 if (tree.def != null) {
926 Name enclClassNamePrev = enclClassName;
927 enclClassName =
928 tree.def.name != null ? tree.def.name :
929 tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty
930 ? tree.type.tsym.name : null;
931 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
932 printBlock(tree.def.defs);
933 enclClassName = enclClassNamePrev;
934 }
935 } catch (IOException e) {
936 throw new UncheckedIOException(e);
937 }
938 }
940 public void visitNewArray(JCNewArray tree) {
941 try {
942 if (tree.elemtype != null) {
943 print("new ");
944 printTypeAnnotations(tree.annotations);
945 JCTree elem = tree.elemtype;
946 printBaseElementType(elem);
947 boolean isElemAnnoType = elem instanceof JCAnnotatedType;
948 int i = 0;
949 List<List<JCAnnotation>> da = tree.dimAnnotations;
950 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
951 if (da.size() > i) {
952 printTypeAnnotations(da.get(i));
953 }
954 print("[");
955 i++;
956 printExpr(l.head);
957 print("]");
958 }
959 if (tree.elems != null) {
960 if (isElemAnnoType) {
961 printTypeAnnotations(((JCAnnotatedType)tree.elemtype).annotations);
962 }
963 print("[]");
964 }
965 if (isElemAnnoType)
966 elem = ((JCAnnotatedType)elem).underlyingType;
967 if (elem instanceof JCArrayTypeTree)
968 printBrackets((JCArrayTypeTree) elem);
969 }
970 if (tree.elems != null) {
971 if (tree.elemtype != null) print("[]");
972 print("{");
973 printExprs(tree.elems);
974 print("}");
975 }
976 } catch (IOException e) {
977 throw new UncheckedIOException(e);
978 }
979 }
981 public void visitLambda(JCLambda tree) {
982 try {
983 print("(");
984 if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT) {
985 printExprs(tree.params);
986 } else {
987 String sep = "";
988 for (JCVariableDecl param : tree.params) {
989 print(sep);
990 print(param.name);
991 sep = ",";
992 }
993 }
994 print(")->");
995 printExpr(tree.body);
996 } catch (IOException e) {
997 throw new UncheckedIOException(e);
998 }
999 }
1001 public void visitParens(JCParens tree) {
1002 try {
1003 print("(");
1004 printExpr(tree.expr);
1005 print(")");
1006 } catch (IOException e) {
1007 throw new UncheckedIOException(e);
1008 }
1009 }
1011 public void visitAssign(JCAssign tree) {
1012 try {
1013 open(prec, TreeInfo.assignPrec);
1014 printExpr(tree.lhs, TreeInfo.assignPrec + 1);
1015 print(" = ");
1016 printExpr(tree.rhs, TreeInfo.assignPrec);
1017 close(prec, TreeInfo.assignPrec);
1018 } catch (IOException e) {
1019 throw new UncheckedIOException(e);
1020 }
1021 }
1023 public String operatorName(JCTree.Tag tag) {
1024 switch(tag) {
1025 case POS: return "+";
1026 case NEG: return "-";
1027 case NOT: return "!";
1028 case COMPL: return "~";
1029 case PREINC: return "++";
1030 case PREDEC: return "--";
1031 case POSTINC: return "++";
1032 case POSTDEC: return "--";
1033 case NULLCHK: return "<*nullchk*>";
1034 case OR: return "||";
1035 case AND: return "&&";
1036 case EQ: return "==";
1037 case NE: return "!=";
1038 case LT: return "<";
1039 case GT: return ">";
1040 case LE: return "<=";
1041 case GE: return ">=";
1042 case BITOR: return "|";
1043 case BITXOR: return "^";
1044 case BITAND: return "&";
1045 case SL: return "<<";
1046 case SR: return ">>";
1047 case USR: return ">>>";
1048 case PLUS: return "+";
1049 case MINUS: return "-";
1050 case MUL: return "*";
1051 case DIV: return "/";
1052 case MOD: return "%";
1053 default: throw new Error();
1054 }
1055 }
1057 public void visitAssignop(JCAssignOp tree) {
1058 try {
1059 open(prec, TreeInfo.assignopPrec);
1060 printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
1061 print(" " + operatorName(tree.getTag().noAssignOp()) + "= ");
1062 printExpr(tree.rhs, TreeInfo.assignopPrec);
1063 close(prec, TreeInfo.assignopPrec);
1064 } catch (IOException e) {
1065 throw new UncheckedIOException(e);
1066 }
1067 }
1069 public void visitUnary(JCUnary tree) {
1070 try {
1071 int ownprec = TreeInfo.opPrec(tree.getTag());
1072 String opname = operatorName(tree.getTag());
1073 open(prec, ownprec);
1074 if (!tree.getTag().isPostUnaryOp()) {
1075 print(opname);
1076 printExpr(tree.arg, ownprec);
1077 } else {
1078 printExpr(tree.arg, ownprec);
1079 print(opname);
1080 }
1081 close(prec, ownprec);
1082 } catch (IOException e) {
1083 throw new UncheckedIOException(e);
1084 }
1085 }
1087 public void visitBinary(JCBinary tree) {
1088 try {
1089 int ownprec = TreeInfo.opPrec(tree.getTag());
1090 String opname = operatorName(tree.getTag());
1091 open(prec, ownprec);
1092 printExpr(tree.lhs, ownprec);
1093 print(" " + opname + " ");
1094 printExpr(tree.rhs, ownprec + 1);
1095 close(prec, ownprec);
1096 } catch (IOException e) {
1097 throw new UncheckedIOException(e);
1098 }
1099 }
1101 public void visitTypeCast(JCTypeCast tree) {
1102 try {
1103 open(prec, TreeInfo.prefixPrec);
1104 print("(");
1105 printExpr(tree.clazz);
1106 print(")");
1107 printExpr(tree.expr, TreeInfo.prefixPrec);
1108 close(prec, TreeInfo.prefixPrec);
1109 } catch (IOException e) {
1110 throw new UncheckedIOException(e);
1111 }
1112 }
1114 public void visitTypeTest(JCInstanceOf tree) {
1115 try {
1116 open(prec, TreeInfo.ordPrec);
1117 printExpr(tree.expr, TreeInfo.ordPrec);
1118 print(" instanceof ");
1119 printExpr(tree.clazz, TreeInfo.ordPrec + 1);
1120 close(prec, TreeInfo.ordPrec);
1121 } catch (IOException e) {
1122 throw new UncheckedIOException(e);
1123 }
1124 }
1126 public void visitIndexed(JCArrayAccess tree) {
1127 try {
1128 printExpr(tree.indexed, TreeInfo.postfixPrec);
1129 print("[");
1130 printExpr(tree.index);
1131 print("]");
1132 } catch (IOException e) {
1133 throw new UncheckedIOException(e);
1134 }
1135 }
1137 public void visitSelect(JCFieldAccess tree) {
1138 try {
1139 printExpr(tree.selected, TreeInfo.postfixPrec);
1140 print("." + tree.name);
1141 } catch (IOException e) {
1142 throw new UncheckedIOException(e);
1143 }
1144 }
1146 public void visitReference(JCMemberReference tree) {
1147 try {
1148 printExpr(tree.expr);
1149 print("::");
1150 if (tree.typeargs != null) {
1151 print("<");
1152 printExprs(tree.typeargs);
1153 print(">");
1154 }
1155 print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
1156 } catch (IOException e) {
1157 throw new UncheckedIOException(e);
1158 }
1159 }
1161 public void visitIdent(JCIdent tree) {
1162 try {
1163 print(tree.name);
1164 } catch (IOException e) {
1165 throw new UncheckedIOException(e);
1166 }
1167 }
1169 public void visitLiteral(JCLiteral tree) {
1170 try {
1171 switch (tree.typetag) {
1172 case INT:
1173 print(tree.value.toString());
1174 break;
1175 case LONG:
1176 print(tree.value + "L");
1177 break;
1178 case FLOAT:
1179 print(tree.value + "F");
1180 break;
1181 case DOUBLE:
1182 print(tree.value.toString());
1183 break;
1184 case CHAR:
1185 print("\'" +
1186 Convert.quote(
1187 String.valueOf((char)((Number)tree.value).intValue())) +
1188 "\'");
1189 break;
1190 case BOOLEAN:
1191 print(((Number)tree.value).intValue() == 1 ? "true" : "false");
1192 break;
1193 case BOT:
1194 print("null");
1195 break;
1196 default:
1197 print("\"" + Convert.quote(tree.value.toString()) + "\"");
1198 break;
1199 }
1200 } catch (IOException e) {
1201 throw new UncheckedIOException(e);
1202 }
1203 }
1205 public void visitTypeIdent(JCPrimitiveTypeTree tree) {
1206 try {
1207 switch(tree.typetag) {
1208 case BYTE:
1209 print("byte");
1210 break;
1211 case CHAR:
1212 print("char");
1213 break;
1214 case SHORT:
1215 print("short");
1216 break;
1217 case INT:
1218 print("int");
1219 break;
1220 case LONG:
1221 print("long");
1222 break;
1223 case FLOAT:
1224 print("float");
1225 break;
1226 case DOUBLE:
1227 print("double");
1228 break;
1229 case BOOLEAN:
1230 print("boolean");
1231 break;
1232 case VOID:
1233 print("void");
1234 break;
1235 default:
1236 print("error");
1237 break;
1238 }
1239 } catch (IOException e) {
1240 throw new UncheckedIOException(e);
1241 }
1242 }
1244 public void visitTypeArray(JCArrayTypeTree tree) {
1245 try {
1246 printBaseElementType(tree);
1247 printBrackets(tree);
1248 } catch (IOException e) {
1249 throw new UncheckedIOException(e);
1250 }
1251 }
1253 // Prints the inner element type of a nested array
1254 private void printBaseElementType(JCTree tree) throws IOException {
1255 printExpr(TreeInfo.innermostType(tree));
1256 }
1258 // prints the brackets of a nested array in reverse order
1259 private void printBrackets(JCArrayTypeTree tree) throws IOException {
1260 JCTree elem;
1261 while (true) {
1262 elem = tree.elemtype;
1263 if (elem.hasTag(ANNOTATED_TYPE)) {
1264 JCAnnotatedType atype = (JCAnnotatedType) elem;
1265 elem = atype.underlyingType;
1266 if (!elem.hasTag(TYPEARRAY)) break;
1267 printTypeAnnotations(atype.annotations);
1268 }
1269 print("[]");
1270 if (!elem.hasTag(TYPEARRAY)) break;
1271 tree = (JCArrayTypeTree) elem;
1272 }
1273 }
1275 public void visitTypeApply(JCTypeApply tree) {
1276 try {
1277 printExpr(tree.clazz);
1278 print("<");
1279 printExprs(tree.arguments);
1280 print(">");
1281 } catch (IOException e) {
1282 throw new UncheckedIOException(e);
1283 }
1284 }
1286 public void visitTypeUnion(JCTypeUnion tree) {
1287 try {
1288 printExprs(tree.alternatives, " | ");
1289 } catch (IOException e) {
1290 throw new UncheckedIOException(e);
1291 }
1292 }
1294 public void visitTypeIntersection(JCTypeIntersection tree) {
1295 try {
1296 printExprs(tree.bounds, " & ");
1297 } catch (IOException e) {
1298 throw new UncheckedIOException(e);
1299 }
1300 }
1302 public void visitTypeParameter(JCTypeParameter tree) {
1303 try {
1304 print(tree.name);
1305 if (tree.bounds.nonEmpty()) {
1306 print(" extends ");
1307 printExprs(tree.bounds, " & ");
1308 }
1309 } catch (IOException e) {
1310 throw new UncheckedIOException(e);
1311 }
1312 }
1314 @Override
1315 public void visitWildcard(JCWildcard tree) {
1316 try {
1317 print(tree.kind);
1318 if (tree.kind.kind != BoundKind.UNBOUND)
1319 printExpr(tree.inner);
1320 } catch (IOException e) {
1321 throw new UncheckedIOException(e);
1322 }
1323 }
1325 @Override
1326 public void visitTypeBoundKind(TypeBoundKind tree) {
1327 try {
1328 print(String.valueOf(tree.kind));
1329 } catch (IOException e) {
1330 throw new UncheckedIOException(e);
1331 }
1332 }
1334 public void visitErroneous(JCErroneous tree) {
1335 try {
1336 print("(ERROR)");
1337 } catch (IOException e) {
1338 throw new UncheckedIOException(e);
1339 }
1340 }
1342 public void visitLetExpr(LetExpr tree) {
1343 try {
1344 print("(let " + tree.defs + " in " + tree.expr + ")");
1345 } catch (IOException e) {
1346 throw new UncheckedIOException(e);
1347 }
1348 }
1350 public void visitModifiers(JCModifiers mods) {
1351 try {
1352 printAnnotations(mods.annotations);
1353 printFlags(mods.flags);
1354 } catch (IOException e) {
1355 throw new UncheckedIOException(e);
1356 }
1357 }
1359 public void visitAnnotation(JCAnnotation tree) {
1360 try {
1361 print("@");
1362 printExpr(tree.annotationType);
1363 print("(");
1364 printExprs(tree.args);
1365 print(")");
1366 } catch (IOException e) {
1367 throw new UncheckedIOException(e);
1368 }
1369 }
1371 public void visitAnnotatedType(JCAnnotatedType tree) {
1372 try {
1373 if (tree.underlyingType.getKind() == JCTree.Kind.MEMBER_SELECT) {
1374 JCFieldAccess access = (JCFieldAccess) tree.underlyingType;
1375 printExpr(access.selected, TreeInfo.postfixPrec);
1376 print(".");
1377 printTypeAnnotations(tree.annotations);
1378 print(access.name);
1379 } else if (tree.underlyingType.getKind() == JCTree.Kind.ARRAY_TYPE) {
1380 JCArrayTypeTree array = (JCArrayTypeTree) tree.underlyingType;
1381 printBaseElementType(tree);
1382 printTypeAnnotations(tree.annotations);
1383 print("[]");
1384 JCExpression elem = array.elemtype;
1385 if (elem.hasTag(TYPEARRAY)) {
1386 printBrackets((JCArrayTypeTree) elem);
1387 }
1388 } else {
1389 printTypeAnnotations(tree.annotations);
1390 printExpr(tree.underlyingType);
1391 }
1392 } catch (IOException e) {
1393 throw new UncheckedIOException(e);
1394 }
1395 }
1397 public void visitTree(JCTree tree) {
1398 try {
1399 print("(UNKNOWN: " + tree + ")");
1400 println();
1401 } catch (IOException e) {
1402 throw new UncheckedIOException(e);
1403 }
1404 }
1406 }