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 }