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 022 import org.codehaus.groovy.antlr.GroovySourceAST; 023 import org.codehaus.groovy.antlr.parser.GroovyTokenTypes; 024 025 /** 026 * An antlr AST visitor that prints groovy source code for each visited node 027 * to the supplied PrintStream. 028 * 029 * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a> 030 * @version $Revision: 1.12 $ 031 */ 032 033 public class SourcePrinter extends VisitorAdapter { 034 private String[] tokenNames; 035 private int tabLevel; 036 private int lastLinePrinted; 037 private boolean newLines; 038 protected PrintStream out; 039 private String className; 040 041 /** 042 * A visitor that prints groovy source code for each node visited. 043 * @param out where to print the source code to 044 * @param tokenNames an array of token names from antlr 045 */ 046 public SourcePrinter(PrintStream out,String[] tokenNames) { 047 this(out,tokenNames,true); 048 } 049 050 /** 051 * A visitor that prints groovy source code for each node visited. 052 * @param out where to print the source code to 053 * @param tokenNames an array of token names from antlr 054 * @param newLines output newline character 055 */ 056 public SourcePrinter(PrintStream out,String[] tokenNames, boolean newLines) { 057 this.tokenNames = tokenNames; 058 tabLevel = 0; 059 lastLinePrinted = 0; 060 this.out = out; 061 this.newLines = newLines; 062 } 063 064 public void visitAnnotation(GroovySourceAST t, int visit) { 065 print(t,visit,"@",null,null); 066 } 067 068 public void visitAnnotations(GroovySourceAST t, int visit) { 069 if (t.getNumberOfChildren() > 0) { 070 //todo - default line below is just a placeholder 071 visitDefault(t,visit); 072 } 073 } 074 075 public void visitAssign(GroovySourceAST t,int visit) { 076 print(t,visit," = ",null,null); 077 } 078 079 public void visitCaseGroup(GroovySourceAST t, int visit) { 080 if (visit == OPENING_VISIT) { 081 tabLevel++; 082 } 083 if (visit == CLOSING_VISIT) { 084 tabLevel--; 085 } 086 } 087 088 public void visitClassDef(GroovySourceAST t,int visit) { 089 print(t,visit,"class ",null,null); 090 091 if (visit == OPENING_VISIT) { 092 // store name of class away for use in constructor ident 093 className = t.childOfType(GroovyTokenTypes.IDENT).getText(); 094 } 095 } 096 097 public void visitClosedBlock(GroovySourceAST t, int visit) { 098 printUpdatingTabLevel(t,visit,"{"," -> ","}"); 099 } 100 public void visitCtorIdent(GroovySourceAST t, int visit) { 101 // use name of class for constructor from the class definition 102 print(t,visit,className,null,null); 103 } 104 public void visitDot(GroovySourceAST t,int visit) { 105 print(t,visit,".",null,null); 106 } 107 public void visitElist(GroovySourceAST t,int visit) { 108 print(t,visit,null,", ",null); 109 } 110 111 public void visitEqual(GroovySourceAST t,int visit) { 112 print(t,visit," == ",null,null); 113 } 114 115 public void visitExpr(GroovySourceAST t,int visit) { 116 } 117 118 public void visitExtendsClause(GroovySourceAST t,int visit) { 119 if (visit == OPENING_VISIT) { 120 if (t.getNumberOfChildren() != 0) { 121 print(t,visit," extends "); 122 } 123 } 124 } 125 126 public void visitForInIterable(GroovySourceAST t, int visit) { 127 printUpdatingTabLevel(t,visit,"("," in ",") "); 128 } 129 130 public void visitGt(GroovySourceAST t, int visit) { 131 print(t,visit," > ",null,null); 132 } 133 134 public void visitIdent(GroovySourceAST t,int visit) { 135 print(t,visit,t.getText(),null,null); 136 } 137 public void visitImplementsClause(GroovySourceAST t,int visit) { 138 if (visit == OPENING_VISIT) { 139 if (t.getNumberOfChildren() != 0) { 140 print(t,visit," implements "); 141 } 142 } 143 if (visit == CLOSING_VISIT) { 144 //space between classdef and objblock 145 print(t,visit," "); 146 } 147 } 148 149 public void visitImplicitParameters(GroovySourceAST t, int visit) { 150 } 151 152 public void visitImport(GroovySourceAST t,int visit) { 153 print(t,visit,"import ",null,null); 154 } 155 156 public void visitIndexOp(GroovySourceAST t, int visit) { 157 printUpdatingTabLevel(t,visit,"[",null,"]"); 158 } 159 160 public void visitLabeledArg(GroovySourceAST t, int visit) { 161 print(t,visit,":",null,null); 162 } 163 164 public void visitLand(GroovySourceAST t, int visit) { 165 print(t,visit," && ",null,null); 166 } 167 168 public void visitListConstructor(GroovySourceAST t, int visit) { 169 printUpdatingTabLevel(t,visit,"[",null,"]"); 170 } 171 172 public void visitLiteralAssert(GroovySourceAST t,int visit) { 173 print(t,visit,"assert ",null,null); 174 } 175 176 public void visitLiteralBoolean(GroovySourceAST t, int visit) { 177 print(t,visit,"boolean",null,null); 178 } 179 180 public void visitLiteralBreak(GroovySourceAST t, int visit) { 181 print(t,visit,"break",null,null); 182 } 183 184 public void visitLiteralCase(GroovySourceAST t, int visit) { 185 print(t,visit,"case ",null,":"); 186 } 187 188 public void visitLiteralCatch(GroovySourceAST t,int visit) { 189 printUpdatingTabLevel(t,visit," catch (",null,") "); 190 } 191 public void visitLiteralFalse(GroovySourceAST t,int visit) { 192 print(t,visit,"false",null,null); 193 } 194 195 public void visitLiteralFloat(GroovySourceAST t,int visit) { 196 print(t,visit,"float",null,null); 197 } 198 199 public void visitLiteralFor(GroovySourceAST t,int visit) { 200 print(t,visit,"for ",null,null); 201 } 202 203 public void visitLiteralIf(GroovySourceAST t,int visit) { 204 // slightly strange as subsequent visit is done after closing visit 205 printUpdatingTabLevel(t,visit,"if ("," else ",") "); 206 } 207 208 public void visitLiteralInstanceof(GroovySourceAST t, int visit) { 209 print(t,visit," instanceof ",null,null); 210 } 211 212 public void visitLiteralInt(GroovySourceAST t,int visit) { 213 print(t,visit,"int",null,null); 214 } 215 216 public void visitLiteralNew(GroovySourceAST t,int visit) { 217 print(t,visit,"new ","(",")"); 218 } 219 220 public void visitLiteralNull(GroovySourceAST t, int visit) { 221 print(t,visit,"null",null,null); 222 } 223 224 public void visitLiteralPrivate(GroovySourceAST t,int visit) { 225 print(t,visit,"private ",null,null); 226 } 227 228 public void visitLiteralProtected(GroovySourceAST t,int visit) { 229 print(t,visit,"protected ",null,null); 230 } 231 232 public void visitLiteralPublic(GroovySourceAST t,int visit) { 233 print(t,visit,"public ",null,null); 234 } 235 236 public void visitLiteralReturn(GroovySourceAST t, int visit) { 237 print(t,visit,"return ",null,null); 238 } 239 240 public void visitLiteralStatic(GroovySourceAST t, int visit) { 241 print(t,visit,"static ",null,null); 242 } 243 244 public void visitLiteralSwitch(GroovySourceAST t, int visit) { 245 if (visit == OPENING_VISIT) { 246 print(t,visit,"switch ("); 247 tabLevel++; 248 } 249 if (visit == SUBSEQUENT_VISIT) { 250 print(t,visit,") {"); 251 } 252 if (visit == CLOSING_VISIT) { 253 tabLevel--; 254 print(t,visit,"}"); 255 } 256 } 257 258 public void visitLiteralThis(GroovySourceAST t, int visit) { 259 print(t,visit,"this",null,null); 260 } 261 262 public void visitLiteralThrow(GroovySourceAST t, int visit) { 263 print(t,visit,"throw ",null,null); 264 } 265 266 public void visitLiteralTrue(GroovySourceAST t,int visit) { 267 print(t,visit,"true",null,null); 268 } 269 public void visitLiteralTry(GroovySourceAST t,int visit) { 270 print(t,visit,"try ",null,null); 271 } 272 public void visitLiteralVoid(GroovySourceAST t,int visit) { 273 print(t,visit,"void",null,null); 274 } 275 public void visitLiteralWhile(GroovySourceAST t,int visit) { 276 printUpdatingTabLevel(t,visit,"while (",null,") "); 277 } 278 279 public void visitLnot(GroovySourceAST t, int visit) { 280 print(t,visit,"!",null,null); 281 } 282 283 public void visitLt(GroovySourceAST t, int visit) { 284 print(t,visit," < ",null,null); 285 } 286 287 public void visitMapConstructor(GroovySourceAST t, int visit) { 288 if (t.getNumberOfChildren() == 0) { 289 print(t,visit,"[:]",null,null); 290 } else { 291 printUpdatingTabLevel(t,visit,"[",null,"]"); 292 } 293 } 294 295 public void visitMemberPointer(GroovySourceAST t, int visit) { 296 print(t,visit,".&",null,null); 297 } 298 299 public void visitMethodCall(GroovySourceAST t,int visit) { 300 printUpdatingTabLevel(t,visit,"("," ",")"); 301 } 302 public void visitMinus(GroovySourceAST t,int visit) { 303 print(t,visit," - ",null,null); 304 } 305 public void visitMethodDef(GroovySourceAST t,int visit) { 306 //do nothing 307 } 308 public void visitModifiers(GroovySourceAST t,int visit) { 309 //do nothing 310 } 311 312 public void visitNotEqual(GroovySourceAST t, int visit) { 313 print(t,visit," != ",null,null); 314 } 315 316 public void visitNumInt(GroovySourceAST t,int visit) { 317 print(t,visit,t.getText(),null,null); 318 } 319 public void visitNumFloat(GroovySourceAST t,int visit) { 320 print(t,visit,t.getText(),null,null); 321 } 322 public void visitObjblock(GroovySourceAST t,int visit) { 323 if (visit == OPENING_VISIT) { 324 tabLevel++; 325 print(t,visit,"{"); 326 } else { 327 tabLevel--; 328 print(t,visit,"}"); 329 } 330 } 331 332 public void visitPackageDef(GroovySourceAST t, int visit) { 333 print(t,visit,"package ",null,null); 334 } 335 336 public void visitParameterDef(GroovySourceAST t,int visit) { 337 //do nothing 338 } 339 340 public void visitParameters(GroovySourceAST t,int visit) { 341 printUpdatingTabLevel(t,visit,"(",", ",") "); 342 } 343 344 public void visitPlus(GroovySourceAST t, int visit) { 345 print(t,visit," + ",null,null); 346 } 347 348 public void visitQuestion(GroovySourceAST t, int visit) { 349 // ternary operator 350 print(t,visit,"?",":",null); 351 } 352 353 public void visitRangeExclusive(GroovySourceAST t, int visit) { 354 print(t,visit,"..<",null,null); 355 } 356 357 public void visitRangeInclusive(GroovySourceAST t, int visit) { 358 print(t,visit,"..",null,null); 359 } 360 361 public void visitSlist(GroovySourceAST t,int visit) { 362 if (visit == OPENING_VISIT) { 363 tabLevel++; 364 print(t,visit,"{"); 365 } else { 366 tabLevel--; 367 print(t,visit,"}"); 368 } 369 } 370 371 public void visitStar(GroovySourceAST t,int visit) { 372 print(t,visit,"*",null,null); 373 } 374 public void visitStringConstructor(GroovySourceAST t,int visit) { 375 print(t,visit,null," + ",null); // string concatenate, so ("abc$foo") becomes ("abc" + foo) for now (todo) 376 } 377 378 public void visitStringLiteral(GroovySourceAST t,int visit) { 379 print(t,visit,"\"" + escape(t.getText()) + "\"",null,null); 380 } 381 382 private String escape(String literal) { 383 literal = literal.replaceAll("\n","\\\\<<REMOVE>>n"); // can't seem to do \n in one go with Java regex 384 literal = literal.replaceAll("<<REMOVE>>",""); 385 return literal; 386 } 387 388 public void visitType(GroovySourceAST t,int visit) { 389 if (visit == OPENING_VISIT) { 390 if (t.getNumberOfChildren() == 0) { 391 print(t,visit,"def"); 392 } 393 } 394 if (visit == CLOSING_VISIT) { 395 print(t,visit," "); 396 } 397 } 398 399 public void visitTypecast(GroovySourceAST t,int visit) { 400 print(t,visit,"(",null,")"); 401 } 402 403 public void visitVariableDef(GroovySourceAST t,int visit) { 404 // do nothing 405 } 406 407 public void visitDefault(GroovySourceAST t,int visit) { 408 if (visit == OPENING_VISIT) { 409 print(t,visit,"<" + tokenNames[t.getType()] + ">"); 410 //out.print("<" + t.getType() + ">"); 411 } else { 412 print(t,visit,"</" + tokenNames[t.getType()] + ">"); 413 //out.print("</" + t.getType() + ">"); 414 } 415 } 416 protected void printUpdatingTabLevel(GroovySourceAST t,int visit,String opening, String subsequent, String closing) { 417 if (visit == OPENING_VISIT && opening != null) { 418 print(t,visit,opening); 419 tabLevel++; 420 } 421 if (visit == SUBSEQUENT_VISIT && subsequent != null) { 422 print(t,visit,subsequent); 423 } 424 if (visit == CLOSING_VISIT && closing != null) { 425 tabLevel--; 426 print(t,visit,closing); 427 } 428 } 429 430 protected void print(GroovySourceAST t,int visit,String opening, String subsequent, String closing) { 431 if (visit == OPENING_VISIT && opening != null) { 432 print(t,visit,opening); 433 } 434 if (visit == SUBSEQUENT_VISIT && subsequent != null) { 435 print(t,visit,subsequent); 436 } 437 if (visit == CLOSING_VISIT && closing != null) { 438 print(t,visit,closing); 439 } 440 } 441 protected void print(GroovySourceAST t,int visit,String value) { 442 if(visit == OPENING_VISIT) { 443 printNewlineAndIndent(t, visit); 444 } 445 if (visit == CLOSING_VISIT) { 446 printNewlineAndIndent(t, visit); 447 } 448 out.print(value); 449 } 450 451 protected void printNewlineAndIndent(GroovySourceAST t, int visit) { 452 int currentLine = t.getLine(); 453 if (lastLinePrinted == 0) { lastLinePrinted = currentLine; } 454 if (lastLinePrinted != currentLine) { 455 if (newLines) { 456 if (!(visit == OPENING_VISIT && t.getType() == GroovyTokenTypes.SLIST)) { 457 for (int i=lastLinePrinted;i<currentLine;i++) { 458 out.println(); 459 } 460 if (lastLinePrinted > currentLine) { 461 out.println(); 462 } 463 if (visit == OPENING_VISIT || (visit == CLOSING_VISIT && lastLinePrinted > currentLine)) { 464 for (int i=0;i<tabLevel;i++) { 465 out.print(" "); 466 } 467 } 468 } 469 } 470 lastLinePrinted = Math.max(currentLine,lastLinePrinted); 471 } 472 } 473 }