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.util.ArrayList;
    21  import java.util.Collections;
    22
    23  import org.codehaus.groovy.antlr.GroovySourceAST;
    24  import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
    25
    26  /***
    27   * A treewalker for the antlr generated AST that attempts to visit the
    28   * AST nodes in the order needed to generate valid groovy source code.
    29   *
    30   * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
    31   * @version $Revision: 1.14 $
    32   */
    33  public class SourceCodeTraversal extends TraversalHelper {
    34      /***
    35       * Constructs a treewalker for the antlr generated AST that attempts to visit the
    36       * AST nodes in the order needed to generate valid groovy source code.
    37       * @param visitor the visitor implementation to call for each AST node.
    38       */
    39      public SourceCodeTraversal(Visitor visitor) {
    40          super(visitor);
    41      }
    42
    43      /***
    44       * gather, sort and process all unvisited nodes
    45       * @param t the AST to process
    46       */
    47      public void setUp(GroovySourceAST t) {
    48          super.setUp(t);
    49
    50          // gather and sort all unvisited AST nodes
    51          unvisitedNodes = new ArrayList();
    52          traverse((GroovySourceAST)t);
    53          Collections.sort(unvisitedNodes);
    54      }
    55
    56      /***
    57       * traverse an AST node
    58       * @param t the AST node to traverse
    59       */
    60      private void traverse(GroovySourceAST t) {
    61          if (t == null) { return; }
    62          if (unvisitedNodes != null) {
    63             unvisitedNodes.add(t);
    64          }
    65          GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
    66          if (child != null) {
    67              traverse(child);
    68          }
    69          GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
    70          if (sibling != null) {
    71              traverse(sibling);
    72          }
    73      }
    74
    75      protected void accept(GroovySourceAST currentNode) {
    76          if (currentNode != null && unvisitedNodes != null && unvisitedNodes.size() > 0) {
    77              GroovySourceAST t = currentNode;
    78
    79              if (!(unvisitedNodes.contains(currentNode))) {
    80                  return;
    81              }
    82              push(t);
    83              switch (t.getType()) {
    84                  case GroovyTokenTypes.QUESTION: // expr?foo:bar
    85                      accept_FirstChild_v_SecondChild_v_ThirdChild_v(t);
    86                      break;
    87
    88                  case GroovyTokenTypes.CASE_GROUP: //
    89                  case GroovyTokenTypes.LITERAL_instanceof: // foo instanceof MyType
    90                      accept_FirstChild_v_SecondChildsChildren_v(t);
    91                      break;
    92
    93                  case GroovyTokenTypes.ELIST: // a,b,c
    94                  case GroovyTokenTypes.PARAMETERS: // a,b,c
    95                  case GroovyTokenTypes.STRING_CONSTRUCTOR: // "foo${bar}wibble"
    96                      accept_v_FirstChild_v_SecondChild_v___LastChild_v(t);
    97                      break;
    98
    99                  case GroovyTokenTypes.INDEX_OP:
    100                     accept_FirstChild_v_SecondChild_v(t);
    101                     break;
    102
    103                 case GroovyTokenTypes.EXPR:
    104                 case GroovyTokenTypes.IMPORT:
    105                 case GroovyTokenTypes.PACKAGE_DEF:
    106                 case GroovyTokenTypes.VARIABLE_DEF:
    107                 case GroovyTokenTypes.METHOD_DEF:
    108                 case GroovyTokenTypes.OBJBLOCK: //class Foo {def bar()}  <-- this block
    109                 case GroovyTokenTypes.PARAMETER_DEF:
    110                 case GroovyTokenTypes.SLIST: // list of expressions, variable defs etc
    111                     accept_v_AllChildren_v(t);
    112                     break;
    113
    114                 case GroovyTokenTypes.ASSIGN: // a=b
    115                 case GroovyTokenTypes.EQUAL: // a==b
    116                 case GroovyTokenTypes.NOT_EQUAL:
    117                     if (t.childAt(1) != null) {
    118                         accept_FirstChild_v_RestOfTheChildren(t);
    119                     } else {
    120                         accept_v_FirstChild_v_RestOfTheChildren(t);
    121                     }
    122                     break;
    123
    124                 case GroovyTokenTypes.CLASS_DEF: // class Foo...
    125                 case GroovyTokenTypes.CTOR_IDENT: // private Foo() {...
    126                 case GroovyTokenTypes.DOT: // foo.bar
    127                 case GroovyTokenTypes.GT: // a > b
    128                 case GroovyTokenTypes.LABELED_ARG: // myMethod(name:"Jez")
    129                 case GroovyTokenTypes.LAND: // true && false
    130                 case GroovyTokenTypes.LT: // a < b
    131                 case GroovyTokenTypes.MEMBER_POINTER: // this.&foo()
    132                 case GroovyTokenTypes.MINUS:
    133                 case GroovyTokenTypes.PLUS:
    134                 case GroovyTokenTypes.RANGE_EXCLUSIVE:
    135                 case GroovyTokenTypes.RANGE_INCLUSIVE:
    136                 case GroovyTokenTypes.STAR: // a * b   or    import foo.*
    137                     accept_FirstChild_v_RestOfTheChildren(t);
    138                     break;
    139
    140                 case GroovyTokenTypes.METHOD_CALL:
    141                     if (t.getNumberOfChildren() == 2 && t.childAt(1) != null && t.childAt(1).getType() == GroovyTokenTypes.CLOSED_BLOCK ) {
    142                         // myMethod {...
    143                         accept_FirstChild_v_SecondChild(t);
    144                     } else {
    145                         GroovySourceAST lastChild = t.childAt(t.getNumberOfChildren() -1);
    146                         if (lastChild != null && lastChild.getType() == GroovyTokenTypes.CLOSED_BLOCK) {
    147                             // myMethod(a,b) {...
    148                             accept_FirstChild_v_RestOfTheChildren_v_LastChild(t);
    149                         } else {
    150                             // myMethod(a,b)
    151                             accept_FirstChild_v_RestOfTheChildren_v(t);
    152                         }
    153                     }
    154                     break;
    155
    156                 case GroovyTokenTypes.LITERAL_while:
    157                 case GroovyTokenTypes.TYPECAST: // (String)itr.next()
    158                     accept_v_FirstChildsFirstChild_v_RestOfTheChildren(t);
    159                     break;
    160
    161                 case GroovyTokenTypes.LITERAL_if: // if (grandchild) {child1} else {child2} ...
    162                     accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(t);
    163                     break;
    164
    165                 case GroovyTokenTypes.CLOSED_BLOCK: // [1,2,3].each {foo(it)}  <-- Closure
    166                     if (t.childAt(0) != null && t.childAt(0).getType() == GroovyTokenTypes.IMPLICIT_PARAMETERS) {
    167                         accept_v_AllChildren_v(t);
    168                     } else {
    169                         accept_v_FirstChild_v_RestOfTheChildren_v(t);
    170                     }
    171                     break;
    172
    173                 case GroovyTokenTypes.FOR_IN_ITERABLE:
    174                 case GroovyTokenTypes.LITERAL_for:
    175                 case GroovyTokenTypes.LITERAL_new:
    176                 case GroovyTokenTypes.LITERAL_switch:
    177                     accept_v_FirstChild_v_RestOfTheChildren_v(t);
    178                     break;
    179
    180                 case GroovyTokenTypes.LITERAL_catch:
    181                 case GroovyTokenTypes.LITERAL_try:
    182                     accept_v_FirstChild_v_RestOfTheChildren(t);
    183                     break;
    184
    185                 default:
    186                     accept_v_FirstChild_v(t);
    187                     break;
    188             }
    189             pop();
    190         }
    191     }
    192 }