1 | /* |
2 | * Copyright 1999-2006 Sun Microsystems, Inc. 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. Sun designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
23 | * have any 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 API supported by Sun Microsystems. If |
43 | * 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 | * soruce. |
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.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.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.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 | print(tree.name); |
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("... " + tree.name); |
492 | } else { |
493 | printExpr(tree.vartype); |
494 | print(" " + tree.name); |
495 | } |
496 | if (tree.init != null) { |
497 | print(" = "); |
498 | printExpr(tree.init); |
499 | } |
500 | if (prec == TreeInfo.notExpression) print(";"); |
501 | } |
502 | } catch (IOException e) { |
503 | throw new UncheckedIOException(e); |
504 | } |
505 | } |
506 | |
507 | public void visitSkip(JCSkip tree) { |
508 | try { |
509 | print(";"); |
510 | } catch (IOException e) { |
511 | throw new UncheckedIOException(e); |
512 | } |
513 | } |
514 | |
515 | public void visitBlock(JCBlock tree) { |
516 | try { |
517 | printFlags(tree.flags); |
518 | printBlock(tree.stats); |
519 | } catch (IOException e) { |
520 | throw new UncheckedIOException(e); |
521 | } |
522 | } |
523 | |
524 | public void visitDoLoop(JCDoWhileLoop tree) { |
525 | try { |
526 | print("do "); |
527 | printStat(tree.body); |
528 | align(); |
529 | print(" while "); |
530 | if (tree.cond.getTag() == JCTree.PARENS) { |
531 | printExpr(tree.cond); |
532 | } else { |
533 | print("("); |
534 | printExpr(tree.cond); |
535 | print(")"); |
536 | } |
537 | print(";"); |
538 | } catch (IOException e) { |
539 | throw new UncheckedIOException(e); |
540 | } |
541 | } |
542 | |
543 | public void visitWhileLoop(JCWhileLoop tree) { |
544 | try { |
545 | print("while "); |
546 | if (tree.cond.getTag() == JCTree.PARENS) { |
547 | printExpr(tree.cond); |
548 | } else { |
549 | print("("); |
550 | printExpr(tree.cond); |
551 | print(")"); |
552 | } |
553 | print(" "); |
554 | printStat(tree.body); |
555 | } catch (IOException e) { |
556 | throw new UncheckedIOException(e); |
557 | } |
558 | } |
559 | |
560 | public void visitForLoop(JCForLoop tree) { |
561 | try { |
562 | print("for ("); |
563 | if (tree.init.nonEmpty()) { |
564 | if (tree.init.head.getTag() == JCTree.VARDEF) { |
565 | printExpr(tree.init.head); |
566 | for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) { |
567 | JCVariableDecl vdef = (JCVariableDecl)l.head; |
568 | print(", " + vdef.name + " = "); |
569 | printExpr(vdef.init); |
570 | } |
571 | } else { |
572 | printExprs(tree.init); |
573 | } |
574 | } |
575 | print("; "); |
576 | if (tree.cond != null) printExpr(tree.cond); |
577 | print("; "); |
578 | printExprs(tree.step); |
579 | print(") "); |
580 | printStat(tree.body); |
581 | } catch (IOException e) { |
582 | throw new UncheckedIOException(e); |
583 | } |
584 | } |
585 | |
586 | public void visitForeachLoop(JCEnhancedForLoop tree) { |
587 | try { |
588 | print("for ("); |
589 | printExpr(tree.var); |
590 | print(" : "); |
591 | printExpr(tree.expr); |
592 | print(") "); |
593 | printStat(tree.body); |
594 | } catch (IOException e) { |
595 | throw new UncheckedIOException(e); |
596 | } |
597 | } |
598 | |
599 | public void visitLabelled(JCLabeledStatement tree) { |
600 | try { |
601 | print(tree.label + ": "); |
602 | printStat(tree.body); |
603 | } catch (IOException e) { |
604 | throw new UncheckedIOException(e); |
605 | } |
606 | } |
607 | |
608 | public void visitSwitch(JCSwitch tree) { |
609 | try { |
610 | print("switch "); |
611 | if (tree.selector.getTag() == JCTree.PARENS) { |
612 | printExpr(tree.selector); |
613 | } else { |
614 | print("("); |
615 | printExpr(tree.selector); |
616 | print(")"); |
617 | } |
618 | print(" {"); |
619 | println(); |
620 | printStats(tree.cases); |
621 | align(); |
622 | print("}"); |
623 | } catch (IOException e) { |
624 | throw new UncheckedIOException(e); |
625 | } |
626 | } |
627 | |
628 | public void visitCase(JCCase tree) { |
629 | try { |
630 | if (tree.pat == null) { |
631 | print("default"); |
632 | } else { |
633 | print("case "); |
634 | printExpr(tree.pat); |
635 | } |
636 | print(": "); |
637 | println(); |
638 | indent(); |
639 | printStats(tree.stats); |
640 | undent(); |
641 | align(); |
642 | } catch (IOException e) { |
643 | throw new UncheckedIOException(e); |
644 | } |
645 | } |
646 | |
647 | public void visitSynchronized(JCSynchronized tree) { |
648 | try { |
649 | print("synchronized "); |
650 | if (tree.lock.getTag() == JCTree.PARENS) { |
651 | printExpr(tree.lock); |
652 | } else { |
653 | print("("); |
654 | printExpr(tree.lock); |
655 | print(")"); |
656 | } |
657 | print(" "); |
658 | printStat(tree.body); |
659 | } catch (IOException e) { |
660 | throw new UncheckedIOException(e); |
661 | } |
662 | } |
663 | |
664 | public void visitTry(JCTry tree) { |
665 | try { |
666 | print("try "); |
667 | printStat(tree.body); |
668 | for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { |
669 | printStat(l.head); |
670 | } |
671 | if (tree.finalizer != null) { |
672 | print(" finally "); |
673 | printStat(tree.finalizer); |
674 | } |
675 | } catch (IOException e) { |
676 | throw new UncheckedIOException(e); |
677 | } |
678 | } |
679 | |
680 | public void visitCatch(JCCatch tree) { |
681 | try { |
682 | print(" catch ("); |
683 | printExpr(tree.param); |
684 | print(") "); |
685 | printStat(tree.body); |
686 | } catch (IOException e) { |
687 | throw new UncheckedIOException(e); |
688 | } |
689 | } |
690 | |
691 | public void visitConditional(JCConditional tree) { |
692 | try { |
693 | open(prec, TreeInfo.condPrec); |
694 | printExpr(tree.cond, TreeInfo.condPrec); |
695 | print(" ? "); |
696 | printExpr(tree.truepart, TreeInfo.condPrec); |
697 | print(" : "); |
698 | printExpr(tree.falsepart, TreeInfo.condPrec); |
699 | close(prec, TreeInfo.condPrec); |
700 | } catch (IOException e) { |
701 | throw new UncheckedIOException(e); |
702 | } |
703 | } |
704 | |
705 | public void visitIf(JCIf tree) { |
706 | try { |
707 | print("if "); |
708 | if (tree.cond.getTag() == JCTree.PARENS) { |
709 | printExpr(tree.cond); |
710 | } else { |
711 | print("("); |
712 | printExpr(tree.cond); |
713 | print(")"); |
714 | } |
715 | print(" "); |
716 | printStat(tree.thenpart); |
717 | if (tree.elsepart != null) { |
718 | print(" else "); |
719 | printStat(tree.elsepart); |
720 | } |
721 | } catch (IOException e) { |
722 | throw new UncheckedIOException(e); |
723 | } |
724 | } |
725 | |
726 | public void visitExec(JCExpressionStatement tree) { |
727 | try { |
728 | printExpr(tree.expr); |
729 | if (prec == TreeInfo.notExpression) print(";"); |
730 | } catch (IOException e) { |
731 | throw new UncheckedIOException(e); |
732 | } |
733 | } |
734 | |
735 | public void visitBreak(JCBreak tree) { |
736 | try { |
737 | print("break"); |
738 | if (tree.label != null) print(" " + tree.label); |
739 | print(";"); |
740 | } catch (IOException e) { |
741 | throw new UncheckedIOException(e); |
742 | } |
743 | } |
744 | |
745 | public void visitContinue(JCContinue tree) { |
746 | try { |
747 | print("continue"); |
748 | if (tree.label != null) print(" " + tree.label); |
749 | print(";"); |
750 | } catch (IOException e) { |
751 | throw new UncheckedIOException(e); |
752 | } |
753 | } |
754 | |
755 | public void visitReturn(JCReturn tree) { |
756 | try { |
757 | print("return"); |
758 | if (tree.expr != null) { |
759 | print(" "); |
760 | printExpr(tree.expr); |
761 | } |
762 | print(";"); |
763 | } catch (IOException e) { |
764 | throw new UncheckedIOException(e); |
765 | } |
766 | } |
767 | |
768 | public void visitThrow(JCThrow tree) { |
769 | try { |
770 | print("throw "); |
771 | printExpr(tree.expr); |
772 | print(";"); |
773 | } catch (IOException e) { |
774 | throw new UncheckedIOException(e); |
775 | } |
776 | } |
777 | |
778 | public void visitAssert(JCAssert tree) { |
779 | try { |
780 | print("assert "); |
781 | printExpr(tree.cond); |
782 | if (tree.detail != null) { |
783 | print(" : "); |
784 | printExpr(tree.detail); |
785 | } |
786 | print(";"); |
787 | } catch (IOException e) { |
788 | throw new UncheckedIOException(e); |
789 | } |
790 | } |
791 | |
792 | public void visitApply(JCMethodInvocation tree) { |
793 | try { |
794 | if (!tree.typeargs.isEmpty()) { |
795 | if (tree.meth.getTag() == JCTree.SELECT) { |
796 | JCFieldAccess left = (JCFieldAccess)tree.meth; |
797 | printExpr(left.selected); |
798 | print(".<"); |
799 | printExprs(tree.typeargs); |
800 | print(">" + left.name); |
801 | } else { |
802 | print("<"); |
803 | printExprs(tree.typeargs); |
804 | print(">"); |
805 | printExpr(tree.meth); |
806 | } |
807 | } else { |
808 | printExpr(tree.meth); |
809 | } |
810 | print("("); |
811 | printExprs(tree.args); |
812 | print(")"); |
813 | } catch (IOException e) { |
814 | throw new UncheckedIOException(e); |
815 | } |
816 | } |
817 | |
818 | public void visitNewClass(JCNewClass tree) { |
819 | try { |
820 | if (tree.encl != null) { |
821 | printExpr(tree.encl); |
822 | print("."); |
823 | } |
824 | print("new "); |
825 | if (!tree.typeargs.isEmpty()) { |
826 | print("<"); |
827 | printExprs(tree.typeargs); |
828 | print(">"); |
829 | } |
830 | printExpr(tree.clazz); |
831 | print("("); |
832 | printExprs(tree.args); |
833 | print(")"); |
834 | if (tree.def != null) { |
835 | Name enclClassNamePrev = enclClassName; |
836 | enclClassName = |
837 | tree.def.name != null ? tree.def.name : |
838 | tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.empty ? tree.type.tsym.name : |
839 | null; |
840 | if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/"); |
841 | printBlock(tree.def.defs); |
842 | enclClassName = enclClassNamePrev; |
843 | } |
844 | } catch (IOException e) { |
845 | throw new UncheckedIOException(e); |
846 | } |
847 | } |
848 | |
849 | public void visitNewArray(JCNewArray tree) { |
850 | try { |
851 | if (tree.elemtype != null) { |
852 | print("new "); |
853 | JCTree elem = tree.elemtype; |
854 | if (elem instanceof JCArrayTypeTree) |
855 | printBaseElementType((JCArrayTypeTree) elem); |
856 | else |
857 | printExpr(elem); |
858 | for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { |
859 | print("["); |
860 | printExpr(l.head); |
861 | print("]"); |
862 | } |
863 | if (elem instanceof JCArrayTypeTree) |
864 | printBrackets((JCArrayTypeTree) elem); |
865 | } |
866 | if (tree.elems != null) { |
867 | if (tree.elemtype != null) print("[]"); |
868 | print("{"); |
869 | printExprs(tree.elems); |
870 | print("}"); |
871 | } |
872 | } catch (IOException e) { |
873 | throw new UncheckedIOException(e); |
874 | } |
875 | } |
876 | |
877 | public void visitParens(JCParens tree) { |
878 | try { |
879 | print("("); |
880 | printExpr(tree.expr); |
881 | print(")"); |
882 | } catch (IOException e) { |
883 | throw new UncheckedIOException(e); |
884 | } |
885 | } |
886 | |
887 | public void visitAssign(JCAssign tree) { |
888 | try { |
889 | open(prec, TreeInfo.assignPrec); |
890 | printExpr(tree.lhs, TreeInfo.assignPrec + 1); |
891 | print(" = "); |
892 | printExpr(tree.rhs, TreeInfo.assignPrec); |
893 | close(prec, TreeInfo.assignPrec); |
894 | } catch (IOException e) { |
895 | throw new UncheckedIOException(e); |
896 | } |
897 | } |
898 | |
899 | public String operatorName(int tag) { |
900 | switch(tag) { |
901 | case JCTree.POS: return "+"; |
902 | case JCTree.NEG: return "-"; |
903 | case JCTree.NOT: return "!"; |
904 | case JCTree.COMPL: return "~"; |
905 | case JCTree.PREINC: return "++"; |
906 | case JCTree.PREDEC: return "--"; |
907 | case JCTree.POSTINC: return "++"; |
908 | case JCTree.POSTDEC: return "--"; |
909 | case JCTree.NULLCHK: return "<*nullchk*>"; |
910 | case JCTree.OR: return "||"; |
911 | case JCTree.AND: return "&&"; |
912 | case JCTree.EQ: return "=="; |
913 | case JCTree.NE: return "!="; |
914 | case JCTree.LT: return "<"; |
915 | case JCTree.GT: return ">"; |
916 | case JCTree.LE: return "<="; |
917 | case JCTree.GE: return ">="; |
918 | case JCTree.BITOR: return "|"; |
919 | case JCTree.BITXOR: return "^"; |
920 | case JCTree.BITAND: return "&"; |
921 | case JCTree.SL: return "<<"; |
922 | case JCTree.SR: return ">>"; |
923 | case JCTree.USR: return ">>>"; |
924 | case JCTree.PLUS: return "+"; |
925 | case JCTree.MINUS: return "-"; |
926 | case JCTree.MUL: return "*"; |
927 | case JCTree.DIV: return "/"; |
928 | case JCTree.MOD: return "%"; |
929 | default: throw new Error(); |
930 | } |
931 | } |
932 | |
933 | public void visitAssignop(JCAssignOp tree) { |
934 | try { |
935 | open(prec, TreeInfo.assignopPrec); |
936 | printExpr(tree.lhs, TreeInfo.assignopPrec + 1); |
937 | print(" " + operatorName(tree.getTag() - JCTree.ASGOffset) + "= "); |
938 | printExpr(tree.rhs, TreeInfo.assignopPrec); |
939 | close(prec, TreeInfo.assignopPrec); |
940 | } catch (IOException e) { |
941 | throw new UncheckedIOException(e); |
942 | } |
943 | } |
944 | |
945 | public void visitUnary(JCUnary tree) { |
946 | try { |
947 | int ownprec = TreeInfo.opPrec(tree.getTag()); |
948 | String opname = operatorName(tree.getTag()); |
949 | open(prec, ownprec); |
950 | if (tree.getTag() <= JCTree.PREDEC) { |
951 | print(opname); |
952 | printExpr(tree.arg, ownprec); |
953 | } else { |
954 | printExpr(tree.arg, ownprec); |
955 | print(opname); |
956 | } |
957 | close(prec, ownprec); |
958 | } catch (IOException e) { |
959 | throw new UncheckedIOException(e); |
960 | } |
961 | } |
962 | |
963 | public void visitBinary(JCBinary tree) { |
964 | try { |
965 | int ownprec = TreeInfo.opPrec(tree.getTag()); |
966 | String opname = operatorName(tree.getTag()); |
967 | open(prec, ownprec); |
968 | printExpr(tree.lhs, ownprec); |
969 | print(" " + opname + " "); |
970 | printExpr(tree.rhs, ownprec + 1); |
971 | close(prec, ownprec); |
972 | } catch (IOException e) { |
973 | throw new UncheckedIOException(e); |
974 | } |
975 | } |
976 | |
977 | public void visitTypeCast(JCTypeCast tree) { |
978 | try { |
979 | open(prec, TreeInfo.prefixPrec); |
980 | print("("); |
981 | printExpr(tree.clazz); |
982 | print(")"); |
983 | printExpr(tree.expr, TreeInfo.prefixPrec); |
984 | close(prec, TreeInfo.prefixPrec); |
985 | } catch (IOException e) { |
986 | throw new UncheckedIOException(e); |
987 | } |
988 | } |
989 | |
990 | public void visitTypeTest(JCInstanceOf tree) { |
991 | try { |
992 | open(prec, TreeInfo.ordPrec); |
993 | printExpr(tree.expr, TreeInfo.ordPrec); |
994 | print(" instanceof "); |
995 | printExpr(tree.clazz, TreeInfo.ordPrec + 1); |
996 | close(prec, TreeInfo.ordPrec); |
997 | } catch (IOException e) { |
998 | throw new UncheckedIOException(e); |
999 | } |
1000 | } |
1001 | |
1002 | public void visitIndexed(JCArrayAccess tree) { |
1003 | try { |
1004 | printExpr(tree.indexed, TreeInfo.postfixPrec); |
1005 | print("["); |
1006 | printExpr(tree.index); |
1007 | print("]"); |
1008 | } catch (IOException e) { |
1009 | throw new UncheckedIOException(e); |
1010 | } |
1011 | } |
1012 | |
1013 | public void visitSelect(JCFieldAccess tree) { |
1014 | try { |
1015 | printExpr(tree.selected, TreeInfo.postfixPrec); |
1016 | print("." + tree.name); |
1017 | } catch (IOException e) { |
1018 | throw new UncheckedIOException(e); |
1019 | } |
1020 | } |
1021 | |
1022 | public void visitIdent(JCIdent tree) { |
1023 | try { |
1024 | print(tree.name); |
1025 | } catch (IOException e) { |
1026 | throw new UncheckedIOException(e); |
1027 | } |
1028 | } |
1029 | |
1030 | public void visitLiteral(JCLiteral tree) { |
1031 | try { |
1032 | switch (tree.typetag) { |
1033 | case TypeTags.INT: |
1034 | print(tree.value.toString()); |
1035 | break; |
1036 | case TypeTags.LONG: |
1037 | print(tree.value + "L"); |
1038 | break; |
1039 | case TypeTags.FLOAT: |
1040 | print(tree.value + "F"); |
1041 | break; |
1042 | case TypeTags.DOUBLE: |
1043 | print(tree.value.toString()); |
1044 | break; |
1045 | case TypeTags.CHAR: |
1046 | print("\'" + |
1047 | Convert.quote( |
1048 | String.valueOf((char)((Number)tree.value).intValue())) + |
1049 | "\'"); |
1050 | break; |
1051 | case TypeTags.BOOLEAN: |
1052 | print(((Number)tree.value).intValue() == 1 ? "true" : "false"); |
1053 | break; |
1054 | case TypeTags.BOT: |
1055 | print("null"); |
1056 | break; |
1057 | default: |
1058 | print("\"" + Convert.quote(tree.value.toString()) + "\""); |
1059 | break; |
1060 | } |
1061 | } catch (IOException e) { |
1062 | throw new UncheckedIOException(e); |
1063 | } |
1064 | } |
1065 | |
1066 | public void visitTypeIdent(JCPrimitiveTypeTree tree) { |
1067 | try { |
1068 | switch(tree.typetag) { |
1069 | case TypeTags.BYTE: |
1070 | print("byte"); |
1071 | break; |
1072 | case TypeTags.CHAR: |
1073 | print("char"); |
1074 | break; |
1075 | case TypeTags.SHORT: |
1076 | print("short"); |
1077 | break; |
1078 | case TypeTags.INT: |
1079 | print("int"); |
1080 | break; |
1081 | case TypeTags.LONG: |
1082 | print("long"); |
1083 | break; |
1084 | case TypeTags.FLOAT: |
1085 | print("float"); |
1086 | break; |
1087 | case TypeTags.DOUBLE: |
1088 | print("double"); |
1089 | break; |
1090 | case TypeTags.BOOLEAN: |
1091 | print("boolean"); |
1092 | break; |
1093 | case TypeTags.VOID: |
1094 | print("void"); |
1095 | break; |
1096 | default: |
1097 | print("error"); |
1098 | break; |
1099 | } |
1100 | } catch (IOException e) { |
1101 | throw new UncheckedIOException(e); |
1102 | } |
1103 | } |
1104 | |
1105 | public void visitTypeArray(JCArrayTypeTree tree) { |
1106 | try { |
1107 | printBaseElementType(tree); |
1108 | printBrackets(tree); |
1109 | } catch (IOException e) { |
1110 | throw new UncheckedIOException(e); |
1111 | } |
1112 | } |
1113 | |
1114 | // Prints the inner element type of a nested array |
1115 | private void printBaseElementType(JCArrayTypeTree tree) throws IOException { |
1116 | JCTree elem = tree.elemtype; |
1117 | while (elem instanceof JCWildcard) |
1118 | elem = ((JCWildcard) elem).inner; |
1119 | if (elem instanceof JCArrayTypeTree) |
1120 | printBaseElementType((JCArrayTypeTree) elem); |
1121 | else |
1122 | printExpr(elem); |
1123 | } |
1124 | |
1125 | // prints the brackets of a nested array in reverse order |
1126 | private void printBrackets(JCArrayTypeTree tree) throws IOException { |
1127 | JCTree elem; |
1128 | while (true) { |
1129 | elem = tree.elemtype; |
1130 | print("[]"); |
1131 | if (!(elem instanceof JCArrayTypeTree)) break; |
1132 | tree = (JCArrayTypeTree) elem; |
1133 | } |
1134 | } |
1135 | |
1136 | public void visitTypeApply(JCTypeApply tree) { |
1137 | try { |
1138 | printExpr(tree.clazz); |
1139 | print("<"); |
1140 | printExprs(tree.arguments); |
1141 | print(">"); |
1142 | } catch (IOException e) { |
1143 | throw new UncheckedIOException(e); |
1144 | } |
1145 | } |
1146 | |
1147 | public void visitTypeParameter(JCTypeParameter tree) { |
1148 | try { |
1149 | print(tree.name); |
1150 | if (tree.bounds.nonEmpty()) { |
1151 | print(" extends "); |
1152 | printExprs(tree.bounds, " & "); |
1153 | } |
1154 | } catch (IOException e) { |
1155 | throw new UncheckedIOException(e); |
1156 | } |
1157 | } |
1158 | |
1159 | @Override |
1160 | public void visitWildcard(JCWildcard tree) { |
1161 | try { |
1162 | print(tree.kind); |
1163 | if (tree.kind.kind != BoundKind.UNBOUND) |
1164 | printExpr(tree.inner); |
1165 | } catch (IOException e) { |
1166 | throw new UncheckedIOException(e); |
1167 | } |
1168 | } |
1169 | |
1170 | @Override |
1171 | public void visitTypeBoundKind(TypeBoundKind tree) { |
1172 | try { |
1173 | print(String.valueOf(tree.kind)); |
1174 | } catch (IOException e) { |
1175 | throw new UncheckedIOException(e); |
1176 | } |
1177 | } |
1178 | |
1179 | public void visitErroneous(JCErroneous tree) { |
1180 | try { |
1181 | print("(ERROR)"); |
1182 | } catch (IOException e) { |
1183 | throw new UncheckedIOException(e); |
1184 | } |
1185 | } |
1186 | |
1187 | public void visitLetExpr(LetExpr tree) { |
1188 | try { |
1189 | print("(let " + tree.defs + " in " + tree.expr + ")"); |
1190 | } catch (IOException e) { |
1191 | throw new UncheckedIOException(e); |
1192 | } |
1193 | } |
1194 | |
1195 | public void visitModifiers(JCModifiers mods) { |
1196 | try { |
1197 | printAnnotations(mods.annotations); |
1198 | printFlags(mods.flags); |
1199 | } catch (IOException e) { |
1200 | throw new UncheckedIOException(e); |
1201 | } |
1202 | } |
1203 | |
1204 | public void visitAnnotation(JCAnnotation tree) { |
1205 | try { |
1206 | print("@"); |
1207 | printExpr(tree.annotationType); |
1208 | print("("); |
1209 | printExprs(tree.args); |
1210 | print(")"); |
1211 | } catch (IOException e) { |
1212 | throw new UncheckedIOException(e); |
1213 | } |
1214 | } |
1215 | |
1216 | public void visitTree(JCTree tree) { |
1217 | try { |
1218 | print("(UNKNOWN: " + tree + ")"); |
1219 | println(); |
1220 | } catch (IOException e) { |
1221 | throw new UncheckedIOException(e); |
1222 | } |
1223 | } |
1224 | } |