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: **/package org.codehaus.groovy.antlr.treewalker;
018:
019: import java.util.ArrayList;
020: import java.util.Collections;
021:
022: import org.codehaus.groovy.antlr.GroovySourceAST;
023: import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
024:
025: /**
026: * A treewalker for the antlr generated AST that attempts to visit the
027: * AST nodes in the order needed to generate valid groovy source code.
028: *
029: * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
030: * @version $Revision: 4538 $
031: */
032: public class SourceCodeTraversal extends TraversalHelper {
033: /**
034: * Constructs a treewalker for the antlr generated AST that attempts to visit the
035: * AST nodes in the order needed to generate valid groovy source code.
036: * @param visitor the visitor implementation to call for each AST node.
037: */
038: public SourceCodeTraversal(Visitor visitor) {
039: super (visitor);
040: }
041:
042: /**
043: * gather, sort and process all unvisited nodes
044: * @param t the AST to process
045: */
046: public void setUp(GroovySourceAST t) {
047: super .setUp(t);
048:
049: // gather and sort all unvisited AST nodes
050: unvisitedNodes = new ArrayList();
051: traverse((GroovySourceAST) t);
052: Collections.sort(unvisitedNodes);
053: }
054:
055: /**
056: * traverse an AST node
057: * @param t the AST node to traverse
058: */
059: private void traverse(GroovySourceAST t) {
060: if (t == null) {
061: return;
062: }
063: if (unvisitedNodes != null) {
064: unvisitedNodes.add(t);
065: }
066: GroovySourceAST child = (GroovySourceAST) t.getFirstChild();
067: if (child != null) {
068: traverse(child);
069: }
070: GroovySourceAST sibling = (GroovySourceAST) t.getNextSibling();
071: if (sibling != null) {
072: traverse(sibling);
073: }
074: }
075:
076: protected void accept(GroovySourceAST currentNode) {
077: if (currentNode != null && unvisitedNodes != null
078: && unvisitedNodes.size() > 0) {
079: GroovySourceAST t = currentNode;
080:
081: if (!(unvisitedNodes.contains(currentNode))) {
082: return;
083: }
084: push(t);
085: switch (t.getType()) {
086: case GroovyTokenTypes.QUESTION: // expr?foo:bar
087: accept_FirstChild_v_SecondChild_v_ThirdChild_v(t);
088: break;
089:
090: case GroovyTokenTypes.CASE_GROUP: //
091: case GroovyTokenTypes.LITERAL_instanceof : // foo instanceof MyType
092: accept_FirstChild_v_SecondChildsChildren_v(t);
093: break;
094:
095: case GroovyTokenTypes.ANNOTATION:
096: accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(t);
097: break;
098:
099: case GroovyTokenTypes.ELIST: // a,b,c
100: case GroovyTokenTypes.PARAMETERS: // a,b,c
101: case GroovyTokenTypes.TYPE_ARGUMENTS: // <String, Object>
102: case GroovyTokenTypes.STRING_CONSTRUCTOR: // "foo${bar}wibble"
103: case GroovyTokenTypes.TYPE_PARAMETER: // class Foo<T extends F>
104: case GroovyTokenTypes.TYPE_PARAMETERS: // class Foo<T>
105: case GroovyTokenTypes.TYPE_UPPER_BOUNDS: // class Foo<T extends F>
106: accept_v_FirstChild_v_SecondChild_v___LastChild_v(t);
107: // todo : confirm that TYPE_LOWER_BOUNDS does not have multiple children
108: break;
109:
110: case GroovyTokenTypes.VARIABLE_PARAMETER_DEF: // void f(String ... others) {}
111: accept_v_FirstChild_SecondChild_v_ThirdChild_v(t);
112: break;
113:
114: case GroovyTokenTypes.INDEX_OP:
115: accept_FirstChild_v_SecondChild_v(t);
116: break;
117:
118: case GroovyTokenTypes.ENUM_CONSTANT_DEF: // enum Foo(THESE,ARE,THEY)
119: case GroovyTokenTypes.EXPR:
120: case GroovyTokenTypes.IMPORT:
121: case GroovyTokenTypes.VARIABLE_DEF:
122: case GroovyTokenTypes.METHOD_DEF:
123: case GroovyTokenTypes.OBJBLOCK: //class Foo {def bar()} <-- this block
124: case GroovyTokenTypes.PARAMETER_DEF: // void f(String me) {}
125: case GroovyTokenTypes.SLIST: // list of expressions, variable defs etc
126: accept_v_AllChildren_v(t);
127: break;
128:
129: case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR: // @Blue(foo=123)
130: case GroovyTokenTypes.ASSIGN: // a = b
131: case GroovyTokenTypes.BAND_ASSIGN: // a &= b
132: case GroovyTokenTypes.BOR_ASSIGN: // a |= b
133: case GroovyTokenTypes.BSR_ASSIGN: // a >>>= b
134: case GroovyTokenTypes.BXOR_ASSIGN: // a ^= b
135: case GroovyTokenTypes.COMPARE_TO: // a <=> b
136: case GroovyTokenTypes.DIV_ASSIGN: // a /= b
137: case GroovyTokenTypes.EQUAL: // a == b
138: case GroovyTokenTypes.MINUS_ASSIGN: // a -= b
139: case GroovyTokenTypes.MOD_ASSIGN: // a %= b
140: case GroovyTokenTypes.NOT_EQUAL: // a != b
141: case GroovyTokenTypes.PLUS_ASSIGN: // a += b
142: case GroovyTokenTypes.REGEX_FIND: // a =~ b
143: case GroovyTokenTypes.REGEX_MATCH: // a ==~ b
144: case GroovyTokenTypes.SL_ASSIGN: // a <<= b
145: case GroovyTokenTypes.SR_ASSIGN: // a >>= b
146: case GroovyTokenTypes.STAR_ASSIGN: // a *= b
147: case GroovyTokenTypes.STAR_STAR_ASSIGN: // x **= 3
148: if (t.childAt(1) != null) {
149: accept_FirstChild_v_RestOfTheChildren(t);
150: } else {
151: accept_v_FirstChild_v_RestOfTheChildren(t);
152: }
153: break;
154:
155: case GroovyTokenTypes.ANNOTATION_FIELD_DEF: // @interface Foo{ int bar()...
156: accept_FirstSecondAndThirdChild_v_v_ForthChild(t);
157: break;
158:
159: case GroovyTokenTypes.ANNOTATION_DEF: // @interface Foo...
160: case GroovyTokenTypes.BAND: // 1 & 2
161: case GroovyTokenTypes.BOR: // 1 | 2
162: case GroovyTokenTypes.BSR: // 1 >>> 2
163: case GroovyTokenTypes.BXOR: // 1 ^ 2
164: case GroovyTokenTypes.CLASS_DEF: // class Foo...
165: case GroovyTokenTypes.CTOR_IDENT: // private Foo() {...
166: case GroovyTokenTypes.DIV: // 3/4
167: case GroovyTokenTypes.DOT: // foo.bar
168: case GroovyTokenTypes.ENUM_DEF: // enum Foo...
169: case GroovyTokenTypes.GE: // a >= b
170: case GroovyTokenTypes.GT: // a > b
171: case GroovyTokenTypes.INTERFACE_DEF: // interface Foo...
172: case GroovyTokenTypes.LABELED_ARG: // myMethod(name:"Jez")
173: case GroovyTokenTypes.LABELED_STAT: // foo:x=1
174: case GroovyTokenTypes.LAND: // true && false
175: case GroovyTokenTypes.LE: // a <= b
176: case GroovyTokenTypes.LITERAL_as: // foo as Bar
177: case GroovyTokenTypes.LITERAL_in: // if (i in myList) ...
178: case GroovyTokenTypes.LOR: // true && false
179: case GroovyTokenTypes.LT: // a < b
180: case GroovyTokenTypes.MEMBER_POINTER: // this.&foo()
181: case GroovyTokenTypes.MOD: // 4 % 3
182: case GroovyTokenTypes.MINUS: // 1 - 1
183: case GroovyTokenTypes.OPTIONAL_DOT: // foo?.bar
184: case GroovyTokenTypes.PACKAGE_DEF:
185: case GroovyTokenTypes.PLUS: // 1 + 1
186: case GroovyTokenTypes.RANGE_EXCLUSIVE: // [1..<10]
187: case GroovyTokenTypes.RANGE_INCLUSIVE: // [1..10]
188: case GroovyTokenTypes.SL: // a << b
189: case GroovyTokenTypes.SR: // a >> b
190: case GroovyTokenTypes.STAR: // a * b or import foo.*
191: case GroovyTokenTypes.STAR_STAR: // x ** 3
192: accept_FirstChild_v_RestOfTheChildren(t);
193: break;
194:
195: case GroovyTokenTypes.CTOR_CALL:
196: case GroovyTokenTypes.METHOD_CALL:
197: if (t.getNumberOfChildren() == 2
198: && t.childAt(1) != null
199: && t.childAt(1).getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
200: // myMethod {...
201: accept_FirstChild_v_SecondChild(t);
202: } else {
203: GroovySourceAST lastChild = t.childAt(t
204: .getNumberOfChildren() - 1);
205: if (lastChild != null
206: && lastChild.getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
207: // myMethod(a,b) {...
208: accept_FirstChild_v_RestOfTheChildren_v_LastChild(t);
209: } else {
210: // myMethod(a,b)
211: accept_FirstChild_v_RestOfTheChildren_v(t);
212: }
213: }
214: break;
215:
216: case GroovyTokenTypes.LITERAL_while:
217: case GroovyTokenTypes.LITERAL_with:
218: case GroovyTokenTypes.TYPECAST: // (String)itr.next()
219: accept_v_FirstChildsFirstChild_v_RestOfTheChildren(t);
220: break;
221:
222: case GroovyTokenTypes.LITERAL_if: // if (grandchild) {child1} else {child2} ...
223: accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(t);
224: break;
225:
226: case GroovyTokenTypes.CLOSABLE_BLOCK: // [1,2,3].each {foo(it)} <-- Closure
227: if (t.childAt(0) != null
228: && t.childAt(0).getType() == GroovyTokenTypes.IMPLICIT_PARAMETERS) {
229: accept_v_AllChildren_v(t);
230: } else {
231: accept_v_FirstChild_v_RestOfTheChildren_v(t);
232: }
233: break;
234:
235: case GroovyTokenTypes.FOR_IN_ITERABLE:
236: case GroovyTokenTypes.LITERAL_for:
237: case GroovyTokenTypes.LITERAL_new:
238: case GroovyTokenTypes.LITERAL_switch:
239: accept_v_FirstChild_v_RestOfTheChildren_v(t);
240: break;
241:
242: case GroovyTokenTypes.ANNOTATIONS: // just like modifiers but for package/enum declarations
243: case GroovyTokenTypes.LITERAL_assert:
244: case GroovyTokenTypes.LITERAL_catch:
245: case GroovyTokenTypes.LITERAL_synchronized:
246: case GroovyTokenTypes.LITERAL_try:
247: case GroovyTokenTypes.MODIFIERS:
248: accept_v_FirstChild_v_RestOfTheChildren(t);
249: break;
250:
251: default:
252: accept_v_FirstChild_v(t);
253: break;
254: }
255: pop();
256: }
257: }
258: }
|