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 }