View Javadoc

1   /*
2   $Id: AsmClassGenerator.java 4598 2006-12-22 20:21:21Z blackdrag $
3   
4   Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6   Redistribution and use of this software and associated documentation
7   ("Software"), with or without modification, are permitted provided
8   that the following conditions are met:
9   
10  1. Redistributions of source code must retain copyright
11     statements and notices.  Redistributions must also contain a
12     copy of this document.
13  
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18  
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus.  For written permission,
22     please contact info@codehaus.org.
23  
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28  
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31  
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44  */
45  
46  package org.codehaus.groovy.classgen;
47  
48  import groovy.lang.GroovyObject;
49  import groovy.lang.GroovyRuntimeException;
50  
51  import java.util.ArrayList;
52  import java.util.Collections;
53  import java.util.Comparator;
54  import java.util.HashSet;
55  import java.util.Iterator;
56  import java.util.LinkedList;
57  import java.util.List;
58  import java.util.Map;
59  import java.util.Set;
60  import java.util.logging.Logger;
61  
62  import org.codehaus.groovy.GroovyBugError;
63  import org.codehaus.groovy.ast.ASTNode;
64  import org.codehaus.groovy.ast.AnnotatedNode;
65  import org.codehaus.groovy.ast.AnnotationNode;
66  import org.codehaus.groovy.ast.ClassHelper;
67  import org.codehaus.groovy.ast.ClassNode;
68  import org.codehaus.groovy.ast.CompileUnit;
69  import org.codehaus.groovy.ast.ConstructorNode;
70  import org.codehaus.groovy.ast.FieldNode;
71  import org.codehaus.groovy.ast.InnerClassNode;
72  import org.codehaus.groovy.ast.MethodNode;
73  import org.codehaus.groovy.ast.Parameter;
74  import org.codehaus.groovy.ast.PropertyNode;
75  import org.codehaus.groovy.ast.VariableScope;
76  import org.codehaus.groovy.ast.expr.ArgumentListExpression;
77  import org.codehaus.groovy.ast.expr.ArrayExpression;
78  import org.codehaus.groovy.ast.expr.AttributeExpression;
79  import org.codehaus.groovy.ast.expr.BinaryExpression;
80  import org.codehaus.groovy.ast.expr.BitwiseNegExpression;
81  import org.codehaus.groovy.ast.expr.BooleanExpression;
82  import org.codehaus.groovy.ast.expr.CastExpression;
83  import org.codehaus.groovy.ast.expr.ClassExpression;
84  import org.codehaus.groovy.ast.expr.ClosureExpression;
85  import org.codehaus.groovy.ast.expr.ConstantExpression;
86  import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
87  import org.codehaus.groovy.ast.expr.DeclarationExpression;
88  import org.codehaus.groovy.ast.expr.Expression;
89  import org.codehaus.groovy.ast.expr.ExpressionTransformer;
90  import org.codehaus.groovy.ast.expr.FieldExpression;
91  import org.codehaus.groovy.ast.expr.GStringExpression;
92  import org.codehaus.groovy.ast.expr.ListExpression;
93  import org.codehaus.groovy.ast.expr.MapEntryExpression;
94  import org.codehaus.groovy.ast.expr.MapExpression;
95  import org.codehaus.groovy.ast.expr.MethodCallExpression;
96  import org.codehaus.groovy.ast.expr.MethodPointerExpression;
97  import org.codehaus.groovy.ast.expr.NegationExpression;
98  import org.codehaus.groovy.ast.expr.NotExpression;
99  import org.codehaus.groovy.ast.expr.PostfixExpression;
100 import org.codehaus.groovy.ast.expr.PrefixExpression;
101 import org.codehaus.groovy.ast.expr.PropertyExpression;
102 import org.codehaus.groovy.ast.expr.RangeExpression;
103 import org.codehaus.groovy.ast.expr.RegexExpression;
104 import org.codehaus.groovy.ast.expr.SpreadExpression;
105 import org.codehaus.groovy.ast.expr.SpreadMapExpression;
106 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
107 import org.codehaus.groovy.ast.expr.TernaryExpression;
108 import org.codehaus.groovy.ast.expr.TupleExpression;
109 import org.codehaus.groovy.ast.expr.VariableExpression;
110 import org.codehaus.groovy.ast.stmt.AssertStatement;
111 import org.codehaus.groovy.ast.stmt.BlockStatement;
112 import org.codehaus.groovy.ast.stmt.BreakStatement;
113 import org.codehaus.groovy.ast.stmt.CaseStatement;
114 import org.codehaus.groovy.ast.stmt.CatchStatement;
115 import org.codehaus.groovy.ast.stmt.ContinueStatement;
116 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
117 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
118 import org.codehaus.groovy.ast.stmt.ForStatement;
119 import org.codehaus.groovy.ast.stmt.IfStatement;
120 import org.codehaus.groovy.ast.stmt.ReturnStatement;
121 import org.codehaus.groovy.ast.stmt.Statement;
122 import org.codehaus.groovy.ast.stmt.SwitchStatement;
123 import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
124 import org.codehaus.groovy.ast.stmt.ThrowStatement;
125 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
126 import org.codehaus.groovy.ast.stmt.WhileStatement;
127 import org.codehaus.groovy.control.SourceUnit;
128 import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
129 import org.codehaus.groovy.syntax.RuntimeParserException;
130 import org.codehaus.groovy.syntax.Types;
131 import org.objectweb.asm.AnnotationVisitor;
132 import org.objectweb.asm.ClassVisitor;
133 import org.objectweb.asm.ClassWriter;
134 import org.objectweb.asm.Label;
135 import org.objectweb.asm.MethodVisitor;
136 import org.objectweb.asm.Opcodes;
137 
138 
139 /***
140  * Generates Java class versions of Groovy classes using ASM.
141  *
142  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
143  * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
144  * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
145  *
146  * @version $Revision: 4598 $
147  */
148 public class AsmClassGenerator extends ClassGenerator {
149 
150     private Logger log = Logger.getLogger(getClass().getName());
151 
152     private ClassVisitor cw;
153     private MethodVisitor cv;
154     private GeneratorContext context;
155 
156     private String sourceFile;
157 
158     // current class details
159     private ClassNode classNode;
160     private ClassNode outermostClass;
161     private String internalClassName;
162     private String internalBaseClassName;
163 
164     /*** maps the variable names to the JVM indices */
165     private CompileStack compileStack;
166 
167     /*** have we output a return statement yet */
168     private boolean outputReturn;
169 
170     /*** are we on the left or right of an expression */
171     private boolean leftHandExpression=false;
172     /***
173      * Notes for leftHandExpression:
174      * The default is false, that menas the right side is default.
175      * The right side means that variables are read and not written.
176      * Any change of leftHandExpression to true, should be made carefully.
177      * If such a change is needed, then it should be set to false as soon as
178      * possible, but most important in the same method. Setting 
179      * leftHandExpression to false is needed for writing variables.
180      */
181 
182     // method invocation
183     MethodCallerMultiAdapter invokeMethodOnCurrent = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeMethodOnCurrent",true,false);
184     MethodCallerMultiAdapter invokeMethodOnSuper   = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeMethodOnSuper",true,false);
185     MethodCallerMultiAdapter invokeMethod          = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeMethod",true,false);
186     MethodCallerMultiAdapter invokeStaticMethod    = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeStaticMethod",true,true);
187     MethodCallerMultiAdapter invokeNew             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeNew",true,true);
188     
189     // fields & properties
190     MethodCallerMultiAdapter setField             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setField",false,false);
191     MethodCallerMultiAdapter getField             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getField",false,false);
192     MethodCallerMultiAdapter setGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setGroovyObjectField",false,false);
193     MethodCallerMultiAdapter getGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getGroovyObjectField",false,false);
194     MethodCallerMultiAdapter setFieldOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setFieldOnSuper",false,false);
195     MethodCallerMultiAdapter getFieldOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getFieldOnSuper",false,false);
196     
197     MethodCallerMultiAdapter setProperty             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setProperty",false,false);
198     MethodCallerMultiAdapter getProperty             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getProperty",false,false);
199     MethodCallerMultiAdapter setGroovyObjectProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setGroovyObjectProperty",false,false);
200     MethodCallerMultiAdapter getGroovyObjectProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getGroovyObjectProperty",false,false);
201     MethodCallerMultiAdapter setPropertyOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setPropertyOnSuper",false,false);
202     MethodCallerMultiAdapter getPropertyOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getPropertyOnSuper",false,false);
203     
204     // iterator
205     MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator.class, "next");
206     MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator.class, "hasNext");
207     // assert
208     MethodCaller assertFailedMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "assertFailed");
209     // isCase
210     MethodCaller isCaseMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "isCase");
211     //compare
212     MethodCaller compareIdenticalMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareIdentical");
213     MethodCaller compareEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareEqual");
214     MethodCaller compareNotEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareNotEqual");
215     MethodCaller compareToMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareTo");
216     MethodCaller compareLessThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThan");
217     MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThanEqual");
218     MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThan");
219     MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThanEqual");
220     //regexpr
221     MethodCaller findRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "findRegex");
222     MethodCaller matchRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "matchRegex");
223     MethodCaller regexPattern = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "regexPattern");
224     // spread expressions
225     MethodCaller spreadMap = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "spreadMap");
226     MethodCaller despreadList = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "despreadList");
227     // Closure
228     MethodCaller getMethodPointer = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getMethodPointer");
229     MethodCaller invokeClosureMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeClosure");
230     //negation
231     MethodCaller negation = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "negate");
232     MethodCaller bitNegation = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "bitNegate");
233 
234     // type converions
235     MethodCaller asTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asType");
236     MethodCaller castToTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "castToType");
237     MethodCaller createListMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createList");
238     MethodCaller createTupleMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createTuple");
239     MethodCaller createMapMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createMap");
240     MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange");
241     
242     // wrapper creation methods
243     MethodCaller createPojoWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createPojoWrapper");
244     MethodCaller createGroovyObjectWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createGroovyObjectWrapper");
245 
246     // constructor calls with this() and super()
247     MethodCaller selectConstructorAndTransformArguments = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "selectConstructorAndTransformArguments");
248  
249     // exception blocks list
250     private List exceptionBlocks = new ArrayList();    
251     
252     private Set syntheticStaticFields = new HashSet();
253     private boolean passingClosureParams;
254 
255     private ConstructorNode constructorNode;
256     private MethodNode methodNode;
257     private BytecodeHelper helper = new BytecodeHelper(null);
258 
259     public static final boolean CREATE_DEBUG_INFO = true;
260     public static final boolean CREATE_LINE_NUMBER_INFO = true;
261     private static final boolean MARK_START = true;
262 
263     public static final boolean ASM_DEBUG = false; // add marker in the bytecode to show source-byecode relationship
264     private int lineNumber = -1;
265     private int columnNumber = -1;
266     private ASTNode currentASTNode = null;
267 
268     private DummyClassGenerator dummyGen = null;
269     private ClassWriter dummyClassWriter = null;
270     
271     private ClassNode interfaceClassLoadingClass;
272 
273     private boolean implicitThis = false;
274 
275     public AsmClassGenerator(
276             GeneratorContext context, ClassVisitor classVisitor,
277             ClassLoader classLoader, String sourceFile
278     ) {
279         super(classLoader);
280         this.context = context;
281         this.cw = classVisitor;
282         this.sourceFile = sourceFile;
283 
284         this.dummyClassWriter = new ClassWriter(true);
285         dummyGen  = new DummyClassGenerator(context, dummyClassWriter, classLoader, sourceFile);
286         compileStack = new CompileStack();
287 
288     }
289     
290     protected SourceUnit getSourceUnit() {
291         return null;
292     }
293 
294     // GroovyClassVisitor interface
295     //-------------------------------------------------------------------------
296     public void visitClass(ClassNode classNode) {
297         // todo to be tested
298         // createDummyClass(classNode);
299 
300         try {
301             syntheticStaticFields.clear();
302             this.classNode = classNode;
303             this.outermostClass = null;
304             this.internalClassName = BytecodeHelper.getClassInternalName(classNode);
305 
306             this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
307 
308             cw.visit(
309                 asmJDKVersion,
310                 classNode.getModifiers(),
311                 internalClassName,
312                 null,
313                 internalBaseClassName,
314                 BytecodeHelper.getClassInternalNames(classNode.getInterfaces())
315             );            
316             cw.visitSource(sourceFile,null);
317             
318             if (classNode.isInterface()) {
319                 ClassNode owner = classNode;
320                 if (owner instanceof InnerClassNode) {
321                     owner = owner.getOuterClass();
322                 }
323                 String outerClassName = owner.getName();
324                 String name = outerClassName + "$" + context.getNextInnerClassIdx();
325                 interfaceClassLoadingClass = new InnerClassNode(owner, name, 4128, ClassHelper.OBJECT_TYPE);
326                 
327                 super.visitClass(classNode);
328                 createInterfaceSyntheticStaticFields();                
329             } else {
330                 super.visitClass(classNode);
331                 createMopMethods();
332                 createSyntheticStaticFields();
333             }
334             
335             for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
336                 ClassNode innerClass = (ClassNode) iter.next();
337                 String innerClassName = innerClass.getName();
338                 String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
339                 {
340                     int index = innerClassName.lastIndexOf('$');
341                     if (index>=0) innerClassName = innerClassName.substring(index+1);
342                 }
343                 String outerClassName = internalClassName; // default for inner classes
344                 MethodNode enclosingMethod = innerClass.getEnclosingMethod();
345                 if (enclosingMethod != null) {
346                     // local inner classes do not specify the outer class name
347                     outerClassName = null;
348                     innerClassName = null;
349                 }
350                 cw.visitInnerClass(
351                     innerClassInternalName,
352                     outerClassName,
353                     innerClassName,
354                     innerClass.getModifiers());
355             }
356             //TODO: an inner class should have an entry of itself
357             cw.visitEnd();
358         }
359         catch (GroovyRuntimeException e) {
360             e.setModule(classNode.getModule());
361             throw e;
362         }
363     }
364    
365     private void createMopMethods() {
366         visitMopMethodList(classNode.getMethods(), true);
367         visitMopMethodList(classNode.getSuperClass().getAllDeclaredMethods(), false);
368     }
369 
370     private String[] buildExceptions(ClassNode[] exceptions) {
371         if (exceptions==null) return null;
372         String[] ret = new String[exceptions.length];
373         for (int i = 0; i < exceptions.length; i++) {
374             ret[i] = BytecodeHelper.getClassInternalName(exceptions[i]);
375         }
376         return ret;
377     }
378     
379     /***
380      * filters a list of method for MOP methods. For all methods that are no 
381      * MOP methods a MOP method is created if the method is not public and the
382      * call would be a call on "this" (isThis == true). If the call is not on
383      * "this", then the call is a call on "super" and all methods are used, 
384      * unless they are already a MOP method
385      *  
386      * @see #generateMopCalls(LinkedList, boolean)
387      *  
388      * @param methods unfiltered list of methods for MOP 
389      * @param isThis  if true, then we are creating a MOP method on "this", "super" else 
390      */
391     private void visitMopMethodList(List methods, boolean isThis){
392         LinkedList mopCalls = new LinkedList();
393         for (Iterator iter = methods.iterator(); iter.hasNext();) {
394             MethodNode mn = (MethodNode) iter.next();
395             if ((mn.getModifiers() & ACC_ABSTRACT) !=0 ) continue;
396             // no this$ methods for protected/public isThis=true
397             // super$ method for protected/public isThis=false
398             // --> results in XOR
399             if (isThis ^ (mn.getModifiers() & (ACC_PUBLIC|ACC_PROTECTED)) == 0) continue; 
400             String methodName = mn.getName();
401             if (isMopMethod(methodName) || methodName.startsWith("<")) continue;
402             String name = getMopMethodName(mn,isThis);
403             if (containsMethod(methods,name,mn.getParameters())) continue;
404             mopCalls.add(mn);
405         }
406         generateMopCalls(mopCalls, isThis);
407         mopCalls.clear();
408     }
409     
410     private boolean containsMethod(List methods, String name, Parameter[] paras) {
411         for (Iterator iter = methods.iterator(); iter.hasNext();) {
412             MethodNode element = (MethodNode) iter.next();
413             if (element.getName().equals(name) && equalParameterTypes(paras,element.getParameters())) return true;
414         }
415         return false;
416     }
417     
418     private boolean equalParameterTypes(Parameter[] p1, Parameter[] p2) {
419         if (p1.length!=p2.length) return false;
420         for (int i=0; i<p1.length; i++) {
421             if (!p1[i].getType().equals(p2[i].getType())) return false;
422         }
423         return true;
424     }
425     
426     /***
427      * generates a Meta Object Protocoll method, that is used to call a non public
428      * method, or to make a call to super.
429      * @param mopCalls list of methods a mop call method should be generated for
430      * @param useThis true if "this" should be used for the naming
431      */
432     private void generateMopCalls(LinkedList mopCalls, boolean useThis) {
433         for (Iterator iter = mopCalls.iterator(); iter.hasNext();) {
434             MethodNode method = (MethodNode) iter.next();
435             String name = getMopMethodName(method,useThis);
436             Parameter[] parameters = method.getParameters();
437             String methodDescriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameters());
438             cv = cw.visitMethod(Opcodes.ACC_PUBLIC & Opcodes.ACC_SYNTHETIC, name, methodDescriptor, null, null);
439             cv.visitVarInsn(ALOAD,0);
440             BytecodeHelper helper = new BytecodeHelper(cv);
441             int newRegister = 1;
442             for (int i=0; i<parameters.length; i++) {
443                 ClassNode type = parameters[i].getType();
444                 helper.load(parameters[i].getType(),newRegister);
445                 // increment to next register, double/long are using two places
446                 newRegister++;
447                 if (type == ClassHelper.double_TYPE || type == ClassHelper.long_TYPE) newRegister++;
448             }
449             cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(method.getDeclaringClass()), method.getName(), methodDescriptor); 
450             helper.doReturn(method.getReturnType());
451             cv.visitMaxs(0, 0);
452             cv.visitEnd();
453             classNode.addMethod(name,Opcodes.ACC_PUBLIC & Opcodes.ACC_SYNTHETIC,method.getReturnType(),parameters,null,null);
454         }
455     }
456 
457     /***
458      * creates a MOP method name from a method
459      * @param method the method to be called by the mop method
460      * @param useThis if true, then it is a call on "this", "super" else
461      * @return the mop method name
462      */
463     public static String getMopMethodName(MethodNode method, boolean useThis) {
464         ClassNode declaringNode = method.getDeclaringClass();
465         int distance = 0;
466         for (;declaringNode!=null; declaringNode=declaringNode.getSuperClass()) {
467             distance++;
468         }
469         return (useThis?"this":"super")+"$"+distance+"$"+method.getName();
470     }
471    
472     /***
473      * method to determine if a method is a MOP method. This is done by the
474      * method name. If the name starts with "this$" or "super$", then it is
475      * a MOP method
476      * @param methodName name of the method to test
477      * @return true if the method is a MOP method
478      */
479     public static boolean isMopMethod(String methodName) {
480         return  methodName.startsWith("this$") || 
481                 methodName.startsWith("super$");
482     }
483     
484     protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
485         String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
486 
487         cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, buildExceptions(node.getExceptions()));
488         helper = new BytecodeHelper(cv);
489         if (!node.isAbstract()) { 
490             Statement code = node.getCode();
491             if (isConstructor && (code == null || !firstStatementIsSpecialConstructorCall(node))) {
492                 // invokes the super class constructor
493                 cv.visitVarInsn(ALOAD, 0);
494                 cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", "()V");
495             }
496             
497             compileStack.init(node.getVariableScope(),node.getParameters(),cv, classNode);
498             
499             // ensure we save the current (meta) class in a register
500             (new ClassExpression(classNode)).visit(this);
501             cv.visitInsn(POP);
502             (new ClassExpression(ClassHelper.METACLASS_TYPE)).visit(this);
503             cv.visitInsn(POP);
504             
505             // handle body
506             super.visitConstructorOrMethod(node, isConstructor);
507             if (!outputReturn || node.isVoidMethod()) {
508                 cv.visitInsn(RETURN);
509             }
510             compileStack.clear();
511             
512             // lets do all the exception blocks
513             for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) {
514                 Runnable runnable = (Runnable) iter.next();
515                 runnable.run();
516             }
517             exceptionBlocks.clear();
518     
519             cv.visitMaxs(0, 0);
520         }
521     }
522 
523     private boolean firstStatementIsSpecialConstructorCall(MethodNode node) {
524         Statement code = node.getFirstStatement();
525         if (code == null || !(code instanceof ExpressionStatement)) return false;
526 
527         Expression expression = ((ExpressionStatement)code).getExpression();
528         if (!(expression instanceof ConstructorCallExpression)) return false;
529         ConstructorCallExpression cce = (ConstructorCallExpression) expression;
530         return cce.isSpecialCall();
531     }
532 
533     public void visitConstructor(ConstructorNode node) {
534         this.constructorNode = node;
535         this.methodNode = null;
536         outputReturn = false;
537         super.visitConstructor(node);
538     }
539 
540     public void visitMethod(MethodNode node) {
541         this.constructorNode = null;
542         this.methodNode = node;
543         outputReturn = false;
544         
545         super.visitMethod(node);
546     }
547 
548     public void visitField(FieldNode fieldNode) {
549         onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
550         ClassNode t = fieldNode.getType();
551         cw.visitField(
552             fieldNode.getModifiers(),
553             fieldNode.getName(),
554             BytecodeHelper.getTypeDescription(t),
555             null, //fieldValue,  //br  all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
556             null);
557         visitAnnotations(fieldNode);
558     }
559 
560     public void visitProperty(PropertyNode statement) {
561         // the verifyer created the field and the setter/getter methods, so here is
562         // not really something to do
563         onLineNumber(statement, "visitProperty:" + statement.getField().getName());
564         this.methodNode = null;
565     }
566 
567     // GroovyCodeVisitor interface
568     //-------------------------------------------------------------------------
569 
570     // Statements
571     //-------------------------------------------------------------------------
572 
573     protected void visitStatement(Statement statement) {
574         String name = statement.getStatementLabel();
575         if (name!=null) {
576             Label label = compileStack.createLocalLabel(name);
577             cv.visitLabel(label);
578         }
579     }
580     
581     public void visitBlockStatement(BlockStatement block) {
582         onLineNumber(block, "visitBlockStatement");
583         visitStatement(block);
584         
585         compileStack.pushVariableScope(block.getVariableScope());
586         super.visitBlockStatement(block);
587         compileStack.pop();
588     }
589 
590     public void visitForLoop(ForStatement loop) {
591         onLineNumber(loop, "visitForLoop");
592         visitStatement(loop);
593 
594         compileStack.pushLoop(loop.getVariableScope(),loop.getStatementLabel());
595 
596         //
597         // Declare the loop counter.
598         Variable variable = compileStack.defineVariable(loop.getVariable(),false);
599 
600         //
601         // Then get the iterator and generate the loop control
602         MethodCallExpression iterator = new MethodCallExpression(loop.getCollectionExpression(),"iterator",new ArgumentListExpression());
603         iterator.visit(this);
604 
605         final int iteratorIdx = compileStack.defineTemporaryVariable("iterator", ClassHelper.make(java.util.Iterator.class),true);
606 
607         Label continueLabel = compileStack.getContinueLabel();
608         Label breakLabel = compileStack.getBreakLabel();
609         
610         cv.visitLabel(continueLabel);
611         cv.visitVarInsn(ALOAD, iteratorIdx);
612         iteratorHasNextMethod.call(cv);
613         // note: ifeq tests for ==0, a boolean is 0 if it is false
614         cv.visitJumpInsn(IFEQ, breakLabel);
615         
616         cv.visitVarInsn(ALOAD, iteratorIdx);
617         iteratorNextMethod.call(cv);
618         helper.storeVar(variable);
619 
620         // Generate the loop body
621         loop.getLoopBlock().visit(this);
622 
623         cv.visitJumpInsn(GOTO, continueLabel);        
624         cv.visitLabel(breakLabel);
625         
626         compileStack.pop();
627     }
628 
629     public void visitWhileLoop(WhileStatement loop) {
630         onLineNumber(loop, "visitWhileLoop");
631         visitStatement(loop);
632 
633         compileStack.pushLoop(loop.getStatementLabel());
634         Label continueLabel = compileStack.getContinueLabel();
635         Label breakLabel = compileStack.getBreakLabel();
636         
637         cv.visitLabel(continueLabel);
638         loop.getBooleanExpression().visit(this);
639         cv.visitJumpInsn(IFEQ, breakLabel);
640         
641         loop.getLoopBlock().visit(this);
642         
643         cv.visitJumpInsn(GOTO, continueLabel);
644         cv.visitLabel(breakLabel);
645         
646         compileStack.pop();
647     }
648 
649     public void visitDoWhileLoop(DoWhileStatement loop) {
650         onLineNumber(loop, "visitDoWhileLoop");
651         visitStatement(loop);
652 
653         compileStack.pushLoop(loop.getStatementLabel());
654         Label breakLabel = compileStack.getBreakLabel();
655         Label continueLabel = compileStack.getContinueLabel();
656         cv.visitLabel(continueLabel);
657 
658         loop.getLoopBlock().visit(this);
659 
660         loop.getBooleanExpression().visit(this);
661         cv.visitJumpInsn(IFEQ, continueLabel);
662         cv.visitLabel(breakLabel);
663         
664         compileStack.pop();
665     }
666 
667     public void visitIfElse(IfStatement ifElse) {
668         onLineNumber(ifElse, "visitIfElse");
669         visitStatement(ifElse);
670         ifElse.getBooleanExpression().visit(this);
671         
672         Label l0 = new Label();
673         cv.visitJumpInsn(IFEQ, l0);
674 
675         ifElse.getIfBlock().visit(this);
676 
677         Label l1 = new Label();
678         cv.visitJumpInsn(GOTO, l1);
679         cv.visitLabel(l0);
680 
681         ifElse.getElseBlock().visit(this);
682         cv.visitLabel(l1);
683     }
684 
685     public void visitTernaryExpression(TernaryExpression expression) {
686         onLineNumber(expression, "visitTernaryExpression");
687 
688         expression.getBooleanExpression().visit(this);
689 
690         Label l0 = new Label();
691         cv.visitJumpInsn(IFEQ, l0);
692         visitAndAutoboxBoolean(expression.getTrueExpression());
693 
694         Label l1 = new Label();
695         cv.visitJumpInsn(GOTO, l1);
696         cv.visitLabel(l0);
697 
698         visitAndAutoboxBoolean(expression.getFalseExpression());
699         cv.visitLabel(l1);
700     }
701 
702     public void visitAssertStatement(AssertStatement statement) {
703         onLineNumber(statement, "visitAssertStatement");
704         visitStatement(statement);
705 
706         BooleanExpression booleanExpression = statement.getBooleanExpression();
707         booleanExpression.visit(this);
708 
709         Label l0 = new Label();
710         cv.visitJumpInsn(IFEQ, l0);
711 
712         // do nothing
713 
714         Label l1 = new Label();
715         cv.visitJumpInsn(GOTO, l1);
716         cv.visitLabel(l0);
717 
718         // push expression string onto stack
719         String expressionText = booleanExpression.getText();
720         List list = new ArrayList();
721         addVariableNames(booleanExpression, list);
722         if (list.isEmpty()) {
723             cv.visitLdcInsn(expressionText);
724         }
725         else {
726             boolean first = true;
727 
728             // lets create a new expression
729             cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
730             cv.visitInsn(DUP);
731             cv.visitLdcInsn(expressionText + ". Values: ");
732 
733             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
734 
735             int tempIndex = compileStack.defineTemporaryVariable("assert",true);
736 
737             for (Iterator iter = list.iterator(); iter.hasNext();) {
738                 String name = (String) iter.next();
739                 String text = name + " = ";
740                 if (first) {
741                     first = false;
742                 }
743                 else {
744                     text = ", " + text;
745                 }
746 
747                 cv.visitVarInsn(ALOAD, tempIndex);
748                 cv.visitLdcInsn(text);
749                 cv.visitMethodInsn(
750                     INVOKEVIRTUAL,
751                     "java/lang/StringBuffer",
752                     "append",
753                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
754                 cv.visitInsn(POP);
755 
756                 cv.visitVarInsn(ALOAD, tempIndex);
757                 new VariableExpression(name).visit(this);
758                 cv.visitMethodInsn(
759                     INVOKEVIRTUAL,
760                     "java/lang/StringBuffer",
761                     "append",
762                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
763                 cv.visitInsn(POP);
764 
765             }
766             cv.visitVarInsn(ALOAD, tempIndex);
767             compileStack.removeVar(tempIndex);
768         }
769         // now the optional exception expression
770         statement.getMessageExpression().visit(this);
771 
772         assertFailedMethod.call(cv);
773         cv.visitLabel(l1);
774     }
775 
776     private void addVariableNames(Expression expression, List list) {
777         if (expression instanceof BooleanExpression) {
778             BooleanExpression boolExp = (BooleanExpression) expression;
779             addVariableNames(boolExp.getExpression(), list);
780         }
781         else if (expression instanceof BinaryExpression) {
782             BinaryExpression binExp = (BinaryExpression) expression;
783             addVariableNames(binExp.getLeftExpression(), list);
784             addVariableNames(binExp.getRightExpression(), list);
785         }
786         else if (expression instanceof VariableExpression) {
787             VariableExpression varExp = (VariableExpression) expression;
788             list.add(varExp.getName());
789         }
790     }
791 
792     public void visitTryCatchFinally(TryCatchStatement statement) {
793         onLineNumber(statement, "visitTryCatchFinally");
794         visitStatement(statement);
795         
796         CatchStatement catchStatement = statement.getCatchStatement(0);
797         Statement tryStatement = statement.getTryStatement();
798         final Statement finallyStatement = statement.getFinallyStatement();
799 
800         int anyExceptionIndex = compileStack.defineTemporaryVariable("exception",false);
801         if (!finallyStatement.isEmpty()) {
802             compileStack.pushFinallyBlock(
803                 new Runnable(){
804                     public void run(){finallyStatement.visit(AsmClassGenerator.this);}
805                 }
806             );
807         }
808         
809         // start try block, label needed for exception table
810         final Label tryStart = new Label();
811         cv.visitLabel(tryStart);
812         tryStatement.visit(this);
813         // goto finally part
814         final Label finallyStart = new Label();
815         cv.visitJumpInsn(GOTO, finallyStart);
816         // marker needed for Exception table
817         final Label tryEnd = new Label();
818         cv.visitLabel(tryEnd);
819         
820         for (Iterator it=statement.getCatchStatements().iterator(); it.hasNext();) {
821             catchStatement = (CatchStatement) it.next();
822             ClassNode exceptionType = catchStatement.getExceptionType();
823             // start catch block, label needed for exception table
824             final Label catchStart = new Label();
825             cv.visitLabel(catchStart);
826             // create exception variable and store the exception 
827             compileStack.defineVariable(catchStatement.getVariable(),true);
828             // handle catch body
829             catchStatement.visit(this);
830             // goto finally start
831             cv.visitJumpInsn(GOTO, finallyStart);
832             // add exception to table
833             final String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
834             exceptionBlocks.add(new Runnable() {
835                 public void run() {
836                     cv.visitTryCatchBlock(tryStart, tryEnd, catchStart, exceptionTypeInternalName);
837                 }
838             });
839         }
840         
841         // marker needed for the exception table
842         final Label endOfAllCatches = new Label();
843         cv.visitLabel(endOfAllCatches);
844         
845         // remove the finally, don't let it visit itself
846         if (!finallyStatement.isEmpty()) compileStack.popFinallyBlock();
847         
848         // start finally
849         cv.visitLabel(finallyStart);
850         finallyStatement.visit(this);
851         // goto end of finally
852         Label afterFinally = new Label();
853         cv.visitJumpInsn(GOTO, afterFinally);
854         
855         // start a block catching any Exception
856         final Label catchAny = new Label();
857         cv.visitLabel(catchAny);
858         //store exception
859         cv.visitVarInsn(ASTORE, anyExceptionIndex);
860         finallyStatement.visit(this);
861         // load the exception and rethrow it
862         cv.visitVarInsn(ALOAD, anyExceptionIndex);
863         cv.visitInsn(ATHROW);
864         
865         // end of all catches and finally parts
866         cv.visitLabel(afterFinally);
867         
868         // add catch any block to exception table
869         exceptionBlocks.add(new Runnable() {
870             public void run() {
871                 cv.visitTryCatchBlock(tryStart, endOfAllCatches, catchAny, null);
872             }
873         });
874     }
875 
876     public void visitSwitch(SwitchStatement statement) {
877         onLineNumber(statement, "visitSwitch");
878         visitStatement(statement);
879 
880         statement.getExpression().visit(this);
881 
882         // switch does not have a continue label. use its parent's for continue
883         Label breakLabel = compileStack.pushSwitch();
884         
885         int switchVariableIndex = compileStack.defineTemporaryVariable("switch",true);
886 
887         List caseStatements = statement.getCaseStatements();
888         int caseCount = caseStatements.size();
889         Label[] labels = new Label[caseCount + 1];
890         for (int i = 0; i < caseCount; i++) {
891             labels[i] = new Label();
892         }
893 
894         int i = 0;
895         for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
896             CaseStatement caseStatement = (CaseStatement) iter.next();
897             visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
898         }
899 
900         statement.getDefaultStatement().visit(this);
901 
902         cv.visitLabel(breakLabel);
903 
904         compileStack.pop();
905     }
906 
907     public void visitCaseStatement(CaseStatement statement) {
908     }
909 
910     public void visitCaseStatement(
911         CaseStatement statement,
912         int switchVariableIndex,
913         Label thisLabel,
914         Label nextLabel) {
915 
916         onLineNumber(statement, "visitCaseStatement");
917 
918         cv.visitVarInsn(ALOAD, switchVariableIndex);
919         statement.getExpression().visit(this);
920 
921         isCaseMethod.call(cv);
922 
923         Label l0 = new Label();
924         cv.visitJumpInsn(IFEQ, l0);
925 
926         cv.visitLabel(thisLabel);
927 
928         statement.getCode().visit(this);
929 
930         // now if we don't finish with a break we need to jump past
931         // the next comparison
932         if (nextLabel != null) {
933             cv.visitJumpInsn(GOTO, nextLabel);
934         }
935 
936         cv.visitLabel(l0);
937     }
938 
939     public void visitBreakStatement(BreakStatement statement) {
940         onLineNumber(statement, "visitBreakStatement");
941         visitStatement(statement);
942         
943         String name = statement.getLabel();
944         Label breakLabel = compileStack.getNamedBreakLabel(name);
945         compileStack.applyFinallyBlocks(breakLabel, true);
946         
947         cv.visitJumpInsn(GOTO, breakLabel);
948     }
949 
950     public void visitContinueStatement(ContinueStatement statement) {
951         onLineNumber(statement, "visitContinueStatement");
952         visitStatement(statement);
953         
954         String name = statement.getLabel();
955         Label continueLabel = compileStack.getContinueLabel();
956         if (name!=null) continueLabel = compileStack.getNamedContinueLabel(name);
957         compileStack.applyFinallyBlocks(continueLabel, false);
958         cv.visitJumpInsn(GOTO, continueLabel);
959     }
960 
961     public void visitSynchronizedStatement(SynchronizedStatement statement) {
962         onLineNumber(statement, "visitSynchronizedStatement");
963         visitStatement(statement);
964         
965         statement.getExpression().visit(this);
966         final int index = compileStack.defineTemporaryVariable("synchronized", ClassHelper.Integer_TYPE,true);
967 
968         final Label synchronizedStart = new Label();
969         final Label synchronizedEnd = new Label();
970         final Label catchAll = new Label();
971         
972         cv.visitVarInsn(ALOAD, index);
973         cv.visitInsn(MONITORENTER);
974         cv.visitLabel(synchronizedStart);
975 
976         Runnable finallyPart = new Runnable(){
977             public void run(){
978                 cv.visitVarInsn(ALOAD, index);
979                 cv.visitInsn(MONITOREXIT);
980             }
981         };
982         compileStack.pushFinallyBlock(finallyPart);
983         statement.getCode().visit(this);
984 
985         finallyPart.run();
986         cv.visitJumpInsn(GOTO, synchronizedEnd);
987         cv.visitLabel(catchAll);
988         finallyPart.run();
989         cv.visitInsn(ATHROW);
990         cv.visitLabel(synchronizedEnd);
991 
992         compileStack.popFinallyBlock();
993         exceptionBlocks.add(new Runnable() {
994             public void run() {
995                 cv.visitTryCatchBlock(synchronizedStart, catchAll, catchAll, null);
996             }
997         });
998     }
999 
1000     public void visitThrowStatement(ThrowStatement statement) {
1001         onLineNumber(statement, "visitThrowStatement");
1002         visitStatement(statement);
1003         
1004         statement.getExpression().visit(this);
1005 
1006         // we should infer the type of the exception from the expression
1007         cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
1008 
1009         cv.visitInsn(ATHROW);
1010     }
1011 
1012     public void visitReturnStatement(ReturnStatement statement) {
1013         onLineNumber(statement, "visitReturnStatement");
1014         visitStatement(statement);
1015         
1016         ClassNode returnType = methodNode.getReturnType();
1017         if (returnType==ClassHelper.VOID_TYPE) {
1018         	if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) {
1019                 throwException("Cannot use return statement with an expression on a method that returns void");
1020         	}
1021             compileStack.applyFinallyBlocks();
1022             cv.visitInsn(RETURN);
1023             outputReturn = true;
1024             return;
1025         }
1026 
1027         Expression expression = statement.getExpression();
1028         evaluateExpression(expression);
1029         if (returnType==ClassHelper.OBJECT_TYPE && expression.getType() != null && expression.getType()==ClassHelper.VOID_TYPE) {
1030             cv.visitInsn(ACONST_NULL); // cheat the caller
1031         } else {
1032             // return is based on class type
1033             // we may need to cast
1034             doConvertAndCast(returnType, expression, false, true, false);
1035             helper.unbox(returnType);
1036         }
1037         if (compileStack.hasFinallyBlocks()) {
1038             int returnValueIdx = compileStack.defineTemporaryVariable("returnValue",returnType,true);
1039             compileStack.applyFinallyBlocks();
1040             helper.load(returnType,returnValueIdx);
1041         }        
1042         helper.doReturn(returnType);
1043         outputReturn = true;
1044     }
1045 
1046     /***
1047      * Casts to the given type unless it can be determined that the cast is unnecessary
1048      */
1049     protected void doConvertAndCast(ClassNode type, Expression expression, boolean ignoreAutoboxing, boolean forceCast, boolean coerce) {
1050         ClassNode expType = getExpressionType(expression);
1051         // temp resolution: convert all primitive casting to corresponsing Object type
1052         if (!ignoreAutoboxing && ClassHelper.isPrimitiveType(type)) {
1053             type = ClassHelper.getWrapper(type);
1054         }
1055         if (forceCast || (type!=null && !type.equals(expType))) {
1056             doConvertAndCast(type,coerce);
1057         }
1058     }    
1059 
1060     /***
1061      * @param expression
1062      */
1063     protected void evaluateExpression(Expression expression) {
1064         visitAndAutoboxBoolean(expression);
1065 
1066         Expression assignExpr = createReturnLHSExpression(expression);
1067         if (assignExpr != null) {
1068             leftHandExpression = false;
1069             assignExpr.visit(this);
1070         }
1071     }
1072 
1073     public void visitExpressionStatement(ExpressionStatement statement) {
1074         onLineNumber(statement, "visitExpressionStatement: " + statement.getExpression().getClass().getName());
1075         visitStatement(statement);
1076         
1077         Expression expression = statement.getExpression();
1078 
1079         visitAndAutoboxBoolean(expression);
1080 
1081         if (isPopRequired(expression)) {
1082             cv.visitInsn(POP);
1083         }
1084     }
1085 
1086     // Expressions
1087     //-------------------------------------------------------------------------
1088 
1089     public void visitDeclarationExpression(DeclarationExpression expression) {
1090         onLineNumber(expression, "visitDeclarationExpression: \""+expression.getVariableExpression().getName()+"\"");
1091 
1092         Expression rightExpression = expression.getRightExpression();
1093         // no need to visit left side, just get the variable name
1094         VariableExpression vex = expression.getVariableExpression();
1095         ClassNode type = vex.getType();
1096 
1097         // lets not cast for primitive types as we handle these in field setting etc
1098         if (ClassHelper.isPrimitiveType(type)) {
1099             rightExpression.visit(this);
1100         } else {
1101             if (type!=ClassHelper.OBJECT_TYPE){
1102                 visitCastExpression(new CastExpression(type, rightExpression));
1103             } else {
1104                 visitAndAutoboxBoolean(rightExpression);
1105             }
1106         }
1107         compileStack.defineVariable(vex,true);
1108     }
1109     
1110     public void visitBinaryExpression(BinaryExpression expression) {
1111         onLineNumber(expression, "visitBinaryExpression: \"" + expression.getOperation().getText() + "\" ");
1112         switch (expression.getOperation().getType()) {
1113             case Types.EQUAL : // = assignment
1114                 evaluateEqual(expression);
1115                 break;
1116 
1117             case Types.COMPARE_IDENTICAL : // ===
1118                 evaluateBinaryExpression(compareIdenticalMethod, expression);
1119                 break;
1120 
1121             case Types.COMPARE_EQUAL : // ==
1122                 evaluateBinaryExpression(compareEqualMethod, expression);
1123                 break;
1124 
1125             case Types.COMPARE_NOT_EQUAL :
1126                 evaluateBinaryExpression(compareNotEqualMethod, expression);
1127                 break;
1128 
1129             case Types.COMPARE_TO :
1130                 evaluateCompareTo(expression);
1131                 break;
1132 
1133             case Types.COMPARE_GREATER_THAN :
1134                 evaluateBinaryExpression(compareGreaterThanMethod, expression);
1135                 break;
1136 
1137             case Types.COMPARE_GREATER_THAN_EQUAL :
1138                 evaluateBinaryExpression(compareGreaterThanEqualMethod, expression);
1139                 break;
1140 
1141             case Types.COMPARE_LESS_THAN :
1142                 evaluateBinaryExpression(compareLessThanMethod, expression);
1143                 break;
1144 
1145             case Types.COMPARE_LESS_THAN_EQUAL :
1146                 evaluateBinaryExpression(compareLessThanEqualMethod, expression);
1147                 break;
1148 
1149             case Types.LOGICAL_AND :
1150                 evaluateLogicalAndExpression(expression);
1151                 break;
1152 
1153             case Types.LOGICAL_OR :
1154                 evaluateLogicalOrExpression(expression);
1155                 break;
1156 
1157             case Types.BITWISE_AND :
1158                 evaluateBinaryExpression("and", expression);
1159                 break;
1160 
1161             case Types.BITWISE_AND_EQUAL :
1162                 evaluateBinaryExpressionWithAsignment("and", expression);
1163                 break;
1164 
1165             case Types.BITWISE_OR :
1166                 evaluateBinaryExpression("or", expression);
1167                 break;
1168 
1169             case Types.BITWISE_OR_EQUAL :
1170                 evaluateBinaryExpressionWithAsignment("or", expression);
1171                 break;
1172 
1173             case Types.BITWISE_XOR :
1174                 evaluateBinaryExpression("xor", expression);
1175                 break;
1176 
1177             case Types.BITWISE_XOR_EQUAL :
1178                 evaluateBinaryExpressionWithAsignment("xor", expression);
1179                 break;
1180 
1181             case Types.PLUS :
1182                 evaluateBinaryExpression("plus", expression);
1183                 break;
1184 
1185             case Types.PLUS_EQUAL :
1186                 evaluateBinaryExpressionWithAsignment("plus", expression);
1187                 break;
1188                 
1189             case Types.MINUS :
1190                 evaluateBinaryExpression("minus", expression);
1191                 break;
1192                 
1193             case Types.MINUS_EQUAL :
1194                 evaluateBinaryExpressionWithAsignment("minus", expression);
1195                 break;
1196 
1197             case Types.MULTIPLY :
1198                 evaluateBinaryExpression("multiply", expression);
1199                 break;
1200 
1201             case Types.MULTIPLY_EQUAL :
1202                 evaluateBinaryExpressionWithAsignment("multiply", expression);
1203                 break;
1204 
1205             case Types.DIVIDE :
1206                 evaluateBinaryExpression("div", expression);
1207                 break;
1208 
1209             case Types.DIVIDE_EQUAL :
1210                 //SPG don't use divide since BigInteger implements directly
1211                 //and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
1212                 evaluateBinaryExpressionWithAsignment("div", expression);
1213                 break;
1214 
1215             case Types.INTDIV :
1216                 evaluateBinaryExpression("intdiv", expression);
1217                 break;
1218 
1219             case Types.INTDIV_EQUAL :
1220                 evaluateBinaryExpressionWithAsignment("intdiv", expression);
1221                 break;
1222 
1223             case Types.MOD :
1224                 evaluateBinaryExpression("mod", expression);
1225                 break;
1226 
1227             case Types.MOD_EQUAL :
1228                 evaluateBinaryExpressionWithAsignment("mod", expression);
1229                 break;
1230 
1231             case Types.POWER :
1232                 evaluateBinaryExpression("power", expression);
1233                 break;
1234 
1235             case Types.POWER_EQUAL :
1236                 evaluateBinaryExpressionWithAsignment("power", expression);
1237                 break;
1238 
1239             case Types.LEFT_SHIFT :
1240                 evaluateBinaryExpression("leftShift", expression);
1241                 break;
1242 
1243             case Types.LEFT_SHIFT_EQUAL :
1244                 evaluateBinaryExpressionWithAsignment("leftShift", expression);
1245                 break;
1246 
1247             case Types.RIGHT_SHIFT :
1248                 evaluateBinaryExpression("rightShift", expression);
1249                 break;
1250 
1251             case Types.RIGHT_SHIFT_EQUAL :
1252                 evaluateBinaryExpressionWithAsignment("rightShift", expression);
1253                 break;
1254 
1255             case Types.RIGHT_SHIFT_UNSIGNED :
1256                 evaluateBinaryExpression("rightShiftUnsigned", expression);
1257                 break;
1258 
1259             case Types.RIGHT_SHIFT_UNSIGNED_EQUAL :
1260                 evaluateBinaryExpressionWithAsignment("rightShiftUnsigned", expression);
1261                 break;
1262 
1263             case Types.KEYWORD_INSTANCEOF :
1264                 evaluateInstanceof(expression);
1265                 break;
1266 
1267             case Types.FIND_REGEX :
1268                 evaluateBinaryExpression(findRegexMethod, expression);
1269                 break;
1270 
1271             case Types.MATCH_REGEX :
1272                 evaluateBinaryExpression(matchRegexMethod, expression);
1273                 break;
1274 
1275             case Types.LEFT_SQUARE_BRACKET :
1276                 if (leftHandExpression) {
1277                     throwException("Should not be called here. Possible reason: postfix operation on array.");
1278                     // This is handled right now in the evaluateEqual()
1279                     // should support this here later
1280                     //evaluateBinaryExpression("putAt", expression);
1281                 } else {
1282                     evaluateBinaryExpression("getAt", expression);
1283                 }
1284                 break;
1285              
1286             case Types.KEYWORD_IN :
1287                 evaluateBinaryExpression(isCaseMethod, expression);
1288                 break;
1289 
1290             default :
1291                 throwException("Operation: " + expression.getOperation() + " not supported");
1292         }
1293     }
1294 
1295     private void load(Expression exp) {
1296 
1297         boolean wasLeft = leftHandExpression;
1298         leftHandExpression = false;
1299 //        if (CREATE_DEBUG_INFO)
1300 //            helper.mark("-- loading expression: " + exp.getClass().getName() +
1301 //                    " at [" + exp.getLineNumber() + ":" + exp.getColumnNumber() + "]");
1302         //exp.visit(this);
1303         visitAndAutoboxBoolean(exp);
1304 //        if (CREATE_DEBUG_INFO)
1305 //            helper.mark(" -- end of loading --");
1306 
1307         leftHandExpression  = wasLeft;
1308     }
1309 
1310     public void visitPostfixExpression(PostfixExpression expression) {
1311         switch (expression.getOperation().getType()) {
1312             case Types.PLUS_PLUS :
1313                 evaluatePostfixMethod("next", expression.getExpression());
1314                 break;
1315             case Types.MINUS_MINUS :
1316                 evaluatePostfixMethod("previous", expression.getExpression());
1317                 break;
1318         }
1319     }
1320 
1321     private void throwException(String s) {
1322         throw new RuntimeParserException(s, currentASTNode);
1323     }
1324 
1325     public void visitPrefixExpression(PrefixExpression expression) {
1326         switch (expression.getOperation().getType()) {
1327             case Types.PLUS_PLUS :
1