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