View Javadoc
Minimize
Table

Bug Overview

linebug prioritybugbug descriptionexisting sinceauthor
1420mediumIL_INFINITE_LOOPDiese Schleife terminiert nicht. Bitte Code überprüfen! Falls dies beabsichtigt ist und der Fehler soll ignoriert werden, dann //NOBUG verwenden. 18.06.2012-10:31Unbekannt
2541mediumIL_INFINITE_LOOPDiese Schleife terminiert nicht. Bitte Code überprüfen! Falls dies beabsichtigt ist und der Fehler soll ignoriert werden, dann //NOBUG verwenden. 18.06.2012-10:31Unbekannt
117mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
180mediumSystemPrintlnBitte keine System.(out|err).print-Ausgaben verwenden, stattdessen Logger-Klassen nutzen. Details zum Fehler...18.06.2012-10:31Unbekannt
193mediumSystemPrintlnBitte keine System.(out|err).print-Ausgaben verwenden, stattdessen Logger-Klassen nutzen. Details zum Fehler...18.06.2012-10:31Unbekannt
205mediumSystemPrintlnBitte keine System.(out|err).print-Ausgaben verwenden, stattdessen Logger-Klassen nutzen. Details zum Fehler...18.06.2012-10:31Unbekannt
220mediumSystemPrintlnBitte keine System.(out|err).print-Ausgaben verwenden, stattdessen Logger-Klassen nutzen. Details zum Fehler...18.06.2012-10:31Unbekannt
228highOBL_UNSATISFIED_OBLIGATIONÖffnet eine Methode einen Stream oder eine andere Ressource muss diese mit einem try/finally-Block geschlossen werden. Bitte Code auf eine entsprechende cleanup-Operation hin überprüfen!  Details zum Fehler...18.06.2012-10:31Unbekannt
229mediumSystemPrintlnBitte keine System.(out|err).print-Ausgaben verwenden, stattdessen Logger-Klassen nutzen. Details zum Fehler...18.06.2012-10:31Unbekannt
232mediumSystemPrintlnBitte keine System.(out|err).print-Ausgaben verwenden, stattdessen Logger-Klassen nutzen. Details zum Fehler...18.06.2012-10:31Unbekannt
323mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
565mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
1626mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
1669mediumExcessiveMethodLengthDiese Methode ist sehr lang, ein Indiz dafür das diese Methode zu viel tut, es sollten Hilfsmethoden genutzt und Copy/Paste-Code entfernt werden. Falls dies beabsichtigt ist und der Fehler soll ignoriert werden, dann //NOBUG verwenden.  Details zum Fehler...18.06.2012-10:31Unbekannt
2050mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
2260mediumEmptyIfStmtLeeres if-Statement, bei Erfüllung der Bedingung wird keine Anweisung ausgeführt, dieser Code kann entfernt werden.  Details zum Fehler...18.06.2012-10:31Unbekannt
2441mediumFIXMEDer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
2539mediumFIXMEDer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
2766mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
2767mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
2848mediumWhileLoopsMustUseBraces Es wird ein while-Statement ohne geschweifte Klammern verwendet, dies führt bei Erweiterungen oft zu Fehlern. Bitte Klammern setzen!  Details zum Fehler...18.06.2012-10:31Unbekannt
3031mediumTODODer Code ist an dieser Stelle eventuell unfertig oder fehlerhaft. Bitte überprüfen!18.06.2012-10:31Unbekannt
3091mediumSystemPrintlnBitte keine System.(out|err).print-Ausgaben verwenden, stattdessen Logger-Klassen nutzen. Details zum Fehler...18.06.2012-10:31Unbekannt

