View Javadoc

1   /*
2   $Id: AsmClassGenerator.java,v 1.58 2005/11/13 16:42:10 blackdrag Exp $
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.*;
49  
50  import java.util.*;
51  import java.util.logging.Logger;
52  
53  import org.codehaus.groovy.ast.ASTNode;
54  import org.codehaus.groovy.ast.AnnotatedNode;
55  import org.codehaus.groovy.ast.AnnotationNode;
56  import org.codehaus.groovy.ast.ClassHelper;
57  import org.codehaus.groovy.ast.ClassNode;
58  import org.codehaus.groovy.ast.CompileUnit;
59  import org.codehaus.groovy.ast.ConstructorNode;
60  import org.codehaus.groovy.ast.FieldNode;
61  import org.codehaus.groovy.ast.GroovyCodeVisitor;
62  import org.codehaus.groovy.ast.InnerClassNode;
63  import org.codehaus.groovy.ast.MethodNode;
64  import org.codehaus.groovy.ast.Parameter;
65  import org.codehaus.groovy.ast.PropertyNode;
66  import org.codehaus.groovy.ast.VariableScope;
67  import org.codehaus.groovy.ast.expr.*;
68  import org.codehaus.groovy.ast.stmt.AssertStatement;
69  import org.codehaus.groovy.ast.stmt.BlockStatement;
70  import org.codehaus.groovy.ast.stmt.BreakStatement;
71  import org.codehaus.groovy.ast.stmt.CaseStatement;
72  import org.codehaus.groovy.ast.stmt.CatchStatement;
73  import org.codehaus.groovy.ast.stmt.ContinueStatement;
74  import org.codehaus.groovy.ast.stmt.DoWhileStatement;
75  import org.codehaus.groovy.ast.stmt.ExpressionStatement;
76  import org.codehaus.groovy.ast.stmt.ForStatement;
77  import org.codehaus.groovy.ast.stmt.IfStatement;
78  import org.codehaus.groovy.ast.stmt.ReturnStatement;
79  import org.codehaus.groovy.ast.stmt.Statement;
80  import org.codehaus.groovy.ast.stmt.SwitchStatement;
81  import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
82  import org.codehaus.groovy.ast.stmt.ThrowStatement;
83  import org.codehaus.groovy.ast.stmt.TryCatchStatement;
84  import org.codehaus.groovy.ast.stmt.WhileStatement;
85  import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
86  import org.codehaus.groovy.syntax.Token;
87  import org.codehaus.groovy.syntax.Types;
88  import org.codehaus.groovy.syntax.RuntimeParserException;
89  import org.objectweb.asm.AnnotationVisitor;
90  import org.objectweb.asm.ClassVisitor;
91  import org.objectweb.asm.MethodVisitor;
92  import org.objectweb.asm.Label;
93  import org.objectweb.asm.ClassWriter;
94  
95  
96  /***
97   * Generates Java class versions of Groovy classes using ASM.
98   *
99   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
100  * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
101  * @author Jochen Theodorou
102  *
103  * @version $Revision: 1.58 $
104  */
105 public class AsmClassGenerator extends ClassGenerator {
106 
107     private Logger log = Logger.getLogger(getClass().getName());
108 
109     private ClassVisitor cw;
110     private MethodVisitor cv;
111     private GeneratorContext context;
112 
113     private String sourceFile;
114 
115     // current class details
116     private ClassNode classNode;
117     private ClassNode outermostClass;
118     private String internalClassName;
119     private String internalBaseClassName;
120 
121     /*** maps the variable names to the JVM indices */
122     private Map variableStack = new HashMap();
123 
124     /*** have we output a return statement yet */
125     private boolean outputReturn;
126 
127     /*** are we on the left or right of an expression */
128     private boolean leftHandExpression;
129 
130     // cached values
131     MethodCaller invokeMethodMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeMethod");
132     MethodCaller invokeMethodSafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeMethodSafe");
133     MethodCaller invokeMethodSpreadSafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeMethodSpreadSafe");
134     MethodCaller invokeStaticMethodMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeStaticMethod");
135     MethodCaller invokeConstructorMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeConstructor");
136     MethodCaller invokeConstructorOfMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeConstructorOf");
137     MethodCaller invokeNoArgumentsConstructorOf = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeNoArgumentsConstructorOf");
138     MethodCaller invokeConstructorAtMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeConstructorAt");
139     MethodCaller invokeNoArgumentsConstructorAt = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeNoArgumentsConstructorAt");
140     MethodCaller invokeClosureMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeClosure");
141     MethodCaller invokeSuperMethodMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeSuperMethod");
142     MethodCaller invokeNoArgumentsMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeNoArgumentsMethod");
143     MethodCaller invokeNoArgumentsSafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeNoArgumentsSafeMethod");
144     MethodCaller invokeNoArgumentsSpreadSafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeNoArgumentsSpreadSafeMethod");
145     MethodCaller invokeStaticNoArgumentsMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeStaticNoArgumentsMethod");
146 
147     MethodCaller asIntMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asInt");
148     MethodCaller asTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asType");
149 
150     MethodCaller getAttributeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getAttribute");
151     MethodCaller getAttributeSafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getAttributeSafe");
152     MethodCaller getAttributeSpreadSafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getAttributeSpreadSafe");
153     MethodCaller setAttributeMethod2 = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "setAttribute2");
154     MethodCaller setAttributeSafeMethod2 = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "setAttributeSafe2");
155 
156     MethodCaller getPropertyMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getProperty");
157     MethodCaller getPropertySafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getPropertySafe");
158     MethodCaller getPropertySpreadSafeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getPropertySpreadSafe");
159     MethodCaller setPropertyMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "setProperty");
160     MethodCaller setPropertyMethod2 = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "setProperty2");
161     MethodCaller setPropertySafeMethod2 = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "setPropertySafe2");
162 
163     MethodCaller getGroovyObjectPropertyMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getGroovyObjectProperty");
164     MethodCaller setGroovyObjectPropertyMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "setGroovyObjectProperty");
165     MethodCaller asIteratorMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asIterator");
166     MethodCaller asBool = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asBool");
167     MethodCaller notBoolean = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "notBoolean");
168     MethodCaller notObject = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "notObject");
169     MethodCaller regexPattern = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "regexPattern");
170     MethodCaller spreadList = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "spreadList");
171     MethodCaller spreadMap = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "spreadMap");
172     MethodCaller getMethodPointer = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getMethodPointer");
173     MethodCaller negation = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "negate");
174     MethodCaller bitNegation = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "bitNegate");
175     MethodCaller convertPrimitiveArray = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "convertPrimitiveArray");
176     MethodCaller convertToPrimitiveArray = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "convertToPrimitiveArray");
177 
178     MethodCaller compareIdenticalMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareIdentical");
179     MethodCaller compareEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareEqual");
180     MethodCaller compareNotEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareNotEqual");
181     MethodCaller compareToMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareTo");
182     MethodCaller findRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "findRegex");
183     MethodCaller matchRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "matchRegex");
184     MethodCaller compareLessThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThan");
185     MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThanEqual");
186     MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThan");
187     MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThanEqual");
188     MethodCaller isCaseMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "isCase");
189 
190     MethodCaller createListMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createList");
191     MethodCaller createTupleMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createTuple");
192     MethodCaller createMapMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createMap");
193     MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange");
194 
195     MethodCaller assertFailedMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "assertFailed");
196 
197     MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator.class, "next");
198     MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator.class, "hasNext");
199 
200 
201     // current stack index
202     private int lastVariableIndex;
203     private static int tempVariableNameCounter;
204 
205     // exception blocks list
206     private List exceptionBlocks = new ArrayList();
207 
208     private boolean definingParameters;
209     private Set syntheticStaticFields = new HashSet();
210     private Set mutableVars = new HashSet();
211     private boolean passingClosureParams;
212 
213     private ConstructorNode constructorNode;
214     private MethodNode methodNode;
215     //private PropertyNode propertyNode;
216     private BlockScope scope;
217     private BytecodeHelper helper = new BytecodeHelper(null);
218 
219     private VariableScope variableScope;
220     public static final boolean CREATE_DEBUG_INFO = false;
221     public static final boolean CREATE_LINE_NUMBER_INFO = true;
222     private static final boolean MARK_START = true;
223 
224     /*public static final String EB_SWITCH_NAME = "static.dispatching";
225     public boolean ENABLE_EARLY_BINDING;
226     {    //
227         String ebSwitch = (String) AccessController.doPrivileged(new PrivilegedAction() {
228             public Object run() {
229                 return System.getProperty(EB_SWITCH_NAME, "false"); // set default to true if early binding is on by default.
230             }
231         });
232         //System.out.println("ebSwitch = " + ebSwitch);
233         if (ebSwitch.equals("true")) {
234             ENABLE_EARLY_BINDING  = true;
235         }
236         else if (ebSwitch.equals("false")) {
237             ENABLE_EARLY_BINDING  = false;
238         }
239         else {
240             ENABLE_EARLY_BINDING  = false;
241             log.warning("The value of system property " + EB_SWITCH_NAME + " is not recognized. Late dispatching is assumed. ");
242         }
243     }*/
244     public static final boolean ASM_DEBUG = false; // add marker in the bytecode to show source-byecode relationship
245     private int lineNumber = -1;
246     private int columnNumber = -1;
247     private ASTNode currentASTNode = null;
248 
249     private DummyClassGenerator dummyGen = null;
250     private ClassWriter dummyClassWriter = null;
251 
252     public AsmClassGenerator(
253         GeneratorContext context,
254         ClassVisitor classVisitor,
255         ClassLoader classLoader,
256         String sourceFile) {
257         super(classLoader);
258         this.context = context;
259         this.cw = classVisitor;
260         this.sourceFile = sourceFile;
261 
262         this.dummyClassWriter = new ClassWriter(true);
263         dummyGen  = new DummyClassGenerator(context, dummyClassWriter, classLoader, sourceFile);
264 
265     }
266 
267     // GroovyClassVisitor interface
268     //-------------------------------------------------------------------------
269     public void visitClass(ClassNode classNode) {
270         // todo to be tested
271         // createDummyClass(classNode);
272 
273         try {
274             syntheticStaticFields.clear();
275             this.classNode = classNode;
276             this.outermostClass = null;
277             this.internalClassName = BytecodeHelper.getClassInternalName(classNode);
278 
279             //System.out.println("Generating class: " + classNode.getName());
280 
281             this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
282 
283             cw.visit(
284                 asmJDKVersion,
285                 classNode.getModifiers(),
286                 internalClassName,
287                 null,
288                 internalBaseClassName,
289                 BytecodeHelper.getClassInternalNames(classNode.getInterfaces())
290             );            
291             cw.visitSource(sourceFile,null);
292             visitAnnotations(classNode);
293 
294             // set the optional enclosing method attribute of the current inner class
295 //          br comment out once Groovy uses the latest CVS HEAD of ASM
296 //            MethodNode enclosingMethod = classNode.getEnclosingMethod();
297 //            String ownerName = BytecodeHelper.getClassInternalName(enclosingMethod.getDeclaringClass().getName());
298 //            String descriptor = BytecodeHelper.getMethodDescriptor(enclosingMethod.getReturnType(), enclosingMethod.getParameters());
299 //            EnclosingMethodAttribute attr = new EnclosingMethodAttribute(ownerName,enclosingMethod.getName(),descriptor);
300 //            cw.visitAttribute(attr);
301 
302             classNode.visitContents(this);
303 
304             createSyntheticStaticFields();
305 
306             for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
307                 ClassNode innerClass = (ClassNode) iter.next();
308                 String innerClassName = innerClass.getName();
309                 String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
310                 {
311                     int index = innerClassName.lastIndexOf('$');
312                     if (index>=0) innerClassName = innerClassName.substring(index+1);
313                 }
314                 String outerClassName = internalClassName; // default for inner classes
315                 MethodNode enclosingMethod = innerClass.getEnclosingMethod();
316                 if (enclosingMethod != null) {
317                     // local inner classes do not specify the outer class name
318                     outerClassName = null;
319                     innerClassName = null;
320                 }
321                 cw.visitInnerClass(
322                     innerClassInternalName,
323                     outerClassName,
324                     innerClassName,
325                     innerClass.getModifiers());
326             }
327 // br TODO an inner class should have an entry of itself
328             cw.visitEnd();
329         }
330         catch (GroovyRuntimeException e) {
331             e.setModule(classNode.getModule());
332             throw e;
333         }
334     }
335 
336     public void visitConstructor(ConstructorNode node) {
337         // creates a MethodWriter for the (implicit) constructor
338         //String methodType = ClassNode.getMethodDescriptor(VOID_TYPE, )
339 
340         this.constructorNode = node;
341         this.methodNode = null;
342         this.variableScope = null;
343 
344         String methodType = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, node.getParameters());
345         cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null);
346         helper = new BytecodeHelper(cv);
347 
348         findMutableVariables();
349         resetVariableStack(node.getParameters());
350 
351         Statement code = node.getCode();
352         if (code == null || !firstStatementIsSuperInit(code)) {
353             // invokes the super class constructor
354             cv.visitVarInsn(ALOAD, 0);
355             cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "()V");
356         }
357         if (code != null) {
358             code.visit(this);
359         }
360 
361         cv.visitInsn(RETURN);
362         cv.visitMaxs(0, 0);
363     }
364 
365     public void visitMethod(MethodNode node) {
366         //System.out.println("Visiting method: " + node.getName() + " with
367         // return type: " + node.getReturnType());
368         this.constructorNode = null;
369         this.methodNode = node;
370         this.variableScope = null;
371 
372         String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
373         cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null);
374         visitAnnotations(node);
375         if (node.getCode()!=null) {
376             Label labelStart = new Label();
377             cv.visitLabel(labelStart);
378             helper = new BytecodeHelper(cv);
379     
380             findMutableVariables();
381             resetVariableStack(node.getParameters());
382     
383     
384             outputReturn = false;
385     
386             node.getCode().visit(this);
387     
388             if (!outputReturn) {
389                 cv.visitInsn(RETURN);
390             }
391     
392             // lets do all the exception blocks
393             for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) {
394                 Runnable runnable = (Runnable) iter.next();
395                 runnable.run();
396             }
397             exceptionBlocks.clear();
398     
399             Label labelEnd = new Label();
400             cv.visitLabel(labelEnd);
401     
402             // br experiment with local var table so debuggers can retrieve variable names
403             if (CREATE_DEBUG_INFO) {
404                 Set vars = this.variableStack.keySet();
405                 for (Iterator iterator = vars.iterator(); iterator.hasNext();) {
406                     String varName = (String) iterator.next();
407                     Variable v = (Variable)variableStack.get(varName);
408                     String type = v.getTypeName();
409                     type = BytecodeHelper.getTypeDescription(type);
410                     Label start = v.getStartLabel() != null ? v.getStartLabel() : labelStart;
411                     Label end = v.getEndLabel() != null ? v.getEndLabel() : labelEnd;
412                     cv.visitLocalVariable(varName, type, null, start, end, v.getIndex());
413                 }
414             }
415             cv.visitMaxs(0, 0);
416         }
417     }
418 
419     public void visitField(FieldNode fieldNode) {
420         onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
421         ClassNode t = fieldNode.getType();
422         cw.visitField(
423             fieldNode.getModifiers(),
424             fieldNode.getName(),
425             BytecodeHelper.getTypeDescription(t),
426             null, //fieldValue,  //br  all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
427             null);
428         visitAnnotations(fieldNode);
429     }
430 
431 
432     /***
433      * Creates a getter, setter and field
434      */
435     public void visitProperty(PropertyNode statement) {
436         onLineNumber(statement, "visitProperty:" + statement.getField().getName());
437         //this.propertyNode = statement;
438         this.methodNode = null;
439     }
440 
441     // GroovyCodeVisitor interface
442     //-------------------------------------------------------------------------
443 
444     // Statements
445     //-------------------------------------------------------------------------
446 
447     public void visitForLoop(ForStatement loop) {
448         onLineNumber(loop, "visitForLoop");
449         Class elemType = null;
450 
451         //
452         // Declare the loop counter.
453         ClassNode variableType = loop.getVariableType();
454         Variable variable = defineVariable(loop.getVariable(), variableType, true);
455 
456         if( isInScriptBody() ) {
457             variable.setProperty( true );
458         }
459 
460 
461         //
462         // Then initialize the iterator and generate the loop control
463 
464         loop.getCollectionExpression().visit(this);
465 
466         asIteratorMethod.call(cv);
467 
468         final Variable iterTemp = storeInTemp("iterator", ClassHelper.make(java.util.Iterator.class));
469         final int iteratorIdx = iterTemp.getIndex();
470 
471         // to push scope here allows the iterator available after the loop, such as the i in: for (i in 1..5)
472         // move it to the top will make the iterator a local var in the for loop.
473         pushBlockScope();
474 
475         Label continueLabel = scope.getContinueLabel();
476         cv.visitJumpInsn(GOTO, continueLabel);
477         Label label2 = new Label();
478         cv.visitLabel(label2);
479 
480         BytecodeExpression expression = new BytecodeExpression() {
481             public void visit(GroovyCodeVisitor visitor) {
482                 cv.visitVarInsn(ALOAD, iteratorIdx);
483                 iteratorNextMethod.call(cv);
484             }
485         };
486 
487         evaluateEqual( BinaryExpression.newAssignmentExpression(loop.getVariable(), expression) );
488         cv.visitInsn(POP); // br now the evaluateEqual() will leave a value on the stack. pop it.
489 
490         //
491         // Generate the loop body
492 
493         loop.getLoopBlock().visit(this);
494 
495 
496         //
497         // Generate the loop tail
498 
499         cv.visitLabel(continueLabel);
500         cv.visitVarInsn(ALOAD, iteratorIdx);
501 
502         iteratorHasNextMethod.call(cv);
503 
504         cv.visitJumpInsn(IFNE, label2);
505 
506         cv.visitLabel(scope.getBreakLabel());
507         popScope();
508     }
509 
510     public void visitWhileLoop(WhileStatement loop) {
511         onLineNumber(loop, "visitWhileLoop");
512 
513         pushBlockScope();
514 
515         Label continueLabel = scope.getContinueLabel();
516 
517         cv.visitJumpInsn(GOTO, continueLabel);
518         Label l1 = new Label();
519         cv.visitLabel(l1);
520 
521         loop.getLoopBlock().visit(this);
522 
523         cv.visitLabel(continueLabel);
524 
525         loop.getBooleanExpression().visit(this);
526 
527         cv.visitJumpInsn(IFNE, l1);
528 
529         cv.visitLabel(scope.getBreakLabel());
530         popScope();
531     }
532 
533     public void visitDoWhileLoop(DoWhileStatement loop) {
534         onLineNumber(loop, "visitDoWhileLoop");
535 
536         pushBlockScope();
537 
538         Label breakLabel = scope.getBreakLabel();
539 
540         Label continueLabel = scope.getContinueLabel();
541         cv.visitLabel(continueLabel);
542         Label l1 = new Label();
543 
544         loop.getLoopBlock().visit(this);
545 
546         cv.visitLabel(l1);
547 
548         loop.getBooleanExpression().visit(this);
549 
550         cv.visitJumpInsn(IFNE, continueLabel);
551 
552         cv.visitLabel(breakLabel);
553         popScope();
554     }
555 
556     public void visitIfElse(IfStatement ifElse) {
557         onLineNumber(ifElse, "visitIfElse");
558 
559         ifElse.getBooleanExpression().visit(this);
560 
561         Label l0 = new Label();
562         cv.visitJumpInsn(IFEQ, l0);
563         pushBlockScope(false, false);
564         ifElse.getIfBlock().visit(this);
565         popScope();
566 
567         Label l1 = new Label();
568         cv.visitJumpInsn(GOTO, l1);
569         cv.visitLabel(l0);
570 
571         pushBlockScope(false, false);
572         ifElse.getElseBlock().visit(this);
573         cv.visitLabel(l1);
574         popScope();
575     }
576 
577     public void visitTernaryExpression(TernaryExpression expression) {
578         onLineNumber(expression, "visitTernaryExpression");
579 
580         expression.getBooleanExpression().visit(this);
581 
582         Label l0 = new Label();
583         cv.visitJumpInsn(IFEQ, l0);
584         expression.getTrueExpression().visit(this);
585 
586         Label l1 = new Label();
587         cv.visitJumpInsn(GOTO, l1);
588         cv.visitLabel(l0);
589 
590         expression.getFalseExpression().visit(this);
591         cv.visitLabel(l1);
592     }
593 
594     public void visitAssertStatement(AssertStatement statement) {
595         onLineNumber(statement, "visitAssertStatement");
596 
597         //System.out.println("Assert: " + statement.getLineNumber() + " for: "
598         // + statement.getText());
599 
600         BooleanExpression booleanExpression = statement.getBooleanExpression();
601         booleanExpression.visit(this);
602 
603         Label l0 = new Label();
604         cv.visitJumpInsn(IFEQ, l0);
605 
606         // do nothing
607 
608         Label l1 = new Label();
609         cv.visitJumpInsn(GOTO, l1);
610         cv.visitLabel(l0);
611 
612         // push expression string onto stack
613         String expressionText = booleanExpression.getText();
614         List list = new ArrayList();
615         addVariableNames(booleanExpression, list);
616         if (list.isEmpty()) {
617             cv.visitLdcInsn(expressionText);
618         }
619         else {
620             boolean first = true;
621 
622             // lets create a new expression
623             cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
624             cv.visitInsn(DUP);
625             cv.visitLdcInsn(expressionText + ". Values: ");
626 
627             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
628 
629             Variable assertTemp = visitASTOREInTemp("assert");
630             int tempIndex  = assertTemp.getIndex();
631 
632             for (Iterator iter = list.iterator(); iter.hasNext();) {
633                 String name = (String) iter.next();
634                 String text = name + " = ";
635                 if (first) {
636                     first = false;
637                 }
638                 else {
639                     text = ", " + text;
640                 }
641 
642                 cv.visitVarInsn(ALOAD, tempIndex);
643                 cv.visitLdcInsn(text);
644                 cv.visitMethodInsn(
645                     INVOKEVIRTUAL,
646                     "java/lang/StringBuffer",
647                     "append",
648                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
649                 cv.visitInsn(POP);
650 
651                 cv.visitVarInsn(ALOAD, tempIndex);
652                 new VariableExpression(name).visit(this);
653                 cv.visitMethodInsn(
654                     INVOKEVIRTUAL,
655                     "java/lang/StringBuffer",
656                     "append",
657                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
658                 cv.visitInsn(POP);
659 
660             }
661             cv.visitVarInsn(ALOAD, tempIndex);
662             removeVar(assertTemp);
663         }
664         // now the optional exception expression
665         statement.getMessageExpression().visit(this);
666 
667         assertFailedMethod.call(cv);
668         cv.visitLabel(l1);
669     }
670 
671     private void addVariableNames(Expression expression, List list) {
672         if (expression instanceof BooleanExpression) {
673             BooleanExpression boolExp = (BooleanExpression) expression;
674             addVariableNames(boolExp.getExpression(), list);
675         }
676         else if (expression instanceof BinaryExpression) {
677             BinaryExpression binExp = (BinaryExpression) expression;
678             addVariableNames(binExp.getLeftExpression(), list);
679             addVariableNames(binExp.getRightExpression(), list);
680         }
681         else if (expression instanceof VariableExpression) {
682             VariableExpression varExp = (VariableExpression) expression;
683             list.add(varExp.getName());
684         }
685     }
686 
687     public void visitTryCatchFinally(TryCatchStatement statement) {
688         onLineNumber(statement, "visitTryCatchFinally");
689 // todo need to add blockscope handling
690         CatchStatement catchStatement = statement.getCatchStatement(0);
691 
692         Statement tryStatement = statement.getTryStatement();
693 
694         if (tryStatement.isEmpty() || catchStatement == null) {
695             final Label l0 = new Label();
696             cv.visitLabel(l0);
697 
698             tryStatement.visit(this);
699 
700 
701             int index1 = defineVariable(this.createVariableName("exception"), ClassHelper.OBJECT_TYPE).getIndex();
702             int index2 = defineVariable(this.createVariableName("exception"), ClassHelper.OBJECT_TYPE).getIndex();
703 
704             final Label l1 = new Label();
705             cv.visitJumpInsn(JSR, l1);
706             final Label l2 = new Label();
707             cv.visitLabel(l2);
708             final Label l3 = new Label();
709             cv.visitJumpInsn(GOTO, l3);
710             final Label l4 = new Label();
711             cv.visitLabel(l4);
712             cv.visitVarInsn(ASTORE, index1);
713             cv.visitJumpInsn(JSR, l1);
714             final Label l5 = new Label();
715             cv.visitLabel(l5);
716             cv.visitVarInsn(ALOAD, index1);
717             cv.visitInsn(ATHROW);
718             cv.visitLabel(l1);
719             cv.visitVarInsn(ASTORE, index2);
720 
721             statement.getFinallyStatement().visit(this);
722 
723             cv.visitVarInsn(RET, index2);
724             cv.visitLabel(l3);
725 
726             exceptionBlocks.add(new Runnable() {
727                 public void run() {
728                     cv.visitTryCatchBlock(l0, l2, l4, null);
729                     cv.visitTryCatchBlock(l4, l5, l4, null);
730                 }
731             });
732 
733         }
734         else {
735             int finallySubAddress = defineVariable(this.createVariableName("exception"), ClassHelper.OBJECT_TYPE).getIndex();
736             int anyExceptionIndex = defineVariable(this.createVariableName("exception"), ClassHelper.OBJECT_TYPE).getIndex();
737 
738             // start try block, label needed for exception table
739             final Label tryStart = new Label();
740             cv.visitLabel(tryStart);
741             tryStatement.visit(this);
742             // goto finally part
743             final Label finallyStart = new Label();
744             cv.visitJumpInsn(GOTO, finallyStart);
745             // marker needed for Exception table
746             final Label tryEnd = new Label();
747             cv.visitLabel(tryEnd);
748             
749             for (Iterator it=statement.getCatchStatements().iterator(); it.hasNext();) {
750                 catchStatement = (CatchStatement) it.next();
751                 ClassNode exceptionType = catchStatement.getExceptionType();
752                 int exceptionIndex = defineVariable(catchStatement.getVariable(), exceptionType, false).getIndex();
753                 
754                 // start catch block, label needed for exception table
755                 final Label catchStart = new Label();
756                 cv.visitLabel(catchStart);
757                 // store the exception 
758                 cv.visitVarInsn(ASTORE, exceptionIndex);
759                 catchStatement.visit(this);
760                 // goto finally start
761                 cv.visitJumpInsn(GOTO, finallyStart);
762                 // add exception to table
763                 final String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
764                 exceptionBlocks.add(new Runnable() {
765                     public void run() {
766                         cv.visitTryCatchBlock(tryStart, tryEnd, catchStart, exceptionTypeInternalName);
767                     }
768                 });
769             }
770             
771             // marker needed for the exception table
772             final Label endOfAllCatches = new Label();
773             cv.visitLabel(endOfAllCatches);
774             
775             // start finally
776             cv.visitLabel(finallyStart);
777             Label finallySub = new Label();
778             // run finally sub
779             cv.visitJumpInsn(JSR, finallySub);
780             // goto end of finally
781             Label afterFinally = new Label();
782             cv.visitJumpInsn(GOTO, afterFinally);
783             
784             // start a block catching any Exception
785             final Label catchAny = new Label();
786             cv.visitLabel(catchAny);
787             //store exception
788             cv.visitVarInsn(ASTORE, anyExceptionIndex);
789             // run finally subroutine
790             cv.visitJumpInsn(JSR, finallySub);
791             // load the exception and rethrow it
792             cv.visitVarInsn(ALOAD, anyExceptionIndex);
793             cv.visitInsn(ATHROW);
794             
795             // start the finally subroutine
796             cv.visitLabel(finallySub);
797             // store jump address
798             cv.visitVarInsn(ASTORE, finallySubAddress);
799             if (!statement.getFinallyStatement().isEmpty())
800                 statement.getFinallyStatement().visit(this);
801             // return from subroutine
802             cv.visitVarInsn(RET, finallySubAddress);
803             
804             // end of all catches and finally parts
805             cv.visitLabel(afterFinally);
806             
807             // add catch any block to exception table
808             exceptionBlocks.add(new Runnable() {
809                 public void run() {
810                     cv.visitTryCatchBlock(tryStart, endOfAllCatches, catchAny, null);
811                 }
812             });
813         }
814     }
815 
816     private Variable storeInTemp(String name, ClassNode type) {
817         Variable var  = defineVariable(createVariableName(name), type, false);
818         int varIdx = var.getIndex();
819         cv.visitVarInsn(ASTORE, varIdx);
820         if (CREATE_DEBUG_INFO) cv.visitLabel(var.getStartLabel());
821         return var;
822     }
823 
824     public void visitSwitch(SwitchStatement statement) {
825         onLineNumber(statement, "visitSwitch");
826 
827         statement.getExpression().visit(this);
828 
829         // switch does not have a continue label. use its parent's for continue
830         pushBlockScope(false, true);
831         //scope.setContinueLabel(scope.getParent().getContinueLabel());
832 
833 
834         int switchVariableIndex = defineVariable(createVariableName("switch"), ClassHelper.OBJECT_TYPE).getIndex();
835         cv.visitVarInsn(ASTORE, switchVariableIndex);
836 
837         List caseStatements = statement.getCaseStatements();
838         int caseCount = caseStatements.size();
839         Label[] labels = new Label[caseCount + 1];
840         for (int i = 0; i < caseCount; i++) {
841             labels[i] = new Label();
842         }
843 
844         int i = 0;
845         for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
846             CaseStatement caseStatement = (CaseStatement) iter.next();
847             visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
848         }
849 
850         statement.getDefaultStatement().visit(this);
851 
852         cv.visitLabel(scope.getBreakLabel());
853 
854         popScope();
855     }
856 
857     public void visitCaseStatement(CaseStatement statement) {
858     }
859 
860     public void visitCaseStatement(
861         CaseStatement statement,
862         int switchVariableIndex,
863         Label thisLabel,
864         Label nextLabel) {
865 
866         onLineNumber(statement, "visitCaseStatement");
867 
868         cv.visitVarInsn(ALOAD, switchVariableIndex);
869         statement.getExpression().visit(this);
870 
871         isCaseMethod.call(cv);
872 
873         Label l0 = new Label();
874         cv.visitJumpInsn(IFEQ, l0);
875 
876         cv.visitLabel(thisLabel);
877 
878         statement.getCode().visit(this);
879 
880         // now if we don't finish with a break we need to jump past
881         // the next comparison
882         if (nextLabel != null) {
883             cv.visitJumpInsn(GOTO, nextLabel);
884         }
885 
886         cv.visitLabel(l0);
887     }
888 
889     public void visitBreakStatement(BreakStatement statement) {
890         onLineNumber(statement, "visitBreakStatement");
891 
892         Label breakLabel = scope.getBreakLabel();
893         if (breakLabel != null ) {
894             cv.visitJumpInsn(GOTO, breakLabel);
895         } else {
896             // should warn that break is not allowed in the context.
897         }
898     }
899 
900     public void visitContinueStatement(ContinueStatement statement) {
901         onLineNumber(statement, "visitContinueStatement");
902 
903         Label continueLabel = scope.getContinueLabel();
904         if (continueLabel != null ) {
905             cv.visitJumpInsn(GOTO, continueLabel);
906         } else {
907             // should warn that continue is not allowed in the context.
908         }
909     }
910 
911     public void visitSynchronizedStatement(SynchronizedStatement statement) {
912         onLineNumber(statement, "visitSynchronizedStatement");
913 
914         statement.getExpression().visit(this);
915 
916         int index = defineVariable(createVariableName("synchronized"), ClassHelper.Integer_TYPE).getIndex();
917 
918         cv.visitVarInsn(ASTORE, index);
919         cv.visitVarInsn(ALOAD, index);
920         cv.visitInsn(MONITORENTER);
921         final Label l0 = new Label();
922         cv.visitLabel(l0);
923 
924         statement.getCode().visit(this);
925 
926         cv.visitVarInsn(ALOAD, index);
927         cv.visitInsn(MONITOREXIT);
928         final Label l1 = new Label();
929         cv.visitJumpInsn(GOTO, l1);
930         final Label l2 = new Label();
931         cv.visitLabel(l2);
932         cv.visitVarInsn(ALOAD, index);
933         cv.visitInsn(MONITOREXIT);
934         cv.visitInsn(ATHROW);
935         cv.visitLabel(l1);
936 
937         exceptionBlocks.add(new Runnable() {
938             public void run() {
939                 cv.visitTryCatchBlock(l0, l2, l2, null);
940             }
941         });
942     }
943 
944     public void visitThrowStatement(ThrowStatement statement) {
945         statement.getExpression().visit(this);
946 
947         // we should infer the type of the exception from the expression
948         cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
949 
950         cv.visitInsn(ATHROW);
951     }
952 
953     public void visitReturnStatement(ReturnStatement statement) {
954         onLineNumber(statement, "visitReturnStatement");
955         ClassNode returnType = methodNode.getReturnType();
956         if (returnType==ClassHelper.VOID_TYPE) {
957         	if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) {
958                 throwException("Cannot use return statement with an expression on a method that returns void");
959         	}
960             cv.visitInsn(RETURN);
961             outputReturn = true;
962             return;
963         }
964 
965         Expression expression = statement.getExpression();
966         evaluateExpression(expression);
967         if (returnType==ClassHelper.OBJECT_TYPE && expression.getType() != null && expression.getType()==ClassHelper.VOID_TYPE) {
968             cv.visitInsn(ACONST_NULL); // cheat the caller
969             cv.visitInsn(ARETURN);
970         } else {
971             //return is based on class type
972             //TODO: make work with arrays
973             // we may need to cast
974             helper.unbox(returnType);
975             if (returnType==ClassHelper.double_TYPE) {
976                 cv.visitInsn(DRETURN);
977             }
978             else if (returnType==ClassHelper.float_TYPE) {
979                 cv.visitInsn(FRETURN);
980             }
981             else if (returnType==ClassHelper.long_TYPE) {
982                 cv.visitInsn(LRETURN);
983             }
984             else if (returnType==ClassHelper.boolean_TYPE) {
985                 cv.visitInsn(IRETURN);
986             }
987             else if (
988                        returnType==ClassHelper.char_TYPE
989                     || returnType==ClassHelper.byte_TYPE
990                     || returnType==ClassHelper.int_TYPE
991                     || returnType==ClassHelper.short_TYPE) 
992             { 
993                 //byte,short,boolean,int are all IRETURN
994                 cv.visitInsn(IRETURN);
995             }
996             else {
997                 doConvertAndCast(returnType, expression, false, true);
998                 cv.visitInsn(ARETURN);
999             }
1000         }
1001         outputReturn = true;
1002     }
1003 
1004     /***
1005      * Casts to the given type unless it can be determined that the cast is unnecessary
1006      */
1007     protected void doConvertAndCast(ClassNode type, Expression expression, boolean ignoreAutoboxing, boolean forceCast) {
1008         ClassNode expType = getExpressionType(expression);
1009         // temp resolution: convert all primitive casting to corresponsing Object type
1010         if (!ignoreAutoboxing && ClassHelper.isPrimitiveType(type)) {
1011             type = ClassHelper.getWrapper(type);
1012         }
1013         if (forceCast || (type!=null && !type.equals(expType))) {
1014             doConvertAndCast(type);
1015         }
1016     }    
1017 
1018     /***
1019      * @param expression
1020      */
1021     protected void evaluateExpression(Expression expression) {
1022         visitAndAutoboxBoolean(expression);
1023         //expression.visit(this);
1024 
1025         Expression assignExpr = createReturnLHSExpression(expression);
1026         if (assignExpr != null) {
1027             leftHandExpression = false;
1028             assignExpr.visit(this);
1029         }
1030     }
1031 
1032     public void visitExpressionStatement(ExpressionStatement statement) {
1033         onLineNumber(statement, "visitExpressionStatement: " + statement.getExpression().getClass().getName());
1034 
1035         Expression expression = statement.getExpression();
1036 // disabled in favor of JIT resolving
1037 //        if (ENABLE_EARLY_BINDING)
1038 //            expression.resolve(this);
1039 
1040         visitAndAutoboxBoolean(expression);
1041 
1042         if (isPopRequired(expression)) {
1043             cv.visitInsn(POP);
1044         }
1045     }
1046 
1047     // Expressions
1048     //-------------------------------------------------------------------------
1049 
1050     public void visitBinaryExpression(BinaryExpression expression) {
1051         onLineNumber(expression, "visitBinaryExpression: \"" + expression.getOperation().getText() + "\" ");
1052         switch (expression.getOperation().getType()) {
1053             case Types.EQUAL : // = assignment
1054                 evaluateEqual(expression);
1055                 break;
1056 
1057             case Types.COMPARE_IDENTICAL : // ===
1058                 evaluateBinaryExpression(compareIdenticalMethod, expression);
1059                 break;
1060 
1061             case Types.COMPARE_EQUAL : // ==
1062                 evaluateBinaryExpression(compareEqualMethod, expression);
1063                 break;
1064 
1065             case Types.COMPARE_NOT_EQUAL :
1066                 evaluateBinaryExpression(compareNotEqualMethod, expression);
1067                 break;
1068 
1069             case Types.COMPARE_TO :
1070                 evaluateCompareTo(expression);
1071                 break;
1072 
1073             case Types.COMPARE_GREATER_THAN :
1074                 evaluateBinaryExpression(compareGreaterThanMethod, expression);
1075                 break;
1076 
1077             case Types.COMPARE_GREATER_THAN_EQUAL :
1078                 evaluateBinaryExpression(compareGreaterThanEqualMethod, expression);
1079                 break;
1080 
1081             case Types.COMPARE_LESS_THAN :
1082                 evaluateBinaryExpression(compareLessThanMethod, expression);
1083                 break;
1084 
1085             case Types.COMPARE_LESS_THAN_EQUAL :
1086                 evaluateBinaryExpression(compareLessThanEqualMethod, expression);
1087                 break;
1088 
1089             case Types.LOGICAL_AND :
1090                 evaluateLogicalAndExpression(expression);
1091                 break;
1092 
1093             case Types.LOGICAL_OR :
1094                 evaluateLogicalOrExpression(expression);
1095                 break;
1096 
1097 	    case Types.BITWISE_AND :
1098                 evaluateBinaryExpression("and", expression);
1099                 break;
1100 
1101             case Types.BITWISE_AND_EQUAL :
1102                 evaluateBinaryExpressionWithAsignment("and", expression);
1103                 break;
1104 
1105             case Types.BITWISE_OR :
1106                 evaluateBinaryExpression("or", expression);
1107                 break;
1108 
1109             case Types.BITWISE_OR_EQUAL :
1110                 evaluateBinaryExpressionWithAsignment("or", expression);
1111                 break;
1112 
1113             case Types.BITWISE_XOR :
1114                 evaluateBinaryExpression("xor", expression);
1115                 break;
1116 
1117             case Types.BITWISE_XOR_EQUAL :
1118                 evaluateBinaryExpressionWithAsignment("xor", expression);
1119                 break;
1120 
1121             case Types.PLUS :
1122                 evaluateBinaryExpression("plus", expression);
1123                 break;
1124 
1125             case Types.PLUS_EQUAL :
1126                 evaluateBinaryExpressionWithAsignment("plus", expression);
1127                 break;
1128                 
1129             case Types.MINUS :
1130                 evaluateBinaryExpression("minus", expression);
1131                 break;
1132                 
1133             case Types.MINUS_EQUAL :
1134                 evaluateBinaryExpressionWithAsignment("minus", expression);
1135                 break;
1136 
1137             case Types.MULTIPLY :
1138                 evaluateBinaryExpression("multiply", expression);
1139                 break;
1140 
1141             case Types.MULTIPLY_EQUAL :
1142                 evaluateBinaryExpressionWithAsignment("multiply", expression);
1143                 break;
1144 
1145             case Types.DIVIDE :
1146                 evaluateBinaryExpression("div", expression);
1147                 break;
1148 
1149             case Types.DIVIDE_EQUAL :
1150                 //SPG don't use divide since BigInteger implements directly
1151                 //and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
1152                 evaluateBinaryExpressionWithAsignment("div", expression);
1153                 break;
1154 
1155             case Types.INTDIV :
1156                 evaluateBinaryExpression("intdiv", expression);
1157                 break;
1158 
1159             case Types.INTDIV_EQUAL :
1160                 evaluateBinaryExpressionWithAsignment("intdiv", expression);
1161                 break;
1162 
1163             case Types.MOD :
1164                 evaluateBinaryExpression("mod", expression);
1165                 break;
1166 
1167             case Types.MOD_EQUAL :
1168                 evaluateBinaryExpressionWithAsignment("mod", expression);
1169                 break;
1170 
1171             case Types.POWER :
1172                 evaluateBinaryExpression("power", expression);
1173                 break;
1174 
1175             case Types.POWER_EQUAL :
1176                 evaluateBinaryExpressionWithAsignment("power", expression);
1177                 break;
1178 
1179             case Types.LEFT_SHIFT :
1180                 evaluateBinaryExpression("leftShift", expression);
1181                 break;
1182 
1183             case Types.LEFT_SHIFT_EQUAL :
1184                 evaluateBinaryExpressionWithAsignment("leftShift", expression);
1185                 break;
1186 
1187             case Types.RIGHT_SHIFT :
1188                 evaluateBinaryExpression("rightShift", expression);
1189                 break;
1190 
1191             case Types.RIGHT_SHIFT_EQUAL :
1192                 evaluateBinaryExpressionWithAsignment("rightShift", expression);
1193                 break;
1194 
1195             case Types.RIGHT_SHIFT_UNSIGNED :
1196                 evaluateBinaryExpression("rightShiftUnsigned", expression);
1197                 break;
1198 
1199             case Types.RIGHT_SHIFT_UNSIGNED_EQUAL :
1200                 evaluateBinaryExpressionWithAsignment("rightShiftUnsigned", expression);
1201                 break;
1202 
1203             case Types.KEYWORD_INSTANCEOF :
1204                 evaluateInstanceof(expression);
1205                 break;
1206 
1207             case Types.FIND_REGEX :
1208                 evaluateBinaryExpression(findRegexMethod, expression);
1209                 break;
1210 
1211             case Types.MATCH_REGEX :
1212                 evaluateBinaryExpression(matchRegexMethod, expression);
1213                 break;
1214 
1215             case Types.LEFT_SQUARE_BRACKET :
1216                 if (leftHandExpression) {
1217                     throwException("Should not be called here. Possible reason: postfix operation on array.");
1218                     // This is handled right now in the evaluateEqual()
1219                     // should support this here later
1220                     //evaluateBinaryExpression("putAt", expression);
1221                 } else {
1222                     evaluateBinaryExpression("getAt", expression);
1223                 }
1224                 break;
1225 
1226             default :
1227                 throwException("Operation: " + expression.getOperation() + " not supported");
1228         }
1229     }
1230 
1231     private void load(Expression exp) {
1232 
1233         boolean wasLeft = leftHandExpression;
1234         leftHandExpression = false;
1235 //        if (CREATE_DEBUG_INFO)
1236 //            helper.mark("-- loading expression: " + exp.getClass().getName() +
1237 //                    " at [" + exp.getLineNumber() + ":" + exp.getColumnNumber() + "]");
1238         //exp.visit(this);
1239         visitAndAutoboxBoolean(exp);
1240 //        if (CREATE_DEBUG_INFO)
1241 //            helper.mark(" -- end of loading --");
1242 
1243         leftHandExpression  = wasLeft;
1244     }
1245 
1246     public void visitPostfixExpression(PostfixExpression expression) {
1247         switch (expression.getOperation().getType()) {
1248             case Types.PLUS_PLUS :
1249                 evaluatePostfixMethod("next", expression.getExpression());
1250                 break;
1251             case Types.MINUS_MINUS :
1252                 evaluatePostfixMethod("previous", expression.getExpression());
1253                 break;
1254         }
1255     }
1256 
1257     // store the data on the stack to the expression (variablem, property, field, etc.
1258     private void store(Expression expression) {
1259         if (expression instanceof BinaryExpression) {
1260             throwException("BinaryExpression appeared on LHS. ");
1261         }
1262         if (ASM_DEBUG) {
1263             if (expression instanceof VariableExpression) {
1264                 helper.mark(((VariableExpression)expression).getName());
1265             }
1266         }
1267         boolean wasLeft = leftHandExpression;
1268         leftHandExpression = true;
1269         expression.visit(this);
1270         //evaluateExpression(expression);
1271         leftHandExpression = wasLeft;
1272         return;
1273     }
1274 
1275     private void throwException(String s) {
1276         //throw new ClassGeneratorException(s + ". Source: " + classNode.getName() + ":[" + this.lineNumber + ":" + this.columnNumber + "]");
1277         throw new RuntimeParserException(s, currentASTNode);
1278     }
1279 
1280     public void visitPrefixExpression(PrefixExpression expression) {
1281         switch (expression.getOperation().getType()) {
1282             case Types.PLUS_PLUS :
1283                 evaluatePrefixMethod("next", expression.getExpression());
1284                 break;
1285             case Types.MINUS_MINUS :
1286                 evaluatePrefixMethod("previous", expression.getExpression());
1287                 break;
1288         }
1289     }
1290 
1291     public void visitClosureExpression(ClosureExpression expression) {
1292         ClassNode innerClass = createClosureClass(expression);
1293         addInnerClass(innerClass);
1294         String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass);
1295 
1296         ClassNode owner = innerClass.getOuterClass();
1297 
1298         passingClosureParams = true;
1299         List constructors = innerClass.getDeclaredConstructors();
1300         ConstructorNode node = (ConstructorNode) constructors.get(0);
1301         Parameter[] localVariableParams = node.getParameters();
1302 
1303 
1304         //
1305         // Define in the context any variables that will be
1306         // created inside the closure.  Note that the first two
1307         // parameters are always _outerInstance and _delegate,
1308         // so we don't worry about them.
1309 		//
1310         for (int i = 2; i < localVariableParams.length; i++) {
1311             Parameter param = localVariableParams[i];
1312             String name = param.getName();
1313 
1314             if (variableStack.get(name) == null && classNode.getField(name) == null) {
1315                 defineVariable(name, ClassHelper.OBJECT_TYPE); // todo  should use param type is available
1316             }
1317         }
1318 
1319         cv.visitTypeInsn(NEW, innerClassinternalName);
1320         cv.visitInsn(DUP);
1321         if (isStaticMethod() || classNode.isStaticClass()) {
1322             visitClassExpression(new ClassExpression(owner));
1323         }
1324         else {
1325             loadThisOrOwner();
1326         }
1327 
1328         if (innerClass.getSuperClass()==ClassHelper.CLOSURE_TYPE) {
1329             if (isStaticMethod()) {
1330                 /***
1331                  * todo could maybe stash this expression in a JVM variable
1332                  * from previous statement above
1333                  */
1334                 visitClassExpression(new ClassExpression(owner));
1335             }
1336             else {
1337               cv.visitVarInsn(ALOAD, 0);
1338             }
1339         }
1340 
1341         //String prototype = "(L" + BytecodeHelper.getClassInternalName(ownerTypeName) + ";Ljava/lang/Object;";
1342 
1343         // now lets load the various parameters we're passing
1344         for (int i = 2; i < localVariableParams.length; i++) {
1345             Parameter param = localVariableParams[i];
1346             String name = param.getName();
1347 
1348             if (variableStack.get(name) == null) {
1349                 visitFieldExpression(new FieldExpression(classNode.getField(name)));
1350             }
1351             else {
1352                 visitVariableExpression(new VariableExpression(name));
1353             }
1354             //prototype = prototype + "L" + BytecodeHelper.getClassInternalName(param.getType()) + ";";
1355         }
1356         passingClosureParams = false;
1357 
1358         // we may need to pass in some other constructors
1359         //cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
1360         cv.visitMethodInsn(
1361             INVOKESPECIAL,
1362             innerClassinternalName,
1363             "<init>",
1364             BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, localVariableParams));
1365     }
1366 
1367     /***
1368      * Loads either this object or if we're inside a closure then load the top level owner
1369      */
1370     protected void loadThisOrOwner() {
1371         if (isInnerClass()) {
1372             visitFieldExpression(new FieldExpression(classNode.getField("owner")));
1373         }
1374         else {
1375             cv.visitVarInsn(ALOAD, 0);
1376         }
1377     }
1378 
1379     public void visitRegexExpression(RegexExpression expression) {
1380         expression.getRegex().visit(this);
1381         regexPattern.call(cv);
1382     }
1383 
1384     /***
1385      * Generate byte code for constants
1386      * @see <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a>
1387      */
1388     public void visitConstantExpression(ConstantExpression expression) {
1389         Object value = expression.getValue();
1390         helper.loadConstant(value);
1391     }
1392 
1393     public void visitSpreadExpression(SpreadExpression expression) {
1394         Expression subExpression = expression.getExpression();
1395         subExpression.visit(this);
1396         spreadList.call(cv);
1397     }
1398 
1399     public void visitSpreadMapExpression(SpreadMapExpression expression) {
1400         Expression subExpression = expression.getExpression();
1401         subExpression.visit(this);
1402         spreadMap.call(cv);
1403     }
1404 
1405     public void visitMethodPointerExpression(MethodPointerExpression expression) {
1406         Expression subExpression = expression.getExpression();
1407         subExpression.visit(this);
1408         helper.loadConstant(expression.getMethodName());
1409         getMethodPointer.call(cv);
1410     }
1411 
1412     public void visitNegationExpression(NegationExpression expression) {
1413         Expression subExpression = expression.getExpression();
1414         subExpression.visit(this);
1415         negation.call(cv);
1416     }
1417 
1418     public void visitBitwiseNegExpression(BitwiseNegExpression expression) {
1419         Expression subExpression = expression.getExpression();
1420         subExpression.visit(this);
1421         bitNegation.call(cv);
1422     }
1423 
1424     public void visitCastExpression(CastExpression expression) {
1425         ClassNode type = expression.getType();
1426         visitAndAutoboxBoolean(expression.getExpression());
1427         doConvertAndCast(type, expression.getExpression(), expression.isIgnoringAutoboxing(),false);
1428     }
1429 
1430     public void visitNotExpression(NotExpression expression) {
1431         Expression subExpression = expression.getExpression();
1432         subExpression.visit(this);
1433 
1434         // This is not the best way to do this. Javac does it by reversing the
1435         // underlying expressions but that proved
1436         // fairly complicated for not much gain. Instead we'll just use a
1437         // utility function for now.
1438         if (isComparisonExpression(expression.getExpression())) {
1439             notBoolean.call(cv);
1440         }
1441         else {
1442             notObject.call(cv);
1443         }
1444     }
1445 
1446     /***
1447      * return a primitive boolean value of the BooleanExpresion.
1448      * @param expression
1449      */
1450     public void visitBooleanExpression(BooleanExpression expression) {
1451         expression.getExpression().visit(this);
1452 
1453         if (!isComparisonExpression(expression.getExpression())) {
1454 // comment out for optimization when boolean values are not autoboxed for eg. function calls.
1455 //           Class typeClass = expression.getExpression().getTypeClass();
1456 //           if (typeClass != null && typeClass != boolean.class) {
1457                 asBool.call(cv); // to return a primitive boolean
1458 //            }
1459         }
1460     }
1461 
1462     public void visitMethodCallExpression(MethodCallExpression call) {
1463         onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":");
1464 
1465         this.leftHandExpression = false;
1466 
1467         Expression arguments = call.getArguments();
1468         /*
1469          * if (arguments instanceof TupleExpression) { TupleExpression
1470          * tupleExpression = (TupleExpression) arguments; int size =
1471          * tupleExpression.getExpressions().size(); if (size == 0) { arguments =
1472          * ConstantExpression.EMPTY_ARRAY; } }
1473          */
1474         boolean superMethodCall = MethodCallExpression.isSuperMethodCall(call);
1475         String method = call.getMethod();
1476         if (superMethodCall && method.equals("<init>")) {
1477             /*** todo handle method types! */
1478             cv.visitVarInsn(ALOAD, 0);
1479             if (isInClosureConstructor()) { // br use the second param to init the super class (Closure)
1480                 cv.visitVarInsn(ALOAD, 2);
1481                 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
1482             }
1483             else {
1484                 cv.visitVarInsn(ALOAD, 1);
1485                 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
1486             }
1487         }
1488         else {
1489             // are we a local variable
1490             if (isThisExpression(call.getObjectExpression()) && isFieldOrVariable(method) && ! classNode.hasPossibleMethod(method, arguments)) {
1491                 /*
1492                  * if (arguments instanceof TupleExpression) { TupleExpression
1493                  * tupleExpression = (TupleExpression) arguments; int size =
1494                  * tupleExpression.getExpressions().size(); if (size == 1) {
1495                  * arguments = (Expression)
1496                  * tupleExpression.getExpressions().get(0); } }
1497                  */
1498 
1499                 // lets invoke the closure method
1500                 visitVariableExpression(new VariableExpression(method));
1501                 arguments.visit(this);
1502                 invokeClosureMethod.call(cv);
1503             }
1504             else {
1505                 if (superMethodCall) {
1506                     if (method.equals("super") || method.equals("<init>")) {
1507                         ConstructorNode superConstructorNode = findSuperConstructor(call);
1508 
1509                         cv.visitVarInsn(ALOAD, 0);
1510 
1511                         loadArguments(superConstructorNode.getParameters(), arguments);
1512 
1513                         String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, superConstructorNode.getParameters());
1514                         cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", descriptor);
1515                     }
1516                     else {
1517                         MethodNode superMethodNode = findSuperMethod(call);
1518 
1519                         cv.visitVarInsn(ALOAD, 0);
1520 
1521                         loadArguments(superMethodNode.getParameters(), arguments);
1522 
1523                         String descriptor = BytecodeHelper.getMethodDescriptor(superMethodNode.getReturnType(), superMethodNode.getParameters());
1524                         cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superMethodNode.getDeclaringClass()), method, descriptor);
1525                     }
1526                 }
1527                 else {
1528                     if (emptyArguments(arguments) && !call.isSafe() && !call.isSpreadSafe()) {
1529                         call.getObjectExpression().visit(this);
1530                         cv.visitLdcInsn(method);
1531                         invokeNoArgumentsMethod.call(cv); // todo try if we can do early binding
1532                     }
1533                     else {
1534                         if (argumentsUseStack(arguments)) {
1535 
1536                             arguments.visit(this);
1537 
1538                             Variable tv = visitASTOREInTemp(method + "_arg");
1539                             int paramIdx = tv.getIndex();
1540 
1541                             call.getObjectExpression().visit(this); // xxx
1542 
1543                             cv.visitLdcInsn(method);
1544 
1545                             cv.visitVarInsn(ALOAD, paramIdx);
1546                             removeVar(tv);
1547                         }
1548                         else {
1549                             call.getObjectExpression().visit(this);
1550                             cv.visitLdcInsn(method);
1551                             arguments.visit(this);
1552                         }
1553 
1554                         if (call.isSpreadSafe()) {
1555                             invokeMethodSpreadSafeMethod.call(cv);
1556                         }
1557                         else if (call.isSafe()) {
1558                             invokeMethodSafeMethod.call(cv);
1559                         }
1560                         else {
1561                             invokeMethodMethod.call(cv);
1562                         }
1563                     }
1564                 }
1565             }
1566         }
1567     }
1568 
1569     /***
1570      * Loads and coerces the argument values for the given method call
1571      */
1572     protected void loadArguments(Parameter[] parameters, Expression expression) {
1573         TupleExpression argListExp = (TupleExpression) expression;
1574         List arguments = argListExp.getExpressions();
1575         for (int i = 0, size = arguments.size(); i < size; i++) {
1576             Expression argExp = argListExp.getExpression(i);
1577             Parameter param = parameters[i];
1578             visitAndAutoboxBoolean(argExp);
1579 
1580             ClassNode type = param.getType();
1581             ClassNode expType = getExpressionType(argExp);
1582             if (!type.equals(expType)) {
1583                 doConvertAndCast(type);
1584             }
1585         }
1586     }
1587 
1588     /***
1589      * Attempts to find the method of the given name in a super class
1590      */
1591     protected MethodNode findSuperMethod(MethodCallExpression call) {
1592         String methodName = call.getMethod();
1593         TupleExpression argExpr = (TupleExpression) call.getArguments();
1594         int argCount = argExpr.getExpressions().size();
1595         ClassNode superClassNode = classNode.getSuperClass();
1596         if (superClassNode != null) {
1597             List methods = superClassNode.getMethods(methodName);
1598             for (Iterator iter = methods.iterator(); iter.hasNext(); ) {
1599                 MethodNode method = (MethodNode) iter.next();
1600                 if (method.getParameters().length == argCount) {
1601                     return method;
1602                 }
1603             }
1604         }
1605         throwException("No such method: " + methodName + " for class: " + classNode.getName());
1606         return null; // should not come here
1607     }
1608 
1609     /***
1610      * Attempts to find the constructor in a super class
1611      */
1612     protected ConstructorNode findSuperConstructor(MethodCallExpression call) {
1613         TupleExpression argExpr = (TupleExpression) call.getArguments();
1614         int argCount = argExpr.getExpressions().size();
1615         ClassNode superClassNode = classNode.getSuperClass();
1616         if (superClassNode != null) {
1617             List constructors = superClassNode.getDeclaredConstructors();
1618             for (Iterator iter = constructors.iterator(); iter.hasNext(); ) {
1619                 ConstructorNode constructor = (ConstructorNode) iter.next();
1620                 if (constructor.getParameters().length == argCount) {
1621                     return constructor;
1622                 }
1623             }
1624         }
1625         throwException("No such constructor for class: " + classNode.getName());
1626         return null; // should not come here
1627     }
1628 
1629     protected boolean emptyArguments(Expression arguments) {
1630         if (arguments instanceof TupleExpression) {
1631             TupleExpression tupleExpression = (TupleExpression) arguments;
1632             int size = tupleExpression.getExpressions().size();
1633             return size == 0;
1634         }
1635         return false;
1636     }
1637 
1638     public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
1639         this.leftHandExpression = false;
1640 
1641         Expression arguments = call.getArguments();
1642         if (emptyArguments(arguments)) {
1643             cv.visitLdcInsn(call.getOwnerType().getName());
1644             cv.visitLdcInsn(call.getMethod());
1645 
1646             invokeStaticNoArgumentsMethod.call(cv);
1647         }
1648         else {
1649             if (arguments instanceof TupleExpression) {
1650                 TupleExpression tupleExpression = (TupleExpression) arguments;
1651                 int size = tupleExpression.getExpressions().size();
1652                 if (size == 1) {
1653                     arguments = (Expression) tupleExpression.getExpressions().get(0);
1654                 }
1655             }
1656 
1657             cv.visitLdcInsn(call.getOwnerType().getName());
1658             cv.visitLdcInsn(call.getMethod());
1659             arguments.visit(this);
1660 
1661             invokeStaticMethodMethod.call(cv);
1662         }
1663     }
1664 
1665     public void visitConstructorCallExpression(ConstructorCallExpression call) {
1666         onLineNumber(call, "visitConstructorCallExpression: \"" + call.getType().getName() + "\":");
1667         this.leftHandExpression = false;
1668 
1669         Expression arguments = call.getArguments();
1670         if (arguments instanceof TupleExpression) {
1671             TupleExpression tupleExpression = (TupleExpression) arguments;
1672             int size = tupleExpression.getExpressions().size();
1673             if (size == 0) {
1674                 arguments = null;
1675             }
1676         }
1677 
1678         // lets check that the type exists
1679         ClassNode type = call.getType();
1680         
1681         if (this.classNode != null) {
1682             // TODO: GROOVY-435
1683             pushClassTypeArgument(this.classNode, this.classNode);
1684             pushClassTypeArgument(this.classNode, type);
1685 
1686             if (arguments != null) {
1687                 arguments.visit(this);
1688                 invokeConstructorAtMethod.call(cv);
1689             } else {
1690                 invokeNoArgumentsConstructorAt.call(cv);
1691             }
1692         }
1693         else {
1694             pushClassTypeArgument(this.classNode, type);
1695 
1696             if (arguments !=null) {
1697                 arguments.visit(this);
1698                 invokeConstructorOfMethod.call(cv);
1699             } else {
1700                 invokeNoArgumentsConstructorOf.call(cv);
1701             }
1702         }
1703     }
1704     
1705     private static String getStaticFieldName(ClassNode type) {
1706         String name = "class$" + BytecodeHelper.getClassInternalName(type).replace('/', '$').replace('[', '_').replace(';', '_');
1707         return name;
1708     }
1709     
1710     protected void pushClassTypeArgument(ClassNode ownerType, ClassNode type) {
1711         String name = type.getName();
1712     	String staticFieldName = getStaticFieldName(type);
1713         String ownerName = ownerType.getName().replace('.','/');
1714 
1715         syntheticStaticFields.add(staticFieldName);
1716         cv.visitFieldInsn(GETSTATIC, ownerName, staticFieldName, "Ljava/lang/Class;");
1717         Label l0 = new Label();
1718         cv.visitJumpInsn(IFNONNULL, l0);
1719         cv.visitLdcInsn(name);
1720         cv.visitMethodInsn(INVOKESTATIC, ownerName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
1721         cv.visitInsn(DUP);
1722         cv.visitFieldInsn(PUTSTATIC, ownerName, staticFieldName, "Ljava/lang/Class;");
1723         Label l1 = new Label();
1724         cv.visitJumpInsn(GOTO, l1);
1725         cv.visitLabel(l0);
1726         cv.visitFieldInsn(GETSTATIC, ownerName, staticFieldName, "Ljava/lang/Class;");
1727         cv.visitLabel(l1);
1728     }
1729  
1730     public void visitPropertyExpression(PropertyExpression expression) {
1731         Expression objectExpression = expression.getObjectExpression();
1732         if (isThisExpression(objectExpression)) {
1733             // lets use the field expression if its available
1734             String name = expression.getProperty();
1735             FieldNode field = classNode.getField(name);
1736             if (field != null) {
1737                 visitFieldExpression(new FieldExpression(field));
1738                 return;
1739             }
1740         }
1741 
1742         // we need to clear the LHS flag to avoid "this." evaluating as ASTORE
1743         // rather than ALOAD
1744         boolean left = leftHandExpression;
1745         leftHandExpression = false;
1746         objectExpression.visit(this);
1747         leftHandExpression = left;
1748 
1749         cv.visitLdcInsn(expression.getProperty());
1750 
1751         if (isGroovyObject(objectExpression) && ! expression.isSafe()) {
1752             if (left) {
1753                 setGroovyObjectPropertyMethod.call(cv);
1754             }
1755             else {
1756                 getGroovyObjectPropertyMethod.call(cv);
1757             }
1758         }
1759         else {
1760             if (expression.isSafe()) {
1761                 if (left) {
1762                     setPropertySafeMethod2.call(cv);
1763                 }
1764                 else {
1765                     if (expression.isSpreadSafe()) {
1766                         getPropertySpreadSafeMethod.call(cv);
1767                     }
1768                     else {
1769                         getPropertySafeMethod.call(cv);
1770                     }
1771                 }
1772             }
1773             else {
1774                 if (left) {
1775                     setPropertyMethod2.call(cv);
1776                 }
1777                 else {
1778                     getPropertyMethod.call(cv);
1779                 }
1780             }
1781         }
1782     }
1783 
1784     public void visitAttributeExpression(AttributeExpression expression) {
1785         Expression objectExpression = expression.getObjectExpression();
1786         if (isThisExpression(objectExpression)) {
1787             // lets use the field expression if its available
1788             String name = expression.getProperty();
1789             FieldNode field = classNode.getField(name);
1790             if (field != null) {
1791                 visitFieldExpression(new FieldExpression(field));
1792                 return;
1793             }
1794         }
1795 
1796         // we need to clear the LHS flag to avoid "this." evaluating as ASTORE
1797         // rather than ALOAD
1798         boolean left = leftHandExpression;
1799         leftHandExpression = false;
1800         objectExpression.visit(this);
1801         leftHandExpression = left;
1802 
1803         cv.visitLdcInsn(expression.getProperty());
1804 
1805         if (expression.isSafe()) {
1806             if (left) {
1807                 setAttributeSafeMethod2.call(cv);
1808             }
1809             else {
1810                 if (expression.isSpreadSafe()) {
1811                     getAttributeSpreadSafeMethod.call(cv);
1812                 }
1813                 else {
1814                     getAttributeSafeMethod.call(cv);
1815                 }
1816             }
1817         }
1818         else {
1819             if (left) {
1820                 setAttributeMethod2.call(cv);
1821             }
1822             else {
1823                 getAttributeMethod.call(cv);
1824             }
1825         }
1826     }
1827 
1828     protected boolean isGroovyObject(Expression objectExpression) {
1829         return isThisExpression(objectExpression);
1830     }
1831 
1832     public void visitFieldExpression(FieldExpression expression) {
1833         FieldNode field = expression.getField();
1834 
1835 
1836 	    if (field.isStatic()) {
1837         	if (leftHandExpression) {
1838         		storeStaticField(expression);
1839         	}
1840         	else {
1841         		loadStaticField(expression);
1842         	}
1843         } else {
1844         	if (leftHandExpression) {
1845         		storeThisInstanceField(expression);
1846         	}
1847         	else {
1848         		loadInstanceField(expression);
1849         	}
1850 		}
1851     }
1852 
1853     /***
1854      *
1855      * @param fldExp
1856      */
1857     public void loadStaticField(FieldExpression fldExp) {
1858         FieldNode field = fldExp.getField();
1859         boolean holder = field.isHolder() && !isInClosureConstructor();
1860         ClassNode type = field.getType();
1861 
1862         String ownerName = (field.getOwner().equals(classNode))
1863                 ? internalClassName
1864                 : BytecodeHelper.getClassInternalName(field.getOwner());
1865         if (holder) {
1866             cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
1867             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
1868         }
1869         else {
1870             cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
1871             if (ClassHelper.isPrimitiveType(type)) {
1872                 helper.box(type);
1873 			} else {
1874 			}
1875         }
1876     }
1877 
1878 	/***
1879 	 * RHS instance field. should move most of the code in the BytecodeHelper
1880 	 * @param fldExp
1881 	 */
1882     public void loadInstanceField(FieldExpression fldExp) {
1883     	FieldNode field = fldExp.getField();
1884         boolean holder = field.isHolder() && !isInClosureConstructor();
1885         ClassNode type = field.getType();
1886         String ownerName = (field.getOwner().equals(classNode))
1887 				? internalClassName
1888 				: helper.getClassInternalName(field.getOwner());
1889 
1890         cv.visitVarInsn(ALOAD, 0);
1891 		cv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
1892 
1893 		if (holder) {
1894 			cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
1895 		} else {
1896 			if (ClassHelper.isPrimitiveType(type)) {
1897 				helper.box(type);
1898 			} else {
1899 			}
1900 		}
1901     }
1902 
1903     public void storeThisInstanceField(FieldExpression expression) {
1904         FieldNode field = expression.getField();
1905 
1906         boolean holder = field.isHolder() && !isInClosureConstructor();
1907         ClassNode type = field.getType();
1908 
1909         String ownerName =  (field.getOwner().equals(classNode)) ?
1910         		internalClassName : BytecodeHelper.getClassInternalName(field.getOwner());
1911         if (holder) {
1912             Variable tv = visitASTOREInTemp(field.getName());
1913             int tempIndex = tv.getIndex();
1914             cv.visitVarInsn(ALOAD, 0);
1915             cv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1916             cv.visitVarInsn(ALOAD, tempIndex);
1917             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
1918             removeVar(tv);
1919         }
1920         else {
1921             if (isInClosureConstructor()) {
1922                 helper.doCast(type);
1923             }
1924             else {
1925                 doConvertAndCast(type);
1926             }
1927             //Variable tmpVar = defineVariable(createVariableName(field.getName()), "java.lang.Object", false);
1928             Variable tmpVar = defineVariable(createVariableName(field.getName()), field.getType(), false);
1929             //int tempIndex = tmpVar.getIndex();
1930             //helper.store(field.getType(), tempIndex);
1931             helper.store(tmpVar, MARK_START);
1932             helper.loadThis(); //cv.visitVarInsn(ALOAD, 0);
1933             helper.load(tmpVar);
1934             helper.putField(field, ownerName);
1935             //cv.visitFieldInsn(PUTFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1936             // let's remove the temp var
1937             removeVar(tmpVar);
1938         }
1939     }
1940 
1941 
1942     public void storeStaticField(FieldExpression expression) {
1943     	FieldNode field = expression.getField();
1944 
1945         boolean holder = field.isHolder() && !isInClosureConstructor();
1946 
1947         ClassNode type = field.getType();
1948 
1949         String ownerName = (field.getOwner().equals(classNode))
1950                 ? internalClassName
1951                 : helper.getClassInternalName(field.getOwner());
1952         if (holder) {
1953             Variable tv = visitASTOREInTemp(field.getName());
1954             int tempIndex = tv.getIndex();
1955             cv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1956             cv.visitVarInsn(ALOAD, tempIndex);
1957             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
1958             removeVar(tv);
1959         }
1960         else {
1961             if (isInClosureConstructor()) {
1962                 helper.doCast(type);
1963             }
1964             else {
1965                 // this may be superfluous
1966                 //doConvertAndCast(type);
1967                 // use weaker cast
1968                 helper.doCast(type);
1969             }
1970             cv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1971         }
1972     }
1973 
1974     protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) {
1975         FieldNode field = expression.getField();
1976         boolean isStatic = field.isStatic();
1977 
1978         Variable fieldTemp = defineVariable(createVariableName(field.getName()), ClassHelper.OBJECT_TYPE, false);
1979         int valueIdx = fieldTemp.getIndex();
1980 
1981         if (leftHandExpression && first) {
1982             cv.visitVarInsn(ASTORE, valueIdx);
1983             visitVariableStartLabel(fieldTemp);
1984         }
1985 
1986         if (steps > 1 || !isStatic) {
1987             cv.visitVarInsn(ALOAD, 0);
1988             cv.visitFieldInsn(
1989                 GETFIELD,
1990                 internalClassName,
1991                 "owner",
1992                 BytecodeHelper.getTypeDescription(outerClassNode));
1993         }
1994 
1995         if( steps == 1 ) {
1996             int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD);
1997             String ownerName = BytecodeHelper.getClassInternalName(outerClassNode);
1998 
1999             if (leftHandExpression) {
2000                 cv.visitVarInsn(ALOAD, valueIdx);
2001                 boolean holder = field.isHolder() && !isInClosureConstructor();
2002                 if ( !holder) {
2003                     doConvertAndCast(field.getType());
2004                 }
2005             }
2006             cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
2007             if (!leftHandExpression) {
2008                 if (ClassHelper.isPrimitiveType(field.getType())) {
2009                     helper.box(field.getType());
2010                 }
2011             }
2012         }
2013 
2014         else {
2015             visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false );
2016         }
2017     }
2018 
2019 
2020 
2021     /***
2022      *  Visits a bare (unqualified) variable expression.
2023      */
2024 
2025     public void visitVariableExpression(VariableExpression expression) {
2026 
2027         String variableName = expression.getName();
2028 
2029       //-----------------------------------------------------------------------
2030       // SPECIAL CASES
2031 
2032         //
2033         // "this" for static methods is the Class instance
2034 
2035         if (isStaticMethod() && variableName.equals("this")) {
2036             visitClassExpression(new ClassExpression(classNode));
2037             return;                                               // <<< FLOW CONTROL <<<<<<<<<
2038         }
2039 
2040         //
2041         // "super" also requires special handling
2042 
2043         if (variableName.equals("super")) {
2044             visitClassExpression(new ClassExpression(classNode.getSuperClass()));
2045             return;                                               // <<< FLOW CONTROL <<<<<<<<<
2046         }
2047 
2048 
2049         //
2050         // class names return a Class instance, too
2051 
2052 //        if (!variableName.equals("this")) {
2053 //            String className = resolveClassName(variableName);
2054 //            if (className != null) {
2055 //                if (leftHandExpression) {
2056 //                    throw new RuntimeParserException(
2057 //                        "Cannot use a class expression on the left hand side of an assignment",
2058 //                        expression);
2059 //                }
2060 //                visitClassExpression(new ClassExpression(className));
2061 //                return;                                               // <<< FLOW CONTROL <<<<<<<<<
2062 //            }
2063 //        }
2064 
2065 
2066       //-----------------------------------------------------------------------
2067       // GENERAL VARIABLE LOOKUP
2068 
2069 
2070         //
2071         // We are handling only unqualified variables here.  Therefore,
2072         // we do not care about accessors, because local access doesn't
2073         // go through them.  Therefore, precedence is as follows:
2074         //   1) local variables, nearest block first
2075         //   2) class fields
2076         //   3) repeat search from 2) in next outer class
2077 
2078         boolean  handled  = false;
2079         Variable variable = (Variable)variableStack.get( variableName );
2080 
2081         if( variable != null ) {
2082 
2083             if( variable.isProperty() ) {
2084                 processPropertyVariable(variable );
2085             }
2086             else {
2087                 processStackVariable(variable );
2088             }
2089 
2090             handled = true;
2091         } else {
2092             //
2093             // Loop through outer classes for fields
2094 
2095             int       steps   = 0;
2096             ClassNode currentClassNode = classNode;
2097             FieldNode field   = null;
2098 
2099             do {
2100                 if( (field = currentClassNode.getField(variableName)) != null ) {
2101                     if (methodNode == null || !methodNode.isStatic() || field.isStatic() )
2102                         break; //this is a match. break out. todo to be tested
2103                 }
2104                 steps++;
2105 
2106             } while( (currentClassNode = currentClassNode.getOuterClass()) != null );
2107 
2108             if( field != null ) {
2109                 processFieldAccess( variableName, field, steps );
2110                 handled = true;
2111             }
2112         }
2113 
2114         //
2115         // Finally, if unhandled, create a variable for it.
2116         // Except there a stack variable should be created,
2117         // we define the variable as a property accessor and
2118         // let other parts of the classgen report the error
2119         // if the property doesn't exist.
2120 
2121         if( !handled ) {
2122             ClassNode variableType = expression.getType();
2123             variable = defineVariable( variableName, variableType );
2124 
2125             if (leftHandExpression && variableType==ClassHelper.DYNAMIC_TYPE) {
2126                 variable.setDynamicTyped(true); // false  by default
2127             }
2128             else {
2129                 variable.setDynamicTyped(false);
2130             }
2131 
2132             if( isInScriptBody() || !leftHandExpression ) { // todo problematic: if on right hand not defined, should I report undefined var error?
2133                 variable.setProperty( true );
2134                 processPropertyVariable(variable );
2135             }
2136             else {
2137                 processStackVariable(variable );
2138             }
2139         }
2140     }
2141 
2142 
2143     protected void processStackVariable(Variable variable ) {
2144         boolean holder = variable.isHolder() && !passingClosureParams;
2145 
2146         if( leftHandExpression ) {
2147             helper.storeVar(variable, holder);
2148         }
2149         else {
2150         	helper.loadVar(variable, holder);
2151         }
2152         if (ASM_DEBUG) {
2153             helper.mark("var: " + variable.getName());
2154         }
2155     }
2156 
2157     private void visitVariableStartLabel(Variable variable) {
2158         if (CREATE_DEBUG_INFO) {
2159             Label l = variable.getStartLabel();
2160             if (l != null) {
2161                 cv.visitLabel(l);
2162             } else {
2163                 System.out.println("start label == null! what to do about this?");
2164             }
2165         }
2166     }
2167 
2168     protected void processPropertyVariable(Variable variable ) {
2169     	String name = variable.getName();
2170         if (variable.isHolder() && passingClosureParams && isInScriptBody() ) {
2171             // lets create a ScriptReference to pass into the closure
2172             cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference");
2173             cv.visitInsn(DUP);
2174 
2175             loadThisOrOwner();
2176             cv.visitLdcInsn(name);
2177 
2178             cv.visitMethodInsn(
2179                 INVOKESPECIAL,
2180                 "org/codehaus/groovy/runtime/ScriptReference",
2181                 "<init>",
2182                 "(Lgroovy/lang/Script;Ljava/lang/String;)V");
2183         }
2184         else {
2185             visitPropertyExpression(new PropertyExpression(VariableExpression.THIS_EXPRESSION, name));
2186         }
2187     }
2188 
2189 
2190     protected void processFieldAccess( String name, FieldNode field, int steps ) {
2191         FieldExpression expression = new FieldExpression(field);
2192 
2193         if( steps == 0 ) {
2194             visitFieldExpression( expression );
2195         }
2196         else {
2197             visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true );
2198         }
2199     }
2200 
2201 
2202 
2203     /***
2204      * @return true if we are in a script body, where all variables declared are no longer
2205      * local variables but are properties
2206      */
2207     protected boolean isInScriptBody() {
2208         if (classNode.isScriptBody()) {
2209             return true;
2210         }
2211         else {
2212             return classNode.isScript() && methodNode != null && methodNode.getName().equals("run");
2213         }
2214     }
2215 
2216     /***
2217      * @return true if this expression will have left a value on the stack
2218      * that must be popped
2219      */
2220     protected boolean isPopRequired(Expression expression) {
2221         if (expression instanceof MethodCallExpression) {
2222             if (expression.getType()==ClassHelper.VOID_TYPE) { // nothing on the stack
2223                 return false;
2224             } else {
2225                 return !MethodCallExpression.isSuperMethodCall((MethodCallExpression) expression);
2226             }
2227         }
2228         if (expression instanceof BinaryExpression) {
2229             BinaryExpression binExp = (BinaryExpression) expression;
2230             switch (binExp.getOperation().getType()) {   // br todo should leave a copy of the value on the stack for all the assignemnt.
2231 //                case Types.EQUAL :   // br a copy of the right value is left on the stack (see evaluateEqual()) so a pop is required for a standalone assignment
2232 //                case Types.PLUS_EQUAL : // this and the following are related to evaluateBinaryExpressionWithAsignment()
2233 //                case Types.MINUS_EQUAL :
2234 //                case Types.MULTIPLY_EQUAL :
2235 //                case Types.DIVIDE_EQUAL :
2236 //                case Types.INTDIV_EQUAL :
2237 //                case Types.MOD_EQUAL :
2238 //                    return false;
2239             }
2240         }
2241         return true;
2242     }
2243 
2244     protected boolean firstStatementIsSuperInit(Statement code) {
2245         ExpressionStatement expStmt = null;
2246         if (code instanceof ExpressionStatement) {
2247             expStmt = (ExpressionStatement) code;
2248         }
2249         else if (code instanceof BlockStatement) {
2250             BlockStatement block = (BlockStatement) code;
2251             if (!block.getStatements().isEmpty()) {
2252                 Object expr = block.getStatements().get(0);
2253                 if (expr instanceof ExpressionStatement) {
2254                     expStmt = (ExpressionStatement) expr;
2255                 }
2256             }
2257         }
2258         if (expStmt != null) {
2259             Expression expr = expStmt.getExpression();
2260             if (expr instanceof MethodCallExpression) {
2261             	MethodCallExpression call = (MethodCallExpression) expr;
2262                 if (MethodCallExpression.isSuperMethodCall(call)) {
2263                     // not sure which one is constantly used as the super class ctor call. To cover both for now
2264                 	return call.getMethod().equals("<init>") || call.getMethod().equals("super");
2265                 }
2266             }
2267         }
2268         return false;
2269     }
2270 
2271     protected void createSyntheticStaticFields() {
2272         for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) {
2273             String staticFieldName = (String) iter.next();
2274             // generate a field node
2275             cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null);
2276         }
2277 
2278         if (!syntheticStaticFields.isEmpty()) {
2279             cv =
2280                 cw.visitMethod(
2281                     ACC_STATIC + ACC_SYNTHETIC,
2282                     "class$",
2283                     "(Ljava/lang/String;)Ljava/lang/Class;",
2284                     null,
2285                     null);
2286             helper = new BytecodeHelper(cv);
2287 
2288             Label l0 = new Label();
2289             cv.visitLabel(l0);
2290             cv.visitVarInsn(ALOAD, 0);
2291             cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
2292             Label l1 = new Label();
2293             cv.visitLabel(l1);
2294             cv.visitInsn(ARETURN);
2295             Label l2 = new Label();
2296             cv.visitLabel(l2);
2297             cv.visitVarInsn(ASTORE, 1);
2298             cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
2299             cv.visitInsn(DUP);
2300             cv.visitVarInsn(ALOAD, 1);
2301             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;");
2302             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
2303             cv.visitInsn(ATHROW);
2304             cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); // br using l2 as the 2nd param seems create the right table entry
2305             cv.visitMaxs(3, 2);
2306 
2307             cw.visitEnd();
2308         }
2309     }
2310 
2311     /*** load class object on stack */
2312     public void visitClassExpression(ClassExpression expression) {
2313         ClassNode type = expression.getType();
2314         //type = checkValidType(type, expression, "Must be a valid type name for a constructor call");
2315 
2316 
2317         if (ClassHelper.isPrimitiveType(type)) {
2318             ClassNode objectType = ClassHelper.getWrapper(type);
2319             cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;");
2320         }
2321         else {
2322             final String staticFieldName =
2323                 (type.equals(classNode)) ? "class$0" : getStaticFieldName(type);
2324 
2325             syntheticStaticFields.add(staticFieldName);
2326 
2327             cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
2328             Label l0 = new Label();
2329             cv.visitJumpInsn(IFNONNULL, l0);
2330             cv.visitLdcInsn(type.getName());
2331             cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
2332             cv.visitInsn(DUP);
2333             cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
2334             Label l1 = new Label();
2335             cv.visitJumpInsn(GOTO, l1);
2336             cv.visitLabel(l0);
2337             cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
2338             cv.visitLabel(l1);
2339         }
2340     }
2341 
2342     public void visitRangeExpression(RangeExpression expression) {
2343         leftHandExpression = false;
2344         expression.getFrom().visit(this);
2345 
2346         leftHandExpression = false;
2347         expression.getTo().visit(this);
2348 
2349         helper.pushConstant(expression.isInclusive());
2350 
2351         createRangeMethod.call(cv);
2352     }
2353 
2354     public void visitMapEntryExpression(MapEntryExpression expression) {
2355     }
2356 
2357     public void visitMapExpression(MapExpression expression) {
2358         List entries = expression.getMapEntryExpressions();
2359         int size = entries.size();
2360         helper.pushConstant(size * 2);
2361 
2362         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2363 
2364         int i = 0;
2365         for (Iterator iter = entries.iterator(); iter.hasNext();) {
2366             Object object = iter.next();
2367             MapEntryExpression entry = (MapEntryExpression) object;
2368 
2369             cv.visitInsn(DUP);
2370             helper.pushConstant(i++);
2371             visitAndAutoboxBoolean(entry.getKeyExpression());
2372             cv.visitInsn(AASTORE);
2373 
2374             cv.visitInsn(DUP);
2375             helper.pushConstant(i++);
2376             visitAndAutoboxBoolean(entry.getValueExpression());
2377             cv.visitInsn(AASTORE);
2378         }
2379         createMapMethod.call(cv);
2380     }
2381 
2382     public void visitTupleExpression(TupleExpression expression) {
2383         int size = expression.getExpressions().size();
2384 
2385         helper.pushConstant(size);
2386 
2387         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2388 
2389         for (int i = 0; i < size; i++) {
2390             cv.visitInsn(DUP);
2391             helper.pushConstant(i);
2392             visitAndAutoboxBoolean(expression.getExpression(i));
2393             cv.visitInsn(AASTORE);
2394         }
2395         //createTupleMethod.call(cv);
2396     }
2397 
2398     public void visitArrayExpression(ArrayExpression expression) {
2399         ClassNode type = expression.getType().getComponentType();
2400         String typeName = BytecodeHelper.getClassInternalName(type);        
2401         Expression sizeExpression = expression.getSizeExpression();
2402 
2403         int size=0;
2404         if (sizeExpression != null) {
2405             // lets convert to an int
2406             visitAndAutoboxBoolean(sizeExpression);
2407             asIntMethod.call(cv);
2408         } else {
2409             size = expression.getExpressions().size();
2410             helper.pushConstant(size);
2411         }
2412 
2413         int storeIns=AASTORE;
2414         if (ClassHelper.isPrimitiveType(type)) {
2415             int primType=0;
2416             if (type==ClassHelper.boolean_TYPE) {
2417                 primType = T_BOOLEAN;
2418                 storeIns = BASTORE;
2419             } else if (type==ClassHelper.char_TYPE) {
2420                 primType = T_CHAR;
2421                 storeIns = CASTORE;
2422             } else if (type==ClassHelper.float_TYPE) {
2423                 primType = T_FLOAT;
2424                 storeIns = FASTORE;
2425             } else if (type==ClassHelper.double_TYPE) {
2426                 primType = T_DOUBLE;
2427                 storeIns = DASTORE;
2428             } else if (type==ClassHelper.byte_TYPE) {
2429                 primType = T_BYTE;
2430                 storeIns = BASTORE;
2431             } else if (type==ClassHelper.short_TYPE) {
2432                 primType = T_SHORT;
2433                 storeIns = SASTORE;
2434             } else if (type==ClassHelper.int_TYPE) {
2435                 primType = T_INT;
2436                 storeIns=IASTORE;
2437             } else if (type==ClassHelper.long_TYPE) {
2438                 primType = T_LONG;
2439                 storeIns = LASTORE;
2440             } 
2441             cv.visitIntInsn(NEWARRAY, primType);
2442         } else {
2443             cv.visitTypeInsn(ANEWARRAY, typeName);
2444         }
2445 
2446         for (int i = 0; i < size; i++) {
2447             cv.visitInsn(DUP);
2448             helper.pushConstant(i);
2449             Expression elementExpression = expression.getExpression(i);
2450             if (elementExpression == null) {
2451                 ConstantExpression.NULL.visit(this);
2452             } else {
2453                 if (!type.equals(elementExpression.getType())) {
2454                     visitCastExpression(new CastExpression(type, elementExpression, true));
2455                 } else {
2456                     visitAndAutoboxBoolean(elementExpression);
2457                 }
2458             }
2459             cv.visitInsn(storeIns);            
2460         }
2461         
2462         if (ClassHelper.isPrimitiveType(type)) {
2463             int par = defineVariable("par",ClassHelper.OBJECT_TYPE).getIndex();
2464             cv.visitVarInsn(ASTORE, par);
2465             cv.visitVarInsn(ALOAD, par);
2466         }
2467     }
2468 
2469     public void visitListExpression(ListExpression expression) {
2470         int size = expression.getExpressions().size();
2471         helper.pushConstant(size);
2472 
2473         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2474 
2475         for (int i = 0; i < size; i++) {
2476             cv.visitInsn(DUP);
2477             helper.pushConstant(i);
2478             visitAndAutoboxBoolean(expression.getExpression(i));
2479             cv.visitInsn(AASTORE);
2480         }
2481         createListMethod.call(cv);
2482     }
2483 
2484     public void visitGStringExpression(GStringExpression expression) {
2485         int size = expression.getValues().size();
2486         helper.pushConstant(size);
2487 
2488         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2489 
2490         for (int i = 0; i < size; i++) {
2491             cv.visitInsn(DUP);
2492             helper.pushConstant(i);
2493             visitAndAutoboxBoolean(expression.getValue(i));
2494             cv.visitInsn(AASTORE);
2495         }
2496 
2497         Variable tv = visitASTOREInTemp("iterator");
2498         int paramIdx = tv.getIndex();
2499 
2500         ClassNode innerClass = createGStringClass(expression);
2501         addInnerClass(innerClass);
2502         String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass);
2503 
2504         cv.visitTypeInsn(NEW, innerClassinternalName);
2505         cv.visitInsn(DUP);
2506         cv.visitVarInsn(ALOAD, paramIdx);
2507 
2508         cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V");
2509         removeVar(tv);
2510     }
2511 
2512     private Variable visitASTOREInTemp(String s) {
2513         return storeInTemp(s, ClassHelper.OBJECT_TYPE);
2514     }
2515     
2516     public void visitAnnotations(AnnotatedNode node) {
2517         Map annotionMap = node.getAnnotations();
2518         if (annotionMap.isEmpty()) return;
2519         Iterator it = annotionMap.values().iterator(); 
2520         while (it.hasNext()) {
2521             AnnotationNode an = (AnnotationNode) it.next();
2522             //skip builtin properties
2523             if (an.isBuiltIn()) continue;
2524             ClassNode type = an.getClassNode();
2525 
2526             String clazz = type.getName();
2527             AnnotationVisitor av = cw.visitAnnotation(BytecodeHelper.formatNameForClassLoading(clazz),false);
2528 
2529             Iterator mIt = an.getMembers().keySet().iterator();
2530             while (mIt.hasNext()) {
2531                 String name = (String) mIt.next();
2532                 ConstantExpression exp = (ConstantExpression) an.getMember(name);
2533                 av.visit(name,exp.getValue());
2534             }
2535             av.visitEnd();
2536         }
2537     }
2538     
2539     
2540     // Implementation methods
2541     //-------------------------------------------------------------------------
2542     protected boolean addInnerClass(ClassNode innerClass) {
2543         innerClass.setModule(classNode.getModule());
2544         return innerClasses.add(innerClass);
2545     }
2546 
2547     protected ClassNode createClosureClass(ClosureExpression expression) {
2548         ClassNode owner = getOutermostClass();
2549         ClassNode outerClass = owner;
2550         String name = owner.getName() + "$"
2551                 + context.getNextClosureInnerName(owner, classNode, methodNode); // br added a more infomative name
2552         boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass();
2553         if (staticMethodOrInStaticClass) {
2554             outerClass = ClassHelper.make(Class.class);
2555         }
2556         Parameter[] parameters = expression.getParameters();
2557         if (parameters == null || parameters.length == 0) {
2558             // lets create a default 'it' parameter
2559             parameters = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL)};
2560         }
2561 
2562         Parameter[] localVariableParams = getClosureSharedVariables(expression);
2563 
2564         InnerClassNode answer = new InnerClassNode(owner, name, 0, ClassHelper.CLOSURE_TYPE); // clsures are local inners and not public
2565         answer.setEnclosingMethod(this.methodNode);
2566         answer.setSynthetic(true);
2567         
2568         if (staticMethodOrInStaticClass) {
2569             answer.setStaticClass(true);
2570         }
2571         if (isInScriptBody()) {
2572             answer.setScriptBody(true);
2573         }
2574         MethodNode method =
2575             answer.addMethod("doCall", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, expression.getCode());
2576 
2577         method.setLineNumber(expression.getLineNumber());
2578         method.setColumnNumber(expression.getColumnNumber());
2579 
2580         VariableScope varScope = expression.getVariableScope();
2581         if (varScope == null) {
2582             throw new RuntimeException(
2583                 "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
2584         }
2585         else {
2586             method.setVariableScope(varScope);
2587         }
2588         if (parameters.length > 1
2589             || (parameters.length == 1
2590                 && parameters[0].getType() != null
2591                 && parameters[0].getType() != ClassHelper.OBJECT_TYPE)) {
2592 
2593             // lets add a typesafe call method
2594             answer.addMethod(
2595                 "call",
2596                 ACC_PUBLIC,
2597                 ClassHelper.OBJECT_TYPE,
2598                 parameters,
2599                 new ReturnStatement(
2600                     new MethodCallExpression(
2601                         VariableExpression.THIS_EXPRESSION,
2602                         "doCall",
2603                         new ArgumentListExpression(parameters))));
2604         }
2605 
2606         FieldNode ownerField = answer.addField("owner", ACC_PRIVATE, outerClass, null);
2607 
2608         // lets make the constructor
2609         BlockStatement block = new BlockStatement();
2610         block.addStatement(
2611             new ExpressionStatement(
2612                 new MethodCallExpression(
2613                     new VariableExpression("super"),
2614                     "<init>",
2615                     new VariableExpression("_outerInstance"))));
2616         block.addStatement(
2617             new ExpressionStatement(
2618                 new BinaryExpression(
2619                     new FieldExpression(ownerField),
2620                     Token.newSymbol(Types.EQUAL, -1, -1),
2621                     new VariableExpression("_outerInstance"))));
2622 
2623         // lets assign all the parameter fields from the outer context
2624         for (int i = 0; i < localVariableParams.length; i++) {
2625             Parameter param = localVariableParams[i];
2626             String paramName = param.getName();
2627             boolean holder = mutableVars.contains(paramName);
2628             Expression initialValue = null;
2629             ClassNode type = param.getType();
2630             FieldNode paramField = null;
2631             if (holder) {
2632             	initialValue = new VariableExpression(paramName);
2633                 ClassNode realType = type;
2634                 type = ClassHelper.makeReference();
2635                 param.setType(type);
2636                 paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue);
2637                 paramField.setHolder(true);
2638                 String methodName = Verifier.capitalize(paramName);
2639 
2640                 // lets add a getter & setter
2641                 Expression fieldExp = new FieldExpression(paramField);
2642                 answer.addMethod(
2643                     "get" + methodName,
2644                     ACC_PUBLIC,
2645                     realType,
2646                     Parameter.EMPTY_ARRAY,
2647                     new ReturnStatement(fieldExp));
2648 
2649                 /*
2650                 answer.addMethod(
2651                     "set" + methodName,
2652                     ACC_PUBLIC,
2653                     "void",
2654                     new Parameter[] { new Parameter(realType, "__value") },
2655                     new ExpressionStatement(
2656                         new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("__value"))));
2657                         */
2658             }
2659             else {
2660             	PropertyNode propertyNode = answer.addProperty(paramName, ACC_PUBLIC, type, initialValue, null, null);
2661                 paramField = propertyNode.getField();
2662                 block.addStatement(
2663                     new ExpressionStatement(
2664                         new BinaryExpression(
2665                             new FieldExpression(paramField),
2666                             Token.newSymbol(Types.EQUAL, -1, -1),
2667                             new VariableExpression(paramName))));
2668             }
2669         }
2670 
2671         Parameter[] params = new Parameter[2 + localVariableParams.length];
2672         params[0] = new Parameter(outerClass, "_outerInstance");
2673         params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_delegate");
2674         System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
2675 
2676         answer.addConstructor(ACC_PUBLIC, params, block);
2677         return answer;
2678     }
2679 
2680     protected ClassNode getOutermostClass() {
2681         if (outermostClass == null) {
2682             outermostClass = classNode;
2683             while (outermostClass instanceof InnerClassNode) {
2684                 outermostClass = outermostClass.getOuterClass();
2685             }
2686         }
2687         return outermostClass;
2688     }
2689 
2690     protected ClassNode createGStringClass(GStringExpression expression) {
2691         ClassNode owner = classNode;
2692         if (owner instanceof InnerClassNode) {
2693             owner = owner.getOuterClass();
2694         }
2695         String outerClassName = owner.getName();
2696         String name = outerClassName + "$" + context.getNextInnerClassIdx();
2697         InnerClassNode answer = new InnerClassNode(owner, name, 0, ClassHelper.GSTRING_TYPE);
2698         answer.setEnclosingMethod(this.methodNode);
2699         FieldNode stringsField =
2700             answer.addField(
2701                 "strings",
2702                 ACC_PRIVATE /*| ACC_STATIC*/,
2703                 ClassHelper.STRING_TYPE.makeArray(),
2704                 new ArrayExpression(ClassHelper.STRING_TYPE, expression.getStrings()));
2705         answer.addMethod(
2706             "getStrings",
2707             ACC_PUBLIC,
2708             ClassHelper.STRING_TYPE.makeArray(),
2709             Parameter.EMPTY_ARRAY,
2710             new ReturnStatement(new FieldExpression(stringsField)));
2711         // lets make the constructor
2712         BlockStatement block = new BlockStatement();
2713         block.addStatement(
2714             new ExpressionStatement(
2715                 new MethodCallExpression(new VariableExpression("super"), "<init>", new VariableExpression("values"))));
2716         Parameter[] contructorParams = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "values")};
2717         answer.addConstructor(ACC_PUBLIC, contructorParams, block);
2718         return answer;
2719     }
2720 
2721     protected void doConvertAndCast(ClassNode type) {
2722         if (type==ClassHelper.OBJECT_TYPE) return;
2723         if (isValidTypeForCast(type)) {
2724             visitClassExpression(new ClassExpression(type));
2725             asTypeMethod.call(cv);
2726         }
2727         helper.doCast(type);
2728     }
2729 
2730     protected void evaluateLogicalOrExpression(BinaryExpression expression) {
2731         visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
2732         Label l0 = new Label();
2733         Label l2 = new Label();
2734         cv.visitJumpInsn(IFEQ, l0);
2735 
2736         cv.visitLabel(l2);
2737 
2738         visitConstantExpression(ConstantExpression.TRUE);
2739 
2740         Label l1 = new Label();
2741         cv.visitJumpInsn(GOTO, l1);
2742         cv.visitLabel(l0);
2743 
2744         visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
2745 
2746         cv.visitJumpInsn(IFNE, l2);
2747 
2748         visitConstantExpression(ConstantExpression.FALSE);
2749         cv.visitLabel(l1);
2750     }
2751 
2752     // todo: optimization: change to return primitive boolean. need to adjust the BinaryExpression and isComparisonExpression for
2753     // consistancy.
2754     protected void evaluateLogicalAndExpression(BinaryExpression expression) {
2755         visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
2756         Label l0 = new Label();
2757         cv.visitJumpInsn(IFEQ, l0);
2758 
2759         visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
2760 
2761         cv.visitJumpInsn(IFEQ, l0);
2762 
2763         visitConstantExpression(ConstantExpression.TRUE);
2764 
2765         Label l1 = new Label();
2766         cv.visitJumpInsn(GOTO, l1);
2767         cv.visitLabel(l0);
2768 
2769         visitConstantExpression(ConstantExpression.FALSE);
2770 
2771         cv.visitLabel(l1);
2772     }
2773 
2774     protected void evaluateBinaryExpression(String method, BinaryExpression expression) {
2775         Expression leftExpression = expression.getLeftExpression();
2776         leftHandExpression = false;
2777         leftExpression.visit(this);
2778         cv.visitLdcInsn(method);
2779         leftHandExpression = false;
2780         new ArgumentListExpression(new Expression[] { expression.getRightExpression()}).visit(this);
2781         // expression.getRightExpression().visit(this);
2782         invokeMethodMethod.call(cv);
2783     }
2784 
2785     protected void evaluateCompareTo(BinaryExpression expression) {
2786         Expression leftExpression = expression.getLeftExpression();
2787         leftHandExpression = false;
2788         leftExpression.visit(this);
2789         if (isComparisonExpression(leftExpression)) {
2790             helper.boxBoolean();
2791         }
2792 
2793         // if the right hand side is a boolean expression, we need to autobox
2794         Expression rightExpression = expression.getRightExpression();
2795         rightExpression.visit(this);
2796         if (isComparisonExpression(rightExpression)) {
2797             helper.boxBoolean();
2798         }
2799         compareToMethod.call(cv);
2800     }
2801 
2802     protected void evaluateBinaryExpressionWithAsignment(String method, BinaryExpression expression) {
2803         Expression leftExpression = expression.getLeftExpression();
2804         if (leftExpression instanceof BinaryExpression) {
2805             BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
2806             if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
2807                 // lets replace this assignment to a subscript operator with a
2808                 // method call
2809                 // e.g. x[5] += 10
2810                 // -> (x, [], 5), =, x[5] + 10
2811                 // -> methodCall(x, "putAt", [5, methodCall(x[5], "plus", 10)])
2812 
2813                 MethodCallExpression methodCall =
2814                     new MethodCallExpression(
2815                         expression.getLeftExpression(),
2816                         method,
2817                         new ArgumentListExpression(new Expression[] { expression.getRightExpression()}));
2818 
2819                 Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression());
2820 
2821                 visitMethodCallExpression(
2822                     new MethodCallExpression(
2823                         leftBinExpr.getLeftExpression(),
2824                         "putAt",
2825                         new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall })));
2826                 //cv.visitInsn(POP);
2827                 return;
2828             }
2829         }
2830 
2831         evaluateBinaryExpression(method, expression);
2832 
2833         // br to leave a copy of rvalue on the stack. see also isPopRequired()
2834         cv.visitInsn(DUP);
2835 
2836         leftHandExpression = true;
2837         evaluateExpression(leftExpression);
2838         leftHandExpression = false;
2839     }
2840 
2841     private void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression bin) {
2842         evalBinaryExp_LateBinding(compareMethod, bin);
2843     }
2844 
2845     protected void evalBinaryExp_LateBinding(MethodCaller compareMethod, BinaryExpression expression) {
2846         Expression leftExp = expression.getLeftExpression();
2847         Expression rightExp = expression.getRightExpression();
2848         load(leftExp);
2849         load(rightExp);
2850         compareMethod.call(cv);
2851     }
2852 
2853     protected void evaluateEqual(BinaryExpression expression) {
2854 
2855         Expression leftExpression = expression.getLeftExpression();
2856         if (leftExpression instanceof BinaryExpression) {
2857             BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
2858             if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
2859                 // lets replace this assignment to a subscript operator with a
2860                 // method call
2861                 // e.g. x[5] = 10
2862                 // -> (x, [], 5), =, 10
2863                 // -> methodCall(x, "putAt", [5, 10])
2864                 
2865                 visitMethodCallExpression(
2866                     new MethodCallExpression(
2867                         leftBinExpr.getLeftExpression(),
2868                         "putAt",
2869                         new ArgumentListExpression(
2870                             new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()})));
2871                  // cv.visitInsn(POP); //this is realted to isPopRequired()
2872                 return;
2873             }
2874         }
2875 
2876         // lets evaluate the RHS then hopefully the LHS will be a field
2877         leftHandExpression = false;
2878         Expression rightExpression = expression.getRightExpression();
2879 
2880         ClassNode type = getLHSType(leftExpression);
2881         // lets not cast for primitive types as we handle these in field setting etc
2882         if (ClassHelper.isPrimitiveType(type)) {
2883             rightExpression.visit(this);
2884         } else {
2885             if (type!=ClassHelper.OBJECT_TYPE){
2886                 visitCastExpression(new CastExpression(type, rightExpression));
2887             } else {
2888                 visitAndAutoboxBoolean(rightExpression);
2889             }
2890         }
2891 
2892         cv.visitInsn(DUP);  // to leave a copy of the rightexpression value on the stack after the assignment.
2893         leftHandExpression = true;
2894         leftExpression.visit(this);
2895         leftHandExpression = false;
2896     }
2897     
2898     /***
2899      * Deduces the type name required for some casting
2900      *
2901      * @return the type of the given (LHS) expression or null if it is java.lang.Object or it cannot be deduced
2902      */
2903     protected ClassNode getLHSType(Expression leftExpression) {
2904         do {
2905 // commented out. not quiteworking yet. would complain something like:
2906 //java.lang.ClassFormatError: Foo$1 (Illegal Field name "class$[Ljava$lang$String;")
2907 //
2908 //            if (ENABLE_EARLY_BINDING) {
2909 //                String type = leftExpression.getType();
2910 //                if (type == null)
2911 //                    break;
2912 //                return isValidTypeForCast(type) ? type : null;
2913 //            }
2914         } while (false);
2915 
2916         if (leftExpression instanceof VariableExpression) {
2917             VariableExpression varExp = (VariableExpression) leftExpression;
2918             ClassNode type = varExp.getType();
2919             if (isValidTypeForCast(type)) {
2920                 return type;
2921             }
2922             String variableName = varExp.getName();
2923             Variable variable = (Variable) variableStack.get(variableName);
2924             if (variable != null) {
2925                 if (variable.isHolder() || variable.isProperty()) {
2926                     return variable.getType();
2927                 }
2928                 type = variable.getType();
2929                 if (isValidTypeForCast(type)) {
2930                     return type;
2931                 }
2932             }
2933             else {
2934                 FieldNode field = classNode.getField(variableName);
2935                 if (field == null) {
2936                     field = classNode.getOuterField(variableName);
2937                 }
2938                 if (field != null) {
2939                     type = field.getType();
2940                     if (!field.isHolder() && isValidTypeForCast(type)) {
2941                         return type;
2942                     }
2943                 }
2944             }
2945         }
2946         else if (leftExpression instanceof FieldExpression) {
2947             FieldExpression fieldExp = (FieldExpression) leftExpression;
2948             ClassNode type = fieldExp.getType();
2949             if (isValidTypeForCast(type)) {
2950                 return type;
2951             }
2952         }
2953         return ClassHelper.DYNAMIC_TYPE;
2954     }
2955 
2956     protected boolean isValidTypeForCast(ClassNode type) {
2957         return type!=ClassHelper.DYNAMIC_TYPE && !type.getName().equals("groovy.lang.Reference") && !ClassHelper.isPrimitiveType(type);
2958     }
2959 
2960     protected void visitAndAutoboxBoolean(Expression expression) {
2961         expression.visit(this);
2962 
2963         if (isComparisonExpression(expression)) {
2964             helper.boxBoolean(); // convert boolean to Boolean
2965         }
2966     }
2967 
2968     protected void evaluatePrefixMethod(String method, Expression expression) {
2969         if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) {
2970             cv.visitVarInsn(ALOAD, 0);
2971         }
2972         expression.visit(this);
2973         cv.visitLdcInsn(method);
2974         invokeNoArgumentsMethod.call(cv);
2975 
2976         leftHandExpression = true;
2977         expression.visit(this);
2978         leftHandExpression = false;
2979         expression.visit(this);
2980     }
2981 
2982     protected void evaluatePostfixMethod(String method, Expression expression) {
2983         leftHandExpression = false;
2984         expression.visit(this);
2985 
2986         Variable tv = visitASTOREInTemp("postfix_" + method);
2987         int tempIdx  = tv.getIndex();
2988         cv.visitVarInsn(ALOAD, tempIdx);
2989 
2990         cv.visitLdcInsn(method);
2991         invokeNoArgumentsMethod.call(cv);
2992 
2993         store(expression);
2994 
2995         cv.visitVarInsn(ALOAD, tempIdx);
2996         removeVar(tv);
2997     }
2998 
2999     protected boolean isHolderVariable(Expression expression) {
3000         if (expression instanceof FieldExpression) {
3001             FieldExpression fieldExp = (FieldExpression) expression;
3002             return fieldExp.getField().isHolder();
3003         }
3004         if (expression instanceof VariableExpression) {
3005             VariableExpression varExp = (VariableExpression) expression;
3006             Variable variable = (Variable) variableStack.get(varExp.getName());
3007             if (variable != null) {
3008                 return variable.isHolder();
3009             }
3010             FieldNode field = classNode.getField(varExp.getName());
3011             if (field != null) {
3012                 return field.isHolder();
3013             }
3014         }
3015         return false;
3016     }
3017 
3018     protected void evaluateInstanceof(BinaryExpression expression) {
3019         expression.getLeftExpression().visit(this);
3020         Expression rightExp = expression.getRightExpression();
3021         ClassNode classType = ClassHelper.DYNAMIC_TYPE;
3022         if (rightExp instanceof ClassExpression) {
3023             ClassExpression classExp = (ClassExpression) rightExp;
3024             classType = classExp.getType();
3025         }
3026         else {
3027             throw new RuntimeException(
3028                 "Right hand side of the instanceof keyworld must be a class name, not: " + rightExp);
3029         }
3030         String classInternalName = BytecodeHelper.getClassInternalName(classType);
3031         cv.visitTypeInsn(INSTANCEOF, classInternalName);
3032     }
3033 
3034     /***
3035      * @return true if the given argument expression requires the stack, in
3036      *         which case the arguments are evaluated first, stored in the
3037      *         variable stack and then reloaded to make a method call
3038      */
3039     protected boolean argumentsUseStack(Expression arguments) {
3040         return arguments instanceof TupleExpression || arguments instanceof ClosureExpression;
3041     }
3042 
3043     /***
3044      * @return true if the given expression represents a non-static field
3045      */
3046     protected boolean isNonStaticField(Expression expression) {
3047         FieldNode field = null;
3048         if (expression instanceof VariableExpression) {
3049             VariableExpression varExp = (VariableExpression) expression;
3050             field = classNode.getField(varExp.getName());
3051         }
3052         else if (expression instanceof FieldExpression) {
3053             FieldExpression fieldExp = (FieldExpression) expression;
3054             field = classNode.getField(fieldExp.getFieldName());
3055         }
3056         else if (expression instanceof PropertyExpression) {
3057             PropertyExpression fieldExp = (PropertyExpression) expression;
3058             field = classNode.getField(fieldExp.getProperty());
3059         }
3060         if (field != null) {
3061             return !field.isStatic();
3062         }
3063         return false;
3064     }
3065 
3066     protected boolean isThisExpression(Expression expression) {
3067         if (expression instanceof VariableExpression) {
3068             VariableExpression varExp = (VariableExpression) expression;
3069             return varExp.getName().equals("this");
3070         }
3071         return false;
3072     }
3073 
3074     /***
3075      * For assignment expressions, return a safe expression for the LHS we can use
3076      * to return the value
3077      */
3078     protected Expression createReturnLHSExpression(Expression expression) {
3079         if (expression instanceof BinaryExpression) {
3080             BinaryExpression binExpr = (BinaryExpression) expression;
3081             if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) {
3082                 return createReusableExpression(binExpr.getLeftExpression());
3083             }
3084         }
3085         return null;
3086     }
3087 
3088     protected Expression createReusableExpression(Expression expression) {
3089         ExpressionTransformer transformer = new ExpressionTransformer() {
3090             public Expression transform(Expression expression) {
3091                 if (expression instanceof PostfixExpression) {
3092                     PostfixExpression postfixExp = (PostfixExpression) expression;
3093                     return postfixExp.getExpression();
3094                 }
3095                 else if (expression instanceof PrefixExpression) {
3096                     PrefixExpression prefixExp = (PrefixExpression) expression;
3097                     return prefixExp.getExpression();
3098                 }
3099                 return expression;
3100             }
3101         };
3102 
3103         // could just be a postfix / prefix expression or nested inside some other expression
3104         return transformer.transform(expression.transformExpression(transformer));
3105     }
3106 
3107     protected boolean isComparisonExpression(Expression expression) {
3108         if (expression instanceof BinaryExpression) {
3109             BinaryExpression binExpr = (BinaryExpression) expression;
3110             switch (binExpr.getOperation().getType()) {
3111                 case Types.COMPARE_EQUAL :
3112                 case Types.MATCH_REGEX :
3113                 case Types.COMPARE_GREATER_THAN :
3114                 case Types.COMPARE_GREATER_THAN_EQUAL :
3115                 case Types.COMPARE_LESS_THAN :
3116                 case Types.COMPARE_LESS_THAN_EQUAL :
3117                 case Types.COMPARE_IDENTICAL :
3118                 case Types.COMPARE_NOT_EQUAL :
3119                 case Types.KEYWORD_INSTANCEOF :
3120                     return true;
3121             }
3122         }
3123         else if (expression instanceof BooleanExpression) {
3124             return true;
3125         }
3126         return false;
3127     }
3128 
3129     protected void onLineNumber(ASTNode statement, String message) {
3130         int line = statement.getLineNumber();
3131         int col = statement.getColumnNumber();
3132         this.currentASTNode = statement;
3133 
3134         if (line >=0) {
3135             lineNumber = line;
3136             columnNumber = col;
3137         }
3138         if (CREATE_LINE_NUMBER_INFO && line >= 0 && cv != null) {
3139             Label l = new Label();
3140             cv.visitLabel(l);
3141             cv.visitLineNumber(line, l);
3142             if (ASM_DEBUG) {
3143                 helper.mark(message + "[" + statement.getLineNumber() + ":" + statement.getColumnNumber() + "]");
3144             }
3145         }
3146     }
3147 
3148     protected VariableScope getVariableScope() {
3149         if (variableScope == null) {
3150             if (methodNode != null) {
3151                 // if we're a closure method we'll have our variable scope already created
3152                 variableScope = methodNode.getVariableScope();
3153             }
3154             else if (constructorNode != null) {
3155                 variableScope = constructorNode.getVariableScope();
3156             }
3157             else {
3158                 throw new RuntimeException("Can't create a variable scope outside of a method or constructor");
3159             }
3160         }
3161         return variableScope;
3162     }
3163 
3164     /***
3165      * @return a list of parameters for each local variable which needs to be
3166      *         passed into a closure
3167      */
3168     protected Parameter[] getClosureSharedVariables(ClosureExpression expression) {
3169         List vars = new ArrayList();
3170 
3171         //
3172         // First up, get the scopes for outside and inside the closure.
3173         // The inner scope must cover all nested closures, as well, as
3174         // everything that will be needed must be imported.
3175 
3176         VariableScope outerScope = getVariableScope().createRecursiveParentScope();
3177         VariableScope innerScope = expression.getVariableScope();
3178         if (innerScope == null) {
3179             System.out.println(
3180                 "No variable scope for: " + expression + " method: " + methodNode + " constructor: " + constructorNode);
3181             innerScope = new VariableScope(getVariableScope());
3182         }
3183         else {
3184             innerScope = innerScope.createRecursiveChildScope();
3185         }
3186 
3187 
3188         //
3189         // DeclaredVariables include any name that was assigned to within
3190         // the scope.  ReferencedVariables include any name that was read
3191         // from within the scope.  We get the sets from each and must piece
3192         // together the stack variable import list for the closure.  Note
3193         // that we don't worry about field variables here, as we don't have
3194         // to do anything special with them.  Stack variables, on the other
3195         // hand, have to be wrapped up in References for use.
3196 
3197         Set outerDecls = outerScope.getDeclaredVariables();
3198         Set outerRefs  = outerScope.getReferencedVariables();
3199         Set innerDecls = innerScope.getDeclaredVariables();
3200         Set innerRefs  = innerScope.getReferencedVariables();
3201 
3202 
3203         //
3204         // So, we care about any name referenced in the closure UNLESS:
3205         //   1) it's not declared in the outer context;
3206         //   2) it's a parameter;
3207         //   3) it's a field in the context class that isn't overridden
3208         //      by a stack variable in the outer context.
3209         //
3210         // BUG: We don't actually have the necessary information to do
3211         //      this right!  The outer declarations don't distinguish
3212         //      between assignments and variable declarations.  Therefore
3213         //      we can't tell when field variables have been overridden
3214         //      by stack variables in the outer context.  This must
3215         //      be fixed!
3216 
3217         Set varSet = new HashSet();
3218         for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
3219             String var = (String) iter.next();
3220             // lets not pass in fields from the most-outer class, but pass in values from an outer closure
3221             if (outerDecls.contains(var) && (isNotFieldOfOutermostClass(var))) {
3222                 ClassNode type = getVariableType(var);
3223                 vars.add(new Parameter(type, var));
3224                 varSet.add(var);
3225             }
3226         }
3227         for (Iterator iter = outerRefs.iterator(); iter.hasNext();) {
3228             String var = (String) iter.next();
3229             // lets not pass in fields from the most-outer class, but pass in values from an outer closure
3230             if (innerDecls.contains(var) && (isNotFieldOfOutermostClass(var)) && !varSet.contains(var)) {
3231                 ClassNode type = getVariableType(var);
3232                 vars.add(new Parameter(type, var));
3233             }
3234         }
3235 
3236 
3237         Parameter[] answer = new Parameter[vars.size()];
3238         vars.toArray(answer);
3239         return answer;
3240     }
3241 
3242     protected boolean isNotFieldOfOutermostClass(String var) {
3243         //return classNode.getField(var) == null || isInnerClass();
3244         return getOutermostClass().getField(var) == null;
3245     }
3246 
3247     protected void findMutableVariables() {
3248         /*
3249         VariableScopeCodeVisitor outerVisitor = new VariableScopeCodeVisitor(true);
3250         node.getCode().visit(outerVisitor);
3251 
3252         addFieldsToVisitor(outerVisitor);
3253 
3254         VariableScopeCodeVisitor innerVisitor = outerVisitor.getClosureVisitor();
3255         */
3256         VariableScope outerScope = getVariableScope();
3257 
3258         // lets create a scope concatenating all the closure expressions
3259         VariableScope innerScope = outerScope.createCompositeChildScope();
3260 
3261         Set outerDecls = outerScope.getDeclaredVariables();
3262         Set outerRefs = outerScope.getReferencedVariables();
3263         Set innerDecls = innerScope.getDeclaredVariables();
3264         Set innerRefs = innerScope.getReferencedVariables();
3265 
3266         mutableVars.clear();
3267 
3268         for (Iterator iter = innerDecls.iterator(); iter.hasNext();) {
3269             String var = (String) iter.next();
3270             if ((outerDecls.contains(var) || outerRefs.contains(var)) && classNode.getField(var) == null) {
3271                 mutableVars.add(var);
3272             }
3273         }
3274 
3275         // we may call the closure twice and modify the variable in the outer scope
3276         // so for now lets assume that all variables are mutable
3277         for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
3278             String var = (String) iter.next();
3279             if (outerDecls.contains(var) && classNode.getField(var) == null) {
3280                 mutableVars.add(var);
3281             }
3282         }
3283 
3284         //                System.out.println();
3285         //                System.out.println("method: " + methodNode + " classNode: " + classNode);
3286         //                System.out.println("child scopes: " + outerScope.getChildren());
3287         //                System.out.println("outerDecls: " + outerDecls);
3288         //                System.out.println("outerRefs: " + outerRefs);
3289         //                System.out.println("innerDecls: " + innerDecls);
3290         //                System.out.println("innerRefs: " + innerRefs);
3291     }
3292 
3293     private boolean isInnerClass() {
3294         return classNode instanceof InnerClassNode;
3295     }
3296 
3297     protected ClassNode getVariableType(String name) {
3298         Variable variable = (Variable) variableStack.get(name);
3299         if (variable != null) {
3300             return variable.getType();
3301         }
3302         return ClassHelper.DYNAMIC_TYPE;
3303     }
3304 
3305     protected void resetVariableStack(Parameter[] parameters) {
3306         lastVariableIndex = -1;
3307         variableStack.clear();
3308 
3309         scope = new BlockScope(null);
3310         //pushBlockScope();
3311 
3312         // lets push this onto the stack
3313         definingParameters = true;
3314         if (!isStaticMethod()) {
3315             defineVariable("this", classNode).getIndex();
3316         } // now lets create indices for the parameteres
3317         for (int i = 0; i < parameters.length; i++) {
3318             Parameter parameter = parameters[i];
3319             ClassNode type = parameter.getType();
3320             Variable v = defineVariable(parameter.getName(), type);
3321             int idx = v.getIndex();
3322             if (ClassHelper.isPrimitiveType(type)) {
3323                 helper.load(type, idx);
3324                 helper.box(type);
3325                 cv.visitVarInsn(ASTORE, idx);
3326             }
3327         }
3328         definingParameters = false;
3329     }
3330 
3331     protected void popScope() {
3332         int lastID = scope.getFirstVariableIndex();
3333 
3334         List removeKeys = new ArrayList();
3335         for (Iterator iter = variableStack.entrySet().iterator(); iter.hasNext();) {
3336             Map.Entry entry = (Map.Entry) iter.next();
3337             String name = (String) entry.getKey();
3338             Variable value = (Variable) entry.getValue();
3339             if (value.getIndex() >= lastID) {
3340                 removeKeys.add(name);
3341             }
3342         }
3343         for (Iterator iter = removeKeys.iterator(); iter.hasNext();) {
3344             Variable v  = (Variable) variableStack.remove(iter.next());
3345             if (CREATE_DEBUG_INFO) { // set localvartable
3346                 if (v != null) {
3347                     visitVariableEndLabel(v);
3348                     cv.visitLocalVariable(
3349                                           v.getName(),
3350                                           BytecodeHelper.getTypeDescription(v.getTypeName()),
3351                                           null,
3352                                           v.getStartLabel(),
3353                                           v.getEndLabel(),
3354                                           v.getIndex()
3355                                           );
3356                 }
3357             }
3358         }
3359         scope = scope.getParent();
3360     }
3361 
3362     void removeVar(Variable v ) {
3363     	variableStack.remove(v.getName());
3364         if (CREATE_DEBUG_INFO) { // set localvartable
3365         	Label endl = new Label();
3366         	cv.visitLabel(endl);
3367         	cv.visitLocalVariable(
3368                                 v.getName(),
3369                                 BytecodeHelper.getTypeDescription(v.getTypeName()),
3370                                 null,
3371                                 v.getStartLabel(),
3372                                 endl,
3373                                 v.getIndex()
3374                                 );
3375         }
3376     }
3377     private void visitVariableEndLabel(Variable v) {
3378         if (CREATE_DEBUG_INFO) {
3379             if(v.getEndLabel() == null) {
3380                 Label end = new Label();
3381                 v.setEndLabel(end);
3382             }
3383             cv.visitLabel(v.getEndLabel());
3384         }
3385     }
3386 
3387     protected void pushBlockScope() {
3388         pushBlockScope(true, true);
3389     }
3390 
3391     /***
3392      * create a new scope. Set break/continue label if the canXXX parameter is true. Otherwise
3393      * inherit parent's label.
3394      * @param canContinue   true if the start of the scope can take continue label
3395      * @param canBreak  true if the end of the scope can take break label
3396      */
3397     protected void pushBlockScope(boolean canContinue, boolean canBreak) {
3398         BlockScope parentScope = scope;
3399         scope = new BlockScope(parentScope);
3400         scope.setContinueLabel(canContinue ? new Label() : (parentScope == null ? null : parentScope.getContinueLabel()));
3401         scope.setBreakLabel(canBreak? new Label() : (parentScope == null ? null : parentScope.getBreakLabel()));
3402         scope.setFirstVariableIndex(getNextVariableID());
3403     }
3404 
3405     /***
3406      * Defines the given variable in scope and assigns it to the stack
3407      */
3408     protected Variable defineVariable(String name, ClassNode type) {
3409         return defineVariable(name, type, true);
3410     }
3411 
3412     private Variable defineVariable(String name, ClassNode type, boolean define) {
3413         Variable answer = (Variable) variableStack.get(name);
3414         if (answer == null) {
3415             lastVariableIndex = getNextVariableID();
3416             answer = new Variable(lastVariableIndex, type, name);
3417             if (mutableVars.contains(name)) {
3418                 answer.setHolder(true);
3419             }
3420             variableStack.put(name, answer);
3421 
3422             Label startLabel  = new Label();
3423             answer.setStartLabel(startLabel);
3424             if (define) {
3425                 if (definingParameters) {
3426                     if (answer.isHolder()) {
3427                         cv.visitTypeInsn(NEW, "groovy/lang/Reference"); // br todo to associate a label with the variable
3428                         cv.visitInsn(DUP);
3429                         cv.visitVarInsn(ALOAD, lastVariableIndex);
3430                         cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V");
3431                         cv.visitVarInsn(ASTORE, lastVariableIndex);
3432                         cv.visitLabel(startLabel);
3433                     }
3434                 }
3435                 else {
3436                     // using new variable inside a comparison expression
3437                     // so lets initialize it too
3438                     if (answer.isHolder() && !isInScriptBody()) {
3439                         //cv.visitVarInsn(ASTORE, lastVariableIndex + 1); // I might need this to set the reference value
3440 
3441                         cv.visitTypeInsn(NEW, "groovy/lang/Reference");
3442                         cv.visitInsn(DUP);
3443                         cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "()V");
3444 
3445                         cv.visitVarInsn(ASTORE, lastVariableIndex);
3446                         cv.visitLabel(startLabel);
3447                         //cv.visitVarInsn(ALOAD, idx + 1);
3448                     }
3449                     else {
3450                         if (!leftHandExpression) { // new var on the RHS: init with null
3451                             cv.visitInsn(ACONST_NULL);
3452                             cv.visitVarInsn(ASTORE, lastVariableIndex);
3453                             cv.visitLabel(startLabel);
3454                         }
3455                     }
3456                 }
3457             }
3458         }
3459         return answer;
3460     }
3461 
3462     private boolean isDoubleSizeVariable(ClassNode type) {
3463         return type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE;
3464     }
3465 
3466     private int getNextVariableID() {
3467     	int index = 0;
3468     	for (Iterator iter = variableStack.values().iterator(); iter.hasNext();) {
3469     		Variable var = (Variable) iter.next();
3470     		if (isDoubleSizeVariable(var.getType())) {
3471     			index += 2;
3472     		} else {
3473     			index++;
3474     		}
3475     	}
3476     	return index;
3477     }
3478 
3479     /*** @return true if the given name is a local variable or a field */
3480     protected boolean isFieldOrVariable(String name) {
3481         return variableStack.containsKey(name) || classNode.getField(name) != null;
3482     }
3483 
3484     /*protected String resolveClassName(String type) {
3485         return classNode.resolveClassName(type);
3486     }*/
3487 
3488     protected String createVariableName(String type) {
3489         return "__" + type + (++tempVariableNameCounter);
3490     }
3491 
3492     /***
3493      * @return if the type of the expression can be determined at compile time
3494      *         then this method returns the type - otherwise null
3495      */
3496     protected ClassNode getExpressionType(Expression expression) {
3497         if (isComparisonExpression(expression)) {
3498             return ClassHelper.boolean_TYPE;
3499         }
3500         if (expression instanceof VariableExpression) {
3501             VariableExpression varExpr = (VariableExpression) expression;
3502             Variable variable = (Variable) variableStack.get(varExpr.getName());
3503             if (variable != null && !variable.isHolder()) {
3504                 ClassNode type = variable.getType();
3505                 if (! variable.isDynamicTyped()) return type;
3506             }
3507         }
3508         return expression.getType();
3509     }
3510 
3511     protected boolean isInClosureConstructor() {
3512         return constructorNode != null
3513             && classNode.getOuterClass() != null
3514             && classNode.getSuperClass()==ClassHelper.CLOSURE_TYPE;
3515     }
3516 
3517     protected boolean isStaticMethod() {
3518         if (methodNode == null) { // we're in a constructor
3519             return false;
3520         }
3521         return methodNode.isStatic();
3522     }
3523 
3524     protected CompileUnit getCompileUnit() {
3525         CompileUnit answer = classNode.getCompileUnit();
3526         if (answer == null) {
3527             answer = context.getCompileUnit();
3528         }
3529         return answer;
3530     }
3531 
3532 }