Pretty.java revision c38ee7ae0239899e7f9d0d5243d8bed77836891c
1881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon/*
2881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * Copyright 2016 Google Inc. All Rights Reserved.
3881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon *
4881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * Licensed under the Apache License, Version 2.0 (the "License");
5881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * you may not use this file except in compliance with the License.
6881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * You may obtain a copy of the License at
7881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon *
8881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon *     http://www.apache.org/licenses/LICENSE-2.0
9881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon *
10881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * Unless required by applicable law or agreed to in writing, software
11881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * distributed under the License is distributed on an "AS IS" BASIS,
12881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * See the License for the specific language governing permissions and
14881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon * limitations under the License.
15881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon */
16881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
17881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonpackage com.google.turbine.tree;
18881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
19881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport com.google.common.base.Joiner;
20881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport com.google.common.base.Strings;
21881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport com.google.common.collect.ImmutableSet;
22c38ee7ae0239899e7f9d0d5243d8bed77836891ccushonimport com.google.turbine.tree.Tree.ClassLiteral;
23881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport java.util.ArrayList;
24881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport java.util.Collections;
25881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport java.util.List;
26881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
27881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon/** A pretty-printer for {@link Tree}s. */
28881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonpublic class Pretty implements Tree.Visitor<Void, Void> {
29881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
30881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  static String pretty(Tree tree) {
31881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    Pretty pretty = new Pretty();
32881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    tree.accept(pretty, null);
33881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return pretty.sb.toString();
34881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
35881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
36881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  private final StringBuilder sb = new StringBuilder();
37881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  int indent = 0;
38881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  boolean newLine = false;
39881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
40881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  void printLine() {
41881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('\n');
42881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    newLine = true;
43881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
44881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
45881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  void printLine(String line) {
46881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!newLine) {
47881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('\n');
48881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
49881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(line).append('\n');
50881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    newLine = true;
51881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
52881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
53881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  Pretty append(char c) {
54881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (c == '\n') {
55881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      newLine = true;
56881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    } else if (newLine) {
57881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      sb.append(Strings.repeat(" ", indent * 2));
58881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      newLine = false;
59881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
60881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    sb.append(c);
61881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return this;
62881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
63881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
64881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  Pretty append(String s) {
65881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (newLine) {
66881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      sb.append(Strings.repeat(" ", indent * 2));
67881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      newLine = false;
68881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
69881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    sb.append(s);
70881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return this;
71881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
72881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
73881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
74881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitWildTy(Tree.WildTy wildTy, Void input) {
75881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('?');
76881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (wildTy.lower().isPresent()) {
77881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" super ");
78881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      wildTy.lower().get().accept(this, null);
79881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
80881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (wildTy.upper().isPresent()) {
81881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" extends ");
82881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      wildTy.upper().get().accept(this, null);
83881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
84881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
85881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
86881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
87881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
88881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitArrTy(Tree.ArrTy arrTy, Void input) {
89881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    arrTy.elem().accept(this, null);
90881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(Strings.repeat("[]", arrTy.dim()));
91881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
92881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
93881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
94881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
95881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitPrimTy(Tree.PrimTy primTy, Void input) {
96881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(primTy.tykind().toString());
97881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
98881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
99881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
100881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
101881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitVoidTy(Tree.VoidTy primTy, Void input) {
102881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append("void");
103881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
104881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
105881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
106881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
107881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitClassTy(Tree.ClassTy classTy, Void input) {
108881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (classTy.base().isPresent()) {
109881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      classTy.base().get().accept(this, null);
110881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('.');
111881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
112881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(classTy.name());
113881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!classTy.tyargs().isEmpty()) {
114881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('<');
115881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
116881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree t : classTy.tyargs()) {
117881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
118881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
119881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
120881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
121881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
122881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
123881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('>');
124881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
125881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
126881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
127881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
128881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
129881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitLiteral(Tree.Literal literal, Void input) {
130881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(literal.value().toString());
131881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
132881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
133881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
134881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
135881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitTypeCast(Tree.TypeCast typeCast, Void input) {
136881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('(');
137881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    typeCast.ty().accept(this, null);
138881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(") ");
139881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    typeCast.expr().accept(this, null);
140881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
141881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
142881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
143881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
144881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitUnary(Tree.Unary unary, Void input) {
145881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    switch (unary.op()) {
146881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case POST_INCR:
147881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case POST_DECR:
148881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        unary.expr().accept(this, null);
149881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(unary.op().toString());
150881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
151881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case PRE_INCR:
152881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case PRE_DECR:
153881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case UNARY_PLUS:
154881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case NEG:
155881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case NOT:
156881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case BITWISE_COMP:
157881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(unary.op().toString());
158881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        unary.expr().accept(this, null);
159881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
160881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      default:
161881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        throw new AssertionError(unary.op().name());
162881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
163881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
164881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
165881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
166881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
167881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitBinary(Tree.Binary binary, Void input) {
168881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('(');
169881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    binary.lhs().accept(this, null);
170881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" " + binary.op() + " ");
171881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    binary.rhs().accept(this, null);
172881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(')');
173881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
174881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
175881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
176881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
177881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitConstVarName(Tree.ConstVarName constVarName, Void input) {
178881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(Joiner.on('.').join(constVarName.name()));
179881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
180881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
181881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
182881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
183c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon  public Void visitClassLiteral(ClassLiteral classLiteral, Void input) {
184c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon    classLiteral.accept(this, input);
185c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon    append(".class");
186c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon    return null;
187c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon  }
188c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon
189c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon  @Override
190881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitAssign(Tree.Assign assign, Void input) {
191881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(assign.name()).append(" = ");
192881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    assign.expr().accept(this, null);
193881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
194881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
195881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
196881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
197881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitConditional(Tree.Conditional conditional, Void input) {
198881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    conditional.cond().accept(this, null);
199881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" ? ");
200881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    conditional.iftrue().accept(this, null);
201881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" : ");
202881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    conditional.iffalse().accept(this, null);
203881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
204881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
205881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
206881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
207881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitArrayInit(Tree.ArrayInit arrayInit, Void input) {
208881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('{');
209881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    boolean first = true;
210881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.Expression e : arrayInit.exprs()) {
211881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      if (!first) {
212881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(", ");
213881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
214881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      e.accept(this, null);
215881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      first = false;
216881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
217881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('}');
218881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
219881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
220881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
221881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
222881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitCompUnit(Tree.CompUnit compUnit, Void input) {
223881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (compUnit.pkg().isPresent()) {
224881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      compUnit.pkg().get().accept(this, null);
225881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printLine();
226881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
227881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.ImportDecl i : compUnit.imports()) {
228881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      i.accept(this, null);
229881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printLine();
230881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
231881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    boolean first = true;
232881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.TyDecl decl : compUnit.decls()) {
233881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      if (!first) {
234881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        printLine();
235881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
236881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      decl.accept(this, null);
237881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      first = false;
238881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
239881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
240881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
241881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
242881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
243881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitImportDecl(Tree.ImportDecl importDecl, Void input) {
244881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append("import ");
245881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (importDecl.stat()) {
246881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append("static ");
247881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
248881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(importDecl.type()).append(";").append('\n');
249881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
250881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
251881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
252881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
253881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitVarDecl(Tree.VarDecl varDecl, Void input) {
254881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printVarDecl(varDecl);
255881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(';');
256881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
257881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
258881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
259881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  private void printVarDecl(Tree.VarDecl varDecl) {
260881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.Anno anno : varDecl.annos()) {
261881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      anno.accept(this, null);
262881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(' ');
263881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
264881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printModifiers(varDecl.mods());
265881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    varDecl.ty().accept(this, null);
266881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(' ').append(varDecl.name());
267881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (varDecl.init().isPresent()) {
268881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" = ");
269881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      varDecl.init().get().accept(this, null);
270881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
271881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
272881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
273881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
274881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitMethDecl(Tree.MethDecl methDecl, Void input) {
275881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.Anno anno : methDecl.annos()) {
276881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      anno.accept(this, null);
277881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printLine();
278881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
279881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printModifiers(methDecl.mods());
280881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!methDecl.typarams().isEmpty()) {
281881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('<');
282881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
283881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.TyParam t : methDecl.typarams()) {
284881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
285881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
286881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
287881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
288881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
289881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
290881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('>');
291881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(' ');
292881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
293881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (methDecl.ret().isPresent()) {
294881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      methDecl.ret().get().accept(this, null);
295881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(' ');
296881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
297881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(methDecl.name());
298881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('(');
299881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    boolean first = true;
300881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.VarDecl param : methDecl.params()) {
301881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      if (!first) {
302881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(", ");
303881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
304881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printVarDecl(param);
305881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      first = false;
306881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
307881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(')');
3083088f83b806b82d866d119e344da274105f42821cushon    if (methDecl.defaultValue().isPresent()) {
309881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" default ");
3103088f83b806b82d866d119e344da274105f42821cushon      methDecl.defaultValue().get().accept(this, null);
311881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(";");
312881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    } else if (methDecl.mods().contains(TurbineModifier.ABSTRACT)
313881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        || methDecl.mods().contains(TurbineModifier.NATIVE)) {
314881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(";");
315881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    } else {
316881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" {}");
317881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
318881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
319881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
320881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
321881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
322881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitAnno(Tree.Anno anno, Void input) {
323881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('@');
324881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(anno.name());
325881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!anno.args().isEmpty()) {
326881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('(');
327881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
328881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.Expression e : anno.args()) {
329881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
330881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
331881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
332881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        e.accept(this, null);
333881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
334881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
335881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(')');
336881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
337881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
338881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
339881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
340881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
341881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitTyDecl(Tree.TyDecl tyDecl, Void input) {
342881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.Anno anno : tyDecl.annos()) {
343881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      anno.accept(this, null);
344881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printLine();
345881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
346881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printModifiers(tyDecl.mods());
347881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    switch (tyDecl.tykind()) {
348881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case CLASS:
349881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("class");
350881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
351881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case INTERFACE:
352881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("interface");
353881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
354881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case ENUM:
355881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("enum");
356881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
357881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case ANNOTATION:
358881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("@interface");
359881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
360881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
361881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(' ').append(tyDecl.name());
362881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!tyDecl.typarams().isEmpty()) {
363881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('<');
364881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
365881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.TyParam t : tyDecl.typarams()) {
366881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
367881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
368881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
369881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
370881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
371881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
372881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('>');
373881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
374881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (tyDecl.xtnds().isPresent()) {
375881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" extends ");
376881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      tyDecl.xtnds().get().accept(this, null);
377881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
378881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!tyDecl.impls().isEmpty()) {
379881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" implements ");
380881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
381881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.ClassTy t : tyDecl.impls()) {
382881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
383881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
384881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
385881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
386881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
387881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
388881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
389881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" {").append('\n');
390881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    indent++;
391881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    switch (tyDecl.tykind()) {
392881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case ENUM:
393881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        {
394881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          List<Tree> nonConsts = new ArrayList<>();
395881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          for (Tree t : tyDecl.members()) {
396881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            if (t instanceof Tree.VarDecl) {
397881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              Tree.VarDecl decl = (Tree.VarDecl) t;
398881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              if (decl.mods().contains(TurbineModifier.ACC_ENUM)) {
399881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon                append(decl.name()).append(',').append('\n');
400881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon                continue;
401881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              }
402881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            }
403881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            nonConsts.add(t);
404881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          }
405881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          printLine(";");
406881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          boolean first = true;
407881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          for (Tree t : nonConsts) {
408881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            if (!first) {
409881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              printLine();
410881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            }
411881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            t.accept(this, null);
412881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            first = false;
413881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          }
414881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
415881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
416881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      default:
417881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        {
418881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          boolean first = true;
419881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          for (Tree t : tyDecl.members()) {
420881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            if (!first) {
421881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              printLine();
422881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            }
423881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            t.accept(this, null);
424881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            first = false;
425881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          }
426881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
427881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
428881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
429881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    indent--;
430881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printLine("}");
431881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
432881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
433881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
434881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  private void printModifiers(ImmutableSet<TurbineModifier> mods) {
435881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    List<TurbineModifier> modifiers = new ArrayList<>(mods);
436881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    Collections.sort(modifiers);
437881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (TurbineModifier mod : modifiers) {
438881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      switch (mod) {
439881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case PRIVATE:
440881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case PROTECTED:
441881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case PUBLIC:
442881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ABSTRACT:
443881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case FINAL:
444881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case STATIC:
445881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case VOLATILE:
446881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case SYNCHRONIZED:
447881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case STRICTFP:
448881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case NATIVE:
449881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case TRANSIENT:
450881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case DEFAULT:
451881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(mod.toString()).append(' ');
452881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
453881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_SUPER:
454881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case VARARGS:
455881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case INTERFACE:
456881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_ENUM:
457881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_ANNOTATION:
458881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_SYNTHETIC:
459881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_BRIDGE:
460881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ENUM_IMPL:
461881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
462881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        default:
463881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          throw new AssertionError(mod);
464881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
465881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
466881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
467881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
468881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
469881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitTyParam(Tree.TyParam tyParam, Void input) {
470881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(tyParam.name());
471881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!tyParam.bounds().isEmpty()) {
472881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" extends ");
473881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
474881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree bound : tyParam.bounds()) {
475881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
476881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(" & ");
477881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
478881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        bound.accept(this, null);
479881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
480881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
481881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
482881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
483881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
484881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
485881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
486881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitPkgDecl(Tree.PkgDecl pkgDecl, Void input) {
487881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append("package ").append(pkgDecl.name()).append(';');
488881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
489881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
490881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon}
491