View Javadoc

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