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