View Javadoc

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