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