Clover coverage report - groovy - 1.0-beta-8
Coverage timestamp: Fri Dec 17 2004 14:55:55 GMT
file stats: LOC: 5,593   Methods: 159
NCLOC: 4,302   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
AsmClassGenerator2.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * $Id: AsmClassGenerator2.java,v 1.5 2004/12/14 16:18:14 russel Exp $
 3   
  *
 4   
  * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
  *
 6   
  * Redistribution and use of this software and associated documentation
 7   
  * ("Software"), with or without modification, are permitted provided that the
 8   
  * following conditions are met: 1. Redistributions of source code must retain
 9   
  * copyright statements and notices. Redistributions must also contain a copy
 10   
  * of this document. 2. Redistributions in binary form must reproduce the above
 11   
  * copyright notice, this list of conditions and the following disclaimer in
 12   
  * the documentation and/or other materials provided with the distribution. 3.
 13   
  * The name "groovy" must not be used to endorse or promote products derived
 14   
  * from this Software without prior written permission of The Codehaus. For
 15   
  * written permission, please contact info@codehaus.org. 4. Products derived
 16   
  * from this Software may not be called "groovy" nor may "groovy" appear in
 17   
  * their names without prior written permission of The Codehaus. "groovy" is a
 18   
  * registered trademark of The Codehaus. 5. Due credit should be given to The
 19   
  * Codehaus - http://groovy.codehaus.org/
 20   
  *
 21   
  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
 22   
  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 23   
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 24   
  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
 25   
  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 26   
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 27   
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 28   
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 29   
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 30   
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 31   
  * DAMAGE.
 32   
  *
 33   
  */
 34   
 package org.codehaus.groovy.classgen;
 35   
 
 36   
 import groovy.lang.*;
 37   
 
 38   
 import java.lang.reflect.Constructor;
 39   
 import java.lang.reflect.Field;
 40   
 import java.lang.reflect.Method;
 41   
 import java.lang.reflect.Modifier;
 42   
 import java.util.*;
 43   
 import java.util.regex.Matcher;
 44   
 import java.util.logging.Logger;
 45   
 import java.security.AccessController;
 46   
 import java.security.PrivilegedAction;
 47   
 
 48   
 import org.codehaus.groovy.ast.ASTNode;
 49   
 import org.codehaus.groovy.ast.ClassNode;
 50   
 import org.codehaus.groovy.ast.CompileUnit;
 51   
 import org.codehaus.groovy.ast.ConstructorNode;
 52   
 import org.codehaus.groovy.ast.FieldNode;
 53   
 import org.codehaus.groovy.ast.GroovyCodeVisitor;
 54   
 import org.codehaus.groovy.ast.InnerClassNode;
 55   
 import org.codehaus.groovy.ast.MethodNode;
 56   
 import org.codehaus.groovy.ast.Parameter;
 57   
 import org.codehaus.groovy.ast.PropertyNode;
 58   
 import org.codehaus.groovy.ast.Type;
 59   
 import org.codehaus.groovy.ast.VariableScope;
 60   
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 61   
 import org.codehaus.groovy.ast.expr.ArrayExpression;
 62   
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 63   
 import org.codehaus.groovy.ast.expr.BooleanExpression;
 64   
 import org.codehaus.groovy.ast.expr.CastExpression;
 65   
 import org.codehaus.groovy.ast.expr.ClassExpression;
 66   
 import org.codehaus.groovy.ast.expr.ClosureExpression;
 67   
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 68   
 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 69   
 import org.codehaus.groovy.ast.expr.Expression;
 70   
 import org.codehaus.groovy.ast.expr.ExpressionTransformer;
 71   
 import org.codehaus.groovy.ast.expr.FieldExpression;
 72   
 import org.codehaus.groovy.ast.expr.GStringExpression;
 73   
 import org.codehaus.groovy.ast.expr.ListExpression;
 74   
 import org.codehaus.groovy.ast.expr.MapEntryExpression;
 75   
 import org.codehaus.groovy.ast.expr.MapExpression;
 76   
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 77   
 import org.codehaus.groovy.ast.expr.NegationExpression;
 78   
 import org.codehaus.groovy.ast.expr.NotExpression;
 79   
 import org.codehaus.groovy.ast.expr.PostfixExpression;
 80   
 import org.codehaus.groovy.ast.expr.PrefixExpression;
 81   
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 82   
 import org.codehaus.groovy.ast.expr.RangeExpression;
 83   
 import org.codehaus.groovy.ast.expr.RegexExpression;
 84   
 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
 85   
 import org.codehaus.groovy.ast.expr.TernaryExpression;
 86   
 import org.codehaus.groovy.ast.expr.TupleExpression;
 87   
 import org.codehaus.groovy.ast.expr.VariableExpression;
 88   
 import org.codehaus.groovy.ast.stmt.AssertStatement;
 89   
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 90   
 import org.codehaus.groovy.ast.stmt.BreakStatement;
 91   
 import org.codehaus.groovy.ast.stmt.CaseStatement;
 92   
 import org.codehaus.groovy.ast.stmt.CatchStatement;
 93   
 import org.codehaus.groovy.ast.stmt.ContinueStatement;
 94   
 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
 95   
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 96   
 import org.codehaus.groovy.ast.stmt.ForStatement;
 97   
 import org.codehaus.groovy.ast.stmt.IfStatement;
 98   
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 99   
 import org.codehaus.groovy.ast.stmt.Statement;
 100   
 import org.codehaus.groovy.ast.stmt.SwitchStatement;
 101   
 import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
 102   
 import org.codehaus.groovy.ast.stmt.ThrowStatement;
 103   
 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
 104   
 import org.codehaus.groovy.ast.stmt.WhileStatement;
 105   
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 106   
 import org.codehaus.groovy.runtime.InvokerHelper;
 107   
 import org.codehaus.groovy.runtime.RegexSupport;
 108   
 import org.codehaus.groovy.syntax.Token;
 109   
 import org.codehaus.groovy.syntax.Types;
 110   
 import org.codehaus.groovy.syntax.SyntaxException;
 111   
 import org.codehaus.groovy.syntax.parser.RuntimeParserException;
 112   
 import org.objectweb.asm.ClassVisitor;
 113   
 import org.objectweb.asm.CodeVisitor;
 114   
 import org.objectweb.asm.Label;
 115   
 import org.objectweb.asm.ClassWriter;
 116   
 
 117   
 /**
 118   
  * Generates Java class versions of Groovy classes using ASM
 119   
  * Based on AsmClassGenerator 1.6.
 120   
  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 121   
  * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
 122   
  *
 123   
  * @version $Revision: 1.5 $
 124   
  */
 125   
 public class AsmClassGenerator2 extends ClassGenerator {
 126   
 
 127   
     private Logger log = Logger.getLogger(getClass().getName());
 128   
 
 129   
     private ClassVisitor cw;
 130   
     private CodeVisitor cv;
 131   
     private GeneratorContext context;
 132   
 
 133   
     private String sourceFile;
 134   
 
 135   
     // current class details
 136   
     private ClassNode classNode;
 137   
     private ClassNode outermostClass;
 138   
     private String internalClassName;
 139   
     private String internalBaseClassName;
 140   
 
 141   
     /** maps the variable names to the JVM indices */
 142   
     private Map variableStack = new HashMap();
 143   
 
 144   
     /** have we output a return statement yet */
 145   
     private boolean outputReturn;
 146   
 
 147   
     /** are we on the left or right of an expression */
 148   
     private boolean leftHandExpression;
 149   
 
 150   
     // cached values
 151   
     MethodCaller invokeMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethod");
 152   
     MethodCaller invokeMethodSafeMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethodSafe");
 153   
     MethodCaller invokeStaticMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticMethod");
 154   
     MethodCaller invokeConstructorMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructor");
 155   
     MethodCaller invokeConstructorOfMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructorOf");
 156   
     MethodCaller invokeNoArgumentsConstructorOf = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsConstructorOf");
 157   
     MethodCaller invokeClosureMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeClosure");
 158   
     MethodCaller invokeSuperMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeSuperMethod");
 159   
     MethodCaller invokeNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsMethod");
 160   
     MethodCaller invokeStaticNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticNoArgumentsMethod");
 161   
 
 162   
     MethodCaller asIntMethod = MethodCaller.newStatic(InvokerHelper.class, "asInt");
 163   
     MethodCaller asTypeMethod = MethodCaller.newStatic(InvokerHelper.class, "asType");
 164   
     MethodCaller getPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getProperty");
 165   
     MethodCaller getPropertySafeMethod = MethodCaller.newStatic(InvokerHelper.class, "getPropertySafe");
 166   
     MethodCaller setPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setProperty");
 167   
     MethodCaller setPropertyMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setProperty2");
 168   
     MethodCaller setPropertySafeMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setPropertySafe2");
 169   
     MethodCaller getGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getGroovyObjectProperty");
 170   
     MethodCaller setGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setGroovyObjectProperty");
 171   
     MethodCaller asIteratorMethod = MethodCaller.newStatic(InvokerHelper.class, "asIterator");
 172   
     MethodCaller asBool = MethodCaller.newStatic(InvokerHelper.class, "asBool");
 173   
     MethodCaller notBoolean = MethodCaller.newStatic(InvokerHelper.class, "notBoolean");
 174   
     MethodCaller notObject = MethodCaller.newStatic(InvokerHelper.class, "notObject");
 175   
     MethodCaller regexPattern = MethodCaller.newStatic(InvokerHelper.class, "regexPattern");
 176   
     MethodCaller negation = MethodCaller.newStatic(InvokerHelper.class, "negate");
 177   
     MethodCaller convertPrimitiveArray = MethodCaller.newStatic(InvokerHelper.class, "convertPrimitiveArray");
 178   
     MethodCaller convertToPrimitiveArray = MethodCaller.newStatic(InvokerHelper.class, "convertToPrimitiveArray");
 179   
 
 180   
     MethodCaller compareIdenticalMethod = MethodCaller.newStatic(InvokerHelper.class, "compareIdentical");
 181   
     MethodCaller compareEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareEqual");
 182   
     MethodCaller compareNotEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareNotEqual");
 183   
     MethodCaller compareToMethod = MethodCaller.newStatic(InvokerHelper.class, "compareTo");
 184   
     MethodCaller findRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "findRegex");
 185   
     MethodCaller matchRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "matchRegex");
 186   
     MethodCaller compareLessThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThan");
 187   
     MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThanEqual");
 188   
     MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThan");
 189   
     MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThanEqual");
 190   
     MethodCaller isCaseMethod = MethodCaller.newStatic(InvokerHelper.class, "isCase");
 191   
 
 192   
     MethodCaller createListMethod = MethodCaller.newStatic(InvokerHelper.class, "createList");
 193   
     MethodCaller createTupleMethod = MethodCaller.newStatic(InvokerHelper.class, "createTuple");
 194   
     MethodCaller createMapMethod = MethodCaller.newStatic(InvokerHelper.class, "createMap");
 195   
     MethodCaller createRangeMethod = MethodCaller.newStatic(InvokerHelper.class, "createRange");
 196   
 
 197   
     MethodCaller assertFailedMethod = MethodCaller.newStatic(InvokerHelper.class, "assertFailed");
 198   
 
 199   
     MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator.class, "next");
 200   
     MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator.class, "hasNext");
 201   
 
 202   
 
 203   
     // current stack index
 204   
     private int lastVariableIndex;
 205   
     private static int tempVariableNameCounter;
 206   
 
 207   
     // exception blocks list
 208   
     private List exceptionBlocks = new ArrayList();
 209   
 
 210   
     private boolean definingParameters;
 211   
     private Set syntheticStaticFields = new HashSet();
 212   
     private Set mutableVars = new HashSet();
 213   
     private boolean passingClosureParams;
 214   
 
 215   
     private ConstructorNode constructorNode;
 216   
     private MethodNode methodNode;
 217   
     //private PropertyNode propertyNode;
 218   
     private BlockScope scope;
 219   
     private BytecodeHelper helper = new BytecodeHelper(null);
 220   
 
 221   
     private VariableScope variableScope;
 222   
     public static final boolean CREATE_DEBUG_INFO = true;
 223   
     private static final boolean MARK_START = true;
 224   
 
 225   
     public static final String EB_SWITCH_NAME = "static.dispatching";
 226   
     public boolean ENABLE_EARLY_BINDING;
 227   
     {    //
 228  0
         String ebSwitch = (String) AccessController.doPrivileged(new PrivilegedAction() {
 229  0
             public Object run() {
 230  0
                 return System.getProperty(EB_SWITCH_NAME, "false"); // set default to true if early binding is on by default.
 231   
             }
 232   
         });
 233   
         //System.out.println("ebSwitch = " + ebSwitch);
 234  0
         if (ebSwitch.equals("true")) {
 235  0
             ENABLE_EARLY_BINDING  = true;
 236   
         }
 237  0
         else if (ebSwitch.equals("false")) {
 238  0
             ENABLE_EARLY_BINDING  = false;
 239   
         }
 240   
         else {
 241  0
             ENABLE_EARLY_BINDING  = false;
 242  0
             log.warning("The value of system property " + EB_SWITCH_NAME + " is not recognized. Late dispatching is assumed. ");
 243   
         }
 244   
     }
 245   
     public static final boolean ASM_DEBUG = false; // add marker in the bytecode to show source-byecode relationship
 246   
     private int lineNumber = -1;
 247   
     private int columnNumber = -1;
 248   
     private ASTNode currentASTNode = null;
 249   
 
 250   
     private DummyClassGenerator dummyGen = null;
 251   
     private ClassWriter dummyClassWriter = null;
 252   
 
 253  0
     public AsmClassGenerator2(
 254   
         GeneratorContext context,
 255   
         ClassVisitor classVisitor,
 256   
         ClassLoader classLoader,
 257   
         String sourceFile) {
 258  0
         super(classLoader);
 259  0
         this.context = context;
 260  0
         this.cw = classVisitor;
 261  0
         this.sourceFile = sourceFile;
 262   
 
 263  0
         this.dummyClassWriter = new ClassWriter(true);
 264  0
         dummyGen  = new DummyClassGenerator(context, dummyClassWriter, classLoader, sourceFile);
 265   
 
 266   
     }
 267   
 
 268   
     // GroovyClassVisitor interface
 269   
     //-------------------------------------------------------------------------
 270  0
     public void visitClass(ClassNode classNode) {
 271   
         // todo to be tested
 272   
         // createDummyClass(classNode);
 273   
 
 274  0
         try {
 275  0
             syntheticStaticFields.clear();
 276  0
             this.classNode = classNode;
 277  0
             this.outermostClass = null;
 278  0
             this.internalClassName = BytecodeHelper.getClassInternalName(classNode.getName());
 279   
 
 280   
             //System.out.println("Generating class: " + classNode.getName());
 281   
 
 282   
             // lets check that the classes are all valid
 283  0
             classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class"));
 284  0
             String[] interfaces = classNode.getInterfaces();
 285  0
             for (int i = 0; i < interfaces.length; i++ ) {
 286  0
                 interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name");
 287   
             }
 288   
 
 289  0
             this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
 290   
 
 291  0
             cw.visit(
 292   
                 asmJDKVersion,
 293   
                 classNode.getModifiers(),
 294   
                 internalClassName,
 295   
                 internalBaseClassName,
 296   
                 BytecodeHelper.getClassInternalNames(classNode.getInterfaces()),
 297   
                 sourceFile);
 298   
 
 299   
             // set the optional enclosing method attribute of the current inner class
 300   
 //          br comment out once Groovy uses the latest CVS HEAD of ASM
 301   
 //            MethodNode enclosingMethod = classNode.getEnclosingMethod();
 302   
 //            String ownerName = BytecodeHelper.getClassInternalName(enclosingMethod.getDeclaringClass().getName());
 303   
 //            String descriptor = BytecodeHelper.getMethodDescriptor(enclosingMethod.getReturnType(), enclosingMethod.getParameters());
 304   
 //            EnclosingMethodAttribute attr = new EnclosingMethodAttribute(ownerName,enclosingMethod.getName(),descriptor);
 305   
 //            cw.visitAttribute(attr);
 306   
 
 307  0
             classNode.visitContents(this);
 308   
 
 309  0
             createSyntheticStaticFields();
 310   
 
 311  0
             for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
 312  0
                 ClassNode innerClass = (ClassNode) iter.next();
 313  0
                 String innerClassName = innerClass.getName();
 314  0
                 String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
 315  0
                 String outerClassName = internalClassName; // default for inner classes
 316  0
                 MethodNode enclosingMethod = innerClass.getEnclosingMethod();
 317  0
                 if (enclosingMethod != null) {
 318   
                     // local inner classes do not specify the outer class name
 319  0
                     outerClassName = null;
 320   
                 }
 321  0
                 cw.visitInnerClass(
 322   
                     innerClassInternalName,
 323   
                     outerClassName,
 324   
                     innerClassName,
 325   
                     innerClass.getModifiers());
 326   
             }
 327   
 // br TODO an inner class should have an entry of itself
 328  0
             cw.visitEnd();
 329   
         }
 330   
         catch (GroovyRuntimeException e) {
 331  0
             e.setModule(classNode.getModule());
 332  0
             throw e;
 333   
         }
 334   
     }
 335   
 
 336   
     // create a surrogate class that represents the classNode
 337   
     // the surrogate has the "face" of the real class. It's used for
 338   
     // type resolving "this"
 339  0
     private void createDummyClass(ClassNode classNode) {
 340  0
         dummyGen.visitClass(classNode);
 341  0
         byte[] code = dummyClassWriter.toByteArray();
 342   
 
 343  0
         ClassLoader parentLoader = getClass().getClassLoader();
 344  0
         GroovyClassLoader groovyLoader = new GroovyClassLoader(parentLoader);
 345  0
         Class theClass = groovyLoader.defineClass(classNode.getName(), code);
 346   
 
 347  0
         if (theClass != null) {
 348  0
             classCache.put(classNode.getName(), theClass);
 349   
         }
 350   
     }
 351   
 
 352  0
     public void visitConstructor(ConstructorNode node) {
 353   
         // creates a MethodWriter for the (implicit) constructor
 354   
         //String methodType = Type.getMethodDescriptor(VOID_TYPE, )
 355   
 
 356  0
         this.constructorNode = node;
 357  0
         this.methodNode = null;
 358  0
         this.variableScope = null;
 359   
 
 360  0
         visitParameters(node, node.getParameters());
 361   
 
 362  0
         String methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters());
 363  0
         cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null);
 364  0
         helper = new BytecodeHelper(cv);
 365   
 
 366  0
         findMutableVariables();
 367  0
         resetVariableStack(node.getParameters());
 368   
 
 369  0
         Statement code = node.getCode();
 370  0
         if (code == null || !firstStatementIsSuperInit(code)) {
 371   
             // invokes the super class constructor
 372  0
             cv.visitVarInsn(ALOAD, 0);
 373  0
             cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "()V");
 374   
         }
 375  0
         if (code != null) {
 376  0
             code.visit(this);
 377   
         }
 378   
 
 379  0
         cv.visitInsn(RETURN);
 380  0
         cv.visitMaxs(0, 0);
 381   
     }
 382   
 
 383  0
     public void visitMethod(MethodNode node) {
 384   
         //System.out.println("Visiting method: " + node.getName() + " with
 385   
         // return type: " + node.getReturnType());
 386  0
         this.constructorNode = null;
 387  0
         this.methodNode = node;
 388  0
         this.variableScope = null;
 389   
 
 390  0
         visitParameters(node, node.getParameters());
 391  0
         node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type"));
 392   
 
 393  0
         String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
 394  0
         cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null);
 395  0
         Label labelStart = new Label();
 396  0
         cv.visitLabel(labelStart);
 397  0
         helper = new BytecodeHelper(cv);
 398   
 
 399  0
         findMutableVariables();
 400  0
         resetVariableStack(node.getParameters());
 401   
 
 402   
 
 403  0
         outputReturn = false;
 404   
 
 405  0
         node.getCode().visit(this);
 406   
 
 407  0
         if (!outputReturn) {
 408  0
             cv.visitInsn(RETURN);
 409   
         }
 410   
 
 411   
         // lets do all the exception blocks
 412  0
         for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) {
 413  0
             Runnable runnable = (Runnable) iter.next();
 414  0
             runnable.run();
 415   
         }
 416  0
         exceptionBlocks.clear();
 417   
 
 418  0
         Label labelEnd = new Label();
 419  0
         cv.visitLabel(labelEnd);
 420   
 
 421   
         // br experiment with local var table so debuggers can retrieve variable names
 422  0
         if (CREATE_DEBUG_INFO) {
 423  0
             Set vars = this.variableStack.keySet();
 424  0
             for (Iterator iterator = vars.iterator(); iterator.hasNext();) {
 425  0
                 String varName = (String) iterator.next();
 426  0
                 Variable v = (Variable)variableStack.get(varName);
 427  0
                 String type = v.getTypeName();
 428  0
                 type = BytecodeHelper.getTypeDescription(type);
 429  0
                 Label start = v.getStartLabel() != null ? v.getStartLabel() : labelStart;
 430  0
                 Label end = v.getEndLabel() != null ? v.getEndLabel() : labelEnd;
 431  0
                 cv.visitLocalVariable(varName, type, start, end, v.getIndex());
 432   
             }
 433   
         }
 434  0
         cv.visitMaxs(0, 0);
 435   
     }
 436   
 
 437  0
     protected void visitParameters(ASTNode node, Parameter[] parameters) {
 438  0
         for (int i = 0, size = parameters.length; i < size; i++ ) {
 439  0
             visitParameter(node, parameters[i]);
 440   
         }
 441   
     }
 442   
 
 443  0
     protected void visitParameter(ASTNode node, Parameter parameter) {
 444  0
         if (! parameter.isDynamicType()) {
 445  0
             parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class"));
 446   
         }
 447   
     }
 448   
 
 449  0
     public void visitField(FieldNode fieldNode) {
 450  0
         onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
 451   
 
 452   
         // lets check that the classes are all valid
 453  0
         fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName()));
 454   
 
 455   
         //System.out.println("Visiting field: " + fieldNode.getName() + " on
 456   
         // class: " + classNode.getName());
 457   
 
 458  0
         Object fieldValue = null;
 459  0
         Expression expression = fieldNode.getInitialValueExpression();
 460  0
         if (expression instanceof ConstantExpression) {
 461  0
             ConstantExpression constantExp = (ConstantExpression) expression;
 462  0
             Object value = constantExp.getValue();
 463  0
             if (isPrimitiveFieldType(fieldNode.getType())) {
 464   
                 // lets convert any primitive types
 465  0
                 Class type = null;
 466  0
                 try {
 467  0
                     type = loadClass(fieldNode.getType());
 468  0
                     fieldValue = /*InvokerHelper.*/asType(value, type);
 469   
                 }
 470   
                 catch (Exception e) {
 471  0
                     log.warning("Caught unexpected: " + e);
 472   
                 }
 473   
             }
 474   
         }
 475  0
         cw.visitField(
 476   
             fieldNode.getModifiers(),
 477   
             fieldNode.getName(),
 478   
             BytecodeHelper.getTypeDescription(fieldNode.getType()),
 479   
             null, //fieldValue,  //br  all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
 480   
             null);
 481   
     }
 482   
 
 483   
     /**
 484   
      * Creates a getter, setter and field
 485   
      */
 486  0
     public void visitProperty(PropertyNode statement) {
 487  0
         onLineNumber(statement, "visitProperty:" + statement.getField().getName());
 488   
         //this.propertyNode = statement;
 489  0
         this.methodNode = null;
 490   
     }
 491   
 
 492   
     // GroovyCodeVisitor interface
 493   
     //-------------------------------------------------------------------------
 494   
 
 495   
     // Statements
 496   
     //-------------------------------------------------------------------------
 497   
 
 498  0
     public void visitForLoop(ForStatement loop) {
 499  0
         onLineNumber(loop, "visitForLoop");
 500  0
         Class elemType = null;
 501  0
         if (ENABLE_EARLY_BINDING) {
 502  0
             Expression collectionExp = loop.getCollectionExpression();
 503  0
             collectionExp.resolve(this);
 504  0
             Class cls = collectionExp.getTypeClass();
 505  0
             if (cls != null) {
 506  0
                 if (cls.isArray()) {
 507  0
                     elemType = cls.getComponentType();
 508  0
                     if (elemType != null) {
 509  0
                         Type varType = new Type(elemType.getName());
 510  0
                         loop.setVariableType(varType);
 511   
                     }
 512   
                 }
 513  0
                 else if (collectionExp instanceof ListExpression) {
 514  0
                     elemType = ((ListExpression)collectionExp).getComponentTypeClass();
 515  0
                     if (elemType != null) {
 516  0
                         Type varType = new Type(elemType.getName());
 517  0
                         loop.setVariableType(varType);
 518   
                     }
 519   
                 }
 520  0
                 else if (collectionExp instanceof RangeExpression) {
 521   
                     // use the from type class. assuming both from and to are of the same type
 522  0
                     elemType = ((RangeExpression)collectionExp).getFrom().getTypeClass();
 523  0
                     if (elemType != null) {
 524  0
                         Type varType = new Type(elemType.getName());
 525  0
                         loop.setVariableType(varType);
 526   
                     }
 527   
                 }
 528   
             }
 529   
         }
 530   
 
 531   
 
 532   
         //
 533   
         // Declare the loop counter.
 534  0
         Type variableType = checkValidType(loop.getVariableType(), loop, "for loop variable");
 535  0
         Variable variable = defineVariable(loop.getVariable(), variableType, true);
 536   
 
 537  0
         if( isInScriptBody() ) {
 538  0
             variable.setProperty( true );
 539   
         }
 540   
 
 541   
 
 542   
         //
 543   
         // Then initialize the iterator and generate the loop control
 544   
 
 545  0
         loop.getCollectionExpression().visit(this);
 546   
 
 547  0
         asIteratorMethod.call(cv);
 548   
 
 549  0
         final Variable iterTemp = storeInTemp("iterator", "java.util.Iterator");
 550  0
         final int iteratorIdx = iterTemp.getIndex();
 551   
 
 552   
         // to push scope here allows the iterator available after the loop, such as the i in: for (i in 1..5)
 553   
         // move it to the top will make the iterator a local var in the for loop.
 554  0
         pushBlockScope();
 555   
 
 556  0
         Label continueLabel = scope.getContinueLabel();
 557  0
         cv.visitJumpInsn(GOTO, continueLabel);
 558  0
         Label label2 = new Label();
 559  0
         cv.visitLabel(label2);
 560   
 
 561  0
         final Class elemClass = elemType;
 562  0
         BytecodeExpression expression = new BytecodeExpression() {
 563  0
             public void visit(GroovyCodeVisitor visitor) {
 564  0
                 cv.visitVarInsn(ALOAD, iteratorIdx);
 565  0
                 iteratorNextMethod.call(cv);
 566   
             }
 567   
 
 568  0
             protected void resolveType(AsmClassGenerator2 resolver) {
 569  0
                 setTypeClass(elemClass);
 570   
             }
 571   
         };
 572   
 
 573  0
         evaluateEqual( BinaryExpression.newAssignmentExpression(loop.getVariable(), expression) );
 574  0
         cv.visitInsn(POP); // br now the evaluateEqual() will leave a value on the stack. pop it.
 575   
 
 576   
         //
 577   
         // Generate the loop body
 578   
 
 579  0
         loop.getLoopBlock().visit(this);
 580   
 
 581   
 
 582   
         //
 583   
         // Generate the loop tail
 584   
 
 585  0
         cv.visitLabel(continueLabel);
 586  0
         cv.visitVarInsn(ALOAD, iteratorIdx);
 587   
 
 588  0
         iteratorHasNextMethod.call(cv);
 589   
 
 590  0
         cv.visitJumpInsn(IFNE, label2);
 591   
 
 592  0
         cv.visitLabel(scope.getBreakLabel());
 593  0
         popScope();
 594   
     }
 595   
 
 596  0
     public void visitWhileLoop(WhileStatement loop) {
 597  0
         onLineNumber(loop, "visitWhileLoop");
 598   
 
 599  0
         pushBlockScope();
 600   
 
 601  0
         Label continueLabel = scope.getContinueLabel();
 602   
 
 603  0
         cv.visitJumpInsn(GOTO, continueLabel);
 604  0
         Label l1 = new Label();
 605  0
         cv.visitLabel(l1);
 606   
 
 607  0
         loop.getLoopBlock().visit(this);
 608   
 
 609  0
         cv.visitLabel(continueLabel);
 610   
 
 611  0
         loop.getBooleanExpression().visit(this);
 612   
 
 613  0
         cv.visitJumpInsn(IFNE, l1);
 614   
 
 615  0
         cv.visitLabel(scope.getBreakLabel());
 616  0
         popScope();
 617   
     }
 618   
 
 619  0
     public void visitDoWhileLoop(DoWhileStatement loop) {
 620  0
         onLineNumber(loop, "visitDoWhileLoop");
 621   
 
 622  0
         pushBlockScope();
 623   
 
 624  0
         Label breakLabel = scope.getBreakLabel();
 625   
 
 626  0
         Label continueLabel = scope.getContinueLabel();
 627  0
         cv.visitLabel(continueLabel);
 628  0
         Label l1 = new Label();
 629   
 
 630  0
         loop.getLoopBlock().visit(this);
 631   
 
 632  0
         cv.visitLabel(l1);
 633   
 
 634  0
         loop.getBooleanExpression().visit(this);
 635   
 
 636  0
         cv.visitJumpInsn(IFNE, continueLabel);
 637   
 
 638  0
         cv.visitLabel(breakLabel);
 639  0
         popScope();
 640   
     }
 641   
 
 642  0
     public void visitIfElse(IfStatement ifElse) {
 643  0
         onLineNumber(ifElse, "visitIfElse");
 644   
 
 645  0
         ifElse.getBooleanExpression().visit(this);
 646   
 
 647  0
         Label l0 = new Label();
 648  0
         cv.visitJumpInsn(IFEQ, l0);
 649  0
         pushBlockScope(false, false);
 650  0
         ifElse.getIfBlock().visit(this);
 651  0
         popScope();
 652   
 
 653  0
         Label l1 = new Label();
 654  0
         cv.visitJumpInsn(GOTO, l1);
 655  0
         cv.visitLabel(l0);
 656   
 
 657  0
         pushBlockScope(false, false);
 658  0
         ifElse.getElseBlock().visit(this);
 659  0
         cv.visitLabel(l1);
 660  0
         popScope();
 661   
     }
 662   
 
 663  0
     public void visitTernaryExpression(TernaryExpression expression) {
 664  0
         onLineNumber(expression, "visitTernaryExpression");
 665   
 
 666  0
         expression.getBooleanExpression().visit(this);
 667   
 
 668  0
         Label l0 = new Label();
 669  0
         cv.visitJumpInsn(IFEQ, l0);
 670  0
         expression.getTrueExpression().visit(this);
 671   
 
 672  0
         Label l1 = new Label();
 673  0
         cv.visitJumpInsn(GOTO, l1);
 674  0
         cv.visitLabel(l0);
 675   
 
 676  0
         expression.getFalseExpression().visit(this);
 677  0
         cv.visitLabel(l1);
 678   
     }
 679   
 
 680  0
     public void visitAssertStatement(AssertStatement statement) {
 681  0
         onLineNumber(statement, "visitAssertStatement");
 682   
 
 683   
         //System.out.println("Assert: " + statement.getLineNumber() + " for: "
 684   
         // + statement.getText());
 685   
 
 686  0
         BooleanExpression booleanExpression = statement.getBooleanExpression();
 687  0
         booleanExpression.visit(this);
 688   
 
 689  0
         Label l0 = new Label();
 690  0
         cv.visitJumpInsn(IFEQ, l0);
 691   
 
 692   
         // do nothing
 693   
 
 694  0
         Label l1 = new Label();
 695  0
         cv.visitJumpInsn(GOTO, l1);
 696  0
         cv.visitLabel(l0);
 697   
 
 698   
         // push expression string onto stack
 699  0
         String expressionText = booleanExpression.getText();
 700  0
         List list = new ArrayList();
 701  0
         addVariableNames(booleanExpression, list);
 702  0
         if (list.isEmpty()) {
 703  0
             cv.visitLdcInsn(expressionText);
 704   
         }
 705   
         else {
 706  0
             boolean first = true;
 707   
 
 708   
             // lets create a new expression
 709  0
             cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
 710  0
             cv.visitInsn(DUP);
 711  0
             cv.visitLdcInsn(expressionText + ". Values: ");
 712   
 
 713  0
             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
 714   
 
 715  0
             Variable assertTemp = visitASTOREInTemp("assert");
 716  0
             int tempIndex  = assertTemp.getIndex();
 717   
 
 718  0
             for (Iterator iter = list.iterator(); iter.hasNext();) {
 719  0
                 String name = (String) iter.next();
 720  0
                 String text = name + " = ";
 721  0
                 if (first) {
 722  0
                     first = false;
 723   
                 }
 724   
                 else {
 725  0
                     text = ", " + text;
 726   
                 }
 727   
 
 728  0
                 cv.visitVarInsn(ALOAD, tempIndex);
 729  0
                 cv.visitLdcInsn(text);
 730  0
                 cv.visitMethodInsn(
 731   
                     INVOKEVIRTUAL,
 732   
                     "java/lang/StringBuffer",
 733   
                     "append",
 734   
                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
 735  0
                 cv.visitInsn(POP);
 736   
 
 737  0
                 cv.visitVarInsn(ALOAD, tempIndex);
 738  0
                 new VariableExpression(name).visit(this);
 739  0
                 cv.visitMethodInsn(
 740   
                     INVOKEVIRTUAL,
 741   
                     "java/lang/StringBuffer",
 742   
                     "append",
 743   
                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
 744  0
                 cv.visitInsn(POP);
 745   
 
 746   
             }
 747  0
             cv.visitVarInsn(ALOAD, tempIndex);
 748  0
             removeVar(assertTemp);
 749   
         }
 750   
         // now the optional exception expression
 751  0
         statement.getMessageExpression().visit(this);
 752   
 
 753  0
         assertFailedMethod.call(cv);
 754  0
         cv.visitLabel(l1);
 755   
     }
 756   
 
 757  0
     private void addVariableNames(Expression expression, List list) {
 758  0
         if (expression instanceof BooleanExpression) {
 759  0
             BooleanExpression boolExp = (BooleanExpression) expression;
 760  0
             addVariableNames(boolExp.getExpression(), list);
 761   
         }
 762  0
         else if (expression instanceof BinaryExpression) {
 763  0
             BinaryExpression binExp = (BinaryExpression) expression;
 764  0
             addVariableNames(binExp.getLeftExpression(), list);
 765  0
             addVariableNames(binExp.getRightExpression(), list);
 766   
         }
 767  0
         else if (expression instanceof VariableExpression) {
 768  0
             VariableExpression varExp = (VariableExpression) expression;
 769  0
             list.add(varExp.getVariable());
 770   
         }
 771   
     }
 772   
 
 773  0
     public void visitTryCatchFinally(TryCatchStatement statement) {
 774  0
         onLineNumber(statement, "visitTryCatchFinally");
 775   
 // todo need to add blockscope handling
 776  0
         CatchStatement catchStatement = statement.getCatchStatement(0);
 777   
 
 778  0
         Statement tryStatement = statement.getTryStatement();
 779   
 
 780  0
         if (tryStatement.isEmpty() || catchStatement == null) {
 781  0
             final Label l0 = new Label();
 782  0
             cv.visitLabel(l0);
 783   
 
 784  0
             tryStatement.visit(this);
 785   
 
 786   
 
 787  0
             int index1 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
 788  0
             int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
 789   
 
 790  0
             final Label l1 = new Label();
 791  0
             cv.visitJumpInsn(JSR, l1);
 792  0
             final Label l2 = new Label();
 793  0
             cv.visitLabel(l2);
 794  0
             final Label l3 = new Label();
 795  0
             cv.visitJumpInsn(GOTO, l3);
 796  0
             final Label l4 = new Label();
 797  0
             cv.visitLabel(l4);
 798  0
             cv.visitVarInsn(ASTORE, index1);
 799  0
             cv.visitJumpInsn(JSR, l1);
 800  0
             final Label l5 = new Label();
 801  0
             cv.visitLabel(l5);
 802  0
             cv.visitVarInsn(ALOAD, index1);
 803  0
             cv.visitInsn(ATHROW);
 804  0
             cv.visitLabel(l1);
 805  0
             cv.visitVarInsn(ASTORE, index2);
 806   
 
 807  0
             statement.getFinallyStatement().visit(this);
 808   
 
 809  0
             cv.visitVarInsn(RET, index2);
 810  0
             cv.visitLabel(l3);
 811   
 
 812  0
             exceptionBlocks.add(new Runnable() {
 813  0
                 public void run() {
 814  0
                     cv.visitTryCatchBlock(l0, l2, l4, null);
 815  0
                     cv.visitTryCatchBlock(l4, l5, l4, null);
 816   
                 }
 817   
             });
 818   
 
 819   
         }
 820   
         else {
 821  0
             String exceptionVar = catchStatement.getVariable();
 822  0
             String exceptionType =
 823   
                 checkValidType(catchStatement.getExceptionType(), catchStatement, "in catch statement");
 824   
 
 825  0
             int exceptionIndex = defineVariable(exceptionVar, exceptionType, false).getIndex();
 826  0
             int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
 827  0
             int index3 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
 828   
 
 829  0
             final Label l0 = new Label();
 830  0
             cv.visitLabel(l0);
 831   
 
 832  0
             tryStatement.visit(this);
 833   
 
 834  0
             final Label l1 = new Label();
 835  0
             cv.visitLabel(l1);
 836  0
             Label l2 = new Label();
 837  0
             cv.visitJumpInsn(JSR, l2);
 838  0
             final Label l3 = new Label();
 839  0
             cv.visitLabel(l3);
 840  0
             Label l4 = new Label();
 841  0
             cv.visitJumpInsn(GOTO, l4);
 842  0
             final Label l5 = new Label();
 843  0
             cv.visitLabel(l5);
 844   
 
 845  0
             cv.visitVarInsn(ASTORE, exceptionIndex);
 846   
 
 847  0
             if (catchStatement != null) {
 848  0
                 catchStatement.visit(this);
 849   
             }
 850   
 
 851  0
             cv.visitJumpInsn(JSR, l2);
 852  0
             final Label l6 = new Label();
 853  0
             cv.visitLabel(l6);
 854  0
             cv.visitJumpInsn(GOTO, l4);
 855   
 
 856  0
             final Label l7 = new Label();
 857  0
             cv.visitLabel(l7);
 858  0
             cv.visitVarInsn(ASTORE, index2);
 859  0
             cv.visitJumpInsn(JSR, l2);
 860   
 
 861  0
             final Label l8 = new Label();
 862  0
             cv.visitLabel(l8);
 863  0
             cv.visitVarInsn(ALOAD, index2);
 864  0
             cv.visitInsn(ATHROW);
 865  0
             cv.visitLabel(l2);
 866  0
             cv.visitVarInsn(ASTORE, index3);
 867   
 
 868  0
             statement.getFinallyStatement().visit(this);
 869   
 
 870  0
             cv.visitVarInsn(RET, index3);
 871  0
             cv.visitLabel(l4);
 872   
 
 873   
             // rest of code goes here...
 874   
 
 875   
             //final String exceptionTypeInternalName = (catchStatement !=
 876   
             // null) ?
 877   
             // getTypeDescription(exceptionType) : null;
 878  0
             final String exceptionTypeInternalName =
 879  0
                 (catchStatement != null) ? BytecodeHelper.getClassInternalName(exceptionType) : null;
 880   
 
 881  0
             exceptionBlocks.add(new Runnable() {
 882  0
                 public void run() {
 883  0
                     cv.visitTryCatchBlock(l0, l1, l5, exceptionTypeInternalName);
 884  0
                     cv.visitTryCatchBlock(l0, l3, l7, null);
 885  0
                     cv.visitTryCatchBlock(l5, l6, l7, null);
 886  0
                     cv.visitTryCatchBlock(l7, l8, l7, null);
 887   
                 }
 888   
             });
 889   
         }
 890   
     }
 891   
 
 892  0
     private Variable storeInTemp(String name, String type) {
 893  0
         Variable var  = defineVariable(createVariableName(name), type, false);
 894  0
         int varIdx = var.getIndex();
 895  0
         cv.visitVarInsn(ASTORE, varIdx);
 896  0
         if (CREATE_DEBUG_INFO) cv.visitLabel(var.getStartLabel());
 897  0
         return var;
 898   
     }
 899   
 
 900  0
     public void visitSwitch(SwitchStatement statement) {
 901  0
         onLineNumber(statement, "visitSwitch");
 902   
 
 903  0
         statement.getExpression().visit(this);
 904   
 
 905   
         // switch does not have a continue label. use its parent's for continue
 906  0
         pushBlockScope(false, true);
 907   
         //scope.setContinueLabel(scope.getParent().getContinueLabel());
 908   
 
 909   
 
 910  0
         int switchVariableIndex = defineVariable(createVariableName("switch"), "java.lang.Object").getIndex();
 911  0
         cv.visitVarInsn(ASTORE, switchVariableIndex);
 912   
 
 913  0
         List caseStatements = statement.getCaseStatements();
 914  0
         int caseCount = caseStatements.size();
 915  0
         Label[] labels = new Label[caseCount + 1];
 916  0
         for (int i = 0; i < caseCount; i++) {
 917  0
             labels[i] = new Label();
 918   
         }
 919   
 
 920  0
         int i = 0;
 921  0
         for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
 922  0
             CaseStatement caseStatement = (CaseStatement) iter.next();
 923  0
             visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
 924   
         }
 925   
 
 926  0
         statement.getDefaultStatement().visit(this);
 927   
 
 928  0
         cv.visitLabel(scope.getBreakLabel());
 929   
 
 930  0
         popScope();
 931   
     }
 932   
 
 933  0
     public void visitCaseStatement(CaseStatement statement) {
 934   
     }
 935   
 
 936  0
     public void visitCaseStatement(
 937   
         CaseStatement statement,
 938   
         int switchVariableIndex,
 939   
         Label thisLabel,
 940   
         Label nextLabel) {
 941   
 
 942  0
         onLineNumber(statement, "visitCaseStatement");
 943   
 
 944  0
         cv.visitVarInsn(ALOAD, switchVariableIndex);
 945  0
         statement.getExpression().visit(this);
 946   
 
 947  0
         isCaseMethod.call(cv);
 948   
 
 949  0
         Label l0 = new Label();
 950  0
         cv.visitJumpInsn(IFEQ, l0);
 951   
 
 952  0
         cv.visitLabel(thisLabel);
 953   
 
 954  0
         statement.getCode().visit(this);
 955   
 
 956   
         // now if we don't finish with a break we need to jump past
 957   
         // the next comparison
 958  0
         if (nextLabel != null) {
 959  0
             cv.visitJumpInsn(GOTO, nextLabel);
 960   
         }
 961   
 
 962  0
         cv.visitLabel(l0);
 963   
     }
 964   
 
 965  0
     public void visitBreakStatement(BreakStatement statement) {
 966  0
         onLineNumber(statement, "visitBreakStatement");
 967   
 
 968  0
         Label breakLabel = scope.getBreakLabel();
 969  0
         if (breakLabel != null ) {
 970  0
             cv.visitJumpInsn(GOTO, breakLabel);
 971   
         } else {
 972   
             // should warn that break is not allowed in the context.
 973   
         }
 974   
     }
 975   
 
 976  0
     public void visitContinueStatement(ContinueStatement statement) {
 977  0
         onLineNumber(statement, "visitContinueStatement");
 978   
 
 979  0
         Label continueLabel = scope.getContinueLabel();
 980  0
         if (continueLabel != null ) {
 981  0
             cv.visitJumpInsn(GOTO, continueLabel);
 982   
         } else {
 983   
             // should warn that continue is not allowed in the context.
 984   
         }
 985   
     }
 986   
 
 987  0
     public void visitSynchronizedStatement(SynchronizedStatement statement) {
 988  0
         onLineNumber(statement, "visitSynchronizedStatement");
 989   
 
 990  0
         statement.getExpression().visit(this);
 991   
 
 992  0
         int index = defineVariable(createVariableName("synchronized"), "java.lang.Integer").getIndex();
 993   
 
 994  0
         cv.visitVarInsn(ASTORE, index);
 995  0
         cv.visitInsn(MONITORENTER);
 996  0
         final Label l0 = new Label();
 997  0
         cv.visitLabel(l0);
 998   
 
 999  0
         statement.getCode().visit(this);
 1000   
 
 1001  0
         cv.visitVarInsn(ALOAD, index);
 1002  0
         cv.visitInsn(MONITOREXIT);
 1003  0
         final Label l1 = new Label();
 1004  0
         cv.visitJumpInsn(GOTO, l1);
 1005  0
         final Label l2 = new Label();
 1006  0
         cv.visitLabel(l2);
 1007  0
         cv.visitVarInsn(ALOAD, index);
 1008  0
         cv.visitInsn(MONITOREXIT);
 1009  0
         cv.visitInsn(ATHROW);
 1010  0
         cv.visitLabel(l1);
 1011   
 
 1012  0
         exceptionBlocks.add(new Runnable() {
 1013  0
             public void run() {
 1014  0
                 cv.visitTryCatchBlock(l0, l2, l2, null);
 1015   
             }
 1016   
         });
 1017   
     }
 1018   
 
 1019  0
     public void visitThrowStatement(ThrowStatement statement) {
 1020  0
         statement.getExpression().visit(this);
 1021   
 
 1022   
         // we should infer the type of the exception from the expression
 1023  0
         cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
 1024   
 
 1025  0
         cv.visitInsn(ATHROW);
 1026   
     }
 1027   
 
 1028  0
     public void visitReturnStatement(ReturnStatement statement) {
 1029  0
         onLineNumber(statement, "visitReturnStatement");
 1030  0
         String returnType = methodNode.getReturnType();
 1031  0
         if (returnType.equals("void")) {
 1032  0
             if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) {
 1033  0
                 throwException("Cannot use return statement with an expression on a method that returns void");
 1034   
             }
 1035  0
             cv.visitInsn(RETURN);
 1036  0
             outputReturn = true;
 1037  0
             return;
 1038   
         }
 1039   
 
 1040  0
         Expression expression = statement.getExpression();
 1041  0
         evaluateExpression(expression);
 1042  0
         if (returnType.equals("java.lang.Object") && expression.getType() != null && expression.getType().equals("void")) {
 1043  0
             cv.visitInsn(ACONST_NULL); // cheat the caller
 1044  0
             cv.visitInsn(ARETURN);
 1045   
         } else {
 1046   
             //return is based on class type
 1047   
             //TODO: make work with arrays
 1048   
             // we may need to cast
 1049  0
             helper.unbox(returnType);
 1050  0
             if (returnType.equals("double")) {
 1051  0
                 cv.visitInsn(DRETURN);
 1052   
             }
 1053  0
             else if (returnType.equals("float")) {
 1054  0
                 cv.visitInsn(FRETURN);
 1055   
             }
 1056  0
             else if (returnType.equals("long")) {
 1057  0
                 cv.visitInsn(LRETURN);
 1058   
             }
 1059  0
             else if (returnType.equals("boolean")) {
 1060  0
                 cv.visitInsn(IRETURN);
 1061   
             }
 1062  0
             else if (
 1063  0
                     returnType.equals("char")
 1064   
                     || returnType.equals("byte")
 1065   
                     || returnType.equals("int")
 1066   
                     || returnType.equals("short")) { //byte,short,boolean,int are
 1067   
                 // all IRETURN
 1068  0
                 cv.visitInsn(IRETURN);
 1069   
             }
 1070   
             else {
 1071  0
                 doConvertAndCast(returnType, expression);
 1072  0
                 cv.visitInsn(ARETURN);
 1073   
 
 1074   
                 /*
 1075   
                 if (c == Boolean.class) {
 1076   
                 Label l0 = new Label();
 1077   
                 cv.visitJumpInsn(IFEQ, l0);
 1078   
                 cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
 1079   
                 cv.visitInsn(ARETURN);
 1080   
                 cv.visitLabel(l0);
 1081   
                 cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
 1082   
                 cv.visitInsn(ARETURN);
 1083   
                 }
 1084   
                 else {
 1085   
                 if (isValidTypeForCast(returnType) && !returnType.equals(c.getName())) {
 1086   
                 doConvertAndCast(returnType, expression);
 1087   
                 }
 1088   
                 cv.visitInsn(ARETURN);
 1089   
                 }
 1090   
                 */
 1091   
             }
 1092   
         }
 1093  0
         outputReturn = true;
 1094   
     }
 1095   
 
 1096   
     /**
 1097   
      * Casts to the given type unless it can be determined that the cast is unnecessary
 1098   
      */
 1099  0
     protected void doConvertAndCast(String type, Expression expression) {
 1100  0
         String expType = getExpressionType(expression);
 1101   
         // temp resolution: convert all primitive casting to corresponsing Object type
 1102  0
         if (BytecodeHelper.isPrimitiveType(type)) {
 1103  0
             type = BytecodeHelper.getObjectTypeForPrimitive(type);
 1104   
         }
 1105  0
         if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) {
 1106  0
             doConvertAndCast(type);
 1107   
         }
 1108   
     }
 1109   
 
 1110   
     /**
 1111   
      * @param expression
 1112   
      */
 1113  0
     protected void evaluateExpression(Expression expression) {
 1114  0
         visitAndAutoboxBoolean(expression);
 1115   
         //expression.visit(this);
 1116   
 
 1117  0
         Expression assignExpr = createReturnLHSExpression(expression);
 1118  0
         if (assignExpr != null) {
 1119  0
             leftHandExpression = false;
 1120  0
             assignExpr.visit(this);
 1121   
         }
 1122   
     }
 1123   
 
 1124  0
     public void visitExpressionStatement(ExpressionStatement statement) {
 1125  0
         onLineNumber(statement, "visitExpressionStatement: " + statement.getExpression().getClass().getName());
 1126   
 
 1127  0
         Expression expression = statement.getExpression();
 1128   
 // disabled in favor of JIT resolving
 1129   
 //        if (ENABLE_EARLY_BINDING)
 1130   
 //            expression.resolve(this);
 1131   
 
 1132  0
         visitAndAutoboxBoolean(expression);
 1133   
 
 1134  0
         if (isPopRequired(expression)) {
 1135  0
             cv.visitInsn(POP);
 1136   
         }
 1137   
     }
 1138   
 
 1139   
     // Expressions
 1140   
     //-------------------------------------------------------------------------
 1141   
 
 1142  0
     public void visitBinaryExpression(BinaryExpression expression) {
 1143  0
         onLineNumber(expression, "visitBinaryExpression: \"" + expression.getOperation().getText() + "\" ");
 1144  0
         switch (expression.getOperation().getType()) {
 1145   
             case Types.EQUAL : // = assignment
 1146  0
                 evaluateEqual(expression);
 1147  0
                 break;
 1148   
 
 1149   
             case Types.COMPARE_IDENTICAL : // ===
 1150  0
                 evaluateBinaryExpression(compareIdenticalMethod, expression);
 1151  0
                 break;
 1152   
 
 1153   
             case Types.COMPARE_EQUAL : // ==
 1154  0
                 evaluateBinaryExpression(compareEqualMethod, expression);
 1155  0
                 break;
 1156   
 
 1157   
             case Types.COMPARE_NOT_EQUAL :
 1158  0
                 evaluateBinaryExpression(compareNotEqualMethod, expression);
 1159  0
                 break;
 1160   
 
 1161   
             case Types.COMPARE_TO :
 1162  0
                 evaluateCompareTo(expression);
 1163  0
                 break;
 1164   
 
 1165   
             case Types.COMPARE_GREATER_THAN :
 1166  0
                 evaluateBinaryExpression(compareGreaterThanMethod, expression);
 1167  0
                 break;
 1168   
 
 1169   
             case Types.COMPARE_GREATER_THAN_EQUAL :
 1170  0
                 evaluateBinaryExpression(compareGreaterThanEqualMethod, expression);
 1171  0
                 break;
 1172   
 
 1173   
             case Types.COMPARE_LESS_THAN :
 1174  0
                 evaluateBinaryExpression(compareLessThanMethod, expression);
 1175  0
                 break;
 1176   
 
 1177   
             case Types.COMPARE_LESS_THAN_EQUAL :
 1178  0
                 evaluateBinaryExpression(compareLessThanEqualMethod, expression);
 1179  0
                 break;
 1180   
 
 1181   
             case Types.LOGICAL_AND :
 1182  0
                 evaluateLogicalAndExpression(expression);
 1183  0
                 break;
 1184   
 
 1185   
             case Types.LOGICAL_OR :
 1186  0
                 evaluateLogicalOrExpression(expression);
 1187  0
                 break;
 1188   
 
 1189   
             case Types.PLUS :
 1190   
                 {
 1191  0
                     if (ENABLE_EARLY_BINDING) {
 1192  0
                         expression.resolve(this);
 1193  0
                         if (expression.isResolveFailed() || !expression.isTypeResolved()) {
 1194  0
                             evaluateBinaryExpression("plus", expression);
 1195  0
                             break;
 1196   
                         }
 1197  0
                         Expression leftExpression = expression.getLeftExpression();
 1198  0
                         Expression rightExpression = expression.getRightExpression();
 1199  0
                         Class lclass = leftExpression.getTypeClass();
 1200  0
                         Class rclass = rightExpression.getTypeClass();
 1201  0
                         if (lclass == null || rclass == null) {
 1202  0
                             evaluateBinaryExpression("plus", expression);
 1203  0
                             break;
 1204   
                         }
 1205  0
                         if (lclass == String.class && rclass == String.class) {
 1206   
 //                            MethodCallExpression call = new MethodCallExpression(
 1207   
 //                                    leftExpression,
 1208   
 //                                    "concat",
 1209   
 //                                    new ArgumentListExpression(new Expression[] {rightExpression}));
 1210   
 //                            call.setTypeClass(String.class); // must do to avoid excessive resolving
 1211   
 //                            visitMethodCallExpression(call);
 1212  0
                             cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
 1213  0
                             cv.visitInsn(DUP);
 1214  0
                             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
 1215  0
                             load(leftExpression);
 1216  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
 1217  0
                             load(rightExpression);
 1218  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
 1219  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
 1220   
                         }
 1221  0
                         else if (lclass == String.class && Number.class.isAssignableFrom(rclass) ) {
 1222  0
                             cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
 1223  0
                             cv.visitInsn(DUP);
 1224  0
                             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
 1225  0
                             load(leftExpression);
 1226  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
 1227  0
                             load(rightExpression);
 1228   
                             // will Object.toString() work here?
 1229  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
 1230  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
 1231  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
 1232   
                         }
 1233  0
                         else if (rclass == String.class && Number.class.isAssignableFrom(lclass) ) {
 1234  0
                             cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
 1235  0
                             cv.visitInsn(DUP);
 1236  0
                             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
 1237  0
                             load(leftExpression);
 1238  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
 1239  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
 1240  0
                             load(rightExpression);
 1241  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); // note the arg is object type for safety
 1242  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
 1243   
                         }
 1244  0
                         else if ((lclass == Integer.class || lclass == int.class) && (rclass == Integer.class || rclass == int.class)) {
 1245   
                             // assuming all return boxed version for primitives
 1246  0
                             load(leftExpression);
 1247  0
                             helper.quickUnboxIfNecessary(int.class);
 1248  0
                             load(rightExpression);
 1249  0
                             helper.quickUnboxIfNecessary(int.class);
 1250  0
                             cv.visitInsn(IADD);
 1251  0
                             helper.quickBoxIfNecessary(int.class);
 1252   
                         }
 1253  0
                         else if (Number.class.isAssignableFrom(lclass) && Number.class.isAssignableFrom(rclass)) {
 1254   
                             // let's use groovy utilities in the DefaultGroovyMethods
 1255  0
                             load(leftExpression);
 1256  0
                             load(rightExpression);
 1257  0
                             cv.visitMethodInsn(
 1258   
                                     INVOKESTATIC,
 1259   
                                     BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1260   
                                     "plus",
 1261   
                                     "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
 1262   
                         }
 1263   
                         else { // todo add more more number optimiztion
 1264  0
                             evaluateBinaryExpression("plus", expression);
 1265   
                         }
 1266   
 
 1267   
                     } else {
 1268  0
                         evaluateBinaryExpression("plus", expression);
 1269   
                     }
 1270   
                 }
 1271  0
                 break;
 1272   
 
 1273   
             case Types.PLUS_EQUAL :
 1274  0
                 evaluateBinaryExpressionWithAsignment("plus", expression);
 1275  0
                 break;
 1276   
             case Types.MINUS :
 1277   
                 {
 1278  0
                     if (ENABLE_EARLY_BINDING) {
 1279  0
                         expression.resolve(this);
 1280  0
                         if (expression.isResolveFailed() || !expression.isTypeResolved()) {
 1281  0
                             evaluateBinaryExpression("minus", expression);
 1282  0
                             break;
 1283   
                         }
 1284  0
                         Expression leftExpression = expression.getLeftExpression();
 1285  0
                         Expression rightExpression = expression.getRightExpression();
 1286  0
                         Class lclass = leftExpression.getTypeClass();
 1287  0
                         Class rclass = rightExpression.getTypeClass();
 1288  0
                         if (lclass == null || rclass == null) {
 1289  0
                             evaluateBinaryExpression("minus", expression);
 1290  0
                             break;
 1291   
                         }
 1292  0
                         if ((lclass == Integer.class || lclass == int.class) && (rclass == Integer.class || rclass == int.class)) {
 1293   
                             // assuming all return boxed version for primitives
 1294  0
                             load(leftExpression);
 1295  0
                             helper.quickUnboxIfNecessary(int.class);
 1296  0
                             load(rightExpression);
 1297  0
                             helper.quickUnboxIfNecessary(int.class);
 1298  0
                             cv.visitInsn(ISUB);
 1299  0
                             helper.quickBoxIfNecessary(int.class);
 1300   
                         }
 1301   
                         else
 1302  0
                         if (Number.class.isAssignableFrom(lclass) && Number.class.isAssignableFrom(rclass)) {
 1303   
                             // let's use groovy utilities in the DefaultGroovyMethods
 1304  0
                             load(leftExpression);
 1305  0
                             load(rightExpression);
 1306  0
                             cv.visitMethodInsn(
 1307   
                                     INVOKESTATIC,
 1308   
                                     BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1309   
                                     "minus",
 1310   
                                     "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
 1311   
                         }
 1312   
                         else { // todo add more more number optimiztion
 1313  0
                             evaluateBinaryExpression("minus", expression);
 1314   
                         }
 1315   
                     } else {
 1316  0
                         evaluateBinaryExpression("minus", expression);
 1317   
                     }
 1318   
                 }
 1319  0
                 break;
 1320   
             case Types.MINUS_EQUAL :
 1321  0
                 evaluateBinaryExpressionWithAsignment("minus", expression);
 1322  0
                 break;
 1323   
 
 1324   
             case Types.MULTIPLY :
 1325   
                 {
 1326  0
                     if (ENABLE_EARLY_BINDING) {
 1327  0
                         expression.resolve(this);
 1328  0
                         if (expression.isResolveFailed() || !expression.isTypeResolved()) {
 1329  0
                             evaluateBinaryExpression("multiply", expression);
 1330  0
                             break;
 1331   
                         }
 1332  0
                         Expression leftExpression = expression.getLeftExpression();
 1333  0
                         Expression rightExpression = expression.getRightExpression();
 1334  0
                         Class lclass = leftExpression.getTypeClass();
 1335  0
                         Class rclass = rightExpression.getTypeClass();
 1336  0
                         if (lclass == null || rclass == null) {
 1337  0
                             evaluateBinaryExpression("multiply", expression);
 1338  0
                             break;
 1339   
                         }
 1340  0
                         if ((lclass == Integer.class || lclass == int.class) && (rclass == Integer.class || rclass == int.class)) {
 1341   
                             // assuming all return boxed version for primitives
 1342  0
                             load(leftExpression);
 1343  0
                             helper.quickUnboxIfNecessary(int.class);
 1344  0
                             load(rightExpression);
 1345  0
                             helper.quickUnboxIfNecessary(int.class);
 1346  0
                             cv.visitInsn(IMUL);
 1347  0
                             helper.quickBoxIfNecessary(int.class);
 1348   
                         }
 1349  0
                         else if (Number.class.isAssignableFrom(lclass) && Number.class.isAssignableFrom(rclass)) {
 1350   
                             // let's use groovy utilities in the DefaultGroovyMethods
 1351  0
                             load(leftExpression);
 1352  0
                             load(rightExpression);
 1353  0
                             cv.visitMethodInsn(
 1354   
                                     INVOKESTATIC,
 1355   
                                     BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1356   
                                     "multiply",
 1357   
                                     "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
 1358   
                         }
 1359   
                         else { // todo add more more number optimiztion
 1360  0
                             evaluateBinaryExpression("multiply", expression);
 1361   
                         }
 1362   
                     } else {
 1363  0
                         evaluateBinaryExpression("multiply", expression);
 1364   
                     }
 1365   
                 }
 1366   
 
 1367  0
                 break;
 1368   
 
 1369   
             case Types.MULTIPLY_EQUAL :
 1370  0
                 evaluateBinaryExpressionWithAsignment("multiply", expression);
 1371  0
                 break;
 1372   
 
 1373   
             case Types.DIVIDE :
 1374   
                 //SPG don't use divide since BigInteger implements directly
 1375   
                 //and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
 1376   
                 {
 1377  0
                     if (ENABLE_EARLY_BINDING) {
 1378  0
                         expression.resolve(this);
 1379  0
                         if (expression.isResolveFailed() || !expression.isTypeResolved()) {
 1380  0
                             evaluateBinaryExpression("div", expression);
 1381  0
                             break;
 1382   
                         }
 1383  0
                         Expression leftExpression = expression.getLeftExpression();
 1384  0
                         Expression rightExpression = expression.getRightExpression();
 1385  0
                         Class lclass = leftExpression.getTypeClass();
 1386  0
                         Class rclass = rightExpression.getTypeClass();
 1387  0
                         if (lclass == null || rclass == null) {
 1388  0
                             evaluateBinaryExpression("div", expression);
 1389  0
                             break;
 1390   
                         }
 1391   
 //
 1392   
 //                        if ((lclass == Integer.class || lclass == int.class) && (rclass == Integer.class || rclass == int.class)) {
 1393   
 //                            // assuming all return boxed version for primitives
 1394   
 //                            load(leftExpression);
 1395   
 //                            helper.quickUnboxIfNecessary(int.class);
 1396   
 //                            cv.visitInsn(I2D);
 1397   
 //                            load(rightExpression);
 1398   
 //                            helper.quickUnboxIfNecessary(int.class);
 1399   
 //                            cv.visitInsn(I2D);
 1400   
 //                            cv.visitInsn(DDIV);
 1401   
 //                            helper.quickBoxIfNecessary(double.class);
 1402   
 //                        }
 1403   
 //                        else
 1404  0
                             if (Number.class.isAssignableFrom(lclass) && Number.class.isAssignableFrom(rclass)) {
 1405   
                             // let's use groovy utilities in the DefaultGroovyMethods
 1406  0
                             load(leftExpression);
 1407  0
                             load(rightExpression);
 1408  0
                             cv.visitMethodInsn(
 1409   
                                     INVOKESTATIC,
 1410   
                                     BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1411   
                                     "div",
 1412   
                                     "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
 1413   
                         }
 1414   
                         else { // todo add more more number optimiztion
 1415  0
                             evaluateBinaryExpression("div", expression);
 1416   
                         }
 1417   
                     } else {
 1418  0
                         evaluateBinaryExpression("div", expression);
 1419   
                     }
 1420   
                 }
 1421   
 
 1422  0
                 break;
 1423   
 
 1424   
             case Types.DIVIDE_EQUAL :
 1425   
                 //SPG don't use divide since BigInteger implements directly
 1426   
                 //and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
 1427  0
                 evaluateBinaryExpressionWithAsignment("div", expression);
 1428  0
                 break;
 1429   
 
 1430   
             case Types.INTDIV :
 1431   
                 {
 1432  0
                     if (ENABLE_EARLY_BINDING) {
 1433  0
                         expression.resolve(this);
 1434  0
                         if (expression.isResolveFailed() || !expression.isTypeResolved()) {
 1435  0
                             evaluateBinaryExpression("intdiv", expression);
 1436  0
                             break;
 1437   
                         }
 1438  0
                         Expression leftExpression = expression.getLeftExpression();
 1439  0
                         Expression rightExpression = expression.getRightExpression();
 1440  0
                         Class lclass = leftExpression.getTypeClass();
 1441  0
                         Class rclass = rightExpression.getTypeClass();
 1442  0
                         if (lclass == null || rclass == null) {
 1443  0
                             evaluateBinaryExpression("intdiv", expression);
 1444  0
                             break;
 1445   
                         }
 1446  0
                         if (Number.class.isAssignableFrom(lclass) && Number.class.isAssignableFrom(rclass)) {
 1447   
                             // let's use groovy utilities in the DefaultGroovyMethods
 1448  0
                             load(leftExpression);
 1449  0
                             load(rightExpression);
 1450  0
                             cv.visitMethodInsn(
 1451   
                                     INVOKESTATIC,
 1452   
                                     BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1453   
                                     "intdiv",
 1454   
                                     "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
 1455   
                         }
 1456   
                         else { // todo add more more number optimiztion
 1457  0
                             evaluateBinaryExpression("intdiv", expression);
 1458   
                         }
 1459   
                     } else {
 1460  0
                         evaluateBinaryExpression("intdiv", expression);
 1461   
                     }
 1462   
                 }
 1463  0
                 break;
 1464   
 
 1465   
             case Types.INTDIV_EQUAL :
 1466  0
                 evaluateBinaryExpressionWithAsignment("intdiv", expression);
 1467  0
                 break;
 1468   
 
 1469   
             case Types.MOD :
 1470  0
                 evaluateBinaryExpression("mod", expression);
 1471  0
                 break;
 1472   
 
 1473   
             case Types.MOD_EQUAL :
 1474  0
                 evaluateBinaryExpressionWithAsignment("mod", expression);
 1475  0
                 break;
 1476   
 
 1477   
             case Types.LEFT_SHIFT :
 1478  0
                 evaluateBinaryExpression("leftShift", expression);
 1479  0
                 break;
 1480   
 
 1481   
             case Types.RIGHT_SHIFT :
 1482  0
                 evaluateBinaryExpression("rightShift", expression);
 1483  0
                 break;
 1484   
 
 1485   
             case Types.RIGHT_SHIFT_UNSIGNED :
 1486  0
                 evaluateBinaryExpression("rightShiftUnsigned", expression);
 1487  0
                 break;
 1488   
 
 1489   
             case Types.KEYWORD_INSTANCEOF :
 1490  0
                 evaluateInstanceof(expression);
 1491  0
                 break;
 1492   
 
 1493   
             case Types.FIND_REGEX :
 1494  0
                 evaluateBinaryExpression(findRegexMethod, expression);
 1495  0
                 break;
 1496   
 
 1497   
             case Types.MATCH_REGEX :
 1498  0
                 evaluateBinaryExpression(matchRegexMethod, expression);
 1499  0
                 break;
 1500   
 
 1501   
             case Types.LEFT_SQUARE_BRACKET :
 1502  0
                 if (leftHandExpression) {
 1503  0
                     throwException("Should not be called here. Possible reason: postfix operation on array.");
 1504   
                     // This is handled right now in the evaluateEqual()
 1505   
                     // should support this here later
 1506   
                     //evaluateBinaryExpression("putAt", expression);
 1507   
                 }
 1508  0
                 else if (ENABLE_EARLY_BINDING) {
 1509  0
                     expression.resolve(this);
 1510  0
                     if (expression.isResolveFailed() || !expression.isTypeResolved()) {
 1511  0
                         evaluateBinaryExpression("getAt", expression);
 1512  0
                         break;
 1513   
                     }
 1514  0
                     Expression leftExpression = expression.getLeftExpression();
 1515  0
                     Expression rightExpression = expression.getRightExpression();
 1516  0
                     Class lclass = leftExpression.getTypeClass();
 1517  0
                     Class rclass = rightExpression.getTypeClass();
 1518  0
                     if (lclass == null || rclass == null) {
 1519  0
                         evaluateBinaryExpression("getAt", expression);
 1520  0
                         break;
 1521   
                     }
 1522  0
                     if (lclass == String.class && rclass == Integer.class) {
 1523  0
                         load(leftExpression); cast(String.class);
 1524  0
                         load(rightExpression); helper.quickUnboxIfNecessary(int.class);
 1525  0
                         cv.visitMethodInsn(
 1526   
                                 INVOKESTATIC,
 1527   
                                 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1528   
                                 "getAt",
 1529   
                                 "([Ljava/lang/String;I)Ljava/lang/String;");
 1530  0
                         break;
 1531   
                     }
 1532  0
                     else if (lclass.isArray() && rclass == Integer.class) {
 1533  0
                         load(leftExpression); // cast it?
 1534  0
                         load(rightExpression); helper.quickUnboxIfNecessary(int.class);
 1535  0
                         Class elemType = lclass.getComponentType();
 1536  0
                         if (!elemType.isPrimitive()) {
 1537  0
                             cv.visitMethodInsn(
 1538   
                                     INVOKESTATIC,
 1539   
                                     BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1540   
                                     "getAt",
 1541   
                                     "([Ljava/lang/Object;I)Ljava/lang/Object;");
 1542  0
                             cast(elemType);
 1543   
                         }
 1544   
                         else {
 1545  0
                             evaluateBinaryExpression("getAt", expression); // todo more optim
 1546   
                         }
 1547  0
                         break;
 1548   
                     }
 1549  0
                     else if (List.class == lclass && rclass == Integer.class){
 1550   
                         // there is special logic in treating list subscript
 1551  0
                         load(leftExpression); cast(List.class);
 1552  0
                         load(rightExpression); helper.quickUnboxIfNecessary(int.class);
 1553   
                             //INVOKESTATIC org/codehaus/groovy/runtime/DefaultGroovyMethods getAt (Ljava/util/List;I)Ljava/lang/Object;
 1554  0
                         cv.visitMethodInsn(
 1555   
                                 INVOKESTATIC,
 1556   
                                 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1557   
                                 "getAt",
 1558   
                                 "(Ljava/util/List;I)Ljava/lang/Object;");
 1559  0
                         break;
 1560   
                     }
 1561  0
                     else if (Map.class.isAssignableFrom(lclass)){ // todo test this
 1562  0
                         visitMethodCallExpression(
 1563   
                                 new MethodCallExpression(
 1564   
                                         leftExpression,
 1565   
                                         "get",
 1566   
                                         new ArgumentListExpression(
 1567   
                                                 new Expression[] { rightExpression})));
 1568  0
                         break;
 1569   
                     }
 1570   
                     else {
 1571  0
                         evaluateBinaryExpression("getAt", expression); // todo more optim
 1572  0
                         break;
 1573   
                     }
 1574   
                 }
 1575   
                 else {
 1576  0
                     evaluateBinaryExpression("getAt", expression);
 1577   
                 }
 1578  0
                 break;
 1579   
 
 1580   
             default :
 1581  0
                 throwException("Operation: " + expression.getOperation() + " not supported");
 1582   
         }
 1583   
     }
 1584   
 
 1585  0
     private void load(Expression exp) {
 1586   
 
 1587  0
         boolean wasLeft = leftHandExpression;
 1588  0
         leftHandExpression = false;
 1589   
 //        if (CREATE_DEBUG_INFO)
 1590   
 //            helper.mark("-- loading expression: " + exp.getClass().getName() +
 1591   
 //                    " at [" + exp.getLineNumber() + ":" + exp.getColumnNumber() + "]");
 1592   
         //exp.visit(this);
 1593  0
         visitAndAutoboxBoolean(exp);
 1594   
 //        if (CREATE_DEBUG_INFO)
 1595   
 //            helper.mark(" -- end of loading --");
 1596   
 
 1597   
 
 1598  0
         if (ENABLE_EARLY_BINDING){
 1599   
 // casting might be expensive. should do JIT casting
 1600   
 
 1601   
 //            Class cls = exp.getTypeClass();
 1602   
 //            if (cls != null && !cls.isPrimitive() && cls != Object.class) {
 1603   
 //                cast(cls);
 1604   
 //            }
 1605   
         }
 1606   
         //evaluateExpression(exp);
 1607  0
         leftHandExpression  = wasLeft;
 1608   
     }
 1609   
 
 1610  0
     public void visitPostfixExpression(PostfixExpression expression) {
 1611  0
         if (ENABLE_EARLY_BINDING) {
 1612  0
             int type = expression.getOperation().getType();
 1613  0
             expression.resolve(this);
 1614  0
             if (expression.isResolveFailed() || !expression.isTypeResolved()) {
 1615  0
                 evaluatePostfixMethod("next", expression.getExpression());
 1616  0
                 return;
 1617   
             }
 1618  0
             Class lclass = expression.getTypeClass();
 1619  0
             Expression exp = expression.getExpression();
 1620  0
             String func = type == Types.PLUS_PLUS ? "next" : "previous";
 1621  0
             int op = type == Types.PLUS_PLUS ? IADD : ISUB;
 1622   
 
 1623  0
             if (lclass == Integer.class) {
 1624  0
                 load(exp);
 1625  0
                 cv.visitInsn(DUP); // leave the old value on the stack;
 1626  0
                 helper.quickUnboxIfNecessary(int.class);
 1627  0
                 cv.visitInsn(ICONST_1);
 1628  0
                 cv.visitInsn(op);
 1629  0
                 helper.quickBoxIfNecessary(int.class);
 1630  0
                 store(exp);
 1631   
             }
 1632  0
             else if (Number.class.isAssignableFrom(lclass)) {
 1633   
                 // let's use groovy utilities in the DefaultGroovyMethods
 1634  0
                 load(exp);
 1635  0
                 cv.visitInsn(DUP); // leave the old value on the stack;
 1636  0
                 cv.visitMethodInsn(
 1637   
                         INVOKESTATIC,
 1638   
                         BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
 1639   
                         func,
 1640   
                         "(Ljava/lang/Number;)Ljava/lang/Number;");
 1641  0
                 store(exp);
 1642   
             }
 1643   
             else { // todo add more more number optimiztion
 1644  0
                 evaluatePostfixMethod(func, exp);
 1645   
             }
 1646   
 
 1647   
         } else {
 1648  0
             switch (expression.getOperation().getType()) {
 1649   
                 case Types.PLUS_PLUS :
 1650  0
                     evaluatePostfixMethod("next", expression.getExpression());
 1651  0
                     break;
 1652   
                 case Types.MINUS_MINUS :
 1653  0
                     evaluatePostfixMethod("previous", expression.getExpression());
 1654  0
                     break;
 1655   
             }
 1656   
         }
 1657   
     }
 1658   
 
 1659   
     // store the data on the stack to the expression (variablem, property, field, etc.
 1660  0
     private void store(Expression expression) {
 1661  0
         if (expression instanceof BinaryExpression) {
 1662  0
             throwException("BinaryExpression appeared on LHS. ");
 1663   
         }
 1664  0
         if (ASM_DEBUG) {
 1665  0
             if (expression instanceof VariableExpression) {
 1666  0
                 helper.mark(((VariableExpression)expression).getVariable());
 1667   
             }
 1668   
         }
 1669  0
         boolean wasLeft = leftHandExpression;
 1670  0
         leftHandExpression = true;
 1671  0
         expression.visit(this);
 1672   
         //evaluateExpression(expression);
 1673  0
         leftHandExpression = wasLeft;
 1674  0
         return;
 1675   
     }
 1676   
 
 1677  0
     private void throwException(String s) {
 1678   
         //throw new ClassGeneratorException(s + ". Source: " + classNode.getName() + ":[" + this.lineNumber + ":" + this.columnNumber + "]");
 1679  0
         throw new RuntimeParserException(s, currentASTNode);
 1680   
     }
 1681   
 
 1682  0
     public void visitPrefixExpression(PrefixExpression expression) {
 1683  0
         switch (expression.getOperation().getType()) {
 1684   
             case Types.PLUS_PLUS :
 1685  0
                 evaluatePrefixMethod("next", expression.getExpression());
 1686  0
                 break;
 1687   
             case Types.MINUS_MINUS :
 1688  0
                 evaluatePrefixMethod("previous", expression.getExpression());
 1689  0
                 break;
 1690   
         }
 1691   
     }
 1692   
 
 1693  0
     public void visitClosureExpression(ClosureExpression expression) {
 1694  0
         ClassNode innerClass = createClosureClass(expression);
 1695  0
         addInnerClass(innerClass);
 1696  0
         String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName());
 1697   
 
 1698  0
         ClassNode owner = innerClass.getOuterClass();
 1699  0
         String ownerTypeName = owner.getName();
 1700  0
         if (classNode.isStaticClass() || isStaticMethod()) {
 1701  0
             ownerTypeName = "java.lang.Class";
 1702   
         }
 1703   
 
 1704  0
         passingClosureParams = true;
 1705  0
         List constructors = innerClass.getDeclaredConstructors();
 1706  0
         ConstructorNode node = (ConstructorNode) constructors.get(0);
 1707  0
         Parameter[] localVariableParams = node.getParameters();
 1708   
 
 1709   
 
 1710   
         //
 1711   
         // Define in the context any variables that will be
 1712   
         // created inside the closure.  Note that the first two
 1713   
         // parameters are always _outerInstance and _delegate,
 1714   
         // so we don't worry about them.
 1715   
 
 1716  0
         for (int i = 2; i < localVariableParams.length; i++) {
 1717  0
             Parameter param = localVariableParams[i];
 1718  0
             String name = param.getName();
 1719   
 
 1720  0
             if (variableStack.get(name) == null && classNode.getField(name) == null) {
 1721  0
                 defineVariable(name, "java.lang.Object"); // todo  should use param type is available
 1722   
             }
 1723   
         }
 1724   
 
 1725  0
         cv.visitTypeInsn(NEW, innerClassinternalName);
 1726  0
         cv.visitInsn(DUP);
 1727  0
         if (isStaticMethod() || classNode.isStaticClass()) {
 1728  0
             visitClassExpression(new ClassExpression(ownerTypeName));
 1729   
         }
 1730   
         else {
 1731  0
             loadThisOrOwner();
 1732   
         }
 1733   
 
 1734  0
         if (innerClass.getSuperClass().equals("groovy.lang.Closure")) {
 1735  0
             if (isStaticMethod()) {
 1736   
                 /**
 1737   
                  * todo could maybe stash this expression in a JVM variable
 1738   
                  * from previous statement above
 1739   
                  */
 1740  0
                 visitClassExpression(new ClassExpression(ownerTypeName));
 1741   
             }
 1742   
             else {
 1743  0
                 loadThisOrOwner();
 1744   
             }
 1745   
         }
 1746   
 
 1747   
         //String prototype = "(L" + BytecodeHelper.getClassInternalName(ownerTypeName) + ";Ljava/lang/Object;";
 1748   
 
 1749   
         // now lets load the various parameters we're passing
 1750  0
         for (int i = 2; i < localVariableParams.length; i++) {
 1751  0
             Parameter param = localVariableParams[i];
 1752  0
             String name = param.getName();
 1753   
 
 1754  0
             if (variableStack.get(name) == null) {
 1755  0
                 visitFieldExpression(new FieldExpression(classNode.getField(name)));
 1756   
             }
 1757   
             else {
 1758  0
                 visitVariableExpression(new VariableExpression(name));
 1759   
             }
 1760   
             //prototype = prototype + "L" + BytecodeHelper.getClassInternalName(param.getType()) + ";";
 1761   
         }
 1762  0
         passingClosureParams = false;
 1763   
 
 1764   
         // we may need to pass in some other constructors
 1765   
         //cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
 1766  0
         cv.visitMethodInsn(
 1767   
             INVOKESPECIAL,
 1768   
             innerClassinternalName,
 1769   
             "<init>",
 1770   
             BytecodeHelper.getMethodDescriptor("void", localVariableParams));
 1771   
     }
 1772   
 
 1773   
     /**
 1774   
      * Loads either this object or if we're inside a closure then load the top level owner
 1775   
      */
 1776  0
     protected void loadThisOrOwner() {
 1777  0
         if (isInnerClass()) {
 1778  0
             visitFieldExpression(new FieldExpression(classNode.getField("owner")));
 1779   
         }
 1780   
         else {
 1781  0
             cv.visitVarInsn(ALOAD, 0);
 1782   
         }
 1783   
     }
 1784   
 
 1785  0
     public void visitRegexExpression(RegexExpression expression) {
 1786  0
         expression.getRegex().visit(this);
 1787  0
         regexPattern.call(cv);
 1788   
     }
 1789   
 
 1790   
     /**
 1791   
      * Generate byte code for constants
 1792   
      * @see <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a>
 1793   
      */
 1794  0
     public void visitConstantExpression(ConstantExpression expression) {
 1795  0
         Object value = expression.getValue();
 1796  0
         helper.loadConstant(value);
 1797   
     }
 1798   
 
 1799  0
     public void visitNegationExpression(NegationExpression expression) {
 1800  0
         Expression subExpression = expression.getExpression();
 1801  0
         subExpression.visit(this);
 1802  0
         negation.call(cv);
 1803   
     }
 1804   
 
 1805  0
     public void visitCastExpression(CastExpression expression) {
 1806  0
         String type = expression.getType();
 1807  0
         type = checkValidType(type, expression, "in cast");
 1808   
 
 1809  0
         visitAndAutoboxBoolean(expression.getExpression());
 1810   
 
 1811  0
         doConvertAndCast(type, expression.getExpression());
 1812   
     }
 1813   
 
 1814  0
     public void visitNotExpression(NotExpression expression) {
 1815  0
         Expression subExpression = expression.getExpression();
 1816  0
         subExpression.visit(this);
 1817   
 
 1818   
         // This is not the best way to do this. Javac does it by reversing the
 1819   
         // underlying expressions but that proved
 1820   
         // fairly complicated for not much gain. Instead we'll just use a
 1821   
         // utility function for now.
 1822  0
         if (isComparisonExpression(expression.getExpression())) {
 1823  0
             notBoolean.call(cv);
 1824   
         }
 1825   
         else {
 1826  0
             notObject.call(cv);
 1827   
         }
 1828   
     }
 1829   
 
 1830   
     /**
 1831   
      * return a primitive boolean value of the BooleanExpresion.
 1832   
      * @param expression
 1833   
      */
 1834  0
     public void visitBooleanExpression(BooleanExpression expression) {
 1835  0
         expression.getExpression().visit(this);
 1836   
 
 1837  0
         if (!isComparisonExpression(expression.getExpression())) {
 1838   
 // comment out for optimization when boolean values are not autoboxed for eg. function calls.
 1839   
 //           Class typeClass = expression.getExpression().getTypeClass();
 1840   
 //           if (typeClass != null && typeClass != boolean.class) {
 1841  0
                 asBool.call(cv); // to return a primitive boolean
 1842   
 //            }
 1843   
         }
 1844   
     }
 1845   
 
 1846  0
     public void visitMethodCallExpression(MethodCallExpression call) {
 1847  0
         onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":");
 1848  0
         if (ENABLE_EARLY_BINDING)
 1849  0
             call.resolve(this);
 1850   
 
 1851  0
         this.leftHandExpression = false;
 1852   
 
 1853  0
         Expression arguments = call.getArguments();
 1854   
         /*
 1855   
          * if (arguments instanceof TupleExpression) { TupleExpression
 1856   
          * tupleExpression = (TupleExpression) arguments; int size =
 1857   
          * tupleExpression.getExpressions().size(); if (size == 0) { arguments =
 1858   
          * ConstantExpression.EMPTY_ARRAY; } }
 1859   
          */
 1860  0
         boolean superMethodCall = MethodCallExpression.isSuperMethodCall(call);
 1861  0
         String method = call.getMethod();
 1862  0
         if (superMethodCall && method.equals("<init>")) {
 1863   
             /** todo handle method types! */
 1864  0
             cv.visitVarInsn(ALOAD, 0);
 1865  0
             if (isInClosureConstructor()) { // br use the second param to init the super class (Closure)
 1866  0
                 cv.visitVarInsn(ALOAD, 2);
 1867  0
                 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
 1868   
             }
 1869   
             else {
 1870  0
                 cv.visitVarInsn(ALOAD, 1);
 1871  0
                 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
 1872   
             }
 1873   
         }
 1874   
         else {
 1875   
             // are we a local variable
 1876  0
             if (isThisExpression(call.getObjectExpression()) && isFieldOrVariable(call.getMethod())) {
 1877   
                 /*
 1878   
                  * if (arguments instanceof TupleExpression) { TupleExpression
 1879   
                  * tupleExpression = (TupleExpression) arguments; int size =
 1880   
                  * tupleExpression.getExpressions().size(); if (size == 1) {
 1881   
                  * arguments = (Expression)
 1882   
                  * tupleExpression.getExpressions().get(0); } }
 1883   
                  */
 1884   
 
 1885   
                 // lets invoke the closure method
 1886  0
                 visitVariableExpression(new VariableExpression(method));
 1887  0
                 arguments.visit(this);
 1888  0
                 invokeClosureMethod.call(cv);
 1889   
             }
 1890   
             else {
 1891  0
                 if (superMethodCall) {
 1892  0
                     if (method.equals("super") || method.equals("<init>")) {
 1893  0
                         ConstructorNode superConstructorNode = findSuperConstructor(call);
 1894   
 
 1895  0
                         cv.visitVarInsn(ALOAD, 0);
 1896   
 
 1897  0
                         loadArguments(superConstructorNode.getParameters(), arguments);
 1898   
 
 1899  0
                         String descriptor = BytecodeHelper.getMethodDescriptor("void", superConstructorNode.getParameters());
 1900  0
                         cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", descriptor);
 1901   
                     }
 1902   
                     else {
 1903  0
                         MethodNode superMethodNode = findSuperMethod(call);
 1904   
 
 1905  0
                         cv.visitVarInsn(ALOAD, 0);
 1906   
 
 1907  0
                         loadArguments(superMethodNode.getParameters(), arguments);
 1908   
 
 1909  0
                         String descriptor = BytecodeHelper.getMethodDescriptor(superMethodNode.getReturnType(), superMethodNode.getParameters());
 1910  0
                         cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superMethodNode.getDeclaringClass().getName()), method, descriptor);
 1911   
                     }
 1912   
                 }
 1913   
                 else {
 1914   
                     // let's try early binding
 1915  0
                     if (ENABLE_EARLY_BINDING) {
 1916  0
                         try {
 1917  0
                             MetaMethod metamethod = call.getMetaMethod(); // todo change it to resolveMethodCallExpression
 1918  0
                             if (metamethod != null) {
 1919  0
                                 Class decClass = metamethod.getDeclaringClass();
 1920  0
                                 String ownerClassName = null;
 1921  0
                                 if (decClass == null) {
 1922   
                                     // meaning the class is the current class
 1923  0
                                     ownerClassName = BytecodeHelper.getClassInternalName(classNode.getName());
 1924   
                                 }
 1925   
                                 else {
 1926  0
                                     ownerClassName = BytecodeHelper.getClassInternalName(decClass.getName());
 1927   
                                 }
 1928   
 
 1929  0
                                 String methodName = call.getMethod();
 1930  0
                                 String descr = BytecodeHelper.getMethodDescriptor(metamethod);
 1931  0
                                 Class[] params = metamethod.getParameterTypes();
 1932   
                                 //
 1933  0
                                 Label l2 = new Label();
 1934   
 
 1935  0
                                 if (metamethod.isStatic()) {
 1936   
                                 } else {
 1937  0
                                     boolean wasLeft = leftHandExpression;
 1938  0
                                     leftHandExpression = false;
 1939  0
                                     call.getObjectExpression().visit(this);
 1940   
 
 1941  0
                                     if (call.isSafe()) {
 1942  0
                                         helper.dup();
 1943  0
                                         cv.visitJumpInsn(IFNULL, l2);
 1944   
                                     }
 1945   
 
 1946  0
                                     cv.visitTypeInsn(CHECKCAST, ownerClassName);
 1947  0
                                     leftHandExpression = wasLeft;
 1948   
                                 }
 1949   
                                 //
 1950  0
                                 if (arguments instanceof TupleExpression) {
 1951  0
                                     TupleExpression tupleExpression = (TupleExpression) arguments;
 1952  0
                                     List argexps = tupleExpression.getExpressions();
 1953  0
                                     for (int i = 0; i < argexps.size(); i++) {
 1954  0
                                         Expression expression = (Expression) argexps.get(i);
 1955  0
                                         load(expression);
 1956   
 
 1957  0
                                         if (params[i].isPrimitive() /*&& !expression.getTypeClass().isPrimitive()*/) { // data always boxed
 1958  0
                                             cast(params[i]);
 1959  0
                                             helper.quickUnboxIfNecessary(params[i]);
 1960   
                                         }
 1961  0
                                         else if (params[i].isArray() && params[i].getComponentType().isPrimitive() ) {
 1962  0
                                             new ClassExpression(params[i].getComponentType()).visit(this);
 1963  0
                                             convertToPrimitiveArray.call(cv);
 1964  0
                                             cast(params[i]);
 1965   
                                         }
 1966   
                                         else {
 1967  0
                                             if (expression.getTypeClass() == GString.class && params[i] == String.class){
 1968  0
                                                 cast(GString.class);
 1969  0
                                                 cv.visitMethodInsn(
 1970   
                                                         INVOKEVIRTUAL,
 1971   
                                                         "java/lang/Object",
 1972   
                                                         "toString",
 1973   
                                                         "()Ljava/lang/String;"
 1974   
                                                 );
 1975   
                                             }
 1976   
                                             else {
 1977  0
                                                 cast(params[i]);
 1978   
                                             }
 1979   
                                         }
 1980   
                                     }
 1981  0
                                     if (metamethod.isStatic()) {
 1982  0
                                         cv.visitMethodInsn(INVOKESTATIC, ownerClassName, methodName, descr);
 1983   
                                     }
 1984  0
                                     else if (decClass != null && decClass.isInterface()){
 1985  0
                                         cv.visitMethodInsn(INVOKEINTERFACE, ownerClassName, methodName, descr);
 1986   
                                     }
 1987   
                                     else {
 1988  0
                                         cv.visitMethodInsn(INVOKEVIRTUAL, ownerClassName, methodName, descr);
 1989   
                                     }
 1990  0
                                     call.setTypeClass(metamethod.getReturnType());
 1991  0
                                     if (metamethod.getReturnType().isPrimitive()
 1992   
                                             && metamethod.getReturnType() != void.class
 1993   
                                             //&& metamethod.getReturnType() != boolean.class
 1994   
                                     ) {
 1995  0
                                         helper.quickBoxIfNecessary(metamethod.getReturnType());
 1996   
                                     }
 1997  0
                                     if (call.isSafe()) {
 1998  0
                                         Label l3 = new Label();
 1999  0
                                         cv.visitJumpInsn(GOTO, l3);
 2000  0
                                         cv.visitLabel(l2);
 2001  0
                                         cv.visitInsn(POP);
 2002  0
                                         cv.visitInsn(ACONST_NULL);
 2003  0
                                         cv.visitLabel(l3);
 2004   
                                     }
 2005  0
                                     return;
 2006   
                                 } else {
 2007  0
                                     throw new GroovyRuntimeException("arguments type not handled. fall through to late binding");
 2008   
                                 }
 2009   
                             }
 2010   
                         } catch (Exception e) {
 2011   
 //                            System.out.println(this.classNode.getName() + ":" + this.methodNode.getName());
 2012   
 //                            //e.printStackTrace(); //System.out.println(e.getMessage());
 2013   
 //                            log.info("ignore: attempt early binding: " + e.getMessage());
 2014   
                             // fall through
 2015   
                         }
 2016   
                     } // end of early binding trial
 2017   
 
 2018  0
                     if (emptyArguments(arguments) && !call.isSafe()) {
 2019  0
                         call.getObjectExpression().visit(this);
 2020  0
                         cv.visitLdcInsn(method);
 2021  0
                         invokeNoArgumentsMethod.call(cv); // todo try if we can do early binding
 2022   
                     }
 2023   
                     else {
 2024  0
                         if (argumentsUseStack(arguments)) {
 2025   
 
 2026  0
                             arguments.visit(this);
 2027   
 
 2028  0
                             Variable tv = visitASTOREInTemp(method + "_arg");
 2029  0
                             int paramIdx = tv.getIndex();
 2030   
 
 2031  0
                             call.getObjectExpression().visit(this); // xxx
 2032   
 
 2033  0
                             cv.visitLdcInsn(method);
 2034   
 
 2035  0
                             cv.visitVarInsn(ALOAD, paramIdx);
 2036  0
                             removeVar(tv);
 2037   
                         }
 2038   
                         else {
 2039  0
                             call.getObjectExpression().visit(this);
 2040  0
                             cv.visitLdcInsn(method);
 2041  0
                             arguments.visit(this);
 2042   
                         }
 2043   
 
 2044  0
                         if (call.isSafe()) {
 2045  0
                             invokeMethodSafeMethod.call(cv);
 2046   
                         }
 2047   
                         else {
 2048  0
                             invokeMethodMethod.call(cv);
 2049   
                         }
 2050   
                     }
 2051   
                 }
 2052   
             }
 2053   
         }
 2054   
     }
 2055   
 
 2056   
     /**
 2057   
      * Loads and coerces the argument values for the given method call
 2058   
      */
 2059  0
     protected void loadArguments(Parameter[] parameters, Expression expression) {
 2060  0
         TupleExpression argListExp = (TupleExpression) expression;
 2061  0
         List arguments = argListExp.getExpressions();
 2062  0
         for (int i = 0, size = arguments.size(); i < size; i++) {
 2063  0
             Expression argExp = argListExp.getExpression(i);
 2064  0
             Parameter param = parameters[i];
 2065  0
             visitAndAutoboxBoolean(argExp);
 2066   
 
 2067  0
             String type = param.getType();
 2068  0
             if (BytecodeHelper.isPrimitiveType(type)) {
 2069  0
                 helper.unbox(type);
 2070   
             }
 2071   
 
 2072  0
             String expType = getExpressionType(argExp);
 2073  0
             if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) {
 2074  0
                 doConvertAndCast(type);
 2075   
             }
 2076   
  //           doConvertAndCast(type, argExp);
 2077   
         }
 2078   
     }
 2079   
 
 2080   
     /**
 2081   
      * Attempts to find the method of the given name in a super class
 2082   
      */
 2083  0
     protected MethodNode findSuperMethod(MethodCallExpression call) {
 2084  0
         String methodName = call.getMethod();
 2085  0
         TupleExpression argExpr = (TupleExpression) call.getArguments();
 2086  0
         int argCount = argExpr.getExpressions().size();
 2087  0
         ClassNode superClassNode = classNode.getSuperClassNode();
 2088  0
         if (superClassNode != null) {
 2089  0
             List methods = superClassNode.getMethods(methodName);
 2090  0
             for (Iterator iter = methods.iterator(); iter.hasNext(); ) {
 2091  0
                 MethodNode method = (MethodNode) iter.next();
 2092  0
                 if (method.getParameters().length == argCount) {
 2093  0
                     return method;
 2094   
                 }
 2095   
             }
 2096   
         }
 2097  0
         throwException("No such method: " + methodName + " for class: " + classNode.getName());
 2098  0
         return null; // should not come here
 2099   
     }
 2100   
 
 2101   
     /**
 2102   
      * Attempts to find the constructor in a super class
 2103   
      */
 2104  0
     protected ConstructorNode findSuperConstructor(MethodCallExpression call) {
 2105  0
         TupleExpression argExpr = (TupleExpression) call.getArguments();
 2106  0
         int argCount = argExpr.getExpressions().size();
 2107  0
         ClassNode superClassNode = classNode.getSuperClassNode();
 2108  0
         if (superClassNode != null) {
 2109  0
             List constructors = superClassNode.getDeclaredConstructors();
 2110  0
             for (Iterator iter = constructors.iterator(); iter.hasNext(); ) {
 2111  0
                 ConstructorNode constructor = (ConstructorNode) iter.next();
 2112  0
                 if (constructor.getParameters().length == argCount) {
 2113  0
                     return constructor;
 2114   
                 }
 2115   
             }
 2116   
         }
 2117  0
         throwException("No such constructor for class: " + classNode.getName());
 2118  0
         return null; // should not come here
 2119   
     }
 2120   
 
 2121  0
     protected boolean emptyArguments(Expression arguments) {
 2122  0
         if (arguments instanceof TupleExpression) {
 2123  0
             TupleExpression tupleExpression = (TupleExpression) arguments;
 2124  0
             int size = tupleExpression.getExpressions().size();
 2125  0
             return size == 0;
 2126   
         }
 2127  0
         return false;
 2128   
     }
 2129   
 
 2130  0
     public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
 2131  0
         this.leftHandExpression = false;
 2132   
 
 2133  0
         Expression arguments = call.getArguments();
 2134  0
         if (emptyArguments(arguments)) {
 2135  0
             cv.visitLdcInsn(call.getType());
 2136  0
             cv.visitLdcInsn(call.getMethod());
 2137   
 
 2138  0
             invokeStaticNoArgumentsMethod.call(cv);
 2139   
         }
 2140   
         else {
 2141  0
             if (arguments instanceof TupleExpression) {
 2142  0
                 TupleExpression tupleExpression = (TupleExpression) arguments;
 2143  0
                 int size = tupleExpression.getExpressions().size();
 2144  0
                 if (size == 1) {
 2145  0
                     arguments = (Expression) tupleExpression.getExpressions().get(0);
 2146   
                 }
 2147   
             }
 2148   
 
 2149  0
             cv.visitLdcInsn(call.getOwnerType());
 2150  0
             cv.visitLdcInsn(call.getMethod());
 2151  0
             arguments.visit(this);
 2152   
 
 2153  0
             invokeStaticMethodMethod.call(cv);
 2154   
         }
 2155   
     }
 2156   
 
 2157  0
     public void visitConstructorCallExpression(ConstructorCallExpression call) {
 2158  0
         onLineNumber(call, "visitConstructorCallExpression: \"" + call.getTypeToSet() + "\":");
 2159  0
         do {
 2160  0
             if (ENABLE_EARLY_BINDING) {
 2161  0
                 call.resolve(this);
 2162  0
                 if (call.isResolveFailed() || call.getTypeClass() == null) {
 2163  0
                     break;
 2164   
                 }
 2165   
                 else {
 2166  0
                     try {
 2167  0
                         Constructor ctor = call.getConstructor(); // todo change it to resolveMethodCallExpression
 2168  0
                         if (ctor != null) {
 2169  0
                             Class decClass = ctor.getDeclaringClass();
 2170  0
                             String ownerClassName = null;
 2171  0
                             if (decClass == null) {
 2172   
                                 // meaning the class is the current class
 2173  0
                                 ownerClassName = BytecodeHelper.getClassInternalName(classNode.getName());
 2174   
                             }
 2175   
                             else {
 2176  0
                                 ownerClassName = BytecodeHelper.getClassInternalName(decClass.getName());
 2177   
                             }
 2178   
 
 2179  0
                             Class[] params = ctor.getParameterTypes();
 2180  0
                             StringBuffer argbuf = new StringBuffer("(");
 2181  0
                             for (int i = 0; i < params.length; i++) {
 2182  0
                                 Class arg = params[i];
 2183  0
                                 String descr = BytecodeHelper.getTypeDescription(arg);
 2184  0
                                 argbuf.append(descr);
 2185   
                             }
 2186  0
                             argbuf.append(")V");
 2187   
                             //
 2188  0
                             cv.visitTypeInsn(NEW, ownerClassName);
 2189  0
                             cv.visitInsn(DUP);
 2190   
 
 2191   
                             //
 2192  0
                             Expression arguments = call.getArguments();
 2193  0
                             if (arguments instanceof TupleExpression) {
 2194  0
                                 TupleExpression tupleExpression = (TupleExpression) arguments;
 2195  0
                                 List argexps = tupleExpression.getExpressions();
 2196  0
                                 for (int i = 0; i < argexps.size(); i++) {
 2197  0
                                     Expression expression = (Expression) argexps.get(i);
 2198  0
                                     load(expression);
 2199  0
                                     if (params[i].isPrimitive() /*&& !expression.getTypeClass().isPrimitive()*/) { // data always boxed
 2200  0
                                         cast(params[i]);
 2201  0
                                         helper.quickUnboxIfNecessary(params[i]);
 2202   
                                     }
 2203  0
                                     else if (params[i].isArray() && params[i].getComponentType().isPrimitive() ) {
 2204  0
                                         new ClassExpression(params[i].getComponentType()).visit(this);
 2205  0
                                         convertToPrimitiveArray.call(cv);
 2206  0
                                         cast(params[i]);
 2207   
                                     }
 2208   
                                     else {
 2209   
                                         //? if the target is String , I might as well call Object.toString() regardless
 2210  0
                                         if (expression.getTypeClass() == GString.class && params[i] == String.class){
 2211  0
                                             cast(GString.class);
 2212  0
                                             cv.visitMethodInsn(
 2213   
                                                     INVOKEVIRTUAL,
 2214   
                                                     "java/lang/Object",
 2215   
                                                     "toString",
 2216   
                                                     "()Ljava/lang/String;"
 2217   
                                             );
 2218   
                                         }
 2219   
                                         else {
 2220  0
                                             cast(params[i]);
 2221   
                                         }
 2222   
                                     }
 2223   
                                 }
 2224   
 
 2225  0
                                 cv.visitMethodInsn(INVOKESPECIAL, ownerClassName, "<init>", argbuf.toString());
 2226  0
                                 return;
 2227   
                             } else {
 2228  0
                                 throw new GroovyRuntimeException("arguments type not handled. fall through to late binding");
 2229   
                             }
 2230   
                         }
 2231   
                     } catch (Exception e) {
 2232   
 //                        System.out.println(this.classNode.getName() + ":" + this.methodNode.getName());
 2233   
                         //e.printStackTrace(); //System.out.println(e.getMessage());
 2234   
 //                        log.info("ignore: attempt early binding: " + e.getMessage());
 2235  0
                         break;// fall through
 2236   
                     }
 2237   
                 }
 2238   
             }
 2239   
         } while(false);
 2240   
 
 2241  0
         this.leftHandExpression = false;
 2242   
 
 2243  0
         Expression arguments = call.getArguments();
 2244  0
         if (arguments instanceof TupleExpression) {
 2245  0
             TupleExpression tupleExpression = (TupleExpression) arguments;
 2246  0
             int size = tupleExpression.getExpressions().size();
 2247  0
             if (size == 0) {
 2248  0
                 arguments = null;
 2249   
             }
 2250   
 //            else if (size == 1) { // why unpack the tuple of 1 component?
 2251   
 //                arguments = (Expression) tupleExpression.getExpressions().get(0);
 2252   
 //            }
 2253   
         }
 2254   
 
 2255   
         // lets check that the type exists
 2256  0
         String type = checkValidType(call.getType(), call, "in constructor call");
 2257   
 
 2258   
         //System.out.println("Constructing: " + type);
 2259   
 
 2260  0
         visitClassExpression(new ClassExpression(type));
 2261  0
         if (arguments !=null) {
 2262  0
                arguments.visit(this);
 2263  0
             invokeConstructorOfMethod.call(cv);     // todo subject to opti
 2264   
         } else {
 2265  0
             invokeNoArgumentsConstructorOf.call(cv); // todo subject to opti
 2266   
         }
 2267   
         /*
 2268   
          * cv.visitLdcInsn(type);
 2269   
          *
 2270   
          * arguments.visit(this);
 2271   
          *
 2272   
          * invokeConstructorMethod.call(cv);
 2273   
          */
 2274   
     }
 2275   
 
 2276  0
     public void visitPropertyExpression(PropertyExpression expression) {
 2277   
 
 2278  0
         do {
 2279  0
             if (true && ENABLE_EARLY_BINDING) {
 2280  0
                 expression.resolve(this);
 2281   
 
 2282  0
                 if (!expression.isTypeResolved()) {
 2283  0
                     break;
 2284   
                 }
 2285  0
                 Expression ownerExp = expression.getObjectExpression();
 2286  0
                 String propName = expression.getProperty();
 2287  0
                 if (expression.getProperty().equals("class")) {
 2288  0
                     break; // the default does the right thing. let it do.
 2289   
                 }
 2290   
 
 2291   
 
 2292  0
                 String ownerType = ownerExp.getType();
 2293  0
                 Class ownerClass = ownerExp.getTypeClass();
 2294  0
                 if (ownerType == null || ownerType.length() == 0) {
 2295  0
                     break;
 2296   
                 }
 2297   
 
 2298  0
                 Label l3 = new Label();
 2299   
                 // handle arraylength
 2300  0
                 if (ownerClass != null && ownerClass.isArray() && propName.equals("length")) {
 2301  0
                     load(ownerExp);
 2302  0
                     if (expression.isSafe()) {
 2303  0
                         helper.dup();
 2304  0
                         cv.visitJumpInsn(IFNULL, l3);
 2305   
                     }
 2306  0
                     cast(ownerClass);
 2307  0
                     cv.visitInsn(ARRAYLENGTH);
 2308  0
                     helper.quickBoxIfNecessary(int.class);
 2309  0
                     cv.visitLabel(l3);
 2310  0
                     return;
 2311   
                 }
 2312   
 
 2313   
 
 2314  0
                 String propertyType = expression.getType();
 2315  0
                 if (propertyType == null || propertyType.length() == 0) {
 2316  0
                     break;
 2317   
                 }
 2318  0
                 boolean isStatic = expression.isStatic();
 2319  0
                 if (!isThisExpression(ownerExp) && GroovyObject.class.isAssignableFrom(ownerExp.getTypeClass())) {
 2320   
                     // call other groovy object property via getProperty()/setProperty()
 2321  0
                     if (!isStatic && ownerExp instanceof ClassExpression) {
 2322  0
                         if (leftHandExpression) {
 2323  0
                             cv.visitMethodInsn(
 2324   
                                     INVOKEVIRTUAL,
 2325   
                                     BytecodeHelper.getClassInternalName(ownerType),
 2326   
                                     "setProperty",
 2327   
                                     BytecodeHelper.getTypeDescription(propertyType));
 2328   
                         } else {
 2329  0
                             cv.visitMethodInsn(
 2330   
                                     INVOKEVIRTUAL,
 2331   
                                     BytecodeHelper.getClassInternalName(ownerType),
 2332   
                                     "getProperty",
 2333   
                                     BytecodeHelper.getTypeDescription(propertyType));
 2334   
                         }
 2335  0
                         return;
 2336   
                     } else {
 2337  0
                         break;
 2338   
                     }
 2339   
                 }
 2340   
 //                else if (isThisExpression(ownerExp)){
 2341   
 //                    if (leftHandExpression) {
 2342   
 //                        helper.loadThis();
 2343   
 //                        cv.visitFieldInsn(
 2344   
 //                                PUTFIELD,
 2345   
 //                                BytecodeHelper.getClassInternalName(ownerType),
 2346   
 //                                expression.getProperty(),
 2347   
 //                                BytecodeHelper.getClassInternalName(propertyType));
 2348   
 //                    } else {
 2349   
 //                        cv.visitMethodInsn(
 2350   
 //                                INVOKEVIRTUAL,
 2351   
 //                                BytecodeHelper.getClassInternalName(ownerType),
 2352   
 //                                "getProperty",
 2353   
 //                                BytecodeHelper.getClassInternalName(propertyType));
 2354   
 //                    }
 2355   
 //                    return;
 2356   
 //                }
 2357   
 
 2358   
                 // the following logic is used for this.<prop> acess too.
 2359   
                 else  { // none direct local access
 2360  0
                     Field fld = expression.getField();
 2361  0
                     Method setter = expression.getSetter();
 2362  0
                     Method getter = expression.getGetter();
 2363   
 
 2364   
                     // gate keeping
 2365  0
                     if (leftHandExpression) {
 2366  0
                         if (fld == null && setter == null) {
 2367  0
                             break;
 2368   
                         }
 2369   
                     }
 2370   
                     else {
 2371  0
                         if (fld == null && getter == null) {
 2372  0
                             break;
 2373   
                         }
 2374   
                     }
 2375   
 
 2376  0
                     if (ownerClass == null && !isThisExpression(ownerExp)) {
 2377  0
                         break;  // ownerClass is null only when the ownerExp is "this"
 2378   
                     }
 2379   
                     // now looking for public fields before accessors
 2380   
 
 2381   
 
 2382  0
                     if (expression.isStatic()) {
 2383  0
                         if (leftHandExpression) {
 2384  0
                             if (fld != null) {
 2385  0
                                 helper.quickUnboxIfNecessary(expression.getTypeClass());
 2386  0
                                 cv.visitFieldInsn(
 2387   
                                         PUTSTATIC,
 2388   
                                         BytecodeHelper.getClassInternalName(ownerType),
 2389   
                                         expression.getProperty(),
 2390   
                                         BytecodeHelper.getTypeDescription(propertyType)
 2391   
                                 );
 2392   
                             }
 2393  0
                             else if (setter != null) {
 2394  0
                                 helper.quickUnboxIfNecessary(setter.getParameterTypes()[0]);
 2395  0
                                 cast(setter.getParameterTypes()[0]);
 2396  0
                                 helper.invoke(setter);
 2397   
                             }
 2398   
                             else {
 2399  0
                                 throwException("no method or field is found for a resolved property access");
 2400   
                             }
 2401   
                         }
 2402   
                         else { // get the property
 2403  0
                             if (fld != null){
 2404  0
                                 cv.visitFieldInsn(
 2405   
                                         GETSTATIC,
 2406   
                                         BytecodeHelper.getClassInternalName(ownerType),
 2407   
                                         propName,
 2408   
                                         BytecodeHelper.getTypeDescription(propertyType)
 2409   
                                 );
 2410  0
                                 helper.quickBoxIfNecessary(expression.getTypeClass());
 2411   
                             }
 2412  0
                             else if (getter != null) {
 2413  0
                                 helper.invoke(getter);
 2414  0
                                 helper.quickBoxIfNecessary(expression.getTypeClass());
 2415   
                             }
 2416   
                             else {
 2417  0
                                 throwException("no method or field is found for a resolved property access");
 2418   
                             }
 2419   
                         }
 2420   
                     } else { // non-static access
 2421  0
                         if (leftHandExpression) { // set the property
 2422   
                               // assumption: the data on the stack are boxed if it's a number
 2423  0
                             helper.quickUnboxIfNecessary(expression.getTypeClass());
 2424  0
                             load(ownerExp);
 2425  0
                             if (expression.isSafe()) {
 2426  0
                                 helper.dup();
 2427  0
                                 cv.visitJumpInsn(IFNULL, l3);
 2428   
                             }
 2429   
 
 2430  0
                             if (ownerClass != null)
 2431  0
                                 cast(ownerClass);
 2432  0
                             Class cls = expression.getTypeClass();
 2433  0
                             if (cls == double.class || cls == long.class) {
 2434  0
                                 cv.visitInsn(DUP_X2);
 2435  0
                                 cv.visitInsn(POP);
 2436   
                             } else {
 2437  0
                                 cv.visitInsn(SWAP);
 2438   
                             }
 2439   
 
 2440  0
                             if (fld != null) {
 2441  0
                                 cv.visitFieldInsn(
 2442   
                                         PUTFIELD,
 2443   
                                         BytecodeHelper.getClassInternalName(ownerType),
 2444   
                                         propName,
 2445   
                                         BytecodeHelper.getTypeDescription(propertyType)
 2446   
                                 );
 2447   
                             }
 2448  0
                             else if (setter != null) {
 2449  0
                                 Method m = setter;
 2450  0
                                 Class[] paramTypes = m.getParameterTypes();
 2451  0
                                 if (paramTypes.length != 1) {
 2452  0
                                     throw new RuntimeException("setter should take a single parameter");
 2453   
                                 }
 2454  0
                                 Class paramType = paramTypes[0];
 2455  0
                                 cast(paramType);
 2456  0
                                 helper.invoke(setter);
 2457   
                             }
 2458   
                             else {
 2459  0
                                 throwException("no method or field is found for a resolved property access");
 2460   
                             }
 2461   
                         }
 2462   
                         else { // get property
 2463  0
                             load(ownerExp);
 2464  0
                             if (expression.isSafe()) {
 2465  0
                                 helper.dup();
 2466  0
                                 cv.visitJumpInsn(IFNULL, l3);
 2467   
                             }
 2468  0
                             if (ownerClass != null)
 2469  0
                                 cast(ownerClass);
 2470  0
                             if (fld != null) {
 2471  0
                                 cv.visitFieldInsn(
 2472   
                                         GETFIELD,
 2473   
                                         BytecodeHelper.getClassInternalName(ownerType),
 2474   
                                         propName,
 2475   
                                         BytecodeHelper.getTypeDescription(propertyType)
 2476   
                                 );
 2477  0
                                 helper.quickBoxIfNecessary(expression.getTypeClass());
 2478   
                             }
 2479  0
                             else if (getter != null) {
 2480  0
                                 helper.invoke(getter);
 2481  0
                                 helper.quickBoxIfNecessary(expression.getTypeClass());
 2482   
                             }
 2483   
                             else {
 2484  0
                                 throwException("no method or field is found for a resolved property access");
 2485   
                             }
 2486   
                         }
 2487   
                     }
 2488  0
                     cv.visitLabel(l3);
 2489  0
                     return;
 2490   
                 }
 2491   
             }
 2492   
         } while (false);
 2493   
 
 2494   
         // lets check if we're a fully qualified class name
 2495  0
         String className = null;
 2496  0
         Expression objectExpression = expression.getObjectExpression();
 2497  0
         if (!isThisExpression(objectExpression)) {
 2498  0
             className = checkForQualifiedClass(expression);
 2499  0
             if (className != null) {
 2500  0
                 visitClassExpression(new ClassExpression(className));
 2501  0
                 return;
 2502   
             }
 2503   
         }
 2504  0
         if (expression.getProperty().equals("class")) {
 2505  0
             if ((objectExpression instanceof ClassExpression)) {
 2506  0
                 visitClassExpression((ClassExpression) objectExpression);
 2507  0
                 return;
 2508   
             }
 2509  0
             else if (objectExpression instanceof VariableExpression) {
 2510  0
                 VariableExpression varExp = (VariableExpression) objectExpression;
 2511  0
                 className = varExp.getVariable();
 2512  0
                 try {
 2513  0
                     className = resolveClassName(className);
 2514  0
                     visitClassExpression(new ClassExpression(className));
 2515  0
                     return;
 2516   
                 }
 2517   
                 catch (Exception e) {
 2518   
                     // ignore
 2519   
                 }
 2520   
             }
 2521   
         }
 2522   
 
 2523  0
         if (isThisExpression(objectExpression)) {
 2524   
             // lets use the field expression if its available
 2525  0
             String name = expression.getProperty();
 2526  0
             FieldNode field = classNode.getField(name);
 2527  0
             if (field != null) {
 2528  0
                 visitFieldExpression(new FieldExpression(field));
 2529  0
                 return;
 2530   
             }
 2531   
         }
 2532   
 
 2533  0
         boolean left = leftHandExpression;
 2534   
         // we need to clear the LHS flag to avoid "this." evaluating as ASTORE
 2535   
         // rather than ALOAD
 2536  0
         leftHandExpression = false;
 2537   
 
 2538  0
         objectExpression.visit(this);
 2539   
 
 2540  0
         cv.visitLdcInsn(expression.getProperty());
 2541   
 
 2542  0
         if (isGroovyObject(objectExpression) && ! expression.isSafe()) {
 2543  0
             if (left) {
 2544  0
                 setGroovyObjectPropertyMethod.call(cv);
 2545   
             }
 2546   
             else {
 2547  0
                 getGroovyObjectPropertyMethod.call(cv);
 2548   
             }
 2549   
         }
 2550   
         else {
 2551  0
             if (expression.isSafe()) {
 2552  0
                 if (left) {
 2553  0
                     setPropertySafeMethod2.call(cv);
 2554   
                 }
 2555   
                 else {
 2556  0
                     getPropertySafeMethod.call(cv);
 2557   
                 }
 2558   
             }
 2559   
             else {
 2560  0
                 if (left) {
 2561  0
                     setPropertyMethod2.call(cv);
 2562   
                 }
 2563   
                 else {
 2564  0
                     getPropertyMethod.call(cv);
 2565   
                 }
 2566   
             }
 2567   
         }
 2568   
     }
 2569   
 
 2570  0
     protected boolean isGroovyObject(Expression objectExpression) {
 2571  0
         return isThisExpression(objectExpression);
 2572   
     }
 2573   
 
 2574   
     /**
 2575   
      * Checks if the given property expression represents a fully qualified class name
 2576   
      * @return the class name or null if the property is not a valid class name
 2577   
      */
 2578  0
     protected String checkForQualifiedClass(PropertyExpression expression) {
 2579  0
         String text = expression.getText();
 2580  0
         try {
 2581  0
             return resolveClassName(text);
 2582   
         }
 2583   
         catch (Exception e) {
 2584  0
             if (text.endsWith(".class")) {
 2585  0
                 text = text.substring(0, text.length() - 6);
 2586  0
                 try {
 2587  0
                     return resolveClassName(text);
 2588   
                 }
 2589   
                 catch (Exception e2) {
 2590   
                 }
 2591   
             }
 2592  0
             return null;
 2593   
         }
 2594   
     }
 2595   
 
 2596  0
     public void visitFieldExpression(FieldExpression expression) {
 2597  0
         FieldNode field = expression.getField();
 2598   
 
 2599   
 
 2600  0
         if (field.isStatic()) {
 2601  0
             if (leftHandExpression) {
 2602  0
                 storeStaticField(expression);
 2603   
             }
 2604   
             else {
 2605  0
                 loadStaticField(expression);
 2606   
             }
 2607   
         } else {
 2608  0
             if (leftHandExpression) {
 2609  0
                 storeThisInstanceField(expression);
 2610   
             }
 2611   
             else {
 2612  0
                 loadInstanceField(expression);
 2613   
             }
 2614   
         }
 2615   
     }
 2616   
 
 2617   
     /**
 2618   
      *
 2619   
      * @param fldExp
 2620   
      */
 2621  0
     public void loadStaticField(FieldExpression fldExp) {
 2622  0
         FieldNode field = fldExp.getField();
 2623  0
         boolean holder = field.isHolder() && !isInClosureConstructor();
 2624  0
         String type = field.getType();
 2625   
 
 2626  0
         String ownerName = (field.getOwner().equals(classNode.getName()))
 2627   
                 ? internalClassName
 2628   
                 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
 2629  0
         if (holder) {
 2630  0
             cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
 2631  0
             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
 2632   
         }
 2633   
         else {
 2634  0
             cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
 2635  0
             if (BytecodeHelper.isPrimitiveType(type)) {
 2636  0
                 helper.box(type);
 2637   
             } else {
 2638   
             }
 2639   
         }
 2640   
     }
 2641   
 
 2642   
     /**
 2643   
      * RHS instance field. should move most of the code in the BytecodeHelper
 2644   
      * @param fldExp
 2645   
      */
 2646  0
     public void loadInstanceField(FieldExpression fldExp) {
 2647  0
         FieldNode field = fldExp.getField();
 2648  0
         boolean holder = field.isHolder() && !isInClosureConstructor();
 2649  0
         String type = field.getType();
 2650  0
         String ownerName = (field.getOwner().equals(classNode.getName()))
 2651   
                 ? internalClassName
 2652   
                 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
 2653   
 
 2654  0
         cv.visitVarInsn(ALOAD, 0);
 2655  0
         cv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
 2656   
 
 2657  0
         if (holder) {
 2658  0
             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
 2659   
         } else {
 2660  0
             if (BytecodeHelper.isPrimitiveType(type)) {
 2661  0
                 helper.box(type);
 2662   
             } else {
 2663   
             }
 2664   
         }
 2665   
     }
 2666   
 
 2667  0
     public void storeThisInstanceField(FieldExpression expression) {
 2668  0
         FieldNode field = expression.getField();
 2669   
 
 2670  0
         boolean holder = field.isHolder() && !isInClosureConstructor();
 2671  0
         String type = field.getType();
 2672   
 
 2673  0
         String ownerName =  (field.getOwner().equals(classNode.getName())) ?
 2674   
                 internalClassName : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
 2675  0
         if (holder) {
 2676  0
             Variable tv = visitASTOREInTemp(field.getName());
 2677  0
             int tempIndex = tv.getIndex();
 2678  0
             cv.visitVarInsn(ALOAD, 0);
 2679  0
             cv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
 2680  0
             cv.visitVarInsn(ALOAD, tempIndex);
 2681  0
             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
 2682  0
             removeVar(tv);
 2683   
         }
 2684   
         else {
 2685  0
             if (isInClosureConstructor()) {
 2686  0
                 helper.doCast(type);
 2687   
             }
 2688   
             else {
 2689  0
                 if (ENABLE_EARLY_BINDING) {
 2690  0
                     helper.doCast(type);
 2691   
                 }
 2692   
                 else {
 2693   
                     // this may be superfluous
 2694  0
                     doConvertAndCast(type);
 2695   
                 }
 2696   
             }
 2697   
             //Variable tmpVar = defineVariable(createVariableName(field.getName()), "java.lang.Object", false);
 2698  0
             Variable tmpVar = defineVariable(createVariableName(field.getName()), field.getType(), false);
 2699   
             //int tempIndex = tmpVar.getIndex();
 2700   
             //helper.store(field.getType(), tempIndex);
 2701  0
             helper.store(tmpVar, MARK_START);
 2702  0
             helper.loadThis(); //cv.visitVarInsn(ALOAD, 0);
 2703  0
             helper.load(tmpVar);
 2704  0
             helper.putField(field, ownerName);
 2705   
             //cv.visitFieldInsn(PUTFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
 2706   
             // let's remove the temp var
 2707  0
             removeVar(tmpVar);
 2708   
         }
 2709   
     }
 2710   
 
 2711   
 
 2712  0
     public void storeStaticField(FieldExpression expression) {
 2713  0
         FieldNode field = expression.getField();
 2714   
 
 2715  0
         boolean holder = field.isHolder() && !isInClosureConstructor();
 2716   
 
 2717  0
         String type = field.getType();
 2718   
 
 2719  0
         String ownerName = (field.getOwner().equals(classNode.getName()))
 2720   
                 ? internalClassName
 2721   
                 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
 2722  0
         if (holder) {
 2723  0
             Variable tv = visitASTOREInTemp(field.getName());
 2724  0
             int tempIndex = tv.getIndex();
 2725  0
             cv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
 2726  0
             cv.visitVarInsn(ALOAD, tempIndex);
 2727  0
             cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
 2728  0
             removeVar(tv);
 2729   
         }
 2730   
         else {
 2731  0
             if (isInClosureConstructor()) {
 2732  0
                 helper.doCast(type);
 2733   
             }
 2734   
             else {
 2735  0
                 if (ENABLE_EARLY_BINDING) {
 2736  0
                     helper.doCast(type);
 2737   
                 }
 2738   
                 else {
 2739   
                     // this may be superfluous
 2740   
                     //doConvertAndCast(type);
 2741   
                     // use weaker cast
 2742  0
                     helper.doCast(type);
 2743   
                 }
 2744   
             }
 2745  0
             cv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
 2746   
         }
 2747   
     }
 2748   
 
 2749  0
     protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) {
 2750  0
         FieldNode field = expression.getField();
 2751  0
         boolean isStatic = field.isStatic();
 2752   
 
 2753  0
         Variable fieldTemp = defineVariable(createVariableName(field.getName()), "java.lang.Object", false);
 2754  0
         int valueIdx = fieldTemp.getIndex();
 2755   
 
 2756  0
         if (leftHandExpression && first) {
 2757  0
             cv.visitVarInsn(ASTORE, valueIdx);
 2758  0
             visitVariableStartLabel(fieldTemp);
 2759   
         }
 2760   
 
 2761  0
         if (steps > 1 || !isStatic) {
 2762  0
             cv.visitVarInsn(ALOAD, 0);
 2763  0
             cv.visitFieldInsn(
 2764   
                 GETFIELD,
 2765   
                 internalClassName,
 2766   
                 "owner",
 2767   
                 BytecodeHelper.getTypeDescription(outerClassNode.getName()));
 2768   
         }
 2769   
 
 2770  0
         if( steps == 1 ) {
 2771  0
             int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD);
 2772  0
             String ownerName = BytecodeHelper.getClassInternalName(outerClassNode.getName());
 2773   
 
 2774  0
             if (leftHandExpression) {
 2775  0
                 cv.visitVarInsn(ALOAD, valueIdx);
 2776  0
                 boolean holder = field.isHolder() && !isInClosureConstructor();
 2777  0
                 if ( !holder) {
 2778  0
                     doConvertAndCast(field.getType());
 2779   
                 }
 2780   
             }
 2781  0
             cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
 2782  0
             if (!leftHandExpression) {
 2783  0
                 if (BytecodeHelper.isPrimitiveType(field.getType())) {
 2784  0
                     helper.box(field.getType());
 2785   
                 }
 2786   
             }
 2787   
         }
 2788   
 
 2789   
         else {
 2790  0
             visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false );
 2791   
         }
 2792   
     }
 2793   
 
 2794   
 
 2795   
 
 2796   
     /**
 2797   
      *  Visits a bare (unqualified) variable expression.
 2798   
      */
 2799   
 
 2800  0
     public void visitVariableExpression(VariableExpression expression) {
 2801   
 
 2802  0
         String variableName = expression.getVariable();
 2803   
 
 2804   
       //-----------------------------------------------------------------------
 2805   
       // SPECIAL CASES
 2806   
 
 2807   
         //
 2808   
         // "this" for static methods is the Class instance
 2809   
 
 2810  0
         if (isStaticMethod() && variableName.equals("this")) {
 2811  0
             visitClassExpression(new ClassExpression(classNode.getName()));
 2812  0
             return;                                               // <<< FLOW CONTROL <<<<<<<<<
 2813   
         }
 2814   
 
 2815   
         //
 2816   
         // "super" also requires special handling
 2817   
 
 2818  0
         if (variableName.equals("super")) {
 2819  0
             visitClassExpression(new ClassExpression(classNode.getSuperClass()));
 2820  0
             return;                                               // <<< FLOW CONTROL <<<<<<<<<
 2821   
         }
 2822   
 
 2823   
 
 2824   
         //
 2825   
         // class names return a Class instance, too
 2826   
 
 2827   
 //        if (!variableName.equals("this")) {
 2828   
 //            String className = resolveClassName(variableName);
 2829   
 //            if (className != null) {
 2830   
 //                if (leftHandExpression) {
 2831   
 //                    throw new RuntimeParserException(
 2832   
 //                        "Cannot use a class expression on the left hand side of an assignment",
 2833   
 //                        expression);
 2834   
 //                }
 2835   
 //                visitClassExpression(new ClassExpression(className));
 2836   
 //                return;                                               // <<< FLOW CONTROL <<<<<<<<<
 2837   
 //            }
 2838   
 //        }
 2839   
 
 2840   
 
 2841   
       //-----------------------------------------------------------------------
 2842   
       // GENERAL VARIABLE LOOKUP
 2843   
 
 2844   
 
 2845   
         //
 2846   
         // We are handling only unqualified variables here.  Therefore,
 2847   
         // we do not care about accessors, because local access doesn't
 2848   
         // go through them.  Therefore, precedence is as follows:
 2849   
         //   1) local variables, nearest block first
 2850   
         //   2) class fields
 2851   
         //   3) repeat search from 2) in next outer class
 2852   
 
 2853  0
         boolean  handled  = false;
 2854  0
         Variable variable = (Variable)variableStack.get( variableName );
 2855   
 
 2856  0
         if( variable != null ) {
 2857   
 
 2858  0
             if( variable.isProperty() ) {
 2859  0
                 processPropertyVariable(variable );
 2860   
             }
 2861   
             else {
 2862  0
                 if (ENABLE_EARLY_BINDING && expression.isTypeResolved() && leftHandExpression) {
 2863   
                     // let's pass the type back to the variable
 2864  0
                     String typeName = expression.getType();
 2865  0
                     Type varOldType = variable.getType();
 2866  0
                     if (varOldType.isDynamic()) {
 2867  0
                         variable.setType(new Type(typeName, true));
 2868   
                     }
 2869  0
                     else if (!varOldType.getName().equals(typeName)){
 2870  0
                         new GroovyRuntimeException("VariableExpression data type conflicts with the existing variable. "
 2871   
                                 + "[" + expression.getLineNumber() + ":" + expression.getColumnNumber() + "]");
 2872   
                     }
 2873   
                 }
 2874  0
                 processStackVariable(variable );
 2875   
             }
 2876   
 
 2877  0
             handled = true;
 2878   
         } else {
 2879   
             //
 2880   
             // Loop through outer classes for fields
 2881   
 
 2882  0
             int       steps   = 0;
 2883  0
             ClassNode currentClassNode = classNode;
 2884  0
             FieldNode field   = null;
 2885   
 
 2886  0
             do {
 2887  0
                 if( (field = currentClassNode.getField(variableName)) != null ) {
 2888  0
                     if (methodNode == null || !methodNode.isStatic() || field.isStatic() )
 2889  0
                         break; //this is a match. break out. todo to be tested
 2890   
                 }
 2891  0
                 steps++;
 2892   
 
 2893  ?
             } while( (currentClassNode = currentClassNode.getOuterClass()) != null );
 2894   
 
 2895  0
             if( field != null ) {
 2896  0
                 processFieldAccess( variableName, field, steps );
 2897  0
                 handled = true;
 2898   
             }
 2899   
         }
 2900   
 
 2901   
         //
 2902   
         // class names return a Class instance, too
 2903  0
         if (!handled  && !variableName.equals("this")) {
 2904  0
             String className = resolveClassName(variableName);
 2905  0
             if (className != null) {
 2906  0
                 if (leftHandExpression) {
 2907  0
                     throwException("Cannot use a class expression on the left hand side of an assignment");
 2908   
                 }
 2909  0
                 visitClassExpression(new ClassExpression(className));
 2910  0
                 return;                                               // <<< FLOW CONTROL <<<<<<<<<
 2911   
             }
 2912   
         }
 2913   
 
 2914   
         //
 2915   
         // Finally, if unhandled, create a variable for it.
 2916   
         // Except there a stack variable should be created,
 2917   
         // we define the variable as a property accessor and
 2918   
         // let other parts of the classgen report the error
 2919   
         // if the property doesn't exist.
 2920   
 
 2921  0
         if( !handled ) {
 2922  0
             String variableType = expression.getType();
 2923  0
             variable = defineVariable( variableName, variableType );
 2924   
 
 2925  0
             if (leftHandExpression && expression.isDynamic()) {
 2926  0
                 variable.setDynamic(true); // false  by default
 2927   
             }
 2928   
             else {
 2929  0
                 variable.setDynamic(false);
 2930   
             }
 2931   
 
 2932  0
             if( isInScriptBody() || !leftHandExpression ) { // todo problematic: if on right hand not defined, should I report undefined var error?
 2933  0
                 variable.setProperty( true );
 2934  0
                 processPropertyVariable(variable );
 2935   
             }
 2936   
             else {
 2937  0
                 processStackVariable(variable );
 2938   
             }
 2939   
         }
 2940   
     }
 2941   
 
 2942   
 
 2943  0
     protected void processStackVariable(Variable variable ) {
 2944  0
         boolean holder = variable.isHolder() && !passingClosureParams;
 2945   
 
 2946  0
         if( leftHandExpression ) {
 2947  0
             helper.storeVar(variable, holder);
 2948   
         }
 2949   
         else {
 2950  0
             helper.loadVar(variable, holder);
 2951   
         }
 2952  0
         if (ASM_DEBUG) {
 2953  0
             helper.mark("var: " + variable.getName());
 2954   
         }
 2955   
     }
 2956   
 
 2957  0
     private void visitVariableStartLabel(Variable variable) {
 2958  0
         if (CREATE_DEBUG_INFO) {
 2959  0
             Label l = variable.getStartLabel();
 2960  0
             if (l != null) {
 2961  0
                 cv.visitLabel(l);
 2962   
             } else {
 2963  0
                 System.out.println("start label == null! what to do about this?");
 2964   
             }
 2965   
         }
 2966   
     }
 2967   
 
 2968  0
     protected void processPropertyVariable(Variable variable ) {
 2969  0
         String name = variable.getName();
 2970  0
         if (variable.isHolder() && passingClosureParams && isInScriptBody() ) {
 2971   
             // lets create a ScriptReference to pass into the closure
 2972  0
             cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference");
 2973  0
             cv.visitInsn(DUP);
 2974   
 
 2975  0
             loadThisOrOwner();
 2976  0
             cv.visitLdcInsn(name);
 2977   
 
 2978  0
             cv.visitMethodInsn(
 2979   
                 INVOKESPECIAL,
 2980   
                 "org/codehaus/groovy/runtime/ScriptReference",
 2981   
                 "<init>",
 2982   
                 "(Lgroovy/lang/Script;Ljava/lang/String;)V");
 2983   
         }
 2984   
         else {
 2985  0
             visitPropertyExpression(new PropertyExpression(VariableExpression.THIS_EXPRESSION, name));
 2986   
         }
 2987   
     }
 2988   
 
 2989   
 
 2990  0
     protected void processFieldAccess( String name, FieldNode field, int steps ) {
 2991  0
         FieldExpression expression = new FieldExpression(field);
 2992   
 
 2993  0
         if( steps == 0 ) {
 2994  0
             visitFieldExpression( expression );
 2995   
         }
 2996   
         else {
 2997  0
             visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true );
 2998   
         }
 2999   
     }
 3000   
 
 3001   
 
 3002   
 
 3003   
     /**
 3004   
      * @return true if we are in a script body, where all variables declared are no longer
 3005   
      * local variables but are properties
 3006   
      */
 3007  0
     protected boolean isInScriptBody() {
 3008  0
         if (classNode.isScriptBody()) {
 3009  0
             return true;
 3010   
         }
 3011   
         else {
 3012  0
             return classNode.isScript() && methodNode != null && methodNode.getName().equals("run");
 3013   
         }
 3014   
     }
 3015   
 
 3016   
     /**
 3017   
      * @return true if this expression will have left a value on the stack
 3018   
      * that must be popped
 3019   
      */
 3020  0
     protected boolean isPopRequired(Expression expression) {
 3021  0
         if (expression instanceof MethodCallExpression) {
 3022  0
             if (expression.getType() != null && expression.getType().equals("void")) { // nothing on the stack
 3023  0
                 return false;
 3024   
             } else {
 3025  0
                 return !MethodCallExpression.isSuperMethodCall((MethodCallExpression) expression);
 3026   
             }
 3027   
         }
 3028  0
         if (expression instanceof BinaryExpression) {
 3029  0
             BinaryExpression binExp = (BinaryExpression) expression;
 3030  0
             switch (binExp.getOperation().getType()) {   // br todo should leave a copy of the value on the stack for all the assignemnt.
 3031   
 //                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
 3032   
 //                case Types.PLUS_EQUAL : // this and the following are related to evaluateBinaryExpressionWithAsignment()
 3033   
 //                case Types.MINUS_EQUAL :
 3034   
 //                case Types.MULTIPLY_EQUAL :
 3035   
 //                case Types.DIVIDE_EQUAL :
 3036   
 //                case Types.INTDIV_EQUAL :
 3037   
 //                case Types.MOD_EQUAL :
 3038   
 //                    return false;
 3039   
             }
 3040   
         }
 3041  0
         return true;
 3042   
     }
 3043   
 
 3044  0
     protected boolean firstStatementIsSuperInit(Statement code) {
 3045  0
         ExpressionStatement expStmt = null;
 3046  0
         if (code instanceof ExpressionStatement) {
 3047  0
             expStmt = (ExpressionStatement) code;
 3048   
         }
 3049  0
         else if (code instanceof BlockStatement) {
 3050  0
             BlockStatement block = (BlockStatement) code;
 3051  0
             if (!block.getStatements().isEmpty()) {
 3052  0
                 Object expr = block.getStatements().get(0);
 3053  0
                 if (expr instanceof ExpressionStatement) {
 3054  0
                     expStmt = (ExpressionStatement) expr;
 3055   
                 }
 3056   
             }
 3057   
         }
 3058  0
         if (expStmt != null) {
 3059  0
             Expression expr = expStmt.getExpression();
 3060  0
             if (expr instanceof MethodCallExpression) {
 3061  0
                 MethodCallExpression call = (MethodCallExpression) expr;
 3062  0
                 if (MethodCallExpression.isSuperMethodCall(call)) {
 3063   
                     // not sure which one is constantly used as the super class ctor call. To cover both for now
 3064  0
                     return call.getMethod().equals("<init>") || call.getMethod().equals("super");
 3065   
                 }
 3066   
             }
 3067   
         }
 3068  0
         return false;
 3069   
     }
 3070   
 
 3071  0
     protected void createSyntheticStaticFields() {
 3072  0
         for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) {
 3073  0
             String staticFieldName = (String) iter.next();
 3074   
             // generate a field node
 3075  0
             cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null);
 3076   
         }
 3077   
 
 3078  0
         if (!syntheticStaticFields.isEmpty()) {
 3079  0
             cv =
 3080   
                 cw.visitMethod(
 3081   
                     ACC_STATIC + ACC_SYNTHETIC,
 3082   
                     "class$",
 3083   
                     "(Ljava/lang/String;)Ljava/lang/Class;",
 3084   
                     null,
 3085   
                     null);
 3086  0
             helper = new BytecodeHelper(cv);
 3087   
 
 3088  0
             Label l0 = new Label();
 3089  0
             cv.visitLabel(l0);
 3090  0
             cv.visitVarInsn(ALOAD, 0);
 3091  0
             cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
 3092  0
             Label l1 = new Label();
 3093  0
             cv.visitLabel(l1);
 3094  0
             cv.visitInsn(ARETURN);
 3095  0
             Label l2 = new Label();
 3096  0
             cv.visitLabel(l2);
 3097  0
             cv.visitVarInsn(ASTORE, 1);
 3098  0
             cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
 3099  0
             cv.visitInsn(DUP);
 3100  0
             cv.visitVarInsn(ALOAD, 1);
 3101  0
             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;");
 3102  0
             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
 3103  0
             cv.visitInsn(ATHROW);
 3104  0
             cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); // br using l2 as the 2nd param seems create the right table entry
 3105  0
             cv.visitMaxs(3, 2);
 3106   
 
 3107  0
             cw.visitEnd();
 3108   
         }
 3109   
     }
 3110   
     /** load class object on stack */
 3111  0
     public void visitClassExpression(ClassExpression expression) {
 3112  0
         String type = expression.getText();
 3113   
         //type = checkValidType(type, expression, "Must be a valid type name for a constructor call");
 3114   
 
 3115   
 
 3116  0
         if (BytecodeHelper.isPrimitiveType(type)) {
 3117  0
             String objectType = BytecodeHelper.getObjectTypeForPrimitive(type);
 3118  0
             cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;");
 3119   
         }
 3120   
         else {
 3121  0
             final String staticFieldName =
 3122  0
                 (type.equals(classNode.getName())) ? "class$0" : "class$" + type.replace('.', '$').replace('[', '_').replace(';', '_');
 3123   
 
 3124  0
             syntheticStaticFields.add(staticFieldName);
 3125   
 
 3126  0
             cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
 3127  0
             Label l0 = new Label();
 3128  0
             cv.visitJumpInsn(IFNONNULL, l0);
 3129  0
             cv.visitLdcInsn(type);
 3130  0
             cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
 3131  0
             cv.visitInsn(DUP);
 3132  0
             cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
 3133  0
             Label l1 = new Label();
 3134  0
             cv.visitJumpInsn(GOTO, l1);
 3135  0
             cv.visitLabel(l0);
 3136  0
             cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
 3137  0
             cv.visitLabel(l1);
 3138   
         }
 3139   
     }
 3140   
 
 3141  0
     public void visitRangeExpression(RangeExpression expression) {
 3142  0
         leftHandExpression = false;
 3143  0
         expression.getFrom().visit(this);
 3144   
 
 3145  0
         leftHandExpression = false;
 3146  0
         expression.getTo().visit(this);
 3147   
 
 3148  0
         helper.pushConstant(expression.isInclusive());
 3149   
 
 3150  0
         createRangeMethod.call(cv);
 3151   
     }
 3152   
 
 3153  0
     public void visitMapEntryExpression(MapEntryExpression expression) {
 3154   
     }
 3155   
 
 3156  0
     public void visitMapExpression(MapExpression expression) {
 3157  0
         List entries = expression.getMapEntryExpressions();
 3158  0
         int size = entries.size();
 3159  0
         helper.pushConstant(size * 2);
 3160   
 
 3161  0
         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
 3162   
 
 3163  0
         int i = 0;
 3164  0
         for (Iterator iter = entries.iterator(); iter.hasNext();) {
 3165  0
             MapEntryExpression entry = (MapEntryExpression) iter.next();
 3166   
 
 3167  0
             cv.visitInsn(DUP);
 3168  0
             helper.pushConstant(i++);
 3169  0
             visitAndAutoboxBoolean(entry.getKeyExpression());
 3170  0
             cv.visitInsn(AASTORE);
 3171   
 
 3172  0
             cv.visitInsn(DUP);
 3173  0
             helper.pushConstant(i++);
 3174  0
             visitAndAutoboxBoolean(entry.getValueExpression());
 3175  0
             cv.visitInsn(AASTORE);
 3176   
         }
 3177  0
         createMapMethod.call(cv);
 3178   
     }
 3179   
 
 3180  0
     public void visitTupleExpression(TupleExpression expression) {
 3181  0
         int size = expression.getExpressions().size();
 3182   
 
 3183  0
         helper.pushConstant(size);
 3184   
 
 3185  0
         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
 3186   
 
 3187  0
         for (int i = 0; i < size; i++) {
 3188  0
             cv.visitInsn(DUP);
 3189  0
             helper.pushConstant(i);
 3190  0
             visitAndAutoboxBoolean(expression.getExpression(i));
 3191  0
             cv.visitInsn(AASTORE);
 3192   
         }
 3193   
         //createTupleMethod.call(cv);
 3194   
     }
 3195   
 
 3196  0
     public void visitArrayExpression(ArrayExpression expression) {
 3197  0
         String type = expression.getElementType();
 3198  0
         String typeName = BytecodeHelper.getClassInternalName(type);
 3199  0
         Expression sizeExpression = expression.getSizeExpression();
 3200  0
         if (sizeExpression != null) {
 3201   
             // lets convert to an int
 3202  0
             visitAndAutoboxBoolean(sizeExpression);
 3203  0
             asIntMethod.call(cv);
 3204   
 
 3205  0
             cv.visitTypeInsn(ANEWARRAY, typeName);
 3206   
         }
 3207   
         else {
 3208  0
             int size = expression.getExpressions().size();
 3209  0
             helper.pushConstant(size);
 3210   
 
 3211  0
             cv.visitTypeInsn(ANEWARRAY, typeName);
 3212   
 
 3213  0
             for (int i = 0; i < size; i++) {
 3214  0
                 cv.visitInsn(DUP);
 3215  0
                 helper.pushConstant(i);
 3216  0
                 Expression elementExpression = expression.getExpression(i);
 3217  0
                 if (elementExpression == null) {
 3218  0
                     ConstantExpression.NULL.visit(this);
 3219   
                 }
 3220   
                 else {
 3221   
 
 3222  0
                     if(!type.equals(elementExpression.getClass().getName())) {
 3223  0
                         visitCastExpression(new CastExpression(type, elementExpression));
 3224   
                     }
 3225   
                     else {
 3226  0
                         visitAndAutoboxBoolean(elementExpression);
 3227   
                     }
 3228   
                 }
 3229  0
                 cv.visitInsn(AASTORE);
 3230   
             }
 3231   
         }
 3232   
     }
 3233   
 
 3234  0
     public void visitListExpression(ListExpression expression) {
 3235  0
         int size = expression.getExpressions().size();
 3236  0
         helper.pushConstant(size);
 3237   
 
 3238  0
         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
 3239   
 
 3240  0
         for (int i = 0; i < size; i++) {
 3241  0
             cv.visitInsn(DUP);
 3242  0
             helper.pushConstant(i);
 3243  0
             visitAndAutoboxBoolean(expression.getExpression(i));
 3244  0
             cv.visitInsn(AASTORE);
 3245   
         }
 3246  0
         createListMethod.call(cv);
 3247   
     }
 3248   
 
 3249  0
     public void visitGStringExpression(GStringExpression expression) {
 3250  0
         int size = expression.getValues().size();
 3251  0
         helper.pushConstant(size);
 3252   
 
 3253  0
         cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
 3254   
 
 3255  0
         for (int i = 0; i < size; i++) {
 3256  0
             cv.visitInsn(DUP);
 3257  0
             helper.pushConstant(i);
 3258  0
             visitAndAutoboxBoolean(expression.getValue(i));
 3259  0
             cv.visitInsn(AASTORE);
 3260   
         }
 3261   
 
 3262  0
         Variable tv = visitASTOREInTemp("iterator");
 3263  0
         int paramIdx = tv.getIndex();
 3264   
 
 3265  0
         ClassNode innerClass = createGStringClass(expression);
 3266  0
         addInnerClass(innerClass);
 3267  0
         String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName());
 3268   
 
 3269  0
         cv.visitTypeInsn(NEW, innerClassinternalName);
 3270  0
         cv.visitInsn(DUP);
 3271  0
         cv.visitVarInsn(ALOAD, paramIdx);
 3272   
 
 3273  0
         cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V");
 3274  0
         removeVar(tv);
 3275   
     }
 3276   
 
 3277  0
     private Variable visitASTOREInTemp(String s) {
 3278  0
         return storeInTemp(s, "java.lang.Object");
 3279   
     }
 3280   
 
 3281   
     // Implementation methods
 3282   
     //-------------------------------------------------------------------------
 3283  0
     protected boolean addInnerClass(ClassNode innerClass) {
 3284  0
         innerClass.setModule(classNode.getModule());
 3285  0
         return innerClasses.add(innerClass);
 3286   
     }
 3287   
 
 3288  0
     protected ClassNode createClosureClass(ClosureExpression expression) {
 3289  0
         ClassNode owner = getOutermostClass();
 3290  0
         boolean parentIsInnerClass = owner instanceof InnerClassNode;
 3291  0
         String outerClassName = owner.getName();
 3292  0
         String name = outerClassName + "$"
 3293   
                 + context.getNextClosureInnerName(owner, classNode, methodNode); // br added a more infomative name
 3294  0
         boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass();
 3295  0
         if (staticMethodOrInStaticClass) {
 3296  0
             outerClassName = "java.lang.Class";
 3297   
         }
 3298  0
         Parameter[] parameters = expression.getParameters();
 3299  0
         if (parameters == null || parameters.length == 0) {
 3300   
             // lets create a default 'it' parameter
 3301  0
             parameters = new Parameter[] { new Parameter("it")};
 3302   
         }
 3303   
 
 3304  0
         Parameter[] localVariableParams = getClosureSharedVariables(expression);
 3305   
 
 3306  0
         InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, "groovy.lang.Closure"); // clsures are local inners and not public
 3307  0
         answer.setEnclosingMethod(this.methodNode);
 3308  0
         if (staticMethodOrInStaticClass) {
 3309  0
             answer.setStaticClass(true);
 3310   
         }
 3311  0
         if (isInScriptBody()) {
 3312  0
             answer.setScriptBody(true);
 3313   
         }
 3314  0
         MethodNode method =
 3315   
             answer.addMethod("doCall", ACC_PUBLIC, "java.lang.Object", parameters, expression.getCode());
 3316   
 
 3317  0
         method.setLineNumber(expression.getLineNumber());
 3318  0
         method.setColumnNumber(expression.getColumnNumber());
 3319   
 
 3320  0
         VariableScope varScope = expression.getVariableScope();
 3321  0
         if (varScope == null) {
 3322  0
             throw new RuntimeException(
 3323   
                 "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
 3324   
         }
 3325   
         else {
 3326  0
             method.setVariableScope(varScope);
 3327   
         }
 3328  0
         if (parameters.length > 1
 3329   
             || (parameters.length == 1
 3330   
                 && parameters[0].getType() != null
 3331   
                 && !parameters[0].getType().equals("java.lang.Object"))) {
 3332   
 
 3333   
             // lets add a typesafe call method
 3334  0
             answer.addMethod(
 3335   
                 "call",
 3336   
                 ACC_PUBLIC,
 3337   
                 "java.lang.Object",
 3338   
                 parameters,
 3339   
                 new ReturnStatement(
 3340   
                     new MethodCallExpression(
 3341   
                         VariableExpression.THIS_EXPRESSION,
 3342   
                         "doCall",
 3343   
                         new ArgumentListExpression(parameters))));
 3344   
         }
 3345   
 
 3346  0
         FieldNode ownerField = answer.addField("owner", ACC_PRIVATE, outerClassName, null);
 3347   
 
 3348   
         // lets make the constructor
 3349  0
         BlockStatement block = new BlockStatement();
 3350  0
         block.addStatement(
 3351   
             new ExpressionStatement(
 3352   
                 new MethodCallExpression(
 3353   
                     new VariableExpression("super"),
 3354   
                     "<init>",
 3355   
                     new VariableExpression("_outerInstance"))));
 3356  0
         block.addStatement(
 3357   
             new ExpressionStatement(
 3358   
                 new BinaryExpression(
 3359   
                     new FieldExpression(ownerField),
 3360   
                     Token.newSymbol(Types.EQUAL, -1, -1),
 3361   
                     new VariableExpression("_outerInstance"))));
 3362   
 
 3363   
         // lets assign all the parameter fields from the outer context
 3364  0
         for (int i = 0; i < localVariableParams.length; i++) {
 3365  0
             Parameter param = localVariableParams[i];
 3366  0
             String paramName = param.getName();
 3367  0
             boolean holder = mutableVars.contains(paramName);
 3368  0
             Expression initialValue = null;
 3369  0
             String type = param.getType();
 3370  0
             FieldNode paramField = null;
 3371  0
             if (holder) {
 3372  0
                 initialValue = new VariableExpression(paramName);
 3373  0
                 type = Reference.class.getName();
 3374  0
                 param.makeReference();
 3375  0
                 paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue);
 3376  0
                 paramField.setHolder(true);
 3377  0
                 String realType = param.getRealType();
 3378  0
                 String methodName = Verifier.capitalize(paramName);
 3379   
 
 3380   
                 // lets add a getter & setter
 3381  0
                 Expression fieldExp = new FieldExpression(paramField);
 3382  0
                 answer.addMethod(
 3383   
                     "get" + methodName,
 3384   
                     ACC_PUBLIC,
 3385   
                     realType,
 3386   
                     Parameter.EMPTY_ARRAY,
 3387   
                     new ReturnStatement(fieldExp));
 3388   
 
 3389   
                 /*
 3390   
                 answer.addMethod(
 3391   
                     "set" + methodName,
 3392   
                     ACC_PUBLIC,
 3393   
                     "void",
 3394   
                     new Parameter[] { new Parameter(realType, "__value") },
 3395   
                     new ExpressionStatement(
 3396   
                         new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("__value"))));
 3397   
                         */
 3398   
             }
 3399   
             else {
 3400  0
                 PropertyNode propertyNode = answer.addProperty(paramName, ACC_PUBLIC, type, initialValue, null, null);
 3401  0
                 paramField = propertyNode.getField();
 3402  0
                 block.addStatement(
 3403   
                     new ExpressionStatement(
 3404   
                         new BinaryExpression(
 3405   
                             new FieldExpression(paramField),
 3406   
                             Token.newSymbol(Types.EQUAL, -1, -1),
 3407   
                             new VariableExpression(paramName))));
 3408   
             }
 3409   
         }
 3410   
 
 3411  0
         Parameter[] params = new Parameter[2 + localVariableParams.length];
 3412  0
         params[0] = new Parameter(outerClassName, "_outerInstance");
 3413  0
         params[1] = new Parameter("java.lang.Object", "_delegate");
 3414  0
         System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
 3415   
 
 3416  0
         answer.addConstructor(ACC_PUBLIC, params, block);
 3417  0
         return answer;
 3418   
     }
 3419   
 
 3420  0
     protected ClassNode getOutermostClass() {
 3421  0
         if (outermostClass == null) {
 3422  0
             outermostClass = classNode;
 3423  0
             while (outermostClass instanceof InnerClassNode) {
 3424  0
                 outermostClass = outermostClass.getOuterClass();
 3425   
             }
 3426   
         }
 3427  0
         return outermostClass;
 3428   
     }
 3429   
 
 3430  0
     protected ClassNode createGStringClass(GStringExpression expression) {
 3431  0
         ClassNode owner = classNode;
 3432  0
         if (owner instanceof InnerClassNode) {
 3433  0
             owner = owner.getOuterClass();
 3434   
         }
 3435  0
         String outerClassName = owner.getName();
 3436  0
         String name = outerClassName + "$" + context.getNextInnerClassIdx();
 3437  0
         InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, GString.class.getName());
 3438  0
         answer.setEnclosingMethod(this.methodNode);
 3439  0
         FieldNode stringsField =
 3440   
             answer.addField(
 3441   
                 "strings",
 3442   
                 ACC_PRIVATE /*| ACC_STATIC*/,
 3443   
                 "java.lang.String[]",
 3444   
                 new ArrayExpression("java.lang.String", expression.getStrings()));
 3445  0
         answer.addMethod(
 3446   
             "getStrings",
 3447   
             ACC_PUBLIC,
 3448   
             "java.lang.String[]",
 3449   
             Parameter.EMPTY_ARRAY,
 3450   
             new ReturnStatement(new FieldExpression(stringsField)));
 3451   
         // lets make the constructor
 3452  0
         BlockStatement block = new BlockStatement();
 3453  0
         block.addStatement(
 3454   
             new ExpressionStatement(
 3455   
                 new MethodCallExpression(new VariableExpression("super"), "<init>", new VariableExpression("values"))));
 3456  0
         Parameter[] contructorParams = new Parameter[] { new Parameter("java.lang.Object[]", "values")};
 3457  0
         answer.addConstructor(ACC_PUBLIC, contructorParams, block);
 3458  0
         return answer;
 3459   
     }
 3460   
 
 3461  0
     protected void doConvertAndCast(String type) {
 3462  0
         if (!type.equals("java.lang.Object")) {
 3463   
             /** todo should probably support array coercions */
 3464  0
             if (!type.endsWith("[]") && isValidTypeForCast(type)) {
 3465  0
                 visitClassExpression(new ClassExpression(type));
 3466  0
                 asTypeMethod.call(cv);
 3467   
             }
 3468   
 
 3469  0
             helper.doCast(type);
 3470   
         }
 3471   
     }
 3472   
 
 3473  0
     protected void evaluateLogicalOrExpression(BinaryExpression expression) {
 3474  0
         visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
 3475  0
         Label l0 = new Label();
 3476  0
         Label l2 = new Label();
 3477  0
         cv.visitJumpInsn(IFEQ, l0);
 3478   
 
 3479  0
         cv.visitLabel(l2);
 3480   
 
 3481  0
         visitConstantExpression(ConstantExpression.TRUE);
 3482   
 
 3483  0
         Label l1 = new Label();
 3484  0
         cv.visitJumpInsn(GOTO, l1);
 3485  0
         cv.visitLabel(l0);
 3486   
 
 3487  0
         visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
 3488   
 
 3489  0
         cv.visitJumpInsn(IFNE, l2);
 3490   
 
 3491  0
         visitConstantExpression(ConstantExpression.FALSE);
 3492  0
         cv.visitLabel(l1);
 3493   
     }
 3494   
 
 3495   
     // todo: optimization: change to return primitive boolean. need to adjust the BinaryExpression and isComparisonExpression for
 3496   
     // consistancy.
 3497  0
     protected void evaluateLogicalAndExpression(BinaryExpression expression) {
 3498  0
         visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
 3499  0
         Label l0 = new Label();
 3500  0
         cv.visitJumpInsn(IFEQ, l0);
 3501   
 
 3502  0
         visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
 3503   
 
 3504  0
         cv.visitJumpInsn(IFEQ, l0);
 3505   
 
 3506  0
         visitConstantExpression(ConstantExpression.TRUE);
 3507   
 
 3508  0
         Label l1 = new Label();
 3509  0
         cv.visitJumpInsn(GOTO, l1);
 3510  0
         cv.visitLabel(l0);
 3511   
 
 3512  0
         visitConstantExpression(ConstantExpression.FALSE);
 3513   
 
 3514  0
         cv.visitLabel(l1);
 3515   
     }
 3516   
 
 3517  0
     protected void evaluateBinaryExpression(String method, BinaryExpression expression) {
 3518  0
         Expression leftExpression = expression.getLeftExpression();
 3519  0
         leftHandExpression = false;
 3520  0
         leftExpression.visit(this);
 3521  0
         cv.visitLdcInsn(method);
 3522  0
         leftHandExpression = false;
 3523  0
         new ArgumentListExpression(new Expression[] { expression.getRightExpression()}).visit(this);
 3524   
         // expression.getRightExpression().visit(this);
 3525  0
         invokeMethodMethod.call(cv);
 3526   
     }
 3527   
 
 3528  0
     protected void evaluateCompareTo(BinaryExpression expression) {
 3529  0
         Expression leftExpression = expression.getLeftExpression();
 3530  0
         leftHandExpression = false;
 3531  0
         leftExpression.visit(this);
 3532  0
         expression.getRightExpression().visit(this);
 3533  0
         compareToMethod.call(cv);
 3534   
     }
 3535   
 
 3536  0
     protected void evaluateBinaryExpressionWithAsignment(String method, BinaryExpression expression) {
 3537  0
         Expression leftExpression = expression.getLeftExpression();
 3538  0
         if (leftExpression instanceof BinaryExpression) {
 3539  0
             BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
 3540  0
             if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
 3541   
                 // lets replace this assignment to a subscript operator with a
 3542   
                 // method call
 3543   
                 // e.g. x[5] += 10
 3544   
                 // -> (x, [], 5), =, x[5] + 10
 3545   
                 // -> methodCall(x, "putAt", [5, methodCall(x[5], "plus", 10)])
 3546   
 
 3547  0
                 MethodCallExpression methodCall =
 3548   
                     new MethodCallExpression(
 3549   
                         expression.getLeftExpression(),
 3550   
                         method,
 3551   
                         new ArgumentListExpression(new Expression[] { expression.getRightExpression()}));
 3552   
 
 3553  0
                 Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression());
 3554   
 
 3555  0
                 visitMethodCallExpression(
 3556   
                     new MethodCallExpression(
 3557   
                         leftBinExpr.getLeftExpression(),
 3558   
                         "putAt",
 3559   
                         new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall })));
 3560   
                 //cv.visitInsn(POP);
 3561  0
                 return;
 3562   
             }
 3563   
         }
 3564   
 
 3565  0
         evaluateBinaryExpression(method, expression);
 3566   
 
 3567   
         // br to leave a copy of rvalue on the stack. see also isPopRequired()
 3568  0
         cv.visitInsn(DUP);
 3569   
 
 3570  0
         leftHandExpression = true;
 3571  0
         evaluateExpression(leftExpression);
 3572  0
         leftHandExpression = false;
 3573   
     }
 3574   
 
 3575  0
     private void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression bin) {
 3576  0
         if (ENABLE_EARLY_BINDING && true) {
 3577  0
             evalBinaryExp_EarlyBinding(compareMethod, bin);
 3578   
         }
 3579   
         else {
 3580  0
             evalBinaryExp_LateBinding(compareMethod, bin);
 3581   
         }
 3582   
     }
 3583   
 
 3584  0
     protected void evalBinaryExp_LateBinding(MethodCaller compareMethod, BinaryExpression expression) {
 3585  0
         Expression leftExp = expression.getLeftExpression();
 3586  0
         Expression rightExp = expression.getRightExpression();
 3587  0
         load(leftExp);
 3588  0
         load(rightExp);
 3589  0
         compareMethod.call(cv);
 3590   
     }
 3591   
 
 3592   
     /**
 3593   
      * note: leave the primitive boolean on staock for comparison expressions. All the result types need to match the
 3594   
      * utility methods in the InvokerHelper.
 3595   
      * @param compareMethod
 3596   
      * @param expression
 3597   
      */
 3598  0
     protected void evalBinaryExp_EarlyBinding(MethodCaller compareMethod, BinaryExpression expression) {
 3599  0
         Expression leftExp = expression.getLeftExpression();
 3600  0
         Expression rightExp = expression.getRightExpression();
 3601   
 
 3602  0
         expression.resolve(this);
 3603  0
         if (expression.isResolveFailed() || expression.getTypeClass() == null){
 3604  0
             evalBinaryExp_LateBinding(compareMethod, expression);
 3605  0
             return;
 3606   
         }
 3607   
         else {
 3608  0
             Class lclass = leftExp.getTypeClass();
 3609  0
             Class rclass = rightExp.getTypeClass();
 3610  0
             if (lclass == null || rclass == null) {
 3611  0
                 if ((lclass == null && rclass != null) || (lclass != null && rclass == null)) {
 3612   
                     // lets treat special cases: obj == null / obj != null . leave primitive boolean on the stack, which will be boxed by visitAndAutoBox()
 3613  0
                     if (leftExp == ConstantExpression.NULL && !rclass.isPrimitive() ||
 3614   
                             rightExp == ConstantExpression.NULL && !lclass.isPrimitive()) {
 3615  0
                         Expression exp = leftExp == ConstantExpression.NULL? rightExp : leftExp;
 3616  0
                         int type = expression.getOperation().getType();
 3617  0
                         switch (type) {
 3618   
                             case Types.COMPARE_EQUAL :
 3619  0
                                 load(exp);
 3620  0
                                 cv.visitInsn(ICONST_1);
 3621  0
                                 cv.visitInsn(SWAP);
 3622  0
                                 Label l1 = new Label();
 3623  0
                                 cv.visitJumpInsn(IFNULL, l1);
 3624  0
                                 cv.visitInsn(POP);
 3625  0
                                 cv.visitInsn(ICONST_0);
 3626  0
                                 cv.visitLabel(l1);
 3627  0
                                 return;
 3628   
                             case Types.COMPARE_NOT_EQUAL :
 3629  0
                                 load(exp);
 3630  0
                                 cv.visitInsn(ICONST_1);
 3631  0
                                 cv.visitInsn(SWAP);
 3632  0
                                 Label l2 = new Label();
 3633  0
                                 cv.visitJumpInsn(IFNONNULL, l2);
 3634  0
                                 cv.visitInsn(POP);
 3635  0
                                 cv.visitInsn(ICONST_0);
 3636  0
                                 cv.visitLabel(l2);
 3637  0
                                 return;
 3638   
                             default:
 3639  0
                                 evalBinaryExp_LateBinding(compareMethod, expression);
 3640  0
                                 return;
 3641   
                         }
 3642   
                     }
 3643   
                     else {
 3644  0
                         evalBinaryExp_LateBinding(compareMethod, expression);
 3645  0
                         return;
 3646   
                     }
 3647   
                 }
 3648   
                 else {
 3649  0
                     evalBinaryExp_LateBinding(compareMethod, expression);
 3650  0
                     return;
 3651   
                 }
 3652   
             }
 3653  0
             else if (lclass == String.class && rclass == String.class) {
 3654  0
                 int type = expression.getOperation().getType();
 3655  0
                 switch (type) {
 3656   
                     case Types.COMPARE_EQUAL : // ==
 3657  0
                         load(leftExp); cast(String.class);
 3658  0
                         load(rightExp); cast(String.class);
 3659  0
                         cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
 3660   
                         //helper.quickBoxIfNecessary(boolean.class);
 3661  0
                         return;
 3662   
                     case Types.COMPARE_NOT_EQUAL :
 3663  0
                         load(leftExp);cast(String.class);
 3664  0
                         load(rightExp); cast(String.class);
 3665  0
                         cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
 3666  0
                         cv.visitInsn(ICONST_1);
 3667  0
                         cv.visitInsn(IXOR);
 3668   
                         //helper.quickBoxIfNecessary(boolean.class);
 3669  0
                         return;
 3670   
                     case Types.COMPARE_TO :
 3671  0
                         load(leftExp);cast(String.class);
 3672  0
                         load(rightExp); cast(String.class);
 3673  0
                         cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I");
 3674  0
                         helper.quickBoxIfNecessary(int.class); // object type
 3675  0
                         return;
 3676   
                     case Types.COMPARE_GREATER_THAN :
 3677   
                     case Types.COMPARE_GREATER_THAN_EQUAL :
 3678   
                     case Types.COMPARE_LESS_THAN :
 3679   
                     case Types.COMPARE_LESS_THAN_EQUAL :
 3680   
                         {
 3681  0
                             int op;
 3682  0
                             switch (type) {
 3683   
                                 case Types.COMPARE_GREATER_THAN :
 3684  0
                                     op = IFLE;
 3685  0
                                     break;
 3686   
                                 case Types.COMPARE_GREATER_THAN_EQUAL :
 3687  0
                                     op = IFLT;
 3688  0
                                     break;
 3689   
                                 case Types.COMPARE_LESS_THAN :
 3690  0
                                     op = IFGE;
 3691  0
                                     break;
 3692   
                                 case Types.COMPARE_LESS_THAN_EQUAL :
 3693  0
                                     op = IFGT;
 3694  0
                                     break;
 3695   
                                 default:
 3696  0
                                     System.err.println("flow control error: should not be here. type: " + type);
 3697  0
                                     return;
 3698   
                             }
 3699  0
                             load(leftExp);cast(String.class);
 3700  0
                             load(rightExp); cast(String.class);
 3701  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I");
 3702   
 
 3703   
                             // set true/false on stack
 3704  0
                             Label l4 = new Label();
 3705  0
                             cv.visitJumpInsn(op, l4);
 3706   
                             // need to use primitive boolean //cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
 3707  0
                             cv.visitInsn(ICONST_1);  // true
 3708  0
                             Label l5 = new Label();
 3709  0
                             cv.visitJumpInsn(GOTO, l5);
 3710  0
                             cv.visitLabel(l4);
 3711  0
                             cv.visitInsn(ICONST_0); //cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
 3712  0
                             cv.visitLabel(l5);
 3713   
                         }
 3714  0
                         return;
 3715   
 
 3716   
                     default:
 3717  0
                         evalBinaryExp_LateBinding(compareMethod, expression);
 3718  0
                         return;
 3719   
                 }
 3720   
             }
 3721  0
             else if (Integer.class == lclass && Integer.class == rclass) {
 3722  0
                 int type = expression.getOperation().getType();
 3723  0
                 switch (type) {
 3724   
                     case Types.COMPARE_EQUAL : // ==
 3725  0
                         load(leftExp); cast(Integer.class);
 3726  0
                         load(rightExp);
 3727  0
                         cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z");
 3728   
                         //helper.quickBoxIfNecessary(boolean.class);
 3729  0
                         return;
 3730   
                     case Types.COMPARE_NOT_EQUAL :
 3731  0
                         load(leftExp); cast(Integer.class);
 3732  0
                         load(rightExp);
 3733  0
                         cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z");
 3734  0
                         cv.visitInsn(ICONST_1);
 3735  0
                         cv.visitInsn(IXOR);
 3736   
                         //helper.quickBoxIfNecessary(boolean.class);
 3737  0
                         return;
 3738   
                     case Types.COMPARE_TO :
 3739  0
                         load(leftExp); cast(Integer.class);
 3740  0
                         load(rightExp);
 3741  0
                         cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I");
 3742  0
                         helper.quickBoxIfNecessary(int.class);
 3743  0
                         return;
 3744   
                     case Types.COMPARE_GREATER_THAN :
 3745   
                     case Types.COMPARE_GREATER_THAN_EQUAL :
 3746   
                     case Types.COMPARE_LESS_THAN :
 3747   
                     case Types.COMPARE_LESS_THAN_EQUAL :
 3748   
                         {
 3749  0
                             int op;
 3750  0
                             switch (type) {
 3751   
                                 case Types.COMPARE_GREATER_THAN :
 3752  0
                                     op = IFLE;
 3753  0
                                     break;
 3754   
                                 case Types.COMPARE_GREATER_THAN_EQUAL :
 3755  0
                                     op = IFLT;
 3756  0
                                     break;
 3757   
                                 case Types.COMPARE_LESS_THAN :
 3758  0
                                     op = IFGE;
 3759  0
                                     break;
 3760   
                                 case Types.COMPARE_LESS_THAN_EQUAL :
 3761  0
                                     op = IFGT;
 3762  0
                                     break;
 3763   
                                 default:
 3764  0
                                     System.err.println("flow control error: should not be here. type: " + type);
 3765  0
                                     return;
 3766   
                             }
 3767  0
                             load(leftExp); cast(Integer.class);
 3768  0
                             load(rightExp);
 3769  0
                             cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I");
 3770   
 
 3771  0
                             Label l4 = new Label();
 3772  0
                             cv.visitJumpInsn(op, l4);
 3773  0
                             cv.visitInsn(ICONST_1); //cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
 3774  0
                             Label l5 = new Label();
 3775  0
                             cv.visitJumpInsn(GOTO, l5);
 3776  0
                             cv.visitLabel(l4);
 3777  0
                             cv.visitInsn(ICONST_0);//cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
 3778  0
                             cv.visitLabel(l5);
 3779   
                         }
 3780  0
                         return;
 3781   
 
 3782   
                     default:
 3783  0
                         evalBinaryExp_LateBinding(compareMethod, expression);
 3784  0
                         return;
 3785   
                 }
 3786   
             }
 3787   
             else {
 3788  0
                 evalBinaryExp_LateBinding(compareMethod, expression);
 3789  0
                 return;
 3790   
             }
 3791   
         }
 3792   
     }
 3793   
 
 3794  0
     private void cast(Class aClass) {
 3795  0
         if (!aClass.isPrimitive() && aClass != Object.class) {
 3796  0
             cv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(aClass.getName()));
 3797   
         }
 3798   
     }
 3799   
 
 3800  0
     protected void evaluateEqual(BinaryExpression expression) {
 3801  0
         if (ENABLE_EARLY_BINDING) {
 3802  0
             expression.resolve(this);
 3803  0
             if (expression.isTypeResolved()) {
 3804  0
                 if (expression.getRightExpression().getTypeClass() == Void.TYPE) {
 3805  0
                     throwException("void value appeared on right hand side of assignment. ");
 3806   
                 }
 3807   
             }
 3808   
         }
 3809   
 
 3810  0
         Expression leftExpression = expression.getLeftExpression();
 3811  0
         if (leftExpression instanceof BinaryExpression) {
 3812  0
             BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
 3813  0
             if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
 3814   
                 // lets replace this assignment to a subscript operator with a
 3815   
                 // method call
 3816   
                 // e.g. x[5] = 10
 3817   
                 // -> (x, [], 5), =, 10
 3818   
                 // -> methodCall(x, "putAt", [5, 10])
 3819  0
                 do {
 3820  0
                     if (true && ENABLE_EARLY_BINDING){
 3821  0
                         Class typeclass = leftBinExpr.getLeftExpression().getTypeClass();
 3822  0
                         if (typeclass == null) {
 3823  0
                             break;
 3824   
                         }
 3825   
 
 3826  0
                         if (typeclass == Map.class) {// call aMap.put()
 3827  0
                             load(expression.getRightExpression());
 3828   
                             // let's leave a copy of the value on the stack.
 3829  0
                             cv.visitInsn(DUP);
 3830  0
                             final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType());
 3831   
                             // VariableExpression tempVarExp = new VariableExpression(rightTemp.getName(), expression.getRightExpression().getType());
 3832  0
                             final Class rclass = expression.getRightExpression().getTypeClass();
 3833  0
                             BytecodeExpression loadTempByteCode = new BytecodeExpression() {
 3834  0
                                 public void visit(GroovyCodeVisitor visitor) {
 3835  0
                                     cv.visitVarInsn(ALOAD, rightTemp.getIndex());
 3836   
                                 }
 3837  0
                                 protected void resolveType(AsmClassGenerator2 resolver) {
 3838  0
                                     setTypeClass(rclass);
 3839   
                                 }
 3840   
                             };
 3841   
 
 3842  0
                             visitMethodCallExpression(
 3843   
                                     new MethodCallExpression(
 3844   
                                             leftBinExpr.getLeftExpression(),
 3845   
                                             "put",
 3846   
                                             new ArgumentListExpression(
 3847   
                                                     new Expression[] {
 3848   
                                                         leftBinExpr.getRightExpression(),
 3849   
                                                         loadTempByteCode})));
 3850  0
                             cv.visitInsn(POP); // pop the put method return
 3851  0
                             removeVar(rightTemp);
 3852  0
                             return;
 3853   
                         }
 3854  0
                         else if (typeclass == List.class){
 3855   
                             // call DefaultGroovyMethods.putAt()V
 3856   
                             // DefaultGroovyMethods.putAt(x, 5, "c"); this is faster thangoing thru metaclass
 3857   
                             // this method does not return any value. so indicate this fact in the expression
 3858   
 
 3859  0
                             load(expression.getRightExpression());
 3860   
                             // let's leave a copy of the value on the stack. this is really lazy.
 3861  0
                             cv.visitInsn(DUP);
 3862  0
                             final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType());
 3863   
                             // VariableExpression tempVarExp = new VariableExpression(rightTemp.getName(), expression.getRightExpression().getType());
 3864  0
                             final Class rclass = expression.getRightExpression().getTypeClass();
 3865  0
                             BytecodeExpression loadTempBytes = new BytecodeExpression() {
 3866  0
                                 public void visit(GroovyCodeVisitor visitor) {
 3867  0
                                     cv.visitVarInsn(ALOAD, rightTemp.getIndex());
 3868   
                                 }
 3869  0
                                 protected void resolveType(AsmClassGenerator2 resolver) {
 3870  0
                                     setTypeClass(rclass);
 3871   
                                 }
 3872   
                             };
 3873   
 
 3874  0
                             visitMethodCallExpression(
 3875   
                                 new MethodCallExpression(
 3876   
                                     new ClassExpression(DefaultGroovyMethods.class),
 3877   
                                     "putAt",
 3878   
                                     new ArgumentListExpression(
 3879   
                                         new Expression[] {
 3880   
                                             leftBinExpr.getLeftExpression(),
 3881   
                                             leftBinExpr.getRightExpression(),
 3882   
                                             loadTempBytes })));
 3883  0
                             removeVar(rightTemp);
 3884  0
                             return;
 3885   
 
 3886   
                         }
 3887   
                         else {
 3888  0
                             break;
 3889   
                         }
 3890   
                     }
 3891   
                 } while (false);
 3892   
 
 3893  0
                 visitMethodCallExpression(
 3894   
                     new MethodCallExpression(
 3895   
                         leftBinExpr.getLeftExpression(),
 3896   
                         "putAt",
 3897   
                         new ArgumentListExpression(
 3898   
                             new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()})));
 3899   
                  // cv.visitInsn(POP); //this is realted to isPopRequired()
 3900  0
                 return;
 3901   
             }
 3902   
         }
 3903   
 
 3904   
         // lets evaluate the RHS then hopefully the LHS will be a field
 3905  0
         leftHandExpression = false;
 3906  0
         Expression rightExpression = expression.getRightExpression();
 3907   
 
 3908  0
         String type = getLHSType(leftExpression);
 3909  0
         if (type != null) {
 3910   
             //System.out.println("### expression: " + leftExpression);
 3911   
             //System.out.println("### type: " + type);
 3912   
 
 3913   
             // lets not cast for primitive types as we handle these in field setting etc
 3914  0
             if (BytecodeHelper.isPrimitiveType(type)) {
 3915  0
                 rightExpression.visit(this);
 3916   
             }
 3917   
             else {
 3918  0
                 if (ENABLE_EARLY_BINDING) {
 3919  0
                     if (leftExpression.isDynamic()) { // br the previous if() probably should check this too!
 3920  0
                         visitAndAutoboxBoolean(rightExpression);
 3921   
                     }
 3922   
                     else {
 3923  0
                         if (type.equals(rightExpression.getType())) {
 3924  0
                             visitAndAutoboxBoolean(rightExpression);
 3925   
                         }
 3926   
                         else {
 3927  0
                             if (rightExpression instanceof ConstantExpression &&
 3928   
                                     ((ConstantExpression)rightExpression).getValue() == null) {
 3929  0
                                 cv.visitInsn(ACONST_NULL);
 3930   
                             }
 3931   
                             else {
 3932  0
                                 visitCastExpression(new CastExpression(type, rightExpression));
 3933   
                             }
 3934   
                         }
 3935   
                     }
 3936   
                 }
 3937  0
                 else if (!type.equals("java.lang.Object")){
 3938  0
                     visitCastExpression(new CastExpression(type, rightExpression));
 3939   
                 }
 3940   
                 else {
 3941  0
                     visitAndAutoboxBoolean(rightExpression);
 3942   
                 }
 3943   
             }
 3944   
         }
 3945   
         else {
 3946  0
             visitAndAutoboxBoolean(rightExpression);
 3947   
         }
 3948   
 
 3949   
 
 3950   
         // br: attempt to pass type info from right to left for assignment
 3951  0
         if (ENABLE_EARLY_BINDING) {
 3952  0
             Class rc = rightExpression.getTypeClass();
 3953  0
             if (rc != null && rc.isArray()) {
 3954  0
                 Class elemType = rc.getComponentType();
 3955  0
                 if (elemType.isPrimitive()) {
 3956  0
                     visitClassExpression(new ClassExpression(elemType));
 3957  0
                     convertPrimitiveArray.call(cv);
 3958  0
                     cast(loadClass(BytecodeHelper.getObjectArrayTypeForPrimitiveArray(elemType.getName() + "[]")));
 3959   
                 }
 3960   
             }
 3961   
 
 3962   
 
 3963  0
             if (leftExpression.isDynamic() ) {
 3964   
                 // propagate the type from right to left if the left is dynamic
 3965  0
                 if (!(leftExpression instanceof FieldExpression ) && !(leftExpression instanceof PropertyExpression))
 3966  0
                     copyTypeClass(leftExpression, rightExpression);
 3967   
             }
 3968   
             else {
 3969  0
                 Class lc = leftExpression.getTypeClass();
 3970   
 //                Class rc = rightExpression.getTypeClass();
 3971  0
                 if (lc != null && rc != null && !lc.isAssignableFrom(rc) && !lc.isPrimitive()) {
 3972   
                     // let's use extended conversion logic in the invoker class.
 3973  0
                     if (!lc.isArray()) {
 3974  0
                         visitClassExpression(new ClassExpression(lc));
 3975  0
                         asTypeMethod.call(cv);
 3976  0
                         helper.doCast(lc);
 3977   
                     }
 3978   
                     else {
 3979   
                         // may not need this, since variable type converts primitive array to object array automatically
 3980  0
                         Class elemType = lc.getComponentType();
 3981  0
                         if (elemType.isPrimitive()) {
 3982   
                             // let's allow type copy for primitive array, meaning [i can be changed to [Integer
 3983  0
                             copyTypeClass(leftExpression, rightExpression);
 3984   
                         }
 3985   
                     }
 3986   
                 }
 3987   
             }
 3988   
         }
 3989  0
         cv.visitInsn(DUP);  // to leave a copy of the rightexpression value on the stack after the assignment.
 3990  0
         leftHandExpression = true;
 3991  0
         leftExpression.visit(this);
 3992  0
         leftHandExpression = false;
 3993   
     }
 3994   
 
 3995  0
     private void copyTypeClass(Expression leftExpression, Expression rightExpression) {
 3996   
         // copy type class from the right to the left, boxing numbers & treat ClassExpression specially
 3997  0
         Class rclass = rightExpression.getTypeClass();
 3998  0
         if (rightExpression instanceof ClassExpression) {
 3999  0
             leftExpression.setTypeClass(Class.class);
 4000   
         }
 4001   
         else {
 4002  0
             rclass = BytecodeHelper.boxOnPrimitive(rclass);
 4003  0
             leftExpression.setTypeClass(rclass);
 4004   
         }
 4005   
     }
 4006   
 
 4007  0
     private boolean canBeAssignedFrom(String ltype, String rtype) {
 4008  0
         if (rtype == null) {
 4009  0
             return false;
 4010   
         }
 4011  0
         else if (ltype == null || ltype.equals("java.lang.Object")) {
 4012  0
             return true;
 4013   
         } else {
 4014  0
             return false;
 4015   
         }
 4016   
     }
 4017   
 
 4018  0
     private boolean canBeAssignedFrom(Expression l, Expression r) {
 4019  0
             if (r.getTypeClass() == null) {
 4020  0
                 return false;
 4021   
             }
 4022  0
             else if (l.isDynamic()){
 4023  0
                 return true;
 4024   
             } else {
 4025  0
                 return false;
 4026   
             }
 4027   
         }
 4028  0
     private boolean canBeAssignedFrom(Class l, Class r) {
 4029  0
             if (r == null) {
 4030  0
                 return false;
 4031   
             }
 4032  0
             else if (l == null || l == Object.class){
 4033  0
                 return true;
 4034   
             } else {
 4035  0
                 return false;
 4036   
             }
 4037   
         }
 4038   
 
 4039   
     /**
 4040   
      * Deduces the type name required for some casting
 4041   
      *
 4042   
      * @return the type of the given (LHS) expression or null if it is java.lang.Object or it cannot be deduced
 4043   
      */
 4044  0
     protected String getLHSType(Expression leftExpression) {
 4045  0
         do {
 4046   
 // commented out. not quiteworking yet. would complain something like:
 4047   
 //java.lang.ClassFormatError: Foo$1 (Illegal Field name "class$[Ljava$lang$String;")
 4048   
 //
 4049   
 //            if (ENABLE_EARLY_BINDING) {
 4050   
 //                String type = leftExpression.getType();
 4051   
 //                if (type == null)
 4052   
 //                    break;
 4053   
 //                return isValidTypeForCast(type) ? type : null;
 4054   
 //            }
 4055   
         } while (false);
 4056   
 
 4057  0
         if (leftExpression instanceof VariableExpression) {
 4058  0
             VariableExpression varExp = (VariableExpression) leftExpression;
 4059  0
             String type = varExp.getType();
 4060  0
             if (isValidTypeForCast(type)) {
 4061  0
                 return type;
 4062   
             }
 4063  0
             String variableName = varExp.getVariable();
 4064  0
             Variable variable = (Variable) variableStack.get(variableName);
 4065  0
             if (variable != null) {
 4066  0
                 if (variable.isHolder() || variable.isProperty()) {
 4067  0
                     return null;
 4068   
                 }
 4069  0
                 type = variable.getTypeName();
 4070  0
                 if (isValidTypeForCast(type)) {
 4071  0
                     return type;
 4072   
                 }
 4073   
             }
 4074   
             else {
 4075  0
                 FieldNode field = classNode.getField(variableName);
 4076  0
                 if (field == null) {
 4077  0
                     field = classNode.getOuterField(variableName);
 4078   
                 }
 4079  0
                 if (field != null) {
 4080  0
                     type = field.getType();
 4081  0
                     if (!field.isHolder() && isValidTypeForCast(type)) {
 4082  0
                         return type;
 4083   
                     }
 4084   
                 }
 4085   
             }
 4086   
         }
 4087  0
         return null;
 4088   
     }
 4089   
 
 4090  0
     protected boolean isValidTypeForCast(String type) {
 4091  0
         return type != null && !type.equals("java.lang.Object") && !type.equals("groovy.lang.Reference") && !BytecodeHelper.isPrimitiveType(type);
 4092   
     }
 4093   
 
 4094  0
     protected void visitAndAutoboxBoolean(Expression expression) {
 4095  0
         expression.visit(this);
 4096   
 
 4097  0
         if (isComparisonExpression(expression)) {
 4098  0
             helper.boxBoolean(); // convert boolean to Boolean
 4099   
         }
 4100   
     }
 4101   
 
 4102  0
     protected void evaluatePrefixMethod(String method, Expression expression) {
 4103  0
         if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) {
 4104  0
             cv.visitVarInsn(ALOAD, 0);
 4105   
         }
 4106  0
         expression.visit(this);
 4107  0
         cv.visitLdcInsn(method);
 4108  0
         invokeNoArgumentsMethod.call(cv);
 4109   
 
 4110  0
         leftHandExpression = true;
 4111  0
         expression.visit(this);
 4112  0
         leftHandExpression = false;
 4113  0
         expression.visit(this);
 4114   
     }
 4115   
 
 4116  0
     protected void evaluatePostfixMethod(String method, Expression expression) {
 4117  0
         leftHandExpression = false;
 4118  0
         expression.visit(this);
 4119   
 
 4120  0
         Variable tv = visitASTOREInTemp("postfix_" + method);
 4121  0
         int tempIdx  = tv.getIndex();
 4122  0
         cv.visitVarInsn(ALOAD, tempIdx);
 4123   
 
 4124  0
         cv.visitLdcInsn(method);
 4125  0
         invokeNoArgumentsMethod.call(cv);
 4126   
 
 4127  0
         store(expression);
 4128   
 
 4129  0
         cv.visitVarInsn(ALOAD, tempIdx);
 4130  0
         removeVar(tv);
 4131   
     }
 4132   
 
 4133  0
     protected boolean isHolderVariable(Expression expression) {
 4134  0
         if (expression instanceof FieldExpression) {
 4135  0
             FieldExpression fieldExp = (FieldExpression) expression;
 4136  0
             return fieldExp.getField().isHolder();
 4137   
         }
 4138  0
         if (expression instanceof VariableExpression) {
 4139  0
             VariableExpression varExp = (VariableExpression) expression;
 4140  0
             Variable variable = (Variable) variableStack.get(varExp.getVariable());
 4141  0
             if (variable != null) {
 4142  0
                 return variable.isHolder();
 4143   
             }
 4144  0
             FieldNode field = classNode.getField(varExp.getVariable());
 4145  0
             if (field != null) {
 4146  0
                 return field.isHolder();
 4147   
             }
 4148   
         }
 4149  0
         return false;
 4150   
     }
 4151   
 
 4152  0
     protected void evaluateInstanceof(BinaryExpression expression) {
 4153  0
         expression.getLeftExpression().visit(this);
 4154  0
         Expression rightExp = expression.getRightExpression();
 4155  0
         String className = null;
 4156  0
         if (rightExp instanceof ClassExpression) {
 4157  0
             ClassExpression classExp = (ClassExpression) rightExp;
 4158  0
             className = classExp.getType();
 4159   
         }
 4160   
         else {
 4161  0
             throw new RuntimeException(
 4162   
                 "Right hand side of the instanceof keyworld must be a class name, not: " + rightExp);
 4163   
         }
 4164  0
         className = checkValidType(className, expression, "Must be a valid type name for an instanceof statement");
 4165  0
         String classInternalName = BytecodeHelper.getClassInternalName(className);
 4166  0
         cv.visitTypeInsn(INSTANCEOF, classInternalName);
 4167   
     }
 4168   
 
 4169   
     /**
 4170   
      * @return true if the given argument expression requires the stack, in
 4171   
      *         which case the arguments are evaluated first, stored in the
 4172   
      *         variable stack and then reloaded to make a method call
 4173   
      */
 4174  0
     protected boolean argumentsUseStack(Expression arguments) {
 4175  0
         return arguments instanceof TupleExpression || arguments instanceof ClosureExpression;
 4176   
     }
 4177   
 
 4178   
     /**
 4179   
      * @return true if the given expression represents a non-static field
 4180   
      */
 4181  0
     protected boolean isNonStaticField(Expression expression) {
 4182  0
         FieldNode field = null;
 4183  0
         if (expression instanceof VariableExpression) {
 4184  0
             VariableExpression varExp = (VariableExpression) expression;
 4185  0
             field = classNode.getField(varExp.getVariable());
 4186   
         }
 4187  0
         else if (expression instanceof FieldExpression) {
 4188  0
             FieldExpression fieldExp = (FieldExpression) expression;
 4189  0
             field = classNode.getField(fieldExp.getFieldName());
 4190   
         }
 4191  0
         else if (expression instanceof PropertyExpression) {
 4192  0
             PropertyExpression fieldExp = (PropertyExpression) expression;
 4193  0
             field = classNode.getField(fieldExp.getProperty());
 4194   
         }
 4195  0
         if (field != null) {
 4196  0
             return !field.isStatic();
 4197   
         }
 4198  0
         return false;
 4199   
     }
 4200   
 
 4201  0
     protected boolean isThisExpression(Expression expression) {
 4202  0
         if (expression instanceof VariableExpression) {
 4203  0
             VariableExpression varExp = (VariableExpression) expression;
 4204  0
             return varExp.getVariable().equals("this");
 4205   
         }
 4206  0
         return false;
 4207   
     }
 4208   
 
 4209   
     /**
 4210   
      * For assignment expressions, return a safe expression for the LHS we can use
 4211   
      * to return the value
 4212   
      */
 4213  0
     protected Expression createReturnLHSExpression(Expression expression) {
 4214  0
         if (expression instanceof BinaryExpression) {
 4215  0
             BinaryExpression binExpr = (BinaryExpression) expression;
 4216  0
             if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) {
 4217  0
                 return createReusableExpression(binExpr.getLeftExpression());
 4218   
             }
 4219   
         }
 4220  0
         return null;
 4221   
     }
 4222   
 
 4223  0
     protected Expression createReusableExpression(Expression expression) {
 4224  0
         ExpressionTransformer transformer = new ExpressionTransformer() {
 4225  0
             public Expression transform(Expression expression) {
 4226  0
                 if (expression instanceof PostfixExpression) {
 4227  0
                     PostfixExpression postfixExp = (PostfixExpression) expression;
 4228  0
                     return postfixExp.getExpression();
 4229   
                 }
 4230  0
                 else if (expression instanceof PrefixExpression) {
 4231  0
                     PrefixExpression prefixExp = (PrefixExpression) expression;
 4232  0
                     return prefixExp.getExpression();
 4233   
                 }
 4234  0
                 return expression;
 4235   
             }
 4236   
         };
 4237   
 
 4238   
         // could just be a postfix / prefix expression or nested inside some other expression
 4239  0
         return transformer.transform(expression.transformExpression(transformer));
 4240   
     }
 4241   
 
 4242  0
     protected boolean isComparisonExpression(Expression expression) {
 4243  0
         if (expression instanceof BinaryExpression) {
 4244  0
             BinaryExpression binExpr = (BinaryExpression) expression;
 4245  0
             switch (binExpr.getOperation().getType()) {
 4246   
                 case Types.COMPARE_EQUAL :
 4247   
                 case Types.MATCH_REGEX :
 4248   
                 case Types.COMPARE_GREATER_THAN :
 4249   
                 case Types.COMPARE_GREATER_THAN_EQUAL :
 4250   
                 case Types.COMPARE_LESS_THAN :
 4251   
                 case Types.COMPARE_LESS_THAN_EQUAL :
 4252   
                 case Types.COMPARE_IDENTICAL :
 4253   
                 case Types.COMPARE_NOT_EQUAL :
 4254   
                 case Types.KEYWORD_INSTANCEOF :
 4255  0
                     return true;
 4256   
             }
 4257   
         }
 4258  0
         else if (expression instanceof BooleanExpression) {
 4259  0
             return true;
 4260   
         }
 4261  0
         return false;
 4262   
     }
 4263   
 
 4264  0
     protected void onLineNumber(ASTNode statement, String message) {
 4265  0
         int line = statement.getLineNumber();
 4266  0
         int col = statement.getColumnNumber();
 4267  0
         this.currentASTNode = statement;
 4268   
 
 4269  0
         if (line >=0) {
 4270  0
             lineNumber = line;
 4271  0
             columnNumber = col;
 4272   
         }
 4273  0
         if (CREATE_DEBUG_INFO && line >= 0 && cv != null) {
 4274  0
             Label l = new Label();
 4275  0
             cv.visitLabel(l);
 4276  0
             cv.visitLineNumber(line, l);
 4277  0
             if (ASM_DEBUG) {
 4278  0
                 helper.mark(message + "[" + statement.getLineNumber() + ":" + statement.getColumnNumber() + "]");
 4279   
             }
 4280   
         }
 4281   
     }
 4282   
 
 4283  0
     protected VariableScope getVariableScope() {
 4284  0
         if (variableScope == null) {
 4285  0
             if (methodNode != null) {
 4286   
                 // if we're a closure method we'll have our variable scope already created
 4287  0
                 variableScope = methodNode.getVariableScope();
 4288  0
                 if (variableScope == null) {
 4289  0
                     variableScope = new VariableScope();
 4290  0
                     methodNode.setVariableScope(variableScope);
 4291  0
                     VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
 4292  0
                     visitor.setParameters(methodNode.getParameters());
 4293  0
                     Statement code = methodNode.getCode();
 4294  0
                     if (code != null) {
 4295  0
                         code.visit(visitor);
 4296   
                     }
 4297   
                 }
 4298  0
                 addFieldsToVisitor(variableScope);
 4299   
             }
 4300  0
             else if (constructorNode != null) {
 4301  0
                 variableScope = new VariableScope();
 4302  0
                 constructorNode.setVariableScope(variableScope);
 4303  0
                 VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
 4304  0
                 visitor.setParameters(constructorNode.getParameters());
 4305  0
                 Statement code = constructorNode.getCode();
 4306  0
                 if (code != null) {
 4307  0
                     code.visit(visitor);
 4308   
                 }
 4309  0
                 addFieldsToVisitor(variableScope);
 4310   
             }
 4311   
             else {
 4312  0
                 throw new RuntimeException("Can't create a variable scope outside of a method or constructor");
 4313   
             }
 4314   
         }
 4315  0
         return variableScope;
 4316   
     }
 4317   
 
 4318   
     /**
 4319   
      * @return a list of parameters for each local variable which needs to be
 4320   
      *         passed into a closure
 4321   
      */
 4322  0
     protected Parameter[] getClosureSharedVariables(ClosureExpression expression) {
 4323  0
         List vars = new ArrayList();
 4324   
 
 4325   
         //
 4326   
         // First up, get the scopes for outside and inside the closure.
 4327   
         // The inner scope must cover all nested closures, as well, as
 4328   
         // everything that will be needed must be imported.
 4329   
 
 4330  0
         VariableScope outerScope = getVariableScope().createRecursiveParentScope();
 4331  0
         VariableScope innerScope = expression.getVariableScope();
 4332  0
         if (innerScope == null) {
 4333  0
             System.out.println(
 4334   
                 "No variable scope for: " + expression + " method: " + methodNode + " constructor: " + constructorNode);
 4335  0
             innerScope = new VariableScope(getVariableScope());
 4336   
         }
 4337   
         else {
 4338  0
             innerScope = innerScope.createRecursiveChildScope();
 4339   
         }
 4340   
 
 4341   
 
 4342   
         //
 4343   
         // DeclaredVariables include any name that was assigned to within
 4344   
         // the scope.  ReferencedVariables include any name that was read
 4345   
         // from within the scope.  We get the sets from each and must piece
 4346   
         // together the stack variable import list for the closure.  Note
 4347   
         // that we don't worry about field variables here, as we don't have
 4348   
         // to do anything special with them.  Stack variables, on the other
 4349   
         // hand, have to be wrapped up in References for use.
 4350   
 
 4351  0
         Set outerDecls = outerScope.getDeclaredVariables();
 4352  0
         Set outerRefs  = outerScope.getReferencedVariables();
 4353  0
         Set innerDecls = innerScope.getDeclaredVariables();
 4354  0
         Set innerRefs  = innerScope.getReferencedVariables();
 4355   
 
 4356   
 
 4357   
         //
 4358   
         // So, we care about any name referenced in the closure UNLESS:
 4359   
         //   1) it's not declared in the outer context;
 4360   
         //   2) it's a parameter;
 4361   
         //   3) it's a field in the context class that isn't overridden
 4362   
         //      by a stack variable in the outer context.
 4363   
         //
 4364   
         // BUG: We don't actually have the necessary information to do
 4365   
         //      this right!  The outer declarations don't distinguish
 4366   
         //      between assignments and variable declarations.  Therefore
 4367   
         //      we can't tell when field variables have been overridden
 4368   
         //      by stack variables in the outer context.  This must
 4369   
         //      be fixed!
 4370   
 
 4371  0
         Set varSet = new HashSet();
 4372  0
         for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
 4373  0
             String var = (String) iter.next();
 4374   
             // lets not pass in fields from the most-outer class, but pass in values from an outer closure
 4375  0
             if (outerDecls.contains(var) && (isNotFieldOfOutermostClass(var))) {
 4376  0
                 String type = getVariableType(var);
 4377  0
                 vars.add(new Parameter(type, var));
 4378  0
                 varSet.add(var);
 4379   
             }
 4380   
         }
 4381  0
         for (Iterator iter = outerRefs.iterator(); iter.hasNext();) {
 4382  0
             String var = (String) iter.next();
 4383   
             // lets not pass in fields from the most-outer class, but pass in values from an outer closure
 4384  0
             if (innerDecls.contains(var) && (isNotFieldOfOutermostClass(var)) && !varSet.contains(var)) {
 4385  0
                 String type = getVariableType(var);
 4386  0
                 vars.add(new Parameter(type, var));
 4387   
             }
 4388   
         }
 4389   
 
 4390   
 
 4391  0
         Parameter[] answer = new Parameter[vars.size()];
 4392  0
         vars.toArray(answer);
 4393  0
         return answer;
 4394   
     }
 4395   
 
 4396  0
     protected boolean isNotFieldOfOutermostClass(String var) {
 4397   
         //return classNode.getField(var) == null || isInnerClass();
 4398  0
         return getOutermostClass().getField(var) == null;
 4399   
     }
 4400   
 
 4401  0
     protected void findMutableVariables() {
 4402   
         /*
 4403   
         VariableScopeCodeVisitor outerVisitor = new VariableScopeCodeVisitor(true);
 4404   
         node.getCode().visit(outerVisitor);
 4405   
 
 4406   
         addFieldsToVisitor(outerVisitor);
 4407   
 
 4408   
         VariableScopeCodeVisitor innerVisitor = outerVisitor.getClosureVisitor();
 4409   
         */
 4410  0
         VariableScope outerScope = getVariableScope();
 4411   
 
 4412   
         // lets create a scope concatenating all the closure expressions
 4413  0
         VariableScope innerScope = outerScope.createCompositeChildScope();
 4414   
 
 4415  0
         Set outerDecls = outerScope.getDeclaredVariables();
 4416  0
         Set outerRefs = outerScope.getReferencedVariables();
 4417  0
         Set innerDecls = innerScope.getDeclaredVariables();
 4418  0
         Set innerRefs = innerScope.getReferencedVariables();
 4419   
 
 4420  0
         mutableVars.clear();
 4421   
 
 4422  0
         for (Iterator iter = innerDecls.iterator(); iter.hasNext();) {
 4423  0
             String var = (String) iter.next();
 4424  0
             if ((outerDecls.contains(var) || outerRefs.contains(var)) && classNode.getField(var) == null) {
 4425  0
                 mutableVars.add(var);
 4426   
             }
 4427   
         }
 4428   
 
 4429   
         // we may call the closure twice and modify the variable in the outer scope
 4430   
         // so for now lets assume that all variables are mutable
 4431  0
         for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
 4432  0
             String var = (String) iter.next();
 4433  0
             if (outerDecls.contains(var) && classNode.getField(var) == null) {
 4434  0
                 mutableVars.add(var);
 4435   
             }
 4436   
         }
 4437   
 
 4438   
         //                System.out.println();
 4439   
         //                System.out.println("method: " + methodNode + " classNode: " + classNode);
 4440   
         //                System.out.println("child scopes: " + outerScope.getChildren());
 4441   
         //                System.out.println("outerDecls: " + outerDecls);
 4442   
         //                System.out.println("outerRefs: " + outerRefs);
 4443   
         //                System.out.println("innerDecls: " + innerDecls);
 4444   
         //                System.out.println("innerRefs: " + innerRefs);
 4445   
     }
 4446   
 
 4447  0
     protected void addFieldsToVisitor(VariableScope scope) {
 4448  0
         for (Iterator iter = classNode.getFields().iterator(); iter.hasNext();) {
 4449  0
             FieldNode field = (FieldNode) iter.next();
 4450  0
             String name = field.getName();
 4451   
 
 4452  0
             scope.getDeclaredVariables().add(name);
 4453  0
             scope.getReferencedVariables().add(name);
 4454   
         }
 4455   
     }
 4456   
 
 4457  0
     private boolean isInnerClass() {
 4458  0
         return classNode instanceof InnerClassNode;
 4459   
     }
 4460   
 
 4461  0
     protected String getVariableType(String name) {
 4462  0
         Variable variable = (Variable) variableStack.get(name);
 4463  0
         if (variable != null) {
 4464  0
             return variable.getTypeName();
 4465   
         }
 4466  0
         return null;
 4467   
     }
 4468   
 
 4469  0
     protected void resetVariableStack(Parameter[] parameters) {
 4470  0
         lastVariableIndex = -1;
 4471  0
         variableStack.clear();
 4472   
 
 4473  0
         scope = new BlockScope(null);
 4474   
         //pushBlockScope();
 4475   
 
 4476   
         // lets push this onto the stack
 4477  0
         definingParameters = true;
 4478  0
         if (!isStaticMethod()) {
 4479  0
             defineVariable("this", classNode.getName()).getIndex();
 4480   
         } // now lets create indices for the parameteres
 4481  0
         for (int i = 0; i < parameters.length; i++) {
 4482  0
             Parameter parameter = parameters[i];
 4483  0
             String type = parameter.getType();
 4484  0
             Variable v = defineVariable(parameter.getName(), type);
 4485  0
             int idx = v.getIndex();
 4486  0
             if (BytecodeHelper.isPrimitiveType(type)) {
 4487  0
                 helper.load(type, idx);
 4488  0
                 helper.box(type);
 4489  0
                 cv.visitVarInsn(ASTORE, idx);
 4490   
             }
 4491   
         }
 4492  0
         definingParameters = false;
 4493   
     }
 4494   
 
 4495  0
     protected void popScope() {
 4496  0
         int lastID = scope.getFirstVariableIndex();
 4497   
 
 4498  0
         List removeKeys = new ArrayList();
 4499  0
         for (Iterator iter = variableStack.entrySet().iterator(); iter.hasNext();) {
 4500  0
             Map.Entry entry = (Map.Entry) iter.next();
 4501  0
             String name = (String) entry.getKey();
 4502  0
             Variable value = (Variable) entry.getValue();
 4503  0
             if (value.getIndex() >= lastID) {
 4504  0
                 removeKeys.add(name);
 4505   
             }
 4506   
         }
 4507  0
         for (Iterator iter = removeKeys.iterator(); iter.hasNext();) {
 4508  0
             Variable v  = (Variable) variableStack.remove(iter.next());
 4509  0
             if (CREATE_DEBUG_INFO) { // set localvartable
 4510  0
                 if (v != null) {
 4511  0
                     visitVariableEndLabel(v);
 4512  0
                     cv.visitLocalVariable(
 4513   
                             v.getName(),
 4514   
                             BytecodeHelper.getTypeDescription(v.getTypeName()),
 4515   
                             v.getStartLabel(),
 4516   
                             v.getEndLabel(),
 4517   
                             v.getIndex()
 4518   
                     );
 4519   
                 }
 4520   
             }
 4521   
         }
 4522  0
         scope = scope.getParent();
 4523   
     }
 4524   
 
 4525  0
     void removeVar(Variable v ) {
 4526  0
         variableStack.remove(v.getName());
 4527  0
         if (CREATE_DEBUG_INFO) { // set localvartable
 4528  0
             Label endl = new Label();
 4529  0
             cv.visitLabel(endl);
 4530  0
             cv.visitLocalVariable(
 4531   
                     v.getName(),
 4532   
                     BytecodeHelper.getTypeDescription(v.getTypeName()),
 4533   
                     v.getStartLabel(),
 4534   
                     endl,
 4535   
                     v.getIndex()
 4536   
             );
 4537   
         }
 4538   
     }
 4539  0
     private void visitVariableEndLabel(Variable v) {
 4540  0
         if (CREATE_DEBUG_INFO) {
 4541  0
             if(v.getEndLabel() == null) {
 4542  0
                 Label end = new Label();
 4543  0
                 v.setEndLabel(end);
 4544   
             }
 4545  0
             cv.visitLabel(v.getEndLabel());
 4546   
         }
 4547   
     }
 4548   
 
 4549  0
     protected void pushBlockScope() {
 4550  0
         pushBlockScope(true, true);
 4551   
     }
 4552   
 
 4553   
     /**
 4554   
      * create a new scope. Set break/continue label if the canXXX parameter is true. Otherwise
 4555   
      * inherit parent's label.
 4556   
      * @param canContinue   true if the start of the scope can take continue label
 4557   
      * @param canBreak  true if the end of the scope can take break label
 4558   
      */
 4559  0
     protected void pushBlockScope(boolean canContinue, boolean canBreak) {
 4560  0
         BlockScope parentScope = scope;
 4561  0
         scope = new BlockScope(parentScope);
 4562  0
         scope.setContinueLabel(canContinue ? new Label() : (parentScope == null ? null : parentScope.getContinueLabel()));
 4563  0
         scope.setBreakLabel(canBreak? new Label() : (parentScope == null ? null : parentScope.getBreakLabel()));
 4564  0
         scope.setFirstVariableIndex(getNextVariableID());
 4565   
     }
 4566   
 
 4567   
     /**
 4568   
      * Defines the given variable in scope and assigns it to the stack
 4569   
      */
 4570  0
     protected Variable defineVariable(String name, String type) {
 4571  0
         return defineVariable(name, type, true);
 4572   
     }
 4573   
 
 4574  0
     protected Variable defineVariable(String name, String type, boolean define) {
 4575  0
         return defineVariable(name, new Type(type), define);
 4576   
     }
 4577   
 
 4578  0
     private Variable defineVariable(String name, Type type, boolean define) {
 4579  0
         Variable answer = (Variable) variableStack.get(name);
 4580  0
         if (answer == null) {
 4581  0
             lastVariableIndex = getNextVariableID();
 4582  0
             answer = new Variable(lastVariableIndex, type, name);
 4583  0
             if (mutableVars.contains(name)) {
 4584  0
                 answer.setHolder(true);
 4585   
             }
 4586  0
             variableStack.put(name, answer);
 4587  0
             Label startLabel  = new Label();
 4588  0
             answer.setStartLabel(startLabel);
 4589  0
             if (define) {
 4590  0
                 if (definingParameters) {
 4591  0
                     if (answer.isHolder()) {
 4592  0
                         cv.visitTypeInsn(NEW, "groovy/lang/Reference"); // br todo to associate a label with the variable
 4593  0
                         cv.visitInsn(DUP);
 4594  0
                         cv.visitVarInsn(ALOAD, lastVariableIndex);
 4595  0
                         cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V");
 4596  0
                         cv.visitVarInsn(ASTORE, lastVariableIndex);
 4597  0
                         cv.visitLabel(startLabel);
 4598   
                     }
 4599   
                 }
 4600   
                 else {
 4601   
                     // using new variable inside a comparison expression
 4602   
                     // so lets initialize it too
 4603  0
                     if (answer.isHolder() && !isInScriptBody()) {
 4604   
                         //cv.visitVarInsn(ASTORE, lastVariableIndex + 1); // I might need this to set the reference value
 4605   
 
 4606  0
                         cv.visitTypeInsn(NEW, "groovy/lang/Reference");
 4607  0
                         cv.visitInsn(DUP);
 4608  0
                         cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "()V");
 4609   
 
 4610  0
                         cv.visitVarInsn(ASTORE, lastVariableIndex);
 4611  0
                         cv.visitLabel(startLabel);
 4612   
                         //cv.visitVarInsn(ALOAD, idx + 1);
 4613   
                     }
 4614   
                     else {
 4615  0
                         if (!leftHandExpression) { // new var on the RHS: init with null
 4616  0
                             cv.visitInsn(ACONST_NULL);
 4617  0
                             cv.visitVarInsn(ASTORE, lastVariableIndex);
 4618  0
                             cv.visitLabel(startLabel);
 4619   
                         }
 4620   
                     }
 4621   
                 }
 4622   
             }
 4623   
         }
 4624  0
         return answer;
 4625   
     }
 4626   
 
 4627  0
     private int getNextVariableID() {
 4628   
         //return Math.max(lastVariableIndex + 1, variableStack.size());
 4629  0
         return variableStack.size(); // todo : rework
 4630   
     }
 4631   
 
 4632   
     /** @return true if the given name is a local variable or a field */
 4633  0
     protected boolean isFieldOrVariable(String name) {
 4634  0
         return variableStack.containsKey(name) || classNode.getField(name) != null;
 4635   
     }
 4636   
 
 4637  0
     protected Type checkValidType(Type type, ASTNode node, String message) {
 4638  0
         if (type.isDynamic()) {
 4639  0
             return type;
 4640   
         }
 4641  0
         String name = checkValidType(type.getName(), node, message);
 4642  0
         if (type.getName().equals(name)) {
 4643  0
             return type;
 4644   
         }
 4645  0
         return new Type(name);
 4646   
     }
 4647   
 
 4648  0
     protected String checkValidType(String type, ASTNode node, String message) {
 4649  0
         if (type!= null && type.length() == 0)
 4650  0
             return "java.lang.Object";
 4651  0
         if (type.endsWith("[]")) {
 4652  0
             String postfix = "[]";
 4653  0
             String prefix = type.substring(0, type.length() - 2);
 4654  0
             return checkValidType(prefix, node, message) + postfix;
 4655   
         }
 4656  0
         int idx = type.indexOf('$');
 4657  0
         if (idx > 0) {
 4658  0
             String postfix = type.substring(idx);
 4659  0
             String prefix = type.substring(0, idx);
 4660  0
             return checkValidType(prefix, node, message) + postfix;
 4661   
         }
 4662  0
         if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) {
 4663  0
             return type;
 4664   
         }
 4665  0
         String original = type;
 4666  0
         type = resolveClassName(type);
 4667  0
         if (type != null) {
 4668  0
             return type;
 4669   
         }
 4670   
 
 4671  0
         throw new MissingClassException(original, node, message + " for class: " + classNode.getName());
 4672   
     }
 4673   
 
 4674  0
     protected String resolveClassName(String type) {
 4675  0
         return classNode.resolveClassName(type);
 4676   
     }
 4677   
 
 4678  0
     protected String createVariableName(String type) {
 4679  0
         return "__" + type + (++tempVariableNameCounter);
 4680   
     }
 4681   
 
 4682   
     /**
 4683   
      * @return if the type of the expression can be determined at compile time
 4684   
      *         then this method returns the type - otherwise null
 4685   
      */
 4686  0
     protected String getExpressionType(Expression expression) {
 4687  0
         if (isComparisonExpression(expression)) {
 4688  0
             return "boolean";
 4689   
         }
 4690  0
         if (expression instanceof VariableExpression) {
 4691  0
             VariableExpression varExpr = (VariableExpression) expression;
 4692  0
             Variable variable = (Variable) variableStack.get(varExpr.getVariable());
 4693  0
             if (variable != null && !variable.isHolder()) {
 4694  0
                 Type type = variable.getType();
 4695  0
                 if (! type.isDynamic()) {
 4696  0
                     return type.getName();
 4697   
                 }
 4698   
             }
 4699   
         }
 4700  0
         return null;
 4701   
     }
 4702   
 
 4703   
     /**
 4704   
      * @return true if the value is an Integer, a Float, a Long, a Double or a
 4705   
      *         String .
 4706   
      */
 4707  0
     protected static boolean isPrimitiveFieldType(String type) {
 4708  0
         return type.equals("java.lang.String")
 4709   
             || type.equals("java.lang.Integer")
 4710   
             || type.equals("java.lang.Double")
 4711   
             || type.equals("java.lang.Long")
 4712   
             || type.equals("java.lang.Float");
 4713   
     }
 4714   
 
 4715  0
     protected boolean isInClosureConstructor() {
 4716  0
         return constructorNode != null
 4717   
             && classNode.getOuterClass() != null
 4718   
             && classNode.getSuperClass().equals(Closure.class.getName());
 4719   
     }
 4720   
 
 4721  0
     protected boolean isStaticMethod() {
 4722  0
         if (methodNode == null) { // we're in a constructor
 4723  0
             return false;
 4724   
         }
 4725  0
         return methodNode.isStatic();
 4726   
     }
 4727   
 
 4728   
     Map classCache = new HashMap();
 4729   
     {
 4730  0
         classCache.put("int", Integer.TYPE);
 4731  0
         classCache.put("byte", Byte.TYPE);
 4732  0
         classCache.put("short", Short.TYPE);
 4733  0
         classCache.put("char", Character.TYPE);
 4734  0
         classCache.put("boolean", Boolean.TYPE);
 4735  0
         classCache.put("long", Long.TYPE);
 4736  0
         classCache.put("double", Double.TYPE);
 4737  0
         classCache.put("float", Float.TYPE);
 4738  0
         classCache.put("void", Void.TYPE);
 4739   
     }
 4740   
     /**
 4741   
      * @return loads the given type name
 4742   
      */
 4743  0
     protected Class loadClass(String name) {
 4744   
 
 4745  0
         if (name.equals(this.classNode.getName())) {
 4746  0
             return Object.class;
 4747   
         }
 4748   
 
 4749  0
         if (name == null) {
 4750  0
             return null;
 4751   
         }
 4752  0
         else if (name.length() == 0) {
 4753  0
             return Object.class;
 4754   
         }
 4755   
 
 4756  0
         name = BytecodeHelper.formatNameForClassLoading(name);
 4757   
 
 4758  0
         try {
 4759  0
             Class cls = (Class)classCache.get(name);
 4760  0
             if (cls != null)
 4761  0
                 return cls;
 4762   
 
 4763  0
             CompileUnit compileUnit = getCompileUnit();
 4764  0
             if (compileUnit != null) {
 4765  0
                 cls = compileUnit.loadClass(name);
 4766  0
                 classCache.put(name, cls);
 4767  0
                 return cls;
 4768   
             }
 4769   
             else {
 4770  0
                 throw new ClassGeneratorException("Could not load class: " + name);
 4771   
             }
 4772   
         }
 4773   
         catch (ClassNotFoundException e) {
 4774  0
             throw new ClassGeneratorException("Error when compiling class: " + classNode.getName() + ". Reason: could not load class: " + name + " reason: " + e, e);
 4775   
         }
 4776   
     }
 4777   
 
 4778  0
     protected CompileUnit getCompileUnit() {
 4779  0
         CompileUnit answer = classNode.getCompileUnit();
 4780  0
         if (answer == null) {
 4781  0
             answer = context.getCompileUnit();
 4782   
         }
 4783  0
         return answer;
 4784   
     }
 4785   
 
 4786   
     /**
 4787   
      * attemtp to identify the exact runtime method call the expression is intended for, for possible early binding.
 4788   
      * @param call
 4789   
      */
 4790  0
     public void resolve(MethodCallExpression call) {
 4791  0
         if (call.isResolveFailed()) {
 4792  0
             return;
 4793   
         }
 4794  0
         else if (call.isTypeResolved()) {
 4795  0
             return;
 4796   
         }
 4797   
 
 4798  0
         Expression obj = call.getObjectExpression();
 4799  0
         String meth = call.getMethod();
 4800  0
         Class ownerClass = null;
 4801  0
         boolean isStaticCall = false;
 4802  0
         boolean isSuperCall = false;
 4803   
 
 4804  0
         List arglist = new ArrayList();
 4805  0
         Expression args = call.getArguments();
 4806  0
         if (args instanceof TupleExpression) {
 4807  0
             TupleExpression tupleExpression = (TupleExpression) args;
 4808  0
             List argexps = tupleExpression.getExpressions();
 4809  0
             for (int i = 0; i < argexps.size(); i++) {
 4810  0
                 Expression expression = (Expression) argexps.get(i);
 4811  0
                 Class cls = expression.getTypeClass();
 4812  0
                 if (cls == null) {
 4813  0
                     call.setResolveFailed(true);
 4814  0
                     return ;
 4815   
                 }
 4816   
                 else {
 4817  0
                     arglist.add(cls);
 4818   
                 }
 4819   
             }
 4820  0
         } else if (args instanceof ClosureExpression) {
 4821  0
             call.setResolveFailed(true);
 4822  0
             return ;// todo
 4823   
         } else {
 4824  0
             call.setResolveFailed(true);
 4825  0
             return ;
 4826   
         }
 4827   
 
 4828   
 
 4829  0
         Class[] argsArray = new Class[arglist.size()];
 4830  0
         arglist.toArray(argsArray);
 4831   
 
 4832   
 
 4833  0
         if (obj instanceof ClassExpression) {
 4834   
             // static call
 4835   
             //ClassExpression cls = (ClassExpression)obj;
 4836   
             //String type = cls.getType();
 4837  0
             ownerClass = obj.getTypeClass(); //loadClass(type);
 4838  0
             isStaticCall = true;
 4839  0
         } else if (obj instanceof VariableExpression) {
 4840  0
             VariableExpression var = (VariableExpression) obj;
 4841  0
             if (var.getVariable().equals("this") && (methodNode == null? true : !methodNode.isStatic()) ) {
 4842  0
                 isStaticCall = false;
 4843  0
                 if (methodNode != null) {
 4844  0
                     isStaticCall = Modifier.isStatic(methodNode.getModifiers());
 4845   
                 }
 4846  0
                 MetaMethod mmeth = getMethodOfThisAndSuper(meth, argsArray, isStaticCall);
 4847  0
                 if (mmeth != null) {
 4848  0
                     call.setMethod(mmeth);
 4849  0
                     return ;
 4850   
                 }
 4851   
                 else {
 4852  0
                     call.setResolveFailed(true);
 4853  0
                     return ;
 4854   
                 }
 4855   
             }
 4856  0
             else if (var.getVariable().equals("super") ) {
 4857  0
                 isSuperCall = true;
 4858  0
                 ownerClass = var.getTypeClass();
 4859   
             }
 4860   
             else {
 4861  0
                 ownerClass = var.getTypeClass();
 4862   
             }
 4863   
         }
 4864   
         else /*if (obj instanceof PropertyExpression)*/ {
 4865  0
             ownerClass = obj.getTypeClass();
 4866  0
             if (ownerClass == null) {
 4867  0
                 call.setResolveFailed(true);
 4868  0
                 call.setFailure("target class is null");
 4869  0
                 return ;  // take care other cases later version
 4870   
             }
 4871   
         }
 4872   
 
 4873  0
         if (ownerClass == Object.class) {
 4874  0
             call.setResolveFailed(true);
 4875  0
             return ; // use late binding for dynamic types
 4876   
         }
 4877  0
         else if (ownerClass == null)  {
 4878  0
             call.setResolveFailed(true);
 4879  0
             return ; // use dynamic dispatching for GroovyObject
 4880   
         }
 4881   
         else
 4882  0
             if (!isSuperCall && !isStaticCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { // not optimize GroovyObject meth call for now
 4883  0
             call.setResolveFailed(true);
 4884  0
             return ;
 4885   
         }
 4886   
         else
 4887  0
             if (ownerClass.isPrimitive()) {
 4888  0
             call.setResolveFailed(true);
 4889  0
             return ; // todo handle primitives
 4890   
         }
 4891   
 
 4892   
 
 4893   
         //MetaMethod mmethod = InvokerHelper.getInstance().getMetaRegistry().getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
 4894   
         // todo is this thread safe?
 4895  0
         MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
 4896  0
         if (mmethod!= null) {
 4897  0
             call.setMethod(mmethod);
 4898   
         }
 4899   
         else {
 4900  0
             call.setResolveFailed(true);
 4901   
         }
 4902  0
         return ;
 4903   
     }
 4904   
     /**
 4905   
      * attemtp to identify the exact runtime method call the expression is intended for, for possible early binding.
 4906   
      * @param call
 4907   
      */
 4908  0
     public void resolve(ConstructorCallExpression call) {
 4909  0
         if (call.isResolveFailed()) {
 4910  0
             return ;
 4911   
         }
 4912  0
         else if (call.isTypeResolved()) {
 4913  0
             return ;
 4914   
         }
 4915   
 
 4916  0
         String declaredType = call.getTypeToSet();
 4917  0
         if (declaredType.equals(classNode.getName())) {
 4918  0
             call.setResolveFailed(true);
 4919  0
             call.setFailure("cannot resolve on the current class itself. ");
 4920  0
             return;
 4921   
         }
 4922   
         else {
 4923  0
             call.setType(declaredType);
 4924  0
             if (call.getTypeClass() == null) {
 4925  0
                 call.setResolveFailed(true);
 4926  0
                 call.setFailure("type name cannot be resolved. ");
 4927  0
                 return;
 4928   
             }
 4929   
         }
 4930   
 
 4931  0
         boolean isSuperCall = false;
 4932   
 
 4933  0
         List arglist = new ArrayList();
 4934  0
         Expression args = call.getArguments();
 4935  0
         if (args instanceof TupleExpression) {
 4936  0
             TupleExpression tupleExpression = (TupleExpression) args;
 4937  0
             List argexps = tupleExpression.getExpressions();
 4938  0
             for (int i = 0; i < argexps.size(); i++) {
 4939  0
                 Expression expression = (Expression) argexps.get(i);
 4940  0
                 Class cls = expression.getTypeClass();
 4941  0
                 if (cls == null) {
 4942  0
                     call.setResolveFailed(true);
 4943  0
                     return ;
 4944   
                 }
 4945   
                 else {
 4946  0
                     arglist.add(cls);
 4947   
                 }
 4948   
             }
 4949  0
         } else if (args instanceof ClosureExpression) {
 4950  0
             call.setResolveFailed(true);
 4951  0
             call.setFailure("don't know how to handle closure arg. ");
 4952  0
             return ;// todo
 4953   
         } else {
 4954  0
             call.setResolveFailed(true);
 4955  0
             call.setFailure("unknown arg type: " + args.getClass().getName());
 4956  0
             return ;
 4957   
         }
 4958   
 
 4959   
 
 4960  0
         Class[] argsArray = new Class[arglist.size()];
 4961  0
         arglist.toArray(argsArray);
 4962   
 
 4963  0
         Class ownerClass = call.getTypeClass();
 4964  0
         if (ownerClass == null) {
 4965  0
             String typeName = call.getType();
 4966  0
             if (typeName.equals(this.classNode.getName())) {
 4967   
                 // this is a ctor call to this class
 4968  0
                 call.setResolveFailed(true);
 4969  0
                 call.setFailure("invoke constructor for this. no optimization for now");
 4970  0
                 return ;
 4971   
             }
 4972   
             else {
 4973  0
                 try {
 4974  0
                     ownerClass = loadClass(typeName);
 4975  0
                     if (ownerClass == null) {
 4976  0
                         call.setResolveFailed(true);
 4977  0
                         call.setFailure("owner class type is null. ");
 4978  0
                         return ;
 4979   
                     }
 4980   
                 }
 4981   
                 catch (Throwable th) {
 4982  0
                     call.setResolveFailed(true);
 4983  0
                     call.setFailure("Exception: " + th);
 4984  0
                     return ;
 4985   
                 }
 4986   
             }
 4987   
         }
 4988   
 
 4989  0
         if (ownerClass == Object.class) {
 4990  0
             call.setResolveFailed(true);
 4991  0
             call.setFailure("owner class type java.lang.Object.  use late binding for dynamic types");
 4992  0
             return ; //
 4993   
         }
 4994  0
         else if (ownerClass == null)  {
 4995  0
             call.setResolveFailed(true);
 4996  0
             call.setFailure("owner class type is null. use dynamic dispatching for GroovyObject");
 4997  0
             return; // use dynamic dispatching for GroovyObject
 4998   
         }
 4999   
 // safe to call groovyobject ctor
 5000   
 //        else if (!isSuperCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { // ie, to allow early binding for a super call
 5001   
 //            call.setResolveFailed(true);
 5002   
 //            return null;
 5003   
 //        }
 5004  0
         else if (ownerClass.isPrimitive()) {
 5005  0
             call.setResolveFailed(true);
 5006  0
             throwException("The owner of the constructor is primitive.");
 5007  0
             return ;
 5008   
         }
 5009   
 
 5010  0
         Constructor ctor = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedConstructor(ownerClass, argsArray);
 5011  0
         if (ctor!= null) {
 5012  0
             call.setConstructor(ctor);
 5013   
         }
 5014   
         else {
 5015  0
             call.setResolveFailed(true);
 5016   
         }
 5017  0
         return ;
 5018   
     }
 5019   
 
 5020  0
     public void resolve(PropertyExpression propertyExpression)  {
 5021  0
         if (propertyExpression.getTypeClass() != null)
 5022  0
             return ;
 5023  0
         if (propertyExpression.isResolveFailed())
 5024  0
             return ;
 5025   
 
 5026  0
         Expression ownerExp = propertyExpression.getObjectExpression();
 5027  0
         Class ownerClass = ownerExp.getTypeClass();
 5028  0
         String propName = propertyExpression.getProperty();
 5029  0
         if (propName.equals("class")) {
 5030  0
             propertyExpression.setTypeClass(Class.class);
 5031  0
             return ;
 5032   
         }
 5033   
 
 5034   
         // handle arraylength
 5035  0
         if (ownerClass != null && ownerClass.isArray() && propName.equals("length")) {
 5036  0
             propertyExpression.setTypeClass(int.class);
 5037  0
             return;
 5038   
         }
 5039   
 
 5040  0
         if (isThisExpression(ownerExp)) {
 5041   
             // lets use the field expression if its available
 5042  0
             if (classNode == null) {
 5043  0
                 propertyExpression.setResolveFailed(true);
 5044  0
                 return ;
 5045   
             }
 5046  0
             FieldNode field   = null;
 5047  0
             ownerExp.setType(classNode.getName());
 5048  0
             try {
 5049  0
                 if( (field = classNode.getField(propName)) != null ) {
 5050   
 //                    Class cls =loadClass(field.getType());
 5051   
 //                    propertyExpression.setAccess(PropertyExpression.LOCAL_FIELD_ACCESS);
 5052   
 //                    propertyExpression.setTypeClass(cls);
 5053   
 // local property access. to be determined in the future
 5054  0
                     propertyExpression.setResolveFailed(true);
 5055  0
                     propertyExpression.setFailure("local property access. to be determined in the future.");
 5056  0
                     return ;
 5057   
                 } else {
 5058   
                     // search for super classes/interface
 5059   
                     // interface first first
 5060  0
                     String[] interfaces = classNode.getInterfaces();
 5061  0
                     String[] supers = new String[interfaces.length + 1];
 5062   
 
 5063  0
                     int i = 0;
 5064  0
                     for (; i < interfaces.length; i++) {
 5065  0
                         supers[i] = interfaces[i];
 5066   
                     }
 5067  0
                     supers[i] = classNode.getSuperClass();
 5068  0
                     for (int j = 0; j < supers.length; j++) {
 5069  0
                         String aSuper = supers[j];
 5070  0
                         Class superClass = loadClass(aSuper);
 5071  0
                         Field fld  = superClass.getDeclaredField(propName);
 5072  0
                         if (fld != null && !Modifier.isPrivate(fld.getModifiers())) {
 5073  0
                             propertyExpression.setField(fld);
 5074  0
                             return ;
 5075   
                         }
 5076   
                     }
 5077   
                 }
 5078   
             } catch (Exception e) {
 5079  0
                 propertyExpression.setResolveFailed(true);
 5080  0
                 propertyExpression.setFailure(e.getMessage());
 5081  0
                 return ;
 5082   
             }
 5083   
         }
 5084  0
         else if (ownerExp instanceof ClassExpression) {
 5085  0
             if (ownerClass != null) {
 5086  0
                 Field fld  = null;
 5087  0
                 try {
 5088  0
                     fld = ownerClass.getDeclaredField(propName);
 5089  0
                     if (!Modifier.isPrivate(fld.getModifiers())) {
 5090  0
                         propertyExpression.setField(fld);
 5091  0
                         return ;
 5092   
                     }
 5093   
                 } catch (NoSuchFieldException e) {
 5094  0
                     propertyExpression.setResolveFailed(true);
 5095  0
                     return ;
 5096   
                 }
 5097   
             }
 5098   
         }
 5099   
         else { // search public field and then setter/getter
 5100  0
             if (ownerClass != null) {
 5101  0
                 propertyExpression.setResolveFailed(true); // will get reset if property/getter/setter were found
 5102  0
                 Field fld  = null;
 5103  0
                 try {
 5104  0
                     fld = ownerClass.getDeclaredField(propName);
 5105   
                 } catch (NoSuchFieldException e) {}
 5106   
 
 5107  0
                 if (fld != null && Modifier.isPublic(fld.getModifiers())) {
 5108  0
                     propertyExpression.setField(fld);
 5109   
                 }
 5110   
 
 5111   
                 // let's get getter and setter
 5112  0
                 String getterName = "get" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
 5113  0
                 String setterName = "set" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
 5114   
 
 5115  0
                 Method[] meths = ownerClass.getMethods();
 5116  0
                 for (int i = 0; i < meths.length; i++) {
 5117  0
                     Method method = meths[i];
 5118  0
                     String methName =method.getName();
 5119  0
                     Class[] paramClasses = method.getParameterTypes();
 5120  0
                     if (methName.equals(getterName) && paramClasses.length == 0) {
 5121  0
                         propertyExpression.setGetter(method);
 5122  0
                     } else if (methName.equals(setterName) && paramClasses.length == 1) {
 5123  0
                         propertyExpression.setSetter(method);
 5124   
                     }
 5125   
                 }
 5126  0
                 return ;
 5127   
             }
 5128   
         }
 5129  0
         propertyExpression.setResolveFailed(true);
 5130  0
         return ;
 5131   
     }
 5132   
     /** search in the current classNode and super class for matching method */
 5133  0
     private MetaMethod getMethodOfThisAndSuper(String methName, Class[] argsArray, boolean isStaticCall) {
 5134  0
         MethodNode candidate = null;
 5135  0
         List meths = classNode.getMethods();
 5136  0
         Class[] candidateParamClasses = null;
 5137  0
         for (int i = 0; i < meths.size(); i++) {
 5138  0
             MethodNode meth = (MethodNode) meths.get(i);
 5139  0
             if (meth.getName().equals(methName)) {
 5140  0
                 Parameter[] params = meth.getParameters();
 5141  0
                 if  (params.length == argsArray.length) {
 5142  0
                     Class[] paramClasses = new Class[params.length];
 5143  0
                     for (int j = 0; j < params.length; j++) {
 5144  0
                         Parameter param = params[j];
 5145  0
                         String type = param.getType();
 5146  0
                         Class paramClass = null;
 5147  0
                         try {
 5148  0
                             paramClass = loadClass(type);
 5149   
                         } catch (Exception e) {
 5150  0
                             log.warning(e.getMessage());
 5151  0
                             return null;
 5152   
                         }
 5153  0
                         paramClasses[j] = paramClass;
 5154   
                     }
 5155  0
                     if (MetaClass.isValidMethod(paramClasses, argsArray, false)) {
 5156  0
                         candidateParamClasses = paramClasses;
 5157  0
                         candidate = meth;
 5158  0
                         break;
 5159   
                     }
 5160   
                     else {
 5161  0
                         if (MetaClass.isValidMethod(paramClasses, argsArray, true)){
 5162  0
                             candidateParamClasses = paramClasses;
 5163  0
                             candidate = meth;
 5164  0
                             break;
 5165   
                         }
 5166   
                     }
 5167   
                 }
 5168   
             }
 5169   
         }
 5170   
 
 5171  0
         if (candidate != null && candidateParamClasses != null) {
 5172   
             // let's synth a MetaMethod from the MethodNode
 5173  0
             try {
 5174  0
                 return new MetaMethod(methName, null, candidateParamClasses, loadClass(candidate.getReturnType()), candidate.getModifiers());
 5175   
             } catch (Exception e) {
 5176  0
                 log.warning(e.getMessage());
 5177  0
                 return null;
 5178   
             }
 5179   
         }
 5180   
         else {
 5181   
             // try super class
 5182  0
             Class superClass = null;
 5183  0
             try {
 5184  0
                 superClass = loadClass(classNode.getSuperClass());
 5185   
             }
 5186   
             catch(Exception e) {
 5187   
                 // the super may be a groovy class that's not compiled yet
 5188  0
                 log.warning(e.getMessage());
 5189   
             }
 5190   
             // should I filter out GroovyObject super class here?
 5191  0
             if (superClass != null ) {
 5192  0
                 MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(superClass, methName, argsArray, isStaticCall);
 5193  0
                 if (mmethod == null)
 5194  0
                     return null;
 5195  0
                 int modies = mmethod.getModifiers();
 5196  0
                 if (Modifier.isPrivate(modies)) {
 5197  0
                     return null;
 5198   
                 }
 5199  0
                 else if(modies == 0) {
 5200   
                     // match package
 5201  0
                     int pThis = classNode.getName().lastIndexOf(".");
 5202  0
                     String packageNameThis = pThis > 0? classNode.getName().substring(0, pThis) : "";
 5203   
 
 5204  0
                     int pSuper = classNode.getSuperClass().lastIndexOf(".");
 5205  0
                     String packageNameSuper = pSuper > 0? classNode.getSuperClass().substring(0, pSuper) : "";
 5206  0
                     if (packageNameThis.equals(packageNameSuper)) {
 5207  0
                         return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers());
 5208   
                     }
 5209   
                     else {
 5210  0
                         return null;
 5211   
                     }
 5212   
                 }
 5213   
                 else {
 5214   
                     // let changes the declaring class back to null (meaning "this"), so that proper class inheritance permission control is obeyed
 5215  0
                     return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers());
 5216   
                 }
 5217   
             }
 5218  0
             return null;
 5219   
         }
 5220   
     }
 5221   
 
 5222   
 
 5223   
     /**
 5224   
      *  to find out the real type of a Variable Object
 5225   
      */
 5226  0
     public void resolve(VariableExpression expression) {
 5227   
 
 5228  0
         String variableName = expression.getVariable();
 5229   
 // todo process arrays!
 5230   
       //-----------------------------------------------------------------------
 5231   
       // SPECIAL CASES
 5232   
 
 5233   
         //
 5234   
         // "this" for static methods is the Class instance
 5235   
 
 5236  0
         if (isStaticMethod() && variableName.equals("this")) {
 5237  0
             expression.setTypeClass(Class.class);
 5238  0
             return;
 5239  0
         } else if (variableName.equals("super")) {
 5240  0
             if (isStaticMethod() ) {
 5241  0
                 expression.setTypeClass(Class.class);
 5242  0
                 return;
 5243   
             }
 5244   
             else {
 5245  0
                 try {
 5246  0
                     Class cls = loadClass(classNode.getSuperClass());
 5247  0
                     expression.setTypeClass(cls);
 5248  0
                     return ;
 5249   
                 }
 5250   
                 catch (Exception e) {
 5251  0
                     expression.setResolveFailed(true);
 5252  0
                     expression.setFailure(e.getMessage());
 5253  0
                     return ;
 5254   
                 }
 5255   
             }
 5256  0
         } else if (variableName.equals("this")){
 5257  0
             return ;
 5258   
         } else {
 5259   
 //            String className = resolveClassName(variableName);
 5260   
 //            if (className != null) {
 5261   
 //                return loadClass(className);
 5262   
 //            }
 5263   
         }
 5264   
 
 5265   
 
 5266   
       //-----------------------------------------------------------------------
 5267   
       // GENERAL VARIABLE LOOKUP
 5268   
 
 5269   
         //
 5270   
         // We are handling only unqualified variables here.  Therefore,
 5271   
         // we do not care about accessors, because local access doesn't
 5272   
         // go through them.  Therefore, precedence is as follows:
 5273   
         //   1) local variables, nearest block first
 5274   
         //   2) class fields
 5275   
         //   3) repeat search from 2) in next outer class
 5276   
 
 5277  0
         boolean  handled  = false;
 5278  0
         Variable variable = (Variable)variableStack.get( variableName );
 5279   
 
 5280  0
         try {
 5281  0
             if( variable != null ) {
 5282  0
                 Type t = variable.getType();
 5283  0
                 if (t.getRealName().length() == 0) {
 5284  0
                     String tname = t.getName();
 5285  0
                     if (tname.endsWith("[]")) {
 5286  0
                         expression.setResolveFailed(true);
 5287  0
                         expression.setFailure("array type to be supported later");
 5288  0
                         return ;  // todo hanlde array
 5289   
                     }
 5290  0
                     else if (tname.equals(classNode.getName())){
 5291  0
                         expression.setResolveFailed(true);
 5292  0
                         return ;
 5293   
                     }
 5294  0
                     else if (classNode.getOuterClass() != null && tname.equals(classNode.getOuterClass().getName())){
 5295  0
                         expression.setResolveFailed(true);
 5296  0
                         return ;
 5297   
                     }
 5298  0
                     Class cls = loadClass(tname);
 5299  0
                     expression.setTypeClass(cls);
 5300  0
                     expression.setDynamic(t.isDynamic());
 5301  0
                     return ;
 5302   
                 } else {
 5303  0
                     String tname = t.getRealName();
 5304  0
                     if (tname.endsWith("[]")) {
 5305  0
                         expression.setResolveFailed(true);
 5306  0
                         expression.setFailure("array type to be supported later");
 5307  0
                         return ;  // todo hanlde array
 5308   
                     }
 5309  0
                     Class cls = loadClass(tname);
 5310  0
                     expression.setTypeClass(cls);
 5311  0
                     expression.setDynamic(t.isDynamic());
 5312  0
                     return ;
 5313   
                 }
 5314   
 
 5315   
 //            if( variable.isProperty() ) {
 5316   
 //                processPropertyVariable(variable );
 5317   
 //            }
 5318   
 //            else {
 5319   
 //                processStackVariable(variable );
 5320   
 //            }
 5321   
 //
 5322   
             } else {
 5323  0
                 int       steps   = 0;
 5324  0
                 ClassNode currentClassNode = classNode;
 5325  0
                 FieldNode field   = null;
 5326  0
                 do {
 5327  0
                     if( (field = currentClassNode.getField(variableName)) != null ) {
 5328  0
                         if (methodNode == null || !methodNode.isStatic() || field.isStatic() ) {
 5329  0
                             if (/*field.isDynamicType() || */field.isHolder()) {
 5330  0
                                 expression.setResolveFailed(true);
 5331  0
                                 expression.setFailure("reference type to be supported later");
 5332  0
                                 return ;
 5333   
                             } else {
 5334  0
                                 String type = field.getType();
 5335  0
                                 Class cls = loadClass(type);
 5336  0
                                 expression.setTypeClass(cls);
 5337  0
                                 expression.setDynamic(field.isDynamicType());
 5338  0
                                 return ;
 5339   
                             }
 5340   
                         }
 5341   
                     }
 5342  0
                     steps++;
 5343  ?
                 } while( (currentClassNode = currentClassNode.getOuterClass()) != null );
 5344   
             }
 5345   
 
 5346   
             //
 5347   
             // Finally, a new variable
 5348   
 
 5349  0
             String variableType = expression.getType();
 5350  0
             if (variableType.length() > 0 && !variableType.equals("java.lang.Object")) {
 5351  0
                 Class cls = loadClass(variableType);
 5352  0
                 expression.setTypeClass(cls);
 5353  0
                 return ;
 5354   
             }
 5355   
         } catch (Exception e) {
 5356  0
             log.warning(e.getMessage());
 5357  0
             expression.setResolveFailed(true);
 5358  0
             expression.setFailure(e.getMessage());
 5359   
         }
 5360  0
         return ;
 5361   
     }
 5362   
 
 5363  0
     public MetaMethod resolve(StaticMethodCallExpression staticCall) {
 5364  0
        if (staticCall.isResolveFailed()) {
 5365  0
             return null;
 5366   
         }
 5367  0
         else if (staticCall.isTypeResolved()) {
 5368  0
             return staticCall.getMetaMethod();
 5369   
         }
 5370   
 
 5371  0
         String ownerTypeName = staticCall.getOwnerType();
 5372  0
         String meth = staticCall.getMethod();
 5373  0
         Class ownerClass = null;
 5374  0
         try {
 5375  0
             ownerClass = loadClass(ownerTypeName);
 5376   
         } catch (Exception e) {
 5377  0
             staticCall.setResolveFailed(true);
 5378  0
             staticCall.setFailure("Owner type could not be resolved: " + e);
 5379  0
             return null;
 5380   
         }
 5381   
 
 5382  0
         boolean isStaticCall = true;
 5383  0
         boolean isSuperCall = false;
 5384   
 
 5385  0
         List arglist = new ArrayList();
 5386  0
         Expression args = staticCall.getArguments();
 5387  0
         if (args instanceof TupleExpression) {
 5388  0
             TupleExpression tupleExpression = (TupleExpression) args;
 5389  0
             List argexps = tupleExpression.getExpressions();
 5390  0
             for (int i = 0; i < argexps.size(); i++) {
 5391  0
                 Expression expression = (Expression) argexps.get(i);
 5392  0
                 Class cls = expression.getTypeClass();
 5393  0
                 if (cls == null) {
 5394  0
                     staticCall.setResolveFailed(true);
 5395  0
                     staticCall.setFailure("Argument type could not be resolved.");
 5396  0
                     return null;
 5397   
                 }
 5398   
                 else {
 5399  0
                     arglist.add(cls);
 5400   
                 }
 5401   
             }
 5402  0
         } else if (args instanceof ClosureExpression) {
 5403  0
             staticCall.setResolveFailed(true);
 5404  0
             staticCall.setFailure("Resolving on Closure call not implemented yet. ");
 5405  0
             return null;// todo
 5406   
         } else {
 5407  0
             staticCall.setResolveFailed(true);
 5408  0
             staticCall.setFailure("Unknown argument expression type.");
 5409  0
             return null;
 5410   
         }
 5411   
 
 5412   
 
 5413  0
         Class[] argsArray = new Class[arglist.size()];
 5414  0
         arglist.toArray(argsArray);
 5415   
 
 5416  0
         if (ownerClass == Object.class) {
 5417  0
             staticCall.setResolveFailed(true);
 5418  0
             staticCall.setFailure("Resolving on java.lang.Object static call not supported. ");
 5419  0
             return null; // use late binding for dynamic types
 5420   
         }
 5421  0
         else if (ownerClass == null)  {
 5422  0
             staticCall.setResolveFailed(true);
 5423  0
             staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. ");
 5424  0
             return null; // use dynamic dispatching for GroovyObject
 5425   
         }
 5426  0
         else if (!isSuperCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { // ie, to allow early binding for a super call
 5427  0
             staticCall.setResolveFailed(true);
 5428  0
             staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. ");
 5429  0
             return null;
 5430   
         }
 5431  0
         else if (ownerClass.isPrimitive()) {
 5432  0
             staticCall.setResolveFailed(true);
 5433  0
             staticCall.setFailure("Could not use primitive as method owner");
 5434  0
             return null; // todo handle primitives
 5435   
         }
 5436   
 
 5437   
 
 5438   
         //MetaMethod mmethod = InvokerHelper.getInstance().getMetaRegistry().getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
 5439   
         // todo is this thread safe?
 5440  0
         MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
 5441  0
         if (mmethod!= null) {
 5442  0
             staticCall.setMetaMethod(mmethod);
 5443   
         }
 5444   
         else {
 5445  0
             staticCall.setResolveFailed(true);
 5446  0
             staticCall.setFailure("Could not find MetaMethod in the MetaClass.");
 5447   
         }
 5448  0
         return mmethod;
 5449   
     }
 5450   
 
 5451   
     // the fowllowing asXXX() methods are copied from the Invoker class, to avoid initilization of an invoker instance,
 5452   
     // which has lots of baggage with it, notably the meta class stuff.
 5453  0
     private static Object asType(Object object, Class type) {
 5454  0
         if (object == null) {
 5455  0
             return null;
 5456   
         }
 5457  0
         if (type.isInstance(object)) {
 5458  0
             return object;
 5459   
         }
 5460  0
         if (type.equals(String.class)) {
 5461  0
             return object.toString();
 5462   
         }
 5463  0
         if (type.equals(Character.class)) {
 5464  0
             if (object instanceof Number) {
 5465  0
                 return asCharacter((Number) object);
 5466   
             }
 5467   
             else {
 5468  0
                 String text = object.toString();
 5469  0
                 if (text.length() == 1) {
 5470  0
                     return new Character(text.charAt(0));
 5471   
                 }
 5472   
                 else {
 5473  0
                     throw new ClassCastException("Cannot cast: " + text + " to a Character");
 5474   
                 }
 5475   
             }
 5476   
         }
 5477  0
         if (Number.class.isAssignableFrom(type)) {
 5478  0
             if (object instanceof Character) {
 5479  0
                 return new Integer(((Character) object).charValue());
 5480   
             }
 5481  0
             else if (object instanceof String) {
 5482  0
                 String c = (String) object;
 5483  0
                 if (c.length() == 1) {
 5484  0
                     return new Integer(c.charAt(0));
 5485   
                 }
 5486   
                 else {
 5487  0
                     throw new ClassCastException("Cannot cast: '" + c + "' to an Integer");
 5488   
                 }
 5489   
             }
 5490   
         }
 5491  0
         if (object instanceof Number) {
 5492  0
             Number n = (Number) object;
 5493  0
             if (type.isPrimitive()) {
 5494  0
                 if (type == byte.class) {
 5495  0
                     return new Byte(n.byteValue());
 5496   
                 }
 5497  0
                 if (type == char.class) {
 5498  0
                     return new Character((char) n.intValue());
 5499   
                 }
 5500  0
                 if (type == short.class) {
 5501  0
                     return new Short(n.shortValue());
 5502   
                 }
 5503  0
                 if (type == int.class) {
 5504  0
                     return new Integer(n.intValue());
 5505   
                 }
 5506  0
                 if (type == long.class) {
 5507  0
                     return new Long(n.longValue());
 5508   
                 }
 5509  0
                 if (type == float.class) {
 5510  0
                     return new Float(n.floatValue());
 5511   
                 }
 5512  0
                 if (type == double.class) {
 5513  0
                     Double answer = new Double(n.doubleValue());
 5514   
                     //throw a runtime exception if conversion would be out-of-range for the type.
 5515  0
                     if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
 5516   
                             || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
 5517  0
                         throw new  GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
 5518   
                                 +" value "+n+" to double failed.  Value is out of range.");
 5519   
                     }
 5520  0
                     return answer;
 5521   
                 }
 5522   
             }
 5523   
             else {
 5524  0
                 if (Number.class.isAssignableFrom(type)) {
 5525  0
                     if (type == Byte.class) {
 5526  0
                         return new Byte(n.byteValue());
 5527   
                     }
 5528  0
                     if (type == Character.class) {
 5529  0
                         return new Character((char) n.intValue());
 5530   
                     }
 5531  0
                     if (type == Short.class) {
 5532  0
                         return new Short(n.shortValue());
 5533   
                     }
 5534  0
                     if (type == Integer.class) {
 5535  0
                         return new Integer(n.intValue());
 5536   
                     }
 5537  0
                     if (type == Long.class) {
 5538  0
                         return new Long(n.longValue());
 5539   
                     }
 5540  0
                     if (type == Float.class) {
 5541  0
                         return new Float(n.floatValue());
 5542   
                     }
 5543  0
                     if (type == Double.class) {
 5544  0
                         Double answer = new Double(n.doubleValue());
 5545   
                         //throw a runtime exception if conversion would be out-of-range for the type.
 5546  0
                         if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
 5547   
                                 || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
 5548  0
                             throw new  GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
 5549   
                                     +" value "+n+" to double failed.  Value is out of range.");
 5550   
                         }
 5551  0
                         return answer;
 5552   
                     }
 5553   
 
 5554   
                 }
 5555   
             }
 5556   
         }
 5557  0
         if (type == Boolean.class) {
 5558  0
             return asBool(object) ? Boolean.TRUE : Boolean.FALSE;
 5559   
         }
 5560  0
         return object;
 5561   
     }
 5562   
 
 5563  0
     private static boolean asBool(Object object) {
 5564  0
        if (object instanceof Boolean) {
 5565  0
             Boolean booleanValue = (Boolean) object;
 5566  0
             return booleanValue.booleanValue();
 5567   
         }
 5568  0
         else if (object instanceof Matcher) {
 5569  0
             Matcher matcher = (Matcher) object;
 5570  0
             RegexSupport.setLastMatcher(matcher);
 5571  0
             return matcher.find();
 5572   
         }
 5573  0
         else if (object instanceof Collection) {
 5574  0
             Collection collection = (Collection) object;
 5575  0
             return !collection.isEmpty();
 5576   
         }
 5577  0
         else if (object instanceof Number) {
 5578  0
             Number n = (Number) object;
 5579  0
             return n.intValue() != 0;
 5580   
         }
 5581   
         else {
 5582  0
             return object != null;
 5583   
         }
 5584   
     }
 5585  0
     private static Character asCharacter(Number value) {
 5586  0
         return new Character((char) value.intValue());
 5587   
     }
 5588   
 
 5589  0
     private static Character asCharacter(String text) {
 5590  0
         return new Character(text.charAt(0));
 5591   
     }
 5592   
 }
 5593