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 }