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