View Javadoc

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