View Javadoc

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              //todo - default line below is just a placeholder
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              // store name of class away for use in constructor ident
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         // use name of class for constructor from the class definition
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             //space between classdef and objblock
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         // slightly strange as subsequent visit is done after closing visit
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         //do nothing
311     }
312     public void visitModifiers(GroovySourceAST t,int visit) {
313         //do nothing
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         //do nothing
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         // ternary operator
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             // every other subsequent visit use an escaping $
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"); // can't seem to do \n in one go with Java regex
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         // No need to print 'def' if we already have some modifiers
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         // do nothing
436     }
437 
438     public void visitDefault(GroovySourceAST t,int visit) {
439         if (visit == OPENING_VISIT) {
440             print(t,visit,"<" + tokenNames[t.getType()] + ">");
441             //out.print("<" + t.getType() + ">");
442         } else {
443             print(t,visit,"</" + tokenNames[t.getType()] + ">");
444             //out.print("</" + t.getType() + ">");
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 }