1   /*
2    * Copyright 2003-2011 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.codehaus.groovy.antlr;
17  
18  import antlr.RecognitionException;
19  import antlr.TokenStreamException;
20  import antlr.TokenStreamRecognitionException;
21  import antlr.collections.AST;
22  import com.thoughtworks.xstream.XStream;
23  import org.codehaus.groovy.GroovyBugError;
24  import org.codehaus.groovy.antlr.parser.GroovyLexer;
25  import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
26  import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
27  import org.codehaus.groovy.antlr.treewalker.*;
28  import org.codehaus.groovy.ast.*;
29  import org.codehaus.groovy.ast.expr.*;
30  import org.codehaus.groovy.ast.stmt.*;
31  import org.codehaus.groovy.control.CompilationFailedException;
32  import org.codehaus.groovy.control.ParserPlugin;
33  import org.codehaus.groovy.control.SourceUnit;
34  import org.codehaus.groovy.syntax.*;
35  import org.objectweb.asm.Opcodes;
36  
37  import java.io.FileNotFoundException;
38  import java.io.FileOutputStream;
39  import java.io.FileWriter;
40  import java.io.PrintStream;
41  import java.io.Reader;
42  import java.security.AccessController;
43  import java.security.PrivilegedAction;
44  import java.util.ArrayList;
45  import java.util.HashSet;
46  import java.util.Iterator;
47  import java.util.LinkedList;
48  import java.util.List;
49  import java.util.Set;
50  
51  /**
52   * A parser plugin which adapts the JSR Antlr Parser to the Groovy runtime
53   *
54   * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
55   */
56  public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, GroovyTokenTypes {
57  
58      private static class AnonymousInnerClassCarrier extends Expression {
59          ClassNode innerClass;
60  
61          public Expression transformExpression(ExpressionTransformer transformer) {
62              return null;
63          }
64  
65          @Override
66          public void setSourcePosition(final ASTNode node) {
67              super.setSourcePosition(node);
68              innerClass.setSourcePosition(node);
69          }
70  
71          @Override
72          public void setColumnNumber(final int columnNumber) {
73              super.setColumnNumber(columnNumber);
74              innerClass.setColumnNumber(columnNumber);
75          }
76  
77          @Override
78          public void setLineNumber(final int lineNumber) {
79              super.setLineNumber(lineNumber);
80              innerClass.setLineNumber(lineNumber);
81          }
82  
83          @Override
84          public void setLastColumnNumber(final int columnNumber) {
85              super.setLastColumnNumber(columnNumber);
86              innerClass.setLastColumnNumber(columnNumber);
87          }
88  
89          @Override
90          public void setLastLineNumber(final int lineNumber) {
91              super.setLastLineNumber(lineNumber);
92              innerClass.setLastLineNumber(lineNumber);
93          }
94      }
95  
96      protected AST ast;
97      private ClassNode classNode;
98      private String[] tokenNames;
99      private int innerClassCounter = 1;
100     private boolean enumConstantBeingDef = false;
101     private boolean forStatementBeingDef = false;
102     private boolean firstParamIsVarArg = false;
103     private boolean firstParam = false;
104 
105     public /*final*/ Reduction parseCST(final SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
106         final SourceBuffer sourceBuffer = new SourceBuffer();
107         transformCSTIntoAST(sourceUnit, reader, sourceBuffer);
108         processAST();
109         return outputAST(sourceUnit, sourceBuffer);
110     }
111 
112     protected void transformCSTIntoAST(SourceUnit sourceUnit, Reader reader, SourceBuffer sourceBuffer) throws CompilationFailedException {
113         ast = null;
114 
115         setController(sourceUnit);
116 
117 bug overview next bug           // TODO find a way to inject any GroovyLexer/GroovyRecognizer 
118 
119         UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(reader, sourceBuffer);
120         UnicodeLexerSharedInputState inputState = new UnicodeLexerSharedInputState(unicodeReader);
121         GroovyLexer lexer = new GroovyLexer(inputState);
122         unicodeReader.setLexer(lexer);
123         GroovyRecognizer parser = GroovyRecognizer.make(lexer);
124         parser.setSourceBuffer(sourceBuffer);
125         tokenNames = parser.getTokenNames();
126         parser.setFilename(sourceUnit.getName());
127 
128         // start parsing at the compilationUnit rule
129         try {
130             parser.compilationUnit();
131         }
132         catch (TokenStreamRecognitionException tsre) {
133             RecognitionException e = tsre.recog;
134             SyntaxException se = new SyntaxException(e.getMessage(), e, e.getLine(), e.getColumn());
135             se.setFatal(true);
136             sourceUnit.addError(se);
137         }
138         catch (RecognitionException e) {
139             SyntaxException se = new SyntaxException(e.getMessage(), e, e.getLine(), e.getColumn());
140             se.setFatal(true);
141             sourceUnit.addError(se);
142         }
143         catch (TokenStreamException e) {
144             sourceUnit.addException(e);
145         }
146 
147         ast = parser.getAST();
148     }
149 
150     protected void processAST() {
151         AntlrASTProcessor snippets = new AntlrASTProcessSnippets();
152         ast = snippets.process(ast);
153     }
154 
155     public Reduction outputAST(final SourceUnit sourceUnit, final SourceBuffer sourceBuffer) {
156         AccessController.doPrivileged(new PrivilegedAction() {
157             public Object run() {
158                 outputASTInVariousFormsIfNeeded(sourceUnit, sourceBuffer);
159                 return null;
160             }
161         });
162 
163         return null; //new Reduction(Tpken.EOF);
164     }
165 
166     private void outputASTInVariousFormsIfNeeded(SourceUnit sourceUnit, SourceBuffer sourceBuffer) {
167         // straight xstream output of AST
168         if ("xml".equals(System.getProperty("antlr.ast"))) {
169             saveAsXML(sourceUnit.getName(), ast);
170         }
171 
172         // 'pretty printer' output of AST
173         if ("groovy".equals(System.getProperty("antlr.ast"))) {
174             try {
175                 PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".pretty.groovy"));
176                 Visitor visitor = new SourcePrinter(out, tokenNames);
177                 AntlrASTProcessor treewalker = new SourceCodeTraversal(visitor);
178                 treewalker.process(ast);
179             } catch (FileNotFoundException e) {
180 previous bug bug overview next bug                   System.out.println("Cannot create " + sourceUnit.getName() + ".pretty.groovy");  HEALTH4J >>  :  SystemPrintln 
181             }
182         }
183 
184         // output AST in format suitable for opening in http://freemind.sourceforge.net
185         // which is a really nice way of seeing the AST, folding nodes etc
186         if ("mindmap".equals(System.getProperty("antlr.ast"))) {
187             try {
188                 PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".mm"));
189                 Visitor visitor = new MindMapPrinter(out, tokenNames);
190                 AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
191                 treewalker.process(ast);
192             } catch (FileNotFoundException e) {
193 previous bug bug overview next bug                   System.out.println("Cannot create " + sourceUnit.getName() + ".mm");  HEALTH4J >>  :  SystemPrintln 
194             }
195         }
196 
197         // include original line/col info and source code on the mindmap output
198         if ("extendedMindmap".equals(System.getProperty("antlr.ast"))) {
199             try {
200                 PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".mm"));
201                 Visitor visitor = new MindMapPrinter(out, tokenNames, sourceBuffer);
202                 AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
203                 treewalker.process(ast);
204             } catch (FileNotFoundException e) {
205 previous bug bug overview next bug                   System.out.println("Cannot create " + sourceUnit.getName() + ".mm");  HEALTH4J >>  :  SystemPrintln 
206             }
207         }
208 
209         // html output of AST
210         if ("html".equals(System.getProperty("antlr.ast"))) {
211             try {
212                 PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".html"));
213                 List<VisitorAdapter> v = new ArrayList<VisitorAdapter>();
214                 v.add(new NodeAsHTMLPrinter(out, tokenNames));
215                 v.add(new SourcePrinter(out, tokenNames));
216                 Visitor visitors = new CompositeVisitor(v);
217                 AntlrASTProcessor treewalker = new SourceCodeTraversal(visitors);
218                 treewalker.process(ast);
219             } catch (FileNotFoundException e) {
220 previous bug bug overview next bug                   System.out.println("Cannot create " + sourceUnit.getName() + ".html");  HEALTH4J >>  :  SystemPrintln 
221             }
222         }
223     }
224 
225     private void saveAsXML(String name, AST ast) {
226         XStream xstream = new XStream();
227         try {
228 previous bug bug overview next bug               xstream.toXML(ast, new FileWriter(name + ".antlr.xml"));  HEALTH4J >>  :  OBL_UNSATISFIED_OBLIGATION 
229 previous bug bug overview next bug               System.out.println("Written AST to " + name + ".antlr.xml");  HEALTH4J >>  :  SystemPrintln 
230         }
231         catch (Exception e) {
232 previous bug bug overview next bug               System.out.println("Couldn't write to " + name + ".antlr.xml");  HEALTH4J >>  :  SystemPrintln 
233             e.printStackTrace();
234         }
235     }
236 
237     public ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException {
238         setClassLoader(classLoader);
239         makeModule();
240         try {
241             convertGroovy(ast);
242             if (output.getStatementBlock().isEmpty() && output.getMethods().isEmpty() && output.getClasses().isEmpty()) {
243                 output.addStatement(ReturnStatement.RETURN_NULL_OR_VOID);
244             }
245 
246             // set the script source position
247 
248             ClassNode scriptClassNode = output.getScriptClassDummy();
249             if (scriptClassNode != null) {
250                 List<Statement> statements = output.getStatementBlock().getStatements();
251                 if (statements.size() > 0) {
252                     Statement firstStatement = statements.get(0);
253                     Statement lastStatement = statements.get(statements.size() - 1);
254 
255                     scriptClassNode.setSourcePosition(firstStatement);
256                     scriptClassNode.setLastColumnNumber(lastStatement.getLastColumnNumber());
257                     scriptClassNode.setLastLineNumber(lastStatement.getLastLineNumber());
258                 }
259             }
260         }
261         catch (ASTRuntimeException e) {
262             throw new ASTParserException(e.getMessage() + ". File: " + sourceUnit.getName(), e);
263         }
264         return output;
265     }
266 
267     /**
268      * Converts the Antlr AST to the Groovy AST
269      */
270     protected void convertGroovy(AST node) {
271         while (node != null) {
272             int type = node.getType();
273             switch (type) {
274                 case PACKAGE_DEF:
275                     packageDef(node);
276                     break;
277 
278                 case STATIC_IMPORT:
279                 case IMPORT:
280                     importDef(node);
281                     break;
282 
283                 case CLASS_DEF:
284                     classDef(node);
285                     break;
286 
287                 case INTERFACE_DEF:
288                     interfaceDef(node);
289                     break;
290 
291                 case METHOD_DEF:
292                     methodDef(node);
293                     break;
294 
295                 case ENUM_DEF:
296                     enumDef(node);
297                     break;
298 
299                 case ANNOTATION_DEF:
300                     annotationDef(node);
301                     break;
302 
303                 default: {
304                     Statement statement = statement(node);
305                     output.addStatement(statement);
306                 }
307             }
308             node = node.getNextSibling();
309         }
310     }
311 
312     // Top level control structures
313     //-------------------------------------------------------------------------
314 
315     protected void packageDef(AST packageDef) {
316         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
317         AST node = packageDef.getFirstChild();
318         if (isType(ANNOTATIONS, node)) {
319             processAnnotations(annotations, node);
320             node = node.getNextSibling();
321         }
322         String name = qualifiedName(node);
323 previous bug bug overview next bug           // TODO should we check package node doesn't already exist? conflict? 
324         PackageNode packageNode = setPackage(name, annotations);
325         configureAST(packageNode, packageDef);
326     }
327 
328     protected void importDef(AST importNode) {
329         boolean isStatic = importNode.getType() == STATIC_IMPORT;
330         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
331 
332         AST node = importNode.getFirstChild();
333         if (isType(ANNOTATIONS, node)) {
334             processAnnotations(annotations, node);
335             node = node.getNextSibling();
336         }
337 
338         String alias = null;
339         if (isType(LITERAL_as, node)) {
340             //import is like "import Foo as Bar"
341             node = node.getFirstChild();
342             AST aliasNode = node.getNextSibling();
343             alias = identifier(aliasNode);
344         }
345 
346         if (node.getNumberOfChildren() == 0) {
347             String name = identifier(node);
348             // import is like  "import Foo"
349             ClassNode type = ClassHelper.make(name);
350             configureAST(type, importNode);
351             addImport(type, name, alias, annotations);
352             return;
353         }
354 
355         AST packageNode = node.getFirstChild();
356         String packageName = qualifiedName(packageNode);
357         AST nameNode = packageNode.getNextSibling();
358         if (isType(STAR, nameNode)) {
359             if (isStatic) {
360                 // import is like "import static foo.Bar.*"
361                 // packageName is actually a className in this case
362                 ClassNode type = ClassHelper.make(packageName);
363                 configureAST(type, importNode);
364                 addStaticStarImport(type, packageName, annotations);
365             } else {
366                 // import is like "import foo.*"
367                 addStarImport(packageName, annotations);
368             }
369 
370             if (alias != null) throw new GroovyBugError(
371                     "imports like 'import foo.* as Bar' are not " +
372                             "supported and should be caught by the grammar");
373         } else {
374             String name = identifier(nameNode);
375             if (isStatic) {
376                 // import is like "import static foo.Bar.method"
377                 // packageName is really class name in this case
378                 ClassNode type = ClassHelper.make(packageName);
379                 configureAST(type, importNode);
380                 addStaticImport(type, name, alias, annotations);
381             } else {
382                 // import is like "import foo.Bar"
383                 ClassNode type = ClassHelper.make(packageName + "." + name);
384                 configureAST(type, importNode);
385                 addImport(type, name, alias, annotations);
386             }
387         }
388     }
389 
390     private void processAnnotations(List<AnnotationNode> annotations, AST node) {
391         AST child = node.getFirstChild();
392         while (child != null) {
393             if (isType(ANNOTATION, child))
394                 annotations.add(annotation(child));
395             child = child.getNextSibling();
396         }
397     }
398 
399     protected void annotationDef(AST classDef) {
400         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
401         AST node = classDef.getFirstChild();
402         int modifiers = Opcodes.ACC_PUBLIC;
403         if (isType(MODIFIERS, node)) {
404             modifiers = modifiers(node, annotations, modifiers);
405             checkNoInvalidModifier(classDef, "Annotation Definition", modifiers, Opcodes.ACC_SYNCHRONIZED, "synchronized");
406             node = node.getNextSibling();
407         }
408         modifiers |= Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_ANNOTATION;
409 
410         String name = identifier(node);
411         node = node.getNextSibling();
412         ClassNode superClass = ClassHelper.OBJECT_TYPE;
413 
414         GenericsType[] genericsType = null;
415         if (isType(TYPE_PARAMETERS, node)) {
416             genericsType = makeGenericsType(node);
417             node = node.getNextSibling();
418         }
419 
420         ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
421         if (isType(EXTENDS_CLAUSE, node)) {
422             interfaces = interfaces(node);
423             node = node.getNextSibling();
424         }
425 
426         boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
427         modifiers &= ~Opcodes.ACC_SYNTHETIC;
428         classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, null);
429         classNode.setSyntheticPublic(syntheticPublic);
430         classNode.addAnnotations(annotations);
431         classNode.setGenericsTypes(genericsType);
432         classNode.addInterface(ClassHelper.Annotation_TYPE);
433         configureAST(classNode, classDef);
434 
435         assertNodeType(OBJBLOCK, node);
436         objectBlock(node);
437         output.addClass(classNode);
438         classNode = null;
439     }
440 
441     protected void interfaceDef(AST classDef) {
442         int oldInnerClassCounter = innerClassCounter;
443         innerInterfaceDef(classDef);
444         classNode = null;
445         innerClassCounter = oldInnerClassCounter;
446     }
447 
448     protected void innerInterfaceDef(AST classDef) {
449         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
450         AST node = classDef.getFirstChild();
451         int modifiers = Opcodes.ACC_PUBLIC;
452         if (isType(MODIFIERS, node)) {
453             modifiers = modifiers(node, annotations, modifiers);
454             checkNoInvalidModifier(classDef, "Interface", modifiers, Opcodes.ACC_SYNCHRONIZED, "synchronized");
455             node = node.getNextSibling();
456         }
457         modifiers |= Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE;
458 
459         String name = identifier(node);
460         node = node.getNextSibling();
461         ClassNode superClass = ClassHelper.OBJECT_TYPE;
462 
463         GenericsType[] genericsType = null;
464         if (isType(TYPE_PARAMETERS, node)) {
465             genericsType = makeGenericsType(node);
466             node = node.getNextSibling();
467         }
468 
469         ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
470         if (isType(EXTENDS_CLAUSE, node)) {
471             interfaces = interfaces(node);
472             node = node.getNextSibling();
473         }
474 
475         ClassNode outerClass = classNode;
476         boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
477         modifiers &= ~Opcodes.ACC_SYNTHETIC;
478         if (classNode != null) {
479             name = classNode.getNameWithoutPackage() + "$" + name;
480             String fullName = dot(classNode.getPackageName(), name);
481             classNode = new InnerClassNode(classNode, fullName, modifiers, superClass, interfaces, null);
482         } else {
483             classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, null);
484         }
485         classNode.setSyntheticPublic(syntheticPublic);
486         classNode.addAnnotations(annotations);
487         classNode.setGenericsTypes(genericsType);
488         configureAST(classNode, classDef);
489 
490         int oldClassCount = innerClassCounter;
491 
492         assertNodeType(OBJBLOCK, node);
493         objectBlock(node);
494         output.addClass(classNode);
495 
496         classNode = outerClass;
497         innerClassCounter = oldClassCount;
498     }
499 
500     protected void classDef(AST classDef) {
501         int oldInnerClassCounter = innerClassCounter;
502         innerClassDef(classDef);
503         classNode = null;
504         innerClassCounter = oldInnerClassCounter;
505     }
506 
507     private ClassNode getClassOrScript(ClassNode node) {
508         if (node != null) return node;
509         return output.getScriptClassDummy();
510     }
511 
512     protected Expression anonymousInnerClassDef(AST node) {
513         ClassNode oldNode = classNode;
514         ClassNode outerClass = getClassOrScript(oldNode);
515         String fullName = outerClass.getName() + '$' + innerClassCounter;
516         innerClassCounter++;
517         if (enumConstantBeingDef) {
518             classNode = new EnumConstantClassNode(outerClass, fullName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
519         } else {
520             classNode = new InnerClassNode(outerClass, fullName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
521         }
522         ((InnerClassNode) classNode).setAnonymous(true);
523 
524         assertNodeType(OBJBLOCK, node);
525         objectBlock(node);
526         output.addClass(classNode);
527         AnonymousInnerClassCarrier ret = new AnonymousInnerClassCarrier();
528         ret.innerClass = classNode;
529         classNode = oldNode;
530 
531         return ret;
532     }
533 
534     protected void innerClassDef(AST classDef) {
535         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
536         AST node = classDef.getFirstChild();
537         int modifiers = Opcodes.ACC_PUBLIC;
538         if (isType(MODIFIERS, node)) {
539             modifiers = modifiers(node, annotations, modifiers);
540             checkNoInvalidModifier(classDef, "Class", modifiers, Opcodes.ACC_SYNCHRONIZED, "synchronized");
541             node = node.getNextSibling();
542         }
543 
544         String name = identifier(node);
545         node = node.getNextSibling();
546 
547         GenericsType[] genericsType = null;
548         if (isType(TYPE_PARAMETERS, node)) {
549             genericsType = makeGenericsType(node);
550             node = node.getNextSibling();
551         }
552 
553         ClassNode superClass = null;
554         if (isType(EXTENDS_CLAUSE, node)) {
555             superClass = makeTypeWithArguments(node);
556             node = node.getNextSibling();
557         }
558 
559         ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
560         if (isType(IMPLEMENTS_CLAUSE, node)) {
561             interfaces = interfaces(node);
562             node = node.getNextSibling();
563         }
564 
565 previous bug bug overview next bug           // TODO read mixins 
566         MixinNode[] mixins = {};
567         ClassNode outerClass = classNode;
568         boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
569         modifiers &= ~Opcodes.ACC_SYNTHETIC;
570         if (classNode != null) {
571             name = classNode.getNameWithoutPackage() + "$" + name;
572             String fullName = dot(classNode.getPackageName(), name);
573             classNode = new InnerClassNode(classNode, fullName, modifiers, superClass, interfaces, mixins);
574         } else {
575             classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, mixins);
576         }
577         classNode.addAnnotations(annotations);
578         classNode.setGenericsTypes(genericsType);
579         classNode.setSyntheticPublic(syntheticPublic);
580         configureAST(classNode, classDef);
581 
582         // we put the class already in output to avoid the most inner classes
583         // will be used as first class later in the loader. The first class
584         // there determines what GCL#parseClass for example will return, so we
585         // have here to ensure it won't be the inner class
586         output.addClass(classNode);
587 
588         int oldClassCount = innerClassCounter;
589 
590         assertNodeType(OBJBLOCK, node);
591         objectBlock(node);
592 
593         classNode = outerClass;
594         innerClassCounter = oldClassCount;
595     }
596 
597     protected void objectBlock(AST objectBlock) {
598         for (AST node = objectBlock.getFirstChild(); node != null; node = node.getNextSibling()) {
599             int type = node.getType();
600             switch (type) {
601                 case OBJBLOCK:
602                     objectBlock(node);
603                     break;
604 
605                 case ANNOTATION_FIELD_DEF:
606                 case METHOD_DEF:
607                     methodDef(node);
608                     break;
609 
610                 case CTOR_IDENT:
611                     constructorDef(node);
612                     break;
613 
614                 case VARIABLE_DEF:
615                     fieldDef(node);
616                     break;
617 
618                 case STATIC_INIT:
619                     staticInit(node);
620                     break;
621 
622                 case INSTANCE_INIT:
623                     objectInit(node);
624                     break;
625 
626                 case ENUM_DEF:
627                     enumDef(node);
628                     break;
629 
630                 case ENUM_CONSTANT_DEF:
631                     enumConstantDef(node);
632                     break;
633 
634                 case CLASS_DEF:
635                     innerClassDef(node);
636                     break;
637 
638                 case INTERFACE_DEF:
639                     innerInterfaceDef(node);
640                     break;
641 
642                 default:
643                     unknownAST(node);
644             }
645         }
646     }
647 
648     protected void enumDef(AST enumNode) {
649         assertNodeType(ENUM_DEF, enumNode);
650         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
651 
652         AST node = enumNode.getFirstChild();
653         int modifiers = Opcodes.ACC_PUBLIC;
654         if (isType(MODIFIERS, node)) {
655             modifiers = modifiers(node, annotations, modifiers);
656             node = node.getNextSibling();
657         }
658 
659         String name = identifier(node);
660         node = node.getNextSibling();
661 
662         ClassNode[] interfaces = interfaces(node);
663         node = node.getNextSibling();
664 
665         boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
666         modifiers &= ~Opcodes.ACC_SYNTHETIC;
667         String enumName = (classNode != null ? name : dot(getPackageName(), name));
668         ClassNode enumClass = EnumHelper.makeEnumNode(enumName, modifiers, interfaces, classNode);
669         enumClass.setSyntheticPublic(syntheticPublic);
670         ClassNode oldNode = classNode;
671         enumClass.addAnnotations(annotations);
672         classNode = enumClass;
673         assertNodeType(OBJBLOCK, node);
674         objectBlock(node);
675         classNode = oldNode;
676 
677         output.addClass(enumClass);
678     }
679 
680     protected void enumConstantDef(AST node) {
681         enumConstantBeingDef = true;
682         assertNodeType(ENUM_CONSTANT_DEF, node);
683         AST element = node.getFirstChild();
684         if (isType(ANNOTATIONS, element)) {
685             element = element.getNextSibling();
686         }
687         String identifier = identifier(element);
688         Expression init = null;
689         element = element.getNextSibling();
690 
691         if (element != null) {
692             init = expression(element);
693             ClassNode innerClass = getAnonymousInnerClassNode(init);
694 
695             if (innerClass != null) {
696                 // we have to handle an enum that defines a class for a constant
697                 // for example the constant having overwriting a method. we need 
698                 // to configure the inner class 
699                 innerClass.setSuperClass(classNode);
700                 innerClass.setModifiers(classNode.getModifiers() | Opcodes.ACC_FINAL);
701                 // we use a ClassExpression for transportation o EnumVisitor
702                 init = new ClassExpression(innerClass);
703                 // and remove the final modifier from classNode to allow the sub class
704                 classNode.setModifiers(classNode.getModifiers() & ~Opcodes.ACC_FINAL);
705             } else if (isType(ELIST, element)) {
706                 if (init instanceof ListExpression && !((ListExpression) init).isWrapped()) {
707                     ListExpression le = new ListExpression();
708                     le.addExpression(init);
709                     init = le;
710                 }
711             }
712         }
713         EnumHelper.addEnumConstant(classNode, identifier, init);
714         enumConstantBeingDef = false;
715     }
716 
717     protected void throwsList(AST node, List<ClassNode> list) {
718         String name;
719         if (isType(DOT, node)) {
720             name = qualifiedName(node);
721         } else {
722             name = identifier(node);
723         }
724         ClassNode exception = ClassHelper.make(name);
725         configureAST(exception, node);
726         list.add(exception);
727         AST next = node.getNextSibling();
728         if (next != null) throwsList(next, list);
729     }
730 
731     protected void methodDef(AST methodDef) {
732         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
733         AST node = methodDef.getFirstChild();
734 
735         GenericsType[] generics = null;
736         if (isType(TYPE_PARAMETERS, node)) {
737             generics = makeGenericsType(node);
738             node = node.getNextSibling();
739         }
740 
741         int modifiers = Opcodes.ACC_PUBLIC;
742         if (isType(MODIFIERS, node)) {
743             modifiers = modifiers(node, annotations, modifiers);
744             checkNoInvalidModifier(methodDef, "Method", modifiers, Opcodes.ACC_VOLATILE, "volatile");
745             node = node.getNextSibling();
746         }
747 
748         if (isAnInterface()) {
749             modifiers |= Opcodes.ACC_ABSTRACT;
750         }
751 
752         ClassNode returnType = null;
753         if (isType(TYPE, node)) {
754             returnType = makeTypeWithArguments(node);
755             node = node.getNextSibling();
756         }
757 
758         String name = identifier(node);
759         if (classNode != null && !classNode.isAnnotationDefinition()) {
760             if (classNode.getNameWithoutPackage().equals(name)) {
761                 if (isAnInterface()) {
762                     throw new ASTRuntimeException(methodDef, "Constructor not permitted within an interface.");
763                 }
764                 throw new ASTRuntimeException(methodDef, "Invalid constructor format. Remove '" + returnType.getName() +
765                         "' as the return type if you want a constructor, or use a different name if you want a method.");
766             }
767         }
768         node = node.getNextSibling();
769 
770         Parameter[] parameters = Parameter.EMPTY_ARRAY;
771         ClassNode[] exceptions = ClassNode.EMPTY_ARRAY;
772 
773         if (classNode == null || !classNode.isAnnotationDefinition()) {
774 
775             assertNodeType(PARAMETERS, node);
776             parameters = parameters(node);
777             if (parameters == null) parameters = Parameter.EMPTY_ARRAY;
778             node = node.getNextSibling();
779 
780             if (isType(LITERAL_throws, node)) {
781                 AST throwsNode = node.getFirstChild();
782                 List<ClassNode> exceptionList = new ArrayList<ClassNode>();
783                 throwsList(throwsNode, exceptionList);
784                 exceptions = exceptionList.toArray(exceptions);
785                 node = node.getNextSibling();
786             }
787         }
788 
789         boolean hasAnnotationDefault = false;
790         Statement code = null;
791         if ((modifiers & Opcodes.ACC_ABSTRACT) == 0) {
792             if (node == null) {
793                 throw new ASTRuntimeException(methodDef, "You defined a method without body. Try adding a body, or declare it abstract.");
794             }
795             assertNodeType(SLIST, node);
796             code = statementList(node);
797         } else if (node != null && classNode.isAnnotationDefinition()) {
798             code = statement(node);
799             hasAnnotationDefault = true;
800         } else if ((modifiers & Opcodes.ACC_ABSTRACT) > 0) {
801             if (node != null) {
802                 throw new ASTRuntimeException(methodDef, "Abstract methods do not define a body.");
803             }
804         }
805 
806         boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
807         modifiers &= ~Opcodes.ACC_SYNTHETIC;
808         MethodNode methodNode = new MethodNode(name, modifiers, returnType, parameters, exceptions, code);
809         methodNode.addAnnotations(annotations);
810         methodNode.setGenericsTypes(generics);
811         methodNode.setAnnotationDefault(hasAnnotationDefault);
812         methodNode.setSyntheticPublic(syntheticPublic);
813         configureAST(methodNode, methodDef);
814 
815         if (classNode != null) {
816             classNode.addMethod(methodNode);
817         } else {
818             output.addMethod(methodNode);
819         }
820     }
821 
822     private void checkNoInvalidModifier(AST node, String nodeType, int modifiers, int modifier, String modifierText) {
823         if ((modifiers & modifier) != 0) {
824             throw new ASTRuntimeException(node, nodeType + " has an incorrect modifier '" + modifierText + "'.");
825         }
826     }
827 
828     private boolean isAnInterface() {
829         return classNode != null && (classNode.getModifiers() & Opcodes.ACC_INTERFACE) > 0;
830     }
831 
832     protected void staticInit(AST staticInit) {
833         BlockStatement code = (BlockStatement) statementList(staticInit);
834         classNode.addStaticInitializerStatements(code.getStatements(), false);
835     }
836 
837     protected void objectInit(AST init) {
838         BlockStatement code = (BlockStatement) statementList(init);
839         classNode.addObjectInitializerStatements(code);
840     }
841 
842     protected void constructorDef(AST constructorDef) {
843         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
844         AST node = constructorDef.getFirstChild();
845         int modifiers = Opcodes.ACC_PUBLIC;
846         if (isType(MODIFIERS, node)) {
847             modifiers = modifiers(node, annotations, modifiers);
848             node = node.getNextSibling();
849         }
850 
851         assertNodeType(PARAMETERS, node);
852         Parameter[] parameters = parameters(node);
853         if (parameters == null) parameters = Parameter.EMPTY_ARRAY;
854         node = node.getNextSibling();
855 
856         ClassNode[] exceptions = ClassNode.EMPTY_ARRAY;
857         if (isType(LITERAL_throws, node)) {
858             AST throwsNode = node.getFirstChild();
859             List<ClassNode> exceptionList = new ArrayList<ClassNode>();
860             throwsList(throwsNode, exceptionList);
861             exceptions = exceptionList.toArray(exceptions);
862             node = node.getNextSibling();
863         }
864 
865         assertNodeType(SLIST, node);
866         Statement code = statementList(node);
867 
868         boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
869         modifiers &= ~Opcodes.ACC_SYNTHETIC;
870         ConstructorNode constructorNode = classNode.addConstructor(modifiers, parameters, exceptions, code);
871         constructorNode.setSyntheticPublic(syntheticPublic);
872         constructorNode.addAnnotations(annotations);
873         configureAST(constructorNode, constructorDef);
874     }
875 
876     protected void fieldDef(AST fieldDef) {
877         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
878         AST node = fieldDef.getFirstChild();
879 
880         int modifiers = 0;
881         if (isType(MODIFIERS, node)) {
882             modifiers = modifiers(node, annotations, modifiers);
883             node = node.getNextSibling();
884         }
885 
886         if (classNode.isInterface()) {
887             modifiers |= Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
888             if ((modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) == 0) {
889                 modifiers |= Opcodes.ACC_PUBLIC;
890             }
891         }
892 
893         ClassNode type = null;
894         if (isType(TYPE, node)) {
895             type = makeTypeWithArguments(node);
896             node = node.getNextSibling();
897         }
898 
899         String name = identifier(node);
900         node = node.getNextSibling();
901 
902         Expression initialValue = null;
903         if (node != null) {
904             assertNodeType(ASSIGN, node);
905             initialValue = expression(node.getFirstChild());
906         }
907 
908         if (classNode.isInterface() && initialValue == null && type != null) {
909             if (type == ClassHelper.int_TYPE) {
910                 initialValue = new ConstantExpression(0);
911             } else if (type == ClassHelper.long_TYPE) {
912                 initialValue = new ConstantExpression(0L);
913             } else if (type == ClassHelper.double_TYPE) {
914                 initialValue = new ConstantExpression(0.0);
915             } else if (type == ClassHelper.float_TYPE) {
916                 initialValue = new ConstantExpression(0.0F);
917             } else if (type == ClassHelper.boolean_TYPE) {
918                 initialValue = ConstantExpression.FALSE;
919             } else if (type == ClassHelper.short_TYPE) {
920                 initialValue = new ConstantExpression((short) 0);
921             } else if (type == ClassHelper.byte_TYPE) {
922                 initialValue = new ConstantExpression((byte) 0);
923             } else if (type == ClassHelper.char_TYPE) {
924                 initialValue = new ConstantExpression((char) 0);
925             }
926         }
927 
928 
929         FieldNode fieldNode = new FieldNode(name, modifiers, type, classNode, initialValue);
930         fieldNode.addAnnotations(annotations);
931         configureAST(fieldNode, fieldDef);
932 
933         if (!hasVisibility(modifiers)) {
934             // let's set the modifiers on the field
935             int fieldModifiers = 0;
936             int flags = Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT | Opcodes.ACC_VOLATILE | Opcodes.ACC_FINAL;
937 
938             if (!hasVisibility(modifiers)) {
939                 modifiers |= Opcodes.ACC_PUBLIC;
940                 fieldModifiers |= Opcodes.ACC_PRIVATE;
941             }
942 
943             // let's pass along any other modifiers we need
944             fieldModifiers |= (modifiers & flags);
945             fieldNode.setModifiers(fieldModifiers);
946             fieldNode.setSynthetic(true);
947 
948             // in the case that there is already a field, we would
949             // like to use that field, instead of the default field
950             // for the property
951             FieldNode storedNode = classNode.getDeclaredField(fieldNode.getName());
952             if (storedNode != null && !classNode.hasProperty(name)) {
953                 fieldNode = storedNode;
954                 // we remove it here, because addProperty will add it
955                 // again and we want to avoid it showing up multiple
956                 // times in the fields list.
957                 classNode.getFields().remove(storedNode);
958             }
959 
960             PropertyNode propertyNode = new PropertyNode(fieldNode, modifiers, null, null);
961             configureAST(propertyNode, fieldDef);
962             classNode.addProperty(propertyNode);
963         } else {
964             fieldNode.setModifiers(modifiers);
965             // if there is a property of that name, then a field of that
966             // name already exists, which means this new field here should
967             // be used instead of the field the property originally has.
968             PropertyNode pn = classNode.getProperty(name);
969             if (pn != null && pn.getField().isSynthetic()) {
970                 classNode.getFields().remove(pn.getField());
971                 pn.setField(fieldNode);
972             }
973             classNode.addField(fieldNode);
974         }
975     }
976 
977     protected ClassNode[] interfaces(AST node) {
978         List<ClassNode> interfaceList = new ArrayList<ClassNode>();
979         for (AST implementNode = node.getFirstChild(); implementNode != null; implementNode = implementNode.getNextSibling()) {
980             interfaceList.add(makeTypeWithArguments(implementNode));
981         }
982         ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
983         if (!interfaceList.isEmpty()) {
984             interfaces = new ClassNode[interfaceList.size()];
985             interfaceList.toArray(interfaces);
986         }
987         return interfaces;
988     }
989 
990     protected Parameter[] parameters(AST parametersNode) {
991         AST node = parametersNode.getFirstChild();
992         firstParam = false;
993         firstParamIsVarArg = false;
994         if (node == null) {
995             if (isType(IMPLICIT_PARAMETERS, parametersNode)) return Parameter.EMPTY_ARRAY;
996             return null;
997         } else {
998             List<Parameter> parameters = new ArrayList<Parameter>();
999             AST firstParameterNode = null;
1000             do {
1001                 firstParam = (firstParameterNode == null);
1002                 if (firstParameterNode == null) firstParameterNode = node;
1003                 parameters.add(parameter(node));
1004                 node = node.getNextSibling();
1005             }
1006             while (node != null);
1007 
1008             verifyParameters(parameters, firstParameterNode);
1009 
1010             Parameter[] answer = new Parameter[parameters.size()];
1011             parameters.toArray(answer);
1012             return answer;
1013         }
1014     }
1015 
1016     private void verifyParameters(List<Parameter> parameters, AST firstParameterNode) {
1017         if (parameters.size() <= 1) return;
1018 
1019         Parameter first = parameters.get(0);
1020         if (firstParamIsVarArg) {
1021             throw new ASTRuntimeException(firstParameterNode, "The var-arg parameter " + first.getName() + " must be the last parameter.");
1022         }
1023     }
1024 
1025     protected Parameter parameter(AST paramNode) {
1026         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
1027         boolean variableParameterDef = isType(VARIABLE_PARAMETER_DEF, paramNode);
1028         AST node = paramNode.getFirstChild();
1029 
1030         int modifiers = 0;
1031         if (isType(MODIFIERS, node)) {
1032             modifiers = modifiers(node, annotations, modifiers);
1033             node = node.getNextSibling();
1034         }
1035 
1036         ClassNode type = ClassHelper.DYNAMIC_TYPE;
1037         if (isType(TYPE, node)) {
1038             type = makeTypeWithArguments(node);
1039             if (variableParameterDef) type = type.makeArray();
1040             node = node.getNextSibling();
1041         }
1042 
1043         String name = identifier(node);
1044         node = node.getNextSibling();
1045 
1046         VariableExpression leftExpression = new VariableExpression(name, type);
1047         leftExpression.setModifiers(modifiers);
1048         configureAST(leftExpression, paramNode);
1049 
1050         Parameter parameter = null;
1051         if (node != null) {
1052             assertNodeType(ASSIGN, node);
1053             Expression rightExpression = expression(node.getFirstChild());
1054             if (isAnInterface()) {
1055                 throw new ASTRuntimeException(node, "Cannot specify default value for method parameter '" + name + " = " + rightExpression.getText() + "' inside an interface");
1056             }
1057             parameter = new Parameter(type, name, rightExpression);
1058         } else
1059             parameter = new Parameter(type, name);
1060 
1061         if (firstParam) firstParamIsVarArg = variableParameterDef;
1062 
1063         configureAST(parameter, paramNode);
1064         parameter.addAnnotations(annotations);
1065         parameter.setModifiers(modifiers);
1066         return parameter;
1067     }
1068 
1069     protected int modifiers(AST modifierNode, List<AnnotationNode> annotations, int defaultModifiers) {
1070         assertNodeType(MODIFIERS, modifierNode);
1071 
1072         boolean access = false;
1073         int answer = 0;
1074 
1075         for (AST node = modifierNode.getFirstChild(); node != null; node = node.getNextSibling()) {
1076             int type = node.getType();
1077             switch (type) {
1078                 case STATIC_IMPORT:
1079                     // ignore
1080                     break;
1081 
1082                 // annotations
1083                 case ANNOTATION:
1084                     annotations.add(annotation(node));
1085                     break;
1086 
1087                 // core access scope modifiers
1088                 case LITERAL_private:
1089                     answer = setModifierBit(node, answer, Opcodes.ACC_PRIVATE);
1090                     access = setAccessTrue(node, access);
1091                     break;
1092 
1093                 case LITERAL_protected:
1094                     answer = setModifierBit(node, answer, Opcodes.ACC_PROTECTED);
1095                     access = setAccessTrue(node, access);
1096                     break;
1097 
1098                 case LITERAL_public:
1099                     answer = setModifierBit(node, answer, Opcodes.ACC_PUBLIC);
1100                     access = setAccessTrue(node, access);
1101                     break;
1102 
1103                 // other modifiers
1104                 case ABSTRACT:
1105                     answer = setModifierBit(node, answer, Opcodes.ACC_ABSTRACT);
1106                     break;
1107 
1108                 case FINAL:
1109                     answer = setModifierBit(node, answer, Opcodes.ACC_FINAL);
1110                     break;
1111 
1112                 case LITERAL_native:
1113                     answer = setModifierBit(node, answer, Opcodes.ACC_NATIVE);
1114                     break;
1115 
1116                 case LITERAL_static:
1117                     answer = setModifierBit(node, answer, Opcodes.ACC_STATIC);
1118                     break;
1119 
1120                 case STRICTFP:
1121                     answer = setModifierBit(node, answer, Opcodes.ACC_STRICT);
1122                     break;
1123 
1124                 case LITERAL_synchronized:
1125                     answer = setModifierBit(node, answer, Opcodes.ACC_SYNCHRONIZED);
1126                     break;
1127 
1128                 case LITERAL_transient:
1129                     answer = setModifierBit(node, answer, Opcodes.ACC_TRANSIENT);
1130                     break;
1131 
1132                 case LITERAL_volatile:
1133                     answer = setModifierBit(node, answer, Opcodes.ACC_VOLATILE);
1134                     break;
1135 
1136                 default:
1137                     unknownAST(node);
1138             }
1139         }
1140         if (!access) {
1141             answer |= defaultModifiers;
1142             // ACC_SYNTHETIC isn't used here, use it as a special flag
1143             if (defaultModifiers == Opcodes.ACC_PUBLIC) answer |= Opcodes.ACC_SYNTHETIC;
1144         }
1145         return answer;
1146     }
1147 
1148     protected boolean setAccessTrue(AST node, boolean access) {
1149         if (!access) {
1150             return true;
1151         } else {
1152             throw new ASTRuntimeException(node, "Cannot specify modifier: " + node.getText() + " when access scope has already been defined");
1153         }
1154     }
1155 
1156     protected int setModifierBit(AST node, int answer, int bit) {
1157         if ((answer & bit) != 0) {
1158             throw new ASTRuntimeException(node, "Cannot repeat modifier: " + node.getText());
1159         }
1160         return answer | bit;
1161     }
1162 
1163     protected AnnotationNode annotation(AST annotationNode) {
1164         AST node = annotationNode.getFirstChild();
1165         String name = qualifiedName(node);
1166         AnnotationNode annotatedNode = new AnnotationNode(ClassHelper.make(name));
1167         configureAST(annotatedNode, annotationNode);
1168         while (true) {
1169             node = node.getNextSibling();
1170             if (isType(ANNOTATION_MEMBER_VALUE_PAIR, node)) {
1171                 AST memberNode = node.getFirstChild();
1172                 String param = identifier(memberNode);
1173                 Expression expression = expression(memberNode.getNextSibling());
1174                 if (annotatedNode.getMember(param) != null) {
1175                     throw new ASTRuntimeException(memberNode, "Annotation member '" + param + "' has already been associated with a value");
1176                 }
1177                 annotatedNode.setMember(param, expression);
1178             } else {
1179                 break;
1180             }
1181         }
1182         return annotatedNode;
1183     }
1184 
1185 
1186     // Statements
1187     //-------------------------------------------------------------------------
1188 
1189     protected Statement statement(AST node) {
1190         Statement statement = null;
1191         int type = node.getType();
1192         switch (type) {
1193             case SLIST:
1194             case LITERAL_finally:
1195                 statement = statementList(node);
1196                 break;
1197 
1198             case METHOD_CALL:
1199                 statement = methodCall(node);
1200                 break;
1201 
1202             case VARIABLE_DEF:
1203                 statement = variableDef(node);
1204                 break;
1205 
1206 
1207             case LABELED_STAT:
1208                 statement = labelledStatement(node);
1209                 break;
1210 
1211             case LITERAL_assert:
1212                 statement = assertStatement(node);
1213                 break;
1214 
1215             case LITERAL_break:
1216                 statement = breakStatement(node);
1217                 break;
1218 
1219             case LITERAL_continue:
1220                 statement = continueStatement(node);
1221                 break;
1222 
1223             case LITERAL_if:
1224                 statement = ifStatement(node);
1225                 break;
1226 
1227             case LITERAL_for:
1228                 statement = forStatement(node);
1229                 break;
1230 
1231             case LITERAL_return:
1232                 statement = returnStatement(node);
1233                 break;
1234 
1235             case LITERAL_synchronized:
1236                 statement = synchronizedStatement(node);
1237                 break;
1238 
1239             case LITERAL_switch:
1240                 statement = switchStatement(node);
1241                 break;
1242 
1243             case LITERAL_try:
1244                 statement = tryStatement(node);
1245                 break;
1246 
1247             case LITERAL_throw:
1248                 statement = throwStatement(node);
1249                 break;
1250 
1251             case LITERAL_while:
1252                 statement = whileStatement(node);
1253                 break;
1254 
1255             default:
1256                 statement = new ExpressionStatement(expression(node));
1257         }
1258         if (statement != null) {
1259             configureAST(statement, node);
1260         }
1261         return statement;
1262     }
1263 
1264     protected Statement statementList(AST code) {
1265         return statementListNoChild(code.getFirstChild(), code);
1266     }
1267 
1268     protected Statement statementListNoChild(AST node, AST alternativeConfigureNode) {
1269         BlockStatement block = new BlockStatement();
1270         // alternativeConfigureNode is used only to set the source position
1271         if (node != null) {
1272             configureAST(block, node);
1273         } else {
1274             configureAST(block, alternativeConfigureNode);
1275         }
1276         for (; node != null; node = node.getNextSibling()) {
1277             block.addStatement(statement(node));
1278         }
1279         return block;
1280     }
1281 
1282     protected Statement assertStatement(AST assertNode) {
1283         AST node = assertNode.getFirstChild();
1284         BooleanExpression booleanExpression = booleanExpression(node);
1285         Expression messageExpression = null;
1286 
1287         node = node.getNextSibling();
1288         if (node != null) {
1289             messageExpression = expression(node);
1290         } else {
1291             messageExpression = ConstantExpression.NULL;
1292         }
1293         AssertStatement assertStatement = new AssertStatement(booleanExpression, messageExpression);
1294         configureAST(assertStatement, assertNode);
1295         return assertStatement;
1296     }
1297 
1298     protected Statement breakStatement(AST node) {
1299         BreakStatement breakStatement = new BreakStatement(label(node));
1300         configureAST(breakStatement, node);
1301         return breakStatement;
1302     }
1303 
1304     protected Statement continueStatement(AST node) {
1305         ContinueStatement continueStatement = new ContinueStatement(label(node));
1306         configureAST(continueStatement, node);
1307         return continueStatement;
1308     }
1309 
1310     protected Statement forStatement(AST forNode) {
1311         AST inNode = forNode.getFirstChild();
1312         Expression collectionExpression;
1313         Parameter forParameter;
1314         if (isType(CLOSURE_LIST, inNode)) {
1315             forStatementBeingDef = true;
1316             ClosureListExpression clist = closureListExpression(inNode);
1317             forStatementBeingDef = false;
1318             int size = clist.getExpressions().size();
1319             if (size != 3) {
1320                 throw new ASTRuntimeException(inNode, "3 expressions are required for the classic for loop, you gave " + size);
1321             }
1322             collectionExpression = clist;
1323             forParameter = ForStatement.FOR_LOOP_DUMMY;
1324         } else {
1325             AST variableNode = inNode.getFirstChild();
1326             AST collectionNode = variableNode.getNextSibling();
1327 
1328             ClassNode type = ClassHelper.OBJECT_TYPE;
1329             if (isType(VARIABLE_DEF, variableNode)) {
1330                 AST node = variableNode.getFirstChild();
1331                 // skip the final modifier if it's present
1332                 if (isType(MODIFIERS, node)) {
1333                     int modifiersMask = modifiers(node, new ArrayList<AnnotationNode>(), 0);
1334                     // only final modifier allowed
1335                     if ((modifiersMask & ~Opcodes.ACC_FINAL) != 0) {
1336                         throw new ASTRuntimeException(node, "Only the 'final' modifier is allowed in front of the for loop variable.");
1337                     }
1338                     node = node.getNextSibling();
1339                 }
1340                 type = makeTypeWithArguments(node);
1341 
1342                 variableNode = node.getNextSibling();
1343             }
1344             String variable = identifier(variableNode);
1345 
1346             collectionExpression = expression(collectionNode);
1347             forParameter = new Parameter(type, variable);
1348             configureAST(forParameter, variableNode);
1349         }
1350 
1351         final AST node = inNode.getNextSibling();
1352         Statement block;
1353         if (isType(SEMI, node)) {
1354             block = EmptyStatement.INSTANCE;
1355         } else {
1356             block = statement(node);
1357         }
1358         ForStatement forStatement = new ForStatement(forParameter, collectionExpression, block);
1359         configureAST(forStatement, forNode);
1360         return forStatement;
1361     }
1362 
1363     protected Statement ifStatement(AST ifNode) {
1364         AST node = ifNode.getFirstChild();
1365         assertNodeType(EXPR, node);
1366         BooleanExpression booleanExpression = booleanExpression(node);
1367 
1368         node = node.getNextSibling();
1369         Statement ifBlock = statement(node);
1370 
1371         Statement elseBlock = EmptyStatement.INSTANCE;
1372         node = node.getNextSibling();
1373         if (node != null) {
1374             elseBlock = statement(node);
1375         }
1376         IfStatement ifStatement = new IfStatement(booleanExpression, ifBlock, elseBlock);
1377         configureAST(ifStatement, ifNode);
1378         return ifStatement;
1379     }
1380 
1381     protected Statement labelledStatement(AST labelNode) {
1382         AST node = labelNode.getFirstChild();
1383         String label = identifier(node);
1384         Statement statement = statement(node.getNextSibling());
1385         if (statement.getStatementLabel() == null) // if statement has multiple labels, retain the last one
1386             statement.setStatementLabel(label);
1387         return statement;
1388     }
1389 
1390     protected Statement methodCall(AST code) {
1391         Expression expression = methodCallExpression(code);
1392         ExpressionStatement expressionStatement = new ExpressionStatement(expression);
1393         configureAST(expressionStatement, code);
1394         return expressionStatement;
1395     }
1396 
1397     protected Expression declarationExpression(AST variableDef) {
1398         AST node = variableDef.getFirstChild();
1399         ClassNode type = null;
1400         List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
1401         int modifiers = 0;
1402         if (isType(MODIFIERS, node)) {
1403             // force check of modifier conflicts
1404             modifiers = modifiers(node, annotations, 0);
1405             node = node.getNextSibling();
1406         }
1407         if (isType(TYPE, node)) {
1408             type = makeTypeWithArguments(node);
1409             node = node.getNextSibling();
1410         }
1411 
1412         Expression leftExpression;
1413         Expression rightExpression = EmptyExpression.INSTANCE;
1414         AST right;
1415 
1416         if (isType(ASSIGN, node)) {
1417             node = node.getFirstChild();
1418             AST left = node.getFirstChild();
1419             ArgumentListExpression alist = new ArgumentListExpression();
1420 previous bug bug overview next bug               for (AST varDef = left; varDef != null; varDef = varDef.getNextSibling()) {  HEALTH4J >>  :  IL_INFINITE_LOOP 
1421                 assertNodeType(VARIABLE_DEF, varDef);
1422                 DeclarationExpression de = (DeclarationExpression) declarationExpression(varDef);
1423                 alist.addExpression(de.getVariableExpression());
1424             }
1425             leftExpression = alist;
1426             right = node.getNextSibling();
1427             if (right != null) rightExpression = expression(right);
1428         } else {
1429             String name = identifier(node);
1430             VariableExpression ve = new VariableExpression(name, type);
1431             ve.setModifiers(modifiers);
1432             leftExpression = ve;
1433 
1434             right = node.getNextSibling();
1435             if (right != null) {
1436                 assertNodeType(ASSIGN, right);
1437                 rightExpression = expression(right.getFirstChild());
1438             }
1439         }
1440 
1441         configureAST(leftExpression, node);
1442 
1443         Token token = makeToken(Types.ASSIGN, variableDef);
1444         DeclarationExpression expression = new DeclarationExpression(leftExpression, token, rightExpression);
1445         expression.addAnnotations(annotations);
1446         configureAST(expression, variableDef);
1447         ExpressionStatement expressionStatement = new ExpressionStatement(expression);
1448         configureAST(expressionStatement, variableDef);
1449         return expression;
1450     }
1451 
1452     protected Statement variableDef(AST variableDef) {
1453         ExpressionStatement expressionStatement = new ExpressionStatement(declarationExpression(variableDef));
1454         configureAST(expressionStatement, variableDef);
1455         return expressionStatement;
1456     }
1457 
1458     protected Statement returnStatement(AST node) {
1459         AST exprNode = node.getFirstChild();
1460 
1461         // This will pick up incorrect sibling node if 'node' is a plain 'return'
1462         //
1463         //if (exprNode == null) {
1464         //    exprNode = node.getNextSibling();
1465         //}
1466         Expression expression = exprNode == null ? ConstantExpression.NULL : expression(exprNode);
1467         ReturnStatement returnStatement = new ReturnStatement(expression);
1468         configureAST(returnStatement, node);
1469         return returnStatement;
1470     }
1471 
1472     protected Statement switchStatement(AST switchNode) {
1473         AST node = switchNode.getFirstChild();
1474         Expression expression = expression(node);
1475         Statement defaultStatement = EmptyStatement.INSTANCE;
1476 
1477         List list = new ArrayList();
1478         for (node = node.getNextSibling(); isType(CASE_GROUP, node); node = node.getNextSibling()) {
1479             Statement tmpDefaultStatement;
1480             AST child = node.getFirstChild();
1481             if (isType(LITERAL_case, child)) {
1482                 List cases = new LinkedList();
1483                 // default statement can be grouped with previous case
1484                 tmpDefaultStatement = caseStatements(child, cases);
1485                 list.addAll(cases);
1486             } else {
1487                 tmpDefaultStatement = statement(child.getNextSibling());
1488             }
1489             if (tmpDefaultStatement != EmptyStatement.INSTANCE) {
1490                 if (defaultStatement == EmptyStatement.INSTANCE) {
1491                     defaultStatement = tmpDefaultStatement;
1492                 } else {
1493                     throw new ASTRuntimeException(switchNode, "The default case is already defined.");
1494                 }
1495             }
1496         }
1497         if (node != null) {
1498             unknownAST(node);
1499         }
1500         SwitchStatement switchStatement = new SwitchStatement(expression, list, defaultStatement);
1501         configureAST(switchStatement, switchNode);
1502         return switchStatement;
1503     }
1504 
1505     protected Statement caseStatements(AST node, List cases) {
1506         List<Expression> expressions = new LinkedList<Expression>();
1507         Statement statement = EmptyStatement.INSTANCE;
1508         Statement defaultStatement = EmptyStatement.INSTANCE;
1509         AST nextSibling = node;
1510         do {
1511             Expression expression = expression(nextSibling.getFirstChild());
1512             expressions.add(expression);
1513             nextSibling = nextSibling.getNextSibling();
1514         } while (isType(LITERAL_case, nextSibling));
1515         if (nextSibling != null) {
1516             if (isType(LITERAL_default, nextSibling)) {
1517                 defaultStatement = statement(nextSibling.getNextSibling());
1518                 statement = EmptyStatement.INSTANCE;
1519             } else {
1520                 statement = statement(nextSibling);
1521             }
1522         }
1523         Iterator iterator = expressions.iterator();
1524         while (iterator.hasNext()) {
1525             Expression expr = (Expression) iterator.next();
1526             Statement stmt;
1527             if (iterator.hasNext()) {
1528                 stmt = new CaseStatement(expr, EmptyStatement.INSTANCE);
1529             } else {
1530                 stmt = new CaseStatement(expr, statement);
1531             }
1532             configureAST(stmt, node);
1533             cases.add(stmt);
1534         }
1535         return defaultStatement;
1536     }
1537 
1538     protected Statement synchronizedStatement(AST syncNode) {
1539         AST node = syncNode.getFirstChild();
1540         Expression expression = expression(node);
1541         Statement code = statement(node.getNextSibling());
1542         SynchronizedStatement synchronizedStatement = new SynchronizedStatement(expression, code);
1543         configureAST(synchronizedStatement, syncNode);
1544         return synchronizedStatement;
1545     }
1546 
1547     protected Statement throwStatement(AST node) {
1548         AST expressionNode = node.getFirstChild();
1549         if (expressionNode == null) {
1550             expressionNode = node.getNextSibling();
1551         }
1552         if (expressionNode == null) {
1553             throw new ASTRuntimeException(node, "No expression available");
1554         }
1555         ThrowStatement throwStatement = new ThrowStatement(expression(expressionNode));
1556         configureAST(throwStatement, node);
1557         return throwStatement;
1558     }
1559 
1560     protected Statement tryStatement(AST tryStatementNode) {
1561         AST tryNode = tryStatementNode.getFirstChild();
1562         Statement tryStatement = statement(tryNode);
1563         Statement finallyStatement = EmptyStatement.INSTANCE;
1564         AST node = tryNode.getNextSibling();
1565 
1566         // let's do the catch nodes
1567         List<CatchStatement> catches = new ArrayList<CatchStatement>();
1568         for (; node != null && isType(LITERAL_catch, node); node = node.getNextSibling()) {
1569             final List<CatchStatement> catchStatements = catchStatement(node);
1570             catches.addAll(catchStatements);
1571         }
1572 
1573         if (isType(LITERAL_finally, node)) {
1574             finallyStatement = statement(node);
1575             node = node.getNextSibling();
1576         }
1577 
1578         if (finallyStatement instanceof EmptyStatement && catches.size() == 0) {
1579             throw new ASTRuntimeException(tryStatementNode, "A try statement must have at least one catch or finally block.");
1580         }
1581 
1582         TryCatchStatement tryCatchStatement = new TryCatchStatement(tryStatement, finallyStatement);
1583         configureAST(tryCatchStatement, tryStatementNode);
1584         for (CatchStatement statement : catches) {
1585             tryCatchStatement.addCatch(statement);
1586         }
1587         return tryCatchStatement;
1588     }
1589 
1590     protected List<CatchStatement> catchStatement(AST catchNode) {
1591         AST node = catchNode.getFirstChild();
1592         List<CatchStatement> catches = new LinkedList<CatchStatement>();
1593         Statement code = statement(node.getNextSibling());
1594         if (MULTICATCH == node.getType()) {
1595             AST variableNode = node.getNextSibling();
1596             final AST multicatches = node.getFirstChild();
1597             if (multicatches.getType() != MULTICATCH_TYPES) {
1598                 // catch (e)
1599                 // catch (def e)
1600                 String variable = identifier(multicatches);
1601                 Parameter catchParameter = new Parameter(ClassHelper.DYNAMIC_TYPE, variable);
1602                 CatchStatement answer = new CatchStatement(catchParameter, code);
1603                 configureAST(answer, catchNode);
1604                 catches.add(answer);
1605             } else {
1606                 // catch (Exception e)
1607                 // catch (Exception1 | Exception2 e)
1608                 AST exceptionNodes = multicatches.getFirstChild();
1609                 String variable = identifier(multicatches.getNextSibling());
1610                 while (exceptionNodes != null) {
1611                     ClassNode exceptionType = buildName(exceptionNodes);
1612                     Parameter catchParameter = new Parameter(exceptionType, variable);
1613                     CatchStatement answer = new CatchStatement(catchParameter, code);
1614                     configureAST(answer, catchNode);
1615                     catches.add(answer);
1616                     exceptionNodes = exceptionNodes.getNextSibling();
1617                 }
1618             }
1619         }
1620         return catches;
1621     }
1622 
1623     protected Statement whileStatement(AST whileNode) {
1624         AST node = whileNode.getFirstChild();
1625         assertNodeType(EXPR, node);
1626 previous bug bug overview next bug           // TODO remove this once we support declarations in the while condition 
1627         if (isType(VARIABLE_DEF, node.getFirstChild())) {
1628             throw new ASTRuntimeException(whileNode,
1629                     "While loop condition contains a declaration; this is currently unsupported.");
1630         }
1631         BooleanExpression booleanExpression = booleanExpression(node);
1632 
1633         node = node.getNextSibling();
1634         Statement block;
1635         if (isType(SEMI, node)) {
1636             block = EmptyStatement.INSTANCE;
1637         } else {
1638             block = statement(node);
1639         }
1640         WhileStatement whileStatement = new WhileStatement(booleanExpression, block);
1641         configureAST(whileStatement, whileNode);
1642         return whileStatement;
1643     }
1644 
1645 
1646     // Expressions
1647     //-------------------------------------------------------------------------
1648 
1649     protected Expression expression(AST node) {
1650         return expression(node, false);
1651     }
1652 
1653     protected Expression expression(AST node, boolean convertToConstant) {
1654         Expression expression = expressionSwitch(node);
1655         if (convertToConstant && expression instanceof VariableExpression) {
1656             // a method name can never be a VariableExpression, so it must converted
1657             // to a ConstantExpression then. This is needed as the expression
1658             // method doesn't know we want a ConstantExpression instead of a
1659             // VariableExpression
1660             VariableExpression ve = (VariableExpression) expression;
1661             if (!ve.isThisExpression() && !ve.isSuperExpression()) {
1662                 expression = new ConstantExpression(ve.getName());
1663             }
1664         }
1665         configureAST(expression, node);
1666         return expression;
1667     }
1668 
1669 previous bug bug overview next bug       protected Expression expressionSwitch(AST node) {  HEALTH4J >>  :  ExcessiveMethodLength 
1670         int type = node.getType();
1671         switch (type) {
1672             case EXPR:
1673                 return expression(node.getFirstChild());
1674 
1675             case ELIST:
1676                 return expressionList(node);
1677 
1678             case SLIST:
1679                 return blockExpression(node);
1680 
1681             case CLOSABLE_BLOCK:
1682                 return closureExpression(node);
1683 
1684             case SUPER_CTOR_CALL:
1685                 return specialConstructorCallExpression(node, ClassNode.SUPER);
1686 
1687             case METHOD_CALL:
1688                 return methodCallExpression(node);
1689 
1690             case LITERAL_new:
1691                 return constructorCallExpression(node);
1692 
1693             case CTOR_CALL:
1694                 return specialConstructorCallExpression(node, ClassNode.THIS);
1695 
1696             case QUESTION:
1697             case ELVIS_OPERATOR:
1698                 return ternaryExpression(node);
1699 
1700             case OPTIONAL_DOT:
1701             case SPREAD_DOT:
1702             case DOT:
1703                 return dotExpression(node);
1704 
1705             case IDENT:
1706             case LITERAL_boolean:
1707             case LITERAL_byte:
1708             case LITERAL_char:
1709             case LITERAL_double:
1710             case LITERAL_float:
1711             case LITERAL_int:
1712             case LITERAL_long:
1713             case LITERAL_short:
1714             case LITERAL_void:
1715             case LITERAL_this:
1716             case LITERAL_super:
1717                 return variableExpression(node);
1718 
1719             case LIST_CONSTRUCTOR:
1720                 return listExpression(node);
1721 
1722             case MAP_CONSTRUCTOR:
1723                 return mapExpression(node);
1724 
1725             case LABELED_ARG:
1726                 return mapEntryExpression(node);
1727 
1728             case SPREAD_ARG:
1729                 return spreadExpression(node);
1730 
1731             case SPREAD_MAP_ARG:
1732                 return spreadMapExpression(node);
1733 
1734             // commented out of groovy.g due to non determinisms
1735             //case MEMBER_POINTER_DEFAULT:
1736             //    return defaultMethodPointerExpression(node);
1737 
1738             case MEMBER_POINTER:
1739                 return methodPointerExpression(node);
1740 
1741             case INDEX_OP:
1742                 return indexExpression(node);
1743 
1744             case LITERAL_instanceof:
1745                 return instanceofExpression(node);
1746 
1747             case LITERAL_as:
1748                 return asExpression(node);
1749 
1750             case TYPECAST:
1751                 return castExpression(node);
1752 
1753             // literals
1754 
1755             case LITERAL_true:
1756                 return literalExpression(node, Boolean.TRUE);
1757             case LITERAL_false:
1758                 return literalExpression(node, Boolean.FALSE);
1759             case LITERAL_null:
1760                 return literalExpression(node, null);
1761             case STRING_LITERAL:
1762                 return literalExpression(node, node.getText());
1763 
1764             case STRING_CONSTRUCTOR:
1765                 return gstring(node);
1766 
1767             case NUM_DOUBLE:
1768             case NUM_FLOAT:
1769             case NUM_BIG_DECIMAL:
1770                 return decimalExpression(node);
1771 
1772             case NUM_BIG_INT:
1773             case NUM_INT:
1774             case NUM_LONG:
1775                 return integerExpression(node);
1776 
1777             // Unary expressions
1778             case LNOT:
1779                 NotExpression notExpression = new NotExpression(expression(node.getFirstChild()));
1780                 configureAST(notExpression, node);
1781                 return notExpression;
1782 
1783             case UNARY_MINUS:
1784                 return unaryMinusExpression(node);
1785 
1786             case BNOT:
1787                 BitwiseNegationExpression bitwiseNegationExpression = new BitwiseNegationExpression(expression(node.getFirstChild()));
1788                 configureAST(bitwiseNegationExpression, node);
1789                 return bitwiseNegationExpression;
1790 
1791             case UNARY_PLUS:
1792                 return unaryPlusExpression(node);
1793 
1794             // Prefix expressions
1795             case INC:
1796                 return prefixExpression(node, Types.PLUS_PLUS);
1797 
1798             case DEC:
1799                 return prefixExpression(node, Types.MINUS_MINUS);
1800 
1801             // Postfix expressions
1802             case POST_INC:
1803                 return postfixExpression(node, Types.PLUS_PLUS);
1804 
1805             case POST_DEC:
1806                 return postfixExpression(node, Types.MINUS_MINUS);
1807 
1808 
1809             // Binary expressions
1810 
1811             case ASSIGN:
1812                 return binaryExpression(Types.ASSIGN, node);
1813 
1814             case EQUAL:
1815                 return binaryExpression(Types.COMPARE_EQUAL, node);
1816 
1817             case IDENTICAL:
1818                 return binaryExpression(Types.COMPARE_IDENTICAL, node);
1819 
1820             case NOT_EQUAL:
1821                 return binaryExpression(Types.COMPARE_NOT_EQUAL, node);
1822 
1823             case NOT_IDENTICAL:
1824                 return binaryExpression(Types.COMPARE_NOT_IDENTICAL, node);
1825 
1826             case COMPARE_TO:
1827                 return binaryExpression(Types.COMPARE_TO, node);
1828 
1829             case LE:
1830                 return binaryExpression(Types.COMPARE_LESS_THAN_EQUAL, node);
1831 
1832             case LT:
1833                 return binaryExpression(Types.COMPARE_LESS_THAN, node);
1834 
1835             case GT:
1836                 return binaryExpression(Types.COMPARE_GREATER_THAN, node);
1837 
1838             case GE:
1839                 return binaryExpression(Types.COMPARE_GREATER_THAN_EQUAL, node);
1840 
1841             /**
1842              * TODO treble equal?
1843              return binaryExpression(Types.COMPARE_IDENTICAL, node);
1844 
1845              case ???:
1846              return binaryExpression(Types.LOGICAL_AND_EQUAL, node);
1847 
1848              case ???:
1849              return binaryExpression(Types.LOGICAL_OR_EQUAL, node);
1850 
1851              */
1852 
1853             case LAND:
1854                 return binaryExpression(Types.LOGICAL_AND, node);
1855 
1856             case LOR:
1857                 return binaryExpression(Types.LOGICAL_OR, node);
1858 
1859             case BAND:
1860                 return binaryExpression(Types.BITWISE_AND, node);
1861 
1862             case BAND_ASSIGN:
1863                 return binaryExpression(Types.BITWISE_AND_EQUAL, node);
1864 
1865             case BOR:
1866                 return binaryExpression(Types.BITWISE_OR, node);
1867 
1868             case BOR_ASSIGN:
1869                 return binaryExpression(Types.BITWISE_OR_EQUAL, node);
1870 
1871             case BXOR:
1872                 return binaryExpression(Types.BITWISE_XOR, node);
1873 
1874             case BXOR_ASSIGN:
1875                 return binaryExpression(Types.BITWISE_XOR_EQUAL, node);
1876 
1877 
1878             case PLUS:
1879                 return binaryExpression(Types.PLUS, node);
1880 
1881             case PLUS_ASSIGN:
1882                 return binaryExpression(Types.PLUS_EQUAL, node);
1883 
1884 
1885             case MINUS:
1886                 return binaryExpression(Types.MINUS, node);
1887 
1888             case MINUS_ASSIGN:
1889                 return binaryExpression(Types.MINUS_EQUAL, node);
1890 
1891 
1892             case STAR:
1893                 return binaryExpression(Types.MULTIPLY, node);
1894 
1895             case STAR_ASSIGN:
1896                 return binaryExpression(Types.MULTIPLY_EQUAL, node);
1897 
1898 
1899             case STAR_STAR:
1900                 return binaryExpression(Types.POWER, node);
1901 
1902             case STAR_STAR_ASSIGN:
1903                 return binaryExpression(Types.POWER_EQUAL, node);
1904 
1905 
1906             case DIV:
1907                 return binaryExpression(Types.DIVIDE, node);
1908 
1909             case DIV_ASSIGN:
1910                 return binaryExpression(Types.DIVIDE_EQUAL, node);
1911 
1912 
1913             case MOD:
1914                 return binaryExpression(Types.MOD, node);
1915 
1916             case MOD_ASSIGN:
1917                 return binaryExpression(Types.MOD_EQUAL, node);
1918 
1919             case SL:
1920                 return binaryExpression(Types.LEFT_SHIFT, node);
1921 
1922             case SL_ASSIGN:
1923                 return binaryExpression(Types.LEFT_SHIFT_EQUAL, node);
1924 
1925             case SR:
1926                 return binaryExpression(Types.RIGHT_SHIFT, node);
1927 
1928             case SR_ASSIGN:
1929                 return binaryExpression(Types.RIGHT_SHIFT_EQUAL, node);
1930 
1931             case BSR:
1932                 return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED, node);
1933 
1934             case BSR_ASSIGN:
1935                 return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED_EQUAL, node);
1936 
1937             case VARIABLE_DEF:
1938                 return declarationExpression(node);
1939 
1940             // Regex
1941             case REGEX_FIND:
1942                 return binaryExpression(Types.FIND_REGEX, node);
1943 
1944             case REGEX_MATCH:
1945                 return binaryExpression(Types.MATCH_REGEX, node);
1946 
1947 
1948             // Ranges
1949             case RANGE_INCLUSIVE:
1950                 return rangeExpression(node, true);
1951 
1952             case RANGE_EXCLUSIVE:
1953                 return rangeExpression(node, false);
1954 
1955             case DYNAMIC_MEMBER:
1956                 return dynamicMemberExpression(node);
1957 
1958             case LITERAL_in:
1959                 return binaryExpression(Types.KEYWORD_IN, node);
1960 
1961             case ANNOTATION:
1962                 return new AnnotationConstantExpression(annotation(node));
1963 
1964             case CLOSURE_LIST:
1965                 return closureListExpression(node);
1966 
1967             case LBRACK:
1968             case LPAREN:
1969                 return tupleExpression(node);
1970 
1971             case OBJBLOCK:
1972                 return anonymousInnerClassDef(node);
1973 
1974             default:
1975                 unknownAST(node);
1976         }
1977         return null;
1978     }
1979 
1980     private TupleExpression tupleExpression(AST node) {
1981         TupleExpression exp = new TupleExpression();
1982         configureAST(exp, node);
1983         node = node.getFirstChild();
1984         while (node != null) {
1985             assertNodeType(VARIABLE_DEF, node);
1986             AST nameNode = node.getFirstChild().getNextSibling();
1987             VariableExpression varExp = new VariableExpression(nameNode.getText());
1988             configureAST(varExp, nameNode);
1989             exp.addExpression(varExp);
1990             node = node.getNextSibling();
1991         }
1992         return exp;
1993     }
1994 
1995     private ClosureListExpression closureListExpression(AST node) {
1996         isClosureListExpressionAllowedHere(node);
1997         AST exprNode = node.getFirstChild();
1998         List<Expression> list = new LinkedList<Expression>();
1999         while (exprNode != null) {
2000             if (isType(EXPR, exprNode)) {
2001                 Expression expr = expression(exprNode);
2002                 configureAST(expr, exprNode);
2003                 list.add(expr);
2004             } else {
2005                 assertNodeType(EMPTY_STAT, exprNode);
2006                 list.add(EmptyExpression.INSTANCE);
2007             }
2008 
2009             exprNode = exprNode.getNextSibling();
2010         }
2011         ClosureListExpression cle = new ClosureListExpression(list);
2012         configureAST(cle, node);
2013         return cle;
2014     }
2015 
2016     private void isClosureListExpressionAllowedHere(AST node) {
2017         if (!forStatementBeingDef) {
2018             throw new ASTRuntimeException(node,
2019                     "Expression list of the form (a; b; c) is not supported in this context.");
2020         }
2021     }
2022 
2023     protected Expression dynamicMemberExpression(AST dynamicMemberNode) {
2024         AST node = dynamicMemberNode.getFirstChild();
2025         return expression(node);
2026     }
2027 
2028     protected Expression ternaryExpression(AST ternaryNode) {
2029         AST node = ternaryNode.getFirstChild();
2030         Expression base = expression(node);
2031         node = node.getNextSibling();
2032         Expression left = expression(node);
2033         node = node.getNextSibling();
2034         Expression ret;
2035         if (node == null) {
2036             ret = new ElvisOperatorExpression(base, left);
2037         } else {
2038             Expression right = expression(node);
2039             BooleanExpression booleanExpression = new BooleanExpression(base);
2040             booleanExpression.setSourcePosition(base);
2041             ret = new TernaryExpression(booleanExpression, left, right);
2042         }
2043         configureAST(ret, ternaryNode);
2044         return ret;
2045     }
2046 
2047     protected Expression variableExpression(AST node) {
2048         String text = node.getText();
2049 
2050 previous bug bug overview next bug           // TODO we might wanna only try to resolve the name if we are 
2051         // on the left hand side of an expression or before a dot?
2052         VariableExpression variableExpression = new VariableExpression(text);
2053         configureAST(variableExpression, node);
2054         return variableExpression;
2055     }
2056 
2057     protected Expression literalExpression(AST node, Object value) {
2058         ConstantExpression constantExpression = new ConstantExpression(value);
2059         configureAST(constantExpression, node);
2060         return constantExpression;
2061     }
2062 
2063     protected Expression rangeExpression(AST rangeNode, boolean inclusive) {
2064         AST node = rangeNode.getFirstChild();
2065         Expression left = expression(node);
2066         Expression right = expression(node.getNextSibling());
2067         RangeExpression rangeExpression = new RangeExpression(left, right, inclusive);
2068         configureAST(rangeExpression, rangeNode);
2069         return rangeExpression;
2070     }
2071 
2072     protected Expression spreadExpression(AST node) {
2073         AST exprNode = node.getFirstChild();
2074         AST listNode = exprNode.getFirstChild();
2075         Expression right = expression(listNode);
2076         SpreadExpression spreadExpression = new SpreadExpression(right);
2077         configureAST(spreadExpression, node);
2078         return spreadExpression;
2079     }
2080 
2081     protected Expression spreadMapExpression(AST node) {
2082         AST exprNode = node.getFirstChild();
2083         Expression expr = expression(exprNode);
2084         SpreadMapExpression spreadMapExpression = new SpreadMapExpression(expr);
2085         configureAST(spreadMapExpression, node);
2086         return spreadMapExpression;
2087     }
2088 
2089     protected Expression methodPointerExpression(AST node) {
2090         AST exprNode = node.getFirstChild();
2091         Expression objectExpression = expression(exprNode);
2092         AST mNode = exprNode.getNextSibling();
2093         Expression methodName;
2094         if (isType(DYNAMIC_MEMBER, mNode)) {
2095             methodName = expression(mNode);
2096         } else {
2097             methodName = new ConstantExpression(identifier(mNode));
2098         }
2099         configureAST(methodName, mNode);
2100         MethodPointerExpression methodPointerExpression = new MethodPointerExpression(objectExpression, methodName);
2101         configureAST(methodPointerExpression, node);
2102         return methodPointerExpression;
2103     }
2104 
2105 /*  commented out due to groovy.g non-determinisms
2106   protected Expression defaultMethodPointerExpression(AST node) {
2107         AST exprNode = node.getFirstChild();
2108         String methodName = exprNode.toString();
2109         MethodPointerExpression methodPointerExpression = new MethodPointerExpression(null, methodName);
2110         configureAST(methodPointerExpression, node);
2111         return methodPointerExpression;
2112     }
2113 */
2114 
2115     protected Expression listExpression(AST listNode) {
2116         List<Expression> expressions = new ArrayList<Expression>();
2117         AST elist = listNode.getFirstChild();
2118         assertNodeType(ELIST, elist);
2119 
2120         for (AST node = elist.getFirstChild(); node != null; node = node.getNextSibling()) {
2121             // check for stray labeled arguments:
2122             switch (node.getType()) {
2123                 case LABELED_ARG:
2124                     assertNodeType(COMMA, node);
2125                     break;  // helpful error?
2126                 case SPREAD_MAP_ARG:
2127                     assertNodeType(SPREAD_ARG, node);
2128                     break;  // helpful error
2129             }
2130             expressions.add(expression(node));
2131         }
2132         ListExpression listExpression = new ListExpression(expressions);
2133         configureAST(listExpression, listNode);
2134         return listExpression;
2135     }
2136 
2137     /**
2138      * Typically only used for map constructors I think?
2139      */
2140     protected Expression mapExpression(AST mapNode) {
2141         List expressions = new ArrayList();
2142         AST elist = mapNode.getFirstChild();
2143         if (elist != null) {  // totally empty in the case of [:]
2144             assertNodeType(ELIST, elist);
2145             for (AST node = elist.getFirstChild(); node != null; node = node.getNextSibling()) {
2146                 switch (node.getType()) {
2147                     case LABELED_ARG:
2148                     case SPREAD_MAP_ARG:
2149                         break;  // legal cases
2150                     case SPREAD_ARG:
2151                         assertNodeType(SPREAD_MAP_ARG, node);
2152                         break;  // helpful error
2153                     default:
2154                         assertNodeType(LABELED_ARG, node);
2155                         break;  // helpful error
2156                 }
2157                 expressions.add(mapEntryExpression(node));
2158             }
2159         }
2160         MapExpression mapExpression = new MapExpression(expressions);
2161         configureAST(mapExpression, mapNode);
2162         return mapExpression;
2163     }
2164 
2165     protected MapEntryExpression mapEntryExpression(AST node) {
2166         if (node.getType() == SPREAD_MAP_ARG) {
2167             AST rightNode = node.getFirstChild();
2168             Expression keyExpression = spreadMapExpression(node);
2169             Expression rightExpression = expression(rightNode);
2170             MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, rightExpression);
2171             configureAST(mapEntryExpression, node);
2172             return mapEntryExpression;
2173         } else {
2174             AST keyNode = node.getFirstChild();
2175             Expression keyExpression = expression(keyNode);
2176             AST valueNode = keyNode.getNextSibling();
2177             Expression valueExpression = expression(valueNode);
2178             MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, valueExpression);
2179             configureAST(mapEntryExpression, node);
2180             return mapEntryExpression;
2181         }
2182     }
2183 
2184 
2185     protected Expression instanceofExpression(AST node) {
2186         AST leftNode = node.getFirstChild();
2187         Expression leftExpression = expression(leftNode);
2188 
2189         AST rightNode = leftNode.getNextSibling();
2190         ClassNode type = buildName(rightNode);
2191         assertTypeNotNull(type, rightNode);
2192 
2193         Expression rightExpression = new ClassExpression(type);
2194         configureAST(rightExpression, rightNode);
2195         BinaryExpression binaryExpression = new BinaryExpression(leftExpression, makeToken(Types.KEYWORD_INSTANCEOF, node), rightExpression);
2196         configureAST(binaryExpression, node);
2197         return binaryExpression;
2198     }
2199 
2200     protected void assertTypeNotNull(ClassNode type, AST rightNode) {
2201         if (type == null) {
2202             throw new ASTRuntimeException(rightNode, "No type available for: " + qualifiedName(rightNode));
2203         }
2204     }
2205 
2206     protected Expression asExpression(AST node) {
2207         AST leftNode = node.getFirstChild();
2208         Expression leftExpression = expression(leftNode);
2209 
2210         AST rightNode = leftNode.getNextSibling();
2211         ClassNode type = makeTypeWithArguments(rightNode);
2212 
2213         return CastExpression.asExpression(type, leftExpression);
2214     }
2215 
2216     protected Expression castExpression(AST castNode) {
2217         AST node = castNode.getFirstChild();
2218         ClassNode type = makeTypeWithArguments(node);
2219         assertTypeNotNull(type, node);
2220 
2221         AST expressionNode = node.getNextSibling();
2222         Expression expression = expression(expressionNode);
2223 
2224         CastExpression castExpression = new CastExpression(type, expression);
2225         configureAST(castExpression, castNode);
2226         return castExpression;
2227     }
2228 
2229 
2230     protected Expression indexExpression(AST indexNode) {
2231         AST bracket = indexNode.getFirstChild();
2232         AST leftNode = bracket.getNextSibling();
2233         Expression leftExpression = expression(leftNode);
2234 
2235         AST rightNode = leftNode.getNextSibling();
2236         Expression rightExpression = expression(rightNode);
2237 
2238         BinaryExpression binaryExpression = new BinaryExpression(leftExpression, makeToken(Types.LEFT_SQUARE_BRACKET, bracket), rightExpression);
2239         configureAST(binaryExpression, indexNode);
2240         return binaryExpression;
2241     }
2242 
2243     protected Expression binaryExpression(int type, AST node) {
2244         Token token = makeToken(type, node);
2245 
2246         AST leftNode = node.getFirstChild();
2247         Expression leftExpression = expression(leftNode);
2248 
2249         AST rightNode = leftNode.getNextSibling();
2250         if (rightNode == null) {
2251             return leftExpression;
2252         }
2253 
2254         if (Types.ofType(type, Types.ASSIGNMENT_OPERATOR)) {
2255             if (leftExpression instanceof VariableExpression ||
2256                     leftExpression.getClass() == PropertyExpression.class ||
2257                     leftExpression instanceof FieldExpression ||
2258                     leftExpression instanceof AttributeExpression ||
2259                     leftExpression instanceof DeclarationExpression ||
2260 previous bug bug overview next bug                       leftExpression instanceof TupleExpression) {  HEALTH4J >>  :  EmptyIfStmt 
2261                 // Do nothing.
2262             } else if (leftExpression instanceof ConstantExpression) {
2263                 throw new ASTRuntimeException(node, "\n[" + ((ConstantExpression) leftExpression).getValue() + "] is a constant expression, but it should be a variable expression");
2264             } else if (leftExpression instanceof BinaryExpression) {
2265                 Expression leftexp = ((BinaryExpression) leftExpression).getLeftExpression();
2266                 int lefttype = ((BinaryExpression) leftExpression).getOperation().getType();
2267                 if (!Types.ofType(lefttype, Types.ASSIGNMENT_OPERATOR) && lefttype != Types.LEFT_SQUARE_BRACKET) {
2268                     throw new ASTRuntimeException(node, "\n" + ((BinaryExpression) leftExpression).getText() + " is a binary expression, but it should be a variable expression");
2269                 }
2270             } else if (leftExpression instanceof GStringExpression) {
2271                 throw new ASTRuntimeException(node, "\n\"" + ((GStringExpression) leftExpression).getText() + "\" is a GString expression, but it should be a variable expression");
2272             } else if (leftExpression instanceof MethodCallExpression) {
2273                 throw new ASTRuntimeException(node, "\n\"" + ((MethodCallExpression) leftExpression).getText() + "\" is a method call expression, but it should be a variable expression");
2274             } else if (leftExpression instanceof MapExpression) {
2275                 throw new ASTRuntimeException(node, "\n'" + ((MapExpression) leftExpression).getText() + "' is a map expression, but it should be a variable expression");
2276             } else {
2277                 throw new ASTRuntimeException(node, "\n" + leftExpression.getClass() + ", with its value '" + leftExpression.getText() + "', is a bad expression as the left hand side of an assignment operator");
2278             }
2279         }
2280         /*if (rightNode == null) {
2281             throw new NullPointerException("No rightNode associated with binary expression");
2282         }*/
2283         Expression rightExpression = expression(rightNode);
2284         BinaryExpression binaryExpression = new BinaryExpression(leftExpression, token, rightExpression);
2285         configureAST(binaryExpression, node);
2286         return binaryExpression;
2287     }
2288 
2289     protected Expression prefixExpression(AST node, int token) {
2290         Expression expression = expression(node.getFirstChild());
2291         PrefixExpression prefixExpression = new PrefixExpression(makeToken(token, node), expression);
2292         configureAST(prefixExpression, node);
2293         return prefixExpression;
2294     }
2295 
2296     protected Expression postfixExpression(AST node, int token) {
2297         Expression expression = expression(node.getFirstChild());
2298         PostfixExpression postfixExpression = new PostfixExpression(expression, makeToken(token, node));
2299         configureAST(postfixExpression, node);
2300         return postfixExpression;
2301     }
2302 
2303     protected BooleanExpression booleanExpression(AST node) {
2304         BooleanExpression booleanExpression = new BooleanExpression(expression(node));
2305         configureAST(booleanExpression, node);
2306         return booleanExpression;
2307     }
2308 
2309     protected Expression dotExpression(AST node) {
2310         // let's decide if this is a property invocation or a method call
2311         AST leftNode = node.getFirstChild();
2312         if (leftNode != null) {
2313             AST identifierNode = leftNode.getNextSibling();
2314             if (identifierNode != null) {
2315                 Expression leftExpression = expression(leftNode);
2316                 if (isType(SELECT_SLOT, identifierNode)) {
2317                     Expression field = expression(identifierNode.getFirstChild(), true);
2318                     AttributeExpression attributeExpression = new AttributeExpression(leftExpression, field, node.getType() != DOT);
2319                     if (node.getType() == SPREAD_DOT) {
2320                         attributeExpression.setSpreadSafe(true);
2321                     }
2322                     configureAST(attributeExpression, node);
2323                     return attributeExpression;
2324                 }
2325                 if (isType(SLIST, identifierNode)) {
2326                     Statement code = statementList(identifierNode);
2327                     ClosureExpression closureExpression = new ClosureExpression(Parameter.EMPTY_ARRAY, code);
2328                     configureAST(closureExpression, identifierNode);
2329                     final PropertyExpression propertyExpression = new PropertyExpression(leftExpression, closureExpression);
2330                     if (node.getType() == SPREAD_DOT) {
2331                         propertyExpression.setSpreadSafe(true);
2332                     }
2333                     configureAST(propertyExpression, node);
2334                     return propertyExpression;
2335                 }
2336                 Expression property = expression(identifierNode, true);
2337 
2338 
2339                 // A."this" assumes a VariableExpression can be used for "this"
2340                 // we correct that here into a ConstantExpression
2341                 if (property instanceof VariableExpression) {
2342                     VariableExpression ve = (VariableExpression) property;
2343                     property = new ConstantExpression(ve.getName());
2344                 }
2345 
2346                 PropertyExpression propertyExpression = new PropertyExpression(leftExpression, property, node.getType() != DOT);
2347                 if (node.getType() == SPREAD_DOT) {
2348                     propertyExpression.setSpreadSafe(true);
2349                 }
2350                 configureAST(propertyExpression, node);
2351                 return propertyExpression;
2352             }
2353         }
2354         return methodCallExpression(node);
2355     }
2356 
2357     protected Expression specialConstructorCallExpression(AST methodCallNode, ClassNode special) {
2358         AST node = methodCallNode.getFirstChild();
2359         Expression arguments = arguments(node);
2360 
2361         ConstructorCallExpression expression = new ConstructorCallExpression(special, arguments);
2362         configureAST(expression, methodCallNode);
2363         return expression;
2364     }
2365 
2366     private int getTypeInParenthesis(AST node) {
2367         if (!isType(EXPR, node)) node = node.getFirstChild();
2368         while (node != null && isType(EXPR, node) && node.getNextSibling() == null) {
2369             node = node.getFirstChild();
2370         }
2371         if (node == null) return -1;
2372         return node.getType();
2373     }
2374 
2375     protected Expression methodCallExpression(AST methodCallNode) {
2376         AST node = methodCallNode.getFirstChild();
2377         Expression objectExpression;
2378         AST selector;
2379         AST elist = node.getNextSibling();
2380         List<GenericsType> typeArgumentList = null;
2381 
2382         boolean implicitThis = false;
2383         boolean safe = isType(OPTIONAL_DOT, node);
2384         boolean spreadSafe = isType(SPREAD_DOT, node);
2385         if (isType(DOT, node) || safe || spreadSafe) {
2386             AST objectNode = node.getFirstChild();
2387             objectExpression = expression(objectNode);
2388             selector = objectNode.getNextSibling();
2389         } else {
2390             implicitThis = true;
2391             objectExpression = VariableExpression.THIS_EXPRESSION;
2392             selector = node;
2393         }
2394 
2395         if (isType(TYPE_ARGUMENTS, selector)) {
2396             typeArgumentList = getTypeArgumentsList(selector);
2397             selector = selector.getNextSibling();
2398         }
2399 
2400         Expression name = null;
2401         if (isType(LITERAL_super, selector)) {
2402             implicitThis = true;
2403             name = new ConstantExpression("super");
2404             if (objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression()) {
2405                 objectExpression = VariableExpression.SUPER_EXPRESSION;
2406             }
2407         } else if (isPrimitiveTypeLiteral(selector)) {
2408             throw new ASTRuntimeException(selector, "Primitive type literal: " + selector.getText()
2409                     + " cannot be used as a method name");
2410         } else if (isType(SELECT_SLOT, selector)) {
2411             Expression field = expression(selector.getFirstChild(), true);
2412             AttributeExpression attributeExpression = new AttributeExpression(objectExpression, field, node.getType() != DOT);
2413             configureAST(attributeExpression, node);
2414             Expression arguments = arguments(elist);
2415             MethodCallExpression expression = new MethodCallExpression(attributeExpression, "call", arguments);
2416             setTypeArgumentsOnMethodCallExpression(expression, typeArgumentList);
2417             configureAST(expression, methodCallNode);
2418             return expression;
2419         } else if (!implicitThis || isType(DYNAMIC_MEMBER, selector) || isType(IDENT, selector) ||
2420                 isType(STRING_CONSTRUCTOR, selector) || isType(STRING_LITERAL, selector)) {
2421             name = expression(selector, true);
2422         } else {
2423             implicitThis = false;
2424             name = new ConstantExpression("call");
2425             objectExpression = expression(selector, true);
2426         }
2427 
2428         // if node text is found to be "super"/"this" when a method call is being processed, it is a 
2429         // call like this(..)/super(..) after the first statement, which shouldn't be allowed. GROOVY-2836
2430         if (selector.getText().equals("this") || selector.getText().equals("super")) {
2431             throw new ASTRuntimeException(elist, "Constructor call must be the first statement in a constructor.");
2432         }
2433 
2434         Expression arguments = arguments(elist);
2435         MethodCallExpression expression = new MethodCallExpression(objectExpression, name, arguments);
2436         expression.setSafe(safe);
2437         expression.setSpreadSafe(spreadSafe);
2438         expression.setImplicitThis(implicitThis);
2439         setTypeArgumentsOnMethodCallExpression(expression, typeArgumentList);
2440         Expression ret = expression;
2441 previous bug bug overview next bug           //FIXME: do we really want this() to create a new object regardless 
2442         // the position.. for example not as first statement in a constructor
2443         // this=first statement in constructor is handled by specialConstructorCallExpression
2444         // we may have to add a check and remove this part of the code
2445         if (implicitThis && "this".equals(expression.getMethodAsString())) {
2446             ret = new ConstructorCallExpression(this.classNode, arguments);
2447         }
2448         configureAST(ret, methodCallNode);
2449         return ret;
2450     }
2451 
2452     private void setTypeArgumentsOnMethodCallExpression(MethodCallExpression expression,
2453                                                         List<GenericsType> typeArgumentList) {
2454         if (typeArgumentList != null && typeArgumentList.size() > 0) {
2455             expression.setGenericsTypes(typeArgumentList.toArray(new GenericsType[typeArgumentList.size()]));
2456         }
2457     }
2458 
2459     protected Expression constructorCallExpression(AST node) {
2460         AST constructorCallNode = node;
2461         ClassNode type = makeTypeWithArguments(constructorCallNode);
2462 
2463         if (isType(CTOR_CALL, node) || isType(LITERAL_new, node)) {
2464             node = node.getFirstChild();
2465         }
2466 
2467         AST elist = node.getNextSibling();
2468 
2469         if (elist == null && isType(ELIST, node)) {
2470             elist = node;
2471             if ("(".equals(type.getName())) {
2472                 type = classNode;
2473             }
2474         }
2475 
2476         if (isType(ARRAY_DECLARATOR, elist)) {
2477             AST expressionNode = elist.getFirstChild();
2478             if (expressionNode == null) {
2479                 throw new ASTRuntimeException(elist, "No expression for the array constructor call");
2480             }
2481             List size = arraySizeExpression(expressionNode);
2482             ArrayExpression arrayExpression = new ArrayExpression(type, null, size);
2483             configureAST(arrayExpression, constructorCallNode);
2484             return arrayExpression;
2485         }
2486         Expression arguments = arguments(elist);
2487         ClassNode innerClass = getAnonymousInnerClassNode(arguments);
2488         ConstructorCallExpression ret = new ConstructorCallExpression(type, arguments);
2489         if (innerClass != null) {
2490             ret.setType(innerClass);
2491             ret.setUsingAnonymousInnerClass(true);
2492             innerClass.setUnresolvedSuperClass(type);
2493         }
2494 
2495         configureAST(ret, constructorCallNode);
2496         return ret;
2497     }
2498 
2499     private ClassNode getAnonymousInnerClassNode(Expression arguments) {
2500         if (arguments instanceof TupleExpression) {
2501             TupleExpression te = (TupleExpression) arguments;
2502             List<Expression> expressions = te.getExpressions();
2503             if (expressions.size() == 0) return null;
2504             Expression last = (Expression) expressions.remove(expressions.size() - 1);
2505             if (last instanceof AnonymousInnerClassCarrier) {
2506                 AnonymousInnerClassCarrier carrier = (AnonymousInnerClassCarrier) last;
2507                 return carrier.innerClass;
2508             } else {
2509                 expressions.add(last);
2510             }
2511         } else if (arguments instanceof AnonymousInnerClassCarrier) {
2512             AnonymousInnerClassCarrier carrier = (AnonymousInnerClassCarrier) arguments;
2513             return carrier.innerClass;
2514         }
2515         return null;
2516     }
2517 
2518     protected List arraySizeExpression(AST node) {
2519         List list;
2520         Expression size = null;
2521         if (isType(ARRAY_DECLARATOR, node)) {
2522             AST right = node.getNextSibling();
2523             if (right != null) {
2524                 size = expression(right);
2525             } else {
2526                 size = ConstantExpression.EMPTY_EXPRESSION;
2527             }
2528             list = arraySizeExpression(node.getFirstChild());
2529         } else {
2530             size = expression(node);
2531             list = new ArrayList();
2532         }
2533         list.add(size);
2534         return list;
2535     }
2536 
2537     protected Expression arguments(AST elist) {
2538         List expressionList = new ArrayList();
2539 previous bug bug overview next bug           // FIXME: all labeled arguments should follow any unlabeled arguments 
2540         boolean namedArguments = false;
2541 previous bug bug overview next bug           for (AST node = elist; node != null; node = node.getNextSibling()) {  HEALTH4J >>  :  IL_INFINITE_LOOP 
2542             if (isType(ELIST, node)) {
2543                 for (AST child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
2544                     namedArguments |= addArgumentExpression(child, expressionList);
2545                 }
2546             } else {
2547                 namedArguments |= addArgumentExpression(node, expressionList);
2548             }
2549         }
2550         if (namedArguments) {
2551             if (!expressionList.isEmpty()) {
2552                 // let's remove any non-MapEntryExpression instances
2553                 // such as if the last expression is a ClosureExpression
2554                 // so let's wrap the named method calls in a Map expression
2555                 List<Expression> argumentList = new ArrayList<Expression>();
2556                 for (Object next : expressionList) {
2557                     Expression expression = (Expression) next;
2558                     if (!(expression instanceof MapEntryExpression)) {
2559                         argumentList.add(expression);
2560                     }
2561                 }
2562                 if (!argumentList.isEmpty()) {
2563                     expressionList.removeAll(argumentList);
2564                     checkDuplicateNamedParams(elist, expressionList);
2565                     MapExpression mapExpression = new MapExpression(expressionList);
2566                     configureAST(mapExpression, elist);
2567                     argumentList.add(0, mapExpression);
2568                     ArgumentListExpression argumentListExpression = new ArgumentListExpression(argumentList);
2569                     configureAST(argumentListExpression, elist);
2570                     return argumentListExpression;
2571                 }
2572             }
2573             checkDuplicateNamedParams(elist, expressionList);
2574             NamedArgumentListExpression namedArgumentListExpression = new NamedArgumentListExpression(expressionList);
2575             configureAST(namedArgumentListExpression, elist);
2576             return namedArgumentListExpression;
2577         } else {
2578             ArgumentListExpression argumentListExpression = new ArgumentListExpression(expressionList);
2579             configureAST(argumentListExpression, elist);
2580             return argumentListExpression;
2581         }
2582     }
2583 
2584     private void checkDuplicateNamedParams(AST elist, List expressionList) {
2585         if (expressionList.isEmpty()) return;
2586 
2587         Set<String> namedArgumentNames = new HashSet<String>();
2588         for (Object expression : expressionList) {
2589             MapEntryExpression meExp = (MapEntryExpression) expression;
2590             if (meExp.getKeyExpression() instanceof ConstantExpression) {
2591                 String argName = meExp.getKeyExpression().getText();
2592                 if (!namedArgumentNames.contains(argName)) {
2593                     namedArgumentNames.add(argName);
2594                 } else {
2595                     throw new ASTRuntimeException(elist, "Duplicate named parameter '" + argName
2596                             + "' found.");
2597                 }
2598             }
2599         }
2600     }
2601 
2602     protected boolean addArgumentExpression(AST node, List<Expression> expressionList) {
2603         if (node.getType() == SPREAD_MAP_ARG) {
2604             AST rightNode = node.getFirstChild();
2605             Expression keyExpression = spreadMapExpression(node);
2606             Expression rightExpression = expression(rightNode);
2607             MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, rightExpression);
2608             expressionList.add(mapEntryExpression);
2609             return true;
2610         } else {
2611             Expression expression = expression(node);
2612             expressionList.add(expression);
2613             return expression instanceof MapEntryExpression;
2614         }
2615     }
2616 
2617     protected Expression expressionList(AST node) {
2618         List<Expression> expressionList = new ArrayList<Expression>();
2619         for (AST child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
2620             expressionList.add(expression(child));
2621         }
2622         if (expressionList.size() == 1) {
2623             return expressionList.get(0);
2624         } else {
2625             ListExpression listExpression = new ListExpression(expressionList);
2626             listExpression.setWrapped(true);
2627             configureAST(listExpression, node);
2628             return listExpression;
2629         }
2630     }
2631 
2632     protected ClosureExpression closureExpression(AST node) {
2633         AST paramNode = node.getFirstChild();
2634         Parameter[] parameters = null;
2635         AST codeNode = paramNode;
2636         if (isType(PARAMETERS, paramNode) || isType(IMPLICIT_PARAMETERS, paramNode)) {
2637             parameters = parameters(paramNode);
2638             codeNode = paramNode.getNextSibling();
2639         }
2640         Statement code = statementListNoChild(codeNode, node);
2641         ClosureExpression closureExpression = new ClosureExpression(parameters, code);
2642         configureAST(closureExpression, node);
2643         return closureExpression;
2644     }
2645 
2646     protected Expression blockExpression(AST node) {
2647         AST codeNode = node.getFirstChild();
2648         if (codeNode == null) return ConstantExpression.NULL;
2649         if (codeNode.getType() == EXPR && codeNode.getNextSibling() == null) {
2650             // Simplify common case of {expr} to expr.
2651             return expression(codeNode);
2652         }
2653         Parameter[] parameters = Parameter.EMPTY_ARRAY;
2654         Statement code = statementListNoChild(codeNode, node);
2655         ClosureExpression closureExpression = new ClosureExpression(parameters, code);
2656         configureAST(closureExpression, node);
2657         // Call it immediately.
2658         String callName = "call";
2659         Expression noArguments = new ArgumentListExpression();
2660         MethodCallExpression call = new MethodCallExpression(closureExpression, callName, noArguments);
2661         configureAST(call, node);
2662         return call;
2663     }
2664 
2665     protected Expression unaryMinusExpression(AST unaryMinusExpr) {
2666         AST node = unaryMinusExpr.getFirstChild();
2667 
2668         // if we are a number literal then let's just parse it
2669         // as the negation operator on MIN_INT causes rounding to a long
2670         String text = node.getText();
2671         switch (node.getType()) {
2672             case NUM_DOUBLE:
2673             case NUM_FLOAT:
2674             case NUM_BIG_DECIMAL:
2675                 ConstantExpression constantExpression = new ConstantExpression(Numbers.parseDecimal("-" + text));
2676                 configureAST(constantExpression, unaryMinusExpr);
2677                 return constantExpression;
2678 
2679             case NUM_BIG_INT:
2680             case NUM_INT:
2681             case NUM_LONG:
2682                 ConstantExpression constantLongExpression = new ConstantExpression(Numbers.parseInteger("-" + text));
2683                 configureAST(constantLongExpression, unaryMinusExpr);
2684                 return constantLongExpression;
2685 
2686             default:
2687                 UnaryMinusExpression unaryMinusExpression = new UnaryMinusExpression(expression(node));
2688                 configureAST(unaryMinusExpression, unaryMinusExpr);
2689                 return unaryMinusExpression;
2690         }
2691     }
2692 
2693     protected Expression unaryPlusExpression(AST unaryPlusExpr) {
2694         AST node = unaryPlusExpr.getFirstChild();
2695         switch (node.getType()) {
2696             case NUM_DOUBLE:
2697             case NUM_FLOAT:
2698             case NUM_BIG_DECIMAL:
2699             case NUM_BIG_INT:
2700             case NUM_INT:
2701             case NUM_LONG:
2702                 return expression(node);
2703 
2704             default:
2705                 UnaryPlusExpression unaryPlusExpression = new UnaryPlusExpression(expression(node));
2706                 configureAST(unaryPlusExpression, unaryPlusExpr);
2707                 return unaryPlusExpression;
2708         }
2709     }
2710 
2711     protected ConstantExpression decimalExpression(AST node) {
2712         String text = node.getText();
2713         ConstantExpression constantExpression = new ConstantExpression(Numbers.parseDecimal(text));
2714         configureAST(constantExpression, node);
2715         return constantExpression;
2716     }
2717 
2718     protected ConstantExpression integerExpression(AST node) {
2719         String text = node.getText();
2720         Object number = Numbers.parseInteger(text);
2721         ConstantExpression constantExpression = new ConstantExpression(number, number instanceof Integer);
2722         configureAST(constantExpression, node);
2723         return constantExpression;
2724     }
2725 
2726     protected Expression gstring(AST gstringNode) {
2727         List strings = new ArrayList();
2728         List values = new ArrayList();
2729 
2730         StringBuffer buffer = new StringBuffer();
2731 
2732         boolean isPrevString = false;
2733 
2734         for (AST node = gstringNode.getFirstChild(); node != null; node = node.getNextSibling()) {
2735             int type = node.getType();
2736             String text = null;
2737             switch (type) {
2738 
2739                 case STRING_LITERAL:
2740                     if (isPrevString) assertNodeType(IDENT, node);  // parser bug
2741                     isPrevString = true;
2742                     text = node.getText();
2743                     ConstantExpression constantExpression = new ConstantExpression(text);
2744                     configureAST(constantExpression, node);
2745                     strings.add(constantExpression);
2746                     buffer.append(text);
2747                     break;
2748 
2749                 default: {
2750                     if (!isPrevString) assertNodeType(IDENT, node);  // parser bug
2751                     isPrevString = false;
2752                     Expression expression = expression(node);
2753                     values.add(expression);
2754                     buffer.append("$");
2755                     buffer.append(expression.getText());
2756                 }
2757                 break;
2758             }
2759         }
2760         GStringExpression gStringExpression = new GStringExpression(buffer.toString(), strings, values);
2761         configureAST(gStringExpression, gstringNode);
2762         return gStringExpression;
2763     }
2764 
2765     protected ClassNode type(AST typeNode) {
2766 previous bug bug overview next bug           // TODO intern types? 
2767 previous bug bug overview next bug           // TODO configureAST(...) 
2768         return buildName(typeNode.getFirstChild());
2769     }
2770 
2771     public static String qualifiedName(AST qualifiedNameNode) {
2772         if (isType(IDENT, qualifiedNameNode)) {
2773             return qualifiedNameNode.getText();
2774         }
2775         if (isType(DOT, qualifiedNameNode)) {
2776             AST node = qualifiedNameNode.getFirstChild();
2777             StringBuffer buffer = new StringBuffer();
2778             boolean first = true;
2779 
2780             for (; node != null && !isType(TYPE_ARGUMENTS, node); node = node.getNextSibling()) {
2781                 if (first) {
2782                     first = false;
2783                 } else {
2784                     buffer.append(".");
2785                 }
2786                 buffer.append(qualifiedName(node));
2787             }
2788             return buffer.toString();
2789         } else {
2790             return qualifiedNameNode.getText();
2791         }
2792     }
2793 
2794     private static AST getTypeArgumentsNode(AST root) {
2795         while (root != null && !isType(TYPE_ARGUMENTS, root)) {
2796             root = root.getNextSibling();
2797         }
2798         return root;
2799     }
2800 
2801     private int getBoundType(AST node) {
2802         if (node == null) return -1;
2803         if (isType(TYPE_UPPER_BOUNDS, node)) return TYPE_UPPER_BOUNDS;
2804         if (isType(TYPE_LOWER_BOUNDS, node)) return TYPE_LOWER_BOUNDS;
2805         throw new ASTRuntimeException(node,
2806                 "Unexpected node type: " + getTokenName(node) +
2807                         " found when expecting type: " + getTokenName(TYPE_UPPER_BOUNDS) +
2808                         " or type: " + getTokenName(TYPE_LOWER_BOUNDS));
2809     }
2810 
2811     private GenericsType makeGenericsArgumentType(AST typeArgument) {
2812         GenericsType gt;
2813         AST rootNode = typeArgument.getFirstChild();
2814         if (isType(WILDCARD_TYPE, rootNode)) {
2815             ClassNode base = ClassHelper.makeWithoutCaching("?");
2816             if (rootNode.getNextSibling() != null) {
2817                 int boundType = getBoundType(rootNode.getNextSibling());
2818                 ClassNode[] gts = makeGenericsBounds(rootNode, boundType);
2819                 if (boundType == TYPE_UPPER_BOUNDS) {
2820                     gt = new GenericsType(base, gts, null);
2821                 } else {
2822                     gt = new GenericsType(base, null, gts[0]);
2823                 }
2824             } else {
2825                 gt = new GenericsType(base, null, null);
2826             }
2827             gt.setName("?");
2828             gt.setWildcard(true);
2829         } else {
2830             ClassNode argument = makeTypeWithArguments(rootNode);
2831             gt = new GenericsType(argument);
2832         }
2833         configureAST(gt, typeArgument);
2834         return gt;
2835     }
2836 
2837     protected ClassNode makeTypeWithArguments(AST rootNode) {
2838         ClassNode basicType = makeType(rootNode);
2839         AST node = rootNode.getFirstChild();
2840         if (node == null || isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) return basicType;
2841 
2842         if (!isType(DOT, node)) {
2843             node = node.getFirstChild();
2844             if (node == null) return basicType;
2845             return addTypeArguments(basicType, node);
2846         } else {
2847             node = node.getFirstChild();
2848 previous bug bug overview next bug               while (node != null && !isType(TYPE_ARGUMENTS, node))  HEALTH4J >>  :  WhileLoopsMustUseBraces 
2849                 node = node.getNextSibling();
2850             return node == null ? basicType : addTypeArguments(basicType, node);
2851         }
2852     }
2853 
2854     private ClassNode addTypeArguments(ClassNode basicType, AST node) {
2855         List<GenericsType> typeArgumentList = getTypeArgumentsList(node);
2856         if (typeArgumentList.size() > 0) {
2857             basicType.setGenericsTypes(typeArgumentList.toArray(new GenericsType[typeArgumentList.size()]));
2858         }
2859         return basicType;
2860     }
2861 
2862     private List<GenericsType> getTypeArgumentsList(AST node) {
2863         assertNodeType(TYPE_ARGUMENTS, node);
2864         List<GenericsType> typeArgumentList = new LinkedList<GenericsType>();
2865         AST typeArgument = node.getFirstChild();
2866 
2867         while (typeArgument != null) {
2868             assertNodeType(TYPE_ARGUMENT, typeArgument);
2869             GenericsType gt = makeGenericsArgumentType(typeArgument);
2870             typeArgumentList.add(gt);
2871             typeArgument = typeArgument.getNextSibling();
2872         }
2873         return typeArgumentList;
2874     }
2875 
2876     private ClassNode[] makeGenericsBounds(AST rn, int boundType) {
2877         AST boundsRoot = rn.getNextSibling();
2878         if (boundsRoot == null) return null;
2879         assertNodeType(boundType, boundsRoot);
2880         LinkedList bounds = new LinkedList();
2881         for (AST boundsNode = boundsRoot.getFirstChild();
2882              boundsNode != null;
2883              boundsNode = boundsNode.getNextSibling()
2884                 ) {
2885             ClassNode bound = null;
2886             bound = makeTypeWithArguments(boundsNode);
2887             configureAST(bound, boundsNode);
2888             bounds.add(bound);
2889         }
2890         if (bounds.size() == 0) return null;
2891         return (ClassNode[]) bounds.toArray(new ClassNode[bounds.size()]);
2892     }
2893 
2894     protected GenericsType[] makeGenericsType(AST rootNode) {
2895         AST typeParameter = rootNode.getFirstChild();
2896         LinkedList ret = new LinkedList();
2897         assertNodeType(TYPE_PARAMETER, typeParameter);
2898 
2899         while (isType(TYPE_PARAMETER, typeParameter)) {
2900             AST typeNode = typeParameter.getFirstChild();
2901             ClassNode type = makeType(typeParameter);
2902 
2903             GenericsType gt = new GenericsType(type, makeGenericsBounds(typeNode, TYPE_UPPER_BOUNDS), null);
2904             configureAST(gt, typeParameter);
2905 
2906             ret.add(gt);
2907             typeParameter = typeParameter.getNextSibling();
2908         }
2909         return (GenericsType[]) ret.toArray(new GenericsType[0]);
2910     }
2911 
2912     protected ClassNode makeType(AST typeNode) {
2913         ClassNode answer = ClassHelper.DYNAMIC_TYPE;
2914         AST node = typeNode.getFirstChild();
2915         if (node != null) {
2916             if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
2917                 answer = makeType(node).makeArray();
2918             } else {
2919                 answer = ClassHelper.make(qualifiedName(node));
2920                 if (answer.isUsingGenerics()) {
2921                     ClassNode newAnswer = ClassHelper.makeWithoutCaching(answer.getName());
2922                     newAnswer.setRedirect(answer);
2923                     answer = newAnswer;
2924                 }
2925             }
2926             configureAST(answer, node);
2927         }
2928         return answer;
2929     }
2930 
2931     /**
2932      * Performs a name resolution to see if the given name is a type from imports,
2933      * aliases or newly created classes
2934      */
2935     /*protected String resolveTypeName(String name, boolean safe) {
2936         if (name == null) {
2937             return null;
2938         }
2939         return resolveNewClassOrName(name, safe);
2940     }*/
2941 
2942     /**
2943      * Extracts an identifier from the Antlr AST and then performs a name resolution
2944      * to see if the given name is a type from imports, aliases or newly created classes
2945      */
2946     protected ClassNode buildName(AST node) {
2947         if (isType(TYPE, node)) {
2948             node = node.getFirstChild();
2949         }
2950         ClassNode answer = null;
2951         if (isType(DOT, node) || isType(OPTIONAL_DOT, node)) {
2952             answer = ClassHelper.make(qualifiedName(node));
2953         } else if (isPrimitiveTypeLiteral(node)) {
2954             answer = ClassHelper.make(node.getText());
2955         } else if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
2956             AST child = node.getFirstChild();
2957             answer = buildName(child).makeArray();
2958             configureAST(answer, node);
2959             return answer;
2960         } else {
2961             String identifier = node.getText();
2962             answer = ClassHelper.make(identifier);
2963         }
2964         AST nextSibling = node.getNextSibling();
2965         if (isType(INDEX_OP, nextSibling) || isType(ARRAY_DECLARATOR, node)) {
2966             answer = answer.makeArray();
2967             configureAST(answer, node);
2968             return answer;
2969         } else {
2970             configureAST(answer, node);
2971             return answer;
2972         }
2973     }
2974 
2975     protected boolean isPrimitiveTypeLiteral(AST node) {
2976         int type = node.getType();
2977         switch (type) {
2978             case LITERAL_boolean:
2979             case LITERAL_byte:
2980             case LITERAL_char:
2981             case LITERAL_double:
2982             case LITERAL_float:
2983             case LITERAL_int:
2984             case LITERAL_long:
2985             case LITERAL_short:
2986                 return true;
2987 
2988             default:
2989                 return false;
2990         }
2991     }
2992 
2993     /**
2994      * Extracts an identifier from the Antlr AST
2995      */
2996     protected String identifier(AST node) {
2997         assertNodeType(IDENT, node);
2998         return node.getText();
2999     }
3000 
3001     protected String label(AST labelNode) {
3002         AST node = labelNode.getFirstChild();
3003         if (node == null) {
3004             return null;
3005         }
3006         return identifier(node);
3007     }
3008 
3009 
3010     // Helper methods
3011     //-------------------------------------------------------------------------
3012 
3013 
3014     /**
3015      * Returns true if the modifiers flags contain a visibility modifier
3016      */
3017     protected boolean hasVisibility(int modifiers) {
3018         return (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) != 0;
3019     }
3020 
3021     protected void configureAST(ASTNode node, AST ast) {
3022         if (ast == null)
3023             throw new ASTRuntimeException(ast, "PARSER BUG: Tried to configure " + node.getClass().getName() + " with null Node");
3024         node.setColumnNumber(ast.getColumn());
3025         node.setLineNumber(ast.getLine());
3026         if (ast instanceof GroovySourceAST) {
3027             node.setLastColumnNumber(((GroovySourceAST) ast).getColumnLast());
3028             node.setLastLineNumber(((GroovySourceAST) ast).getLineLast());
3029         }
3030 
3031 previous bug bug overview next bug           // TODO we could one day store the Antlr AST on the Groovy AST 
3032         // node.setCSTNode(ast);
3033     }
3034 
3035     protected static Token makeToken(int typeCode, AST node) {
3036         return Token.newSymbol(typeCode, node.getLine(), node.getColumn());
3037     }
3038 
3039     protected String getFirstChildText(AST node) {
3040         AST child = node.getFirstChild();
3041         return child != null ? child.getText() : null;
3042     }
3043 
3044 
3045     public static boolean isType(int typeCode, AST node) {
3046         return node != null && node.getType() == typeCode;
3047     }
3048 
3049     private String getTokenName(int token) {
3050         if (tokenNames == null) return "" + token;
3051         return tokenNames[token];
3052     }
3053 
3054     private String getTokenName(AST node) {
3055         if (node == null) return "null";
3056         return getTokenName(node.getType());
3057     }
3058 
3059     protected void assertNodeType(int type, AST node) {
3060         if (node == null) {
3061             throw new ASTRuntimeException(node, "No child node available in AST when expecting type: " + getTokenName(type));
3062         }
3063         if (node.getType() != type) {
3064             throw new ASTRuntimeException(node, "Unexpected node type: " + getTokenName(node) + " found when expecting type: " + getTokenName(type));
3065         }
3066     }
3067 
3068     protected void notImplementedYet(AST node) {
3069         throw new ASTRuntimeException(node, "AST node not implemented yet for type: " + getTokenName(node));
3070     }
3071 
3072     protected void unknownAST(AST node) {
3073         if (node.getType() == CLASS_DEF) {
3074             throw new ASTRuntimeException(node,
3075                     "Class definition not expected here. Please define the class at an appropriate place or perhaps try using a block/Closure instead.");
3076         }
3077         if (node.getType() == METHOD_DEF) {
3078             throw new ASTRuntimeException(node,
3079                     "Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead.");
3080         }
3081         throw new ASTRuntimeException(node, "Unknown type: " + getTokenName(node));
3082     }
3083 
3084     protected void dumpTree(AST ast) {
3085         for (AST node = ast.getFirstChild(); node != null; node = node.getNextSibling()) {
3086             dump(node);
3087         }
3088     }
3089 
3090     protected void dump(AST node) {
3091 previous bug bug overview           System.out.println("Type: " + getTokenName(node) + " text: " + node.getText());  HEALTH4J >>  :  SystemPrintln 
3092     }
3093 }