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

changeset 0
959103a6100f
child 2525
2eb010b6cb22
equal deleted inserted replaced
-1:000000000000 0:959103a6100f
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 */
25
26 package com.sun.tools.javac.tree;
27
28 import java.io.*;
29
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.*;
38
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 {
47
48 public Pretty(Writer out, boolean sourceOutput) {
49 this.out = out;
50 this.sourceOutput = sourceOutput;
51 }
52
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;
59
60 /** The output stream on which trees are printed.
61 */
62 Writer out;
63
64 /** Indentation width (can be reassigned from outside).
65 */
66 public int width = 4;
67
68 /** The current left margin.
69 */
70 int lmargin = 0;
71
72 /** The enclosing class name.
73 */
74 Name enclClassName;
75
76 /** A table mapping trees to their documentation comments
77 * (can be null)
78 */
79 DocCommentTable docComments = null;
80
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 = "[...]";
86
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;
91
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 }
97
98 /** Increase left margin by indentation width.
99 */
100 void indent() {
101 lmargin = lmargin + width;
102 }
103
104 /** Decrease left margin by indentation width.
105 */
106 void undent() {
107 lmargin = lmargin - width;
108 }
109
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 }
118
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 }
127
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 }
133
134 /** Print new line.
135 */
136 public void println() throws IOException {
137 out.write(lineSep);
138 }
139
140 public static String toSimpleString(JCTree tree) {
141 return toSimpleString(tree, PREFERRED_LENGTH);
142 }
143
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 }
165
166 String lineSep = System.getProperty("line.separator");
167
168 /**************************************************************************
169 * Traversal methods
170 *************************************************************************/
171
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 }
179
180 /** Visitor argument: the current precedence level.
181 */
182 int prec;
183
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 }
203
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 }
210
211 /** Derived visitor method: print statement tree.
212 */
213 public void printStat(JCTree tree) throws IOException {
214 printExpr(tree, TreeInfo.notExpression);
215 }
216
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 }
229
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 }
235
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 }
245
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 }
254
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 }
262
263 public void printTypeAnnotations(List<JCAnnotation> trees) throws IOException {
264 for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
265 printExpr(l.head);
266 print(" ");
267 }
268 }
269
270 /** Print documentation comment, if it exists
271 * @param tree The tree for which a documentation comment should be printed.
272 */
273 public void printDocComment(JCTree tree) throws IOException {
274 if (docComments != null) {
275 String dc = docComments.getCommentText(tree);
276 if (dc != null) {
277 print("/**"); println();
278 int pos = 0;
279 int endpos = lineEndPos(dc, pos);
280 while (pos < dc.length()) {
281 align();
282 print(" *");
283 if (pos < dc.length() && dc.charAt(pos) > ' ') print(" ");
284 print(dc.substring(pos, endpos)); println();
285 pos = endpos + 1;
286 endpos = lineEndPos(dc, pos);
287 }
288 align(); print(" */"); println();
289 align();
290 }
291 }
292 }
293 //where
294 static int lineEndPos(String s, int start) {
295 int pos = s.indexOf('\n', start);
296 if (pos < 0) pos = s.length();
297 return pos;
298 }
299
300 /** If type parameter list is non-empty, print it enclosed in
301 * {@literal "<...>"} brackets.
302 */
303 public void printTypeParameters(List<JCTypeParameter> trees) throws IOException {
304 if (trees.nonEmpty()) {
305 print("<");
306 printExprs(trees);
307 print(">");
308 }
309 }
310
311 /** Print a block.
312 */
313 public void printBlock(List<? extends JCTree> stats) throws IOException {
314 print("{");
315 println();
316 indent();
317 printStats(stats);
318 undent();
319 align();
320 print("}");
321 }
322
323 /** Print a block.
324 */
325 public void printEnumBody(List<JCTree> stats) throws IOException {
326 print("{");
327 println();
328 indent();
329 boolean first = true;
330 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
331 if (isEnumerator(l.head)) {
332 if (!first) {
333 print(",");
334 println();
335 }
336 align();
337 printStat(l.head);
338 first = false;
339 }
340 }
341 print(";");
342 println();
343 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
344 if (!isEnumerator(l.head)) {
345 align();
346 printStat(l.head);
347 println();
348 }
349 }
350 undent();
351 align();
352 print("}");
353 }
354
355 /** Is the given tree an enumerator definition? */
356 boolean isEnumerator(JCTree t) {
357 return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0;
358 }
359
360 /** Print unit consisting of package clause and import statements in toplevel,
361 * followed by class definition. if class definition == null,
362 * print all definitions in toplevel.
363 * @param tree The toplevel tree
364 * @param cdef The class definition, which is assumed to be part of the
365 * toplevel tree.
366 */
367 public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
368 docComments = tree.docComments;
369 printDocComment(tree);
370 if (tree.pid != null) {
371 print("package ");
372 printExpr(tree.pid);
373 print(";");
374 println();
375 }
376 boolean firstImport = true;
377 for (List<JCTree> l = tree.defs;
378 l.nonEmpty() && (cdef == null || l.head.hasTag(IMPORT));
379 l = l.tail) {
380 if (l.head.hasTag(IMPORT)) {
381 JCImport imp = (JCImport)l.head;
382 Name name = TreeInfo.name(imp.qualid);
383 if (name == name.table.names.asterisk ||
384 cdef == null ||
385 isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
386 if (firstImport) {
387 firstImport = false;
388 println();
389 }
390 printStat(imp);
391 }
392 } else {
393 printStat(l.head);
394 }
395 }
396 if (cdef != null) {
397 printStat(cdef);
398 println();
399 }
400 }
401 // where
402 boolean isUsed(final Symbol t, JCTree cdef) {
403 class UsedVisitor extends TreeScanner {
404 public void scan(JCTree tree) {
405 if (tree!=null && !result) tree.accept(this);
406 }
407 boolean result = false;
408 public void visitIdent(JCIdent tree) {
409 if (tree.sym == t) result = true;
410 }
411 }
412 UsedVisitor v = new UsedVisitor();
413 v.scan(cdef);
414 return v.result;
415 }
416
417 /**************************************************************************
418 * Visitor methods
419 *************************************************************************/
420
421 public void visitTopLevel(JCCompilationUnit tree) {
422 try {
423 printUnit(tree, null);
424 } catch (IOException e) {
425 throw new UncheckedIOException(e);
426 }
427 }
428
429 public void visitImport(JCImport tree) {
430 try {
431 print("import ");
432 if (tree.staticImport) print("static ");
433 printExpr(tree.qualid);
434 print(";");
435 println();
436 } catch (IOException e) {
437 throw new UncheckedIOException(e);
438 }
439 }
440
441 public void visitClassDef(JCClassDecl tree) {
442 try {
443 println(); align();
444 printDocComment(tree);
445 printAnnotations(tree.mods.annotations);
446 printFlags(tree.mods.flags & ~INTERFACE);
447 Name enclClassNamePrev = enclClassName;
448 enclClassName = tree.name;
449 if ((tree.mods.flags & INTERFACE) != 0) {
450 print("interface " + tree.name);
451 printTypeParameters(tree.typarams);
452 if (tree.implementing.nonEmpty()) {
453 print(" extends ");
454 printExprs(tree.implementing);
455 }
456 } else {
457 if ((tree.mods.flags & ENUM) != 0)
458 print("enum " + tree.name);
459 else
460 print("class " + tree.name);
461 printTypeParameters(tree.typarams);
462 if (tree.extending != null) {
463 print(" extends ");
464 printExpr(tree.extending);
465 }
466 if (tree.implementing.nonEmpty()) {
467 print(" implements ");
468 printExprs(tree.implementing);
469 }
470 }
471 print(" ");
472 if ((tree.mods.flags & ENUM) != 0) {
473 printEnumBody(tree.defs);
474 } else {
475 printBlock(tree.defs);
476 }
477 enclClassName = enclClassNamePrev;
478 } catch (IOException e) {
479 throw new UncheckedIOException(e);
480 }
481 }
482
483 public void visitMethodDef(JCMethodDecl tree) {
484 try {
485 // when producing source output, omit anonymous constructors
486 if (tree.name == tree.name.table.names.init &&
487 enclClassName == null &&
488 sourceOutput) return;
489 println(); align();
490 printDocComment(tree);
491 printExpr(tree.mods);
492 printTypeParameters(tree.typarams);
493 if (tree.name == tree.name.table.names.init) {
494 print(enclClassName != null ? enclClassName : tree.name);
495 } else {
496 printExpr(tree.restype);
497 print(" " + tree.name);
498 }
499 print("(");
500 if (tree.recvparam!=null) {
501 printExpr(tree.recvparam);
502 if (tree.params.size() > 0) {
503 print(", ");
504 }
505 }
506 printExprs(tree.params);
507 print(")");
508 if (tree.thrown.nonEmpty()) {
509 print(" throws ");
510 printExprs(tree.thrown);
511 }
512 if (tree.defaultValue != null) {
513 print(" default ");
514 printExpr(tree.defaultValue);
515 }
516 if (tree.body != null) {
517 print(" ");
518 printStat(tree.body);
519 } else {
520 print(";");
521 }
522 } catch (IOException e) {
523 throw new UncheckedIOException(e);
524 }
525 }
526
527 public void visitVarDef(JCVariableDecl tree) {
528 try {
529 if (docComments != null && docComments.hasComment(tree)) {
530 println(); align();
531 }
532 printDocComment(tree);
533 if ((tree.mods.flags & ENUM) != 0) {
534 print("/*public static final*/ ");
535 print(tree.name);
536 if (tree.init != null) {
537 if (sourceOutput && tree.init.hasTag(NEWCLASS)) {
538 print(" /*enum*/ ");
539 JCNewClass init = (JCNewClass) tree.init;
540 if (init.args != null && init.args.nonEmpty()) {
541 print("(");
542 print(init.args);
543 print(")");
544 }
545 if (init.def != null && init.def.defs != null) {
546 print(" ");
547 printBlock(init.def.defs);
548 }
549 return;
550 }
551 print(" /* = ");
552 printExpr(tree.init);
553 print(" */");
554 }
555 } else {
556 printExpr(tree.mods);
557 if ((tree.mods.flags & VARARGS) != 0) {
558 JCTree vartype = tree.vartype;
559 List<JCAnnotation> tas = null;
560 if (vartype instanceof JCAnnotatedType) {
561 tas = ((JCAnnotatedType)vartype).annotations;
562 vartype = ((JCAnnotatedType)vartype).underlyingType;
563 }
564 printExpr(((JCArrayTypeTree) vartype).elemtype);
565 if (tas != null) {
566 print(' ');
567 printTypeAnnotations(tas);
568 }
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 }
584
585 public void visitSkip(JCSkip tree) {
586 try {
587 print(";");
588 } catch (IOException e) {
589 throw new UncheckedIOException(e);
590 }
591 }
592
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 }
601
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 }
620
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 }
637
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 }
663
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 }
676
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 }
685
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 }
705
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 }
724
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 }
741
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 }
770
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 }
781
782 public void visitConditional(JCConditional tree) {
783 try {
784 open(prec, TreeInfo.condPrec);
785 printExpr(tree.cond, TreeInfo.condPrec + 1);
786 print(" ? ");
787 printExpr(tree.truepart);
788 print(" : ");
789 printExpr(tree.falsepart, TreeInfo.condPrec);
790 close(prec, TreeInfo.condPrec);
791 } catch (IOException e) {
792 throw new UncheckedIOException(e);
793 }
794 }
795
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 }
816
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 }
825
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 }
835
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 }
845
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 }
858
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 }
868
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 }
882
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 }
908
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 if (tree.def != null && tree.def.mods.annotations.nonEmpty()) {
922 printTypeAnnotations(tree.def.mods.annotations);
923 }
924 printExpr(tree.clazz);
925 print("(");
926 printExprs(tree.args);
927 print(")");
928 if (tree.def != null) {
929 Name enclClassNamePrev = enclClassName;
930 enclClassName =
931 tree.def.name != null ? tree.def.name :
932 tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty
933 ? tree.type.tsym.name : null;
934 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
935 printBlock(tree.def.defs);
936 enclClassName = enclClassNamePrev;
937 }
938 } catch (IOException e) {
939 throw new UncheckedIOException(e);
940 }
941 }
942
943 public void visitNewArray(JCNewArray tree) {
944 try {
945 if (tree.elemtype != null) {
946 print("new ");
947 JCTree elem = tree.elemtype;
948 printBaseElementType(elem);
949
950 if (!tree.annotations.isEmpty()) {
951 print(' ');
952 printTypeAnnotations(tree.annotations);
953 }
954 if (tree.elems != null) {
955 print("[]");
956 }
957
958 int i = 0;
959 List<List<JCAnnotation>> da = tree.dimAnnotations;
960 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
961 if (da.size() > i && !da.get(i).isEmpty()) {
962 print(' ');
963 printTypeAnnotations(da.get(i));
964 }
965 print("[");
966 i++;
967 printExpr(l.head);
968 print("]");
969 }
970 printBrackets(elem);
971 }
972 if (tree.elems != null) {
973 print("{");
974 printExprs(tree.elems);
975 print("}");
976 }
977 } catch (IOException e) {
978 throw new UncheckedIOException(e);
979 }
980 }
981
982 public void visitLambda(JCLambda tree) {
983 try {
984 print("(");
985 if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT) {
986 printExprs(tree.params);
987 } else {
988 String sep = "";
989 for (JCVariableDecl param : tree.params) {
990 print(sep);
991 print(param.name);
992 sep = ",";
993 }
994 }
995 print(")->");
996 printExpr(tree.body);
997 } catch (IOException e) {
998 throw new UncheckedIOException(e);
999 }
1000 }
1001
1002 public void visitParens(JCParens tree) {
1003 try {
1004 print("(");
1005 printExpr(tree.expr);
1006 print(")");
1007 } catch (IOException e) {
1008 throw new UncheckedIOException(e);
1009 }
1010 }
1011
1012 public void visitAssign(JCAssign tree) {
1013 try {
1014 open(prec, TreeInfo.assignPrec);
1015 printExpr(tree.lhs, TreeInfo.assignPrec + 1);
1016 print(" = ");
1017 printExpr(tree.rhs, TreeInfo.assignPrec);
1018 close(prec, TreeInfo.assignPrec);
1019 } catch (IOException e) {
1020 throw new UncheckedIOException(e);
1021 }
1022 }
1023
1024 public String operatorName(JCTree.Tag tag) {
1025 switch(tag) {
1026 case POS: return "+";
1027 case NEG: return "-";
1028 case NOT: return "!";
1029 case COMPL: return "~";
1030 case PREINC: return "++";
1031 case PREDEC: return "--";
1032 case POSTINC: return "++";
1033 case POSTDEC: return "--";
1034 case NULLCHK: return "<*nullchk*>";
1035 case OR: return "||";
1036 case AND: return "&&";
1037 case EQ: return "==";
1038 case NE: return "!=";
1039 case LT: return "<";
1040 case GT: return ">";
1041 case LE: return "<=";
1042 case GE: return ">=";
1043 case BITOR: return "|";
1044 case BITXOR: return "^";
1045 case BITAND: return "&";
1046 case SL: return "<<";
1047 case SR: return ">>";
1048 case USR: return ">>>";
1049 case PLUS: return "+";
1050 case MINUS: return "-";
1051 case MUL: return "*";
1052 case DIV: return "/";
1053 case MOD: return "%";
1054 default: throw new Error();
1055 }
1056 }
1057
1058 public void visitAssignop(JCAssignOp tree) {
1059 try {
1060 open(prec, TreeInfo.assignopPrec);
1061 printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
1062 print(" " + operatorName(tree.getTag().noAssignOp()) + "= ");
1063 printExpr(tree.rhs, TreeInfo.assignopPrec);
1064 close(prec, TreeInfo.assignopPrec);
1065 } catch (IOException e) {
1066 throw new UncheckedIOException(e);
1067 }
1068 }
1069
1070 public void visitUnary(JCUnary tree) {
1071 try {
1072 int ownprec = TreeInfo.opPrec(tree.getTag());
1073 String opname = operatorName(tree.getTag());
1074 open(prec, ownprec);
1075 if (!tree.getTag().isPostUnaryOp()) {
1076 print(opname);
1077 printExpr(tree.arg, ownprec);
1078 } else {
1079 printExpr(tree.arg, ownprec);
1080 print(opname);
1081 }
1082 close(prec, ownprec);
1083 } catch (IOException e) {
1084 throw new UncheckedIOException(e);
1085 }
1086 }
1087
1088 public void visitBinary(JCBinary tree) {
1089 try {
1090 int ownprec = TreeInfo.opPrec(tree.getTag());
1091 String opname = operatorName(tree.getTag());
1092 open(prec, ownprec);
1093 printExpr(tree.lhs, ownprec);
1094 print(" " + opname + " ");
1095 printExpr(tree.rhs, ownprec + 1);
1096 close(prec, ownprec);
1097 } catch (IOException e) {
1098 throw new UncheckedIOException(e);
1099 }
1100 }
1101
1102 public void visitTypeCast(JCTypeCast tree) {
1103 try {
1104 open(prec, TreeInfo.prefixPrec);
1105 print("(");
1106 printExpr(tree.clazz);
1107 print(")");
1108 printExpr(tree.expr, TreeInfo.prefixPrec);
1109 close(prec, TreeInfo.prefixPrec);
1110 } catch (IOException e) {
1111 throw new UncheckedIOException(e);
1112 }
1113 }
1114
1115 public void visitTypeTest(JCInstanceOf tree) {
1116 try {
1117 open(prec, TreeInfo.ordPrec);
1118 printExpr(tree.expr, TreeInfo.ordPrec);
1119 print(" instanceof ");
1120 printExpr(tree.clazz, TreeInfo.ordPrec + 1);
1121 close(prec, TreeInfo.ordPrec);
1122 } catch (IOException e) {
1123 throw new UncheckedIOException(e);
1124 }
1125 }
1126
1127 public void visitIndexed(JCArrayAccess tree) {
1128 try {
1129 printExpr(tree.indexed, TreeInfo.postfixPrec);
1130 print("[");
1131 printExpr(tree.index);
1132 print("]");
1133 } catch (IOException e) {
1134 throw new UncheckedIOException(e);
1135 }
1136 }
1137
1138 public void visitSelect(JCFieldAccess tree) {
1139 try {
1140 printExpr(tree.selected, TreeInfo.postfixPrec);
1141 print("." + tree.name);
1142 } catch (IOException e) {
1143 throw new UncheckedIOException(e);
1144 }
1145 }
1146
1147 public void visitReference(JCMemberReference tree) {
1148 try {
1149 printExpr(tree.expr);
1150 print("::");
1151 if (tree.typeargs != null) {
1152 print("<");
1153 printExprs(tree.typeargs);
1154 print(">");
1155 }
1156 print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
1157 } catch (IOException e) {
1158 throw new UncheckedIOException(e);
1159 }
1160 }
1161
1162 public void visitIdent(JCIdent tree) {
1163 try {
1164 print(tree.name);
1165 } catch (IOException e) {
1166 throw new UncheckedIOException(e);
1167 }
1168 }
1169
1170 public void visitLiteral(JCLiteral tree) {
1171 try {
1172 switch (tree.typetag) {
1173 case INT:
1174 print(tree.value.toString());
1175 break;
1176 case LONG:
1177 print(tree.value + "L");
1178 break;
1179 case FLOAT:
1180 print(tree.value + "F");
1181 break;
1182 case DOUBLE:
1183 print(tree.value.toString());
1184 break;
1185 case CHAR:
1186 print("\'" +
1187 Convert.quote(
1188 String.valueOf((char)((Number)tree.value).intValue())) +
1189 "\'");
1190 break;
1191 case BOOLEAN:
1192 print(((Number)tree.value).intValue() == 1 ? "true" : "false");
1193 break;
1194 case BOT:
1195 print("null");
1196 break;
1197 default:
1198 print("\"" + Convert.quote(tree.value.toString()) + "\"");
1199 break;
1200 }
1201 } catch (IOException e) {
1202 throw new UncheckedIOException(e);
1203 }
1204 }
1205
1206 public void visitTypeIdent(JCPrimitiveTypeTree tree) {
1207 try {
1208 switch(tree.typetag) {
1209 case BYTE:
1210 print("byte");
1211 break;
1212 case CHAR:
1213 print("char");
1214 break;
1215 case SHORT:
1216 print("short");
1217 break;
1218 case INT:
1219 print("int");
1220 break;
1221 case LONG:
1222 print("long");
1223 break;
1224 case FLOAT:
1225 print("float");
1226 break;
1227 case DOUBLE:
1228 print("double");
1229 break;
1230 case BOOLEAN:
1231 print("boolean");
1232 break;
1233 case VOID:
1234 print("void");
1235 break;
1236 default:
1237 print("error");
1238 break;
1239 }
1240 } catch (IOException e) {
1241 throw new UncheckedIOException(e);
1242 }
1243 }
1244
1245 public void visitTypeArray(JCArrayTypeTree tree) {
1246 try {
1247 printBaseElementType(tree);
1248 printBrackets(tree);
1249 } catch (IOException e) {
1250 throw new UncheckedIOException(e);
1251 }
1252 }
1253
1254 // Prints the inner element type of a nested array
1255 private void printBaseElementType(JCTree tree) throws IOException {
1256 printExpr(TreeInfo.innermostType(tree));
1257 }
1258
1259 // prints the brackets of a nested array in reverse order
1260 // tree is either JCArrayTypeTree or JCAnnotatedTypeTree
1261 private void printBrackets(JCTree tree) throws IOException {
1262 JCTree elem = tree;
1263 while (true) {
1264 if (elem.hasTag(ANNOTATED_TYPE)) {
1265 JCAnnotatedType atype = (JCAnnotatedType) elem;
1266 elem = atype.underlyingType;
1267 if (elem.hasTag(TYPEARRAY)) {
1268 print(' ');
1269 printTypeAnnotations(atype.annotations);
1270 }
1271 }
1272 if (elem.hasTag(TYPEARRAY)) {
1273 print("[]");
1274 elem = ((JCArrayTypeTree)elem).elemtype;
1275 } else {
1276 break;
1277 }
1278 }
1279 }
1280
1281 public void visitTypeApply(JCTypeApply tree) {
1282 try {
1283 printExpr(tree.clazz);
1284 print("<");
1285 printExprs(tree.arguments);
1286 print(">");
1287 } catch (IOException e) {
1288 throw new UncheckedIOException(e);
1289 }
1290 }
1291
1292 public void visitTypeUnion(JCTypeUnion tree) {
1293 try {
1294 printExprs(tree.alternatives, " | ");
1295 } catch (IOException e) {
1296 throw new UncheckedIOException(e);
1297 }
1298 }
1299
1300 public void visitTypeIntersection(JCTypeIntersection tree) {
1301 try {
1302 printExprs(tree.bounds, " & ");
1303 } catch (IOException e) {
1304 throw new UncheckedIOException(e);
1305 }
1306 }
1307
1308 public void visitTypeParameter(JCTypeParameter tree) {
1309 try {
1310 if (tree.annotations.nonEmpty()) {
1311 this.printTypeAnnotations(tree.annotations);
1312 }
1313 print(tree.name);
1314 if (tree.bounds.nonEmpty()) {
1315 print(" extends ");
1316 printExprs(tree.bounds, " & ");
1317 }
1318 } catch (IOException e) {
1319 throw new UncheckedIOException(e);
1320 }
1321 }
1322
1323 @Override
1324 public void visitWildcard(JCWildcard tree) {
1325 try {
1326 print(tree.kind);
1327 if (tree.kind.kind != BoundKind.UNBOUND)
1328 printExpr(tree.inner);
1329 } catch (IOException e) {
1330 throw new UncheckedIOException(e);
1331 }
1332 }
1333
1334 @Override
1335 public void visitTypeBoundKind(TypeBoundKind tree) {
1336 try {
1337 print(String.valueOf(tree.kind));
1338 } catch (IOException e) {
1339 throw new UncheckedIOException(e);
1340 }
1341 }
1342
1343 public void visitErroneous(JCErroneous tree) {
1344 try {
1345 print("(ERROR)");
1346 } catch (IOException e) {
1347 throw new UncheckedIOException(e);
1348 }
1349 }
1350
1351 public void visitLetExpr(LetExpr tree) {
1352 try {
1353 print("(let " + tree.defs + " in " + tree.expr + ")");
1354 } catch (IOException e) {
1355 throw new UncheckedIOException(e);
1356 }
1357 }
1358
1359 public void visitModifiers(JCModifiers mods) {
1360 try {
1361 printAnnotations(mods.annotations);
1362 printFlags(mods.flags);
1363 } catch (IOException e) {
1364 throw new UncheckedIOException(e);
1365 }
1366 }
1367
1368 public void visitAnnotation(JCAnnotation tree) {
1369 try {
1370 print("@");
1371 printExpr(tree.annotationType);
1372 print("(");
1373 printExprs(tree.args);
1374 print(")");
1375 } catch (IOException e) {
1376 throw new UncheckedIOException(e);
1377 }
1378 }
1379
1380 public void visitAnnotatedType(JCAnnotatedType tree) {
1381 try {
1382 if (tree.underlyingType.hasTag(SELECT)) {
1383 JCFieldAccess access = (JCFieldAccess) tree.underlyingType;
1384 printExpr(access.selected, TreeInfo.postfixPrec);
1385 print(".");
1386 printTypeAnnotations(tree.annotations);
1387 print(access.name);
1388 } else if (tree.underlyingType.hasTag(TYPEARRAY)) {
1389 printBaseElementType(tree);
1390 printBrackets(tree);
1391 } else {
1392 printTypeAnnotations(tree.annotations);
1393 printExpr(tree.underlyingType);
1394 }
1395 } catch (IOException e) {
1396 throw new UncheckedIOException(e);
1397 }
1398 }
1399
1400 public void visitTree(JCTree tree) {
1401 try {
1402 print("(UNKNOWN: " + tree + ")");
1403 println();
1404 } catch (IOException e) {
1405 throw new UncheckedIOException(e);
1406 }
1407 }
1408
1409 }

mercurial