001 /**
002 *
003 * Copyright 2005 Jeremy Rayner
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 **/
018 package org.codehaus.groovy.antlr.treewalker;
019
020 import java.io.PrintStream;
021 import java.util.Stack;
022
023 import org.codehaus.groovy.antlr.GroovySourceAST;
024 import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
025
026 /**
027 * An antlr AST visitor that prints groovy source code for each visited node
028 * to the supplied PrintStream.
029 *
030 * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
031 * @version $Revision: 4538 $
032 */
033
034 public class SourcePrinter extends VisitorAdapter {
035 private String[] tokenNames;
036 private int tabLevel;
037 private int lastLinePrinted;
038 private boolean newLines;
039 protected PrintStream out;
040 private String className;
041 private Stack stack;
042 private int stringConstructorCounter;
043
044 /**
045 * A visitor that prints groovy source code for each node visited.
046 * @param out where to print the source code to
047 * @param tokenNames an array of token names from antlr
048 */
049 public SourcePrinter(PrintStream out,String[] tokenNames) {
050 this(out,tokenNames,true);
051 }
052
053 /**
054 * A visitor that prints groovy source code for each node visited.
055 * @param out where to print the source code to
056 * @param tokenNames an array of token names from antlr
057 * @param newLines output newline character
058 */
059 public SourcePrinter(PrintStream out,String[] tokenNames, boolean newLines) {
060 this.tokenNames = tokenNames;
061 tabLevel = 0;
062 lastLinePrinted = 0;
063 this.out = out;
064 this.newLines = newLines;
065 this.stack = new Stack();
066 }
067
068
069 public void visitAbstract(GroovySourceAST t, int visit) {
070 print(t,visit,"abstract ",null,null);
071 }
072
073 public void visitAnnotation(GroovySourceAST t, int visit) {
074 if (visit == OPENING_VISIT) {
075 print(t,visit,"@");
076 }
077 if (visit == SECOND_VISIT) {
078 print(t,visit,"(");
079 }
080 if (visit == SUBSEQUENT_VISIT) {
081 print(t,visit,", ");
082 }
083 if (visit == CLOSING_VISIT) {
084 if (t.getNumberOfChildren() > 1) {
085 print(t,visit,") ");
086 } else {
087 print(t,visit," ");
088 }
089 }
090
091 }
092
093 public void visitAnnotations(GroovySourceAST t, int visit) {
094 // do nothing
095 }
096
097 public void visitAnnotationDef(GroovySourceAST t,int visit) {
098 print(t,visit,"@interface ",null,null);
099 }
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 }