View Javadoc

1   /***
2    *
3    * Copyright 2004 James Strachan
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;
19  
20  import antlr.RecognitionException;
21  import antlr.TokenStreamException;
22  import antlr.TokenStreamRecognitionException;
23  import antlr.collections.AST;
24  import com.thoughtworks.xstream.XStream;
25  
26  import org.codehaus.groovy.GroovyBugError;
27  import org.codehaus.groovy.antlr.parser.GroovyLexer;
28  import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
29  import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
30  import org.codehaus.groovy.antlr.treewalker.*;
31  import org.codehaus.groovy.ast.*;
32  import org.codehaus.groovy.ast.expr.*;
33  import org.codehaus.groovy.ast.stmt.*;
34  import org.codehaus.groovy.control.CompilationFailedException;
35  import org.codehaus.groovy.control.ParserPlugin;
36  import org.codehaus.groovy.control.SourceUnit;
37  import org.codehaus.groovy.syntax.Numbers;
38  import org.codehaus.groovy.syntax.Reduction;
39  import org.codehaus.groovy.syntax.SyntaxException;
40  import org.codehaus.groovy.syntax.Token;
41  import org.codehaus.groovy.syntax.Types;
42  import org.codehaus.groovy.syntax.ASTHelper;
43  import org.codehaus.groovy.syntax.ParserException;
44  import org.objectweb.asm.Opcodes;
45  
46  import java.io.*;
47  import java.util.ArrayList;
48  import java.util.Iterator;
49  import java.util.List;
50  
51  /***
52   * A parser plugin which adapts the JSR Antlr Parser to the Groovy runtime
53   *
54   * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
55   * @version $Revision: 1.50 $
56   */
57  public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, GroovyTokenTypes {
58      private static final Type OBJECT_TYPE = new Type("java.lang.Object", true);
59  
60      private AST ast;
61      private ClassNode classNode;
62      private String[] tokenNames;
63  
64  
65      public Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
66          ast = null;
67  
68          setController(sourceUnit);
69  
70          SourceBuffer sourceBuffer = new SourceBuffer();
71          UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(reader,sourceBuffer);
72          GroovyLexer lexer = new GroovyLexer(unicodeReader);
73          unicodeReader.setLexer(lexer);
74          GroovyRecognizer parser = GroovyRecognizer.make(lexer);
75          parser.setSourceBuffer(sourceBuffer);
76          tokenNames = parser.getTokenNames();
77          parser.setFilename(sourceUnit.getName());
78  
79          // start parsing at the compilationUnit rule
80          try {
81              parser.compilationUnit();
82          }
83          catch (TokenStreamRecognitionException tsre) {
84              RecognitionException e = tsre.recog;
85              SyntaxException se = new SyntaxException(e.getMessage(),e,e.getLine(),e.getColumn());
86              se.setFatal(true);
87              sourceUnit.addError(se);
88          }
89          catch (RecognitionException e) {
90              SyntaxException se = new SyntaxException(e.getMessage(),e,e.getLine(),e.getColumn());
91              se.setFatal(true);
92              sourceUnit.addError(se);
93          }
94          catch (TokenStreamException e) {
95              sourceUnit.addException(e);
96          }
97  
98          ast = parser.getAST();
99  
100         AntlrASTProcessor snippets = new AntlrASTProcessSnippets(sourceBuffer);
101         ast = snippets.process(ast);
102 
103         outputASTInVariousFormsIfNeeded(sourceUnit);
104 
105         return null; //new Reduction(Tpken.EOF);
106     }
107 
108     private void outputASTInVariousFormsIfNeeded(SourceUnit sourceUnit) {
109         // straight xstream output of AST
110         if ("xml".equals(System.getProperty("antlr.ast"))) {
111             saveAsXML(sourceUnit.getName(), ast);
112         }
113 
114         // 'pretty printer' output of AST
115         if ("groovy".equals(System.getProperty("antlr.ast"))) {
116             try {
117                 PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".pretty.groovy"));
118                 Visitor visitor = new SourcePrinter(out,tokenNames);
119                 AntlrASTProcessor treewalker = new SourceCodeTraversal(visitor);
120                 treewalker.process(ast);
121             } catch (FileNotFoundException e) {
122                 System.out.println("Cannot create " + sourceUnit.getName() + ".pretty.groovy");
123             }
124         }
125 
126         // output AST in format suitable for opening in http://freemind.sourceforge.net
127         // which is a really nice way of seeing the AST, folding nodes etc
128         if ("mindmap".equals(System.getProperty("antlr.ast"))) {
129             try {
130                 PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".mm"));
131                 Visitor visitor = new MindMapPrinter(out,tokenNames);
132                 AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
133                 treewalker.process(ast);
134             } catch (FileNotFoundException e) {
135                 System.out.println("Cannot create " + sourceUnit.getName() + ".mm");
136             }
137         }
138 
139         // html output of AST
140         if ("html".equals(System.getProperty("antlr.ast"))) {
141             try {
142                 PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".html"));
143                 List v = new ArrayList();
144                 v.add(new NodeAsHTMLPrinter(out,tokenNames));
145                 v.add(new SourcePrinter(out,tokenNames));
146                 Visitor visitors = new CompositeVisitor(v);
147                 AntlrASTProcessor treewalker = new SourceCodeTraversal(visitors);
148                 treewalker.process(ast);
149             } catch (FileNotFoundException e) {
150                 System.out.println("Cannot create " + sourceUnit.getName() + ".html");
151             }
152         }
153 
154 
155     }
156 
157     private void saveAsXML(String name, AST ast) {
158         XStream xstream = new XStream();
159         try {
160             xstream.toXML(ast, new FileWriter(name + ".antlr.xml"));
161             System.out.println("Written AST to " + name + ".antlr.xml");
162         }
163         catch (Exception e) {
164             System.out.println("Couldn't write to " + name + ".antlr.xml");
165             e.printStackTrace();
166         }
167     }
168 
169     public ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException {
170         setClassLoader(classLoader);
171         makeModule();
172         try {
173             convertGroovy(ast);
174         }
175         catch (ASTRuntimeException e) {
176             throw new ASTParserException(e.getMessage() + ". File: " + sourceUnit.getName(), e);
177         }
178         return output;
179     }
180 
181     /***
182      * Converts the Antlr AST to the Groovy AST
183      */
184     protected void convertGroovy(AST node) {
185         while (node != null) {
186             int type = node.getType();
187             switch (type) {
188                 case PACKAGE_DEF:
189                     packageDef(node);
190                     break;
191 
192                 case IMPORT:
193                     importDef(node);
194                     break;
195 
196                 case CLASS_DEF:
197                     classDef(node);
198                     break;
199 
200                 case INTERFACE_DEF:
201                     interfaceDef(node);
202                     break;
203 
204                 case METHOD_DEF:
205                     methodDef(node);
206                     break;
207 
208                 default:
209                     {
210                         Statement statement = statement(node);
211                         output.addStatement(statement);
212                     }
213             }
214             node = node.getNextSibling();
215         }
216     }
217 
218     // Top level control structures
219     //-------------------------------------------------------------------------
220 
221     protectedong> void packageDef(AST packageDef) {
222         AST node = packageDef.getFirstChild();
223         if (isType(ANNOTATIONS, node)) {
224             node = node.getNextSibling();
225         }
226         String name = qualifiedName(node);
227         setPackageName(name);
228     }
229 
230     protected void importDef(AST importNode) {
231         // TODO handle static imports
232 
233         AST node = importNode.getFirstChild();
234 
235         String alias = null;
236         if (isType(LITERAL_as, node)) {
237             //import is like "import Foo as Bar"
238             node = node.getFirstChild();
239             AST aliasNode = node.getNextSibling();
240             alias = identifier(aliasNode);
241         }
242 
243         if (node.getNumberOfChildren()==0) {
244             // import is like  "import Foo"
245             String name = identifier(node);
246             importClass(null, name, alias);
247             return;
248         }
249 
250         AST packageNode = node.getFirstChild();
251         String packageName = qualifiedName(packageNode);
252         AST nameNode = packageNode.getNextSibling();
253         if (isType(STAR, nameNode)) {
254             // import is like "import foo.*"
255             importPackageWithStar(packageName);
256             if (alias!=null) throw new GroovyBugError(
257                     "imports like 'import foo.* as Bar' are not "+
258                     "supported and should be catched by the grammar");
259         } else {
260             // import is like "import foo.Bar"
261             String name = identifier(nameNode);
262             importClass(packageName, name, alias);
263         }
264     }
265 
266     protected void interfaceDef(AST classDef) {
267         List annotations = new ArrayList();
268         AST node = classDef.getFirstChild();
269         int modifiers = Opcodes.ACC_PUBLIC;
270         if (isType(MODIFIERS, node)) {
271             modifiers = modifiers(node, annotations, modifiers);
272             node = node.getNextSibling();
273         }
274         modifiers |= Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE;
275 
276         String name = identifier(node);
277         node = node.getNextSibling();
278         String superClass = "java.lang.Object";
279 
280         String[] interfaces = {};
281         if (isType(EXTENDS_CLAUSE, node)) {
282             interfaces = interfaces(node);
283             node = node.getNextSibling();
284         }
285 
286         addNewClassName(name);
287         String fullClassName = dot(getPackageName(), name);
288         classNode = new ClassNode(fullClassName, modifiers, superClass, interfaces, null);
289         classNode.addAnnotations(annotations);
290         configureAST(classNode, classDef);
291 
292         assertNodeType(OBJBLOCK, node);
293         objectBlock(node);
294         output.addClass(classNode);
295         classNode = null;
296     }
297 
298     protected void classDef(AST classDef) {
299         List annotations = new ArrayList();
300         AST node = classDef.getFirstChild();
301         int modifiers = Opcodes.ACC_PUBLIC;
302         if (isType(MODIFIERS, node)) {
303             modifiers = modifiers(node, annotations, modifiers);
304             node = node.getNextSibling();
305         }
306 
307         String name = identifier(node);
308         node = node.getNextSibling();
309 
310         String superClass = null;
311         if (isType(EXTENDS_CLAUSE, node)) {
312             superClass = typeName(node);
313             node = node.getNextSibling();
314         }
315         if (superClass == null) {
316             superClass = "java.lang.Object";
317         }
318 
319         String[] interfaces = {};
320         if (isType(IMPLEMENTS_CLAUSE, node)) {
321             interfaces = interfaces(node);
322             node = node.getNextSibling();
323         }
324 
325         // TODO read mixins
326         MixinNode[] mixins = {};
327 
328         addNewClassName(name);
329         String fullClassName = dot(getPackageName(), name);
330         classNode = new ClassNode(fullClassName, modifiers, superClass, interfaces, mixins);
331         classNode.addAnnotations(annotations);
332         configureAST(classNode, classDef);
333 
334         assertNodeType(OBJBLOCK, node);
335         objectBlock(node);
336         output.addClass(classNode);
337         classNode = null;
338     }
339 
340     protected void objectBlock(AST objectBlock) {
341         for (AST node = objectBlock.getFirstChild(); node != null; node = node.getNextSibling()) {
342             int type = node.getType();
343             switch (type) {
344                 case OBJBLOCK:
345                     objectBlock(node);
346                     break;
347 
348                 case METHOD_DEF:
349                     methodDef(node);
350                     break;
351 
352                 case CTOR_IDENT:
353                     constructorDef(node);
354                     break;
355 
356                 case VARIABLE_DEF:
357                     fieldDef(node);
358                     break;
359 
360                 default:
361                     unknownAST(node);
362             }
363         }
364     }
365 
366     protected void methodDef(AST methodDef) {
367         List annotations = new ArrayList();
368         AST node = methodDef.getFirstChild();
369         int modifiers = Opcodes.ACC_PUBLIC;
370         if (isType(MODIFIERS, node)) {
371             modifiers = modifiers(node, annotations, modifiers);
372             node = node.getNextSibling();
373         }
374 
375         if (classNode!=null && (classNode.getModifiers() & Opcodes.ACC_INTERFACE) >0) {
376             modifiers |= Opcodes.ACC_ABSTRACT;
377         }
378 
379         String returnType = null;
380 
381         if (isType(TYPE, node)) {
382             returnType = typeName(node);
383             node = node.getNextSibling();
384         }
385 
386         String name = identifier(node);
387         if (classNode != null) {
388             if (classNode.getNameWithoutPackage().equals(name)) {
389                 throw new ASTRuntimeException(methodDef, "Invalid constructor format. Try remove the 'def' expression?");
390             }
391         }
392         node = node.getNextSibling();
393 
394         assertNodeType(PARAMETERS, node);
395         Parameter[] parameters = parameters(node);
396         node = node.getNextSibling();
397 
398         Statement code = null;
399         if ((modifiers & Opcodes.ACC_ABSTRACT) == 0) {
400             if (node==null) {
401                 throw new ASTRuntimeException(methodDef, "You defined a method without body. Try adding a body, or declare it abstract.");
402             }
403             assertNodeType(SLIST, node);
404             code = statementList(node);
405         }
406 
407         MethodNode methodNode = new MethodNode(name, modifiers, returnType, parameters, code);
408         methodNode.addAnnotations(annotations);
409         configureAST(methodNode, methodDef);
410         if (classNode != null) {
411             classNode.addMethod(methodNode);
412         }
413         else {
414             output.addMethod(methodNode);
415         }
416     }
417 
418     protected void constructorDef(AST constructorDef) {
419         List annotations = new ArrayList();
420         AST node = constructorDef.getFirstChild();
421         int modifiers = Opcodes.ACC_PUBLIC;
422         if (isType(MODIFIERS, node)) {
423             modifiers = modifiers(node, annotations, modifiers);
424             node = node.getNextSibling();
425         }
426 
427         assertNodeType(PARAMETERS, node);
428         Parameter[] parameters = parameters(node);
429         node = node.getNextSibling();
430 
431         assertNodeType(SLIST, node);
432         Statement code = statementList(node);
433 
434         ConstructorNode constructorNode = classNode.addConstructor(modifiers, parameters, code);
435         constructorNode.addAnnotations(annotations);
436         configureAST(constructorNode, constructorDef);
437     }
438 
439     protected void fieldDef(AST fieldDef) {
440         List annotations = new ArrayList();
441         AST node = fieldDef.getFirstChild();
442 
443         int modifiers = 0;
444         if (isType(MODIFIERS, node)) {
445             modifiers = modifiers(node, annotations, modifiers);
446             node = node.getNextSibling();
447         }
448 
449         String type = null;
450         if (isType(TYPE, node)) {
451             type = typeName(node);
452             node = node.getNextSibling();
453         }
454 
455         String name = identifier(node);
456         node = node.getNextSibling();
457 
458         Expression initialValue = null;
459         if (node != null) {
460             assertNodeType(ASSIGN, node);
461             initialValue = expression(node);
462         }
463 
464 
465         FieldNode fieldNode = new FieldNode(name, modifiers, type, classNode, initialValue);
466         fieldNode.addAnnotations(annotations);
467         configureAST(fieldNode, fieldDef);
468 
469         // lets check for a property annotation first
470         if (fieldNode.getAnnotations("Property") != null) {
471             // lets set the modifiers on the field
472             int fieldModifiers = 0;
473             int flags = Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT | Opcodes.ACC_VOLATILE | Opcodes.ACC_FINAL;
474 
475             // lets pass along any other modifiers we need
476             fieldModifiers |= (modifiers & flags);
477             fieldNode.setModifiers(fieldModifiers);
478 
479             if (!hasVisibility(modifiers)) {
480                 modifiers |= Opcodes.ACC_PUBLIC;
481             }
482             PropertyNode propertyNode = new PropertyNode(fieldNode, modifiers, null, null);
483             configureAST(propertyNode, fieldDef);
484             classNode.addProperty(propertyNode);
485         }
486         else {
487             /*
488             if (!hasVisibility(modifiers)) {
489                 modifiers |= Opcodes.ACC_PRIVATE;
490                 fieldNode.setModifiers(modifiers);
491             }
492             */
493             fieldNode.setModifiers(modifiers);
494 
495             classNode.addField(fieldNode);
496         }
497     }
498 
499     protected String[] interfaces(AST node) {
500         List interfaceList = new ArrayList();
501         for (AST implementNode = node.getFirstChild(); implementNode != null; implementNode = implementNode.getNextSibling()) {
502             interfaceList.add(resolveTypeName(qualifiedName(implementNode)));
503         }
504         String[] interfaces = {};
505         if (!interfaceList.isEmpty()) {
506             interfaces = new String[interfaceList.size()];
507             interfaceList.toArray(interfaces);
508 
509         }
510         return interfaces;
511     }
512 
513     protected Parameter[] parameters(AST parametersNode) {
514         AST node = parametersNode.getFirstChild();
515         if (node == null) {
516             return Parameter.EMPTY_ARRAY;
517         }
518         else {
519             List parameters = new ArrayList();
520             do {
521                 parameters.add(parameter(node));
522                 node = node.getNextSibling();
523             }
524             while (node != null);
525             Parameter[] answer = new Parameter[parameters.size()];
526             parameters.toArray(answer);
527             return answer;
528         }
529     }
530 
531     protected Parameter parameter(AST paramNode) {
532         List annotations = new ArrayList();
533         AST node = paramNode.getFirstChild();
534 
535         int modifiers = 0;
536         if (isType(MODIFIERS, node)) {
537             modifiers = modifiers(node, annotations, modifiers);
538             node = node.getNextSibling();
539         }
540 
541         String type = null;
542         if (isType(TYPE, node)) {
543             type = typeName(node);
544             node = node.getNextSibling();
545         }
546 
547         String name = identifier(node);
548         node = node.getNextSibling();
549         VariableExpression leftExpression = new VariableExpression(name, type);
550         configureAST(leftExpression, paramNode);
551 
552         Parameter parameter = null;
553         if (node != null) {
554             assertNodeType(ASSIGN, node);
555             Expression rightExpression = expression(node.getFirstChild());
556             parameter = new Parameter(type, name, rightExpression);
557         }
558         else
559             parameter = new Parameter(type, name);
560 
561         // TODO
562         //configureAST(parameter,paramNode);
563         //parameter.addAnnotations(annotations);
564         return parameter;
565     }
566 
567     protected int modifiers(AST modifierNode, List annotations, int defaultModifiers) {
568         assertNodeType(MODIFIERS, modifierNode);
569 
570         boolean access = false;
571         int answer = 0;
572 
573         for (AST node = modifierNode.getFirstChild(); node != null; node = node.getNextSibling()) {
574             int type = node.getType();
575             switch (type) {
576                 // annotations
577                 case ANNOTATION:
578                     annotations.add(annotation(node));
579                     break;
580 
581 
582                     // core access scope modifiers
583                 case LITERAL_private:
584                     answer = setModifierBit(node, answer, Opcodes.ACC_PRIVATE);
585                     access = setAccessTrue(node, access);
586                     break;
587 
588                 case LITERAL_protected:
589                     answer = setModifierBit(node, answer, Opcodes.ACC_PROTECTED);
590                     access = setAccessTrue(node, access);
591                     break;
592 
593                 case LITERAL_public:
594                     answer = setModifierBit(node, answer, Opcodes.ACC_PUBLIC);
595                     access = setAccessTrue(node, access);
596                     break;
597 
598                     // other modifiers
599                 case ABSTRACT:
600                     answer = setModifierBit(node, answer, Opcodes.ACC_ABSTRACT);
601                     break;
602 
603                 case FINAL:
604                     answer = setModifierBit(node, answer, Opcodes.ACC_FINAL);
605                     break;
606 
607                 case LITERAL_native:
608                     answer = setModifierBit(node, answer, Opcodes.ACC_NATIVE);
609                     break;
610 
611                 case LITERAL_static:
612                     answer = setModifierBit(node, answer, Opcodes.ACC_STATIC);
613                     break;
614 
615                 case STRICTFP:
616                     answer = setModifierBit(node, answer, Opcodes.ACC_STRICT);
617                     break;
618 
619                 case LITERAL_synchronized:
620                     answer = setModifierBit(node, answer, Opcodes.ACC_SYNCHRONIZED);
621                     break;
622 
623                 case LITERAL_transient:
624                     answer = setModifierBit(node, answer, Opcodes.ACC_TRANSIENT);
625                     break;
626 
627                 case LITERAL_volatile:
628                     answer = setModifierBit(node, answer, Opcodes.ACC_VOLATILE);
629                     break;
630 
631                 default:
632                     unknownAST(node);
633             }
634         }
635         if (!access) {
636             answer |= defaultModifiers;
637         }
638         return answer;
639     }
640 
641     protected boolean setAccessTrue(AST node, boolean access) {
642         if (!access) {
643             return true;
644         }
645         else {
646             throw new ASTRuntimeException(node, "Cannot specify modifier: " + node.getText() + " when access scope has already been defined");
647         }
648     }
649 
650     protected int setModifierBit(AST node, int answer, int bit) {
651         if ((answer & bit) != 0) {
652             throw new ASTRuntimeException(node, "Cannot repeat modifier: " + node.getText());
653         }
654         return answer | bit;
655     }
656 
657     protected AnnotationNode annotation(AST annotationNode) {
658         AST node = annotationNode.getFirstChild();
659         String name = identifier(node);
660         AnnotationNode annotatedNode = new AnnotationNode(name);
661         configureAST(annotatedNode, node);
662         while (true) {
663             node = node.getNextSibling();
664             if (isType(ANNOTATION_MEMBER_VALUE_PAIR, node)) {
665                 AST memberNode = node.getFirstChild();
666                 String param = identifier(memberNode);
667                 Expression expression = expression(memberNode.getNextSibling());
668                 annotatedNode.addMember(param, expression);
669             }
670             else {
671                 break;
672             }
673         }
674         return annotatedNode;
675     }
676 
677 
678 
679     // Statements
680     //-------------------------------------------------------------------------
681 
682     protected Statement statement(AST node) {
683         Statement statement = null;
684         int type = node.getType();
685         switch (type) {
686             case SLIST:
687             case LITERAL_finally:
688                 statement = statementList(node);
689                 break;
690 
691             case METHOD_CALL:
692                 statement = methodCall(node);
693                 break;
694 
695             case VARIABLE_DEF:
696                 statement = variableDef(node);
697                 break;
698 
699 
700             case LABELED_STAT:
701                 statement = labelledStatement(node);
702                 break;
703 
704             case LITERAL_assert:
705                 statement = assertStatement(node);
706                 break;
707 
708             case LITERAL_break:
709                 statement = breakStatement(node);
710                 break;
711 
712             case LITERAL_continue:
713                 statement = continueStatement(node);
714                 break;
715 
716             case LITERAL_if:
717                 statement = ifStatement(node);
718                 break;
719 
720             case LITERAL_for:
721                 statement = forStatement(node);
722                 break;
723 
724             case LITERAL_return:
725                 statement = returnStatement(node);
726                 break;
727 
728             case LITERAL_synchronized:
729                 statement = synchronizedStatement(node);
730                 break;
731 
732             case LITERAL_switch:
733                 statement = switchStatement(node);
734                 break;
735 
736             case LITERAL_with:
737                 statement = withStatement(node);
738                 break;
739 
740             case LITERAL_try:
741                 statement = tryStatement(node);
742                 break;
743 
744             case LITERAL_throw:
745                 statement = throwStatement(node);
746                 break;
747 
748             case LITERAL_while:
749                 statement = whileStatement(node);
750                 break;
751 
752             default:
753                 statement = new ExpressionStatement(expression(node));
754         }
755         if (statement != null) {
756             configureAST(statement, node);
757         }
758         return statement;
759     }
760 
761     protected Statement statementList(AST code) {
762         return statementListNoChild(code.getFirstChild());
763     }
764 
765     protected Statement statementListNoChild(AST node) {
766         BlockStatement block = new BlockStatement();
767         // no need to configureAST(block,node); as node is probably null
768         for (; node != null; node = node.getNextSibling()) {
769             block.addStatement(statement(node));
770         }
771         return block;
772     }
773 
774     protected Statement assertStatement(AST assertNode) {
775         AST node = assertNode.getFirstChild();
776         BooleanExpression booleanExpression = booleanExpression(node);
777         Expression messageExpression = null;
778 
779         node = node.getNextSibling();
780         if (node != null) {
781             messageExpression = expression(node);
782         }
783         else {
784             messageExpression = ConstantExpression.NULL;
785         }
786         AssertStatement assertStatement = new AssertStatement(booleanExpression, messageExpression);
787         configureAST(assertStatement, assertNode);
788         return assertStatement;
789     }
790 
791     protected Statement breakStatement(AST node) {
792         BreakStatement breakStatement = new BreakStatement(label(node));
793         configureAST(breakStatement, node);
794         return breakStatement;
795     }
796 
797     protected Statement continueStatement(AST node) {
798         ContinueStatement continueStatement = new ContinueStatement(label(node));
799         configureAST(continueStatement, node);
800         return continueStatement;
801     }
802 
803     protected Statement forStatement(AST forNode) {
804         AST inNode = forNode.getFirstChild();
805         AST variableNode = inNode.getFirstChild();
806         AST collectionNode = variableNode.getNextSibling();
807 
808         Type type = OBJECT_TYPE;
809         if (isType(VARIABLE_DEF, variableNode)) {
810             AST typeNode = variableNode.getFirstChild();
811             assertNodeType(TYPE, typeNode);
812 
813             type = type(typeNode);
814             variableNode = typeNode.getNextSibling();
815         }
816         String variable = identifier(variableNode);
817 
818         Expression collectionExpression = expression(collectionNode);
819         Statement block = statement(inNode.getNextSibling());
820 
821         ForStatement forStatement = new ForStatement(variable, type, collectionExpression, block);
822         configureAST(forStatement, forNode);
823         return forStatement;
824     }
825 
826     protected Statement ifStatement(AST ifNode) {
827         AST node = ifNode.getFirstChild();
828         assertNodeType(EXPR, node);
829         BooleanExpression booleanExpression = booleanExpression(node);
830 
831         node = node.getNextSibling();
832         Statement ifBlock = statement(node);
833 
834         Statement elseBlock = EmptyStatement.INSTANCE;
835         node = node.getNextSibling();
836         if (node != null) {
837             elseBlock = statement(node);
838         }
839         IfStatement ifStatement = new IfStatement(booleanExpression, ifBlock, elseBlock);
840         configureAST(ifStatement, ifNode);
841         return ifStatement;
842     }
843 
844     protected Statement labelledStatement(AST labelNode) {
845         AST node = labelNode.getFirstChild();
846         String label = identifier(node);
847         Statement statement = statement(node.getNextSibling());
848         statement.setStatementLabel(label);
849         return statement;
850     }
851 
852     protected Statement methodCall(AST code) {
853         Expression expression = methodCallExpression(code);
854         ExpressionStatement expressionStatement = new ExpressionStatement(expression);
855         configureAST(expressionStatement, code);
856         return expressionStatement;
857     }
858 
859     protected Statement variableDef(AST variableDef) {
860         AST node = variableDef.getFirstChild();
861         String type = null;
862         if (isType(MODIFIERS, node)) {
863             node = node.getNextSibling();
864         }
865         if (isType(TYPE, node)) {
866             type = typeName(node);
867             node = node.getNextSibling();
868         }
869 
870         String name = identifier(node);
871         node = node.getNextSibling();
872 
873         VariableExpression leftExpression = new VariableExpression(name, type);
874         configureAST(leftExpression, variableDef);
875 
876         Expression rightExpression = ConstantExpression.NULL;
877         if (node != null) {
878             assertNodeType(ASSIGN, node);
879 
880             rightExpression = expression(node.getFirstChild());
881         }
882         Token token = makeToken(Types.ASSIGN, variableDef);
883 
884         // TODO should we have a variable declaration statement?
885         DeclarationExpression expression = new DeclarationExpression(leftExpression, token, rightExpression);
886         configureAST(expression, variableDef);
887         ExpressionStatement expressionStatement = new ExpressionStatement(expression);
888         configureAST(expressionStatement, variableDef);
889         return expressionStatement;
890     }
891 
892     protected Statement returnStatement(AST node) {
893         AST exprNode = node.getFirstChild();
894 
895         // This will pick up incorrect sibling node if 'node' is a plain 'return'
896 		//
897 		//if (exprNode == null) {
898         //    exprNode = node.getNextSibling();
899         //}
900         if (exprNode != null) {
901             Expression expression = expression(exprNode);
902             if (expression instanceof ConstantExpression) {
903                 ConstantExpression constantExpr = (ConstantExpression) expression;
904                 if (constantExpr.getValue() == null) {
905                     return ReturnStatement.RETURN_NULL_OR_VOID;
906                 }
907             }
908             ReturnStatement returnStatement = new ReturnStatement(expression);
909             configureAST(returnStatement, node);
910             return returnStatement;
911         }
912         else {
913             return ReturnStatement.RETURN_NULL_OR_VOID;
914         }
915     }
916 
917     protected Statement switchStatement(AST switchNode) {
918         AST node = switchNode.getFirstChild();
919         Expression expression = expression(node);
920         Statement defaultStatement = EmptyStatement.INSTANCE;
921 
922         List list = new ArrayList();
923         for (node = node.getNextSibling(); isType(CASE_GROUP, node); node = node.getNextSibling()) {
924             AST child = node.getFirstChild();
925             if (isType(LITERAL_case, child)) {
926                 list.add(caseStatement(child));
927             }
928             else {
929                 defaultStatement = statement(child.getNextSibling());
930             }
931         }
932         if (node != null) {
933             unknownAST(node);
934         }
935         SwitchStatement switchStatement = new SwitchStatement(expression, list, defaultStatement);
936         configureAST(switchStatement, switchNode);
937         return switchStatement;
938     }
939 
940     protected CaseStatement caseStatement(AST node) {
941         Expression expression = expression(node.getFirstChild());
942         AST nextSibling = node.getNextSibling();
943         Statement statement = EmptyStatement.INSTANCE;
944         if (!isType(LITERAL_default, nextSibling)) {
945              statement = statement(nextSibling);
946         }
947         CaseStatement answer = new CaseStatement(expression, statement);
948         configureAST(answer, node);
949         return answer;
950     }
951 
952     protected Statement synchronizedStatement(AST syncNode) {
953         AST node = syncNode.getFirstChild();
954         Expression expression = expression(node);
955         Statement code = statement(node.getNextSibling());
956         SynchronizedStatement synchronizedStatement = new SynchronizedStatement(expression, code);
957         configureAST(synchronizedStatement, syncNode);
958         return synchronizedStatement;
959     }
960 
961     protected Statement throwStatement(AST node) {
962         AST expressionNode = node.getFirstChild();
963         if (expressionNode == null) {
964             expressionNode = node.getNextSibling();
965         }
966         if (expressionNode == null) {
967             throw new ASTRuntimeException(node, "No expression available");
968         }
969         ThrowStatement throwStatement = new ThrowStatement(expression(expressionNode));
970         configureAST(throwStatement, node);
971         return throwStatement;
972     }
973 
974     protected Statement tryStatement(AST tryStatementNode) {
975         AST tryNode = tryStatementNode.getFirstChild();
976         Statement tryStatement = statement(tryNode);
977         Statement finallyStatement = EmptyStatement.INSTANCE;
978         AST node = tryNode.getNextSibling();
979 
980         // lets do the catch nodes
981         List catches = new ArrayList();
982         for (; node != null && isType(LITERAL_catch, node); node = node.getNextSibling()) {
983             catches.add(catchStatement(node));
984         }
985 
986         if (isType(LITERAL_finally, node)) {
987             finallyStatement = statement(node);
988             node = node.getNextSibling();
989         }
990 
991         TryCatchStatement tryCatchStatement = new TryCatchStatement(tryStatement, finallyStatement);
992         configureAST(tryCatchStatement, tryStatementNode);
993         for (Iterator iter = catches.iterator(); iter.hasNext();) {
994             CatchStatement statement = (CatchStatement) iter.next();
995             tryCatchStatement.addCatch(statement);
996         }
997         return tryCatchStatement;
998     }
999 
1000     protected CatchStatement catchStatement(AST catchNode) {
1001         AST node = catchNode.getFirstChild();
1002         Parameter parameter = parameter(node);
1003         String exceptionType = parameter.getType();
1004         String variable = parameter.getName();
1005         node = node.getNextSibling();
1006         Statement code = statement(node);
1007         CatchStatement answer = new CatchStatement(exceptionType, variable, code);
1008         configureAST(answer, catchNode);
1009         return answer;
1010     }
1011 
1012     protected Statement whileStatement(AST whileNode) {
1013         AST node = whileNode.getFirstChild();
1014         assertNodeType(EXPR, node);
1015         BooleanExpression booleanExpression = booleanExpression(node);
1016 
1017         node = node.getNextSibling();
1018         Statement block = statement(node);
1019         WhileStatement whileStatement = new WhileStatement(booleanExpression, block);
1020         configureAST(whileStatement, whileNode);
1021         return whileStatement;
1022     }
1023 
1024     protected Statement withStatement(AST node) {
1025         notImplementedYet(node);
1026         return null; /*** TODO */
1027     }
1028 
1029 
1030 
1031     // Expressions
1032     //-------------------------------------------------------------------------
1033 
1034     protected Expression expression(AST node) {
1035         Expression expression = expressionSwitch(node);
1036         configureAST(expression, node);
1037         return expression;
1038     }
1039 
1040     protected Expression expressionSwitch(AST node) {
1041         int type = node.getType();
1042         switch (type) {
1043             case EXPR:
1044                 return expression(node.getFirstChild());
1045 
1046             case ELIST:
1047                 return expressionList(node);
1048 
1049             case SLIST:
1050                 return blockExpression(node);
1051 
1052             case CLOSED_BLOCK:
1053                 return closureExpression(node);
1054 
1055             case SUPER_CTOR_CALL:
1056                 return superMethodCallExpression(node);
1057 
1058             case METHOD_CALL:
1059                 return methodCallExpression(node);
1060 
1061             case LITERAL_new:
1062                 return constructorCallExpression(node.getFirstChild());
1063 
1064             case CTOR_CALL:
1065                 return constructorCallExpression(node);
1066 
1067             case QUESTION:
1068                 return ternaryExpression(node);
1069 
1070             case OPTIONAL_DOT:
1071             case SPREAD_DOT:
1072             case DOT:
1073                 return dotExpression(node);
1074 
1075             case IDENT:
1076             case LITERAL_boolean:
1077             case LITERAL_byte:
1078             case LITERAL_char:
1079             case LITERAL_double:
1080             case LITERAL_float:
1081             case LITERAL_int:
1082             case LITERAL_long:
1083             case LITERAL_short:
1084                 return variableExpression(node);
1085 
1086             case LIST_CONSTRUCTOR:
1087                 return listExpression(node);
1088 
1089             case MAP_CONSTRUCTOR:
1090                 return mapExpression(node);
1091 
1092             case LABELED_ARG:
1093                 return mapEntryExpression(node);
1094 
1095             case SPREAD_ARG:
1096                 return spreadExpression(node);
1097 
1098             case SPREAD_MAP_ARG:
1099                 return spreadMapExpression(node);
1100 
1101             // commented out of groovy.g due to non determinisms
1102             //case MEMBER_POINTER_DEFAULT:
1103             //    return defaultMethodPointerExpression(node);
1104 
1105             case MEMBER_POINTER:
1106                 return methodPointerExpression(node);
1107 
1108             case INDEX_OP:
1109                 return indexExpression(node);
1110 
1111             case LITERAL_instanceof:
1112                 return instanceofExpression(node);
1113 
1114             case LITERAL_as:
1115                 return asExpression(node);
1116 
1117             case TYPECAST:
1118                 return castExpression(node);
1119 
1120                 // literals
1121 
1122             case LITERAL_true:
1123                 return ConstantExpression.TRUE;
1124 
1125             case LITERAL_false:
1126                 return ConstantExpression.FALSE;
1127 
1128             case LITERAL_null:
1129                 return ConstantExpression.NULL;
1130 
1131             case STRING_LITERAL:
1132                 ConstantExpression constantExpression = new ConstantExpression(node.getText());
1133                 configureAST(constantExpression, node);
1134                 return constantExpression;
1135 
1136             case STRING_CONSTRUCTOR:
1137                 return gstring(node);
1138 
1139             case NUM_DOUBLE:
1140             case NUM_FLOAT:
1141             case NUM_BIG_DECIMAL:
1142                 return decimalExpression(node);
1143 
1144             case NUM_BIG_INT:
1145             case NUM_INT:
1146             case NUM_LONG:
1147                 return integerExpression(node);
1148 
1149             case LITERAL_this:
1150                 return VariableExpression.THIS_EXPRESSION;
1151 
1152             case LITERAL_super:
1153                 return VariableExpression.SUPER_EXPRESSION;
1154 
1155 
1156                 // Unary expressions
1157             case LNOT:
1158                 NotExpression notExpression = new NotExpression(expression(node.getFirstChild()));
1159                 configureAST(notExpression, node);
1160                 return notExpression;
1161 
1162             case UNARY_MINUS:
1163                 return negateExpression(node);
1164 
1165             case BNOT:
1166                 BitwiseNegExpression bitwiseNegExpression = new BitwiseNegExpression(expression(node.getFirstChild()));
1167                 configureAST(bitwiseNegExpression, node);
1168                 return bitwiseNegExpression;
1169 
1170             case UNARY_PLUS:
1171                 return expression(node.getFirstChild());
1172 
1173 
1174                 // Prefix expressions
1175             case INC:
1176                 return prefixExpression(node, Types.PLUS_PLUS);
1177 
1178             case DEC:
1179                 return prefixExpression(node, Types.MINUS_MINUS);
1180 
1181                 // Postfix expressions
1182             case POST_INC:
1183                 return postfixExpression(node, Types.PLUS_PLUS);
1184 
1185             case POST_DEC:
1186                 return postfixExpression(node, Types.MINUS_MINUS);
1187 
1188 
1189                 // Binary expressions
1190 
1191             case ASSIGN:
1192                 return binaryExpression(Types.ASSIGN, node);
1193 
1194             case EQUAL:
1195                 return binaryExpression(Types.COMPARE_EQUAL, node);
1196 
1197             case NOT_EQUAL:
1198                 return binaryExpression(Types.COMPARE_NOT_EQUAL, node);
1199 
1200             case COMPARE_TO:
1201                 return binaryExpression(Types.COMPARE_TO, node);
1202 
1203             case LE:
1204                 return binaryExpression(Types.COMPARE_LESS_THAN_EQUAL, node);
1205 
1206             case LT:
1207                 return binaryExpression(Types.COMPARE_LESS_THAN, node);
1208 
1209             case GT:
1210                 return binaryExpression(Types.COMPARE_GREATER_THAN, node);
1211 
1212             case GE:
1213                 return binaryExpression(Types.COMPARE_GREATER_THAN_EQUAL, node);
1214 
1215                 /***
1216                  * TODO treble equal?
1217                  return binaryExpression(Types.COMPARE_IDENTICAL, node);
1218 
1219                  case ???:
1220                  return binaryExpression(Types.LOGICAL_AND_EQUAL, node);
1221 
1222                  case ???:
1223                  return binaryExpression(Types.LOGICAL_OR_EQUAL, node);
1224 
1225                  */
1226 
1227             case LAND:
1228                 return binaryExpression(Types.LOGICAL_AND, node);
1229 
1230             case LOR:
1231                 return binaryExpression(Types.LOGICAL_OR, node);
1232 
1233             case BAND:
1234                 return binaryExpression(Types.BITWISE_AND, node);
1235 
1236             case BAND_ASSIGN:
1237                 return binaryExpression(Types.BITWISE_AND_EQUAL, node);
1238 
1239             case BOR:
1240                 return binaryExpression(Types.BITWISE_OR, node);
1241 
1242             case BOR_ASSIGN:
1243                 return binaryExpression(Types.BITWISE_OR_EQUAL, node);
1244 
1245             case BXOR:
1246                 return binaryExpression(Types.BITWISE_XOR, node);
1247 
1248             case BXOR_ASSIGN:
1249                 return binaryExpression(Types.BITWISE_XOR_EQUAL, node);
1250 
1251 
1252             case PLUS:
1253                 return binaryExpression(Types.PLUS, node);
1254 
1255             case PLUS_ASSIGN:
1256                 return binaryExpression(Types.PLUS_EQUAL, node);
1257 
1258 
1259             case MINUS:
1260                 return binaryExpression(Types.MINUS, node);
1261 
1262             case MINUS_ASSIGN:
1263                 return binaryExpression(Types.MINUS_EQUAL, node);
1264 
1265 
1266             case STAR:
1267                 return binaryExpression(Types.MULTIPLY, node);
1268 
1269             case STAR_ASSIGN:
1270                 return binaryExpression(Types.MULTIPLY_EQUAL, node);
1271 
1272 
1273             case STAR_STAR:
1274                 return binaryExpression(Types.POWER, node);
1275 
1276             case STAR_STAR_ASSIGN:
1277                 return binaryExpression(Types.POWER_EQUAL, node);
1278 
1279 
1280             case DIV:
1281                 return binaryExpression(Types.DIVIDE, node);
1282 
1283             case DIV_ASSIGN:
1284                 return binaryExpression(Types.DIVIDE_EQUAL, node);
1285 
1286 
1287             case MOD:
1288                 return binaryExpression(Types.MOD, node);
1289 
1290             case MOD_ASSIGN:
1291                 return binaryExpression(Types.MOD_EQUAL, node);
1292 
1293             case SL:
1294                 return binaryExpression(Types.LEFT_SHIFT, node);
1295 
1296             case SL_ASSIGN:
1297                 return binaryExpression(Types.LEFT_SHIFT_EQUAL, node);
1298 
1299             case SR:
1300                 return binaryExpression(Types.RIGHT_SHIFT, node);
1301 
1302             case SR_ASSIGN:
1303                 return binaryExpression(Types.RIGHT_SHIFT_EQUAL, node);
1304 
1305             case BSR:
1306                 return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED, node);
1307 
1308             case BSR_ASSIGN:
1309                 return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED_EQUAL, node);
1310 
1311                 // Regex
1312             case REGEX_FIND:
1313                 return binaryExpression(Types.FIND_REGEX, node);
1314 
1315             case REGEX_MATCH:
1316                 return binaryExpression(Types.MATCH_REGEX, node);
1317 
1318 
1319                 // Ranges
1320             case RANGE_INCLUSIVE:
1321                 return rangeExpression(node, true);
1322 
1323             case RANGE_EXCLUSIVE:
1324                 return rangeExpression(node, false);
1325 
1326             default:
1327                 unknownAST(node);
1328         }
1329         return null;
1330     }
1331 
1332     protected Expression ternaryExpression(AST ternaryNode) {
1333         AST node = ternaryNode.getFirstChild();
1334         BooleanExpression booleanExpression = booleanExpression(node);
1335         node = node.getNextSibling();
1336         Expression left = expression(node);
1337         Expression right = expression(node.getNextSibling());
1338         TernaryExpression ternaryExpression = new TernaryExpression(booleanExpression, left, right);
1339         configureAST(ternaryExpression, ternaryNode);
1340         return ternaryExpression;
1341     }
1342 
1343     protected Expression variableExpression(AST node) {
1344         String text = node.getText();
1345 
1346         // TODO we might wanna only try to resolve the name if we are
1347         // on the left hand side of an expression or before a dot?
1348         String newText = resolveTypeName(text, false);
1349         if (newText == null) {
1350             VariableExpression variableExpression = new VariableExpression(text);
1351             configureAST(variableExpression, node);
1352             return variableExpression;
1353         }
1354         else {
1355             ClassExpression classExpression = new ClassExpression(newText);
1356             configureAST(classExpression, node);
1357             return classExpression;
1358         }
1359     }
1360 
1361     protected Expression rangeExpression(AST rangeNode, boolean inclusive) {
1362         AST node = rangeNode.getFirstChild();
1363         Expression left = expression(node);
1364         Expression right = expression(node.getNextSibling());
1365         RangeExpression rangeExpression = new RangeExpression(left, right, inclusive);
1366         configureAST(rangeExpression, rangeNode);
1367         return rangeExpression;
1368     }
1369 
1370     protected Expression spreadExpression(AST node) {
1371         AST exprNode = node.getFirstChild();
1372         AST listNode = exprNode.getFirstChild();
1373         Expression right = expression(listNode);
1374         SpreadExpression spreadExpression = new SpreadExpression(right);
1375         configureAST(spreadExpression, node);
1376         return spreadExpression;
1377     }
1378 
1379     protected Expression spreadMapExpression(AST node) {
1380         AST exprNode = node.getFirstChild();
1381         Expression expr = expression(exprNode);
1382         SpreadMapExpression spreadMapExpression = new SpreadMapExpression(expr);
1383         configureAST(spreadMapExpression, node);
1384         return spreadMapExpression;
1385     }
1386 
1387     protected Expression methodPointerExpression(AST node) {
1388         AST exprNode = node.getFirstChild();
1389         String methodName = identifier(exprNode.getNextSibling());
1390         Expression expression = expression(exprNode);
1391         MethodPointerExpression methodPointerExpression = new MethodPointerExpression(expression, methodName);
1392         configureAST(methodPointerExpression, node);
1393         return methodPointerExpression;
1394     }
1395 
1396 /*  commented out due to groovy.g non-determinisms
1397   protected Expression defaultMethodPointerExpression(AST node) {
1398         AST exprNode = node.getFirstChild();
1399         String methodName = exprNode.toString();
1400         MethodPointerExpression methodPointerExpression = new MethodPointerExpression(null, methodName);
1401         configureAST(methodPointerExpression, node);
1402         return methodPointerExpression;
1403     }
1404 */
1405 
1406     protected Expression listExpression(AST listNode) {
1407         List expressions = new ArrayList();
1408         AST elist = listNode.getFirstChild();
1409         assertNodeType(ELIST, elist);
1410 
1411         for (AST node = elist.getFirstChild(); node != null; node = node.getNextSibling()) {
1412             // check for stray labeled arguments:
1413             switch (node.getType()) {
1414             case LABELED_ARG:       assertNodeType(COMMA, node);       break;  // helpful error?
1415             case SPREAD_MAP_ARG:    assertNodeType(SPREAD_ARG, node);  break;  // helpful error
1416             }
1417             expressions.add(expression(node));
1418         }
1419         ListExpression listExpression = new ListExpression(expressions);
1420         configureAST(listExpression, listNode);
1421         return listExpression;
1422     }
1423 
1424     /***
1425      * Typically only used for map constructors I think?
1426      */
1427     protected Expression mapExpression(AST mapNode) {
1428         List expressions = new ArrayList();
1429         AST elist = mapNode.getFirstChild();
1430         if (elist != null) {  // totally empty in the case of [:]
1431             assertNodeType(ELIST, elist);
1432             for (AST node = elist.getFirstChild(); node != null; node = node.getNextSibling()) {
1433                 switch (node.getType()) {
1434                 case LABELED_ARG:
1435                 case SPREAD_MAP_ARG:
1436                     break;  // legal cases
1437                 case SPREAD_ARG:
1438                     assertNodeType(SPREAD_MAP_ARG, node);  break;  // helpful error
1439                 default:
1440                     assertNodeType(LABELED_ARG, node);  break;  // helpful error
1441                 }
1442                 expressions.add(mapEntryExpression(node));
1443             }
1444         }
1445         MapExpression mapExpression = new MapExpression(expressions);
1446         configureAST(mapExpression, mapNode);
1447         return mapExpression;
1448     }
1449 
1450     protected MapEntryExpression mapEntryExpression(AST node) {
1451         if (node.getType() == SPREAD_MAP_ARG) {
1452             AST rightNode = node.getFirstChild();
1453             Expression keyExpression = spreadMapExpression(node);
1454             Expression rightExpression = expression(rightNode);
1455             MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, rightExpression);
1456             configureAST(mapEntryExpression, node);
1457             return mapEntryExpression;
1458         }
1459         else {
1460             AST keyNode = node.getFirstChild();
1461             Expression keyExpression = expression(keyNode);
1462             AST valueNode = keyNode.getNextSibling();
1463             Expression valueExpression = expression(valueNode);
1464             MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, valueExpression);
1465             configureAST(mapEntryExpression, node);
1466             return mapEntryExpression;
1467         }
1468     }
1469 
1470 
1471     protected Expression instanceofExpression(AST node) {
1472         AST leftNode = node.getFirstChild();
1473         Expression leftExpression = expression(leftNode);
1474 
1475         AST rightNode = leftNode.getNextSibling();
1476         String typeName = resolvedName(rightNode);
1477         assertTypeNotNull(typeName, rightNode);
1478 
1479         Expression rightExpression = new ClassExpression(typeName);
1480         configureAST(rightExpression, rightNode);
1481         BinaryExpression binaryExpression = new BinaryExpression(leftExpression, makeToken(Types.KEYWORD_INSTANCEOF, node), rightExpression);
1482         configureAST(binaryExpression, node);
1483         return binaryExpression;
1484     }
1485 
1486     protected void assertTypeNotNull(String typeName, AST rightNode) {
1487         if (typeName == null) {
1488             throw new ASTRuntimeException(rightNode, "No type available for: " + qualifiedName(rightNode));
1489         }
1490     }
1491 
1492     protected Expression asExpression(AST node) {
1493         AST leftNode = node.getFirstChild();
1494         Expression leftExpression = expression(leftNode);
1495 
1496         AST rightNode = leftNode.getNextSibling();
1497         String typeName = resolvedName(rightNode);
1498 
1499         return CastExpression.asExpression(typeName, leftExpression);
1500     }
1501 
1502     protected Expression castExpression(AST castNode) {
1503         AST node = castNode.getFirstChild();
1504         String typeName = resolvedName(node);
1505         assertTypeNotNull(typeName, node);
1506 
1507         AST expressionNode = node.getNextSibling();
1508         Expression expression = expression(expressionNode);
1509 
1510         CastExpression castExpression = new CastExpression(typeName, expression);
1511         configureAST(castExpression, castNode);
1512         return castExpression;
1513     }
1514 
1515 
1516     protected Expression indexExpression(AST indexNode) {
1517         AST leftNode = indexNode.getFirstChild();
1518         Expression leftExpression = expression(leftNode);
1519 
1520         AST rightNode = leftNode.getNextSibling();
1521         Expression rightExpression = expression(rightNode);
1522 
1523         BinaryExpression binaryExpression = new BinaryExpression(leftExpression, makeToken(Types.LEFT_SQUARE_BRACKET, indexNode), rightExpression);
1524         configureAST(binaryExpression, indexNode);
1525         return binaryExpression;
1526     }
1527 
1528     protected Expression binaryExpression(int type, AST node) {
1529         Token token = makeToken(type, node);
1530 
1531         AST leftNode = node.getFirstChild();
1532         Expression leftExpression = expression(leftNode);
1533 
1534         AST rightNode = leftNode.getNextSibling();
1535         if (rightNode == null) {
1536             return leftExpression;
1537         }
1538 
1539         if (Types.ofType(type, Types.ASSIGNMENT_OPERATOR)) {
1540             if (leftExpression instanceof VariableExpression || leftExpression instanceof PropertyExpression
1541                                                              || leftExpression instanceof FieldExpression
1542                                                              || leftExpression instanceof DeclarationExpression) {
1543                 // Do nothing.
1544             }
1545             else if (leftExpression instanceof ConstantExpression) {
1546                 throw new ASTRuntimeException(node, "\n[" + ((ConstantExpression) leftExpression).getValue() + "] is a constant expression, but it should be a variable expression");
1547             }
1548             else if (leftExpression instanceof BinaryExpression) {
1549                 Expression leftexp = ((BinaryExpression) leftExpression).getLeftExpression();
1550                 int lefttype = ((BinaryExpression) leftExpression).getOperation().getType();
1551                 if (!Types.ofType(lefttype, Types.ASSIGNMENT_OPERATOR) && lefttype != Types.LEFT_SQUARE_BRACKET) {
1552                     throw new ASTRuntimeException(node, "\n" + ((BinaryExpression) leftExpression).getText() + " is a binary expression, but it should be a variable expression");
1553                 }
1554             }
1555             else if (leftExpression instanceof GStringExpression) {
1556                 throw new ASTRuntimeException(node, "\n\"" + ((GStringExpression) leftExpression).getText() + "\" is a GString expression, but it should be a variable expression");
1557             }
1558             else if (leftExpression instanceof MethodCallExpression) {
1559                 throw new ASTRuntimeException(node, "\n\"" + ((MethodCallExpression) leftExpression).getText() + "\" is a method call expression, but it should be a variable expression");
1560             }
1561             else if (leftExpression instanceof MapExpression) {
1562                 throw new ASTRuntimeException(node, "\n'" + ((MapExpression) leftExpression).getText() + "' is a map expression, but it should be a variable expression");
1563             }
1564             else {
1565                 throw new ASTRuntimeException(node, "\n" + leftExpression.getClass() + ", with its value '" + leftExpression.getText() + "', is a bad expression as the LSH of an assignment operator");
1566             }
1567         }
1568         /*if (rightNode == null) {
1569             throw new NullPointerException("No rightNode associated with binary expression");
1570         }*/
1571         Expression rightExpression = expression(rightNode);
1572         BinaryExpression binaryExpression = new BinaryExpression(leftExpression, token, rightExpression);
1573         configureAST(binaryExpression, node);
1574         return binaryExpression;
1575     }
1576 
1577     protected Expression prefixExpression(AST node, int token) {
1578         Expression expression = expression(node.getFirstChild());
1579         PrefixExpression prefixExpression = new PrefixExpression(makeToken(token, node), expression);
1580         configureAST(prefixExpression, node);
1581         return prefixExpression;
1582     }
1583 
1584     protected Expression postfixExpression(AST node, int token) {
1585         Expression expression = expression(node.getFirstChild());
1586         PostfixExpression postfixExpression = new PostfixExpression(expression, makeToken(token, node));
1587         configureAST(postfixExpression, node);
1588         return postfixExpression;
1589     }
1590 
1591     protected BooleanExpression booleanExpression(AST node) {
1592         BooleanExpression booleanExpression = new BooleanExpression(expression(node));
1593         configureAST(booleanExpression, node);
1594         return booleanExpression;
1595     }
1596 
1597     protected Expression dotExpression(AST node) {
1598         // lets decide if this is a propery invocation or a method call
1599         AST leftNode = node.getFirstChild();
1600         if (leftNode != null) {
1601             AST identifierNode = leftNode.getNextSibling();
1602             if (identifierNode != null) {
1603                 Expression leftExpression = expression(leftNode);
1604                 if (isType(SELECT_SLOT, identifierNode)) {
1605                     String field = identifier(identifierNode.getFirstChild());
1606                     AttributeExpression attributeExpression = new AttributeExpression(leftExpression, field, node.getType() != DOT);
1607                     if (node.getType() == SPREAD_DOT) {
1608                         attributeExpression.setSpreadSafe(true);
1609                     }
1610                     configureAST(attributeExpression, node);
1611                     return attributeExpression;
1612                 }
1613                 String property = identifier(identifierNode);
1614                 PropertyExpression propertyExpression = new PropertyExpression(leftExpression, property, node.getType() != DOT);
1615                 if (node.getType() == SPREAD_DOT) {
1616                     propertyExpression.setSpreadSafe(true);
1617                 }
1618                 configureAST(propertyExpression, node);
1619                 return propertyExpression;
1620             }
1621         }
1622         return methodCallExpression(node);
1623     }
1624 
1625     protected Expression superMethodCallExpression(AST methodCallNode) {
1626         AST node = methodCallNode.getFirstChild();
1627 
1628         String name = "super";
1629         Expression objectExpression = VariableExpression.SUPER_EXPRESSION;
1630 
1631         Expression arguments = arguments(node);
1632         MethodCallExpression expression = new MethodCallExpression(objectExpression, name, arguments);
1633         configureAST(expression, methodCallNode);
1634         return expression;
1635     }
1636 
1637 
1638     protected Expression methodCallExpression(AST methodCallNode) {
1639         AST node = methodCallNode.getFirstChild();
1640         /* // Bad idea, since foo(1)(2) is valid Groovy for foo(1).call(2).
1641         if (isType(METHOD_CALL, node)) {
1642             // sometimes method calls get wrapped in method calls for some wierd reason
1643             return methodCallExpression(node);
1644         }
1645         */
1646 
1647         Expression objectExpression;
1648         AST selector;
1649         AST elist = node.getNextSibling();
1650         boolean safe = isType(OPTIONAL_DOT, node);
1651         boolean spreadSafe = isType(SPREAD_DOT, node);
1652         if (isType(DOT, node) || safe || spreadSafe) {
1653             AST objectNode = node.getFirstChild();
1654             objectExpression = expression(objectNode);
1655             selector = objectNode.getNextSibling();
1656         } else if (isType(IDENT, node)) {
1657             objectExpression = VariableExpression.THIS_EXPRESSION;
1658             selector = node;
1659 
1660         } else {
1661             objectExpression = expression(node);
1662             selector = null;  // implicit "call"
1663         }
1664 
1665         String name = null;
1666         if (selector == null) {
1667             name = "call";
1668         }  else if (isType(LITERAL_super, selector)) {
1669             name = "super";
1670             if (objectExpression == VariableExpression.THIS_EXPRESSION) {
1671                 objectExpression = VariableExpression.SUPER_EXPRESSION;
1672             }
1673         }
1674         else if (isPrimitiveTypeLiteral(selector)) {
1675             throw new ASTRuntimeException(selector, "Primitive type literal: " + selector.getText()
1676                     + " cannot be used as a method name");
1677         }
1678         else {
1679             name = identifier(selector);
1680         }
1681 
1682         Expression arguments = arguments(elist);
1683         MethodCallExpression expression = new MethodCallExpression(objectExpression, name, arguments);
1684         boolean implicitThis = (objectExpression == VariableExpression.THIS_EXPRESSION);
1685         implicitThis = implicitThis || (objectExpression == VariableExpression.SUPER_EXPRESSION);
1686         expression.setSafe(safe);
1687         expression.setSpreadSafe(spreadSafe);
1688         expression.setImplicitThis(implicitThis);
1689         configureAST(expression, methodCallNode);
1690         return expression;
1691     }
1692 
1693     protected Expression constructorCallExpression(AST node) {
1694         AST constructorCallNode = node;
1695         String name = resolvedName(constructorCallNode);
1696 
1697         if (isType(CTOR_CALL, node) || isType(LITERAL_new, node)) {
1698             node = node.getFirstChild();
1699         }
1700 
1701         AST elist = node.getNextSibling();
1702 
1703         if (elist == null && isType(ELIST, node)) {
1704             elist = node;
1705             if ("(".equals(name.toString())) {
1706                 name = classNode.getName();
1707             }
1708         }
1709 
1710         if (isType(ARRAY_DECLARATOR, elist)) {
1711             AST expressionNode = elist.getFirstChild();
1712             if (expressionNode == null) {
1713                 throw new ASTRuntimeException(elist, "No expression for the array constructor call");
1714             }
1715             Expression size = expression(expressionNode);
1716             ArrayExpression arrayExpression = new ArrayExpression(name, size);
1717             configureAST(arrayExpression, constructorCallNode);
1718             return arrayExpression;
1719         }
1720         Expression arguments = arguments(elist);
1721         ConstructorCallExpression expression = new ConstructorCallExpression(name, arguments);
1722         configureAST(expression, constructorCallNode);
1723         return expression;
1724     }
1725 
1726     protected Expression arguments(AST elist) {
1727         List expressionList = new ArrayList();
1728         // FIXME: all labeled arguments should follow any unlabeled arguments
1729         boolean namedArguments = false;
1730         for (AST node = elist; node != null; node = node.getNextSibling()) {
1731             if (isType(ELIST, node)) {
1732                 for (AST child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
1733                     namedArguments |= addArgumentExpression(child, expressionList);
1734                 }
1735             }
1736             else {
1737                 namedArguments |= addArgumentExpression(node, expressionList);
1738             }
1739         }
1740         if (namedArguments) {
1741             if (!expressionList.isEmpty()) {
1742                 // lets remove any non-MapEntryExpression instances
1743                 // such as if the last expression is a ClosureExpression
1744                 // so lets wrap the named method calls in a Map expression
1745                 List argumentList = new ArrayList();
1746                 for (Iterator iter = expressionList.iterator(); iter.hasNext();) {
1747                     Expression expression = (Expression) iter.next();
1748                     if (!(expression instanceof MapEntryExpression)) {
1749                         argumentList.add(expression);
1750                     }
1751                 }
1752                 if (!argumentList.isEmpty()) {
1753                     expressionList.removeAll(argumentList);
1754                     MapExpression mapExpression = new MapExpression(expressionList);
1755                     configureAST(mapExpression, elist);
1756                     argumentList.add(0, mapExpression);
1757                     ArgumentListExpression argumentListExpression = new ArgumentListExpression(argumentList);
1758                     configureAST(argumentListExpression, elist);
1759                     return argumentListExpression;
1760                 }
1761             }
1762             NamedArgumentListExpression namedArgumentListExpression = new NamedArgumentListExpression(expressionList);
1763             configureAST(namedArgumentListExpression, elist);
1764             return namedArgumentListExpression;
1765         }
1766         else {
1767             ArgumentListExpression argumentListExpression = new ArgumentListExpression(expressionList);
1768             configureAST(argumentListExpression, elist);
1769             return argumentListExpression;
1770         }
1771     }
1772 
1773     protected boolean addArgumentExpression(AST node, List expressionList) {
1774         if (node.getType() == SPREAD_MAP_ARG) {
1775             AST rightNode = node.getFirstChild();
1776             Expression keyExpression = spreadMapExpression(node);
1777             Expression rightExpression = expression(rightNode);
1778             MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, rightExpression);
1779             expressionList.add(mapEntryExpression);
1780             return true;
1781         }
1782         else {
1783             Expression expression = expression(node);
1784             expressionList.add(expression);
1785             return expression instanceof MapEntryExpression;
1786         }
1787     }
1788 
1789     protected Expression expressionList(AST node) {
1790         List expressionList = new ArrayList();
1791         for (AST child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
1792             expressionList.add(expression(child));
1793         }
1794         if (expressionList.size() == 1) {
1795             return (Expression) expressionList.get(0);
1796         }
1797         else {
1798             ListExpression listExpression = new ListExpression(expressionList);
1799             configureAST(listExpression, node);
1800             return listExpression;
1801         }
1802     }
1803 
1804     protected ClosureExpression closureExpression(AST node) {
1805         AST paramNode = node.getFirstChild();
1806         Parameter[] parameters = Parameter.EMPTY_ARRAY;
1807         AST codeNode = paramNode;
1808         if (isType(PARAMETERS, paramNode) || isType(IMPLICIT_PARAMETERS, paramNode)) {
1809             parameters = parameters(paramNode);
1810             codeNode = paramNode.getNextSibling();
1811         }
1812         Statement code = statementListNoChild(codeNode);
1813         ClosureExpression closureExpression = new ClosureExpression(parameters, code);
1814         configureAST(closureExpression, node);
1815         return closureExpression;
1816     }
1817 
1818     protected Expression blockExpression(AST node) {
1819         AST codeNode = node.getFirstChild();
1820         if (codeNode == null)  return ConstantExpression.NULL;
1821         if (codeNode.getType() == EXPR && codeNode.getNextSibling() == null) {
1822             // Simplify common case of {expr} to expr.
1823             return expression(codeNode);
1824         }
1825         Parameter[] parameters = Parameter.EMPTY_ARRAY;
1826         Statement code = statementListNoChild(codeNode);
1827         ClosureExpression closureExpression = new ClosureExpression(parameters, code);
1828         configureAST(closureExpression, node);
1829         // Call it immediately.
1830         String callName = "call";
1831         Expression noArguments = new ArgumentListExpression();
1832         MethodCallExpression call = new MethodCallExpression(closureExpression, callName, noArguments);
1833         configureAST(call, node);
1834         return call;
1835     }
1836 
1837     protected Expression negateExpression(AST negateExpr) {
1838         AST node = negateExpr.getFirstChild();
1839 
1840         // if we are a number literal then lets just parse it
1841         // as the negation operator on MIN_INT causes rounding to a long
1842         String text = node.getText();
1843         switch (node.getType()) {
1844             case NUM_DOUBLE:
1845             case NUM_FLOAT:
1846             case NUM_BIG_DECIMAL:
1847                 ConstantExpression constantExpression = new ConstantExpression(Numbers.parseDecimal("-" + text));
1848                 configureAST(constantExpression, negateExpr);
1849                 return constantExpression;
1850 
1851             case NUM_BIG_INT:
1852             case NUM_INT:
1853             case NUM_LONG:
1854                 ConstantExpression constantLongExpression = new ConstantExpression(Numbers.parseInteger("-" + text));
1855                 configureAST(constantLongExpression, negateExpr);
1856                 return constantLongExpression;
1857 
1858             default:
1859                 NegationExpression negationExpression = new NegationExpression(expression(node));
1860                 configureAST(negationExpression, negateExpr);
1861                 return negationExpression;
1862         }
1863     }
1864 
1865     protected ConstantExpression decimalExpression(AST node) {
1866         String text = node.getText();
1867         ConstantExpression constantExpression = new ConstantExpression(Numbers.parseDecimal(text));
1868         configureAST(constantExpression, node);
1869         return constantExpression;
1870     }
1871 
1872     protected ConstantExpression integerExpression(AST node) {
1873         String text = node.getText();
1874         ConstantExpression constantExpression = new ConstantExpression(Numbers.parseInteger(text));
1875         configureAST(constantExpression, node);
1876         return constantExpression;
1877     }
1878 
1879     protected Expression gstring(AST gstringNode) {
1880         List strings = new ArrayList();
1881         List values = new ArrayList();
1882 
1883         StringBuffer buffer = new StringBuffer();
1884 
1885         boolean isPrevString = false;
1886 
1887         for (AST node = gstringNode.getFirstChild(); node != null; node = node.getNextSibling()) {
1888             int type = node.getType();
1889             String text = null;
1890             switch (type) {
1891 
1892                 case STRING_LITERAL:
1893                     if (isPrevString)  assertNodeType(IDENT, node);  // parser bug
1894                     isPrevString = true;
1895                     text = node.getText();
1896                     ConstantExpression constantExpression = new ConstantExpression(text);
1897                     configureAST(constantExpression, node);
1898                     strings.add(constantExpression);
1899                     buffer.append(text);
1900                     break;
1901 
1902                 default:
1903                     {
1904                         if (!isPrevString)  assertNodeType(IDENT, node);  // parser bug
1905                         isPrevString = false;
1906                         Expression expression = expression(node);
1907                         values.add(expression);
1908                         buffer.append("$");
1909                         buffer.append(expression.getText());
1910                     }
1911                     break;
1912             }
1913         }
1914         GStringExpression gStringExpression = new GStringExpression(buffer.toString(), strings, values);
1915         configureAST(gStringExpression, gstringNode);
1916         return gStringExpression;
1917     }
1918 
1919     protected Type type(AST typeNode) {
1920         // TODO intern types?
1921         // TODO configureAST(...)
1922         return new Type(resolvedName(typeNode.getFirstChild()));
1923     }
1924 
1925     protected String qualifiedName(AST qualifiedNameNode) {
1926         if (isType(IDENT, qualifiedNameNode)) {
1927             return qualifiedNameNode.getText();
1928         }
1929         if (isType(DOT, qualifiedNameNode)) {
1930             AST node = qualifiedNameNode.getFirstChild();
1931             StringBuffer buffer = new StringBuffer();
1932             boolean first = true;
1933 
1934             for (; node != null; node = node.getNextSibling()) {
1935                 if (first) {
1936                     first = false;
1937                 }
1938                 else {
1939                     buffer.append(".");
1940                 }
1941                 buffer.append(qualifiedName(node));
1942             }
1943             return buffer.toString();
1944         }
1945         else {
1946             return qualifiedNameNode.getText();
1947         }
1948     }
1949 
1950     protected String typeName(AST typeNode) {
1951         String answer = null;
1952         AST node = typeNode.getFirstChild();
1953         if (node != null) {
1954             if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
1955                 return resolveTypeName(qualifiedName(node.getFirstChild())) + "[]";
1956             }
1957             answer = resolveTypeName(qualifiedName(node));
1958             node = node.getNextSibling();
1959             if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
1960                 return answer + "[]";
1961             }
1962         }
1963         return answer;
1964     }
1965 
1966     /***
1967      * Performs a name resolution to see if the given name is a type from imports,
1968      * aliases or newly created classes
1969      */
1970     protected String resolveTypeName(String name, boolean safe) {
1971         if (name == null) {
1972             return null;
1973         }
1974         return resolveNewClassOrName(name, safe);
1975     }
1976 
1977     /***
1978      * Performs a name resolution to see if the given name is a type from imports,
1979      * aliases or newly created classes
1980      */
1981     protected String resolveTypeName(String name) {
1982         return resolveTypeName(name, true);
1983     }
1984 
1985     /***
1986      * Extracts an identifier from the Antlr AST and then performs a name resolution
1987      * to see if the given name is a type from imports, aliases or newly created classes
1988      */
1989     protected String resolvedName(AST node) {
1990         if (isType(TYPE, node)) {
1991             node = node.getFirstChild();
1992         }
1993         String answer = null;
1994         if (isType(DOT, node) || isType(OPTIONAL_DOT, node)) {
1995             answer = qualifiedName(node);
1996         }
1997         else if (isPrimitiveTypeLiteral(node)) {
1998             answer = node.getText();
1999         }
2000         else if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
2001             AST child = node.getFirstChild();
2002             String text = resolvedName(child);
2003             // TODO sometimes we have ARRAY_DECLARATOR->typeName
2004             // and sometimes we have typeName->ARRAY_DECLARATOR
2005             // so here's a little fudge while we be more consistent in the Antlr
2006             if (text.endsWith("[]")) {
2007                 return text;
2008             }
2009             return text + "[]";
2010         }
2011         else {
2012             String identifier = node.getText();
2013             answer = resolveTypeName(identifier);
2014 
2015         }
2016         AST nextSibling = node.getNextSibling();
2017         if (isType(INDEX_OP, nextSibling) || isType(ARRAY_DECLARATOR, node)) {
2018             return answer + "[]";
2019         }
2020         else {
2021             return answer;
2022         }
2023     }
2024 
2025     protected boolean isPrimitiveTypeLiteral(AST node) {
2026         int type = node.getType();
2027         switch (type) {
2028             case LITERAL_boolean:
2029             case LITERAL_byte:
2030             case LITERAL_char:
2031             case LITERAL_double:
2032             case LITERAL_float:
2033             case LITERAL_int:
2034             case LITERAL_long:
2035             case LITERAL_short:
2036                 return true;
2037 
2038             default:
2039                 return false;
2040         }
2041     }
2042 
2043     /***
2044      * Extracts an identifier from the Antlr AST
2045      */
2046     protected String identifier(AST node) {
2047         assertNodeType(IDENT, node);
2048         return node.getText();
2049     }
2050 
2051     protected String label(AST labelNode) {
2052         AST node = labelNode.getFirstChild();
2053         if (node == null) {
2054             return null;
2055         }
2056         return identifier(node);
2057     }
2058 
2059 
2060 
2061     // Helper methods
2062     //-------------------------------------------------------------------------
2063 
2064 
2065     /***
2066      * Returns true if the modifiers flags contain a visibility modifier
2067      */
2068     protected boolean hasVisibility(int modifiers) {
2069         return (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) != 0;
2070     }
2071 
2072     protected void configureAST(ASTNode node, AST ast) {
2073         if (ast==null) throw new ASTRuntimeException(ast, "PARSER BUG: Tried to configure "+node.getClass().getName()+" with null Node");
2074         node.setColumnNumber(ast.getColumn());
2075         node.setLineNumber(ast.getLine());
2076 
2077         // TODO we could one day store the Antlr AST on the Groovy AST
2078         // node.setCSTNode(ast);
2079     }
2080 
2081     protected static Token makeToken(int typeCode, AST node) {
2082         return Token.newSymbol(typeCode, node.getLine(), node.getColumn());
2083     }
2084 
2085     protected String getFirstChildText(AST node) {
2086         AST child = node.getFirstChild();
2087         return child != null ? child.getText() : null;
2088     }
2089 
2090 
2091     protected boolean isType(int typeCode, AST node) {
2092         return node != null && node.getType() == typeCode;
2093     }
2094 
2095     private String getTokenName(int token) {
2096         if (tokenNames==null) return ""+token;
2097         return tokenNames[token];
2098     }
2099     
2100     private String getTokenName(AST node) {
2101         if (node==null) return "null";
2102         return getTokenName(node.getType());
2103     }
2104 
2105     protected void assertNodeType(int type, AST node) {
2106         if (node == null) {
2107             throw new ASTRuntimeException(node, "No child node available in AST when expecting type: " + getTokenName(type));
2108         }
2109         if (node.getType() != type) {            
2110             throw new ASTRuntimeException(node, "Unexpected node type: " + getTokenName(node) + " found when expecting type: " + getTokenName(type));
2111         }
2112     }
2113 
2114     protected void notImplementedYet(AST node) {
2115         throw new ASTRuntimeException(node, "AST node not implemented yet for type: " + getTokenName(node));
2116     }
2117 
2118     protected void unknownAST(AST node) {
2119         throw new ASTRuntimeException(node, "Unknown type: " + getTokenName(node));
2120     }
2121 
2122     protected void dumpTree(AST ast) {
2123         for (AST node = ast.getFirstChild(); node != null; node = node.getNextSibling()) {
2124             dump(node);
2125         }
2126     }
2127 
2128     protected void dump(AST node) {
2129         System.out.println("Type: " + getTokenName(node) + " text: " + node.getText());
2130     }
2131 }