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.util.ArrayList;
021 import java.util.Collections;
022
023 import org.codehaus.groovy.antlr.GroovySourceAST;
024 import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
025
026 /**
027 * A treewalker for the antlr generated AST that attempts to visit the
028 * AST nodes in the order needed to generate valid groovy source code.
029 *
030 * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
031 * @version $Revision: 4538 $
032 */
033 public class SourceCodeTraversal extends TraversalHelper {
034 /**
035 * Constructs a treewalker for the antlr generated AST that attempts to visit the
036 * AST nodes in the order needed to generate valid groovy source code.
037 * @param visitor the visitor implementation to call for each AST node.
038 */
039 public SourceCodeTraversal(Visitor visitor) {
040 super(visitor);
041 }
042
043 /**
044 * gather, sort and process all unvisited nodes
045 * @param t the AST to process
046 */
047 public void setUp(GroovySourceAST t) {
048 super.setUp(t);
049
050 // gather and sort all unvisited AST nodes
051 unvisitedNodes = new ArrayList();
052 traverse((GroovySourceAST)t);
053 Collections.sort(unvisitedNodes);
054 }
055
056 /**
057 * traverse an AST node
058 * @param t the AST node to traverse
059 */
060 private void traverse(GroovySourceAST t) {
061 if (t == null) { return; }
062 if (unvisitedNodes != null) {
063 unvisitedNodes.add(t);
064 }
065 GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
066 if (child != null) {
067 traverse(child);
068 }
069 GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
070 if (sibling != null) {
071 traverse(sibling);
072 }
073 }
074
075 protected void accept(GroovySourceAST currentNode) {
076 if (currentNode != null && unvisitedNodes != null && unvisitedNodes.size() > 0) {
077 GroovySourceAST t = currentNode;
078
079 if (!(unvisitedNodes.contains(currentNode))) {
080 return;
081 }
082 push(t);
083 switch (t.getType()) {
084 case GroovyTokenTypes.QUESTION: // expr?foo:bar
085 accept_FirstChild_v_SecondChild_v_ThirdChild_v(t);
086 break;
087
088 case GroovyTokenTypes.CASE_GROUP: //
089 case GroovyTokenTypes.LITERAL_instanceof: // foo instanceof MyType
090 accept_FirstChild_v_SecondChildsChildren_v(t);
091 break;
092
093 case GroovyTokenTypes.ANNOTATION:
094 accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(t);
095 break;
096
097 case GroovyTokenTypes.ELIST: // a,b,c
098 case GroovyTokenTypes.PARAMETERS: // a,b,c
099 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 }