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