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