View Javadoc
Minimize
Table

1   /*
2    * Copyright 2003-2007 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.codehaus.groovy.antlr.treewalker;
17  
18  import java.io.PrintStream;
19  import java.util.Stack;
20  
21  import antlr.collections.AST;
22  import org.codehaus.groovy.antlr.GroovySourceAST;
23  import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
24  
25  /**
26   * An antlr AST visitor that prints groovy source code for each visited node
27   * to the supplied PrintStream.
28   *
29   * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
30   * @version $Revision: 21821 $
31   */
32  
33  public class SourcePrinter extends VisitorAdapter {
34      private final String[] tokenNames;
35      private int tabLevel;
36      private int lastLinePrinted;
37      private final boolean newLines;
38      protected final PrintStream out;
39      private String className;
40      private final Stack stack;
41      private int stringConstructorCounter;
42  
43      /**
44       * A visitor that prints groovy source code for each node visited.
45       * @param out where to print the source code to
46       * @param tokenNames an array of token names from antlr
47       */
48      public SourcePrinter(PrintStream out,String[] tokenNames) {
49          this(out,tokenNames,true);
50      }
51  
52      /**
53       * A visitor that prints groovy source code for each node visited.
54       * @param out where to print the source code to
55       * @param tokenNames an array of token names from antlr
56       * @param newLines output newline character
57       */
58      public SourcePrinter(PrintStream out,String[] tokenNames, boolean newLines) {
59          this.tokenNames = tokenNames;
60          tabLevel = 0;
61          lastLinePrinted = 0;
62          this.out = out;
63          this.newLines = newLines;
64          this.stack = new Stack();
65      }
66      
67  
68      public void visitAbstract(GroovySourceAST t, int visit) {
69          print(t,visit,"abstract ",null,null);
70      }
71  
72      public void visitAnnotation(GroovySourceAST t, int visit) {
73          if (visit == OPENING_VISIT) {
74              print(t,visit,"@");
75          }
76          if (visit == SECOND_VISIT) {
77              print(t,visit,"(");
78          }
79          if (visit == SUBSEQUENT_VISIT) {
80              print(t,visit,", ");
81          }
82          if (visit == CLOSING_VISIT) {
83              if (t.getNumberOfChildren() > 1) {
84                  print(t,visit,") ");
85              } else {
86                  print(t,visit," ");
87              }
88          }
89  
90      }
91  
92      public void visitAnnotations(GroovySourceAST t, int visit) {
93          // do nothing
94      }
95  
96      public void visitAnnotationDef(GroovySourceAST t,int visit) {
97          print(t,visit,"@interface ",null,null);
98      }
99  
100     public void visitAnnotationFieldDef(GroovySourceAST t, int visit) {
101         print(t,visit,"() ","default ",null);
102     }
103 
104     public void visitAnnotationMemberValuePair(GroovySourceAST t, int visit) {
105         print(t,visit," = ",null,null);
106     }
107 
108     public void visitArrayDeclarator(GroovySourceAST t, int visit) {
109         //<ARRAY_DECLARATOR>int</ARRAY_DECLARATOR> primes = new int(<ARRAY_DECLARATOR>5</ARRAY_DECLARATOR>)
110         if (getParentNode().getType() == GroovyTokenTypes.TYPE ||
111                 getParentNode().getType() == GroovyTokenTypes.TYPECAST) { // ugly hack
112             // type definition, i.e.   int[] x;
113             print(t,visit,null,null,"[]");
114         } else {
115             // usually in new, i.e.   def y = new int[5];
116             print(t,visit,"[",null,"]");
117         }
118     }
119 
120     public void visitAssign(GroovySourceAST t,int visit) {
121         print(t,visit," = ",null,null);
122     }
123     
124     // visitAt() ...
125     //   token type 'AT' should never be visited, as annotation definitions and usage, and
126     //   direct field access should have all moved this token out of the way. No test needed.
127 
128     //   one of the BAND tokens is actually replaced by TYPE_UPPER_BOUNDS (e.g. class Foo<T extends C & I> {T t} )
129     public void visitBand(GroovySourceAST t, int visit) {
130         print(t,visit," & ",null,null);
131     }
132 
133     public void visitBandAssign(GroovySourceAST t,int visit) {
134         print(t,visit," &= ",null,null);
135     }
136     
137     // visitBigSuffix() ...
138     //   token type BIG_SUFFIX never created/visited, NUM_BIG_INT, NUM_BIG_DECIMAL instead...    
139     
140     // visitBlock() ...
141     //   token type BLOCK never created/visited, see CLOSABLE_BLOCK etc...
142     
143     public void visitBnot(GroovySourceAST t, int visit) {
144         print(t,visit,"~",null,null);
145     }
146     
147     // Note: old closure syntax using BOR is deprecated, and also never creates/visits a BOR node
148     public void visitBor(GroovySourceAST t, int visit) {
149         print(t,visit," | ",null,null);
150     }
151     
152     public void visitBorAssign(GroovySourceAST t,int visit) {
153         print(t,visit," |= ",null,null);
154     }
155     
156     public void visitBsr(GroovySourceAST t, int visit) {
157         print(t,visit," >>> ",null,null);
158     }
159     
160     public void visitBsrAssign(GroovySourceAST t,int visit) {
161         print(t,visit," >>>= ",null,null);
162     }
163     
164     public void visitBxor(GroovySourceAST t, int visit) {
165         print(t,visit," ^ ",null,null);
166     }
167     
168     public void visitBxorAssign(GroovySourceAST t,int visit) {
169         print(t,visit," ^= ",null,null);
170     }
171     
172     public void visitCaseGroup(GroovySourceAST t, int visit) {
173         if (visit == OPENING_VISIT) {
174             tabLevel++;
175         }
176         if (visit == CLOSING_VISIT) {
177             tabLevel--;
178         }
179     }
180 
181     public void visitClassDef(GroovySourceAST t,int visit) {
182         print(t,visit,"class ",null,null);
183 
184         if (visit == OPENING_VISIT) {
185             // store name of class away for use in constructor ident
186             className = t.childOfType(GroovyTokenTypes.IDENT).getText();
187         }
188     }
189 
190     public void visitClosedBlock(GroovySourceAST t, int visit) {
191         printUpdatingTabLevel(t,visit,"{","-> ","}");
192     }
193     
194     public void visitClosureList(GroovySourceAST t, int visit) {
195         print(t,visit,"(","; ",")");
196     }
197     // visitClosureOp ...
198     //   token type CLOSABLE_BLOCK_OP never created/visited, see CLOSABLE_BLOCK...
199     
200 
201     // visitColon ...
202     //   token type COLON never created/visited, see LABELED_STAT, FOR_IN_ITERABLE, 
203     //   ASSERT, CASE, QUESTION, MAP_CONSTRUCTOR, LABELED_ARG, SPREAD_MAP_ARG
204 
205     // visitComma ...
206     //   token type COMMA never created/visited,
207     //   see TYPE_ARGUMENTS, ANNOTATION, many others ...
208     
209     public void visitCompareTo(GroovySourceAST t,int visit) {
210         print(t,visit," <=> ",null,null);
211     }
212 
213     public void visitCtorCall(GroovySourceAST t,int visit) {
214         printUpdatingTabLevel(t,visit,"this("," ",")");
215     }
216 
217     public void visitCtorIdent(GroovySourceAST t, int visit) {
218         // use name of class for constructor from the class definition
219         print(t,visit,className,null,null);
220     }
221 
222     public void visitDec(GroovySourceAST t, int visit) {
223         print(t,visit,"--",null,null);
224     }
225     
226     // visitDigit ...
227     //    never created/visited
228     
229     public void visitDiv(GroovySourceAST t, int visit) {
230         print(t,visit," / ",null,null);
231     }
232 
233     public void visitDivAssign(GroovySourceAST t,int visit) {
234         print(t,visit," /= ",null,null);
235     }
236     
237     // visitDollar ...
238     //   token type DOLLAR never created/visited, see SCOPE_ESCAPE instead
239     
240     public void visitDot(GroovySourceAST t,int visit) {
241         print(t,visit,".",null,null);
242     }
243     
244     public void visitDynamicMember(GroovySourceAST t, int visit) {
245         if (t.childOfType(GroovyTokenTypes.STRING_CONSTRUCTOR) == null) {
246             printUpdatingTabLevel(t,visit,"(",null,")");
247         }
248     }
249     
250     public void visitElist(GroovySourceAST t,int visit) {
251         if (getParentNode().getType() == GroovyTokenTypes.ENUM_CONSTANT_DEF) {
252             print(t,visit,"(",", ",")");
253         } else {
254             print(t,visit,null,", ",null);
255         }
256     }
257 
258     // visitEmptyStat ...
259     //   token type EMPTY_STAT obsolete and should be removed, never visited/created
260     
261     public void visitEnumConstantDef(GroovySourceAST t,int visit) {
262         GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
263         if (sibling != null && sibling.getType() == GroovyTokenTypes.ENUM_CONSTANT_DEF) {
264             print(t,visit,null,null,", ");
265         }
266     }
267 
268     public void visitEnumDef(GroovySourceAST t,int visit) {
269         print(t,visit,"enum ",null,null);
270     }
271 
272     // visitEof ...
273     //   token type EOF never visited/created
274 
275     public void visitEqual(GroovySourceAST t,int visit) {
276         print(t,visit," == ",null,null);
277     }
278 
279     // visitExponent ...
280     //   token type EXPONENT only used by lexer, never visited/created
281     
282     public void visitExpr(GroovySourceAST t,int visit) {
283         // do nothing
284     }
285 
286     public void visitExtendsClause(GroovySourceAST t,int visit) {
287         if (visit == OPENING_VISIT) {
288             if (t.getNumberOfChildren() != 0) {
289                 print(t,visit," extends ");
290             }
291         }
292     }
293     
294     public void visitFinal(GroovySourceAST t, int visit) {
295         print(t,visit,"final ",null,null);
296     }
297 
298     // visitFloatSuffix ... never visited/created see NUM_DOUBLE or NUM_FLOAT instead
299     
300     public void visitForCondition(GroovySourceAST t, int visit) {
301         print(t,visit," ; ",null,null);
302     }
303     
304     // visitForEachClause ... 
305     //   FOR_EACH_CLAUSE obsolete and should be removed, never visited/created
306 
307     public void visitForInit(GroovySourceAST t, int visit) {
308         print(t,visit,"(",null,null);
309     }
310     
311     public void visitForInIterable(GroovySourceAST t, int visit) {
312         printUpdatingTabLevel(t,visit,"("," in ",") ");
313     }
314 
315     public void visitForIterator(GroovySourceAST t, int visit) {
316         print(t,visit," ; ",null,")");
317     }
318     
319     public void visitGe(GroovySourceAST t, int visit) {
320         print(t,visit," >= ",null,null);
321     }
322     
323     public void visitGt(GroovySourceAST t, int visit) {
324         print(t,visit," > ",null,null);
325     }
326 
327     public void visitIdent(GroovySourceAST t,int visit) {
328         print(t,visit,t.getText(),null,null);
329     }
330     public void visitImplementsClause(GroovySourceAST t,int visit) {
331         if (visit == OPENING_VISIT) {
332             if (t.getNumberOfChildren() != 0) {
333                 print(t,visit," implements ");
334             }
335         }
336         if (visit == CLOSING_VISIT) {
337             //space between classdef and objblock
338             print(t,visit," ");
339         }
340     }
341 
342     public void visitImplicitParameters(GroovySourceAST t, int visit) {
343         // do nothing
344     }
345 
346     public void visitImport(GroovySourceAST t,int visit) {
347         print(t,visit,"import ",null,null);
348     }
349 
350     public void visitInc(GroovySourceAST t, int visit) {
351         print(t,visit,"++",null,null);
352     }
353 
354     public void visitIndexOp(GroovySourceAST t, int visit) {
355         printUpdatingTabLevel(t,visit,"[",null,"]");
356     }
357 
358     public void visitInterfaceDef(GroovySourceAST t,int visit) {
359         print(t,visit,"interface ",null,null);
360     }
361 
362     public void visitInstanceInit(GroovySourceAST t, int visit) {
363         // do nothing
364     }
365 
366     public void visitLabeledArg(GroovySourceAST t, int visit) {
367         print(t,visit,":",null,null);
368     }
369 
370     public void visitLabeledStat(GroovySourceAST t, int visit) {
371         print(t,visit,":",null,null);
372     }
373 
374     public void visitLand(GroovySourceAST t, int visit) {
375         print(t,visit," && ",null,null);
376     }
377 
378     // visit lbrack()
379     //   token type LBRACK only used inside parser, never visited/created
380 
381     // visit lcurly()
382     //   token type LCURLY only used inside parser, never visited/created
383     
384     public void visitLe(GroovySourceAST t, int visit) {
385         print(t,visit," <= ",null,null);
386     }
387 
388     // visitLetter ...
389     //   token type LETTER only used by lexer, never visited/created
390 
391     public void visitListConstructor(GroovySourceAST t, int visit) {
392         printUpdatingTabLevel(t,visit,"[",null,"]");
393     }
394 
395     public void visitLiteralAs(GroovySourceAST t,int visit) {
396         print(t,visit," as ",null,null);
397     }
398 
399     public void visitLiteralAssert(GroovySourceAST t,int visit) {
400         if (t.getNumberOfChildren() > 1) {
401             print(t,visit,"assert ",null," : ");
402         } else {
403             print(t,visit,"assert ",null,null);
404         }
405     }
406 
407     public void visitLiteralBoolean(GroovySourceAST t, int visit) {
408         print(t,visit,"boolean",null,null);
409     }
410 
411     public void visitLiteralBreak(GroovySourceAST t, int visit) {
412         print(t,visit,"break ",null,null);
413     }
414 
415     public void visitLiteralByte(GroovySourceAST t, int visit) {
416         print(t,visit,"byte",null,null);
417     }
418 
419     public void visitLiteralCase(GroovySourceAST t, int visit) {
420         print(t,visit,"case ",null,":");
421     }
422 
423     public void visitLiteralCatch(GroovySourceAST t,int visit) {
424         printUpdatingTabLevel(t, visit, " catch (", null, ") ");
425     }
426 
427     public void visitLiteralChar(GroovySourceAST t, int visit) {
428         print(t,visit,"char",null,null);
429     }
430 
431     // visitLiteralClass ...
432     //   token type "class" only used by parser, never visited/created directly
433 
434     public void visitLiteralContinue(GroovySourceAST t, int visit) {
435         print(t,visit,"continue ",null,null);
436     }
437 
438     // visitLiteralDef ...
439     //   token type "def" only used by parser, never visited/created directly
440 
441     public void visitLiteralDefault(GroovySourceAST t,int visit) {
442         print(t,visit,"default",null,":");
443     }
444 
445     public void visitLiteralDouble(GroovySourceAST t, int visit) {
446         print(t,visit,"double",null,null);
447     }
448 
449     // visitLiteralElse ...
450     //   token type "else" only used by parser, never visited/created directly
451 
452     // visitLiteralEnum ...
453     //   token type "enum" only used by parser, never visited/created directly
454 
455     // visitLiteralExtends
456     //   token type "extends" only used by parser, never visited/created directly
457     
458     public void visitLiteralFalse(GroovySourceAST t,int visit) {
459         print(t,visit,"false",null,null);
460     }
461 
462     public void visitLiteralFinally(GroovySourceAST t,int visit) {
463         print(t,visit,"finally ",null,null);
464     }
465     public void visitLiteralFloat(GroovySourceAST t,int visit) {
466         print(t,visit,"float",null,null);
467     }
468 
469     public void visitLiteralFor(GroovySourceAST t,int visit) {
470         print(t,visit,"for ",null,null);
471     }
472     
473     public void visitLiteralIf(GroovySourceAST t,int visit) {
474         // slightly strange as subsequent visit is done after closing visit
475         printUpdatingTabLevel(t,visit,"if ("," else ",") ");
476     }
477 
478     // visitLiteralImplements
479     //   token type "implements" only used by parser, never visited/created directly
480 
481     // visitLiteralImport
482     //   token type "import" only used by parser, never visited/created directly
483 
484     public void visitLiteralIn(GroovySourceAST t, int visit) {
485         print(t,visit," in ",null,null);
486     }
487 
488     public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
489         print(t,visit," instanceof ",null,null);
490     }
491 
492     public void visitLiteralInt(GroovySourceAST t,int visit) {
493         print(t,visit,"int",null,null);
494     }
495 
496     // visitLiteralInterface
497     //   token type "interface" only used by parser, never visited/created directly
498 
499     public void visitLiteralLong(GroovySourceAST t,int visit) {
500         print(t,visit,"long",null,null);
501     }
502 
503     public void visitLiteralNative(GroovySourceAST t,int visit) {
504         print(t,visit,"native ",null,null);
505     }
506     public void visitLiteralNew(GroovySourceAST t,int visit) {
507         if (t.childOfType(GroovyTokenTypes.ARRAY_DECLARATOR) == null) {
508             // only print parenthesis if is not of form def x = new int[5]
509             print(t,visit,"new ","(",")");
510         } else {
511             print(t,visit,"new ",null,null);
512         }
513     }
514 
515     public void visitLiteralNull(GroovySourceAST t, int visit) {
516         print(t,visit,"null",null,null);
517     }
518 
519     // visitLiteralPackage
520     //   token type "package" only used by parser, never visited/created directly
521 
522     public void visitLiteralPrivate(GroovySourceAST t,int visit) {
523         print(t,visit,"private ",null,null);
524     }
525 
526     public void visitLiteralProtected(GroovySourceAST t,int visit) {
527         print(t,visit,"protected ",null,null);
528     }
529 
530     public void visitLiteralPublic(GroovySourceAST t,int visit) {
531         print(t,visit,"public ",null,null);
532     }
533 
534     public void visitLiteralReturn(GroovySourceAST t, int visit) {
535         print(t,visit,"return ",null,null);
536     }
537 
538     public void visitLiteralShort(GroovySourceAST t,int visit) {
539         print(t,visit,"short",null,null);
540     }
541 
542     public void visitLiteralStatic(GroovySourceAST t, int visit) {
543         print(t,visit,"static ",null,null);
544     }
545 
546     public void visitLiteralSuper(GroovySourceAST t, int visit) {
547         // only visited when calling super() without parentheses, i.e. "super 99" is equivalent to "super(99)"
548         print(t,visit,"super",null,null);
549     }
550 
551     public void visitLiteralSwitch(GroovySourceAST t, int visit) {
552         if (visit == OPENING_VISIT) {
553             print(t,visit,"switch (");
554             tabLevel++;
555         }
556         if (visit == SUBSEQUENT_VISIT) {
557             print(t,visit,") {");
558         }
559         if (visit == CLOSING_VISIT) {
560             tabLevel--;
561             print(t,visit,"}");
562         }
563     }
564 
565     public void visitLiteralSynchronized(GroovySourceAST t,int visit) {
566         if (t.getNumberOfChildren() > 0) {
567             print(t,visit,"synchronized (",null,") ");
568         } else {
569             print(t,visit,"synchronized ",null,null);            
570         }
571     }
572 
573     public void visitLiteralThis(GroovySourceAST t, int visit) {
574         print(t,visit,"this",null,null);
575     }
576 
577     public void visitLiteralThreadsafe(GroovySourceAST t,int visit) {
578         print(t,visit,"threadsafe ",null,null);
579     }
580 
581     public void visitLiteralThrow(GroovySourceAST t, int visit) {
582         print(t,visit,"throw ",null,null);
583     }
584 
585     public void visitLiteralThrows(GroovySourceAST t, int visit) {
586         print(t,visit,"throws ",null,null);
587     }
588 
589     public void visitLiteralTransient(GroovySourceAST t,int visit) {
590         print(t,visit,"transient ",null,null);
591     }
592 
593     public void visitLiteralTrue(GroovySourceAST t,int visit) {
594         print(t,visit,"true",null,null);
595     }
596     public void visitLiteralTry(GroovySourceAST t,int visit) {
597         print(t,visit,"try ",null,null);
598     }
599     public void visitLiteralVoid(GroovySourceAST t,int visit) {
600         print(t,visit,"void",null,null);
601     }
602     public void visitLiteralVolatile(GroovySourceAST t,int visit) {
603         print(t,visit,"volatile ",null,null);
604     }
605     public void visitLiteralWhile(GroovySourceAST t,int visit) {
606         printUpdatingTabLevel(t,visit,"while (",null,") ");
607     }
608 
609 //deprecated
610 //  public void visitLiteralWith(GroovySourceAST t,int visit) {
611 //        printUpdatingTabLevel(t,visit,"with (",null,") ");
612 //    }
613     
614     public void visitLnot(GroovySourceAST t, int visit) {
615         print(t,visit,"!",null,null);
616     }
617 
618     // Note: old closure syntax using LOR is deprecated, and also never creates/visits a LOR node
619     public void visitLor(GroovySourceAST t, int visit) {
620         print(t,visit," || ",null,null);
621     }
622 
623     public void visitLt(GroovySourceAST t, int visit) {
624         print(t,visit," < ",null,null);
625     }
626 
627     public void visitMapConstructor(GroovySourceAST t, int visit) {
628         if (t.getNumberOfChildren() == 0) {
629             print(t,visit,"[:]",null,null);
630         } else {
631             printUpdatingTabLevel(t,visit,"[",null,"]");
632         }
633     }
634 
635     public void visitMemberPointer(GroovySourceAST t, int visit) {
636         print(t,visit,".&",null,null);
637     }
638 
639     public void visitMethodCall(GroovySourceAST t,int visit) {
640         if ("<command>".equals(t.getText())) {
641             printUpdatingTabLevel(t,visit," "," ",null);
642         } else {
643             printUpdatingTabLevel(t,visit,"("," ",")");
644         }
645     }
646     public void visitMethodDef(GroovySourceAST t,int visit) {
647         //do nothing
648     }
649     public void visitMinus(GroovySourceAST t,int visit) {
650         print(t,visit," - ",null,null);
651     }
652     public void visitMinusAssign(GroovySourceAST t, int visit) {
653         print(t,visit," -= ",null,null);
654     }
655 
656     // visitMlComment
657     //   multi-line comments are not created on the AST currently.
658 
659     public void visitMod(GroovySourceAST t, int visit) {
660         print(t,visit," % ",null,null);
661     }
662 
663     public void visitModifiers(GroovySourceAST t,int visit) {
664         //do nothing
665     }
666     public void visitModAssign(GroovySourceAST t, int visit) {
667         print(t,visit," %= ",null,null);
668     }
669 
670     @Override
671     public void visitMultiCatch(final GroovySourceAST t, final int visit) {
672         if (visit == CLOSING_VISIT) {
673             final AST child = t.getFirstChild();
674             if ("MULTICATCH_TYPES".equals(child.getText())) {
675                 print(t, visit, null, null, " "+child.getNextSibling().getText());
676             } else {
677                 print(t, visit, null, null, " "+child.getFirstChild().getText());
678             }
679         }
680     }
681 
682     @Override
683     public void visitMultiCatchTypes(final GroovySourceAST t, final int visit) {
684     }
685 
686     // visitNls
687     //   new lines are used by parser, but are not created on the AST,
688     //   they can be implied by the source code line/column information
689 
690     // visitNullTreeLookahead
691     //   not used explicitly by parser.
692     
693     
694     public void visitNotEqual(GroovySourceAST t, int visit) {
695         print(t,visit," != ",null,null);
696     }
697 
698     public void visitNumBigDecimal(GroovySourceAST t,int visit) {
699         print(t,visit,t.getText(),null,null);
700     }
701     public void visitNumBigInt(GroovySourceAST t,int visit) {
702         print(t,visit,t.getText(),null,null);
703     }
704     public void visitNumDouble(GroovySourceAST t,int visit) {
705         print(t,visit,t.getText(),null,null);
706     }
707     public void visitNumInt(GroovySourceAST t,int visit) {
708         print(t,visit,t.getText(),null,null);
709     }
710     public void visitNumFloat(GroovySourceAST t,int visit) {
711         print(t,visit,t.getText(),null,null);
712     }
713     public void visitNumLong(GroovySourceAST t,int visit) {
714         print(t,visit,t.getText(),null,null);
715     }
716     public void visitObjblock(GroovySourceAST t,int visit) {
717         if (visit == OPENING_VISIT) {
718             tabLevel++;
719             print(t,visit,"{");
720         } else {
721             tabLevel--;
722             print(t,visit,"}");
723         }
724     }
725 
726     // visitOneNl
727     //   new lines are used by parser, but are not created on the AST,
728     //   they can be implied by the source code line/column information
729 
730     public void visitOptionalDot(GroovySourceAST t,int visit) {
731         print(t,visit,"?.",null,null);
732     }
733     
734     public void visitPackageDef(GroovySourceAST t, int visit) {
735         print(t,visit,"package ",null,null);
736     }
737 
738     public void visitParameterDef(GroovySourceAST t,int visit) {
739         //do nothing
740     }
741 
742     public void visitParameters(GroovySourceAST t,int visit) {
743         if (getParentNode().getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
744             printUpdatingTabLevel(t,visit,null,","," ");
745         } else {
746             printUpdatingTabLevel(t,visit,"(",", ",") ");
747         }
748     }
749 
750     public void visitPlus(GroovySourceAST t, int visit) {
751         print(t,visit," + ",null,null);
752     }
753     
754     public void visitPlusAssign(GroovySourceAST t, int visit) {
755         print(t,visit," += ",null,null);
756     }
757     public void visitPostDec(GroovySourceAST t, int visit) {
758         print(t,visit,null,null,"--");
759     }
760 
761     public void visitPostInc(GroovySourceAST t, int visit) {
762         print(t,visit,null,null,"++");
763     }
764 
765     public void visitQuestion(GroovySourceAST t, int visit) {
766         // ternary operator
767         print(t,visit,"?",":",null);
768     }
769 
770     public void visitRangeExclusive(GroovySourceAST t, int visit) {
771         print(t,visit,"..<",null,null);
772     }
773 
774     public void visitRangeInclusive(GroovySourceAST t, int visit) {
775         print(t,visit,"..",null,null);
776     }
777 
778     // visit rbrack()
779     //   token type RBRACK only used inside parser, never visited/created
780 
781     // visit rcurly()
782     //   token type RCURLY only used inside parser, never visited/created
783 
784     // visit RegexpCtorEnd
785     // visit RegexpLiteral
786     // visit RegexpSymbol
787     //    token types REGEXP_CTOR_END, REGEXP_LITERAL, REGEXP_SYMBOL only used inside lexer
788     
789     public void visitRegexFind(GroovySourceAST t, int visit) {
790         print(t,visit," =~ ",null,null);
791     }
792     public void visitRegexMatch(GroovySourceAST t, int visit) {
793         print(t,visit," ==~ ",null,null);
794     }
795     // visit rparen()
796     //   token type RPAREN only used inside parser, never visited/created
797 
798     public void visitSelectSlot(GroovySourceAST t, int visit) {
799         print(t,visit,"@",null,null);
800     }
801     
802     // visit semi()
803     //  SEMI only used inside parser, never visited/created (see visitForCondition(), visitForIterator())
804     
805     // visit ShComment()
806     //  never visited/created by parser
807     
808     public void visitSl(GroovySourceAST t, int visit) {
809         print(t,visit," << ",null,null);
810     }
811     public void visitSlAssign(GroovySourceAST t, int visit) {
812         print(t,visit," <<= ",null,null);
813     }
814     public void visitSlist(GroovySourceAST t,int visit) {
815         if (visit == OPENING_VISIT) {
816             tabLevel++;
817             print(t,visit,"{");
818         } else {
819             tabLevel--;
820             print(t,visit,"}");
821         }
822     }
823 
824     // visit SlComment()
825     //   never visited/created by parser
826     
827     public void visitSpreadArg(GroovySourceAST t,int visit) {
828         print(t,visit,"*",null,null);
829     }
830 
831     public void visitSpreadDot(GroovySourceAST t,int visit) {
832     print(t,visit,"*.",null,null);
833     }
834 
835     public void visitSpreadMapArg(GroovySourceAST t,int visit) {
836         print(t,visit,"*:",null,null);
837     }
838     
839     public void visitSr(GroovySourceAST t, int visit) {
840         print(t,visit," >> ",null,null);
841     }
842     public void visitSrAssign(GroovySourceAST t, int visit) {
843         print(t,visit," >>= ",null,null);
844     }
845 
846     public void visitStar(GroovySourceAST t,int visit) {
847         print(t,visit,"*",null,null);
848     }
849     public void visitStarAssign(GroovySourceAST t, int visit) {
850         print(t,visit," *= ",null,null);
851     }
852     public void visitStarStar(GroovySourceAST t,int visit) {
853         print(t,visit,"**",null,null);
854     }
855     public void visitStarStarAssign(GroovySourceAST t, int visit) {
856         print(t,visit," **= ",null,null);
857     }
858     
859     public void visitStaticInit(GroovySourceAST t, int visit) {
860         print(t,visit,"static ",null,null);
861     }
862     public void visitStaticImport(GroovySourceAST t,int visit) {
863         print(t,visit,"import static ",null,null);
864     }
865     public void visitStrictfp(GroovySourceAST t,int visit) {
866         print(t,visit,"strictfp ",null,null);
867     }
868 
869     // visitStringch
870     //   String characters only used by lexer, never visited/created directly
871 
872 
873     public void visitStringConstructor(GroovySourceAST t,int visit) {
874         if (visit == OPENING_VISIT) {
875             stringConstructorCounter = 0;
876             print(t,visit,"\"");
877         }
878         if (visit == SUBSEQUENT_VISIT) {
879             // every other subsequent visit use an escaping $
880             if (stringConstructorCounter % 2 == 0) {
881                print(t,visit,"$");
882             }
883             stringConstructorCounter++;
884         }
885         if (visit == CLOSING_VISIT) {
886             print(t,visit,"\"");
887         }
888     }
889 
890     public void visitStringLiteral(GroovySourceAST t,int visit) {
891         if (visit == OPENING_VISIT) {
892             String theString = escape(t.getText());
893         if (getParentNode().getType() != GroovyTokenTypes.LABELED_ARG &&
894             getParentNode().getType() != GroovyTokenTypes.STRING_CONSTRUCTOR) {
895                 theString = "\"" + theString + "\"";
896             }
897             print(t,visit,theString);
898         }
899     }
900 
901     private String escape(String literal) {
902         literal = literal.replaceAll("\n","\\\\<<REMOVE>>n"); // can't seem to do \n in one go with Java regex
903         literal = literal.replaceAll("<<REMOVE>>","");
904         return literal;
905     }
906 
907     public void visitSuperCtorCall(GroovySourceAST t,int visit) {
908         printUpdatingTabLevel(t,visit,"super("," ",")");
909     }
910     
911     // visit TripleDot, not used in the AST
912     
913     public void visitType(GroovySourceAST t,int visit) {
914         GroovySourceAST parent = getParentNode();
915         GroovySourceAST modifiers = parent.childOfType(GroovyTokenTypes.MODIFIERS);
916 
917         // No need to print 'def' if we already have some modifiers
918         if (modifiers == null || modifiers.getNumberOfChildren() == 0) {
919 
920             if (visit == OPENING_VISIT) {
921                 if (t.getNumberOfChildren() == 0 && 
922                         parent.getType() != GroovyTokenTypes.PARAMETER_DEF) { // no need for 'def' if in a parameter list
923                     print(t,visit,"def");
924                 }
925             } 
926             if (visit == CLOSING_VISIT) {
927                 if (  parent.getType() == GroovyTokenTypes.VARIABLE_DEF         ||
928                       parent.getType() == GroovyTokenTypes.METHOD_DEF           ||
929                       parent.getType() == GroovyTokenTypes.ANNOTATION_FIELD_DEF ||
930                      (parent.getType() == GroovyTokenTypes.PARAMETER_DEF && t.getNumberOfChildren()!=0))             
931                 {
932                     print(t,visit," ");
933                 }
934             }
935             
936             /*if (visit == CLOSING_VISIT) {
937                 print(t,visit," ");
938             }*/
939         } else {
940             if (visit == CLOSING_VISIT) {
941                 if (t.getNumberOfChildren() != 0) {
942                     print(t,visit," ");
943                 }
944             }
945         }
946     }
947     public void visitTypeArgument(GroovySourceAST t, int visit) {
948         // print nothing
949     }
950 
951     public void visitTypeArguments(GroovySourceAST t, int visit) {
952         print(t,visit,"<",", ",">");
953     }
954 
955     public void visitTypecast(GroovySourceAST t,int visit) {
956         print(t,visit,"(",null,")");
957     }
958     public void visitTypeLowerBounds(GroovySourceAST t,int visit) {
959         print(t,visit," super "," & ",null);
960     }
961     public void visitTypeParameter(GroovySourceAST t, int visit) {
962         // print nothing
963     }
964 
965     public void visitTypeParameters(GroovySourceAST t, int visit) {
966         print(t,visit,"<",", ",">");
967     }
968 
969     public void visitTypeUpperBounds(GroovySourceAST t,int visit) {
970         print(t,visit," extends "," & ",null);
971     }
972     public void visitUnaryMinus(GroovySourceAST t, int visit) {
973         print(t,visit,"-",null,null);
974     }
975     public void visitUnaryPlus(GroovySourceAST t, int visit) {
976         print(t,visit,"+",null,null);
977     }
978 
979     // visit Unused "const", "do", "goto" - unsurprisingly these are unused by the AST.
980     
981     public void visitVariableDef(GroovySourceAST t,int visit) {
982         // do nothing
983     }
984 
985     // a.k.a. "variable arity parameter" in the JLS
986     public void visitVariableParameterDef(GroovySourceAST t,int visit) {
987         print(t,visit,null,"... ",null);
988     }
989     
990     // visit Vocab - only used by Lexer
991     
992     public void visitWildcardType(GroovySourceAST t, int visit) {
993         print(t,visit,"?",null,null);
994     }
995 
996     // visit WS - only used by lexer
997     
998     
999     
1000     public void visitDefault(GroovySourceAST t,int visit) {
1001         if (visit == OPENING_VISIT) {
1002             print(t,visit,"<" + tokenNames[t.getType()] + ">");
1003             //out.print("<" + t.getType() + ">");
1004         } else {
1005             print(t,visit,"</" + tokenNames[t.getType()] + ">");
1006             //out.print("</" + t.getType() + ">");
1007         }
1008     }
1009 
1010     protected void printUpdatingTabLevel(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
1011         if (visit == OPENING_VISIT && opening != null) {
1012             print(t,visit,opening);
1013             tabLevel++;
1014         }
1015         if (visit == SUBSEQUENT_VISIT && subsequent != null) {
1016             print(t,visit,subsequent);
1017         }
1018         if (visit == CLOSING_VISIT && closing != null) {
1019             tabLevel--;
1020             print(t,visit,closing);
1021         }
1022     }
1023 
1024     protected void print(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
1025         if (visit == OPENING_VISIT && opening != null) {
1026             print(t,visit,opening);
1027         }
1028         if (visit == SUBSEQUENT_VISIT && subsequent != null) {
1029             print(t,visit,subsequent);
1030         }
1031         if (visit == CLOSING_VISIT && closing != null) {
1032             print(t,visit,closing);
1033         }
1034     }
1035     protected void print(GroovySourceAST t,int visit,String value) {
1036         if(visit == OPENING_VISIT) {
1037             printNewlineAndIndent(t, visit);
1038         }
1039         if (visit == CLOSING_VISIT) {
1040             printNewlineAndIndent(t, visit);
1041         }
1042         out.print(value);
1043     }
1044 
1045     protected void printNewlineAndIndent(GroovySourceAST t, int visit) {
1046         int currentLine = t.getLine();
1047         if (lastLinePrinted == 0) { lastLinePrinted = currentLine; }
1048         if (lastLinePrinted != currentLine) {
1049             if (newLines) {
1050                 if (!(visit == OPENING_VISIT && t.getType() == GroovyTokenTypes.SLIST)) {
1051                     for (int i=lastLinePrinted;i<currentLine;i++) {
1052                         out.println();
1053                     }
1054                     if (lastLinePrinted > currentLine) {
1055                         out.println();
1056                         lastLinePrinted = currentLine;
1057                     }
1058                     if (visit == OPENING_VISIT || (visit == CLOSING_VISIT && lastLinePrinted > currentLine)) {
1059                         for (int i=0;i<tabLevel;i++) {
1060                             out.print("    ");
1061                         }
1062                     }
1063                 }
1064             }
1065             lastLinePrinted = Math.max(currentLine,lastLinePrinted);
1066         }
1067     }
1068 
1069     public void push(GroovySourceAST t) {
1070         stack.push(t);
1071     }
1072     public GroovySourceAST pop() {
1073         if (!stack.empty()) {
1074             return (GroovySourceAST) stack.pop();
1075         }
1076         return null;
1077     }
1078 
1079     private GroovySourceAST getParentNode() {
1080         Object currentNode = stack.pop();
1081         Object parentNode = stack.peek();
1082         stack.push(currentNode);
1083         return (GroovySourceAST) parentNode;
1084     }
1085 
1086 }