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