View Javadoc

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