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;
2184213d0af45dfb55e638e2ee1f36007e7bfe5a02cushonimport com.google.common.collect.ImmutableList;
22881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport com.google.common.collect.ImmutableSet;
2384213d0af45dfb55e638e2ee1f36007e7bfe5a02cushonimport com.google.turbine.tree.Tree.Anno;
24c38ee7ae0239899e7f9d0d5243d8bed77836891ccushonimport com.google.turbine.tree.Tree.ClassLiteral;
25881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport java.util.ArrayList;
26881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport java.util.Collections;
27881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonimport java.util.List;
28881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
29881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon/** A pretty-printer for {@link Tree}s. */
30881d847a3ccf0bca29a5c809aeb68eff9f467cedcushonpublic class Pretty implements Tree.Visitor<Void, Void> {
31881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
32881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  static String pretty(Tree tree) {
33881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    Pretty pretty = new Pretty();
34881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    tree.accept(pretty, null);
35881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return pretty.sb.toString();
36881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
37881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
38881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  private final StringBuilder sb = new StringBuilder();
39881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  int indent = 0;
40881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  boolean newLine = false;
41881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
42881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  void printLine() {
43881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('\n');
44881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    newLine = true;
45881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
46881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
47881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  void printLine(String line) {
48881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!newLine) {
49881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('\n');
50881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
51881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(line).append('\n');
52881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    newLine = true;
53881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
54881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
55881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  Pretty append(char c) {
56881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (c == '\n') {
57881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      newLine = true;
58881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    } else if (newLine) {
59881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      sb.append(Strings.repeat(" ", indent * 2));
60881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      newLine = false;
61881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
62881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    sb.append(c);
63881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return this;
64881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
65881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
66881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  Pretty append(String s) {
67881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (newLine) {
68881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      sb.append(Strings.repeat(" ", indent * 2));
69881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      newLine = false;
70881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
71881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    sb.append(s);
72881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return this;
73881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
74881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
75881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
76881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitWildTy(Tree.WildTy wildTy, Void input) {
7784213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    printAnnos(wildTy.annos());
78881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('?');
79881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (wildTy.lower().isPresent()) {
80881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" super ");
81881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      wildTy.lower().get().accept(this, null);
82881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
83881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (wildTy.upper().isPresent()) {
84881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" extends ");
85881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      wildTy.upper().get().accept(this, null);
86881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
87881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
88881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
89881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
90881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
91881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitArrTy(Tree.ArrTy arrTy, Void input) {
92881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    arrTy.elem().accept(this, null);
9384213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    if (!arrTy.annos().isEmpty()) {
9484213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      append(' ');
9584213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      printAnnos(arrTy.annos());
9684213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    }
9784213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    append("[]");
98881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
99881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
100881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
101881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
102881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitPrimTy(Tree.PrimTy primTy, Void input) {
103881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(primTy.tykind().toString());
104881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
105881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
106881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
107881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
108881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitVoidTy(Tree.VoidTy primTy, Void input) {
109881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append("void");
110881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
111881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
112881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
113881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
114881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitClassTy(Tree.ClassTy classTy, Void input) {
115881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (classTy.base().isPresent()) {
116881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      classTy.base().get().accept(this, null);
117881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('.');
118881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
11984213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    printAnnos(classTy.annos());
120881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(classTy.name());
121881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!classTy.tyargs().isEmpty()) {
122881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('<');
123881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
124881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree t : classTy.tyargs()) {
125881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
126881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
127881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
128881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
129881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
130881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
131881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('>');
132881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
133881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
134881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
135881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
136881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
137881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitLiteral(Tree.Literal literal, Void input) {
138881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(literal.value().toString());
139881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
140881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
141881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
142881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
143881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitTypeCast(Tree.TypeCast typeCast, Void input) {
144881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('(');
145881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    typeCast.ty().accept(this, null);
146881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(") ");
147881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    typeCast.expr().accept(this, null);
148881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
149881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
150881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
151881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
152881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitUnary(Tree.Unary unary, Void input) {
153881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    switch (unary.op()) {
154881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case POST_INCR:
155881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case POST_DECR:
156881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        unary.expr().accept(this, null);
157881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(unary.op().toString());
158881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
159881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case PRE_INCR:
160881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case PRE_DECR:
161881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case UNARY_PLUS:
162881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case NEG:
163881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case NOT:
164881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case BITWISE_COMP:
165881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(unary.op().toString());
166881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        unary.expr().accept(this, null);
167881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
168881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      default:
169881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        throw new AssertionError(unary.op().name());
170881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
171881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
172881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
173881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
174881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
175881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitBinary(Tree.Binary binary, Void input) {
176881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('(');
177881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    binary.lhs().accept(this, null);
178881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" " + binary.op() + " ");
179881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    binary.rhs().accept(this, null);
180881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(')');
181881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
182881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
183881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
184881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
185881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitConstVarName(Tree.ConstVarName constVarName, Void input) {
186881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(Joiner.on('.').join(constVarName.name()));
187881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
188881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
189881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
190881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
191c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon  public Void visitClassLiteral(ClassLiteral classLiteral, Void input) {
192c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon    classLiteral.accept(this, input);
193c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon    append(".class");
194c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon    return null;
195c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon  }
196c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon
197c38ee7ae0239899e7f9d0d5243d8bed77836891ccushon  @Override
198881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitAssign(Tree.Assign assign, Void input) {
199881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(assign.name()).append(" = ");
200881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    assign.expr().accept(this, null);
201881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
202881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
203881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
204881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
205881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitConditional(Tree.Conditional conditional, Void input) {
2065317ebf1069fbc15aaad76e6496b01db585cf024cushon    append("(");
207881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    conditional.cond().accept(this, null);
208881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" ? ");
209881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    conditional.iftrue().accept(this, null);
210881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" : ");
211881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    conditional.iffalse().accept(this, null);
2125317ebf1069fbc15aaad76e6496b01db585cf024cushon    append(")");
213881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
214881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
215881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
216881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
217881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitArrayInit(Tree.ArrayInit arrayInit, Void input) {
218881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('{');
219881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    boolean first = true;
220881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.Expression e : arrayInit.exprs()) {
221881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      if (!first) {
222881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(", ");
223881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
224881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      e.accept(this, null);
225881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      first = false;
226881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
227881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('}');
228881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
229881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
230881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
231881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
232881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitCompUnit(Tree.CompUnit compUnit, Void input) {
233881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (compUnit.pkg().isPresent()) {
234881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      compUnit.pkg().get().accept(this, null);
235881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printLine();
236881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
237881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.ImportDecl i : compUnit.imports()) {
238881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      i.accept(this, null);
239881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
240881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.TyDecl decl : compUnit.decls()) {
24187b4e7d593d3acc15553cdb7451f91dece6c6664cushon      printLine();
242881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      decl.accept(this, null);
243881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
244881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
245881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
246881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
247881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
248881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitImportDecl(Tree.ImportDecl importDecl, Void input) {
249881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append("import ");
250881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (importDecl.stat()) {
251881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append("static ");
252881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
25387b4e7d593d3acc15553cdb7451f91dece6c6664cushon    append(Joiner.on('.').join(importDecl.type()));
25487b4e7d593d3acc15553cdb7451f91dece6c6664cushon    if (importDecl.wild()) {
25587b4e7d593d3acc15553cdb7451f91dece6c6664cushon      append(".*");
25687b4e7d593d3acc15553cdb7451f91dece6c6664cushon    }
25787b4e7d593d3acc15553cdb7451f91dece6c6664cushon    append(";").append('\n');
258881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
259881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
260881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
261881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
262881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitVarDecl(Tree.VarDecl varDecl, Void input) {
263881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printVarDecl(varDecl);
264881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(';');
265881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
266881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
267881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
268881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  private void printVarDecl(Tree.VarDecl varDecl) {
26984213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    printAnnos(varDecl.annos());
270881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printModifiers(varDecl.mods());
271881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    varDecl.ty().accept(this, null);
272881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(' ').append(varDecl.name());
273881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (varDecl.init().isPresent()) {
274881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" = ");
275881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      varDecl.init().get().accept(this, null);
276881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
277881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
278881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
27984213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon  private void printAnnos(ImmutableList<Anno> annos) {
28084213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    for (Tree.Anno anno : annos) {
28184213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      anno.accept(this, null);
28284213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      append(' ');
28384213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    }
28484213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon  }
28584213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon
286881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
287881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitMethDecl(Tree.MethDecl methDecl, Void input) {
288881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.Anno anno : methDecl.annos()) {
289881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      anno.accept(this, null);
290881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printLine();
291881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
292881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printModifiers(methDecl.mods());
293881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!methDecl.typarams().isEmpty()) {
294881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('<');
295881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
296881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.TyParam t : methDecl.typarams()) {
297881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
298881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
299881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
300881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
301881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
302881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
303881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('>');
304881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(' ');
305881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
306881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (methDecl.ret().isPresent()) {
307881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      methDecl.ret().get().accept(this, null);
308881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(' ');
309881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
310881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(methDecl.name());
311881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('(');
312881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    boolean first = true;
313881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.VarDecl param : methDecl.params()) {
314881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      if (!first) {
315881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append(", ");
316881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
317881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printVarDecl(param);
318881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      first = false;
319881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
320881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(')');
32184213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    if (!methDecl.exntys().isEmpty()) {
32284213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      append(" throws ");
32384213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      first = true;
32484213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      for (Tree.Type e : methDecl.exntys()) {
32584213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon        if (!first) {
32684213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon          append(", ");
32784213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon        }
32884213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon        e.accept(this, null);
32984213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon        first = false;
33084213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon      }
33184213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    }
3323088f83b806b82d866d119e344da274105f42821cushon    if (methDecl.defaultValue().isPresent()) {
333881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" default ");
3343088f83b806b82d866d119e344da274105f42821cushon      methDecl.defaultValue().get().accept(this, null);
335881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(";");
336881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    } else if (methDecl.mods().contains(TurbineModifier.ABSTRACT)
337881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        || methDecl.mods().contains(TurbineModifier.NATIVE)) {
338881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(";");
339881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    } else {
340881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" {}");
341881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
342881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
343881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
344881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
345881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
346881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitAnno(Tree.Anno anno, Void input) {
347881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append('@');
3485bd34220e797da6446ba3f69aae9d62023171a9ecushon    append(Joiner.on('.').join(anno.name()));
349881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!anno.args().isEmpty()) {
350881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('(');
351881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
352881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.Expression e : anno.args()) {
353881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
354881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
355881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
356881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        e.accept(this, null);
357881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
358881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
359881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(')');
360881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
361881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
362881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
363881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
364881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
365881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitTyDecl(Tree.TyDecl tyDecl, Void input) {
366881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (Tree.Anno anno : tyDecl.annos()) {
367881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      anno.accept(this, null);
368881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      printLine();
369881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
370881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printModifiers(tyDecl.mods());
371881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    switch (tyDecl.tykind()) {
372881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case CLASS:
373881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("class");
374881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
375881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case INTERFACE:
376881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("interface");
377881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
378881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case ENUM:
379881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("enum");
380881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
381881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case ANNOTATION:
382881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        append("@interface");
383881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        break;
384881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
385881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(' ').append(tyDecl.name());
386881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!tyDecl.typarams().isEmpty()) {
387881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('<');
388881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
389881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.TyParam t : tyDecl.typarams()) {
390881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
391881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
392881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
393881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
394881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
395881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
396881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append('>');
397881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
398881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (tyDecl.xtnds().isPresent()) {
399881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" extends ");
400881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      tyDecl.xtnds().get().accept(this, null);
401881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
402881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!tyDecl.impls().isEmpty()) {
403881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" implements ");
404881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
405881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree.ClassTy t : tyDecl.impls()) {
406881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
407881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(", ");
408881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
409881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        t.accept(this, null);
410881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
411881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
412881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
413881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(" {").append('\n');
414881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    indent++;
415881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    switch (tyDecl.tykind()) {
416881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      case ENUM:
417881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        {
418881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          List<Tree> nonConsts = new ArrayList<>();
419881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          for (Tree t : tyDecl.members()) {
420881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            if (t instanceof Tree.VarDecl) {
421881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              Tree.VarDecl decl = (Tree.VarDecl) t;
422881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              if (decl.mods().contains(TurbineModifier.ACC_ENUM)) {
423881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon                append(decl.name()).append(',').append('\n');
424881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon                continue;
425881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              }
426881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            }
427881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            nonConsts.add(t);
428881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          }
429881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          printLine(";");
430881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          boolean first = true;
431881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          for (Tree t : nonConsts) {
432881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            if (!first) {
433881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              printLine();
434881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            }
435881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            t.accept(this, null);
436881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            first = false;
437881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          }
438881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
439881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
440881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      default:
441881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        {
442881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          boolean first = true;
443881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          for (Tree t : tyDecl.members()) {
444881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            if (!first) {
445881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon              printLine();
446881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            }
447881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            t.accept(this, null);
448881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon            first = false;
449881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          }
450881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
451881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
452881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
453881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    indent--;
454881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    printLine("}");
455881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
456881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
457881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
458881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  private void printModifiers(ImmutableSet<TurbineModifier> mods) {
459881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    List<TurbineModifier> modifiers = new ArrayList<>(mods);
460881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    Collections.sort(modifiers);
461881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    for (TurbineModifier mod : modifiers) {
462881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      switch (mod) {
463881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case PRIVATE:
464881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case PROTECTED:
465881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case PUBLIC:
466881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ABSTRACT:
467881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case FINAL:
468881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case STATIC:
469881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case VOLATILE:
470881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case SYNCHRONIZED:
471881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case STRICTFP:
472881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case NATIVE:
473881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case TRANSIENT:
474881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case DEFAULT:
475881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(mod.toString()).append(' ');
476881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
477881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_SUPER:
478881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case VARARGS:
479881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case INTERFACE:
480881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_ENUM:
481881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_ANNOTATION:
482881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_SYNTHETIC:
483881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        case ACC_BRIDGE:
484881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          break;
485881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        default:
486881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          throw new AssertionError(mod);
487881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
488881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
489881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
490881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
491881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
492881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitTyParam(Tree.TyParam tyParam, Void input) {
49384213d0af45dfb55e638e2ee1f36007e7bfe5a02cushon    printAnnos(tyParam.annos());
494881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    append(tyParam.name());
495881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    if (!tyParam.bounds().isEmpty()) {
496881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      append(" extends ");
497881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      boolean first = true;
498881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      for (Tree bound : tyParam.bounds()) {
499881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        if (!first) {
500881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon          append(" & ");
501881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        }
502881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        bound.accept(this, null);
503881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon        first = false;
504881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon      }
505881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    }
506881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
507881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
508881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon
509881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  @Override
510881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  public Void visitPkgDecl(Tree.PkgDecl pkgDecl, Void input) {
5110037bd9c79395e6116dc9964de80712e7a603583cushon    for (Tree.Anno anno : pkgDecl.annos()) {
5120037bd9c79395e6116dc9964de80712e7a603583cushon      anno.accept(this, null);
5130037bd9c79395e6116dc9964de80712e7a603583cushon      printLine();
5140037bd9c79395e6116dc9964de80712e7a603583cushon    }
5155bd34220e797da6446ba3f69aae9d62023171a9ecushon    append("package ").append(Joiner.on('.').join(pkgDecl.name())).append(';');
516881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon    return null;
517881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon  }
518881d847a3ccf0bca29a5c809aeb68eff9f467cedcushon}
519