001    /**
002     *
003     * Copyright 2004 James Strachan
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     * http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     *
017     **/
018    package org.codehaus.groovy.antlr;
019    
020    import antlr.RecognitionException;
021    import antlr.TokenStreamException;
022    import antlr.TokenStreamRecognitionException;
023    import antlr.collections.AST;
024    import com.thoughtworks.xstream.XStream;
025    
026    import org.codehaus.groovy.GroovyBugError;
027    import org.codehaus.groovy.antlr.parser.GroovyLexer;
028    import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
029    import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
030    import org.codehaus.groovy.ast.*;
031    import org.codehaus.groovy.ast.expr.*;
032    import org.codehaus.groovy.ast.stmt.*;
033    import org.codehaus.groovy.control.CompilationFailedException;
034    import org.codehaus.groovy.control.ParserPlugin;
035    import org.codehaus.groovy.control.SourceUnit;
036    import org.codehaus.groovy.syntax.Numbers;
037    import org.codehaus.groovy.syntax.Reduction;
038    import org.codehaus.groovy.syntax.SyntaxException;
039    import org.codehaus.groovy.syntax.Token;
040    import org.codehaus.groovy.syntax.Types;
041    import org.codehaus.groovy.syntax.ASTHelper;
042    import org.codehaus.groovy.syntax.ParserException;
043    import org.objectweb.asm.Opcodes;
044    
045    import java.io.FileWriter;
046    import java.io.Reader;
047    import java.util.ArrayList;
048    import java.util.Iterator;
049    import java.util.List;
050    
051    /**
052     * A parser plugin which adapts the JSR Antlr Parser to the Groovy runtime
053     *
054     * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
055     * @version $Revision: 1.46 $
056     */
057    public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, GroovyTokenTypes {
058        private static final Type OBJECT_TYPE = new Type("java.lang.Object", true);
059    
060        private AST ast;
061        private ClassNode classNode;
062        private String[] tokenNames;
063    
064    
065        public Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
066            ast = null;
067    
068            setController(sourceUnit);
069    
070            SourceBuffer sourceBuffer = new SourceBuffer();
071            UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(reader,sourceBuffer);
072            GroovyLexer lexer = new GroovyLexer(unicodeReader);
073            unicodeReader.setLexer(lexer);
074            GroovyRecognizer parser = GroovyRecognizer.make(lexer);
075            parser.setSourceBuffer(sourceBuffer);
076            tokenNames = parser.getTokenNames();
077            parser.setFilename(sourceUnit.getName());
078    
079            // start parsing at the compilationUnit rule
080            try {
081                parser.compilationUnit();
082            }
083            catch (TokenStreamRecognitionException tsre) {
084                RecognitionException e = tsre.recog;
085                SyntaxException se = new SyntaxException(e.getMessage(),e,e.getLine(),e.getColumn());
086                se.setFatal(true);
087                sourceUnit.addError(se);
088            }
089            catch (RecognitionException e) {
090                SyntaxException se = new SyntaxException(e.getMessage(),e,e.getLine(),e.getColumn());
091                se.setFatal(true);
092                sourceUnit.addError(se);
093            }
094            catch (TokenStreamException e) {
095                sourceUnit.addException(e);
096            }
097    
098            ast = parser.getAST();
099    
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        protected 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    }