001 /**
002 *
003 * Copyright 2005 Jeremy Rayner
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 **/
018 package org.codehaus.groovy.antlr.treewalker;
019
020 import java.io.PrintStream;
021
022 import org.codehaus.groovy.antlr.GroovySourceAST;
023 import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
024
025 /**
026 * An antlr AST visitor that prints groovy source code for each visited node
027 * to the supplied PrintStream.
028 *
029 * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
030 * @version $Revision: 1.12 $
031 */
032
033 public class SourcePrinter extends VisitorAdapter {
034 private String[] tokenNames;
035 private int tabLevel;
036 private int lastLinePrinted;
037 private boolean newLines;
038 protected PrintStream out;
039 private String className;
040
041 /**
042 * A visitor that prints groovy source code for each node visited.
043 * @param out where to print the source code to
044 * @param tokenNames an array of token names from antlr
045 */
046 public SourcePrinter(PrintStream out,String[] tokenNames) {
047 this(out,tokenNames,true);
048 }
049
050 /**
051 * A visitor that prints groovy source code for each node visited.
052 * @param out where to print the source code to
053 * @param tokenNames an array of token names from antlr
054 * @param newLines output newline character
055 */
056 public SourcePrinter(PrintStream out,String[] tokenNames, boolean newLines) {
057 this.tokenNames = tokenNames;
058 tabLevel = 0;
059 lastLinePrinted = 0;
060 this.out = out;
061 this.newLines = newLines;
062 }
063
064 public void visitAnnotation(GroovySourceAST t, int visit) {
065 print(t,visit,"@",null,null);
066 }
067
068 public void visitAnnotations(GroovySourceAST t, int visit) {
069 if (t.getNumberOfChildren() > 0) {
070 //todo - default line below is just a placeholder
071 visitDefault(t,visit);
072 }
073 }
074
075 public void visitAssign(GroovySourceAST t,int visit) {
076 print(t,visit," = ",null,null);
077 }
078
079 public void visitCaseGroup(GroovySourceAST t, int visit) {
080 if (visit == OPENING_VISIT) {
081 tabLevel++;
082 }
083 if (visit == CLOSING_VISIT) {
084 tabLevel--;
085 }
086 }
087
088 public void visitClassDef(GroovySourceAST t,int visit) {
089 print(t,visit,"class ",null,null);
090
091 if (visit == OPENING_VISIT) {
092 // store name of class away for use in constructor ident
093 className = t.childOfType(GroovyTokenTypes.IDENT).getText();
094 }
095 }
096
097 public void visitClosedBlock(GroovySourceAST t, int visit) {
098 printUpdatingTabLevel(t,visit,"{"," -> ","}");
099 }
100 public void visitCtorIdent(GroovySourceAST t, int visit) {
101 // use name of class for constructor from the class definition
102 print(t,visit,className,null,null);
103 }
104 public void visitDot(GroovySourceAST t,int visit) {
105 print(t,visit,".",null,null);
106 }
107 public void visitElist(GroovySourceAST t,int visit) {
108 print(t,visit,null,", ",null);
109 }
110
111 public void visitEqual(GroovySourceAST t,int visit) {
112 print(t,visit," == ",null,null);
113 }
114
115 public void visitExpr(GroovySourceAST t,int visit) {
116 }
117
118 public void visitExtendsClause(GroovySourceAST t,int visit) {
119 if (visit == OPENING_VISIT) {
120 if (t.getNumberOfChildren() != 0) {
121 print(t,visit," extends ");
122 }
123 }
124 }
125
126 public void visitForInIterable(GroovySourceAST t, int visit) {
127 printUpdatingTabLevel(t,visit,"("," in ",") ");
128 }
129
130 public void visitGt(GroovySourceAST t, int visit) {
131 print(t,visit," > ",null,null);
132 }
133
134 public void visitIdent(GroovySourceAST t,int visit) {
135 print(t,visit,t.getText(),null,null);
136 }
137 public void visitImplementsClause(GroovySourceAST t,int visit) {
138 if (visit == OPENING_VISIT) {
139 if (t.getNumberOfChildren() != 0) {
140 print(t,visit," implements ");
141 }
142 }
143 if (visit == CLOSING_VISIT) {
144 //space between classdef and objblock
145 print(t,visit," ");
146 }
147 }
148
149 public void visitImplicitParameters(GroovySourceAST t, int visit) {
150 }
151
152 public void visitImport(GroovySourceAST t,int visit) {
153 print(t,visit,"import ",null,null);
154 }
155
156 public void visitIndexOp(GroovySourceAST t, int visit) {
157 printUpdatingTabLevel(t,visit,"[",null,"]");
158 }
159
160 public void visitLabeledArg(GroovySourceAST t, int visit) {
161 print(t,visit,":",null,null);
162 }
163
164 public void visitLand(GroovySourceAST t, int visit) {
165 print(t,visit," && ",null,null);
166 }
167
168 public void visitListConstructor(GroovySourceAST t, int visit) {
169 printUpdatingTabLevel(t,visit,"[",null,"]");
170 }
171
172 public void visitLiteralAssert(GroovySourceAST t,int visit) {
173 print(t,visit,"assert ",null,null);
174 }
175
176 public void visitLiteralBoolean(GroovySourceAST t, int visit) {
177 print(t,visit,"boolean",null,null);
178 }
179
180 public void visitLiteralBreak(GroovySourceAST t, int visit) {
181 print(t,visit,"break",null,null);
182 }
183
184 public void visitLiteralCase(GroovySourceAST t, int visit) {
185 print(t,visit,"case ",null,":");
186 }
187
188 public void visitLiteralCatch(GroovySourceAST t,int visit) {
189 printUpdatingTabLevel(t,visit," catch (",null,") ");
190 }
191 public void visitLiteralFalse(GroovySourceAST t,int visit) {
192 print(t,visit,"false",null,null);
193 }
194
195 public void visitLiteralFloat(GroovySourceAST t,int visit) {
196 print(t,visit,"float",null,null);
197 }
198
199 public void visitLiteralFor(GroovySourceAST t,int visit) {
200 print(t,visit,"for ",null,null);
201 }
202
203 public void visitLiteralIf(GroovySourceAST t,int visit) {
204 // slightly strange as subsequent visit is done after closing visit
205 printUpdatingTabLevel(t,visit,"if ("," else ",") ");
206 }
207
208 public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
209 print(t,visit," instanceof ",null,null);
210 }
211
212 public void visitLiteralInt(GroovySourceAST t,int visit) {
213 print(t,visit,"int",null,null);
214 }
215
216 public void visitLiteralNew(GroovySourceAST t,int visit) {
217 print(t,visit,"new ","(",")");
218 }
219
220 public void visitLiteralNull(GroovySourceAST t, int visit) {
221 print(t,visit,"null",null,null);
222 }
223
224 public void visitLiteralPrivate(GroovySourceAST t,int visit) {
225 print(t,visit,"private ",null,null);
226 }
227
228 public void visitLiteralProtected(GroovySourceAST t,int visit) {
229 print(t,visit,"protected ",null,null);
230 }
231
232 public void visitLiteralPublic(GroovySourceAST t,int visit) {
233 print(t,visit,"public ",null,null);
234 }
235
236 public void visitLiteralReturn(GroovySourceAST t, int visit) {
237 print(t,visit,"return ",null,null);
238 }
239
240 public void visitLiteralStatic(GroovySourceAST t, int visit) {
241 print(t,visit,"static ",null,null);
242 }
243
244 public void visitLiteralSwitch(GroovySourceAST t, int visit) {
245 if (visit == OPENING_VISIT) {
246 print(t,visit,"switch (");
247 tabLevel++;
248 }
249 if (visit == SUBSEQUENT_VISIT) {
250 print(t,visit,") {");
251 }
252 if (visit == CLOSING_VISIT) {
253 tabLevel--;
254 print(t,visit,"}");
255 }
256 }
257
258 public void visitLiteralThis(GroovySourceAST t, int visit) {
259 print(t,visit,"this",null,null);
260 }
261
262 public void visitLiteralThrow(GroovySourceAST t, int visit) {
263 print(t,visit,"throw ",null,null);
264 }
265
266 public void visitLiteralTrue(GroovySourceAST t,int visit) {
267 print(t,visit,"true",null,null);
268 }
269 public void visitLiteralTry(GroovySourceAST t,int visit) {
270 print(t,visit,"try ",null,null);
271 }
272 public void visitLiteralVoid(GroovySourceAST t,int visit) {
273 print(t,visit,"void",null,null);
274 }
275 public void visitLiteralWhile(GroovySourceAST t,int visit) {
276 printUpdatingTabLevel(t,visit,"while (",null,") ");
277 }
278
279 public void visitLnot(GroovySourceAST t, int visit) {
280 print(t,visit,"!",null,null);
281 }
282
283 public void visitLt(GroovySourceAST t, int visit) {
284 print(t,visit," < ",null,null);
285 }
286
287 public void visitMapConstructor(GroovySourceAST t, int visit) {
288 if (t.getNumberOfChildren() == 0) {
289 print(t,visit,"[:]",null,null);
290 } else {
291 printUpdatingTabLevel(t,visit,"[",null,"]");
292 }
293 }
294
295 public void visitMemberPointer(GroovySourceAST t, int visit) {
296 print(t,visit,".&",null,null);
297 }
298
299 public void visitMethodCall(GroovySourceAST t,int visit) {
300 printUpdatingTabLevel(t,visit,"("," ",")");
301 }
302 public void visitMinus(GroovySourceAST t,int visit) {
303 print(t,visit," - ",null,null);
304 }
305 public void visitMethodDef(GroovySourceAST t,int visit) {
306 //do nothing
307 }
308 public void visitModifiers(GroovySourceAST t,int visit) {
309 //do nothing
310 }
311
312 public void visitNotEqual(GroovySourceAST t, int visit) {
313 print(t,visit," != ",null,null);
314 }
315
316 public void visitNumInt(GroovySourceAST t,int visit) {
317 print(t,visit,t.getText(),null,null);
318 }
319 public void visitNumFloat(GroovySourceAST t,int visit) {
320 print(t,visit,t.getText(),null,null);
321 }
322 public void visitObjblock(GroovySourceAST t,int visit) {
323 if (visit == OPENING_VISIT) {
324 tabLevel++;
325 print(t,visit,"{");
326 } else {
327 tabLevel--;
328 print(t,visit,"}");
329 }
330 }
331
332 public void visitPackageDef(GroovySourceAST t, int visit) {
333 print(t,visit,"package ",null,null);
334 }
335
336 public void visitParameterDef(GroovySourceAST t,int visit) {
337 //do nothing
338 }
339
340 public void visitParameters(GroovySourceAST t,int visit) {
341 printUpdatingTabLevel(t,visit,"(",", ",") ");
342 }
343
344 public void visitPlus(GroovySourceAST t, int visit) {
345 print(t,visit," + ",null,null);
346 }
347
348 public void visitQuestion(GroovySourceAST t, int visit) {
349 // ternary operator
350 print(t,visit,"?",":",null);
351 }
352
353 public void visitRangeExclusive(GroovySourceAST t, int visit) {
354 print(t,visit,"..<",null,null);
355 }
356
357 public void visitRangeInclusive(GroovySourceAST t, int visit) {
358 print(t,visit,"..",null,null);
359 }
360
361 public void visitSlist(GroovySourceAST t,int visit) {
362 if (visit == OPENING_VISIT) {
363 tabLevel++;
364 print(t,visit,"{");
365 } else {
366 tabLevel--;
367 print(t,visit,"}");
368 }
369 }
370
371 public void visitStar(GroovySourceAST t,int visit) {
372 print(t,visit,"*",null,null);
373 }
374 public void visitStringConstructor(GroovySourceAST t,int visit) {
375 print(t,visit,null," + ",null); // string concatenate, so ("abc$foo") becomes ("abc" + foo) for now (todo)
376 }
377
378 public void visitStringLiteral(GroovySourceAST t,int visit) {
379 print(t,visit,"\"" + escape(t.getText()) + "\"",null,null);
380 }
381
382 private String escape(String literal) {
383 literal = literal.replaceAll("\n","\\\\<<REMOVE>>n"); // can't seem to do \n in one go with Java regex
384 literal = literal.replaceAll("<<REMOVE>>","");
385 return literal;
386 }
387
388 public void visitType(GroovySourceAST t,int visit) {
389 if (visit == OPENING_VISIT) {
390 if (t.getNumberOfChildren() == 0) {
391 print(t,visit,"def");
392 }
393 }
394 if (visit == CLOSING_VISIT) {
395 print(t,visit," ");
396 }
397 }
398
399 public void visitTypecast(GroovySourceAST t,int visit) {
400 print(t,visit,"(",null,")");
401 }
402
403 public void visitVariableDef(GroovySourceAST t,int visit) {
404 // do nothing
405 }
406
407 public void visitDefault(GroovySourceAST t,int visit) {
408 if (visit == OPENING_VISIT) {
409 print(t,visit,"<" + tokenNames[t.getType()] + ">");
410 //out.print("<" + t.getType() + ">");
411 } else {
412 print(t,visit,"</" + tokenNames[t.getType()] + ">");
413 //out.print("</" + t.getType() + ">");
414 }
415 }
416 protected void printUpdatingTabLevel(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
417 if (visit == OPENING_VISIT && opening != null) {
418 print(t,visit,opening);
419 tabLevel++;
420 }
421 if (visit == SUBSEQUENT_VISIT && subsequent != null) {
422 print(t,visit,subsequent);
423 }
424 if (visit == CLOSING_VISIT && closing != null) {
425 tabLevel--;
426 print(t,visit,closing);
427 }
428 }
429
430 protected void print(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
431 if (visit == OPENING_VISIT && opening != null) {
432 print(t,visit,opening);
433 }
434 if (visit == SUBSEQUENT_VISIT && subsequent != null) {
435 print(t,visit,subsequent);
436 }
437 if (visit == CLOSING_VISIT && closing != null) {
438 print(t,visit,closing);
439 }
440 }
441 protected void print(GroovySourceAST t,int visit,String value) {
442 if(visit == OPENING_VISIT) {
443 printNewlineAndIndent(t, visit);
444 }
445 if (visit == CLOSING_VISIT) {
446 printNewlineAndIndent(t, visit);
447 }
448 out.print(value);
449 }
450
451 protected void printNewlineAndIndent(GroovySourceAST t, int visit) {
452 int currentLine = t.getLine();
453 if (lastLinePrinted == 0) { lastLinePrinted = currentLine; }
454 if (lastLinePrinted != currentLine) {
455 if (newLines) {
456 if (!(visit == OPENING_VISIT && t.getType() == GroovyTokenTypes.SLIST)) {
457 for (int i=lastLinePrinted;i<currentLine;i++) {
458 out.println();
459 }
460 if (lastLinePrinted > currentLine) {
461 out.println();
462 }
463 if (visit == OPENING_VISIT || (visit == CLOSING_VISIT && lastLinePrinted > currentLine)) {
464 for (int i=0;i<tabLevel;i++) {
465 out.print(" ");
466 }
467 }
468 }
469 }
470 lastLinePrinted = Math.max(currentLine,lastLinePrinted);
471 }
472 }
473 }