blob: 5eedc99efbb51d776fd902ca54c75915b94b9ae3 [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.antlr.treewalker;
import java.util.ArrayList;
import java.util.Collections;
import org.codehaus.groovy.antlr.GroovySourceAST;
import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
/**
* A treewalker for the antlr generated AST that attempts to visit the
* AST nodes in the order needed to generate valid groovy source code.
*
* @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
* @version $Revision$
*/
public class SourceCodeTraversal extends TraversalHelper {
/**
* Constructs a treewalker for the antlr generated AST that attempts to visit the
* AST nodes in the order needed to generate valid groovy source code.
* @param visitor the visitor implementation to call for each AST node.
*/
public SourceCodeTraversal(Visitor visitor) {
super(visitor);
}
/**
* gather, sort and process all unvisited nodes
* @param t the AST to process
*/
public void setUp(GroovySourceAST t) {
super.setUp(t);
// gather and sort all unvisited AST nodes
unvisitedNodes = new ArrayList();
traverse((GroovySourceAST)t);
Collections.sort(unvisitedNodes);
}
/**
* traverse an AST node
* @param t the AST node to traverse
*/
private void traverse(GroovySourceAST t) {
if (t == null) { return; }
if (unvisitedNodes != null) {
unvisitedNodes.add(t);
}
GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
if (child != null) {
traverse(child);
}
GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
if (sibling != null) {
traverse(sibling);
}
}
protected void accept(GroovySourceAST currentNode) {
if (currentNode != null && unvisitedNodes != null && unvisitedNodes.size() > 0) {
GroovySourceAST t = currentNode;
if (!(unvisitedNodes.contains(currentNode))) {
return;
}
push(t);
switch (t.getType()) {
case GroovyTokenTypes.QUESTION: // expr?foo:bar
accept_FirstChild_v_SecondChild_v_ThirdChild_v(t);
break;
case GroovyTokenTypes.CASE_GROUP: //
case GroovyTokenTypes.LITERAL_instanceof: // foo instanceof MyType
accept_FirstChild_v_SecondChildsChildren_v(t);
break;
case GroovyTokenTypes.ANNOTATION:
accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(t);
break;
case GroovyTokenTypes.CLOSURE_LIST: // (a=1; a<10; a++)
case GroovyTokenTypes.ELIST: // a,b,c
case GroovyTokenTypes.PARAMETERS: // a,b,c
case GroovyTokenTypes.TYPE_ARGUMENTS: // <String, Object>
case GroovyTokenTypes.STRING_CONSTRUCTOR: // "foo${bar}wibble"
case GroovyTokenTypes.TYPE_PARAMETER: // class Foo<T extends F>
case GroovyTokenTypes.TYPE_PARAMETERS: // class Foo<T>
case GroovyTokenTypes.TYPE_UPPER_BOUNDS: // class Foo<T extends F>
accept_v_FirstChild_v_SecondChild_v___LastChild_v(t);
// todo : confirm that TYPE_LOWER_BOUNDS does not have multiple children
break;
case GroovyTokenTypes.VARIABLE_PARAMETER_DEF: // void f(String ... others) {}
accept_v_FirstChild_SecondChild_v_ThirdChild_v(t);
break;
case GroovyTokenTypes.INDEX_OP:
accept_FirstChild_v_SecondChild_v(t);
break;
case GroovyTokenTypes.ENUM_CONSTANT_DEF: // enum Foo(THESE,ARE,THEY)
case GroovyTokenTypes.EXPR:
case GroovyTokenTypes.IMPORT:
case GroovyTokenTypes.VARIABLE_DEF:
case GroovyTokenTypes.METHOD_DEF:
case GroovyTokenTypes.OBJBLOCK: //class Foo {def bar()} <-- this block
case GroovyTokenTypes.PARAMETER_DEF: // void f(String me) {}
case GroovyTokenTypes.SLIST: // list of expressions, variable defs etc
accept_v_AllChildren_v(t);
break;
case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR: // @Blue(foo=123)
case GroovyTokenTypes.ASSIGN: // a = b
case GroovyTokenTypes.BAND_ASSIGN: // a &= b
case GroovyTokenTypes.BOR_ASSIGN: // a |= b
case GroovyTokenTypes.BSR_ASSIGN: // a >>>= b
case GroovyTokenTypes.BXOR_ASSIGN: // a ^= b
case GroovyTokenTypes.COMPARE_TO: // a <=> b
case GroovyTokenTypes.DIV_ASSIGN: // a /= b
case GroovyTokenTypes.EQUAL: // a == b
case GroovyTokenTypes.MINUS_ASSIGN: // a -= b
case GroovyTokenTypes.MOD_ASSIGN: // a %= b
case GroovyTokenTypes.NOT_EQUAL: // a != b
case GroovyTokenTypes.PLUS_ASSIGN: // a += b
case GroovyTokenTypes.REGEX_FIND: // a =~ b
case GroovyTokenTypes.REGEX_MATCH: // a ==~ b
case GroovyTokenTypes.SL_ASSIGN: // a <<= b
case GroovyTokenTypes.SR_ASSIGN: // a >>= b
case GroovyTokenTypes.STAR_ASSIGN: // a *= b
case GroovyTokenTypes.STAR_STAR_ASSIGN: // x **= 3
if (t.childAt(1) != null) {
accept_FirstChild_v_RestOfTheChildren(t);
} else {
accept_v_FirstChild_v_RestOfTheChildren(t);
}
break;
case GroovyTokenTypes.ANNOTATION_FIELD_DEF: // @interface Foo{ int bar()...
accept_FirstSecondAndThirdChild_v_v_ForthChild(t);
break;
case GroovyTokenTypes.ANNOTATION_DEF: // @interface Foo...
case GroovyTokenTypes.BAND: // 1 & 2
case GroovyTokenTypes.BOR: // 1 | 2
case GroovyTokenTypes.BSR: // 1 >>> 2
case GroovyTokenTypes.BXOR: // 1 ^ 2
case GroovyTokenTypes.CLASS_DEF: // class Foo...
case GroovyTokenTypes.CTOR_IDENT: // private Foo() {...
case GroovyTokenTypes.DIV: // 3/4
case GroovyTokenTypes.DOT: // foo.bar
case GroovyTokenTypes.ENUM_DEF: // enum Foo...
case GroovyTokenTypes.GE: // a >= b
case GroovyTokenTypes.GT: // a > b
case GroovyTokenTypes.INTERFACE_DEF: // interface Foo...
case GroovyTokenTypes.LABELED_ARG: // myMethod(name:"Jez")
case GroovyTokenTypes.LABELED_STAT: // foo:x=1
case GroovyTokenTypes.LAND: // true && false
case GroovyTokenTypes.LE: // a <= b
case GroovyTokenTypes.LITERAL_as: // foo as Bar
case GroovyTokenTypes.LITERAL_in: // if (i in myList) ...
case GroovyTokenTypes.LOR: // true && false
case GroovyTokenTypes.LT: // a < b
case GroovyTokenTypes.MEMBER_POINTER: // this.&foo()
case GroovyTokenTypes.MOD: // 4 % 3
case GroovyTokenTypes.MINUS: // 1 - 1
case GroovyTokenTypes.OPTIONAL_DOT: // foo?.bar
case GroovyTokenTypes.PACKAGE_DEF:
case GroovyTokenTypes.PLUS: // 1 + 1
case GroovyTokenTypes.RANGE_EXCLUSIVE: // [1..<10]
case GroovyTokenTypes.RANGE_INCLUSIVE: // [1..10]
case GroovyTokenTypes.SL: // a << b
case GroovyTokenTypes.SPREAD_DOT: // foo*.bar
case GroovyTokenTypes.SR: // a >> b
case GroovyTokenTypes.STAR: // a * b or import foo.*
case GroovyTokenTypes.STAR_STAR: // x ** 3
accept_FirstChild_v_RestOfTheChildren(t);
break;
case GroovyTokenTypes.CTOR_CALL:
case GroovyTokenTypes.METHOD_CALL:
if (t.getNumberOfChildren() == 2 && t.childAt(1) != null && t.childAt(1).getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
// myMethod {...
accept_FirstChild_v_SecondChild(t);
} else {
GroovySourceAST lastChild = t.childAt(t.getNumberOfChildren() -1);
if (lastChild != null && lastChild.getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
// myMethod(a,b) {...
accept_FirstChild_v_RestOfTheChildren_v_LastChild(t);
} else {
// myMethod(a,b)
accept_FirstChild_v_RestOfTheChildren_v(t);
}
}
break;
case GroovyTokenTypes.LITERAL_while:
//deprecated case GroovyTokenTypes.LITERAL_with:
case GroovyTokenTypes.TYPECAST: // (String)itr.next()
accept_v_FirstChildsFirstChild_v_RestOfTheChildren(t);
break;
case GroovyTokenTypes.LITERAL_if: // if (grandchild) {child1} else {child2} ...
accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(t);
break;
case GroovyTokenTypes.CLOSABLE_BLOCK: // [1,2,3].each {foo(it)} <-- Closure
if (t.childAt(0) != null && t.childAt(0).getType() == GroovyTokenTypes.IMPLICIT_PARAMETERS) {
accept_v_AllChildren_v(t);
} else {
accept_v_FirstChild_v_RestOfTheChildren_v(t);
}
break;
case GroovyTokenTypes.FOR_IN_ITERABLE:
case GroovyTokenTypes.LITERAL_for:
case GroovyTokenTypes.LITERAL_new:
case GroovyTokenTypes.LITERAL_switch:
accept_v_FirstChild_v_RestOfTheChildren_v(t);
break;
case GroovyTokenTypes.ANNOTATIONS: // just like modifiers but for package/enum declarations
case GroovyTokenTypes.LITERAL_assert:
case GroovyTokenTypes.LITERAL_catch:
case GroovyTokenTypes.LITERAL_synchronized:
case GroovyTokenTypes.LITERAL_try:
case GroovyTokenTypes.MODIFIERS:
accept_v_FirstChild_v_RestOfTheChildren(t);
break;
case GroovyTokenTypes.WILDCARD_TYPE:
accept_v_Siblings_v(t);
break;
default:
accept_v_FirstChild_v(t);
break;
}
pop();
}
}
}