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