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: 4538 $
    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.ANNOTATION:
    94                      accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(t);
    95                      break;
    96
    97                  case GroovyTokenTypes.ELIST: // a,b,c
    98                  case GroovyTokenTypes.PARAMETERS: // a,b,c
    99                  case GroovyTokenTypes.TYPE_ARGUMENTS: // <String, Object>
    100                 case GroovyTokenTypes.STRING_CONSTRUCTOR: // "foo${bar}wibble"
    101                 case GroovyTokenTypes.TYPE_PARAMETER: // class Foo<T extends F>
    102                 case GroovyTokenTypes.TYPE_PARAMETERS: // class Foo<T>
    103                 case GroovyTokenTypes.TYPE_UPPER_BOUNDS: // class Foo<T extends F>
    104                     accept_v_FirstChild_v_SecondChild_v___LastChild_v(t);
    105                     // todo : confirm that TYPE_LOWER_BOUNDS does not have multiple children
    106                     break;
    107
    108                 case GroovyTokenTypes.VARIABLE_PARAMETER_DEF: // void f(String ... others) {}
    109                     accept_v_FirstChild_SecondChild_v_ThirdChild_v(t);
    110                     break;
    111
    112                 case GroovyTokenTypes.INDEX_OP:
    113                     accept_FirstChild_v_SecondChild_v(t);
    114                     break;
    115
    116                 case GroovyTokenTypes.ENUM_CONSTANT_DEF: // enum Foo(THESE,ARE,THEY)
    117                 case GroovyTokenTypes.EXPR:
    118                 case GroovyTokenTypes.IMPORT:
    119                 case GroovyTokenTypes.VARIABLE_DEF:
    120                 case GroovyTokenTypes.METHOD_DEF:
    121                 case GroovyTokenTypes.OBJBLOCK: //class Foo {def bar()}  <-- this block
    122                 case GroovyTokenTypes.PARAMETER_DEF: // void f(String me) {}
    123                 case GroovyTokenTypes.SLIST: // list of expressions, variable defs etc
    124                     accept_v_AllChildren_v(t);
    125                     break;
    126
    127                 case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR: // @Blue(foo=123)
    128                 case GroovyTokenTypes.ASSIGN: // a = b
    129                 case GroovyTokenTypes.BAND_ASSIGN: // a &= b
    130                 case GroovyTokenTypes.BOR_ASSIGN: // a |= b
    131                 case GroovyTokenTypes.BSR_ASSIGN: // a >>>= b
    132                 case GroovyTokenTypes.BXOR_ASSIGN: // a ^= b
    133                 case GroovyTokenTypes.COMPARE_TO: // a <=> b
    134                 case GroovyTokenTypes.DIV_ASSIGN: // a /= b
    135                 case GroovyTokenTypes.EQUAL: // a == b
    136                 case GroovyTokenTypes.MINUS_ASSIGN: // a -= b
    137                 case GroovyTokenTypes.MOD_ASSIGN: // a %= b
    138                 case GroovyTokenTypes.NOT_EQUAL: // a != b
    139                 case GroovyTokenTypes.PLUS_ASSIGN: // a += b
    140                 case GroovyTokenTypes.REGEX_FIND: // a =~ b
    141                 case GroovyTokenTypes.REGEX_MATCH: // a ==~ b
    142                 case GroovyTokenTypes.SL_ASSIGN: // a <<= b
    143                 case GroovyTokenTypes.SR_ASSIGN: // a >>= b
    144                 case GroovyTokenTypes.STAR_ASSIGN: // a *= b
    145                 case GroovyTokenTypes.STAR_STAR_ASSIGN: // x **= 3
    146                     if (t.childAt(1) != null) {
    147                         accept_FirstChild_v_RestOfTheChildren(t);
    148                     } else {
    149                         accept_v_FirstChild_v_RestOfTheChildren(t);
    150                     }
    151                     break;
    152
    153                 case GroovyTokenTypes.ANNOTATION_FIELD_DEF: // @interface Foo{ int bar()...
    154                     accept_FirstSecondAndThirdChild_v_v_ForthChild(t);
    155                     break;
    156
    157                 case GroovyTokenTypes.ANNOTATION_DEF: // @interface Foo...
    158                 case GroovyTokenTypes.BAND: // 1 & 2
    159                 case GroovyTokenTypes.BOR: // 1 | 2
    160                 case GroovyTokenTypes.BSR: // 1 >>> 2
    161                 case GroovyTokenTypes.BXOR: // 1 ^ 2
    162                 case GroovyTokenTypes.CLASS_DEF: // class Foo...
    163                 case GroovyTokenTypes.CTOR_IDENT: // private Foo() {...
    164                 case GroovyTokenTypes.DIV: //  3/4
    165                 case GroovyTokenTypes.DOT: // foo.bar
    166                 case GroovyTokenTypes.ENUM_DEF: // enum Foo...
    167                 case GroovyTokenTypes.GE: // a >= b
    168                 case GroovyTokenTypes.GT: // a > b
    169                 case GroovyTokenTypes.INTERFACE_DEF: // interface Foo...
    170                 case GroovyTokenTypes.LABELED_ARG: // myMethod(name:"Jez")
    171                 case GroovyTokenTypes.LABELED_STAT: // foo:x=1
    172                 case GroovyTokenTypes.LAND: // true && false
    173                 case GroovyTokenTypes.LE: // a <= b
    174                 case GroovyTokenTypes.LITERAL_as: // foo as Bar
    175                 case GroovyTokenTypes.LITERAL_in: // if (i in myList) ...
    176                 case GroovyTokenTypes.LOR: // true && false
    177                 case GroovyTokenTypes.LT: // a < b
    178                 case GroovyTokenTypes.MEMBER_POINTER: // this.&foo()
    179                 case GroovyTokenTypes.MOD: //  4 % 3
    180                 case GroovyTokenTypes.MINUS: // 1 - 1
    181                 case GroovyTokenTypes.OPTIONAL_DOT: // foo?.bar
    182                 case GroovyTokenTypes.PACKAGE_DEF:
    183                 case GroovyTokenTypes.PLUS: // 1 + 1
    184                 case GroovyTokenTypes.RANGE_EXCLUSIVE: // [1..<10]
    185                 case GroovyTokenTypes.RANGE_INCLUSIVE: // [1..10]
    186                 case GroovyTokenTypes.SL: // a << b
    187                 case GroovyTokenTypes.SR: // a >> b
    188                 case GroovyTokenTypes.STAR: // a * b   or    import foo.*
    189                 case GroovyTokenTypes.STAR_STAR: // x ** 3
    190                     accept_FirstChild_v_RestOfTheChildren(t);
    191                     break;
    192
    193                 case GroovyTokenTypes.CTOR_CALL:
    194                 case GroovyTokenTypes.METHOD_CALL:
    195                     if (t.getNumberOfChildren() == 2 && t.childAt(1) != null && t.childAt(1).getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
    196                         // myMethod {...
    197                         accept_FirstChild_v_SecondChild(t);
    198                     } else {
    199                         GroovySourceAST lastChild = t.childAt(t.getNumberOfChildren() -1);
    200                         if (lastChild != null && lastChild.getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
    201                             // myMethod(a,b) {...
    202                             accept_FirstChild_v_RestOfTheChildren_v_LastChild(t);
    203                         } else {
    204                             // myMethod(a,b)
    205                             accept_FirstChild_v_RestOfTheChildren_v(t);
    206                         }
    207                     }
    208                     break;
    209
    210                 case GroovyTokenTypes.LITERAL_while:
    211                 case GroovyTokenTypes.LITERAL_with:
    212                 case GroovyTokenTypes.TYPECAST: // (String)itr.next()
    213                     accept_v_FirstChildsFirstChild_v_RestOfTheChildren(t);
    214                     break;
    215
    216                 case GroovyTokenTypes.LITERAL_if: // if (grandchild) {child1} else {child2} ...
    217                     accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(t);
    218                     break;
    219
    220                 case GroovyTokenTypes.CLOSABLE_BLOCK: // [1,2,3].each {foo(it)}  <-- Closure
    221                     if (t.childAt(0) != null && t.childAt(0).getType() == GroovyTokenTypes.IMPLICIT_PARAMETERS) {
    222                         accept_v_AllChildren_v(t);
    223                     } else {
    224                         accept_v_FirstChild_v_RestOfTheChildren_v(t);
    225                     }
    226                     break;
    227
    228                 case GroovyTokenTypes.FOR_IN_ITERABLE:
    229                 case GroovyTokenTypes.LITERAL_for:
    230                 case GroovyTokenTypes.LITERAL_new:
    231                 case GroovyTokenTypes.LITERAL_switch:
    232                     accept_v_FirstChild_v_RestOfTheChildren_v(t);
    233                     break;
    234
    235                 case GroovyTokenTypes.ANNOTATIONS: // just like modifiers but for package/enum declarations
    236                 case GroovyTokenTypes.LITERAL_assert:
    237                 case GroovyTokenTypes.LITERAL_catch:
    238                 case GroovyTokenTypes.LITERAL_synchronized:
    239                 case GroovyTokenTypes.LITERAL_try:
    240                 case GroovyTokenTypes.MODIFIERS:
    241                     accept_v_FirstChild_v_RestOfTheChildren(t);
    242                     break;
    243
    244                 default:
    245                     accept_v_FirstChild_v(t);
    246                     break;
    247             }
    248             pop();
    249         }
    250     }
    251 }