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