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 }