1 /***
2 *
3 * Copyright 2005 Jeremy Rayner
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18 package org.codehaus.groovy.antlr.treewalker;
19
20 import java.io.PrintStream;
21 import java.util.Stack;
22
23 import org.codehaus.groovy.antlr.GroovySourceAST;
24 import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
25
26 /***
27 * An antlr AST visitor that prints groovy source code for each visited node
28 * to the supplied PrintStream.
29 *
30 * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
31 * @version $Revision: 1.13 $
32 */
33
34 public class SourcePrinter extends VisitorAdapter {
35 private String[] tokenNames;
36 private int tabLevel;
37 private int lastLinePrinted;
38 private boolean newLines;
39 protected PrintStream out;
40 private String className;
41 private Stack stack;
42 private int stringConstructorCounter;
43
44 /***
45 * A visitor that prints groovy source code for each node visited.
46 * @param out where to print the source code to
47 * @param tokenNames an array of token names from antlr
48 */
49 public SourcePrinter(PrintStream out,String[] tokenNames) {
50 this(out,tokenNames,true);
51 }
52
53 /***
54 * A visitor that prints groovy source code for each node visited.
55 * @param out where to print the source code to
56 * @param tokenNames an array of token names from antlr
57 * @param newLines output newline character
58 */
59 public SourcePrinter(PrintStream out,String[] tokenNames, boolean newLines) {
60 this.tokenNames = tokenNames;
61 tabLevel = 0;
62 lastLinePrinted = 0;
63 this.out = out;
64 this.newLines = newLines;
65 this.stack = new Stack();
66 }
67
68 public void visitAnnotation(GroovySourceAST t, int visit) {
69 print(t,visit,"@",null," ");
70 }
71
72 public void visitAnnotations(GroovySourceAST t, int visit) {
73 if (t.getNumberOfChildren() > 0) {
74
75 visitDefault(t,visit);
76 }
77 }
78
79 public void visitAssign(GroovySourceAST t,int visit) {
80 print(t,visit," = ",null,null);
81 }
82
83 public void visitCaseGroup(GroovySourceAST t, int visit) {
84 if (visit == OPENING_VISIT) {
85 tabLevel++;
86 }
87 if (visit == CLOSING_VISIT) {
88 tabLevel--;
89 }
90 }
91
92 public void visitClassDef(GroovySourceAST t,int visit) {
93 print(t,visit,"class ",null,null);
94
95 if (visit == OPENING_VISIT) {
96
97 className = t.childOfType(GroovyTokenTypes.IDENT).getText();
98 }
99 }
100
101 public void visitClosedBlock(GroovySourceAST t, int visit) {
102 printUpdatingTabLevel(t,visit,"{"," -> ","}");
103 }
104 public void visitCtorIdent(GroovySourceAST t, int visit) {
105
106 print(t,visit,className,null,null);
107 }
108 public void visitDot(GroovySourceAST t,int visit) {
109 print(t,visit,".",null,null);
110 }
111 public void visitElist(GroovySourceAST t,int visit) {
112 print(t,visit,null,", ",null);
113 }
114
115 public void visitEqual(GroovySourceAST t,int visit) {
116 print(t,visit," == ",null,null);
117 }
118
119 public void visitExpr(GroovySourceAST t,int visit) {
120 }
121
122 public void visitExtendsClause(GroovySourceAST t,int visit) {
123 if (visit == OPENING_VISIT) {
124 if (t.getNumberOfChildren() != 0) {
125 print(t,visit," extends ");
126 }
127 }
128 }
129
130 public void visitForInIterable(GroovySourceAST t, int visit) {
131 printUpdatingTabLevel(t,visit,"("," in ",") ");
132 }
133
134 public void visitGt(GroovySourceAST t, int visit) {
135 print(t,visit," > ",null,null);
136 }
137
138 public void visitIdent(GroovySourceAST t,int visit) {
139 print(t,visit,t.getText(),null,null);
140 }
141 public void visitImplementsClause(GroovySourceAST t,int visit) {
142 if (visit == OPENING_VISIT) {
143 if (t.getNumberOfChildren() != 0) {
144 print(t,visit," implements ");
145 }
146 }
147 if (visit == CLOSING_VISIT) {
148
149 print(t,visit," ");
150 }
151 }
152
153 public void visitImplicitParameters(GroovySourceAST t, int visit) {
154 }
155
156 public void visitImport(GroovySourceAST t,int visit) {
157 print(t,visit,"import ",null,null);
158 }
159
160 public void visitIndexOp(GroovySourceAST t, int visit) {
161 printUpdatingTabLevel(t,visit,"[",null,"]");
162 }
163
164 public void visitLabeledArg(GroovySourceAST t, int visit) {
165 print(t,visit,":",null,null);
166 }
167
168 public void visitLand(GroovySourceAST t, int visit) {
169 print(t,visit," && ",null,null);
170 }
171
172 public void visitListConstructor(GroovySourceAST t, int visit) {
173 printUpdatingTabLevel(t,visit,"[",null,"]");
174 }
175
176 public void visitLiteralAssert(GroovySourceAST t,int visit) {
177 print(t,visit,"assert ",null,null);
178 }
179
180 public void visitLiteralBoolean(GroovySourceAST t, int visit) {
181 print(t,visit,"boolean",null,null);
182 }
183
184 public void visitLiteralBreak(GroovySourceAST t, int visit) {
185 print(t,visit,"break",null,null);
186 }
187
188 public void visitLiteralCase(GroovySourceAST t, int visit) {
189 print(t,visit,"case ",null,":");
190 }
191
192 public void visitLiteralCatch(GroovySourceAST t,int visit) {
193 printUpdatingTabLevel(t,visit," catch (",null,") ");
194 }
195 public void visitLiteralFalse(GroovySourceAST t,int visit) {
196 print(t,visit,"false",null,null);
197 }
198
199 public void visitLiteralFloat(GroovySourceAST t,int visit) {
200 print(t,visit,"float",null,null);
201 }
202
203 public void visitLiteralFor(GroovySourceAST t,int visit) {
204 print(t,visit,"for ",null,null);
205 }
206
207 public void visitLiteralIf(GroovySourceAST t,int visit) {
208
209 printUpdatingTabLevel(t,visit,"if ("," else ",") ");
210 }
211
212 public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
213 print(t,visit," instanceof ",null,null);
214 }
215
216 public void visitLiteralInt(GroovySourceAST t,int visit) {
217 print(t,visit,"int",null,null);
218 }
219
220 public void visitLiteralNew(GroovySourceAST t,int visit) {
221 print(t,visit,"new ","(",")");
222 }
223
224 public void visitLiteralNull(GroovySourceAST t, int visit) {
225 print(t,visit,"null",null,null);
226 }
227
228 public void visitLiteralPrivate(GroovySourceAST t,int visit) {
229 print(t,visit,"private ",null,null);
230 }
231
232 public void visitLiteralProtected(GroovySourceAST t,int visit) {
233 print(t,visit,"protected ",null,null);
234 }
235
236 public void visitLiteralPublic(GroovySourceAST t,int visit) {
237 print(t,visit,"public ",null,null);
238 }
239
240 public void visitLiteralReturn(GroovySourceAST t, int visit) {
241 print(t,visit,"return ",null,null);
242 }
243
244 public void visitLiteralStatic(GroovySourceAST t, int visit) {
245 print(t,visit,"static ",null,null);
246 }
247
248 public void visitLiteralSwitch(GroovySourceAST t, int visit) {
249 if (visit == OPENING_VISIT) {
250 print(t,visit,"switch (");
251 tabLevel++;
252 }
253 if (visit == SUBSEQUENT_VISIT) {
254 print(t,visit,") {");
255 }
256 if (visit == CLOSING_VISIT) {
257 tabLevel--;
258 print(t,visit,"}");
259 }
260 }
261
262 public void visitLiteralThis(GroovySourceAST t, int visit) {
263 print(t,visit,"this",null,null);
264 }
265
266 public void visitLiteralThrow(GroovySourceAST t, int visit) {
267 print(t,visit,"throw ",null,null);
268 }
269
270 public void visitLiteralTrue(GroovySourceAST t,int visit) {
271 print(t,visit,"true",null,null);
272 }
273 public void visitLiteralTry(GroovySourceAST t,int visit) {
274 print(t,visit,"try ",null,null);
275 }
276 public void visitLiteralVoid(GroovySourceAST t,int visit) {
277 print(t,visit,"void",null," ");
278 }
279 public void visitLiteralWhile(GroovySourceAST t,int visit) {
280 printUpdatingTabLevel(t,visit,"while (",null,") ");
281 }
282
283 public void visitLnot(GroovySourceAST t, int visit) {
284 print(t,visit,"!",null,null);
285 }
286
287 public void visitLt(GroovySourceAST t, int visit) {
288 print(t,visit," < ",null,null);
289 }
290
291 public void visitMapConstructor(GroovySourceAST t, int visit) {
292 if (t.getNumberOfChildren() == 0) {
293 print(t,visit,"[:]",null,null);
294 } else {
295 printUpdatingTabLevel(t,visit,"[",null,"]");
296 }
297 }
298
299 public void visitMemberPointer(GroovySourceAST t, int visit) {
300 print(t,visit,".&",null,null);
301 }
302
303 public void visitMethodCall(GroovySourceAST t,int visit) {
304 printUpdatingTabLevel(t,visit,"("," ",")");
305 }
306 public void visitMinus(GroovySourceAST t,int visit) {
307 print(t,visit," - ",null,null);
308 }
309 public void visitMethodDef(GroovySourceAST t,int visit) {
310
311 }
312 public void visitModifiers(GroovySourceAST t,int visit) {
313
314 }
315
316 public void visitNotEqual(GroovySourceAST t, int visit) {
317 print(t,visit," != ",null,null);
318 }
319
320 public void visitNumInt(GroovySourceAST t,int visit) {
321 print(t,visit,t.getText(),null,null);
322 }
323 public void visitNumFloat(GroovySourceAST t,int visit) {
324 print(t,visit,t.getText(),null,null);
325 }
326 public void visitObjblock(GroovySourceAST t,int visit) {
327 if (visit == OPENING_VISIT) {
328 tabLevel++;
329 print(t,visit,"{");
330 } else {
331 tabLevel--;
332 print(t,visit,"}");
333 }
334 }
335
336 public void visitPackageDef(GroovySourceAST t, int visit) {
337 print(t,visit,"package ",null,null);
338 }
339
340 public void visitParameterDef(GroovySourceAST t,int visit) {
341
342 }
343
344 public void visitParameters(GroovySourceAST t,int visit) {
345 printUpdatingTabLevel(t,visit,"(",", ",") ");
346 }
347
348 public void visitPlus(GroovySourceAST t, int visit) {
349 print(t,visit," + ",null,null);
350 }
351
352 public void visitQuestion(GroovySourceAST t, int visit) {
353
354 print(t,visit,"?",":",null);
355 }
356
357 public void visitRangeExclusive(GroovySourceAST t, int visit) {
358 print(t,visit,"..<",null,null);
359 }
360
361 public void visitRangeInclusive(GroovySourceAST t, int visit) {
362 print(t,visit,"..",null,null);
363 }
364
365 public void visitSlist(GroovySourceAST t,int visit) {
366 if (visit == OPENING_VISIT) {
367 tabLevel++;
368 print(t,visit,"{");
369 } else {
370 tabLevel--;
371 print(t,visit,"}");
372 }
373 }
374
375 public void visitStar(GroovySourceAST t,int visit) {
376 print(t,visit,"*",null,null);
377 }
378 public void visitStringConstructor(GroovySourceAST t,int visit) {
379 if (visit == OPENING_VISIT) {
380 stringConstructorCounter = 0;
381 print(t,visit,"\"");
382 }
383 if (visit == SUBSEQUENT_VISIT) {
384
385 if (stringConstructorCounter % 2 == 0) {
386 print(t,visit,"$");
387 }
388 stringConstructorCounter++;
389 }
390 if (visit == CLOSING_VISIT) {
391 print(t,visit,"\"");
392 }
393 }
394
395 public void visitStringLiteral(GroovySourceAST t,int visit) {
396 if (visit == OPENING_VISIT) {
397 String theString = escape(t.getText());
398 if (getParentNode().getType() != GroovyTokenTypes.LABELED_ARG &&
399 getParentNode().getType() != GroovyTokenTypes.STRING_CONSTRUCTOR) {
400 theString = "\"" + theString + "\"";
401 }
402 print(t,visit,theString);
403 }
404 }
405
406 private String escape(String literal) {
407 literal = literal.replaceAll("\n","////<<REMOVE>>n");
408 literal = literal.replaceAll("<<REMOVE>>","");
409 return literal;
410 }
411
412 public void visitType(GroovySourceAST t,int visit) {
413 GroovySourceAST parent = getParentNode();
414 GroovySourceAST modifiers = parent.childOfType(GroovyTokenTypes.MODIFIERS);
415
416
417 if (modifiers == null || modifiers.getNumberOfChildren() == 0) {
418
419 if (visit == OPENING_VISIT) {
420 if (t.getNumberOfChildren() == 0) {
421 print(t,visit,"def");
422 }
423 }
424 if (visit == CLOSING_VISIT) {
425 print(t,visit," ");
426 }
427 }
428 }
429
430 public void visitTypecast(GroovySourceAST t,int visit) {
431 print(t,visit,"(",null,")");
432 }
433
434 public void visitVariableDef(GroovySourceAST t,int visit) {
435
436 }
437
438 public void visitDefault(GroovySourceAST t,int visit) {
439 if (visit == OPENING_VISIT) {
440 print(t,visit,"<" + tokenNames[t.getType()] + ">");
441
442 } else {
443 print(t,visit,"</" + tokenNames[t.getType()] + ">");
444
445 }
446 }
447
448 protected void printUpdatingTabLevel(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
449 if (visit == OPENING_VISIT && opening != null) {
450 print(t,visit,opening);
451 tabLevel++;
452 }
453 if (visit == SUBSEQUENT_VISIT && subsequent != null) {
454 print(t,visit,subsequent);
455 }
456 if (visit == CLOSING_VISIT && closing != null) {
457 tabLevel--;
458 print(t,visit,closing);
459 }
460 }
461
462 protected void print(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
463 if (visit == OPENING_VISIT && opening != null) {
464 print(t,visit,opening);
465 }
466 if (visit == SUBSEQUENT_VISIT && subsequent != null) {
467 print(t,visit,subsequent);
468 }
469 if (visit == CLOSING_VISIT && closing != null) {
470 print(t,visit,closing);
471 }
472 }
473 protected void print(GroovySourceAST t,int visit,String value) {
474 if(visit == OPENING_VISIT) {
475 printNewlineAndIndent(t, visit);
476 }
477 if (visit == CLOSING_VISIT) {
478 printNewlineAndIndent(t, visit);
479 }
480 out.print(value);
481 }
482
483 protected void printNewlineAndIndent(GroovySourceAST t, int visit) {
484 int currentLine = t.getLine();
485 if (lastLinePrinted == 0) { lastLinePrinted = currentLine; }
486 if (lastLinePrinted != currentLine) {
487 if (newLines) {
488 if (!(visit == OPENING_VISIT && t.getType() == GroovyTokenTypes.SLIST)) {
489 for (int i=lastLinePrinted;i<currentLine;i++) {
490 out.println();
491 }
492 if (lastLinePrinted > currentLine) {
493 out.println();
494 }
495 if (visit == OPENING_VISIT || (visit == CLOSING_VISIT && lastLinePrinted > currentLine)) {
496 for (int i=0;i<tabLevel;i++) {
497 out.print(" ");
498 }
499 }
500 }
501 }
502 lastLinePrinted = Math.max(currentLine,lastLinePrinted);
503 }
504 }
505
506 public void push(GroovySourceAST t) {
507 stack.push(t);
508 }
509 public GroovySourceAST pop() {
510 if (!stack.empty()) {
511 return (GroovySourceAST) stack.pop();
512 }
513 return null;
514 }
515
516 private GroovySourceAST getParentNode() {
517 Object currentNode = stack.pop();
518 Object parentNode = stack.peek();
519 stack.push(currentNode);
520 return (GroovySourceAST) parentNode;
521 }
522
523 }