1 /* 2 * Copyright (c) 1999, 2011, 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 import java.util.*; 30 31 import com.sun.tools.javac.util.*; 32 import com.sun.tools.javac.util.List; 33 import com.sun.tools.javac.code.*; 34 35 import com.sun.tools.javac.code.Symbol.*; 36 import com.sun.tools.javac.tree.JCTree.*; 37 38 import static com.sun.tools.javac.code.Flags.*; 39 40 /** Prints out a tree as an indented Java source program. 41 * 42 * <p><b>This is NOT part of any supported API. 43 * If you write code that depends on this, you do so at your own risk. 44 * This code and its internal interfaces are subject to change or 45 * deletion without notice.</b> 46 */ 47 public class Pretty extends JCTree.Visitor { 48 49 public Pretty(Writer out, boolean sourceOutput) { 50 this.out = out; 51 this.sourceOutput = sourceOutput; 52 } 53 54 /** Set when we are producing source output. If we're not 55 * producing source output, we can sometimes give more detail in 56 * the output even though that detail would not be valid java 57 * source. 58 */ 59 private final boolean sourceOutput; 60 61 /** The output stream on which trees are printed. 62 */ 63 Writer out; 64 65 /** Indentation width (can be reassigned from outside). 66 */ 67 public int width = 4; 68 69 /** The current left margin. 70 */ 71 int lmargin = 0; 72 73 /** The enclosing class name. 74 */ 75 Name enclClassName; 76 77 /** A hashtable mapping trees to their documentation comments 78 * (can be null) 79 */ 80 Map<JCTree, String> docComments = null; 81 82 /** Align code to be indented to left margin. 83 */ 84 void align() throws IOException { 85 for (int i = 0; i < lmargin; i++) out.write(" "); 86 } 87 88 /** Increase left margin by indentation width. 89 */ 90 void indent() { 91 lmargin = lmargin + width; 92 } 93 94 /** Decrease left margin by indentation width. 95 */ 96 void undent() { 97 lmargin = lmargin - width; 98 } 99 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 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 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 String lineSep = System.getProperty("line.separator"); 131 132 /************************************************************************** 133 * Traversal methods 134 *************************************************************************/ 135 136 /** Exception to propogate IOException through visitXXX methods */ 137 private static class UncheckedIOException extends Error { 138 static final long serialVersionUID = -4032692679158424751L; 139 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.defaultValue != null) { 463 print(" default "); 464 printExpr(tree.defaultValue); 465 } 466 if (tree.body != null) { 467 print(" "); 468 printStat(tree.body); 469 } else { 470 print(";"); 471 } 472 } catch (IOException e) { 473 throw new UncheckedIOException(e); 474 } 475 } 476 477 public void visitVarDef(JCVariableDecl tree) { 478 try { 479 if (docComments != null && docComments.get(tree) != null) { 480 println(); align(); 481 } 482 printDocComment(tree); 483 if ((tree.mods.flags & ENUM) != 0) { 484 print("/*public static final*/ "); 485 print(tree.name); 486 if (tree.init != null) { 487 if (sourceOutput && tree.init.getTag() == JCTree.NEWCLASS) { 488 print(" /*enum*/ "); 489 JCNewClass init = (JCNewClass) tree.init; 490 if (init.args != null && init.args.nonEmpty()) { 491 print("("); 492 print(init.args); 493 print(")"); 494 } 495 if (init.def != null && init.def.defs != null) { 496 print(" "); 497 printBlock(init.def.defs); 498 } 499 return; 500 } 501 print(" /* = "); 502 printExpr(tree.init); 503 print(" */"); 504 } 505 } else { 506 printExpr(tree.mods); 507 if ((tree.mods.flags & VARARGS) != 0) { 508 printExpr(((JCArrayTypeTree) tree.vartype).elemtype); 509 print("... " + tree.name); 510 } else { 511 printExpr(tree.vartype); 512 print(" " + tree.name); 513 } 514 if (tree.init != null) { 515 print(" = "); 516 printExpr(tree.init); 517 } 518 if (prec == TreeInfo.notExpression) print(";"); 519 } 520 } catch (IOException e) { 521 throw new UncheckedIOException(e); 522 } 523 } 524 525 public void visitSkip(JCSkip tree) { 526 try { 527 print(";"); 528 } catch (IOException e) { 529 throw new UncheckedIOException(e); 530 } 531 } 532 533 public void visitBlock(JCBlock tree) { 534 try { 535 printFlags(tree.flags); 536 printBlock(tree.stats); 537 } catch (IOException e) { 538 throw new UncheckedIOException(e); 539 } 540 } 541 542 public void visitDoLoop(JCDoWhileLoop tree) { 543 try { 544 print("do "); 545 printStat(tree.body); 546 align(); 547 print(" while "); 548 if (tree.cond.getTag() == JCTree.PARENS) { 549 printExpr(tree.cond); 550 } else { 551 print("("); 552 printExpr(tree.cond); 553 print(")"); 554 } 555 print(";"); 556 } catch (IOException e) { 557 throw new UncheckedIOException(e); 558 } 559 } 560 561 public void visitWhileLoop(JCWhileLoop tree) { 562 try { 563 print("while "); 564 if (tree.cond.getTag() == JCTree.PARENS) { 565 printExpr(tree.cond); 566 } else { 567 print("("); 568 printExpr(tree.cond); 569 print(")"); 570 } 571 print(" "); 572 printStat(tree.body); 573 } catch (IOException e) { 574 throw new UncheckedIOException(e); 575 } 576 } 577 578 public void visitForLoop(JCForLoop tree) { 579 try { 580 print("for ("); 581 if (tree.init.nonEmpty()) { 582 if (tree.init.head.getTag() == JCTree.VARDEF) { 583 printExpr(tree.init.head); 584 for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) { 585 JCVariableDecl vdef = (JCVariableDecl)l.head; 586 print(", " + vdef.name + " = "); 587 printExpr(vdef.init); 588 } 589 } else { 590 printExprs(tree.init); 591 } 592 } 593 print("; "); 594 if (tree.cond != null) printExpr(tree.cond); 595 print("; "); 596 printExprs(tree.step); 597 print(") "); 598 printStat(tree.body); 599 } catch (IOException e) { 600 throw new UncheckedIOException(e); 601 } 602 } 603 604 public void visitForeachLoop(JCEnhancedForLoop tree) { 605 try { 606 print("for ("); 607 printExpr(tree.var); 608 print(" : "); 609 printExpr(tree.expr); 610 print(") "); 611 printStat(tree.body); 612 } catch (IOException e) { 613 throw new UncheckedIOException(e); 614 } 615 } 616 617 public void visitLabelled(JCLabeledStatement tree) { 618 try { 619 print(tree.label + ": "); 620 printStat(tree.body); 621 } catch (IOException e) { 622 throw new UncheckedIOException(e); 623 } 624 } 625 626 public void visitSwitch(JCSwitch tree) { 627 try { 628 print("switch "); 629 if (tree.selector.getTag() == JCTree.PARENS) { 630 printExpr(tree.selector); 631 } else { 632 print("("); 633 printExpr(tree.selector); 634 print(")"); 635 } 636 print(" {"); 637 println(); 638 printStats(tree.cases); 639 align(); 640 print("}"); 641 } catch (IOException e) { 642 throw new UncheckedIOException(e); 643 } 644 } 645 646 public void visitCase(JCCase tree) { 647 try { 648 if (tree.pat == null) { 649 print("default"); 650 } else { 651 print("case "); 652 printExpr(tree.pat); 653 } 654 print(": "); 655 println(); 656 indent(); 657 printStats(tree.stats); 658 undent(); 659 align(); 660 } catch (IOException e) { 661 throw new UncheckedIOException(e); 662 } 663 } 664 665 public void visitSynchronized(JCSynchronized tree) { 666 try { 667 print("synchronized "); 668 if (tree.lock.getTag() == JCTree.PARENS) { 669 printExpr(tree.lock); 670 } else { 671 print("("); 672 printExpr(tree.lock); 673 print(")"); 674 } 675 print(" "); 676 printStat(tree.body); 677 } catch (IOException e) { 678 throw new UncheckedIOException(e); 679 } 680 } 681 682 public void visitTry(JCTry tree) { 683 try { 684 print("try "); 685 if (tree.resources.nonEmpty()) { 686 print("("); 687 boolean first = true; 688 for (JCTree var : tree.resources) { 689 if (!first) { 690 println(); 691 indent(); 692 } 693 printStat(var); 694 first = false; 695 } 696 print(") "); 697 } 698 printStat(tree.body); 699 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 700 printStat(l.head); 701 } 702 if (tree.finalizer != null) { 703 print(" finally "); 704 printStat(tree.finalizer); 705 } 706 } catch (IOException e) { 707 throw new UncheckedIOException(e); 708 } 709 } 710 711 public void visitCatch(JCCatch tree) { 712 try { 713 print(" catch ("); 714 printExpr(tree.param); 715 print(") "); 716 printStat(tree.body); 717 } catch (IOException e) { 718 throw new UncheckedIOException(e); 719 } 720 } 721 722 public void visitConditional(JCConditional tree) { 723 try { 724 open(prec, TreeInfo.condPrec); 725 printExpr(tree.cond, TreeInfo.condPrec); 726 print(" ? "); 727 printExpr(tree.truepart, TreeInfo.condPrec); 728 print(" : "); 729 printExpr(tree.falsepart, TreeInfo.condPrec); 730 close(prec, TreeInfo.condPrec); 731 } catch (IOException e) { 732 throw new UncheckedIOException(e); 733 } 734 } 735 736 public void visitIf(JCIf tree) { 737 try { 738 print("if "); 739 if (tree.cond.getTag() == JCTree.PARENS) { 740 printExpr(tree.cond); 741 } else { 742 print("("); 743 printExpr(tree.cond); 744 print(")"); 745 } 746 print(" "); 747 printStat(tree.thenpart); 748 if (tree.elsepart != null) { 749 print(" else "); 750 printStat(tree.elsepart); 751 } 752 } catch (IOException e) { 753 throw new UncheckedIOException(e); 754 } 755 } 756 757 public void visitExec(JCExpressionStatement tree) { 758 try { 759 printExpr(tree.expr); 760 if (prec == TreeInfo.notExpression) print(";"); 761 } catch (IOException e) { 762 throw new UncheckedIOException(e); 763 } 764 } 765 766 public void visitBreak(JCBreak tree) { 767 try { 768 print("break"); 769 if (tree.label != null) print(" " + tree.label); 770 print(";"); 771 } catch (IOException e) { 772 throw new UncheckedIOException(e); 773 } 774 } 775 776 public void visitContinue(JCContinue tree) { 777 try { 778 print("continue"); 779 if (tree.label != null) print(" " + tree.label); 780 print(";"); 781 } catch (IOException e) { 782 throw new UncheckedIOException(e); 783 } 784 } 785 786 public void visitReturn(JCReturn tree) { 787 try { 788 print("return"); 789 if (tree.expr != null) { 790 print(" "); 791 printExpr(tree.expr); 792 } 793 print(";"); 794 } catch (IOException e) { 795 throw new UncheckedIOException(e); 796 } 797 } 798 799 public void visitThrow(JCThrow tree) { 800 try { 801 print("throw "); 802 printExpr(tree.expr); 803 print(";"); 804 } catch (IOException e) { 805 throw new UncheckedIOException(e); 806 } 807 } 808 809 public void visitAssert(JCAssert tree) { 810 try { 811 print("assert "); 812 printExpr(tree.cond); 813 if (tree.detail != null) { 814 print(" : "); 815 printExpr(tree.detail); 816 } 817 print(";"); 818 } catch (IOException e) { 819 throw new UncheckedIOException(e); 820 } 821 } 822 823 public void visitApply(JCMethodInvocation tree) { 824 try { 825 if (!tree.typeargs.isEmpty()) { 826 if (tree.meth.getTag() == JCTree.SELECT) { 827 JCFieldAccess left = (JCFieldAccess)tree.meth; 828 printExpr(left.selected); 829 print(".<"); 830 printExprs(tree.typeargs); 831 print(">" + left.name); 832 } else { 833 print("<"); 834 printExprs(tree.typeargs); 835 print(">"); 836 printExpr(tree.meth); 837 } 838 } else { 839 printExpr(tree.meth); 840 } 841 print("("); 842 printExprs(tree.args); 843 print(")"); 844 } catch (IOException e) { 845 throw new UncheckedIOException(e); 846 } 847 } 848 849 public void visitNewClass(JCNewClass tree) { 850 try { 851 if (tree.encl != null) { 852 printExpr(tree.encl); 853 print("."); 854 } 855 print("new "); 856 if (!tree.typeargs.isEmpty()) { 857 print("<"); 858 printExprs(tree.typeargs); 859 print(">"); 860 } 861 printExpr(tree.clazz); 862 print("("); 863 printExprs(tree.args); 864 print(")"); 865 if (tree.def != null) { 866 Name enclClassNamePrev = enclClassName; 867 enclClassName = 868 tree.def.name != null ? tree.def.name : 869 tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty 870 ? tree.type.tsym.name : null; 871 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/"); 872 printBlock(tree.def.defs); 873 enclClassName = enclClassNamePrev; 874 } 875 } catch (IOException e) { 876 throw new UncheckedIOException(e); 877 } 878 } 879 880 public void visitNewArray(JCNewArray tree) { 881 try { 882 if (tree.elemtype != null) { 883 print("new "); 884 JCTree elem = tree.elemtype; 885 if (elem.getTag() == JCTree.TYPEARRAY) 886 printBaseElementType((JCArrayTypeTree) elem); 887 else 888 printExpr(elem); 889 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { 890 print("["); 891 printExpr(l.head); 892 print("]"); 893 } 894 if (elem instanceof JCArrayTypeTree) 895 printBrackets((JCArrayTypeTree) elem); 896 } 897 if (tree.elems != null) { 898 if (tree.elemtype != null) print("[]"); 899 print("{"); 900 printExprs(tree.elems); 901 print("}"); 902 } 903 } catch (IOException e) { 904 throw new UncheckedIOException(e); 905 } 906 } 907 908 public void visitParens(JCParens tree) { 909 try { 910 print("("); 911 printExpr(tree.expr); 912 print(")"); 913 } catch (IOException e) { 914 throw new UncheckedIOException(e); 915 } 916 } 917 918 public void visitAssign(JCAssign tree) { 919 try { 920 open(prec, TreeInfo.assignPrec); 921 printExpr(tree.lhs, TreeInfo.assignPrec + 1); 922 print(" = "); 923 printExpr(tree.rhs, TreeInfo.assignPrec); 924 close(prec, TreeInfo.assignPrec); 925 } catch (IOException e) { 926 throw new UncheckedIOException(e); 927 } 928 } 929 930 public String operatorName(int tag) { 931 switch(tag) { 932 case JCTree.POS: return "+"; 933 case JCTree.NEG: return "-"; 934 case JCTree.NOT: return "!"; 935 case JCTree.COMPL: return "~"; 936 case JCTree.PREINC: return "++"; 937 case JCTree.PREDEC: return "--"; 938 case JCTree.POSTINC: return "++"; 939 case JCTree.POSTDEC: return "--"; 940 case JCTree.NULLCHK: return "<*nullchk*>"; 941 case JCTree.OR: return "||"; 942 case JCTree.AND: return "&&"; 943 case JCTree.EQ: return "=="; 944 case JCTree.NE: return "!="; 945 case JCTree.LT: return "<"; 946 case JCTree.GT: return ">"; 947 case JCTree.LE: return "<="; 948 case JCTree.GE: return ">="; 949 case JCTree.BITOR: return "|"; 950 case JCTree.BITXOR: return "^"; 951 case JCTree.BITAND: return "&"; 952 case JCTree.SL: return "<<"; 953 case JCTree.SR: return ">>"; 954 case JCTree.USR: return ">>>"; 955 case JCTree.PLUS: return "+"; 956 case JCTree.MINUS: return "-"; 957 case JCTree.MUL: return "*"; 958 case JCTree.DIV: return "/"; 959 case JCTree.MOD: return "%"; 960 default: throw new Error(); 961 } 962 } 963 964 public void visitAssignop(JCAssignOp tree) { 965 try { 966 open(prec, TreeInfo.assignopPrec); 967 printExpr(tree.lhs, TreeInfo.assignopPrec + 1); 968 print(" " + operatorName(tree.getTag() - JCTree.ASGOffset) + "= "); 969 printExpr(tree.rhs, TreeInfo.assignopPrec); 970 close(prec, TreeInfo.assignopPrec); 971 } catch (IOException e) { 972 throw new UncheckedIOException(e); 973 } 974 } 975 976 public void visitUnary(JCUnary tree) { 977 try { 978 int ownprec = TreeInfo.opPrec(tree.getTag()); 979 String opname = operatorName(tree.getTag()); 980 open(prec, ownprec); 981 if (tree.getTag() <= JCTree.PREDEC) { 982 print(opname); 983 printExpr(tree.arg, ownprec); 984 } else { 985 printExpr(tree.arg, ownprec); 986 print(opname); 987 } 988 close(prec, ownprec); 989 } catch (IOException e) { 990 throw new UncheckedIOException(e); 991 } 992 } 993 994 public void visitBinary(JCBinary tree) { 995 try { 996 int ownprec = TreeInfo.opPrec(tree.getTag()); 997 String opname = operatorName(tree.getTag()); 998 open(prec, ownprec); 999 printExpr(tree.lhs, ownprec); 1000 print(" " + opname + " "); 1001 printExpr(tree.rhs, ownprec + 1); 1002 close(prec, ownprec); 1003 } catch (IOException e) { 1004 throw new UncheckedIOException(e); 1005 } 1006 } 1007 1008 public void visitTypeCast(JCTypeCast tree) { 1009 try { 1010 open(prec, TreeInfo.prefixPrec); 1011 print("("); 1012 printExpr(tree.clazz); 1013 print(")"); 1014 printExpr(tree.expr, TreeInfo.prefixPrec); 1015 close(prec, TreeInfo.prefixPrec); 1016 } catch (IOException e) { 1017 throw new UncheckedIOException(e); 1018 } 1019 } 1020 1021 public void visitTypeTest(JCInstanceOf tree) { 1022 try { 1023 open(prec, TreeInfo.ordPrec); 1024 printExpr(tree.expr, TreeInfo.ordPrec); 1025 print(" instanceof "); 1026 printExpr(tree.clazz, TreeInfo.ordPrec + 1); 1027 close(prec, TreeInfo.ordPrec); 1028 } catch (IOException e) { 1029 throw new UncheckedIOException(e); 1030 } 1031 } 1032 1033 public void visitIndexed(JCArrayAccess tree) { 1034 try { 1035 printExpr(tree.indexed, TreeInfo.postfixPrec); 1036 print("["); 1037 printExpr(tree.index); 1038 print("]"); 1039 } catch (IOException e) { 1040 throw new UncheckedIOException(e); 1041 } 1042 } 1043 1044 public void visitSelect(JCFieldAccess tree) { 1045 try { 1046 printExpr(tree.selected, TreeInfo.postfixPrec); 1047 print("." + tree.name); 1048 } catch (IOException e) { 1049 throw new UncheckedIOException(e); 1050 } 1051 } 1052 1053 public void visitIdent(JCIdent tree) { 1054 try { 1055 print(tree.name); 1056 } catch (IOException e) { 1057 throw new UncheckedIOException(e); 1058 } 1059 } 1060 1061 public void visitLiteral(JCLiteral tree) { 1062 try { 1063 switch (tree.typetag) { 1064 case TypeTags.INT: 1065 print(tree.value.toString()); 1066 break; 1067 case TypeTags.LONG: 1068 print(tree.value + "L"); 1069 break; 1070 case TypeTags.FLOAT: 1071 print(tree.value + "F"); 1072 break; 1073 case TypeTags.DOUBLE: 1074 print(tree.value.toString()); 1075 break; 1076 case TypeTags.CHAR: 1077 print("\'" + 1078 Convert.quote( 1079 String.valueOf((char)((Number)tree.value).intValue())) + 1080 "\'"); 1081 break; 1082 case TypeTags.BOOLEAN: 1083 print(((Number)tree.value).intValue() == 1 ? "true" : "false"); 1084 break; 1085 case TypeTags.BOT: 1086 print("null"); 1087 break; 1088 default: 1089 print("\"" + Convert.quote(tree.value.toString()) + "\""); 1090 break; 1091 } 1092 } catch (IOException e) { 1093 throw new UncheckedIOException(e); 1094 } 1095 } 1096 1097 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 1098 try { 1099 switch(tree.typetag) { 1100 case TypeTags.BYTE: 1101 print("byte"); 1102 break; 1103 case TypeTags.CHAR: 1104 print("char"); 1105 break; 1106 case TypeTags.SHORT: 1107 print("short"); 1108 break; 1109 case TypeTags.INT: 1110 print("int"); 1111 break; 1112 case TypeTags.LONG: 1113 print("long"); 1114 break; 1115 case TypeTags.FLOAT: 1116 print("float"); 1117 break; 1118 case TypeTags.DOUBLE: 1119 print("double"); 1120 break; 1121 case TypeTags.BOOLEAN: 1122 print("boolean"); 1123 break; 1124 case TypeTags.VOID: 1125 print("void"); 1126 break; 1127 default: 1128 print("error"); 1129 break; 1130 } 1131 } catch (IOException e) { 1132 throw new UncheckedIOException(e); 1133 } 1134 } 1135 1136 public void visitTypeArray(JCArrayTypeTree tree) { 1137 try { 1138 printBaseElementType(tree); 1139 printBrackets(tree); 1140 } catch (IOException e) { 1141 throw new UncheckedIOException(e); 1142 } 1143 } 1144 1145 // Prints the inner element type of a nested array 1146 private void printBaseElementType(JCTree tree) throws IOException { 1147 printExpr(TreeInfo.innermostType(tree)); 1148 } 1149 1150 // prints the brackets of a nested array in reverse order 1151 private void printBrackets(JCArrayTypeTree tree) throws IOException { 1152 JCTree elem; 1153 while (true) { 1154 elem = tree.elemtype; 1155 print("[]"); 1156 if (elem.getTag() != JCTree.TYPEARRAY) break; 1157 tree = (JCArrayTypeTree) elem; 1158 } 1159 } 1160 1161 public void visitTypeApply(JCTypeApply tree) { 1162 try { 1163 printExpr(tree.clazz); 1164 print("<"); 1165 printExprs(tree.arguments); 1166 print(">"); 1167 } catch (IOException e) { 1168 throw new UncheckedIOException(e); 1169 } 1170 } 1171 1172 public void visitTypeDisjunction(JCTypeDisjunction tree) { 1173 try { 1174 printExprs(tree.alternatives, " | "); 1175 } catch (IOException e) { 1176 throw new UncheckedIOException(e); 1177 } 1178 } 1179 1180 public void visitTypeParameter(JCTypeParameter tree) { 1181 try { 1182 print(tree.name); 1183 if (tree.bounds.nonEmpty()) { 1184 print(" extends "); 1185 printExprs(tree.bounds, " & "); 1186 } 1187 } catch (IOException e) { 1188 throw new UncheckedIOException(e); 1189 } 1190 } 1191 1192 @Override 1193 public void visitWildcard(JCWildcard tree) { 1194 try { 1195 print(tree.kind); 1196 if (tree.kind.kind != BoundKind.UNBOUND) 1197 printExpr(tree.inner); 1198 } catch (IOException e) { 1199 throw new UncheckedIOException(e); 1200 } 1201 } 1202 1203 @Override 1204 public void visitTypeBoundKind(TypeBoundKind tree) { 1205 try { 1206 print(String.valueOf(tree.kind)); 1207 } catch (IOException e) { 1208 throw new UncheckedIOException(e); 1209 } 1210 } 1211 1212 public void visitErroneous(JCErroneous tree) { 1213 try { 1214 print("(ERROR)"); 1215 } catch (IOException e) { 1216 throw new UncheckedIOException(e); 1217 } 1218 } 1219 1220 public void visitLetExpr(LetExpr tree) { 1221 try { 1222 print("(let " + tree.defs + " in " + tree.expr + ")"); 1223 } catch (IOException e) { 1224 throw new UncheckedIOException(e); 1225 } 1226 } 1227 1228 public void visitModifiers(JCModifiers mods) { 1229 try { 1230 printAnnotations(mods.annotations); 1231 printFlags(mods.flags); 1232 } catch (IOException e) { 1233 throw new UncheckedIOException(e); 1234 } 1235 } 1236 1237 public void visitAnnotation(JCAnnotation tree) { 1238 try { 1239 print("@"); 1240 printExpr(tree.annotationType); 1241 print("("); 1242 printExprs(tree.args); 1243 print(")"); 1244 } catch (IOException e) { 1245 throw new UncheckedIOException(e); 1246 } 1247 } 1248 1249 public void visitTree(JCTree tree) { 1250 try { 1251 print("(UNKNOWN: " + tree + ")"); 1252 println(); 1253 } catch (IOException e) { 1254 throw new UncheckedIOException(e); 1255 } 1256 } 1257 1258 }