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: 1.13 $
    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      public void visitAnnotation(GroovySourceAST t, int visit) {
    69          print(t,visit,"@",null," ");
    70      }
    71
    72      public void visitAnnotations(GroovySourceAST t, int visit) {
    73          if (t.getNumberOfChildren() > 0) {
    74              //todo - default line below is just a placeholder
    75              visitDefault(t,visit);
    76          }
    77      }
    78
    79      public void visitAssign(GroovySourceAST t,int visit) {
    80          print(t,visit," = ",null,null);
    81      }
    82
    83      public void visitCaseGroup(GroovySourceAST t, int visit) {
    84          if (visit == OPENING_VISIT) {
    85              tabLevel++;
    86          }
    87          if (visit == CLOSING_VISIT) {
    88              tabLevel--;
    89          }
    90      }
    91
    92      public void visitClassDef(GroovySourceAST t,int visit) {
    93          print(t,visit,"class ",null,null);
    94
    95          if (visit == OPENING_VISIT) {
    96              // store name of class away for use in constructor ident
    97              className = t.childOfType(GroovyTokenTypes.IDENT).getText();
    98          }
    99      }
    100
    101     public void visitClosedBlock(GroovySourceAST t, int visit) {
    102         printUpdatingTabLevel(t,visit,"{"," -> ","}");
    103     }
    104     public void visitCtorIdent(GroovySourceAST t, int visit) {
    105         // use name of class for constructor from the class definition
    106         print(t,visit,className,null,null);
    107     }
    108     public void visitDot(GroovySourceAST t,int visit) {
    109         print(t,visit,".",null,null);
    110     }
    111     public void visitElist(GroovySourceAST t,int visit) {
    112         print(t,visit,null,", ",null);
    113     }
    114
    115     public void visitEqual(GroovySourceAST t,int visit) {
    116         print(t,visit," == ",null,null);
    117     }
    118
    119     public void visitExpr(GroovySourceAST t,int visit) {
    120     }
    121
    122     public void visitExtendsClause(GroovySourceAST t,int visit) {
    123         if (visit == OPENING_VISIT) {
    124             if (t.getNumberOfChildren() != 0) {
    125                 print(t,visit," extends ");
    126             }
    127         }
    128     }
    129
    130     public void visitForInIterable(GroovySourceAST t, int visit) {
    131         printUpdatingTabLevel(t,visit,"("," in ",") ");
    132     }
    133
    134     public void visitGt(GroovySourceAST t, int visit) {
    135         print(t,visit," > ",null,null);
    136     }
    137
    138     public void visitIdent(GroovySourceAST t,int visit) {
    139         print(t,visit,t.getText(),null,null);
    140     }
    141     public void visitImplementsClause(GroovySourceAST t,int visit) {
    142         if (visit == OPENING_VISIT) {
    143             if (t.getNumberOfChildren() != 0) {
    144                 print(t,visit," implements ");
    145             }
    146         }
    147         if (visit == CLOSING_VISIT) {
    148             //space between classdef and objblock
    149             print(t,visit," ");
    150         }
    151     }
    152
    153     public void visitImplicitParameters(GroovySourceAST t, int visit) {
    154     }
    155
    156     public void visitImport(GroovySourceAST t,int visit) {
    157         print(t,visit,"import ",null,null);
    158     }
    159
    160     public void visitIndexOp(GroovySourceAST t, int visit) {
    161         printUpdatingTabLevel(t,visit,"[",null,"]");
    162     }
    163
    164     public void visitLabeledArg(GroovySourceAST t, int visit) {
    165         print(t,visit,":",null,null);
    166     }
    167
    168     public void visitLand(GroovySourceAST t, int visit) {
    169         print(t,visit," && ",null,null);
    170     }
    171
    172     public void visitListConstructor(GroovySourceAST t, int visit) {
    173         printUpdatingTabLevel(t,visit,"[",null,"]");
    174     }
    175
    176     public void visitLiteralAssert(GroovySourceAST t,int visit) {
    177         print(t,visit,"assert ",null,null);
    178     }
    179
    180     public void visitLiteralBoolean(GroovySourceAST t, int visit) {
    181         print(t,visit,"boolean",null,null);
    182     }
    183
    184     public void visitLiteralBreak(GroovySourceAST t, int visit) {
    185         print(t,visit,"break",null,null);
    186     }
    187
    188     public void visitLiteralCase(GroovySourceAST t, int visit) {
    189         print(t,visit,"case ",null,":");
    190     }
    191
    192     public void visitLiteralCatch(GroovySourceAST t,int visit) {
    193         printUpdatingTabLevel(t,visit," catch (",null,") ");
    194     }
    195     public void visitLiteralFalse(GroovySourceAST t,int visit) {
    196         print(t,visit,"false",null,null);
    197     }
    198
    199     public void visitLiteralFloat(GroovySourceAST t,int visit) {
    200         print(t,visit,"float",null,null);
    201     }
    202
    203     public void visitLiteralFor(GroovySourceAST t,int visit) {
    204         print(t,visit,"for ",null,null);
    205     }
    206
    207     public void visitLiteralIf(GroovySourceAST t,int visit) {
    208         // slightly strange as subsequent visit is done after closing visit
    209         printUpdatingTabLevel(t,visit,"if ("," else ",") ");
    210     }
    211
    212     public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
    213         print(t,visit," instanceof ",null,null);
    214     }
    215
    216     public void visitLiteralInt(GroovySourceAST t,int visit) {
    217         print(t,visit,"int",null,null);
    218     }
    219
    220     public void visitLiteralNew(GroovySourceAST t,int visit) {
    221         print(t,visit,"new ","(",")");
    222     }
    223
    224     public void visitLiteralNull(GroovySourceAST t, int visit) {
    225         print(t,visit,"null",null,null);
    226     }
    227
    228     public void visitLiteralPrivate(GroovySourceAST t,int visit) {
    229         print(t,visit,"private ",null,null);
    230     }
    231
    232     public void visitLiteralProtected(GroovySourceAST t,int visit) {
    233         print(t,visit,"protected ",null,null);
    234     }
    235
    236     public void visitLiteralPublic(GroovySourceAST t,int visit) {
    237         print(t,visit,"public ",null,null);
    238     }
    239
    240     public void visitLiteralReturn(GroovySourceAST t, int visit) {
    241         print(t,visit,"return ",null,null);
    242     }
    243
    244     public void visitLiteralStatic(GroovySourceAST t, int visit) {
    245         print(t,visit,"static ",null,null);
    246     }
    247
    248     public void visitLiteralSwitch(GroovySourceAST t, int visit) {
    249         if (visit == OPENING_VISIT) {
    250             print(t,visit,"switch (");
    251             tabLevel++;
    252         }
    253         if (visit == SUBSEQUENT_VISIT) {
    254             print(t,visit,") {");
    255         }
    256         if (visit == CLOSING_VISIT) {
    257             tabLevel--;
    258             print(t,visit,"}");
    259         }
    260     }
    261
    262     public void visitLiteralThis(GroovySourceAST t, int visit) {
    263         print(t,visit,"this",null,null);
    264     }
    265
    266     public void visitLiteralThrow(GroovySourceAST t, int visit) {
    267         print(t,visit,"throw ",null,null);
    268     }
    269
    270     public void visitLiteralTrue(GroovySourceAST t,int visit) {
    271         print(t,visit,"true",null,null);
    272     }
    273     public void visitLiteralTry(GroovySourceAST t,int visit) {
    274         print(t,visit,"try ",null,null);
    275     }
    276     public void visitLiteralVoid(GroovySourceAST t,int visit) {
    277         print(t,visit,"void",null," ");
    278     }
    279     public void visitLiteralWhile(GroovySourceAST t,int visit) {
    280         printUpdatingTabLevel(t,visit,"while (",null,") ");
    281     }
    282
    283     public void visitLnot(GroovySourceAST t, int visit) {
    284         print(t,visit,"!",null,null);
    285     }
    286
    287     public void visitLt(GroovySourceAST t, int visit) {
    288         print(t,visit," < ",null,null);
    289     }
    290
    291     public void visitMapConstructor(GroovySourceAST t, int visit) {
    292         if (t.getNumberOfChildren() == 0) {
    293             print(t,visit,"[:]",null,null);
    294         } else {
    295             printUpdatingTabLevel(t,visit,"[",null,"]");
    296         }
    297     }
    298
    299     public void visitMemberPointer(GroovySourceAST t, int visit) {
    300         print(t,visit,".&",null,null);
    301     }
    302
    303     public void visitMethodCall(GroovySourceAST t,int visit) {
    304         printUpdatingTabLevel(t,visit,"("," ",")");
    305     }
    306     public void visitMinus(GroovySourceAST t,int visit) {
    307         print(t,visit," - ",null,null);
    308     }
    309     public void visitMethodDef(GroovySourceAST t,int visit) {
    310         //do nothing
    311     }
    312     public void visitModifiers(GroovySourceAST t,int visit) {
    313         //do nothing
    314     }
    315
    316     public void visitNotEqual(GroovySourceAST t, int visit) {
    317         print(t,visit," != ",null,null);
    318     }
    319
    320     public void visitNumInt(GroovySourceAST t,int visit) {
    321         print(t,visit,t.getText(),null,null);
    322     }
    323     public void visitNumFloat(GroovySourceAST t,int visit) {
    324         print(t,visit,t.getText(),null,null);
    325     }
    326     public void visitObjblock(GroovySourceAST t,int visit) {
    327         if (visit == OPENING_VISIT) {
    328             tabLevel++;
    329             print(t,visit,"{");
    330         } else {
    331             tabLevel--;
    332             print(t,visit,"}");
    333         }
    334     }
    335
    336     public void visitPackageDef(GroovySourceAST t, int visit) {
    337         print(t,visit,"package ",null,null);
    338     }
    339
    340     public void visitParameterDef(GroovySourceAST t,int visit) {
    341         //do nothing
    342     }
    343
    344     public void visitParameters(GroovySourceAST t,int visit) {
    345         printUpdatingTabLevel(t,visit,"(",", ",") ");
    346     }
    347
    348     public void visitPlus(GroovySourceAST t, int visit) {
    349         print(t,visit," + ",null,null);
    350     }
    351
    352     public void visitQuestion(GroovySourceAST t, int visit) {
    353         // ternary operator
    354         print(t,visit,"?",":",null);
    355     }
    356
    357     public void visitRangeExclusive(GroovySourceAST t, int visit) {
    358         print(t,visit,"..<",null,null);
    359     }
    360
    361     public void visitRangeInclusive(GroovySourceAST t, int visit) {
    362         print(t,visit,"..",null,null);
    363     }
    364
    365     public void visitSlist(GroovySourceAST t,int visit) {
    366         if (visit == OPENING_VISIT) {
    367             tabLevel++;
    368             print(t,visit,"{");
    369         } else {
    370             tabLevel--;
    371             print(t,visit,"}");
    372         }
    373     }
    374
    375     public void visitStar(GroovySourceAST t,int visit) {
    376         print(t,visit,"*",null,null);
    377     }
    378     public void visitStringConstructor(GroovySourceAST t,int visit) {
    379         if (visit == OPENING_VISIT) {
    380             stringConstructorCounter = 0;
    381             print(t,visit,"\"");
    382         }
    383         if (visit == SUBSEQUENT_VISIT) {
    384             // every other subsequent visit use an escaping $
    385             if (stringConstructorCounter % 2 == 0) {
    386                print(t,visit,"$");
    387             }
    388             stringConstructorCounter++;
    389         }
    390         if (visit == CLOSING_VISIT) {
    391             print(t,visit,"\"");
    392         }
    393     }
    394
    395     public void visitStringLiteral(GroovySourceAST t,int visit) {
    396         if (visit == OPENING_VISIT) {
    397             String theString = escape(t.getText());
    398         if (getParentNode().getType() != GroovyTokenTypes.LABELED_ARG &&
    399             getParentNode().getType() != GroovyTokenTypes.STRING_CONSTRUCTOR) {
    400                 theString = "\"" + theString + "\"";
    401             }
    402             print(t,visit,theString);
    403         }
    404     }
    405
    406     private String escape(String literal) {
    407         literal = literal.replaceAll("\n","////<<REMOVE>>n"); // can't seem to do \n in one go with Java regex
    408         literal = literal.replaceAll("<<REMOVE>>","");
    409         return literal;
    410     }
    411
    412     public void visitType(GroovySourceAST t,int visit) {
    413         GroovySourceAST parent = getParentNode();
    414         GroovySourceAST modifiers = parent.childOfType(GroovyTokenTypes.MODIFIERS);
    415
    416         // No need to print 'def' if we already have some modifiers
    417         if (modifiers == null || modifiers.getNumberOfChildren() == 0) {
    418
    419             if (visit == OPENING_VISIT) {
    420                 if (t.getNumberOfChildren() == 0) {
    421                     print(t,visit,"def");
    422                 }
    423             }
    424             if (visit == CLOSING_VISIT) {
    425                 print(t,visit," ");
    426             }
    427         }
    428     }
    429
    430     public void visitTypecast(GroovySourceAST t,int visit) {
    431         print(t,visit,"(",null,")");
    432     }
    433
    434     public void visitVariableDef(GroovySourceAST t,int visit) {
    435         // do nothing
    436     }
    437
    438     public void visitDefault(GroovySourceAST t,int visit) {
    439         if (visit == OPENING_VISIT) {
    440             print(t,visit,"<" + tokenNames[t.getType()] + ">");
    441             //out.print("<" + t.getType() + ">");
    442         } else {
    443             print(t,visit,"</" + tokenNames[t.getType()] + ">");
    444             //out.print("</" + t.getType() + ">");
    445         }
    446     }
    447
    448     protected void printUpdatingTabLevel(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
    449         if (visit == OPENING_VISIT && opening != null) {
    450             print(t,visit,opening);
    451             tabLevel++;
    452         }
    453         if (visit == SUBSEQUENT_VISIT && subsequent != null) {
    454             print(t,visit,subsequent);
    455         }
    456         if (visit == CLOSING_VISIT && closing != null) {
    457             tabLevel--;
    458             print(t,visit,closing);
    459         }
    460     }
    461
    462     protected void print(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
    463         if (visit == OPENING_VISIT && opening != null) {
    464             print(t,visit,opening);
    465         }
    466         if (visit == SUBSEQUENT_VISIT && subsequent != null) {
    467             print(t,visit,subsequent);
    468         }
    469         if (visit == CLOSING_VISIT && closing != null) {
    470             print(t,visit,closing);
    471         }
    472     }
    473     protected void print(GroovySourceAST t,int visit,String value) {
    474         if(visit == OPENING_VISIT) {
    475             printNewlineAndIndent(t, visit);
    476         }
    477         if (visit == CLOSING_VISIT) {
    478             printNewlineAndIndent(t, visit);
    479         }
    480         out.print(value);
    481     }
    482
    483     protected void printNewlineAndIndent(GroovySourceAST t, int visit) {
    484         int currentLine = t.getLine();
    485         if (lastLinePrinted == 0) { lastLinePrinted = currentLine; }
    486         if (lastLinePrinted != currentLine) {
    487             if (newLines) {
    488                 if (!(visit == OPENING_VISIT && t.getType() == GroovyTokenTypes.SLIST)) {
    489                     for (int i=lastLinePrinted;i<currentLine;i++) {
    490                         out.println();
    491                     }
    492                     if (lastLinePrinted > currentLine) {
    493                         out.println();
    494                     }
    495                     if (visit == OPENING_VISIT || (visit == CLOSING_VISIT && lastLinePrinted > currentLine)) {
    496                         for (int i=0;i<tabLevel;i++) {
    497                             out.print("    ");
    498                         }
    499                     }
    500                 }
    501             }
    502             lastLinePrinted = Math.max(currentLine,lastLinePrinted);
    503         }
    504     }
    505
    506     public void push(GroovySourceAST t) {
    507         stack.push(t);
    508     }
    509     public GroovySourceAST pop() {
    510         if (!stack.empty()) {
    511             return (GroovySourceAST) stack.pop();
    512         }
    513         return null;
    514     }
    515
    516     private GroovySourceAST getParentNode() {
    517         Object currentNode = stack.pop();
    518         Object parentNode = stack.peek();
    519         stack.push(currentNode);
    520         return (GroovySourceAST) parentNode;
    521     }
    522
    523 }