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