KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > classgen > AsmClassGenerator2


1 /*
2  * $Id: AsmClassGenerator2.java,v 1.7 2005/01/11 16:57:13 glaforge Exp $
3  *
4  * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5  *
6  * Redistribution and use of this software and associated documentation
7  * ("Software"), with or without modification, are permitted provided that the
8  * following conditions are met: 1. Redistributions of source code must retain
9  * copyright statements and notices. Redistributions must also contain a copy
10  * of this document. 2. Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer in
12  * the documentation and/or other materials provided with the distribution. 3.
13  * The name "groovy" must not be used to endorse or promote products derived
14  * from this Software without prior written permission of The Codehaus. For
15  * written permission, please contact info@codehaus.org. 4. Products derived
16  * from this Software may not be called "groovy" nor may "groovy" appear in
17  * their names without prior written permission of The Codehaus. "groovy" is a
18  * registered trademark of The Codehaus. 5. Due credit should be given to The
19  * Codehaus - http://groovy.codehaus.org/
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
22  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31  * DAMAGE.
32  *
33  */

34 package org.codehaus.groovy.classgen;
35
36 import groovy.lang.*;
37
38 import java.lang.reflect.Constructor JavaDoc;
39 import java.lang.reflect.Field JavaDoc;
40 import java.lang.reflect.Method JavaDoc;
41 import java.lang.reflect.Modifier JavaDoc;
42 import java.util.*;
43 import java.util.regex.Matcher JavaDoc;
44 import java.util.logging.Logger JavaDoc;
45 import java.security.AccessController JavaDoc;
46 import java.security.PrivilegedAction JavaDoc;
47
48 import org.codehaus.groovy.ast.ASTNode;
49 import org.codehaus.groovy.ast.ClassNode;
50 import org.codehaus.groovy.ast.CompileUnit;
51 import org.codehaus.groovy.ast.ConstructorNode;
52 import org.codehaus.groovy.ast.FieldNode;
53 import org.codehaus.groovy.ast.GroovyCodeVisitor;
54 import org.codehaus.groovy.ast.InnerClassNode;
55 import org.codehaus.groovy.ast.MethodNode;
56 import org.codehaus.groovy.ast.Parameter;
57 import org.codehaus.groovy.ast.PropertyNode;
58 import org.codehaus.groovy.ast.Type;
59 import org.codehaus.groovy.ast.VariableScope;
60 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
61 import org.codehaus.groovy.ast.expr.ArrayExpression;
62 import org.codehaus.groovy.ast.expr.BinaryExpression;
63 import org.codehaus.groovy.ast.expr.BooleanExpression;
64 import org.codehaus.groovy.ast.expr.CastExpression;
65 import org.codehaus.groovy.ast.expr.ClassExpression;
66 import org.codehaus.groovy.ast.expr.ClosureExpression;
67 import org.codehaus.groovy.ast.expr.ConstantExpression;
68 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
69 import org.codehaus.groovy.ast.expr.Expression;
70 import org.codehaus.groovy.ast.expr.ExpressionTransformer;
71 import org.codehaus.groovy.ast.expr.FieldExpression;
72 import org.codehaus.groovy.ast.expr.GStringExpression;
73 import org.codehaus.groovy.ast.expr.ListExpression;
74 import org.codehaus.groovy.ast.expr.MapEntryExpression;
75 import org.codehaus.groovy.ast.expr.MapExpression;
76 import org.codehaus.groovy.ast.expr.MethodCallExpression;
77 import org.codehaus.groovy.ast.expr.NegationExpression;
78 import org.codehaus.groovy.ast.expr.NotExpression;
79 import org.codehaus.groovy.ast.expr.PostfixExpression;
80 import org.codehaus.groovy.ast.expr.PrefixExpression;
81 import org.codehaus.groovy.ast.expr.PropertyExpression;
82 import org.codehaus.groovy.ast.expr.RangeExpression;
83 import org.codehaus.groovy.ast.expr.RegexExpression;
84 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
85 import org.codehaus.groovy.ast.expr.TernaryExpression;
86 import org.codehaus.groovy.ast.expr.TupleExpression;
87 import org.codehaus.groovy.ast.expr.VariableExpression;
88 import org.codehaus.groovy.ast.stmt.AssertStatement;
89 import org.codehaus.groovy.ast.stmt.BlockStatement;
90 import org.codehaus.groovy.ast.stmt.BreakStatement;
91 import org.codehaus.groovy.ast.stmt.CaseStatement;
92 import org.codehaus.groovy.ast.stmt.CatchStatement;
93 import org.codehaus.groovy.ast.stmt.ContinueStatement;
94 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
95 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
96 import org.codehaus.groovy.ast.stmt.ForStatement;
97 import org.codehaus.groovy.ast.stmt.IfStatement;
98 import org.codehaus.groovy.ast.stmt.ReturnStatement;
99 import org.codehaus.groovy.ast.stmt.Statement;
100 import org.codehaus.groovy.ast.stmt.SwitchStatement;
101 import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
102 import org.codehaus.groovy.ast.stmt.ThrowStatement;
103 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
104 import org.codehaus.groovy.ast.stmt.WhileStatement;
105 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
106 import org.codehaus.groovy.runtime.InvokerHelper;
107 import org.codehaus.groovy.runtime.RegexSupport;
108 import org.codehaus.groovy.syntax.Token;
109 import org.codehaus.groovy.syntax.Types;
110 import org.codehaus.groovy.syntax.SyntaxException;
111 import org.codehaus.groovy.syntax.parser.RuntimeParserException;
112 import org.objectweb.asm.ClassVisitor;
113 import org.objectweb.asm.CodeVisitor;
114 import org.objectweb.asm.Label;
115 import org.objectweb.asm.ClassWriter;
116
117 /**
118  * Generates Java class versions of Groovy classes using ASM
119  * Based on AsmClassGenerator 1.6.
120  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
121  * @author <a HREF="mailto:b55r@sina.com">Bing Ran</a>
122  *
123  * @version $Revision: 1.7 $
124  */

125 public class AsmClassGenerator2 extends ClassGenerator {
126
127     private Logger JavaDoc log = Logger.getLogger(getClass().getName());
128
129     private ClassVisitor cw;
130     private CodeVisitor cv;
131     private GeneratorContext context;
132
133     private String JavaDoc sourceFile;
134
135     // current class details
136
private ClassNode classNode;
137     private ClassNode outermostClass;
138     private String JavaDoc internalClassName;
139     private String JavaDoc internalBaseClassName;
140
141     /** maps the variable names to the JVM indices */
142     private Map variableStack = new HashMap();
143
144     /** have we output a return statement yet */
145     private boolean outputReturn;
146
147     /** are we on the left or right of an expression */
148     private boolean leftHandExpression;
149
150     // cached values
151
MethodCaller invokeMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethod");
152     MethodCaller invokeMethodSafeMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethodSafe");
153     MethodCaller invokeStaticMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticMethod");
154     MethodCaller invokeConstructorMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructor");
155     MethodCaller invokeConstructorOfMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructorOf");
156     MethodCaller invokeNoArgumentsConstructorOf = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsConstructorOf");
157     MethodCaller invokeClosureMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeClosure");
158     MethodCaller invokeSuperMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeSuperMethod");
159     MethodCaller invokeNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsMethod");
160     MethodCaller invokeStaticNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticNoArgumentsMethod");
161
162     MethodCaller asIntMethod = MethodCaller.newStatic(InvokerHelper.class, "asInt");
163     MethodCaller asTypeMethod = MethodCaller.newStatic(InvokerHelper.class, "asType");
164     MethodCaller getPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getProperty");
165     MethodCaller getPropertySafeMethod = MethodCaller.newStatic(InvokerHelper.class, "getPropertySafe");
166     MethodCaller setPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setProperty");
167     MethodCaller setPropertyMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setProperty2");
168     MethodCaller setPropertySafeMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setPropertySafe2");
169     MethodCaller getGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getGroovyObjectProperty");
170     MethodCaller setGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setGroovyObjectProperty");
171     MethodCaller asIteratorMethod = MethodCaller.newStatic(InvokerHelper.class, "asIterator");
172     MethodCaller asBool = MethodCaller.newStatic(InvokerHelper.class, "asBool");
173     MethodCaller notBoolean = MethodCaller.newStatic(InvokerHelper.class, "notBoolean");
174     MethodCaller notObject = MethodCaller.newStatic(InvokerHelper.class, "notObject");
175     MethodCaller regexPattern = MethodCaller.newStatic(InvokerHelper.class, "regexPattern");
176     MethodCaller negation = MethodCaller.newStatic(InvokerHelper.class, "negate");
177     MethodCaller convertPrimitiveArray = MethodCaller.newStatic(InvokerHelper.class, "convertPrimitiveArray");
178     MethodCaller convertToPrimitiveArray = MethodCaller.newStatic(InvokerHelper.class, "convertToPrimitiveArray");
179
180     MethodCaller compareIdenticalMethod = MethodCaller.newStatic(InvokerHelper.class, "compareIdentical");
181     MethodCaller compareEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareEqual");
182     MethodCaller compareNotEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareNotEqual");
183     MethodCaller compareToMethod = MethodCaller.newStatic(InvokerHelper.class, "compareTo");
184     MethodCaller findRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "findRegex");
185     MethodCaller matchRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "matchRegex");
186     MethodCaller compareLessThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThan");
187     MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThanEqual");
188     MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThan");
189     MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThanEqual");
190     MethodCaller isCaseMethod = MethodCaller.newStatic(InvokerHelper.class, "isCase");
191
192     MethodCaller createListMethod = MethodCaller.newStatic(InvokerHelper.class, "createList");
193     MethodCaller createTupleMethod = MethodCaller.newStatic(InvokerHelper.class, "createTuple");
194     MethodCaller createMapMethod = MethodCaller.newStatic(InvokerHelper.class, "createMap");
195     MethodCaller createRangeMethod = MethodCaller.newStatic(InvokerHelper.class, "createRange");
196
197     MethodCaller assertFailedMethod = MethodCaller.newStatic(InvokerHelper.class, "assertFailed");
198
199     MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator.class, "next");
200     MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator.class, "hasNext");
201
202
203     // current stack index
204
private int lastVariableIndex;
205     private static int tempVariableNameCounter;
206
207     // exception blocks list
208
private List exceptionBlocks = new ArrayList();
209
210     private boolean definingParameters;
211     private Set syntheticStaticFields = new HashSet();
212     private Set mutableVars = new HashSet();
213     private boolean passingClosureParams;
214
215     private ConstructorNode constructorNode;
216     private MethodNode methodNode;
217     //private PropertyNode propertyNode;
218
private BlockScope scope;
219     private BytecodeHelper helper = new BytecodeHelper(null);
220
221     private VariableScope variableScope;
222     public static final boolean CREATE_DEBUG_INFO = false;
223     private static final boolean MARK_START = true;
224
225     public static final String JavaDoc EB_SWITCH_NAME = "static.dispatching";
226     public boolean ENABLE_EARLY_BINDING;
227     { //
228
String JavaDoc ebSwitch = (String JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
229             public Object JavaDoc run() {
230                 return System.getProperty(EB_SWITCH_NAME, "false"); // set default to true if early binding is on by default.
231
}
232         });
233         //System.out.println("ebSwitch = " + ebSwitch);
234
if (ebSwitch.equals("true")) {
235             ENABLE_EARLY_BINDING = true;
236         }
237         else if (ebSwitch.equals("false")) {
238             ENABLE_EARLY_BINDING = false;
239         }
240         else {
241             ENABLE_EARLY_BINDING = false;
242             log.warning("The value of system property " + EB_SWITCH_NAME + " is not recognized. Late dispatching is assumed. ");
243         }
244     }
245     public static final boolean ASM_DEBUG = false; // add marker in the bytecode to show source-byecode relationship
246
private int lineNumber = -1;
247     private int columnNumber = -1;
248     private ASTNode currentASTNode = null;
249
250     private DummyClassGenerator dummyGen = null;
251     private ClassWriter dummyClassWriter = null;
252
253     public AsmClassGenerator2(
254         GeneratorContext context,
255         ClassVisitor classVisitor,
256         ClassLoader JavaDoc classLoader,
257         String JavaDoc sourceFile) {
258         super(classLoader);
259         this.context = context;
260         this.cw = classVisitor;
261         this.sourceFile = sourceFile;
262
263         this.dummyClassWriter = new ClassWriter(true);
264         dummyGen = new DummyClassGenerator(context, dummyClassWriter, classLoader, sourceFile);
265
266     }
267
268     // GroovyClassVisitor interface
269
//-------------------------------------------------------------------------
270
public void visitClass(ClassNode classNode) {
271         // todo to be tested
272
// createDummyClass(classNode);
273

274         try {
275             syntheticStaticFields.clear();
276             this.classNode = classNode;
277             this.outermostClass = null;
278             this.internalClassName = BytecodeHelper.getClassInternalName(classNode.getName());
279
280             //System.out.println("Generating class: " + classNode.getName());
281

282             // lets check that the classes are all valid
283
classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class"));
284             String JavaDoc[] interfaces = classNode.getInterfaces();
285             for (int i = 0; i < interfaces.length; i++ ) {
286                 interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name");
287             }
288
289             this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
290
291             cw.visit(
292                 asmJDKVersion,
293                 classNode.getModifiers(),
294                 internalClassName,
295                 internalBaseClassName,
296                 BytecodeHelper.getClassInternalNames(classNode.getInterfaces()),
297                 sourceFile);
298
299             // set the optional enclosing method attribute of the current inner class
300
// br comment out once Groovy uses the latest CVS HEAD of ASM
301
// MethodNode enclosingMethod = classNode.getEnclosingMethod();
302
// String ownerName = BytecodeHelper.getClassInternalName(enclosingMethod.getDeclaringClass().getName());
303
// String descriptor = BytecodeHelper.getMethodDescriptor(enclosingMethod.getReturnType(), enclosingMethod.getParameters());
304
// EnclosingMethodAttribute attr = new EnclosingMethodAttribute(ownerName,enclosingMethod.getName(),descriptor);
305
// cw.visitAttribute(attr);
306

307             classNode.visitContents(this);
308
309             createSyntheticStaticFields();
310
311             for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
312                 ClassNode innerClass = (ClassNode) iter.next();
313                 String JavaDoc innerClassName = innerClass.getName();
314                 String JavaDoc innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
315                 String JavaDoc outerClassName = internalClassName; // default for inner classes
316
MethodNode enclosingMethod = innerClass.getEnclosingMethod();
317                 if (enclosingMethod != null) {
318                     // local inner classes do not specify the outer class name
319
outerClassName = null;
320                 }
321                 cw.visitInnerClass(
322                     innerClassInternalName,
323                     outerClassName,
324                     innerClassName,
325                     innerClass.getModifiers());
326             }
327 // br TODO an inner class should have an entry of itself
328
cw.visitEnd();
329         }
330         catch (GroovyRuntimeException e) {
331             e.setModule(classNode.getModule());
332             throw e;
333         }
334     }
335
336     // create a surrogate class that represents the classNode
337
// the surrogate has the "face" of the real class. It's used for
338
// type resolving "this"
339
private void createDummyClass(ClassNode classNode) {
340         dummyGen.visitClass(classNode);
341         byte[] code = dummyClassWriter.toByteArray();
342
343         ClassLoader JavaDoc parentLoader = getClass().getClassLoader();
344         GroovyClassLoader groovyLoader = new GroovyClassLoader(parentLoader);
345         Class JavaDoc theClass = groovyLoader.defineClass(classNode.getName(), code);
346
347         if (theClass != null) {
348             classCache.put(classNode.getName(), theClass);
349         }
350     }
351
352     public void visitConstructor(ConstructorNode node) {
353         // creates a MethodWriter for the (implicit) constructor
354
//String methodType = Type.getMethodDescriptor(VOID_TYPE, )
355

356         this.constructorNode = node;
357         this.methodNode = null;
358         this.variableScope = null;
359
360         visitParameters(node, node.getParameters());
361
362         String JavaDoc methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters());
363         cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null);
364         helper = new BytecodeHelper(cv);
365
366         findMutableVariables();
367         resetVariableStack(node.getParameters());
368
369         Statement code = node.getCode();
370         if (code == null || !firstStatementIsSuperInit(code)) {
371             // invokes the super class constructor
372
cv.visitVarInsn(ALOAD, 0);
373             cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "()V");
374         }
375         if (code != null) {
376             code.visit(this);
377         }
378
379         cv.visitInsn(RETURN);
380         cv.visitMaxs(0, 0);
381     }
382
383     public void visitMethod(MethodNode node) {
384         //System.out.println("Visiting method: " + node.getName() + " with
385
// return type: " + node.getReturnType());
386
this.constructorNode = null;
387         this.methodNode = node;
388         this.variableScope = null;
389
390         visitParameters(node, node.getParameters());
391         node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type"));
392
393         String JavaDoc methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
394         cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null);
395         Label labelStart = new Label();
396         cv.visitLabel(labelStart);
397         helper = new BytecodeHelper(cv);
398
399         findMutableVariables();
400         resetVariableStack(node.getParameters());
401
402
403         outputReturn = false;
404
405         node.getCode().visit(this);
406
407         if (!outputReturn) {
408             cv.visitInsn(RETURN);
409         }
410
411         // lets do all the exception blocks
412
for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) {
413             Runnable JavaDoc runnable = (Runnable JavaDoc) iter.next();
414             runnable.run();
415         }
416         exceptionBlocks.clear();
417
418         Label labelEnd = new Label();
419         cv.visitLabel(labelEnd);
420
421         // br experiment with local var table so debuggers can retrieve variable names
422
if (CREATE_DEBUG_INFO) {
423             Set vars = this.variableStack.keySet();
424             for (Iterator iterator = vars.iterator(); iterator.hasNext();) {
425                 String JavaDoc varName = (String JavaDoc) iterator.next();
426                 Variable v = (Variable)variableStack.get(varName);
427                 String JavaDoc type = v.getTypeName();
428                 type = BytecodeHelper.getTypeDescription(type);
429                 Label start = v.getStartLabel() != null ? v.getStartLabel() : labelStart;
430                 Label end = v.getEndLabel() != null ? v.getEndLabel() : labelEnd;
431                 cv.visitLocalVariable(varName, type, start, end, v.getIndex());
432             }
433         }
434         cv.visitMaxs(0, 0);
435     }
436
437     protected void visitParameters(ASTNode node, Parameter[] parameters) {
438         for (int i = 0, size = parameters.length; i < size; i++ ) {
439             visitParameter(node, parameters[i]);
440         }
441     }
442
443     protected void visitParameter(ASTNode node, Parameter parameter) {
444         if (! parameter.isDynamicType()) {
445             parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class"));
446         }
447     }
448
449     public void visitField(FieldNode fieldNode) {
450         onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
451
452         // lets check that the classes are all valid
453
fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName()));
454
455         //System.out.println("Visiting field: " + fieldNode.getName() + " on
456
// class: " + classNode.getName());
457

458         Object JavaDoc fieldValue = null;
459         Expression expression = fieldNode.getInitialValueExpression();
460         if (expression instanceof ConstantExpression) {
461             ConstantExpression constantExp = (ConstantExpression) expression;
462             Object JavaDoc value = constantExp.getValue();
463             if (isPrimitiveFieldType(fieldNode.getType())) {
464                 // lets convert any primitive types
465
Class JavaDoc type = null;
466                 try {
467                     type = loadClass(fieldNode.getType());
468                     fieldValue = /*InvokerHelper.*/asType(value, type);
469                 }
470                 catch (Exception JavaDoc e) {
471                     log.warning("Caught unexpected: " + e);
472                 }
473             }
474         }
475         cw.visitField(
476             fieldNode.getModifiers(),
477             fieldNode.getName(),
478             BytecodeHelper.getTypeDescription(fieldNode.getType()),
479             null, //fieldValue, //br all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
480
null);
481     }
482
483     /**
484      * Creates a getter, setter and field
485      */

486     public void visitProperty(PropertyNode statement) {
487         onLineNumber(statement, "visitProperty:" + statement.getField().getName());
488         //this.propertyNode = statement;
489
this.methodNode = null;
490     }
491
492     // GroovyCodeVisitor interface
493
//-------------------------------------------------------------------------
494

495     // Statements
496
//-------------------------------------------------------------------------
497

498     public void visitForLoop(ForStatement loop) {
499         onLineNumber(loop, "visitForLoop");
500         Class JavaDoc elemType = null;
501         if (ENABLE_EARLY_BINDING) {
502             Expression collectionExp = loop.getCollectionExpression();
503             collectionExp.resolve(this);
504             Class JavaDoc cls = collectionExp.getTypeClass();
505             if (cls != null) {
506                 if (cls.isArray()) {
507                     elemType = cls.getComponentType();
508                     if (elemType != null) {
509                         Type varType = new Type(elemType.getName());
510                         loop.setVariableType(varType);
511                     }
512                 }
513                 else if (collectionExp instanceof ListExpression) {
514                     elemType = ((ListExpression)collectionExp).getComponentTypeClass();
515                     if (elemType != null) {
516                         Type varType = new Type(elemType.getName());
517                         loop.setVariableType(varType);
518                     }
519                 }
520                 else if (collectionExp instanceof RangeExpression) {
521                     // use the from type class. assuming both from and to are of the same type
522
elemType = ((RangeExpression)collectionExp).getFrom().getTypeClass();
523                     if (elemType != null) {
524                         Type varType = new Type(elemType.getName());
525                         loop.setVariableType(varType);
526                     }
527                 }
528             }
529         }
530
531
532         //
533
// Declare the loop counter.
534
Type variableType = checkValidType(loop.getVariableType(), loop, "for loop variable");
535         Variable variable = defineVariable(loop.getVariable(), variableType, true);
536
537         if( isInScriptBody() ) {
538             variable.setProperty( true );
539         }
540
541
542         //
543
// Then initialize the iterator and generate the loop control
544

545         loop.getCollectionExpression().visit(this);
546
547         asIteratorMethod.call(cv);
548
549         final Variable iterTemp = storeInTemp("iterator", "java.util.Iterator");
550         final int iteratorIdx = iterTemp.getIndex();
551
552         // to push scope here allows the iterator available after the loop, such as the i in: for (i in 1..5)
553
// move it to the top will make the iterator a local var in the for loop.
554
pushBlockScope();
555
556         Label continueLabel = scope.getContinueLabel();
557         cv.visitJumpInsn(GOTO, continueLabel);
558         Label label2 = new Label();
559         cv.visitLabel(label2);
560
561         final Class JavaDoc elemClass = elemType;
562         BytecodeExpression expression = new BytecodeExpression() {
563             public void visit(GroovyCodeVisitor visitor) {
564                 cv.visitVarInsn(ALOAD, iteratorIdx);
565                 iteratorNextMethod.call(cv);
566             }
567
568             protected void resolveType(AsmClassGenerator2 resolver) {
569                 setTypeClass(elemClass);
570             }
571         };
572
573         evaluateEqual( BinaryExpression.newAssignmentExpression(loop.getVariable(), expression) );
574         cv.visitInsn(POP); // br now the evaluateEqual() will leave a value on the stack. pop it.
575

576         //
577
// Generate the loop body
578

579         loop.getLoopBlock().visit(this);
580
581
582         //
583
// Generate the loop tail
584

585         cv.visitLabel(continueLabel);
586         cv.visitVarInsn(ALOAD, iteratorIdx);
587
588         iteratorHasNextMethod.call(cv);
589
590         cv.visitJumpInsn(IFNE, label2);
591
592         cv.visitLabel(scope.getBreakLabel());
593         popScope();
594     }
595
596     public void visitWhileLoop(WhileStatement loop) {
597         onLineNumber(loop, "visitWhileLoop");
598
599         pushBlockScope();
600
601         Label continueLabel = scope.getContinueLabel();
602
603         cv.visitJumpInsn(GOTO, continueLabel);
604         Label l1 = new Label();
605         cv.visitLabel(l1);
606
607         loop.getLoopBlock().visit(this);
608
609         cv.visitLabel(continueLabel);
610
611         loop.getBooleanExpression().visit(this);
612
613         cv.visitJumpInsn(IFNE, l1);
614
615         cv.visitLabel(scope.getBreakLabel());
616         popScope();
617     }
618
619     public void visitDoWhileLoop(DoWhileStatement loop) {
620         onLineNumber(loop, "visitDoWhileLoop");
621
622         pushBlockScope();
623
624         Label breakLabel = scope.getBreakLabel();
625
626         Label continueLabel = scope.getContinueLabel();
627         cv.visitLabel(continueLabel);
628         Label l1 = new Label();
629
630         loop.getLoopBlock().visit(this);
631
632         cv.visitLabel(l1);
633
634         loop.getBooleanExpression().visit(this);
635
636         cv.visitJumpInsn(IFNE, continueLabel);
637
638         cv.visitLabel(breakLabel);
639         popScope();
640     }
641
642     public void visitIfElse(IfStatement ifElse) {
643         onLineNumber(ifElse, "visitIfElse");
644
645         ifElse.getBooleanExpression().visit(this);
646
647         Label l0 = new Label();
648         cv.visitJumpInsn(IFEQ, l0);
649         pushBlockScope(false, false);
650         ifElse.getIfBlock().visit(this);
651         popScope();
652
653         Label l1 = new Label();
654         cv.visitJumpInsn(GOTO, l1);
655         cv.visitLabel(l0);
656
657         pushBlockScope(false, false);
658         ifElse.getElseBlock().visit(this);
659         cv.visitLabel(l1);
660         popScope();
661     }
662
663     public void visitTernaryExpression(TernaryExpression expression) {
664         onLineNumber(expression, "visitTernaryExpression");
665
666         expression.getBooleanExpression().visit(this);
667
668         Label l0 = new Label();
669         cv.visitJumpInsn(IFEQ, l0);
670         expression.getTrueExpression().visit(this);
671
672         Label l1 = new Label();
673         cv.visitJumpInsn(GOTO, l1);
674         cv.visitLabel(l0);
675
676         expression.getFalseExpression().visit(this);
677         cv.visitLabel(l1);
678     }
679
680     public void visitAssertStatement(AssertStatement statement) {
681         onLineNumber(statement, "visitAssertStatement");
682
683         //System.out.println("Assert: " + statement.getLineNumber() + " for: "
684
// + statement.getText());
685

686         BooleanExpression booleanExpression = statement.getBooleanExpression();
687         booleanExpression.visit(this);
688
689         Label l0 = new Label();
690         cv.visitJumpInsn(IFEQ, l0);
691
692         // do nothing
693

694         Label l1 = new Label();
695         cv.visitJumpInsn(GOTO, l1);
696         cv.visitLabel(l0);
697
698         // push expression string onto stack
699
String JavaDoc expressionText = booleanExpression.getText();
700         List list = new ArrayList();
701         addVariableNames(booleanExpression, list);
702         if (list.isEmpty()) {
703             cv.visitLdcInsn(expressionText);
704         }
705         else {
706             boolean first = true;
707
708             // lets create a new expression
709
cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
710             cv.visitInsn(DUP);
711             cv.visitLdcInsn(expressionText + ". Values: ");
712
713             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
714
715             Variable assertTemp = visitASTOREInTemp("assert");
716             int tempIndex = assertTemp.getIndex();
717
718             for (Iterator iter = list.iterator(); iter.hasNext();) {
719                 String JavaDoc name = (String JavaDoc) iter.next();
720                 String JavaDoc text = name + " = ";
721                 if (first) {
722                     first = false;
723                 }
724                 else {
725                     text = ", " + text;
726                 }
727
728                 cv.visitVarInsn(ALOAD, tempIndex);
729                 cv.visitLdcInsn(text);
730                 cv.visitMethodInsn(
731                     INVOKEVIRTUAL,
732                     "java/lang/StringBuffer",
733                     "append",
734                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
735                 cv.visitInsn(POP);
736
737                 cv.visitVarInsn(ALOAD, tempIndex);
738                 new VariableExpression(name).visit(this);
739                 cv.visitMethodInsn(
740                     INVOKEVIRTUAL,
741                     "java/lang/StringBuffer",
742                     "append",
743                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
744                 cv.visitInsn(POP);
745
746             }
747             cv.visitVarInsn(ALOAD, tempIndex);
748             removeVar(assertTemp);
749         }
750         // now the optional exception expression
751
statement.getMessageExpression().visit(this);
752
753         assertFailedMethod.call(cv);
754         cv.visitLabel(l1);
755     }
756
757     private void addVariableNames(Expression expression, List list) {
758         if (expression instanceof BooleanExpression) {
759             BooleanExpression boolExp = (BooleanExpression) expression;
760             addVariableNames(boolExp.getExpression(), list);
761         }
762         else if (expression instanceof BinaryExpression) {
763             BinaryExpression binExp = (BinaryExpression) expression;
764             addVariableNames(binExp.getLeftExpression(), list);
765             addVariableNames(binExp.getRightExpression(), list);
766         }
767         else if (expression instanceof VariableExpression) {
768             VariableExpression varExp = (VariableExpression) expression;
769             list.add(varExp.getVariable());
770         }
771     }
772
773     public void visitTryCatchFinally(TryCatchStatement statement) {
774         onLineNumber(statement, "visitTryCatchFinally");
775 // todo need to add blockscope handling
776
CatchStatement catchStatement = statement.getCatchStatement(0);
777
778         Statement tryStatement = statement.getTryStatement();
779
780         if (tryStatement.isEmpty() || catchStatement == null) {
781             final Label l0 = new Label();
782             cv.visitLabel(l0);
783
784             tryStatement.visit(this);
785
786
787             int index1 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
788             int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
789
790             final Label l1 = new Label();
791             cv.visitJumpInsn(JSR, l1);
792             final Label l2 = new Label();
793             cv.visitLabel(l2);
794             final Label l3 = new Label();
795             cv.visitJumpInsn(GOTO, l3);
796             final Label l4 = new Label();
797             cv.visitLabel(l4);
798             cv.visitVarInsn(ASTORE, index1);
799             cv.visitJumpInsn(JSR, l1);
800             final Label l5 = new Label();
801             cv.visitLabel(l5);
802             cv.visitVarInsn(ALOAD, index1);
803             cv.visitInsn(ATHROW);
804             cv.visitLabel(l1);
805             cv.visitVarInsn(ASTORE, index2);
806
807             statement.getFinallyStatement().visit(this);
808
809             cv.visitVarInsn(RET, index2);
810             cv.visitLabel(l3);
811
812             exceptionBlocks.add(new Runnable JavaDoc() {
813                 public void run() {
814                     cv.visitTryCatchBlock(l0, l2, l4, null);
815                     cv.visitTryCatchBlock(l4, l5, l4, null);
816                 }
817             });
818
819         }
820         else {
821             String JavaDoc exceptionVar = catchStatement.getVariable();
822             String JavaDoc exceptionType =
823                 checkValidType(catchStatement.getExceptionType(), catchStatement, "in catch statement");
824
825             int exceptionIndex = defineVariable(exceptionVar, exceptionType, false).getIndex();
826             int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
827             int index3 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
828
829             final Label l0 = new Label();
830             cv.visitLabel(l0);
831
832             tryStatement.visit(this);
833
834             final Label l1 = new Label();
835             cv.visitLabel(l1);
836             Label l2 = new Label();
837             cv.visitJumpInsn(JSR, l2);
838             final Label l3 = new Label();
839             cv.visitLabel(l3);
840             Label l4 = new Label();
841             cv.visitJumpInsn(GOTO, l4);
842             final Label l5 = new Label();
843             cv.visitLabel(l5);
844
845             cv.visitVarInsn(ASTORE, exceptionIndex);
846
847             if (catchStatement != null) {
848                 catchStatement.visit(this);
849             }
850
851             cv.visitJumpInsn(JSR, l2);
852             final Label l6 = new Label();
853             cv.visitLabel(l6);
854             cv.visitJumpInsn(GOTO, l4);
855
856             final Label l7 = new Label();
857             cv.visitLabel(l7);
858             cv.visitVarInsn(ASTORE, index2);
859             cv.visitJumpInsn(JSR, l2);
860
861             final Label l8 = new Label();
862             cv.visitLabel(l8);
863             cv.visitVarInsn(ALOAD, index2);
864             cv.visitInsn(ATHROW);
865             cv.visitLabel(l2);
866             cv.visitVarInsn(ASTORE, index3);
867
868             statement.getFinallyStatement().visit(this);
869
870             cv.visitVarInsn(RET, index3);
871             cv.visitLabel(l4);
872
873             // rest of code goes here...
874

875             //final String exceptionTypeInternalName = (catchStatement !=
876
// null) ?
877
// getTypeDescription(exceptionType) : null;
878
final String JavaDoc exceptionTypeInternalName =
879                 (catchStatement != null) ? BytecodeHelper.getClassInternalName(exceptionType) : null;
880
881             exceptionBlocks.add(new Runnable JavaDoc() {
882                 public void run() {
883                     cv.visitTryCatchBlock(l0, l1, l5, exceptionTypeInternalName);
884                     cv.visitTryCatchBlock(l0, l3, l7, null);
885                     cv.visitTryCatchBlock(l5, l6, l7, null);
886                     cv.visitTryCatchBlock(l7, l8, l7, null);
887                 }
888             });
889         }
890     }
891
892     private Variable storeInTemp(String JavaDoc name, String JavaDoc type) {
893         Variable var = defineVariable(createVariableName(name), type, false);
894         int varIdx = var.getIndex();
895         cv.visitVarInsn(ASTORE, varIdx);
896         if (CREATE_DEBUG_INFO) cv.visitLabel(var.getStartLabel());
897         return var;
898     }
899
900     public void visitSwitch(SwitchStatement statement) {
901         onLineNumber(statement, "visitSwitch");
902
903         statement.getExpression().visit(this);
904
905         // switch does not have a continue label. use its parent's for continue
906
pushBlockScope(false, true);
907         //scope.setContinueLabel(scope.getParent().getContinueLabel());
908

909
910         int switchVariableIndex = defineVariable(createVariableName("switch"), "java.lang.Object").getIndex();
911         cv.visitVarInsn(ASTORE, switchVariableIndex);
912
913         List caseStatements = statement.getCaseStatements();
914         int caseCount = caseStatements.size();
915         Label[] labels = new Label[caseCount + 1];
916         for (int i = 0; i < caseCount; i++) {
917             labels[i] = new Label();
918         }
919
920         int i = 0;
921         for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
922             CaseStatement caseStatement = (CaseStatement) iter.next();
923             visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
924         }
925
926         statement.getDefaultStatement().visit(this);
927
928         cv.visitLabel(scope.getBreakLabel());
929
930         popScope();
931     }
932
933     public void visitCaseStatement(CaseStatement statement) {
934     }
935
936     public void visitCaseStatement(
937         CaseStatement statement,
938         int switchVariableIndex,
939         Label thisLabel,
940         Label nextLabel) {
941
942         onLineNumber(statement, "visitCaseStatement");
943
944         cv.visitVarInsn(ALOAD, switchVariableIndex);
945         statement.getExpression().visit(this);
946
947         isCaseMethod.call(cv);
948
949         Label l0 = new Label();
950         cv.visitJumpInsn(IFEQ, l0);
951
952         cv.visitLabel(thisLabel);
953
954         statement.getCode().visit(this);
955
956         // now if we don't finish with a break we need to jump past
957
// the next comparison
958
if (nextLabel != null) {
959             cv.visitJumpInsn(GOTO, nextLabel);
960         }
961
962         cv.visitLabel(l0);
963     }
964
965     public void visitBreakStatement(BreakStatement statement) {
966         onLineNumber(statement, "visitBreakStatement");
967
968         Label breakLabel = scope.getBreakLabel();
969         if (breakLabel != null ) {
970             cv.visitJumpInsn(GOTO, breakLabel);
971         } else {
972             // should warn that break is not allowed in the context.
973
}
974     }
975
976     public void visitContinueStatement(ContinueStatement statement) {
977         onLineNumber(statement, "visitContinueStatement");
978
979         Label continueLabel = scope.getContinueLabel();
980         if (continueLabel != null ) {
981             cv.visitJumpInsn(GOTO, continueLabel);
982         } else {
983             // should warn that continue is not allowed in the context.
984
}
985     }
986
987     public void visitSynchronizedStatement(SynchronizedStatement statement) {
988         onLineNumber(statement, "visitSynchronizedStatement");
989
990         statement.getExpression().visit(this);
991
992         int index = defineVariable(createVariableName("synchronized"), "java.lang.Integer").getIndex();
993
994         cv.visitVarInsn(ASTORE, index);
995         cv.visitInsn(MONITORENTER);
996         final Label l0 = new Label();
997         cv.visitLabel(l0);
998
999         statement.getCode().visit(this);
1000
1001        cv.visitVarInsn(ALOAD, index);
1002        cv.visitInsn(MONITOREXIT);
1003        final Label l1 = new Label();
1004        cv.visitJumpInsn(GOTO, l1);
1005        final Label l2 = new Label();
1006        cv.visitLabel(l2);
1007        cv.visitVarInsn(ALOAD, index);
1008        cv.visitInsn(MONITOREXIT);
1009        cv.visitInsn(ATHROW);
1010        cv.visitLabel(l1);
1011
1012        exceptionBlocks.add(new Runnable JavaDoc() {
1013            public void run() {
1014                cv.visitTryCatchBlock(l0, l2, l2, null);
1015            }
1016        });
1017    }
1018
1019    public void visitThrowStatement(ThrowStatement statement) {
1020        statement.getExpression().visit(this);
1021
1022        // we should infer the type of the exception from the expression
1023
cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
1024
1025        cv.visitInsn(ATHROW);
1026    }
1027
1028    public void visitReturnStatement(ReturnStatement statement) {
1029        onLineNumber(statement, "visitReturnStatement");
1030        String JavaDoc returnType = methodNode.getReturnType();
1031        if (returnType.equals("void")) {
1032            if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) {
1033                throwException("Cannot use return statement with an expression on a method that returns void");
1034            }
1035            cv.visitInsn(RETURN);
1036            outputReturn = true;
1037            return;
1038        }
1039
1040        Expression expression = statement.getExpression();
1041        evaluateExpression(expression);
1042        if (returnType.equals("java.lang.Object") && expression.getType() != null && expression.getType().equals("void")) {
1043            cv.visitInsn(ACONST_NULL); // cheat the caller
1044
cv.visitInsn(ARETURN);
1045        } else {
1046            //return is based on class type
1047
//TODO: make work with arrays
1048
// we may need to cast
1049
helper.unbox(returnType);
1050            if (returnType.equals("double")) {
1051                cv.visitInsn(DRETURN);
1052            }
1053            else if (returnType.equals("float")) {
1054                cv.visitInsn(FRETURN);
1055            }
1056            else if (returnType.equals("long")) {
1057                cv.visitInsn(LRETURN);
1058            }
1059            else if (returnType.equals("boolean")) {
1060                cv.visitInsn(IRETURN);
1061            }
1062            else if (
1063                    returnType.equals("char")
1064                    || returnType.equals("byte")
1065                    || returnType.equals("int")
1066                    || returnType.equals("short")) { //byte,short,boolean,int are
1067
// all IRETURN
1068
cv.visitInsn(IRETURN);
1069            }
1070            else {
1071                doConvertAndCast(returnType, expression);
1072                cv.visitInsn(ARETURN);
1073
1074                /*
1075                if (c == Boolean.class) {
1076                Label l0 = new Label();
1077                cv.visitJumpInsn(IFEQ, l0);
1078                cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
1079                cv.visitInsn(ARETURN);
1080                cv.visitLabel(l0);
1081                cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
1082                cv.visitInsn(ARETURN);
1083                }
1084                else {
1085                if (isValidTypeForCast(returnType) && !returnType.equals(c.getName())) {
1086                doConvertAndCast(returnType, expression);
1087                }
1088                cv.visitInsn(ARETURN);
1089                }
1090                */

1091            }
1092        }
1093        outputReturn = true;
1094    }
1095
1096    /**
1097     * Casts to the given type unless it can be determined that the cast is unnecessary
1098     */

1099    protected void doConvertAndCast(String JavaDoc type, Expression expression) {
1100        String JavaDoc expType = getExpressionType(expression);
1101        // temp resolution: convert all primitive casting to corresponsing Object type
1102
if (BytecodeHelper.isPrimitiveType(type)) {
1103            type = BytecodeHelper.getObjectTypeForPrimitive(type);
1104        }
1105        if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) {
1106            doConvertAndCast(type);
1107        }
1108    }
1109
1110    /**
1111     * @param expression
1112     */

1113    protected void evaluateExpression(Expression expression) {
1114        visitAndAutoboxBoolean(expression);
1115        //expression.visit(this);
1116

1117        Expression assignExpr = createReturnLHSExpression(expression);
1118        if (assignExpr != null) {
1119            leftHandExpression = false;
1120            assignExpr.visit(this);
1121        }
1122    }
1123
1124    public void visitExpressionStatement(ExpressionStatement statement) {
1125        onLineNumber(statement, "visitExpressionStatement: " + statement.getExpression().getClass().getName());
1126
1127        Expression expression = statement.getExpression();
1128// disabled in favor of JIT resolving
1129
// if (ENABLE_EARLY_BINDING)
1130
// expression.resolve(this);
1131

1132        visitAndAutoboxBoolean(expression);
1133
1134        if (isPopRequired(expression)) {
1135            cv.visitInsn(POP);
1136        }
1137    }
1138
1139    // Expressions
1140
//-------------------------------------------------------------------------
1141

1142    public void visitBinaryExpression(BinaryExpression expression) {
1143        onLineNumber(expression, "visitBinaryExpression: \"" + expression.getOperation().getText() + "\" ");
1144        switch (expression.getOperation().getType()) {
1145            case Types.EQUAL : // = assignment
1146
evaluateEqual(expression);
1147                break;
1148
1149            case Types.COMPARE_IDENTICAL : // ===
1150
evaluateBinaryExpression(compareIdenticalMethod, expression);
1151                break;
1152
1153            case Types.COMPARE_EQUAL : // ==
1154
evaluateBinaryExpression(compareEqualMethod, expression);
1155                break;
1156
1157            case Types.COMPARE_NOT_EQUAL :
1158                evaluateBinaryExpression(compareNotEqualMethod, expression);
1159                break;
1160
1161            case Types.COMPARE_TO :
1162                evaluateCompareTo(expression);
1163                break;
1164
1165            case Types.COMPARE_GREATER_THAN :
1166                evaluateBinaryExpression(compareGreaterThanMethod, expression);
1167                break;
1168
1169            case Types.COMPARE_GREATER_THAN_EQUAL :
1170                evaluateBinaryExpression(compareGreaterThanEqualMethod, expression);
1171                break;
1172
1173            case Types.COMPARE_LESS_THAN :
1174                evaluateBinaryExpression(compareLessThanMethod, expression);
1175                break;
1176
1177            case Types.COMPARE_LESS_THAN_EQUAL :
1178                evaluateBinaryExpression(compareLessThanEqualMethod, expression);
1179                break;
1180
1181            case Types.LOGICAL_AND :
1182                evaluateLogicalAndExpression(expression);
1183                break;
1184
1185            case Types.LOGICAL_OR :
1186                evaluateLogicalOrExpression(expression);
1187                break;
1188
1189            case Types.PLUS :
1190                {
1191                    if (ENABLE_EARLY_BINDING) {
1192                        expression.resolve(this);
1193                        if (expression.isResolveFailed() || !expression.isTypeResolved()) {
1194                            evaluateBinaryExpression("plus", expression);
1195                            break;
1196                        }
1197                        Expression leftExpression = expression.getLeftExpression();
1198                        Expression rightExpression = expression.getRightExpression();
1199                        Class JavaDoc lclass = leftExpression.getTypeClass();
1200                        Class JavaDoc rclass = rightExpression.getTypeClass();
1201                        if (lclass == null || rclass == null) {
1202                            evaluateBinaryExpression("plus", expression);
1203                            break;
1204                        }
1205                        if (lclass == String JavaDoc.class && rclass == String JavaDoc.class) {
1206// MethodCallExpression call = new MethodCallExpression(
1207
// leftExpression,
1208
// "concat",
1209
// new ArgumentListExpression(new Expression[] {rightExpression}));
1210
// call.setTypeClass(String.class); // must do to avoid excessive resolving
1211
// visitMethodCallExpression(call);
1212
cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
1213                            cv.visitInsn(DUP);
1214                            cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
1215                            load(leftExpression);
1216                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
1217                            load(rightExpression);
1218                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
1219                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
1220                        }
1221                        else if (lclass == String JavaDoc.class && Number JavaDoc.class.isAssignableFrom(rclass) ) {
1222                            cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
1223                            cv.visitInsn(DUP);
1224                            cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
1225                            load(leftExpression);
1226                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
1227                            load(rightExpression);
1228                            // will Object.toString() work here?
1229
cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
1230                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
1231                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
1232                        }
1233                        else if (rclass == String JavaDoc.class && Number JavaDoc.class.isAssignableFrom(lclass) ) {
1234                            cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
1235                            cv.visitInsn(DUP);
1236                            cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
1237                            load(leftExpression);
1238                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
1239                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
1240                            load(rightExpression);
1241                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); // note the arg is object type for safety
1242
cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
1243                        }
1244                        else if ((lclass == Integer JavaDoc.class || lclass == int.class) && (rclass == Integer JavaDoc.class || rclass == int.class)) {
1245                            // assuming all return boxed version for primitives
1246
load(leftExpression);
1247                            helper.quickUnboxIfNecessary(int.class);
1248                            load(rightExpression);
1249                            helper.quickUnboxIfNecessary(int.class);
1250                            cv.visitInsn(IADD);
1251                            helper.quickBoxIfNecessary(int.class);
1252                        }
1253                        else if (Number JavaDoc.class.isAssignableFrom(lclass) && Number JavaDoc.class.isAssignableFrom(rclass)) {
1254                            // let's use groovy utilities in the DefaultGroovyMethods
1255
load(leftExpression);
1256                            load(rightExpression);
1257                            cv.visitMethodInsn(
1258                                    INVOKESTATIC,
1259                                    BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1260                                    "plus",
1261                                    "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
1262                        }
1263                        else { // todo add more more number optimiztion
1264
evaluateBinaryExpression("plus", expression);
1265                        }
1266
1267                    } else {
1268                        evaluateBinaryExpression("plus", expression);
1269                    }
1270                }
1271                break;
1272
1273            case Types.PLUS_EQUAL :
1274                evaluateBinaryExpressionWithAsignment("plus", expression);
1275                break;
1276            case Types.MINUS :
1277                {
1278                    if (ENABLE_EARLY_BINDING) {
1279                        expression.resolve(this);
1280                        if (expression.isResolveFailed() || !expression.isTypeResolved()) {
1281                            evaluateBinaryExpression("minus", expression);
1282                            break;
1283                        }
1284                        Expression leftExpression = expression.getLeftExpression();
1285                        Expression rightExpression = expression.getRightExpression();
1286                        Class JavaDoc lclass = leftExpression.getTypeClass();
1287                        Class JavaDoc rclass = rightExpression.getTypeClass();
1288                        if (lclass == null || rclass == null) {
1289                            evaluateBinaryExpression("minus", expression);
1290                            break;
1291                        }
1292                        if ((lclass == Integer JavaDoc.class || lclass == int.class) && (rclass == Integer JavaDoc.class || rclass == int.class)) {
1293                            // assuming all return boxed version for primitives
1294
load(leftExpression);
1295                            helper.quickUnboxIfNecessary(int.class);
1296                            load(rightExpression);
1297                            helper.quickUnboxIfNecessary(int.class);
1298                            cv.visitInsn(ISUB);
1299                            helper.quickBoxIfNecessary(int.class);
1300                        }
1301                        else
1302                        if (Number JavaDoc.class.isAssignableFrom(lclass) && Number JavaDoc.class.isAssignableFrom(rclass)) {
1303                            // let's use groovy utilities in the DefaultGroovyMethods
1304
load(leftExpression);
1305                            load(rightExpression);
1306                            cv.visitMethodInsn(
1307                                    INVOKESTATIC,
1308                                    BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1309                                    "minus",
1310                                    "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
1311                        }
1312                        else { // todo add more more number optimiztion
1313
evaluateBinaryExpression("minus", expression);
1314                        }
1315                    } else {
1316                        evaluateBinaryExpression("minus", expression);
1317                    }
1318                }
1319                break;
1320            case Types.MINUS_EQUAL :
1321                evaluateBinaryExpressionWithAsignment("minus", expression);
1322                break;
1323
1324            case Types.MULTIPLY :
1325                {
1326                    if (ENABLE_EARLY_BINDING) {
1327                        expression.resolve(this);
1328                        if (expression.isResolveFailed() || !expression.isTypeResolved()) {
1329                            evaluateBinaryExpression("multiply", expression);
1330                            break;
1331                        }
1332                        Expression leftExpression = expression.getLeftExpression();
1333                        Expression rightExpression = expression.getRightExpression();
1334                        Class JavaDoc lclass = leftExpression.getTypeClass();
1335                        Class JavaDoc rclass = rightExpression.getTypeClass();
1336                        if (lclass == null || rclass == null) {
1337                            evaluateBinaryExpression("multiply", expression);
1338                            break;
1339                        }
1340                        if ((lclass == Integer JavaDoc.class || lclass == int.class) && (rclass == Integer JavaDoc.class || rclass == int.class)) {
1341                            // assuming all return boxed version for primitives
1342
load(leftExpression);
1343                            helper.quickUnboxIfNecessary(int.class);
1344                            load(rightExpression);
1345                            helper.quickUnboxIfNecessary(int.class);
1346                            cv.visitInsn(IMUL);
1347                            helper.quickBoxIfNecessary(int.class);
1348                        }
1349                        else if (Number JavaDoc.class.isAssignableFrom(lclass) && Number JavaDoc.class.isAssignableFrom(rclass)) {
1350                            // let's use groovy utilities in the DefaultGroovyMethods
1351
load(leftExpression);
1352                            load(rightExpression);
1353                            cv.visitMethodInsn(
1354                                    INVOKESTATIC,
1355                                    BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1356                                    "multiply",
1357                                    "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
1358                        }
1359                        else { // todo add more more number optimiztion
1360
evaluateBinaryExpression("multiply", expression);
1361                        }
1362                    } else {
1363                        evaluateBinaryExpression("multiply", expression);
1364                    }
1365                }
1366
1367                break;
1368
1369            case Types.MULTIPLY_EQUAL :
1370                evaluateBinaryExpressionWithAsignment("multiply", expression);
1371                break;
1372
1373            case Types.DIVIDE :
1374                //SPG don't use divide since BigInteger implements directly
1375
//and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
1376
{
1377                    if (ENABLE_EARLY_BINDING) {
1378                        expression.resolve(this);
1379                        if (expression.isResolveFailed() || !expression.isTypeResolved()) {
1380                            evaluateBinaryExpression("div", expression);
1381                            break;
1382                        }
1383                        Expression leftExpression = expression.getLeftExpression();
1384                        Expression rightExpression = expression.getRightExpression();
1385                        Class JavaDoc lclass = leftExpression.getTypeClass();
1386                        Class JavaDoc rclass = rightExpression.getTypeClass();
1387                        if (lclass == null || rclass == null) {
1388                            evaluateBinaryExpression("div", expression);
1389                            break;
1390                        }
1391//
1392
// if ((lclass == Integer.class || lclass == int.class) && (rclass == Integer.class || rclass == int.class)) {
1393
// // assuming all return boxed version for primitives
1394
// load(leftExpression);
1395
// helper.quickUnboxIfNecessary(int.class);
1396
// cv.visitInsn(I2D);
1397
// load(rightExpression);
1398
// helper.quickUnboxIfNecessary(int.class);
1399
// cv.visitInsn(I2D);
1400
// cv.visitInsn(DDIV);
1401
// helper.quickBoxIfNecessary(double.class);
1402
// }
1403
// else
1404
if (Number JavaDoc.class.isAssignableFrom(lclass) && Number JavaDoc.class.isAssignableFrom(rclass)) {
1405                            // let's use groovy utilities in the DefaultGroovyMethods
1406
load(leftExpression);
1407                            load(rightExpression);
1408                            cv.visitMethodInsn(
1409                                    INVOKESTATIC,
1410                                    BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1411                                    "div",
1412                                    "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
1413                        }
1414                        else { // todo add more more number optimiztion
1415
evaluateBinaryExpression("div", expression);
1416                        }
1417                    } else {
1418                        evaluateBinaryExpression("div", expression);
1419                    }
1420                }
1421
1422                break;
1423
1424            case Types.DIVIDE_EQUAL :
1425                //SPG don't use divide since BigInteger implements directly
1426
//and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
1427
evaluateBinaryExpressionWithAsignment("div", expression);
1428                break;
1429
1430            case Types.INTDIV :
1431                {
1432                    if (ENABLE_EARLY_BINDING) {
1433                        expression.resolve(this);
1434                        if (expression.isResolveFailed() || !expression.isTypeResolved()) {
1435                            evaluateBinaryExpression("intdiv", expression);
1436                            break;
1437                        }
1438                        Expression leftExpression = expression.getLeftExpression();
1439                        Expression rightExpression = expression.getRightExpression();
1440                        Class JavaDoc lclass = leftExpression.getTypeClass();
1441                        Class JavaDoc rclass = rightExpression.getTypeClass();
1442                        if (lclass == null || rclass == null) {
1443                            evaluateBinaryExpression("intdiv", expression);
1444                            break;
1445                        }
1446                        if (Number JavaDoc.class.isAssignableFrom(lclass) && Number JavaDoc.class.isAssignableFrom(rclass)) {
1447                            // let's use groovy utilities in the DefaultGroovyMethods
1448
load(leftExpression);
1449                            load(rightExpression);
1450                            cv.visitMethodInsn(
1451                                    INVOKESTATIC,
1452                                    BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1453                                    "intdiv",
1454                                    "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;");
1455                        }
1456                        else { // todo add more more number optimiztion
1457
evaluateBinaryExpression("intdiv", expression);
1458                        }
1459                    } else {
1460                        evaluateBinaryExpression("intdiv", expression);
1461                    }
1462                }
1463                break;
1464
1465            case Types.INTDIV_EQUAL :
1466                evaluateBinaryExpressionWithAsignment("intdiv", expression);
1467                break;
1468
1469            case Types.MOD :
1470                evaluateBinaryExpression("mod", expression);
1471                break;
1472
1473            case Types.MOD_EQUAL :
1474                evaluateBinaryExpressionWithAsignment("mod", expression);
1475                break;
1476
1477            case Types.LEFT_SHIFT :
1478                evaluateBinaryExpression("leftShift", expression);
1479                break;
1480
1481            case Types.RIGHT_SHIFT :
1482                evaluateBinaryExpression("rightShift", expression);
1483                break;
1484
1485            case Types.RIGHT_SHIFT_UNSIGNED :
1486                evaluateBinaryExpression("rightShiftUnsigned", expression);
1487                break;
1488
1489            case Types.KEYWORD_INSTANCEOF :
1490                evaluateInstanceof(expression);
1491                break;
1492
1493            case Types.FIND_REGEX :
1494                evaluateBinaryExpression(findRegexMethod, expression);
1495                break;
1496
1497            case Types.MATCH_REGEX :
1498                evaluateBinaryExpression(matchRegexMethod, expression);
1499                break;
1500
1501            case Types.LEFT_SQUARE_BRACKET :
1502                if (leftHandExpression) {
1503                    throwException("Should not be called here. Possible reason: postfix operation on array.");
1504                    // This is handled right now in the evaluateEqual()
1505
// should support this here later
1506
//evaluateBinaryExpression("putAt", expression);
1507
}
1508                else if (ENABLE_EARLY_BINDING) {
1509                    expression.resolve(this);
1510                    if (expression.isResolveFailed() || !expression.isTypeResolved()) {
1511                        evaluateBinaryExpression("getAt", expression);
1512                        break;
1513                    }
1514                    Expression leftExpression = expression.getLeftExpression();
1515                    Expression rightExpression = expression.getRightExpression();
1516                    Class JavaDoc lclass = leftExpression.getTypeClass();
1517                    Class JavaDoc rclass = rightExpression.getTypeClass();
1518                    if (lclass == null || rclass == null) {
1519                        evaluateBinaryExpression("getAt", expression);
1520                        break;
1521                    }
1522                    if (lclass == String JavaDoc.class && rclass == Integer JavaDoc.class) {
1523                        load(leftExpression); cast(String JavaDoc.class);
1524                        load(rightExpression); helper.quickUnboxIfNecessary(int.class);
1525                        cv.visitMethodInsn(
1526                                INVOKESTATIC,
1527                                BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1528                                "getAt",
1529                                "([Ljava/lang/String;I)Ljava/lang/String;");
1530                        break;
1531                    }
1532                    else if (lclass.isArray() && rclass == Integer JavaDoc.class) {
1533                        load(leftExpression); // cast it?
1534
load(rightExpression); helper.quickUnboxIfNecessary(int.class);
1535                        Class JavaDoc elemType = lclass.getComponentType();
1536                        if (!elemType.isPrimitive()) {
1537                            cv.visitMethodInsn(
1538                                    INVOKESTATIC,
1539                                    BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1540                                    "getAt",
1541                                    "([Ljava/lang/Object;I)Ljava/lang/Object;");
1542                            cast(elemType);
1543                        }
1544                        else {
1545                            evaluateBinaryExpression("getAt", expression); // todo more optim
1546
}
1547                        break;
1548                    }
1549                    else if (List.class == lclass && rclass == Integer JavaDoc.class){
1550                        // there is special logic in treating list subscript
1551
load(leftExpression); cast(List.class);
1552                        load(rightExpression); helper.quickUnboxIfNecessary(int.class);
1553                            //INVOKESTATIC org/codehaus/groovy/runtime/DefaultGroovyMethods getAt (Ljava/util/List;I)Ljava/lang/Object;
1554
cv.visitMethodInsn(
1555                                INVOKESTATIC,
1556                                BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1557                                "getAt",
1558                                "(Ljava/util/List;I)Ljava/lang/Object;");
1559                        break;
1560                    }
1561                    else if (Map.class.isAssignableFrom(lclass)){ // todo test this
1562
visitMethodCallExpression(
1563                                new MethodCallExpression(
1564                                        leftExpression,
1565                                        "get",
1566                                        new ArgumentListExpression(
1567                                                new Expression[] { rightExpression})));
1568                        break;
1569                    }
1570                    else {
1571                        evaluateBinaryExpression("getAt", expression); // todo more optim
1572
break;
1573                    }
1574                }
1575                else {
1576                    evaluateBinaryExpression("getAt", expression);
1577                }
1578                break;
1579
1580            default :
1581                throwException("Operation: " + expression.getOperation() + " not supported");
1582        }
1583    }
1584
1585    private void load(Expression exp) {
1586
1587        boolean wasLeft = leftHandExpression;
1588        leftHandExpression = false;
1589// if (CREATE_DEBUG_INFO)
1590
// helper.mark("-- loading expression: " + exp.getClass().getName() +
1591
// " at [" + exp.getLineNumber() + ":" + exp.getColumnNumber() + "]");
1592
//exp.visit(this);
1593
visitAndAutoboxBoolean(exp);
1594// if (CREATE_DEBUG_INFO)
1595
// helper.mark(" -- end of loading --");
1596

1597
1598        if (ENABLE_EARLY_BINDING){
1599// casting might be expensive. should do JIT casting
1600

1601// Class cls = exp.getTypeClass();
1602
// if (cls != null && !cls.isPrimitive() && cls != Object.class) {
1603
// cast(cls);
1604
// }
1605
}
1606        //evaluateExpression(exp);
1607
leftHandExpression = wasLeft;
1608    }
1609
1610    public void visitPostfixExpression(PostfixExpression expression) {
1611        if (ENABLE_EARLY_BINDING) {
1612            int type = expression.getOperation().getType();
1613            expression.resolve(this);
1614            if (expression.isResolveFailed() || !expression.isTypeResolved()) {
1615                evaluatePostfixMethod("next", expression.getExpression());
1616                return;
1617            }
1618            Class JavaDoc lclass = expression.getTypeClass();
1619            Expression exp = expression.getExpression();
1620            String JavaDoc func = type == Types.PLUS_PLUS ? "next" : "previous";
1621            int op = type == Types.PLUS_PLUS ? IADD : ISUB;
1622
1623            if (lclass == Integer JavaDoc.class) {
1624                load(exp);
1625                cv.visitInsn(DUP); // leave the old value on the stack;
1626
helper.quickUnboxIfNecessary(int.class);
1627                cv.visitInsn(ICONST_1);
1628                cv.visitInsn(op);
1629                helper.quickBoxIfNecessary(int.class);
1630                store(exp);
1631            }
1632            else if (Number JavaDoc.class.isAssignableFrom(lclass)) {
1633                // let's use groovy utilities in the DefaultGroovyMethods
1634
load(exp);
1635                cv.visitInsn(DUP); // leave the old value on the stack;
1636
cv.visitMethodInsn(
1637                        INVOKESTATIC,
1638                        BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()),
1639                        func,
1640                        "(Ljava/lang/Number;)Ljava/lang/Number;");
1641                store(exp);
1642            }
1643            else { // todo add more more number optimiztion
1644
evaluatePostfixMethod(func, exp);
1645            }
1646
1647        } else {
1648            switch (expression.getOperation().getType()) {
1649                case Types.PLUS_PLUS :
1650                    evaluatePostfixMethod("next", expression.getExpression());
1651                    break;
1652                case Types.MINUS_MINUS :
1653                    evaluatePostfixMethod("previous", expression.getExpression());
1654                    break;
1655            }
1656        }
1657    }
1658
1659    // store the data on the stack to the expression (variablem, property, field, etc.
1660
private void store(Expression expression) {
1661        if (expression instanceof BinaryExpression) {
1662            throwException("BinaryExpression appeared on LHS. ");
1663        }
1664        if (ASM_DEBUG) {
1665            if (expression instanceof VariableExpression) {
1666                helper.mark(((VariableExpression)expression).getVariable());
1667            }
1668        }
1669        boolean wasLeft = leftHandExpression;
1670        leftHandExpression = true;
1671        expression.visit(this);
1672        //evaluateExpression(expression);
1673
leftHandExpression = wasLeft;
1674        return;
1675    }
1676
1677    private void throwException(String JavaDoc s) {
1678        //throw new ClassGeneratorException(s + ". Source: " + classNode.getName() + ":[" + this.lineNumber + ":" + this.columnNumber + "]");
1679
throw new RuntimeParserException(s, currentASTNode);
1680    }
1681
1682    public void visitPrefixExpression(PrefixExpression expression) {
1683        switch (expression.getOperation().getType()) {
1684            case Types.PLUS_PLUS :
1685                evaluatePrefixMethod("next", expression.getExpression());
1686                break;
1687            case Types.MINUS_MINUS :
1688                evaluatePrefixMethod("previous", expression.getExpression());
1689                break;
1690        }
1691    }
1692
1693    public void visitClosureExpression(ClosureExpression expression) {
1694        ClassNode innerClass = createClosureClass(expression);
1695        addInnerClass(innerClass);
1696        String JavaDoc innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName());
1697
1698        ClassNode owner = innerClass.getOuterClass();
1699        String JavaDoc ownerTypeName = owner.getName();
1700        if (classNode.isStaticClass() || isStaticMethod()) {
1701            ownerTypeName = "java.lang.Class";
1702        }
1703
1704        passingClosureParams = true;
1705        List constructors = innerClass.getDeclaredConstructors();
1706        ConstructorNode node = (ConstructorNode) constructors.get(0);
1707        Parameter[] localVariableParams = node.getParameters();
1708
1709
1710        //
1711
// Define in the context any variables that will be
1712
// created inside the closure. Note that the first two
1713
// parameters are always _outerInstance and _delegate,
1714
// so we don't worry about them.
1715

1716        for (int i = 2; i < localVariableParams.length; i++) {
1717            Parameter param = localVariableParams[i];
1718            String JavaDoc name = param.getName();
1719
1720            if (variableStack.get(name) == null && classNode.getField(name) == null) {
1721                defineVariable(name, "java.lang.Object"); // todo should use param type is available
1722
}
1723        }
1724
1725        cv.visitTypeInsn(NEW, innerClassinternalName);
1726        cv.visitInsn(DUP);
1727        if (isStaticMethod() || classNode.isStaticClass()) {
1728            visitClassExpression(new ClassExpression(ownerTypeName));
1729        }
1730        else {
1731            loadThisOrOwner();
1732        }
1733
1734        if (innerClass.getSuperClass().equals("groovy.lang.Closure")) {
1735            if (isStaticMethod()) {
1736                /**
1737                 * todo could maybe stash this expression in a JVM variable
1738                 * from previous statement above
1739                 */

1740                visitClassExpression(new ClassExpression(ownerTypeName));
1741            }
1742            else {
1743                loadThisOrOwner();
1744            }
1745        }
1746
1747        //String prototype = "(L" + BytecodeHelper.getClassInternalName(ownerTypeName) + ";Ljava/lang/Object;";
1748

1749        // now lets load the various parameters we're passing
1750
for (int i = 2; i < localVariableParams.length; i++) {
1751            Parameter param = localVariableParams[i];
1752            String JavaDoc name = param.getName();
1753
1754            if (variableStack.get(name) == null) {
1755                visitFieldExpression(new FieldExpression(classNode.getField(name)));
1756            }
1757            else {
1758                visitVariableExpression(new VariableExpression(name));
1759            }
1760            //prototype = prototype + "L" + BytecodeHelper.getClassInternalName(param.getType()) + ";";
1761
}
1762        passingClosureParams = false;
1763
1764        // we may need to pass in some other constructors
1765
//cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
1766
cv.visitMethodInsn(
1767            INVOKESPECIAL,
1768            innerClassinternalName,
1769            "<init>",
1770            BytecodeHelper.getMethodDescriptor("void", localVariableParams));
1771    }
1772
1773    /**
1774     * Loads either this object or if we're inside a closure then load the top level owner
1775     */

1776    protected void loadThisOrOwner() {
1777        if (isInnerClass()) {
1778            visitFieldExpression(new FieldExpression(classNode.getField("owner")));
1779        }
1780        else {
1781            cv.visitVarInsn(ALOAD, 0);
1782        }
1783    }
1784
1785    public void visitRegexExpression(RegexExpression expression) {
1786        expression.getRegex().visit(this);
1787        regexPattern.call(cv);
1788    }
1789
1790    /**
1791     * Generate byte code for constants
1792     * @see <a HREF="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a>
1793     */

1794    public void visitConstantExpression(ConstantExpression expression) {
1795        Object JavaDoc value = expression.getValue();
1796        helper.loadConstant(value);
1797    }
1798
1799    public void visitNegationExpression(NegationExpression expression) {
1800        Expression subExpression = expression.getExpression();
1801        subExpression.visit(this);
1802        negation.call(cv);
1803    }
1804
1805    public void visitCastExpression(CastExpression expression) {
1806        String JavaDoc type = expression.getType();
1807        type = checkValidType(type, expression, "in cast");
1808
1809        visitAndAutoboxBoolean(expression.getExpression());
1810
1811        doConvertAndCast(type, expression.getExpression());
1812    }
1813
1814    public void visitNotExpression(NotExpression expression) {
1815        Expression subExpression = expression.getExpression();
1816        subExpression.visit(this);
1817
1818        // This is not the best way to do this. Javac does it by reversing the
1819
// underlying expressions but that proved
1820
// fairly complicated for not much gain. Instead we'll just use a
1821
// utility function for now.
1822
if (isComparisonExpression(expression.getExpression())) {
1823            notBoolean.call(cv);
1824        }
1825        else {
1826            notObject.call(cv);
1827        }
1828    }
1829
1830    /**
1831     * return a primitive boolean value of the BooleanExpresion.
1832     * @param expression
1833     */

1834    public void visitBooleanExpression(BooleanExpression expression) {
1835        expression.getExpression().visit(this);
1836
1837        if (!isComparisonExpression(expression.getExpression())) {
1838// comment out for optimization when boolean values are not autoboxed for eg. function calls.
1839
// Class typeClass = expression.getExpression().getTypeClass();
1840
// if (typeClass != null && typeClass != boolean.class) {
1841
asBool.call(cv); // to return a primitive boolean
1842
// }
1843
}
1844    }
1845
1846    public void visitMethodCallExpression(MethodCallExpression call) {
1847        onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":");
1848        if (ENABLE_EARLY_BINDING)
1849            call.resolve(this);
1850
1851        this.leftHandExpression = false;
1852
1853        Expression arguments = call.getArguments();
1854        /*
1855         * if (arguments instanceof TupleExpression) { TupleExpression
1856         * tupleExpression = (TupleExpression) arguments; int size =
1857         * tupleExpression.getExpressions().size(); if (size == 0) { arguments =
1858         * ConstantExpression.EMPTY_ARRAY; } }
1859         */

1860        boolean superMethodCall = MethodCallExpression.isSuperMethodCall(call);
1861        String JavaDoc method = call.getMethod();
1862        if (superMethodCall && method.equals("<init>")) {
1863            /** todo handle method types! */
1864            cv.visitVarInsn(ALOAD, 0);
1865            if (isInClosureConstructor()) { // br use the second param to init the super class (Closure)
1866
cv.visitVarInsn(ALOAD, 2);
1867                cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
1868            }
1869            else {
1870                cv.visitVarInsn(ALOAD, 1);
1871                cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
1872            }
1873        }
1874        else {
1875            // are we a local variable
1876
if (isThisExpression(call.getObjectExpression()) && isFieldOrVariable(call.getMethod())) {
1877                /*
1878                 * if (arguments instanceof TupleExpression) { TupleExpression
1879                 * tupleExpression = (TupleExpression) arguments; int size =
1880                 * tupleExpression.getExpressions().size(); if (size == 1) {
1881                 * arguments = (Expression)
1882                 * tupleExpression.getExpressions().get(0); } }
1883                 */

1884
1885                // lets invoke the closure method
1886
visitVariableExpression(new VariableExpression(method));
1887                arguments.visit(this);
1888                invokeClosureMethod.call(cv);
1889            }
1890            else {
1891                if (superMethodCall) {
1892                    if (method.equals("super") || method.equals("<init>")) {
1893                        ConstructorNode superConstructorNode = findSuperConstructor(call);
1894
1895                        cv.visitVarInsn(ALOAD, 0);
1896
1897                        loadArguments(superConstructorNode.getParameters(), arguments);
1898
1899                        String JavaDoc descriptor = BytecodeHelper.getMethodDescriptor("void", superConstructorNode.getParameters());
1900                        cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", descriptor);
1901                    }
1902                    else {
1903                        MethodNode superMethodNode = findSuperMethod(call);
1904
1905                        cv.visitVarInsn(ALOAD, 0);
1906
1907                        loadArguments(superMethodNode.getParameters(), arguments);
1908
1909                        String JavaDoc descriptor = BytecodeHelper.getMethodDescriptor(superMethodNode.getReturnType(), superMethodNode.getParameters());
1910                        cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superMethodNode.getDeclaringClass().getName()), method, descriptor);
1911                    }
1912                }
1913                else {
1914                    // let's try early binding
1915
if (ENABLE_EARLY_BINDING) {
1916                        try {
1917                            MetaMethod metamethod = call.getMetaMethod(); // todo change it to resolveMethodCallExpression
1918
if (metamethod != null) {
1919                                Class JavaDoc decClass = metamethod.getDeclaringClass();
1920                                String JavaDoc ownerClassName = null;
1921                                if (decClass == null) {
1922                                    // meaning the class is the current class
1923
ownerClassName = BytecodeHelper.getClassInternalName(classNode.getName());
1924                                }
1925                                else {
1926                                    ownerClassName = BytecodeHelper.getClassInternalName(decClass.getName());
1927                                }
1928
1929                                String JavaDoc methodName = call.getMethod();
1930                                String JavaDoc descr = BytecodeHelper.getMethodDescriptor(metamethod);
1931                                Class JavaDoc[] params = metamethod.getParameterTypes();
1932                                //
1933
Label l2 = new Label();
1934
1935                                if (metamethod.isStatic()) {
1936                                } else {
1937                                    boolean wasLeft = leftHandExpression;
1938                                    leftHandExpression = false;
1939                                    call.getObjectExpression().visit(this);
1940
1941                                    if (call.isSafe()) {
1942                                        helper.dup();
1943                                        cv.visitJumpInsn(IFNULL, l2);
1944                                    }
1945
1946                                    cv.visitTypeInsn(CHECKCAST, ownerClassName);
1947                                    leftHandExpression = wasLeft;
1948                                }
1949                                //
1950
if (arguments instanceof TupleExpression) {
1951                                    TupleExpression tupleExpression = (TupleExpression) arguments;
1952                                    List argexps = tupleExpression.getExpressions();
1953                                    for (int i = 0; i < argexps.size(); i++) {
1954                                        Expression expression = (Expression) argexps.get(i);
1955                                        load(expression);
1956
1957                                        if (params[i].isPrimitive() /*&& !expression.getTypeClass().isPrimitive()*/) { // data always boxed
1958
cast(params[i]);
1959                                            helper.quickUnboxIfNecessary(params[i]);
1960                                        }
1961                                        else if (params[i].isArray() && params[i].getComponentType().isPrimitive() ) {
1962                                            new ClassExpression(params[i].getComponentType()).visit(this);
1963                                            convertToPrimitiveArray.call(cv);
1964                                            cast(params[i]);
1965                                        }
1966                                        else {
1967                                            if (expression.getTypeClass() == GString.class && params[i] == String JavaDoc.class){
1968                                                cast(GString.class);
1969                                                cv.visitMethodInsn(
1970                                                        INVOKEVIRTUAL,
1971                                                        "java/lang/Object",
1972                                                        "toString",
1973                                                        "()Ljava/lang/String;"
1974                                                );
1975                                            }
1976                                            else {
1977                                                cast(params[i]);
1978                                            }
1979                                        }
1980                                    }
1981                                    if (metamethod.isStatic()) {
1982                                        cv.visitMethodInsn(INVOKESTATIC, ownerClassName, methodName, descr);
1983                                    }
1984                                    else if (decClass != null && decClass.isInterface()){
1985                                        cv.visitMethodInsn(INVOKEINTERFACE, ownerClassName, methodName, descr);
1986                                    }
1987                                    else {
1988                                        cv.visitMethodInsn(INVOKEVIRTUAL, ownerClassName, methodName, descr);
1989                                    }
1990                                    call.setTypeClass(metamethod.getReturnType());
1991                                    if (metamethod.getReturnType().isPrimitive()
1992                                            && metamethod.getReturnType() != void.class
1993                                            //&& metamethod.getReturnType() != boolean.class
1994
) {
1995                                        helper.quickBoxIfNecessary(metamethod.getReturnType());
1996                                    }
1997                                    if (call.isSafe()) {
1998                                        Label l3 = new Label();
1999                                        cv.visitJumpInsn(GOTO, l3);
2000                                        cv.visitLabel(l2);
2001                                        cv.visitInsn(POP);
2002                                        cv.visitInsn(ACONST_NULL);
2003                                        cv.visitLabel(l3);
2004                                    }
2005                                    return;
2006                                } else {
2007                                    throw new GroovyRuntimeException("arguments type not handled. fall through to late binding");
2008                                }
2009                            }
2010                        } catch (Exception JavaDoc e) {
2011// System.out.println(this.classNode.getName() + ":" + this.methodNode.getName());
2012
// //e.printStackTrace(); //System.out.println(e.getMessage());
2013
// log.info("ignore: attempt early binding: " + e.getMessage());
2014
// fall through
2015
}
2016                    } // end of early binding trial
2017

2018                    if (emptyArguments(arguments) && !call.isSafe()) {
2019                        call.getObjectExpression().visit(this);
2020                        cv.visitLdcInsn(method);
2021                        invokeNoArgumentsMethod.call(cv); // todo try if we can do early binding
2022
}
2023                    else {
2024                        if (argumentsUseStack(arguments)) {
2025
2026                            arguments.visit(this);
2027
2028                            Variable tv = visitASTOREInTemp(method + "_arg");
2029                            int paramIdx = tv.getIndex();
2030
2031                            call.getObjectExpression().visit(this); // xxx
2032

2033                            cv.visitLdcInsn(method);
2034
2035                            cv.visitVarInsn(ALOAD, paramIdx);
2036                            removeVar(tv);
2037                        }
2038                        else {
2039                            call.getObjectExpression().visit(this);
2040                            cv.visitLdcInsn(method);
2041                            arguments.visit(this);
2042                        }
2043
2044                        if (call.isSafe()) {
2045                            invokeMethodSafeMethod.call(cv);
2046                        }
2047                        else {
2048                            invokeMethodMethod.call(cv);
2049                        }
2050                    }
2051                }
2052            }
2053        }
2054    }
2055
2056    /**
2057     * Loads and coerces the argument values for the given method call
2058     */

2059    protected void loadArguments(Parameter[] parameters, Expression expression) {
2060        TupleExpression argListExp = (TupleExpression) expression;
2061        List arguments = argListExp.getExpressions();
2062        for (int i = 0, size = arguments.size(); i < size; i++) {
2063            Expression argExp = argListExp.getExpression(i);
2064            Parameter param = parameters[i];
2065            visitAndAutoboxBoolean(argExp);
2066
2067            String JavaDoc type = param.getType();
2068            if (BytecodeHelper.isPrimitiveType(type)) {
2069                helper.unbox(type);
2070            }
2071
2072            String JavaDoc expType = getExpressionType(argExp);
2073            if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) {
2074                doConvertAndCast(type);
2075            }
2076 // doConvertAndCast(type, argExp);
2077
}
2078    }
2079
2080    /**
2081     * Attempts to find the method of the given name in a super class
2082     */

2083    protected MethodNode findSuperMethod(MethodCallExpression call) {
2084        String JavaDoc methodName = call.getMethod();
2085        TupleExpression argExpr = (TupleExpression) call.getArguments();
2086        int argCount = argExpr.getExpressions().size();
2087        ClassNode superClassNode = classNode.getSuperClassNode();
2088        if (superClassNode != null) {
2089            List methods = superClassNode.getMethods(methodName);
2090            for (Iterator iter = methods.iterator(); iter.hasNext(); ) {
2091                MethodNode method = (MethodNode) iter.next();
2092                if (method.getParameters().length == argCount) {
2093                    return method;
2094                }
2095            }
2096        }
2097        throwException("No such method: " + methodName + " for class: " + classNode.getName());
2098        return null; // should not come here
2099
}
2100
2101    /**
2102     * Attempts to find the constructor in a super class
2103     */

2104    protected ConstructorNode findSuperConstructor(MethodCallExpression call) {
2105        TupleExpression argExpr = (TupleExpression) call.getArguments();
2106        int argCount = argExpr.getExpressions().size();
2107        ClassNode superClassNode = classNode.getSuperClassNode();
2108        if (superClassNode != null) {
2109            List constructors = superClassNode.getDeclaredConstructors();
2110            for (Iterator iter = constructors.iterator(); iter.hasNext(); ) {
2111                ConstructorNode constructor = (ConstructorNode) iter.next();
2112                if (constructor.getParameters().length == argCount) {
2113                    return constructor;
2114                }
2115            }
2116        }
2117        throwException("No such constructor for class: " + classNode.getName());
2118        return null; // should not come here
2119
}
2120
2121    protected boolean emptyArguments(Expression arguments) {
2122        if (arguments instanceof TupleExpression) {
2123            TupleExpression tupleExpression = (TupleExpression) arguments;
2124            int size = tupleExpression.getExpressions().size();
2125            return size == 0;
2126        }
2127        return false;
2128    }
2129
2130    public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
2131        this.leftHandExpression = false;
2132
2133        Expression arguments = call.getArguments();
2134        if (emptyArguments(arguments)) {
2135            cv.visitLdcInsn(call.getType());
2136            cv.visitLdcInsn(call.getMethod());
2137
2138            invokeStaticNoArgumentsMethod.call(cv);
2139        }
2140        else {
2141            if (arguments instanceof TupleExpression) {
2142                TupleExpression tupleExpression = (TupleExpression) arguments;
2143                int size = tupleExpression.getExpressions().size();
2144                if (size == 1) {
2145                    arguments = (Expression) tupleExpression.getExpressions().get(0);
2146                }
2147            }
2148
2149            cv.visitLdcInsn(call.getOwnerType());
2150            cv.visitLdcInsn(call.getMethod());
2151            arguments.visit(this);
2152
2153            invokeStaticMethodMethod.call(cv);
2154        }
2155    }
2156
2157    public void visitConstructorCallExpression(ConstructorCallExpression call) {
2158        onLineNumber(call, "visitConstructorCallExpression: \"" + call.getTypeToSet() + "\":");
2159        do {
2160            if (ENABLE_EARLY_BINDING) {
2161                call.resolve(this);
2162                if (call.isResolveFailed() || call.getTypeClass() == null) {
2163                    break;
2164                }
2165                else {
2166                    try {
2167                        Constructor JavaDoc ctor = call.getConstructor(); // todo change it to resolveMethodCallExpression
2168
if (ctor != null) {
2169                            Class JavaDoc decClass = ctor.getDeclaringClass();
2170                            String JavaDoc ownerClassName = null;
2171                            if (decClass == null) {
2172                                // meaning the class is the current class
2173
ownerClassName = BytecodeHelper.getClassInternalName(classNode.getName());
2174                            }
2175                            else {
2176                                ownerClassName = BytecodeHelper.getClassInternalName(decClass.getName());
2177                            }
2178
2179                            Class JavaDoc[] params = ctor.getParameterTypes();
2180                            StringBuffer JavaDoc argbuf = new StringBuffer JavaDoc("(");
2181                            for (int i = 0; i < params.length; i++) {
2182                                Class JavaDoc arg = params[i];
2183                                String JavaDoc descr = BytecodeHelper.getTypeDescription(arg);
2184                                argbuf.append(descr);
2185                            }
2186                            argbuf.append(")V");
2187                            //
2188
cv.visitTypeInsn(NEW, ownerClassName);
2189                            cv.visitInsn(DUP);
2190
2191                            //
2192
Expression arguments = call.getArguments();
2193                            if (arguments instanceof TupleExpression) {
2194                                TupleExpression tupleExpression = (TupleExpression) arguments;
2195                                List argexps = tupleExpression.getExpressions();
2196                                for (int i = 0; i < argexps.size(); i++) {
2197                                    Expression expression = (Expression) argexps.get(i);
2198                                    load(expression);
2199                                    if (params[i].isPrimitive() /*&& !expression.getTypeClass().isPrimitive()*/) { // data always boxed
2200
cast(params[i]);
2201                                        helper.quickUnboxIfNecessary(params[i]);
2202                                    }
2203                                    else if (params[i].isArray() && params[i].getComponentType().isPrimitive() ) {
2204                                        new ClassExpression(params[i].getComponentType()).visit(this);
2205                                        convertToPrimitiveArray.call(cv);
2206                                        cast(params[i]);
2207                                    }
2208                                    else {
2209                                        //? if the target is String , I might as well call Object.toString() regardless
2210
if (expression.getTypeClass() == GString.class && params[i] == String JavaDoc.class){
2211                                            cast(GString.class);
2212                                            cv.visitMethodInsn(
2213                                                    INVOKEVIRTUAL,
2214                                                    "java/lang/Object",
2215                                                    "toString",
2216                                                    "()Ljava/lang/String;"
2217                                            );
2218                                        }
2219                                        else {
2220                                            cast(params[i]);
2221                                        }
2222                                    }
2223                                }
2224
2225                                cv.visitMethodInsn(INVOKESPECIAL, ownerClassName, "<init>", argbuf.toString());
2226                                return;
2227                            } else {
2228                                throw new GroovyRuntimeException("arguments type not handled. fall through to late binding");
2229                            }
2230                        }
2231                    } catch (Exception JavaDoc e) {
2232// System.out.println(this.classNode.getName() + ":" + this.methodNode.getName());
2233
//e.printStackTrace(); //System.out.println(e.getMessage());
2234
// log.info("ignore: attempt early binding: " + e.getMessage());
2235
break;// fall through
2236
}
2237                }
2238            }
2239        } while(false);
2240
2241        this.leftHandExpression = false;
2242
2243        Expression arguments = call.getArguments();
2244        if (arguments instanceof TupleExpression) {
2245            TupleExpression tupleExpression = (TupleExpression) arguments;
2246            int size = tupleExpression.getExpressions().size();
2247            if (size == 0) {
2248                arguments = null;
2249            }
2250// else if (size == 1) { // why unpack the tuple of 1 component?
2251
// arguments = (Expression) tupleExpression.getExpressions().get(0);
2252
// }
2253
}
2254
2255        // lets check that the type exists
2256
String JavaDoc type = checkValidType(call.getType(), call, "in constructor call");
2257
2258        //System.out.println("Constructing: " + type);
2259

2260        visitClassExpression(new ClassExpression(type));
2261        if (arguments !=null) {
2262               arguments.visit(this);
2263            invokeConstructorOfMethod.call(cv); // todo subject to opti
2264
} else {
2265            invokeNoArgumentsConstructorOf.call(cv); // todo subject to opti
2266
}
2267        /*
2268         * cv.visitLdcInsn(type);
2269         *
2270         * arguments.visit(this);
2271         *
2272         * invokeConstructorMethod.call(cv);
2273         */

2274    }
2275
2276    public void visitPropertyExpression(PropertyExpression expression) {
2277
2278        do {
2279            if (true && ENABLE_EARLY_BINDING) {
2280                expression.resolve(this);
2281
2282                if (!expression.isTypeResolved()) {
2283                    break;
2284                }
2285                Expression ownerExp = expression.getObjectExpression();
2286                String JavaDoc propName = expression.getProperty();
2287                if (expression.getProperty().equals("class")) {
2288                    break; // the default does the right thing. let it do.
2289
}
2290
2291
2292                String JavaDoc ownerType = ownerExp.getType();
2293                Class JavaDoc ownerClass = ownerExp.getTypeClass();
2294                if (ownerType == null || ownerType.length() == 0) {
2295                    break;
2296                }
2297
2298                Label l3 = new Label();
2299                // handle arraylength
2300
if (ownerClass != null && ownerClass.isArray() && propName.equals("length")) {
2301                    load(ownerExp);
2302                    if (expression.isSafe()) {
2303                        helper.dup();
2304                        cv.visitJumpInsn(IFNULL, l3);
2305                    }
2306                    cast(ownerClass);
2307                    cv.visitInsn(ARRAYLENGTH);
2308                    helper.quickBoxIfNecessary(int.class);
2309                    cv.visitLabel(l3);
2310                    return;
2311                }
2312
2313
2314                String JavaDoc propertyType = expression.getType();
2315                if (propertyType == null || propertyType.length() == 0) {
2316                    break;
2317                }
2318                boolean isStatic = expression.isStatic();
2319                if (!isThisExpression(ownerExp) && GroovyObject.class.isAssignableFrom(ownerExp.getTypeClass())) {
2320                    // call other groovy object property via getProperty()/setProperty()
2321
if (!isStatic && ownerExp instanceof ClassExpression) {
2322                        if (leftHandExpression) {
2323                            cv.visitMethodInsn(
2324                                    INVOKEVIRTUAL,
2325                                    BytecodeHelper.getClassInternalName(ownerType),
2326                                    "setProperty",
2327                                    BytecodeHelper.getTypeDescription(propertyType));
2328                        } else {
2329                            cv.visitMethodInsn(
2330                                    INVOKEVIRTUAL,
2331                                    BytecodeHelper.getClassInternalName(ownerType),
2332                                    "getProperty",
2333                                    BytecodeHelper.getTypeDescription(propertyType));
2334                        }
2335                        return;
2336                    } else {
2337                        break;
2338                    }
2339                }
2340// else if (isThisExpression(ownerExp)){
2341
// if (leftHandExpression) {
2342
// helper.loadThis();
2343
// cv.visitFieldInsn(
2344
// PUTFIELD,
2345
// BytecodeHelper.getClassInternalName(ownerType),
2346
// expression.getProperty(),
2347
// BytecodeHelper.getClassInternalName(propertyType));
2348
// } else {
2349
// cv.visitMethodInsn(
2350
// INVOKEVIRTUAL,
2351
// BytecodeHelper.getClassInternalName(ownerType),
2352
// "getProperty",
2353
// BytecodeHelper.getClassInternalName(propertyType));
2354
// }
2355
// return;
2356
// }
2357

2358                // the following logic is used for this.<prop> acess too.
2359
else { // none direct local access
2360
Field JavaDoc fld = expression.getField();
2361                    Method JavaDoc setter = expression.getSetter();
2362                    Method JavaDoc getter = expression.getGetter();
2363
2364                    // gate keeping
2365
if (leftHandExpression) {
2366                        if (fld == null && setter == null) {
2367                            break;
2368                        }
2369                    }
2370                    else {
2371                        if (fld == null && getter == null) {
2372                            break;
2373                        }
2374                    }
2375
2376                    if (ownerClass == null && !isThisExpression(ownerExp)) {
2377                        break; // ownerClass is null only when the ownerExp is "this"
2378
}
2379                    // now looking for public fields before accessors
2380

2381
2382                    if (expression.isStatic()) {
2383                        if (leftHandExpression) {
2384                            if (fld != null) {
2385                                helper.quickUnboxIfNecessary(expression.getTypeClass());
2386                                cv.visitFieldInsn(
2387                                        PUTSTATIC,
2388                                        BytecodeHelper.getClassInternalName(ownerType),
2389                                        expression.getProperty(),
2390                                        BytecodeHelper.getTypeDescription(propertyType)
2391                                );
2392                            }
2393                            else if (setter != null) {
2394                                helper.quickUnboxIfNecessary(setter.getParameterTypes()[0]);
2395                                cast(setter.getParameterTypes()[0]);
2396                                helper.invoke(setter);
2397                            }
2398                            else {
2399                                throwException("no method or field is found for a resolved property access");
2400                            }
2401                        }
2402                        else { // get the property
2403
if (fld != null){
2404                                cv.visitFieldInsn(
2405                                        GETSTATIC,
2406                                        BytecodeHelper.getClassInternalName(ownerType),
2407                                        propName,
2408                                        BytecodeHelper.getTypeDescription(propertyType)
2409                                );
2410                                helper.quickBoxIfNecessary(expression.getTypeClass());
2411                            }
2412                            else if (getter != null) {
2413                                helper.invoke(getter);
2414                                helper.quickBoxIfNecessary(expression.getTypeClass());
2415                            }
2416                            else {
2417                                throwException("no method or field is found for a resolved property access");
2418                            }
2419                        }
2420                    } else { // non-static access
2421
if (leftHandExpression) { // set the property
2422
// assumption: the data on the stack are boxed if it's a number
2423
helper.quickUnboxIfNecessary(expression.getTypeClass());
2424                            load(ownerExp);
2425                            if (expression.isSafe()) {
2426                                helper.dup();
2427                                cv.visitJumpInsn(IFNULL, l3);
2428                            }
2429
2430                            if (ownerClass != null)
2431                                cast(ownerClass);
2432                            Class JavaDoc cls = expression.getTypeClass();
2433                            if (cls == double.class || cls == long.class) {
2434                                cv.visitInsn(DUP_X2);
2435                                cv.visitInsn(POP);
2436                            } else {
2437                                cv.visitInsn(SWAP);
2438                            }
2439
2440                            if (fld != null) {
2441                                cv.visitFieldInsn(
2442                                        PUTFIELD,
2443                                        BytecodeHelper.getClassInternalName(ownerType),
2444                                        propName,
2445                                        BytecodeHelper.getTypeDescription(propertyType)
2446                                );
2447                            }
2448                            else if (setter != null) {
2449                                Method JavaDoc m = setter;
2450                                Class JavaDoc[] paramTypes = m.getParameterTypes();
2451                                if (paramTypes.length != 1) {
2452                                    throw new RuntimeException JavaDoc("setter should take a single parameter");
2453                                }
2454                                Class JavaDoc paramType = paramTypes[0];
2455                                cast(paramType);
2456                                helper.invoke(setter);
2457                            }
2458                            else {
2459                                throwException("no method or field is found for a resolved property access");
2460                            }
2461                        }
2462                        else { // get property
2463
load(ownerExp);
2464                            if (expression.isSafe()) {
2465                                helper.dup();
2466                                cv.visitJumpInsn(IFNULL, l3);
2467                            }
2468                            if (ownerClass != null)
2469                                cast(ownerClass);
2470                            if (fld != null) {
2471                                cv.visitFieldInsn(
2472                                        GETFIELD,
2473                                        BytecodeHelper.getClassInternalName(ownerType),
2474                                        propName,
2475                                        BytecodeHelper.getTypeDescription(propertyType)
2476                                );
2477                                helper.quickBoxIfNecessary(expression.getTypeClass());
2478                            }
2479                            else if (getter != null) {
2480                                helper.invoke(getter);
2481                                helper.quickBoxIfNecessary(expression.getTypeClass());
2482                            }
2483                            else {
2484                                throwException("no method or field is found for a resolved property access");
2485                            }
2486                        }
2487                    }
2488                    cv.visitLabel(l3);
2489                    return;
2490                }
2491            }
2492        } while (false);
2493
2494        // lets check if we're a fully qualified class name
2495
String JavaDoc className = null;
2496        Expression objectExpression = expression.getObjectExpression();
2497        if (!isThisExpression(objectExpression)) {
2498            className = checkForQualifiedClass(expression);
2499            if (className != null) {
2500                visitClassExpression(new ClassExpression(className));
2501                return;
2502            }
2503        }
2504        if (expression.getProperty().equals("class")) {
2505            if ((objectExpression instanceof ClassExpression)) {
2506                visitClassExpression((ClassExpression) objectExpression);
2507                return;
2508            }
2509            else if (objectExpression instanceof VariableExpression) {
2510                VariableExpression varExp = (VariableExpression) objectExpression;
2511                className = varExp.getVariable();
2512                try {
2513                    className = resolveClassName(className);
2514                    visitClassExpression(new ClassExpression(className));
2515                    return;
2516                }
2517                catch (Exception JavaDoc e) {
2518                    // ignore
2519
}
2520            }
2521        }
2522
2523        if (isThisExpression(objectExpression)) {
2524            // lets use the field expression if its available
2525
String JavaDoc name = expression.getProperty();
2526            FieldNode field = classNode.getField(name);
2527            if (field != null) {
2528                visitFieldExpression(new FieldExpression(field));
2529                return;
2530            }
2531        }
2532
2533        boolean left = leftHandExpression;
2534        // we need to clear the LHS flag to avoid "this." evaluating as ASTORE
2535
// rather than ALOAD
2536
leftHandExpression = false;
2537
2538        objectExpression.visit(this);
2539
2540        cv.visitLdcInsn(expression.getProperty());
2541
2542        if (isGroovyObject(objectExpression) && ! expression.isSafe()) {
2543            if (left) {
2544                setGroovyObjectPropertyMethod.call(cv);
2545            }
2546            else {
2547                getGroovyObjectPropertyMethod.call(cv);
2548            }
2549        }
2550        else {
2551            if (expression.isSafe()) {
2552                if (left) {
2553                    setPropertySafeMethod2.call(cv);
2554                }
2555                else {
2556                    getPropertySafeMethod.call(cv);
2557                }
2558            }
2559            else {
2560                if (left) {
2561                    setPropertyMethod2.call(cv);
2562                }
2563                else {
2564                    getPropertyMethod.call(cv);
2565                }
2566            }
2567        }
2568    }
2569
2570    protected boolean isGroovyObject(Expression objectExpression) {
2571        return isThisExpression(objectExpression);
2572    }
2573
2574    /**
2575     * Checks if the given property expression represents a fully qualified class name
2576     * @return the class name or null if the property is not a valid class name
2577     */

2578    protected String JavaDoc checkForQualifiedClass(PropertyExpression expression) {
2579        String JavaDoc text = expression.getText();
2580        if (text != null && text.endsWith(".class")) {
2581            text = text.substring(0, text.length() - 6);
2582        }
2583        try {
2584            return resolveClassName(text);
2585        }
2586        catch (Exception JavaDoc e) {
2587            return null;
2588        }
2589    }
2590
2591    public void visitFieldExpression(FieldExpression expression) {
2592        FieldNode field = expression.getField();
2593
2594
2595        if (field.isStatic()) {
2596            if (leftHandExpression) {
2597                storeStaticField(expression);
2598            }
2599            else {
2600                loadStaticField(expression);
2601            }
2602        } else {
2603            if (leftHandExpression) {
2604                storeThisInstanceField(expression);
2605            }
2606            else {
2607                loadInstanceField(expression);
2608            }
2609        }
2610    }
2611
2612    /**
2613     *
2614     * @param fldExp
2615     */

2616    public void loadStaticField(FieldExpression fldExp) {
2617        FieldNode field = fldExp.getField();
2618        boolean holder = field.isHolder() && !isInClosureConstructor();
2619        String JavaDoc type = field.getType();
2620
2621        String JavaDoc ownerName = (field.getOwner().equals(classNode.getName()))
2622                ? internalClassName
2623                : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2624        if (holder) {
2625            cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
2626            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
2627        }
2628        else {
2629            cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
2630            if (BytecodeHelper.isPrimitiveType(type)) {
2631                helper.box(type);
2632            } else {
2633            }
2634        }
2635    }
2636
2637    /**
2638     * RHS instance field. should move most of the code in the BytecodeHelper
2639     * @param fldExp
2640     */

2641    public void loadInstanceField(FieldExpression fldExp) {
2642        FieldNode field = fldExp.getField();
2643        boolean holder = field.isHolder() && !isInClosureConstructor();
2644        String JavaDoc type = field.getType();
2645        String JavaDoc ownerName = (field.getOwner().equals(classNode.getName()))
2646                ? internalClassName
2647                : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2648
2649        cv.visitVarInsn(ALOAD, 0);
2650        cv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
2651
2652        if (holder) {
2653            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
2654        } else {
2655            if (BytecodeHelper.isPrimitiveType(type)) {
2656                helper.box(type);
2657            } else {
2658            }
2659        }
2660    }
2661
2662    public void storeThisInstanceField(FieldExpression expression) {
2663        FieldNode field = expression.getField();
2664
2665        boolean holder = field.isHolder() && !isInClosureConstructor();
2666        String JavaDoc type = field.getType();
2667
2668        String JavaDoc ownerName = (field.getOwner().equals(classNode.getName())) ?
2669                internalClassName : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2670        if (holder) {
2671            Variable tv = visitASTOREInTemp(field.getName());
2672            int tempIndex = tv.getIndex();
2673            cv.visitVarInsn(ALOAD, 0);
2674            cv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
2675            cv.visitVarInsn(ALOAD, tempIndex);
2676            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
2677            removeVar(tv);
2678        }
2679        else {
2680            if (isInClosureConstructor()) {
2681                helper.doCast(type);
2682            }
2683            else {
2684                if (ENABLE_EARLY_BINDING) {
2685                    helper.doCast(type);
2686                }
2687                else {
2688                    // this may be superfluous
2689
doConvertAndCast(type);
2690                }
2691            }
2692            //Variable tmpVar = defineVariable(createVariableName(field.getName()), "java.lang.Object", false);
2693
Variable tmpVar = defineVariable(createVariableName(field.getName()), field.getType(), false);
2694            //int tempIndex = tmpVar.getIndex();
2695
//helper.store(field.getType(), tempIndex);
2696
helper.store(tmpVar, MARK_START);
2697            helper.loadThis(); //cv.visitVarInsn(ALOAD, 0);
2698
helper.load(tmpVar);
2699            helper.putField(field, ownerName);
2700            //cv.visitFieldInsn(PUTFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
2701
// let's remove the temp var
2702
removeVar(tmpVar);
2703        }
2704    }
2705
2706
2707    public void storeStaticField(FieldExpression expression) {
2708        FieldNode field = expression.getField();
2709
2710        boolean holder = field.isHolder() && !isInClosureConstructor();
2711
2712        String JavaDoc type = field.getType();
2713
2714        String JavaDoc ownerName = (field.getOwner().equals(classNode.getName()))
2715                ? internalClassName
2716                : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2717        if (holder) {
2718            Variable tv = visitASTOREInTemp(field.getName());
2719            int tempIndex = tv.getIndex();
2720            cv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
2721            cv.visitVarInsn(ALOAD, tempIndex);
2722            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
2723            removeVar(tv);
2724        }
2725        else {
2726            if (isInClosureConstructor()) {
2727                helper.doCast(type);
2728            }
2729            else {
2730                if (ENABLE_EARLY_BINDING) {
2731                    helper.doCast(type);
2732                }
2733                else {
2734                    // this may be superfluous
2735
//doConvertAndCast(type);
2736
// use weaker cast
2737
helper.doCast(type);
2738                }
2739            }
2740            cv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
2741        }
2742    }
2743
2744    protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) {
2745        FieldNode field = expression.getField();
2746        boolean isStatic = field.isStatic();
2747
2748        Variable fieldTemp = defineVariable(createVariableName(field.getName()), "java.lang.Object", false);
2749        int valueIdx = fieldTemp.getIndex();
2750
2751        if (leftHandExpression && first) {
2752            cv.visitVarInsn(ASTORE, valueIdx);
2753            visitVariableStartLabel(fieldTemp);
2754        }
2755
2756        if (steps > 1 || !isStatic) {
2757            cv.visitVarInsn(ALOAD, 0);
2758            cv.visitFieldInsn(
2759                GETFIELD,
2760                internalClassName,
2761                "owner",
2762                BytecodeHelper.getTypeDescription(outerClassNode.getName()));
2763        }
2764
2765        if( steps == 1 ) {
2766            int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD);
2767            String JavaDoc ownerName = BytecodeHelper.getClassInternalName(outerClassNode.getName());
2768
2769            if (leftHandExpression) {
2770                cv.visitVarInsn(ALOAD, valueIdx);
2771                boolean holder = field.isHolder() && !isInClosureConstructor();
2772                if ( !holder) {
2773                    doConvertAndCast(field.getType());
2774                }
2775            }
2776            cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
2777            if (!leftHandExpression) {
2778                if (BytecodeHelper.isPrimitiveType(field.getType())) {
2779                    helper.box(field.getType());
2780                }
2781            }
2782        }
2783
2784        else {
2785            visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false );
2786        }
2787    }
2788
2789
2790
2791    /**
2792     * Visits a bare (unqualified) variable expression.
2793     */

2794
2795    public void visitVariableExpression(VariableExpression expression) {
2796
2797        String JavaDoc variableName = expression.getVariable();
2798
2799      //-----------------------------------------------------------------------
2800
// SPECIAL CASES
2801

2802        //
2803
// "this" for static methods is the Class instance
2804

2805        if (isStaticMethod() && variableName.equals("this")) {
2806            visitClassExpression(new ClassExpression(classNode.getName()));
2807            return; // <<< FLOW CONTROL <<<<<<<<<
2808
}
2809
2810        //
2811
// "super" also requires special handling
2812

2813        if (variableName.equals("super")) {
2814            visitClassExpression(new ClassExpression(classNode.getSuperClass()));
2815            return; // <<< FLOW CONTROL <<<<<<<<<
2816
}
2817
2818
2819        //
2820
// class names return a Class instance, too
2821

2822// if (!variableName.equals("this")) {
2823
// String className = resolveClassName(variableName);
2824
// if (className != null) {
2825
// if (leftHandExpression) {
2826
// throw new RuntimeParserException(
2827
// "Cannot use a class expression on the left hand side of an assignment",
2828
// expression);
2829
// }
2830
// visitClassExpression(new ClassExpression(className));
2831
// return; // <<< FLOW CONTROL <<<<<<<<<
2832
// }
2833
// }
2834

2835
2836      //-----------------------------------------------------------------------
2837
// GENERAL VARIABLE LOOKUP
2838

2839
2840        //
2841
// We are handling only unqualified variables here. Therefore,
2842
// we do not care about accessors, because local access doesn't
2843
// go through them. Therefore, precedence is as follows:
2844
// 1) local variables, nearest block first
2845
// 2) class fields
2846
// 3) repeat search from 2) in next outer class
2847

2848        boolean handled = false;
2849        Variable variable = (Variable)variableStack.get( variableName );
2850
2851        if( variable != null ) {
2852
2853            if( variable.isProperty() ) {
2854                processPropertyVariable(variable );
2855            }
2856            else {
2857                if (ENABLE_EARLY_BINDING && expression.isTypeResolved() && leftHandExpression) {
2858                    // let's pass the type back to the variable
2859
String JavaDoc typeName = expression.getType();
2860                    Type varOldType = variable.getType();
2861                    if (varOldType.isDynamic()) {
2862                        variable.setType(new Type(typeName, true));
2863                    }
2864                    else if (!varOldType.getName().equals(typeName)){
2865                        new GroovyRuntimeException("VariableExpression data type conflicts with the existing variable. "
2866                                + "[" + expression.getLineNumber() + ":" + expression.getColumnNumber() + "]");
2867                    }
2868                }
2869                processStackVariable(variable );
2870            }
2871
2872            handled = true;
2873        } else {
2874            //
2875
// Loop through outer classes for fields
2876

2877            int steps = 0;
2878            ClassNode currentClassNode = classNode;
2879            FieldNode field = null;
2880
2881            do {
2882                if( (field = currentClassNode.getField(variableName)) != null ) {
2883                    if (methodNode == null || !methodNode.isStatic() || field.isStatic() )
2884                        break; //this is a match. break out. todo to be tested
2885
}
2886                steps++;
2887
2888            } while( (currentClassNode = currentClassNode.getOuterClass()) != null );
2889
2890            if( field != null ) {
2891                processFieldAccess( variableName, field, steps );
2892                handled = true;
2893            }
2894        }
2895
2896        //
2897
// class names return a Class instance, too
2898
if (!handled && !variableName.equals("this")) {
2899            String JavaDoc className = resolveClassName(variableName);
2900            if (className != null) {
2901                if (leftHandExpression) {
2902                    throwException("Cannot use a class expression on the left hand side of an assignment");
2903                }
2904                visitClassExpression(new ClassExpression(className));
2905                return; // <<< FLOW CONTROL <<<<<<<<<
2906
}
2907        }
2908
2909        //
2910
// Finally, if unhandled, create a variable for it.
2911
// Except there a stack variable should be created,
2912
// we define the variable as a property accessor and
2913
// let other parts of the classgen report the error
2914
// if the property doesn't exist.
2915

2916        if( !handled ) {
2917            String JavaDoc variableType = expression.getType();
2918            variable = defineVariable( variableName, variableType );
2919
2920            if (leftHandExpression && expression.isDynamic()) {
2921                variable.setDynamic(true); // false by default
2922
}
2923            else {
2924                variable.setDynamic(false);
2925            }
2926
2927            if( isInScriptBody() || !leftHandExpression ) { // todo problematic: if on right hand not defined, should I report undefined var error?
2928
variable.setProperty( true );
2929                processPropertyVariable(variable );
2930            }
2931            else {
2932                processStackVariable(variable );
2933            }
2934        }
2935    }
2936
2937
2938    protected void processStackVariable(Variable variable ) {
2939        boolean holder = variable.isHolder() && !passingClosureParams;
2940
2941        if( leftHandExpression ) {
2942            helper.storeVar(variable, holder);
2943        }
2944        else {
2945            helper.loadVar(variable, holder);
2946        }
2947        if (ASM_DEBUG) {
2948            helper.mark("var: " + variable.getName());
2949        }
2950    }
2951
2952    private void visitVariableStartLabel(Variable variable) {
2953        if (CREATE_DEBUG_INFO) {
2954            Label l = variable.getStartLabel();
2955            if (l != null) {
2956                cv.visitLabel(l);
2957            } else {
2958                System.out.println("start label == null! what to do about this?");
2959            }
2960        }
2961    }
2962
2963    protected void processPropertyVariable(Variable variable ) {
2964        String JavaDoc name = variable.getName();
2965        if (variable.isHolder() && passingClosureParams && isInScriptBody() ) {
2966            // lets create a ScriptReference to pass into the closure
2967
cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference");
2968            cv.visitInsn(DUP);
2969
2970            loadThisOrOwner();
2971            cv.visitLdcInsn(name);
2972
2973            cv.visitMethodInsn(
2974                INVOKESPECIAL,
2975                "org/codehaus/groovy/runtime/ScriptReference",
2976                "<init>",
2977                "(Lgroovy/lang/Script;Ljava/lang/String;)V");
2978        }
2979        else {
2980            visitPropertyExpression(new PropertyExpression(VariableExpression.THIS_EXPRESSION, name));
2981        }
2982    }
2983
2984
2985    protected void processFieldAccess( String JavaDoc name, FieldNode field, int steps ) {
2986        FieldExpression expression = new FieldExpression(field);
2987
2988        if( steps == 0 ) {
2989            visitFieldExpression( expression );
2990        }
2991        else {
2992            visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true );
2993        }
2994    }
2995
2996
2997
2998    /**
2999     * @return true if we are in a script body, where all variables declared are no longer
3000     * local variables but are properties
3001     */

3002    protected boolean isInScriptBody() {
3003        if (classNode.isScriptBody()) {
3004            return true;
3005        }
3006        else {
3007            return classNode.isScript() && methodNode != null && methodNode.getName().equals("run");
3008        }
3009    }
3010
3011    /**
3012     * @return true if this expression will have left a value on the stack
3013     * that must be popped
3014     */

3015    protected boolean isPopRequired(Expression expression) {
3016        if (expression instanceof MethodCallExpression) {
3017            if (expression.getType() != null && expression.getType().equals("void")) { // nothing on the stack
3018
return false;
3019            } else {
3020                return !MethodCallExpression.isSuperMethodCall((MethodCallExpression) expression);
3021            }
3022        }
3023        if (expression instanceof BinaryExpression) {
3024            BinaryExpression binExp = (BinaryExpression) expression;
3025            switch (binExp.getOperation().getType()) { // br todo should leave a copy of the value on the stack for all the assignemnt.
3026
// case Types.EQUAL : // br a copy of the right value is left on the stack (see evaluateEqual()) so a pop is required for a standalone assignment
3027
// case Types.PLUS_EQUAL : // this and the following are related to evaluateBinaryExpressionWithAsignment()
3028
// case Types.MINUS_EQUAL :
3029
// case Types.MULTIPLY_EQUAL :
3030
// case Types.DIVIDE_EQUAL :
3031
// case Types.INTDIV_EQUAL :
3032
// case Types.MOD_EQUAL :
3033
// return false;
3034
}
3035        }
3036        return true;
3037    }
3038
3039    protected boolean firstStatementIsSuperInit(Statement code) {
3040        ExpressionStatement expStmt = null;
3041        if (code instanceof ExpressionStatement) {
3042            expStmt = (ExpressionStatement) code;
3043        }
3044        else if (code instanceof BlockStatement) {
3045            BlockStatement block = (BlockStatement) code;
3046            if (!block.getStatements().isEmpty()) {
3047                Object JavaDoc expr = block.getStatements().get(0);
3048                if (expr instanceof ExpressionStatement) {
3049                    expStmt = (ExpressionStatement) expr;
3050                }
3051            }
3052        }
3053        if (expStmt != null) {
3054            Expression expr = expStmt.getExpression();
3055            if (expr instanceof MethodCallExpression) {
3056                MethodCallExpression call = (MethodCallExpression) expr;
3057                if (MethodCallExpression.isSuperMethodCall(call)) {
3058                    // not sure which one is constantly used as the super class ctor call. To cover both for now
3059
return call.getMethod().equals("<init>") || call.getMethod().equals("super");
3060                }
3061            }
3062        }
3063        return false;
3064    }
3065
3066    protected void createSyntheticStaticFields() {
3067        for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) {
3068            String JavaDoc staticFieldName = (String JavaDoc) iter.next();
3069            // generate a field node
3070
cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null);
3071        }
3072
3073        if (!syntheticStaticFields.isEmpty()) {
3074            cv =
3075                cw.visitMethod(
3076                    ACC_STATIC + ACC_SYNTHETIC,
3077                    "class$",
3078                    "(Ljava/lang/String;)Ljava/lang/Class;",
3079                    null,
3080                    null);
3081            helper = new BytecodeHelper(cv);
3082
3083            Label l0 = new Label();
3084            cv.visitLabel(l0);
3085            cv.visitVarInsn(ALOAD, 0);
3086            cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
3087            Label l1 = new Label();
3088            cv.visitLabel(l1);
3089            cv.visitInsn(ARETURN);
3090            Label l2 = new Label();
3091            cv.visitLabel(l2);
3092            cv.visitVarInsn(ASTORE, 1);
3093            cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
3094            cv.visitInsn(DUP);
3095            cv.visitVarInsn(ALOAD, 1);
3096            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;");
3097            cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
3098            cv.visitInsn(ATHROW);
3099            cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); // br using l2 as the 2nd param seems create the right table entry
3100
cv.visitMaxs(3, 2);
3101
3102            cw.visitEnd();
3103        }
3104    }
3105    /** load class object on stack */
3106    public void visitClassExpression(ClassExpression expression) {
3107        String JavaDoc type = expression.getText();
3108        //type = checkValidType(type, expression, "Must be a valid type name for a constructor call");
3109

3110
3111        if (BytecodeHelper.isPrimitiveType(type)) {
3112            String JavaDoc objectType = BytecodeHelper.getObjectTypeForPrimitive(type);
3113            cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;");
3114        }
3115        else {
3116            final String JavaDoc staticFieldName =
3117                (type.equals(classNode.getName())) ? "class$0" : "class$" + type.replace('.', '$').replace('[', '_').replace(';', '_');
3118
3119            syntheticStaticFields.add(staticFieldName);
3120
3121            cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
3122            Label l0 = new Label();
3123            cv.visitJumpInsn(IFNONNULL, l0);
3124            cv.visitLdcInsn(type);
3125            cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
3126            cv.visitInsn(DUP);
3127            cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
3128            Label l1 = new Label();
3129            cv.visitJumpInsn(GOTO, l1);
3130            cv.visitLabel(l0);
3131            cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
3132            cv.visitLabel(l1);
3133        }
3134    }
3135
3136    public void visitRangeExpression(RangeExpression expression) {
3137        leftHandExpression = false;
3138        expression.getFrom().visit(this);
3139
3140        leftHandExpression = false;
3141        expression.getTo().visit(this);
3142
3143        helper.pushConstant(expression.isInclusive());
3144
3145        createRangeMethod.call(cv);
3146    }
3147
3148    public void visitMapEntryExpression(MapEntryExpression expression) {
3149    }
3150
3151    public void visitMapExpression(MapExpression expression) {
3152        List entries = expression.getMapEntryExpressions();
3153        int size = entries.size();
3154        helper.pushConstant(size * 2);
3155
3156        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3157
3158        int i = 0;
3159        for (Iterator iter = entries.iterator(); iter.hasNext();) {
3160            MapEntryExpression entry = (MapEntryExpression) iter.next();
3161
3162            cv.visitInsn(DUP);
3163            helper.pushConstant(i++);
3164            visitAndAutoboxBoolean(entry.getKeyExpression());
3165            cv.visitInsn(AASTORE);
3166
3167            cv.visitInsn(DUP);
3168            helper.pushConstant(i++);
3169            visitAndAutoboxBoolean(entry.getValueExpression());
3170            cv.visitInsn(AASTORE);
3171        }
3172        createMapMethod.call(cv);
3173    }
3174
3175    public void visitTupleExpression(TupleExpression expression) {
3176        int size = expression.getExpressions().size();
3177
3178        helper.pushConstant(size);
3179
3180        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3181
3182        for (int i = 0; i < size; i++) {
3183            cv.visitInsn(DUP);
3184            helper.pushConstant(i);
3185            visitAndAutoboxBoolean(expression.getExpression(i));
3186            cv.visitInsn(AASTORE);
3187        }
3188        //createTupleMethod.call(cv);
3189
}
3190
3191    public void visitArrayExpression(ArrayExpression expression) {
3192        String JavaDoc type = expression.getElementType();
3193        String JavaDoc typeName = BytecodeHelper.getClassInternalName(type);
3194        Expression sizeExpression = expression.getSizeExpression();
3195        if (sizeExpression != null) {
3196            // lets convert to an int
3197
visitAndAutoboxBoolean(sizeExpression);
3198            asIntMethod.call(cv);
3199
3200            cv.visitTypeInsn(ANEWARRAY, typeName);
3201        }
3202        else {
3203            int size = expression.getExpressions().size();
3204            helper.pushConstant(size);
3205
3206            cv.visitTypeInsn(ANEWARRAY, typeName);
3207
3208            for (int i = 0; i < size; i++) {
3209                cv.visitInsn(DUP);
3210                helper.pushConstant(i);
3211                Expression elementExpression = expression.getExpression(i);
3212                if (elementExpression == null) {
3213                    ConstantExpression.NULL.visit(this);
3214                }
3215                else {
3216
3217                    if(!type.equals(elementExpression.getClass().getName())) {
3218                        visitCastExpression(new CastExpression(type, elementExpression));
3219                    }
3220                    else {
3221                        visitAndAutoboxBoolean(elementExpression);
3222                    }
3223                }
3224                cv.visitInsn(AASTORE);
3225            }
3226        }
3227    }
3228
3229    public void visitListExpression(ListExpression expression) {
3230        int size = expression.getExpressions().size();
3231        helper.pushConstant(size);
3232
3233        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3234
3235        for (int i = 0; i < size; i++) {
3236            cv.visitInsn(DUP);
3237            helper.pushConstant(i);
3238            visitAndAutoboxBoolean(expression.getExpression(i));
3239            cv.visitInsn(AASTORE);
3240        }
3241        createListMethod.call(cv);
3242    }
3243
3244    public void visitGStringExpression(GStringExpression expression) {
3245        int size = expression.getValues().size();
3246        helper.pushConstant(size);
3247
3248        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3249
3250        for (int i = 0; i < size; i++) {
3251            cv.visitInsn(DUP);
3252            helper.pushConstant(i);
3253            visitAndAutoboxBoolean(expression.getValue(i));
3254            cv.visitInsn(AASTORE);
3255        }
3256
3257        Variable tv = visitASTOREInTemp("iterator");
3258        int paramIdx = tv.getIndex();
3259
3260        ClassNode innerClass = createGStringClass(expression);
3261        addInnerClass(innerClass);
3262        String JavaDoc innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName());
3263
3264        cv.visitTypeInsn(NEW, innerClassinternalName);
3265        cv.visitInsn(DUP);
3266        cv.visitVarInsn(ALOAD, paramIdx);
3267
3268        cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V");
3269        removeVar(tv);
3270    }
3271
3272    private Variable visitASTOREInTemp(String JavaDoc s) {
3273        return storeInTemp(s, "java.lang.Object");
3274    }
3275
3276    // Implementation methods
3277
//-------------------------------------------------------------------------
3278
protected boolean addInnerClass(ClassNode innerClass) {
3279        innerClass.setModule(classNode.getModule());
3280        return innerClasses.add(innerClass);
3281    }
3282
3283    protected ClassNode createClosureClass(ClosureExpression expression) {
3284        ClassNode owner = getOutermostClass();
3285        boolean parentIsInnerClass = owner instanceof InnerClassNode;
3286        String JavaDoc outerClassName = owner.getName();
3287        String JavaDoc name = outerClassName + "$"
3288                + context.getNextClosureInnerName(owner, classNode, methodNode); // br added a more infomative name
3289
boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass();
3290        if (staticMethodOrInStaticClass) {
3291            outerClassName = "java.lang.Class";
3292        }
3293        Parameter[] parameters = expression.getParameters();
3294        if (parameters == null || parameters.length == 0) {
3295            // lets create a default 'it' parameter
3296
parameters = new Parameter[] { new Parameter("it")};
3297        }
3298
3299        Parameter[] localVariableParams = getClosureSharedVariables(expression);
3300
3301        InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, "groovy.lang.Closure"); // clsures are local inners and not public
3302
answer.setEnclosingMethod(this.methodNode);
3303        if (staticMethodOrInStaticClass) {
3304            answer.setStaticClass(true);
3305        }
3306        if (isInScriptBody()) {
3307            answer.setScriptBody(true);
3308        }
3309        MethodNode method =
3310            answer.addMethod("doCall", ACC_PUBLIC, "java.lang.Object", parameters, expression.getCode());
3311
3312        method.setLineNumber(expression.getLineNumber());
3313        method.setColumnNumber(expression.getColumnNumber());
3314
3315        VariableScope varScope = expression.getVariableScope();
3316        if (varScope == null) {
3317            throw new RuntimeException JavaDoc(
3318                "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
3319        }
3320        else {
3321            method.setVariableScope(varScope);
3322        }
3323        if (parameters.length > 1
3324            || (parameters.length == 1
3325                && parameters[0].getType() != null
3326                && !parameters[0].getType().equals("java.lang.Object"))) {
3327
3328            // lets add a typesafe call method
3329
answer.addMethod(
3330                "call",
3331                ACC_PUBLIC,
3332                "java.lang.Object",
3333                parameters,
3334                new ReturnStatement(
3335                    new MethodCallExpression(
3336                        VariableExpression.THIS_EXPRESSION,
3337                        "doCall",
3338                        new ArgumentListExpression(parameters))));
3339        }
3340
3341        FieldNode ownerField = answer.addField("owner", ACC_PRIVATE, outerClassName, null);
3342
3343        // lets make the constructor
3344
BlockStatement block = new BlockStatement();
3345        block.addStatement(
3346            new ExpressionStatement(
3347                new MethodCallExpression(
3348                    new VariableExpression("super"),
3349                    "<init>",
3350                    new VariableExpression("_outerInstance"))));
3351        block.addStatement(
3352            new ExpressionStatement(
3353                new BinaryExpression(
3354                    new FieldExpression(ownerField),
3355                    Token.newSymbol(Types.EQUAL, -1, -1),
3356                    new VariableExpression("_outerInstance"))));
3357
3358        // lets assign all the parameter fields from the outer context
3359
for (int i = 0; i < localVariableParams.length; i++) {
3360            Parameter param = localVariableParams[i];
3361            String JavaDoc paramName = param.getName();
3362            boolean holder = mutableVars.contains(paramName);
3363            Expression initialValue = null;
3364            String JavaDoc type = param.getType();
3365            FieldNode paramField = null;
3366            if (holder) {
3367                initialValue = new VariableExpression(paramName);
3368                type = Reference.class.getName();
3369                param.makeReference();
3370                paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue);
3371                paramField.setHolder(true);
3372                String JavaDoc realType = param.getRealType();
3373                String JavaDoc methodName = Verifier.capitalize(paramName);
3374
3375                // lets add a getter & setter
3376
Expression fieldExp = new FieldExpression(paramField);
3377                answer.addMethod(
3378                    "get" + methodName,
3379                    ACC_PUBLIC,
3380                    realType,
3381                    Parameter.EMPTY_ARRAY,
3382                    new ReturnStatement(fieldExp));
3383
3384                /*
3385                answer.addMethod(
3386                    "set" + methodName,
3387                    ACC_PUBLIC,
3388                    "void",
3389                    new Parameter[] { new Parameter(realType, "__value") },
3390                    new ExpressionStatement(
3391                        new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("__value"))));
3392                        */

3393            }
3394            else {
3395                PropertyNode propertyNode = answer.addProperty(paramName, ACC_PUBLIC, type, initialValue, null, null);
3396                paramField = propertyNode.getField();
3397                block.addStatement(
3398                    new ExpressionStatement(
3399                        new BinaryExpression(
3400                            new FieldExpression(paramField),
3401                            Token.newSymbol(Types.EQUAL, -1, -1),
3402                            new VariableExpression(paramName))));
3403            }
3404        }
3405
3406        Parameter[] params = new Parameter[2 + localVariableParams.length];
3407        params[0] = new Parameter(outerClassName, "_outerInstance");
3408        params[1] = new Parameter("java.lang.Object", "_delegate");
3409        System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
3410
3411        answer.addConstructor(ACC_PUBLIC, params, block);
3412        return answer;
3413    }
3414
3415    protected ClassNode getOutermostClass() {
3416        if (outermostClass == null) {
3417            outermostClass = classNode;
3418            while (outermostClass instanceof InnerClassNode) {
3419                outermostClass = outermostClass.getOuterClass();
3420            }
3421        }
3422        return outermostClass;
3423    }
3424
3425    protected ClassNode createGStringClass(GStringExpression expression) {
3426        ClassNode owner = classNode;
3427        if (owner instanceof InnerClassNode) {
3428            owner = owner.getOuterClass();
3429        }
3430        String JavaDoc outerClassName = owner.getName();
3431        String JavaDoc name = outerClassName + "$" + context.getNextInnerClassIdx();
3432        InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, GString.class.getName());
3433        answer.setEnclosingMethod(this.methodNode);
3434        FieldNode stringsField =
3435            answer.addField(
3436                "strings",
3437                ACC_PRIVATE /*| ACC_STATIC*/,
3438                "java.lang.String[]",
3439                new ArrayExpression("java.lang.String", expression.getStrings()));
3440        answer.addMethod(
3441            "getStrings",
3442            ACC_PUBLIC,
3443            "java.lang.String[]",
3444            Parameter.EMPTY_ARRAY,
3445            new ReturnStatement(new FieldExpression(stringsField)));
3446        // lets make the constructor
3447
BlockStatement block = new BlockStatement();
3448        block.addStatement(
3449            new ExpressionStatement(
3450                new MethodCallExpression(new VariableExpression("super"), "<init>", new VariableExpression("values"))));
3451        Parameter[] contructorParams = new Parameter[] { new Parameter("java.lang.Object[]", "values")};
3452        answer.addConstructor(ACC_PUBLIC, contructorParams, block);
3453        return answer;
3454    }
3455
3456    protected void doConvertAndCast(String JavaDoc type) {
3457        if (!type.equals("java.lang.Object")) {
3458            /** todo should probably support array coercions */
3459            if (!type.endsWith("[]") && isValidTypeForCast(type)) {
3460                visitClassExpression(new ClassExpression(type));
3461                asTypeMethod.call(cv);
3462            }
3463
3464            helper.doCast(type);
3465        }
3466    }
3467
3468    protected void evaluateLogicalOrExpression(BinaryExpression expression) {
3469        visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
3470        Label l0 = new Label();
3471        Label l2 = new Label();
3472        cv.visitJumpInsn(IFEQ, l0);
3473
3474        cv.visitLabel(l2);
3475
3476        visitConstantExpression(ConstantExpression.TRUE);
3477
3478        Label l1 = new Label();
3479        cv.visitJumpInsn(GOTO, l1);
3480        cv.visitLabel(l0);
3481
3482        visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
3483
3484        cv.visitJumpInsn(IFNE, l2);
3485
3486        visitConstantExpression(ConstantExpression.FALSE);
3487        cv.visitLabel(l1);
3488    }
3489
3490    // todo: optimization: change to return primitive boolean. need to adjust the BinaryExpression and isComparisonExpression for
3491
// consistancy.
3492
protected void evaluateLogicalAndExpression(BinaryExpression expression) {
3493        visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
3494        Label l0 = new Label();
3495        cv.visitJumpInsn(IFEQ, l0);
3496
3497        visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
3498
3499        cv.visitJumpInsn(IFEQ, l0);
3500
3501        visitConstantExpression(ConstantExpression.TRUE);
3502
3503        Label l1 = new Label();
3504        cv.visitJumpInsn(GOTO, l1);
3505        cv.visitLabel(l0);
3506
3507        visitConstantExpression(ConstantExpression.FALSE);
3508
3509        cv.visitLabel(l1);
3510    }
3511
3512    protected void evaluateBinaryExpression(String JavaDoc method, BinaryExpression expression) {
3513        Expression leftExpression = expression.getLeftExpression();
3514        leftHandExpression = false;
3515        leftExpression.visit(this);
3516        cv.visitLdcInsn(method);
3517        leftHandExpression = false;
3518        new ArgumentListExpression(new Expression[] { expression.getRightExpression()}).visit(this);
3519        // expression.getRightExpression().visit(this);
3520
invokeMethodMethod.call(cv);
3521    }
3522
3523    protected void evaluateCompareTo(BinaryExpression expression) {
3524        Expression leftExpression = expression.getLeftExpression();
3525        leftHandExpression = false;
3526        leftExpression.visit(this);
3527        expression.getRightExpression().visit(this);
3528        compareToMethod.call(cv);
3529    }
3530
3531    protected void evaluateBinaryExpressionWithAsignment(String JavaDoc method, BinaryExpression expression) {
3532        Expression leftExpression = expression.getLeftExpression();
3533        if (leftExpression instanceof BinaryExpression) {
3534            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
3535            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
3536                // lets replace this assignment to a subscript operator with a
3537
// method call
3538
// e.g. x[5] += 10
3539
// -> (x, [], 5), =, x[5] + 10
3540
// -> methodCall(x, "putAt", [5, methodCall(x[5], "plus", 10)])
3541

3542                MethodCallExpression methodCall =
3543                    new MethodCallExpression(
3544                        expression.getLeftExpression(),
3545                        method,
3546                        new ArgumentListExpression(new Expression[] { expression.getRightExpression()}));
3547
3548                Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression());
3549
3550                visitMethodCallExpression(
3551                    new MethodCallExpression(
3552                        leftBinExpr.getLeftExpression(),
3553                        "putAt",
3554                        new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall })));
3555                //cv.visitInsn(POP);
3556
return;
3557            }
3558        }
3559
3560        evaluateBinaryExpression(method, expression);
3561
3562        // br to leave a copy of rvalue on the stack. see also isPopRequired()
3563
cv.visitInsn(DUP);
3564
3565        leftHandExpression = true;
3566        evaluateExpression(leftExpression);
3567        leftHandExpression = false;
3568    }
3569
3570    private void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression bin) {
3571        if (ENABLE_EARLY_BINDING && true) {
3572            evalBinaryExp_EarlyBinding(compareMethod, bin);
3573        }
3574        else {
3575            evalBinaryExp_LateBinding(compareMethod, bin);
3576        }
3577    }
3578
3579    protected void evalBinaryExp_LateBinding(MethodCaller compareMethod, BinaryExpression expression) {
3580        Expression leftExp = expression.getLeftExpression();
3581        Expression rightExp = expression.getRightExpression();
3582        load(leftExp);
3583        load(rightExp);
3584        compareMethod.call(cv);
3585    }
3586
3587    /**
3588     * note: leave the primitive boolean on staock for comparison expressions. All the result types need to match the
3589     * utility methods in the InvokerHelper.
3590     * @param compareMethod
3591     * @param expression
3592     */

3593    protected void evalBinaryExp_EarlyBinding(MethodCaller compareMethod, BinaryExpression expression) {
3594        Expression leftExp = expression.getLeftExpression();
3595        Expression rightExp = expression.getRightExpression();
3596
3597        expression.resolve(this);
3598        if (expression.isResolveFailed() || expression.getTypeClass() == null){
3599            evalBinaryExp_LateBinding(compareMethod, expression);
3600            return;
3601        }
3602        else {
3603            Class JavaDoc lclass = leftExp.getTypeClass();
3604            Class JavaDoc rclass = rightExp.getTypeClass();
3605            if (lclass == null || rclass == null) {
3606                if ((lclass == null && rclass != null) || (lclass != null && rclass == null)) {
3607                    // lets treat special cases: obj == null / obj != null . leave primitive boolean on the stack, which will be boxed by visitAndAutoBox()
3608
if (leftExp == ConstantExpression.NULL && !rclass.isPrimitive() ||
3609                            rightExp == ConstantExpression.NULL && !lclass.isPrimitive()) {
3610                        Expression exp = leftExp == ConstantExpression.NULL? rightExp : leftExp;
3611                        int type = expression.getOperation().getType();
3612                        switch (type) {
3613                            case Types.COMPARE_EQUAL :
3614                                load(exp);
3615                                cv.visitInsn(ICONST_1);
3616                                cv.visitInsn(SWAP);
3617                                Label l1 = new Label();
3618                                cv.visitJumpInsn(IFNULL, l1);
3619                                cv.visitInsn(POP);
3620                                cv.visitInsn(ICONST_0);
3621                                cv.visitLabel(l1);
3622                                return;
3623                            case Types.COMPARE_NOT_EQUAL :
3624                                load(exp);
3625                                cv.visitInsn(ICONST_1);
3626                                cv.visitInsn(SWAP);
3627                                Label l2 = new Label();
3628                                cv.visitJumpInsn(IFNONNULL, l2);
3629                                cv.visitInsn(POP);
3630                                cv.visitInsn(ICONST_0);
3631                                cv.visitLabel(l2);
3632                                return;
3633                            default:
3634                                evalBinaryExp_LateBinding(compareMethod, expression);
3635                                return;
3636                        }
3637                    }
3638                    else {
3639                        evalBinaryExp_LateBinding(compareMethod, expression);
3640                        return;
3641                    }
3642                }
3643                else {
3644                    evalBinaryExp_LateBinding(compareMethod, expression);
3645                    return;
3646                }
3647            }
3648            else if (lclass == String JavaDoc.class && rclass == String JavaDoc.class) {
3649                int type = expression.getOperation().getType();
3650                switch (type) {
3651                    case Types.COMPARE_EQUAL : // ==
3652
load(leftExp); cast(String JavaDoc.class);
3653                        load(rightExp); cast(String JavaDoc.class);
3654                        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
3655                        //helper.quickBoxIfNecessary(boolean.class);
3656
return;
3657                    case Types.COMPARE_NOT_EQUAL :
3658                        load(leftExp);cast(String JavaDoc.class);
3659                        load(rightExp); cast(String JavaDoc.class);
3660                        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
3661                        cv.visitInsn(ICONST_1);
3662                        cv.visitInsn(IXOR);
3663                        //helper.quickBoxIfNecessary(boolean.class);
3664
return;
3665                    case Types.COMPARE_TO :
3666                        load(leftExp);cast(String JavaDoc.class);
3667                        load(rightExp); cast(String JavaDoc.class);
3668                        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I");
3669                        helper.quickBoxIfNecessary(int.class); // object type
3670
return;
3671                    case Types.COMPARE_GREATER_THAN :
3672                    case Types.COMPARE_GREATER_THAN_EQUAL :
3673                    case Types.COMPARE_LESS_THAN :
3674                    case Types.COMPARE_LESS_THAN_EQUAL :
3675                        {
3676                            int op;
3677                            switch (type) {
3678                                case Types.COMPARE_GREATER_THAN :
3679                                    op = IFLE;
3680                                    break;
3681                                case Types.COMPARE_GREATER_THAN_EQUAL :
3682                                    op = IFLT;
3683                                    break;
3684                                case Types.COMPARE_LESS_THAN :
3685                                    op = IFGE;
3686                                    break;
3687                                case Types.COMPARE_LESS_THAN_EQUAL :
3688                                    op = IFGT;
3689                                    break;
3690                                default:
3691                                    System.err.println("flow control error: should not be here. type: " + type);
3692                                    return;
3693                            }
3694                            load(leftExp);cast(String JavaDoc.class);
3695                            load(rightExp); cast(String JavaDoc.class);
3696                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I");
3697
3698                            // set true/false on stack
3699
Label l4 = new Label();
3700                            cv.visitJumpInsn(op, l4);
3701                            // need to use primitive boolean //cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
3702
cv.visitInsn(ICONST_1); // true
3703
Label l5 = new Label();
3704                            cv.visitJumpInsn(GOTO, l5);
3705                            cv.visitLabel(l4);
3706                            cv.visitInsn(ICONST_0); //cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
3707
cv.visitLabel(l5);
3708                        }
3709                        return;
3710
3711                    default:
3712                        evalBinaryExp_LateBinding(compareMethod, expression);
3713                        return;
3714                }
3715            }
3716            else if (Integer JavaDoc.class == lclass && Integer JavaDoc.class == rclass) {
3717                int type = expression.getOperation().getType();
3718                switch (type) {
3719                    case Types.COMPARE_EQUAL : // ==
3720
load(leftExp); cast(Integer JavaDoc.class);
3721                        load(rightExp);
3722                        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z");
3723                        //helper.quickBoxIfNecessary(boolean.class);
3724
return;
3725                    case Types.COMPARE_NOT_EQUAL :
3726                        load(leftExp); cast(Integer JavaDoc.class);
3727                        load(rightExp);
3728                        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z");
3729                        cv.visitInsn(ICONST_1);
3730                        cv.visitInsn(IXOR);
3731                        //helper.quickBoxIfNecessary(boolean.class);
3732
return;
3733                    case Types.COMPARE_TO :
3734                        load(leftExp); cast(Integer JavaDoc.class);
3735                        load(rightExp);
3736                        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I");
3737                        helper.quickBoxIfNecessary(int.class);
3738                        return;
3739                    case Types.COMPARE_GREATER_THAN :
3740                    case Types.COMPARE_GREATER_THAN_EQUAL :
3741                    case Types.COMPARE_LESS_THAN :
3742                    case Types.COMPARE_LESS_THAN_EQUAL :
3743                        {
3744                            int op;
3745                            switch (type) {
3746                                case Types.COMPARE_GREATER_THAN :
3747                                    op = IFLE;
3748                                    break;
3749                                case Types.COMPARE_GREATER_THAN_EQUAL :
3750                                    op = IFLT;
3751                                    break;
3752                                case Types.COMPARE_LESS_THAN :
3753                                    op = IFGE;
3754                                    break;
3755                                case Types.COMPARE_LESS_THAN_EQUAL :
3756                                    op = IFGT;
3757                                    break;
3758                                default:
3759                                    System.err.println("flow control error: should not be here. type: " + type);
3760                                    return;
3761                            }
3762                            load(leftExp); cast(Integer JavaDoc.class);
3763                            load(rightExp);
3764                            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I");
3765
3766                            Label l4 = new Label();
3767                            cv.visitJumpInsn(op, l4);
3768                            cv.visitInsn(ICONST_1); //cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
3769
Label l5 = new Label();
3770                            cv.visitJumpInsn(GOTO, l5);
3771                            cv.visitLabel(l4);
3772                            cv.visitInsn(ICONST_0);//cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
3773
cv.visitLabel(l5);
3774                        }
3775                        return;
3776
3777                    default:
3778                        evalBinaryExp_LateBinding(compareMethod, expression);
3779                        return;
3780                }
3781            }
3782            else {
3783                evalBinaryExp_LateBinding(compareMethod, expression);
3784                return;
3785            }
3786        }
3787    }
3788
3789    private void cast(Class JavaDoc aClass) {
3790        if (!aClass.isPrimitive() && aClass != Object JavaDoc.class) {
3791            cv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(aClass.getName()));
3792        }
3793    }
3794
3795    protected void evaluateEqual(BinaryExpression expression) {
3796        if (ENABLE_EARLY_BINDING) {
3797            expression.resolve(this);
3798            if (expression.isTypeResolved()) {
3799                if (expression.getRightExpression().getTypeClass() == Void.TYPE) {
3800                    throwException("void value appeared on right hand side of assignment. ");
3801                }
3802            }
3803        }
3804
3805        Expression leftExpression = expression.getLeftExpression();
3806        if (leftExpression instanceof BinaryExpression) {
3807            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
3808            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
3809                // lets replace this assignment to a subscript operator with a
3810
// method call
3811
// e.g. x[5] = 10
3812
// -> (x, [], 5), =, 10
3813
// -> methodCall(x, "putAt", [5, 10])
3814
do {
3815                    if (true && ENABLE_EARLY_BINDING){
3816                        Class JavaDoc typeclass = leftBinExpr.getLeftExpression().getTypeClass();
3817                        if (typeclass == null) {
3818                            break;
3819                        }
3820
3821                        if (typeclass == Map.class) {// call aMap.put()
3822
load(expression.getRightExpression());
3823                            // let's leave a copy of the value on the stack.
3824
cv.visitInsn(DUP);
3825                            final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType());
3826                            // VariableExpression tempVarExp = new VariableExpression(rightTemp.getName(), expression.getRightExpression().getType());
3827
final Class JavaDoc rclass = expression.getRightExpression().getTypeClass();
3828                            BytecodeExpression loadTempByteCode = new BytecodeExpression() {
3829                                public void visit(GroovyCodeVisitor visitor) {
3830                                    cv.visitVarInsn(ALOAD, rightTemp.getIndex());
3831                                }
3832                                protected void resolveType(AsmClassGenerator2 resolver) {
3833                                    setTypeClass(rclass);
3834                                }
3835                            };
3836
3837                            visitMethodCallExpression(
3838                                    new MethodCallExpression(
3839                                            leftBinExpr.getLeftExpression(),
3840                                            "put",
3841                                            new ArgumentListExpression(
3842                                                    new Expression[] {
3843                                                        leftBinExpr.getRightExpression(),
3844                                                        loadTempByteCode})));
3845                            cv.visitInsn(POP); // pop the put method return
3846
removeVar(rightTemp);
3847                            return;
3848                        }
3849                        else if (typeclass == List.class){
3850                            // call DefaultGroovyMethods.putAt()V
3851
// DefaultGroovyMethods.putAt(x, 5, "c"); this is faster thangoing thru metaclass
3852
// this method does not return any value. so indicate this fact in the expression
3853

3854                            load(expression.getRightExpression());
3855                            // let's leave a copy of the value on the stack. this is really lazy.
3856
cv.visitInsn(DUP);
3857                            final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType());
3858                            // VariableExpression tempVarExp = new VariableExpression(rightTemp.getName(), expression.getRightExpression().getType());
3859
final Class JavaDoc rclass = expression.getRightExpression().getTypeClass();
3860                            BytecodeExpression loadTempBytes = new BytecodeExpression() {
3861                                public void visit(GroovyCodeVisitor visitor) {
3862                                    cv.visitVarInsn(ALOAD, rightTemp.getIndex());
3863                                }
3864                                protected void resolveType(AsmClassGenerator2 resolver) {
3865                                    setTypeClass(rclass);
3866                                }
3867                            };
3868
3869                            visitMethodCallExpression(
3870                                new MethodCallExpression(
3871                                    new ClassExpression(DefaultGroovyMethods.class),
3872                                    "putAt",
3873                                    new ArgumentListExpression(
3874                                        new Expression[] {
3875                                            leftBinExpr.getLeftExpression(),
3876                                            leftBinExpr.getRightExpression(),
3877                                            loadTempBytes })));
3878                            removeVar(rightTemp);
3879                            return;
3880
3881                        }
3882                        else {
3883                            break;
3884                        }
3885                    }
3886                } while (false);
3887
3888                visitMethodCallExpression(
3889                    new MethodCallExpression(
3890                        leftBinExpr.getLeftExpression(),
3891                        "putAt",
3892                        new ArgumentListExpression(
3893                            new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()})));
3894                 // cv.visitInsn(POP); //this is realted to isPopRequired()
3895
return;
3896            }
3897        }
3898
3899        // lets evaluate the RHS then hopefully the LHS will be a field
3900
leftHandExpression = false;
3901        Expression rightExpression = expression.getRightExpression();
3902
3903        String JavaDoc type = getLHSType(leftExpression);
3904        if (type != null) {
3905            //System.out.println("### expression: " + leftExpression);
3906
//System.out.println("### type: " + type);
3907

3908            // lets not cast for primitive types as we handle these in field setting etc
3909
if (BytecodeHelper.isPrimitiveType(type)) {
3910                rightExpression.visit(this);
3911            }
3912            else {
3913                if (ENABLE_EARLY_BINDING) {
3914                    if (leftExpression.isDynamic()) { // br the previous if() probably should check this too!
3915
visitAndAutoboxBoolean(rightExpression);
3916                    }
3917                    else {
3918                        if (type.equals(rightExpression.getType())) {
3919                            visitAndAutoboxBoolean(rightExpression);
3920                        }
3921                        else {
3922                            if (rightExpression instanceof ConstantExpression &&
3923                                    ((ConstantExpression)rightExpression).getValue() == null) {
3924                                cv.visitInsn(ACONST_NULL);
3925                            }
3926                            else {
3927                                visitCastExpression(new CastExpression(type, rightExpression));
3928                            }
3929                        }
3930                    }
3931                }
3932                else if (!type.equals("java.lang.Object")){
3933                    visitCastExpression(new CastExpression(type, rightExpression));
3934                }
3935                else {
3936                    visitAndAutoboxBoolean(rightExpression);
3937                }
3938            }
3939        }
3940        else {
3941            visitAndAutoboxBoolean(rightExpression);
3942        }
3943
3944
3945        // br: attempt to pass type info from right to left for assignment
3946
if (ENABLE_EARLY_BINDING) {
3947            Class JavaDoc rc = rightExpression.getTypeClass();
3948            if (rc != null && rc.isArray()) {
3949                Class JavaDoc elemType = rc.getComponentType();
3950                if (elemType.isPrimitive()) {
3951                    visitClassExpression(new ClassExpression(elemType));
3952                    convertPrimitiveArray.call(cv);
3953                    cast(loadClass(BytecodeHelper.getObjectArrayTypeForPrimitiveArray(elemType.getName() + "[]")));
3954                }
3955            }
3956
3957
3958            if (leftExpression.isDynamic() ) {
3959                // propagate the type from right to left if the left is dynamic
3960
if (!(leftExpression instanceof FieldExpression ) && !(leftExpression instanceof PropertyExpression))
3961                    copyTypeClass(leftExpression, rightExpression);
3962            }
3963            else {
3964                Class JavaDoc lc = leftExpression.getTypeClass();
3965// Class rc = rightExpression.getTypeClass();
3966
if (lc != null && rc != null && !lc.isAssignableFrom(rc) && !lc.isPrimitive()) {
3967                    // let's use extended conversion logic in the invoker class.
3968
if (!lc.isArray()) {
3969                        visitClassExpression(new ClassExpression(lc));
3970                        asTypeMethod.call(cv);
3971                        helper.doCast(lc);
3972                    }
3973                    else {
3974                        // may not need this, since variable type converts primitive array to object array automatically
3975
Class JavaDoc elemType = lc.getComponentType();
3976                        if (elemType.isPrimitive()) {
3977                            // let's allow type copy for primitive array, meaning [i can be changed to [Integer
3978
copyTypeClass(leftExpression, rightExpression);
3979                        }
3980                    }
3981                }
3982            }
3983        }
3984        cv.visitInsn(DUP); // to leave a copy of the rightexpression value on the stack after the assignment.
3985
leftHandExpression = true;
3986        leftExpression.visit(this);
3987        leftHandExpression = false;
3988    }
3989
3990    private void copyTypeClass(Expression leftExpression, Expression rightExpression) {
3991        // copy type class from the right to the left, boxing numbers & treat ClassExpression specially
3992
Class JavaDoc rclass = rightExpression.getTypeClass();
3993        if (rightExpression instanceof ClassExpression) {
3994            leftExpression.setTypeClass(Class JavaDoc.class);
3995        }
3996        else {
3997            rclass = BytecodeHelper.boxOnPrimitive(rclass);
3998            leftExpression.setTypeClass(rclass);
3999        }
4000    }
4001
4002    private boolean canBeAssignedFrom(String JavaDoc ltype, String JavaDoc rtype) {
4003        if (rtype == null) {
4004            return false;
4005        }
4006        else if (ltype == null || ltype.equals("java.lang.Object")) {
4007            return true;
4008        } else {
4009            return false;
4010        }
4011    }
4012
4013    private boolean canBeAssignedFrom(Expression l, Expression r) {
4014            if (r.getTypeClass() == null) {
4015                return false;
4016            }
4017            else if (l.isDynamic()){
4018                return true;
4019            } else {
4020                return false;
4021            }
4022        }
4023    private boolean canBeAssignedFrom(Class JavaDoc l, Class JavaDoc r) {
4024            if (r == null) {
4025                return false;
4026            }
4027            else if (l == null || l == Object JavaDoc.class){
4028                return true;
4029            } else {
4030                return false;
4031            }
4032        }
4033
4034    /**
4035     * Deduces the type name required for some casting
4036     *
4037     * @return the type of the given (LHS) expression or null if it is java.lang.Object or it cannot be deduced
4038     */

4039    protected String JavaDoc getLHSType(Expression leftExpression) {
4040        do {
4041// commented out. not quiteworking yet. would complain something like:
4042
//java.lang.ClassFormatError: Foo$1 (Illegal Field name "class$[Ljava$lang$String;")
4043
//
4044
// if (ENABLE_EARLY_BINDING) {
4045
// String type = leftExpression.getType();
4046
// if (type == null)
4047
// break;
4048
// return isValidTypeForCast(type) ? type : null;
4049
// }
4050
} while (false);
4051
4052        if (leftExpression instanceof VariableExpression) {
4053            VariableExpression varExp = (VariableExpression) leftExpression;
4054            String JavaDoc type = varExp.getType();
4055            if (isValidTypeForCast(type)) {
4056                return type;
4057            }
4058            String JavaDoc variableName = varExp.getVariable();
4059            Variable variable = (Variable) variableStack.get(variableName);
4060            if (variable != null) {
4061                if (variable.isHolder() || variable.isProperty()) {
4062                    return null;
4063                }
4064                type = variable.getTypeName();
4065                if (isValidTypeForCast(type)) {
4066                    return type;
4067                }
4068            }
4069            else {
4070                FieldNode field = classNode.getField(variableName);
4071                if (field == null) {
4072                    field = classNode.getOuterField(variableName);
4073                }
4074                if (field != null) {
4075                    type = field.getType();
4076                    if (!field.isHolder() && isValidTypeForCast(type)) {
4077                        return type;
4078                    }
4079                }
4080            }
4081        }
4082        return null;
4083    }
4084
4085    protected boolean isValidTypeForCast(String JavaDoc type) {
4086        return type != null && !type.equals("java.lang.Object") && !type.equals("groovy.lang.Reference") && !BytecodeHelper.isPrimitiveType(type);
4087    }
4088
4089    protected void visitAndAutoboxBoolean(Expression expression) {
4090        expression.visit(this);
4091
4092        if (isComparisonExpression(expression)) {
4093            helper.boxBoolean(); // convert boolean to Boolean
4094
}
4095    }
4096
4097    protected void evaluatePrefixMethod(String JavaDoc method, Expression expression) {
4098        if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) {
4099            cv.visitVarInsn(ALOAD, 0);
4100        }
4101        expression.visit(this);
4102        cv.visitLdcInsn(method);
4103        invokeNoArgumentsMethod.call(cv);
4104
4105        leftHandExpression = true;
4106        expression.visit(this);
4107        leftHandExpression = false;
4108        expression.visit(this);
4109    }
4110
4111    protected void evaluatePostfixMethod(String JavaDoc method, Expression expression) {
4112        leftHandExpression = false;
4113        expression.visit(this);
4114
4115        Variable tv = visitASTOREInTemp("postfix_" + method);
4116        int tempIdx = tv.getIndex();
4117        cv.visitVarInsn(ALOAD, tempIdx);
4118
4119        cv.visitLdcInsn(method);
4120        invokeNoArgumentsMethod.call(cv);
4121
4122        store(expression);
4123
4124        cv.visitVarInsn(ALOAD, tempIdx);
4125        removeVar(tv);
4126    }
4127
4128    protected boolean isHolderVariable(Expression expression) {
4129        if (expression instanceof FieldExpression) {
4130            FieldExpression fieldExp = (FieldExpression) expression;
4131            return fieldExp.getField().isHolder();
4132        }
4133        if (expression instanceof VariableExpression) {
4134            VariableExpression varExp = (VariableExpression) expression;
4135            Variable variable = (Variable) variableStack.get(varExp.getVariable());
4136            if (variable != null) {
4137                return variable.isHolder();
4138            }
4139            FieldNode field = classNode.getField(varExp.getVariable());
4140            if (field != null) {
4141                return field.isHolder();
4142            }
4143        }
4144        return false;
4145    }
4146
4147    protected void evaluateInstanceof(BinaryExpression expression) {
4148        expression.getLeftExpression().visit(this);
4149        Expression rightExp = expression.getRightExpression();
4150        String JavaDoc className = null;
4151        if (rightExp instanceof ClassExpression) {
4152            ClassExpression classExp = (ClassExpression) rightExp;
4153            className = classExp.getType();
4154        }
4155        else {
4156            throw new RuntimeException JavaDoc(
4157                "Right hand side of the instanceof keyworld must be a class name, not: " + rightExp);
4158        }
4159        className = checkValidType(className, expression, "Must be a valid type name for an instanceof statement");
4160        String JavaDoc classInternalName = BytecodeHelper.getClassInternalName(className);
4161        cv.visitTypeInsn(INSTANCEOF, classInternalName);
4162    }
4163
4164    /**
4165     * @return true if the given argument expression requires the stack, in
4166     * which case the arguments are evaluated first, stored in the
4167     * variable stack and then reloaded to make a method call
4168     */

4169    protected boolean argumentsUseStack(Expression arguments) {
4170        return arguments instanceof TupleExpression || arguments instanceof ClosureExpression;
4171    }
4172
4173    /**
4174     * @return true if the given expression represents a non-static field
4175     */

4176    protected boolean isNonStaticField(Expression expression) {
4177        FieldNode field = null;
4178        if (expression instanceof VariableExpression) {
4179            VariableExpression varExp = (VariableExpression) expression;
4180            field = classNode.getField(varExp.getVariable());
4181        }
4182        else if (expression instanceof FieldExpression) {
4183            FieldExpression fieldExp = (FieldExpression) expression;
4184            field = classNode.getField(fieldExp.getFieldName());
4185        }
4186        else if (expression instanceof PropertyExpression) {
4187            PropertyExpression fieldExp = (PropertyExpression) expression;
4188            field = classNode.getField(fieldExp.getProperty());
4189        }
4190        if (field != null) {
4191            return !field.isStatic();
4192        }
4193        return false;
4194    }
4195
4196    protected boolean isThisExpression(Expression expression) {
4197        if (expression instanceof VariableExpression) {
4198            VariableExpression varExp = (VariableExpression) expression;
4199            return varExp.getVariable().equals("this");
4200        }
4201        return false;
4202    }
4203
4204    /**
4205     * For assignment expressions, return a safe expression for the LHS we can use
4206     * to return the value
4207     */

4208    protected Expression createReturnLHSExpression(Expression expression) {
4209        if (expression instanceof BinaryExpression) {
4210            BinaryExpression binExpr = (BinaryExpression) expression;
4211            if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) {
4212                return createReusableExpression(binExpr.getLeftExpression());
4213            }
4214        }
4215        return null;
4216    }
4217
4218    protected Expression createReusableExpression(Expression expression) {
4219        ExpressionTransformer transformer = new ExpressionTransformer() {
4220            public Expression transform(Expression expression) {
4221                if (expression instanceof PostfixExpression) {
4222                    PostfixExpression postfixExp = (PostfixExpression) expression;
4223                    return postfixExp.getExpression();
4224                }
4225                else if (expression instanceof PrefixExpression) {
4226                    PrefixExpression prefixExp = (PrefixExpression) expression;
4227                    return prefixExp.getExpression();
4228                }
4229                return expression;
4230            }
4231        };
4232
4233        // could just be a postfix / prefix expression or nested inside some other expression
4234
return transformer.transform(expression.transformExpression(transformer));
4235    }
4236
4237    protected boolean isComparisonExpression(Expression expression) {
4238        if (expression instanceof BinaryExpression) {
4239            BinaryExpression binExpr = (BinaryExpression) expression;
4240            switch (binExpr.getOperation().getType()) {
4241                case Types.COMPARE_EQUAL :
4242                case Types.MATCH_REGEX :
4243                case Types.COMPARE_GREATER_THAN :
4244                case Types.COMPARE_GREATER_THAN_EQUAL :
4245                case Types.COMPARE_LESS_THAN :
4246                case Types.COMPARE_LESS_THAN_EQUAL :
4247                case Types.COMPARE_IDENTICAL :
4248                case Types.COMPARE_NOT_EQUAL :
4249                case Types.KEYWORD_INSTANCEOF :
4250                    return true;
4251            }
4252        }
4253        else if (expression instanceof BooleanExpression) {
4254            return true;
4255        }
4256        return false;
4257    }
4258
4259    protected void onLineNumber(ASTNode statement, String JavaDoc message) {
4260        int line = statement.getLineNumber();
4261        int col = statement.getColumnNumber();
4262        this.currentASTNode = statement;
4263
4264        if (line >=0) {
4265            lineNumber = line;
4266            columnNumber = col;
4267        }
4268        if (CREATE_DEBUG_INFO && line >= 0 && cv != null) {
4269            Label l = new Label();
4270            cv.visitLabel(l);
4271            cv.visitLineNumber(line, l);
4272            if (ASM_DEBUG) {
4273                helper.mark(message + "[" + statement.getLineNumber() + ":" + statement.getColumnNumber() + "]");
4274            }
4275        }
4276    }
4277
4278    protected VariableScope getVariableScope() {
4279        if (variableScope == null) {
4280            if (methodNode != null) {
4281                // if we're a closure method we'll have our variable scope already created
4282
variableScope = methodNode.getVariableScope();
4283                if (variableScope == null) {
4284                    variableScope = new VariableScope();
4285                    methodNode.setVariableScope(variableScope);
4286                    VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
4287                    visitor.setParameters(methodNode.getParameters());
4288                    Statement code = methodNode.getCode();
4289                    if (code != null) {
4290                        code.visit(visitor);
4291                    }
4292                }
4293                addFieldsToVisitor(variableScope);
4294            }
4295            else if (constructorNode != null) {
4296                variableScope = new VariableScope();
4297                constructorNode.setVariableScope(variableScope);
4298                VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
4299                visitor.setParameters(constructorNode.getParameters());
4300                Statement code = constructorNode.getCode();
4301                if (code != null) {
4302                    code.visit(visitor);
4303                }
4304                addFieldsToVisitor(variableScope);
4305            }
4306            else {
4307                throw new RuntimeException JavaDoc("Can't create a variable scope outside of a method or constructor");
4308            }
4309        }
4310        return variableScope;
4311    }
4312
4313    /**
4314     * @return a list of parameters for each local variable which needs to be
4315     * passed into a closure
4316     */

4317    protected Parameter[] getClosureSharedVariables(ClosureExpression expression) {
4318        List vars = new ArrayList();
4319
4320        //
4321
// First up, get the scopes for outside and inside the closure.
4322
// The inner scope must cover all nested closures, as well, as
4323
// everything that will be needed must be imported.
4324

4325        VariableScope outerScope = getVariableScope().createRecursiveParentScope();
4326        VariableScope innerScope = expression.getVariableScope();
4327        if (innerScope == null) {
4328            System.out.println(
4329                "No variable scope for: " + expression + " method: " + methodNode + " constructor: " + constructorNode);
4330            innerScope = new VariableScope(getVariableScope());
4331        }
4332        else {
4333            innerScope = innerScope.createRecursiveChildScope();
4334        }
4335
4336
4337        //
4338
// DeclaredVariables include any name that was assigned to within
4339
// the scope. ReferencedVariables include any name that was read
4340
// from within the scope. We get the sets from each and must piece
4341
// together the stack variable import list for the closure. Note
4342
// that we don't worry about field variables here, as we don't have
4343
// to do anything special with them. Stack variables, on the other
4344
// hand, have to be wrapped up in References for use.
4345

4346        Set outerDecls = outerScope.getDeclaredVariables();
4347        Set outerRefs = outerScope.getReferencedVariables();
4348        Set innerDecls = innerScope.getDeclaredVariables();
4349        Set innerRefs = innerScope.getReferencedVariables();
4350
4351
4352        //
4353
// So, we care about any name referenced in the closure UNLESS:
4354
// 1) it's not declared in the outer context;
4355
// 2) it's a parameter;
4356
// 3) it's a field in the context class that isn't overridden
4357
// by a stack variable in the outer context.
4358
//
4359
// BUG: We don't actually have the necessary information to do
4360
// this right! The outer declarations don't distinguish
4361
// between assignments and variable declarations. Therefore
4362
// we can't tell when field variables have been overridden
4363
// by stack variables in the outer context. This must
4364
// be fixed!
4365

4366        Set varSet = new HashSet();
4367        for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
4368            String JavaDoc var = (String JavaDoc) iter.next();
4369            // lets not pass in fields from the most-outer class, but pass in values from an outer closure
4370
if (outerDecls.contains(var) && (isNotFieldOfOutermostClass(var))) {
4371                String JavaDoc type = getVariableType(var);
4372                vars.add(new Parameter(type, var));
4373                varSet.add(var);
4374            }
4375        }
4376        for (Iterator iter = outerRefs.iterator(); iter.hasNext();) {
4377            String JavaDoc var = (String JavaDoc) iter.next();
4378            // lets not pass in fields from the most-outer class, but pass in values from an outer closure
4379
if (innerDecls.contains(var) && (isNotFieldOfOutermostClass(var)) && !varSet.contains(var)) {
4380                String JavaDoc type = getVariableType(var);
4381                vars.add(new Parameter(type, var));
4382            }
4383        }
4384
4385
4386        Parameter[] answer = new Parameter[vars.size()];
4387        vars.toArray(answer);
4388        return answer;
4389    }
4390
4391    protected boolean isNotFieldOfOutermostClass(String JavaDoc var) {
4392        //return classNode.getField(var) == null || isInnerClass();
4393
return getOutermostClass().getField(var) == null;
4394    }
4395
4396    protected void findMutableVariables() {
4397        /*
4398        VariableScopeCodeVisitor outerVisitor = new VariableScopeCodeVisitor(true);
4399        node.getCode().visit(outerVisitor);
4400
4401        addFieldsToVisitor(outerVisitor);
4402
4403        VariableScopeCodeVisitor innerVisitor = outerVisitor.getClosureVisitor();
4404        */

4405        VariableScope outerScope = getVariableScope();
4406
4407        // lets create a scope concatenating all the closure expressions
4408
VariableScope innerScope = outerScope.createCompositeChildScope();
4409
4410        Set outerDecls = outerScope.getDeclaredVariables();
4411        Set outerRefs = outerScope.getReferencedVariables();
4412        Set innerDecls = innerScope.getDeclaredVariables();
4413        Set innerRefs = innerScope.getReferencedVariables();
4414
4415        mutableVars.clear();
4416
4417        for (Iterator iter = innerDecls.iterator(); iter.hasNext();) {
4418            String JavaDoc var = (String JavaDoc) iter.next();
4419            if ((outerDecls.contains(var) || outerRefs.contains(var)) && classNode.getField(var) == null) {
4420                mutableVars.add(var);
4421            }
4422        }
4423
4424        // we may call the closure twice and modify the variable in the outer scope
4425
// so for now lets assume that all variables are mutable
4426
for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
4427            String JavaDoc var = (String JavaDoc) iter.next();
4428            if (outerDecls.contains(var) && classNode.getField(var) == null) {
4429                mutableVars.add(var);
4430            }
4431        }
4432
4433        // System.out.println();
4434
// System.out.println("method: " + methodNode + " classNode: " + classNode);
4435
// System.out.println("child scopes: " + outerScope.getChildren());
4436
// System.out.println("outerDecls: " + outerDecls);
4437
// System.out.println("outerRefs: " + outerRefs);
4438
// System.out.println("innerDecls: " + innerDecls);
4439
// System.out.println("innerRefs: " + innerRefs);
4440
}
4441
4442    protected void addFieldsToVisitor(VariableScope scope) {
4443        for (Iterator iter = classNode.getFields().iterator(); iter.hasNext();) {
4444            FieldNode field = (FieldNode) iter.next();
4445            String JavaDoc name = field.getName();
4446
4447            scope.getDeclaredVariables().add(name);
4448            scope.getReferencedVariables().add(name);
4449        }
4450    }
4451
4452    private boolean isInnerClass() {
4453        return classNode instanceof InnerClassNode;
4454    }
4455
4456    protected String JavaDoc getVariableType(String JavaDoc name) {
4457        Variable variable = (Variable) variableStack.get(name);
4458        if (variable != null) {
4459            return variable.getTypeName();
4460        }
4461        return null;
4462    }
4463
4464    protected void resetVariableStack(Parameter[] parameters) {
4465        lastVariableIndex = -1;
4466        variableStack.clear();
4467
4468        scope = new BlockScope(null);
4469        //pushBlockScope();
4470

4471        // lets push this onto the stack
4472
definingParameters = true;
4473        if (!isStaticMethod()) {
4474            defineVariable("this", classNode.getName()).getIndex();
4475        } // now lets create indices for the parameteres
4476
for (int i = 0; i < parameters.length; i++) {
4477            Parameter parameter = parameters[i];
4478            String JavaDoc type = parameter.getType();
4479            Variable v = defineVariable(parameter.getName(), type);
4480            int idx = v.getIndex();
4481            if (BytecodeHelper.isPrimitiveType(type)) {
4482                helper.load(type, idx);
4483                helper.box(type);
4484                cv.visitVarInsn(ASTORE, idx);
4485            }
4486        }
4487        definingParameters = false;
4488    }
4489
4490    protected void popScope() {
4491        int lastID = scope.getFirstVariableIndex();
4492
4493        List removeKeys = new ArrayList();
4494        for (Iterator iter = variableStack.entrySet().iterator(); iter.hasNext();) {
4495            Map.Entry entry = (Map.Entry) iter.next();
4496            String JavaDoc name = (String JavaDoc) entry.getKey();
4497            Variable value = (Variable) entry.getValue();
4498            if (value.getIndex() >= lastID) {
4499                removeKeys.add(name);
4500            }
4501        }
4502        for (Iterator iter = removeKeys.iterator(); iter.hasNext();) {
4503            Variable v = (Variable) variableStack.remove(iter.next());
4504            if (CREATE_DEBUG_INFO) { // set localvartable
4505
if (v != null) {
4506                    visitVariableEndLabel(v);
4507                    cv.visitLocalVariable(
4508                            v.getName(),
4509                            BytecodeHelper.getTypeDescription(v.getTypeName()),
4510                            v.getStartLabel(),
4511                            v.getEndLabel(),
4512                            v.getIndex()
4513                    );
4514                }
4515            }
4516        }
4517        scope = scope.getParent();
4518    }
4519
4520    void removeVar(Variable v ) {
4521        variableStack.remove(v.getName());
4522        if (CREATE_DEBUG_INFO) { // set localvartable
4523
Label endl = new Label();
4524            cv.visitLabel(endl);
4525            cv.visitLocalVariable(
4526                    v.getName(),
4527                    BytecodeHelper.getTypeDescription(v.getTypeName()),
4528                    v.getStartLabel(),
4529                    endl,
4530                    v.getIndex()
4531            );
4532        }
4533    }
4534    private void visitVariableEndLabel(Variable v) {
4535        if (CREATE_DEBUG_INFO) {
4536            if(v.getEndLabel() == null) {
4537                Label end = new Label();
4538                v.setEndLabel(end);
4539            }
4540            cv.visitLabel(v.getEndLabel());
4541        }
4542    }
4543
4544    protected void pushBlockScope() {
4545        pushBlockScope(true, true);
4546    }
4547
4548    /**
4549     * create a new scope. Set break/continue label if the canXXX parameter is true. Otherwise
4550     * inherit parent's label.
4551     * @param canContinue true if the start of the scope can take continue label
4552     * @param canBreak true if the end of the scope can take break label
4553     */

4554    protected void pushBlockScope(boolean canContinue, boolean canBreak) {
4555        BlockScope parentScope = scope;
4556        scope = new BlockScope(parentScope);
4557        scope.setContinueLabel(canContinue ? new Label() : (parentScope == null ? null : parentScope.getContinueLabel()));
4558        scope.setBreakLabel(canBreak? new Label() : (parentScope == null ? null : parentScope.getBreakLabel()));
4559        scope.setFirstVariableIndex(getNextVariableID());
4560    }
4561
4562    /**
4563     * Defines the given variable in scope and assigns it to the stack
4564     */

4565    protected Variable defineVariable(String JavaDoc name, String JavaDoc type) {
4566        return defineVariable(name, type, true);
4567    }
4568
4569    protected Variable defineVariable(String JavaDoc name, String JavaDoc type, boolean define) {
4570        return defineVariable(name, new Type(type), define);
4571    }
4572
4573    private Variable defineVariable(String JavaDoc name, Type type, boolean define) {
4574        Variable answer = (Variable) variableStack.get(name);
4575        if (answer == null) {
4576            lastVariableIndex = getNextVariableID();
4577            answer = new Variable(lastVariableIndex, type, name);
4578            if (mutableVars.contains(name)) {
4579                answer.setHolder(true);
4580            }
4581            variableStack.put(name, answer);
4582            Label startLabel = new Label();
4583            answer.setStartLabel(startLabel);
4584            if (define) {
4585                if (definingParameters) {
4586                    if (answer.isHolder()) {
4587                        cv.visitTypeInsn(NEW, "groovy/lang/Reference"); // br todo to associate a label with the variable
4588
cv.visitInsn(DUP);
4589                        cv.visitVarInsn(ALOAD, lastVariableIndex);
4590                        cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V");
4591                        cv.visitVarInsn(ASTORE, lastVariableIndex);
4592                        cv.visitLabel(startLabel);
4593                    }
4594                }
4595                else {
4596                    // using new variable inside a comparison expression
4597
// so lets initialize it too
4598
if (answer.isHolder() && !isInScriptBody()) {
4599                        //cv.visitVarInsn(ASTORE, lastVariableIndex + 1); // I might need this to set the reference value
4600

4601                        cv.visitTypeInsn(NEW, "groovy/lang/Reference");
4602                        cv.visitInsn(DUP);
4603                        cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "()V");
4604
4605                        cv.visitVarInsn(ASTORE, lastVariableIndex);
4606                        cv.visitLabel(startLabel);
4607                        //cv.visitVarInsn(ALOAD, idx + 1);
4608
}
4609                    else {
4610                        if (!leftHandExpression) { // new var on the RHS: init with null
4611
cv.visitInsn(ACONST_NULL);
4612                            cv.visitVarInsn(ASTORE, lastVariableIndex);
4613                            cv.visitLabel(startLabel);
4614                        }
4615                    }
4616                }
4617            }
4618        }
4619        return answer;
4620    }
4621
4622    private int getNextVariableID() {
4623        //return Math.max(lastVariableIndex + 1, variableStack.size());
4624
return variableStack.size(); // todo : rework
4625
}
4626
4627    /** @return true if the given name is a local variable or a field */
4628    protected boolean isFieldOrVariable(String JavaDoc name) {
4629        return variableStack.containsKey(name) || classNode.getField(name) != null;
4630    }
4631
4632    protected Type checkValidType(Type type, ASTNode node, String JavaDoc message) {
4633        if (type.isDynamic()) {
4634            return type;
4635        }
4636        String JavaDoc name = checkValidType(type.getName(), node, message);
4637        if (type.getName().equals(name)) {
4638            return type;
4639        }
4640        return new Type(name);
4641    }
4642
4643    protected String JavaDoc checkValidType(String JavaDoc type, ASTNode node, String JavaDoc message) {
4644        if (type!= null && type.length() == 0)
4645            return "java.lang.Object";
4646        if (type.endsWith("[]")) {
4647            String JavaDoc postfix = "[]";
4648            String JavaDoc prefix = type.substring(0, type.length() - 2);
4649            return checkValidType(prefix, node, message) + postfix;
4650        }
4651        int idx = type.indexOf('$');
4652        if (idx > 0) {
4653            String JavaDoc postfix = type.substring(idx);
4654            String JavaDoc prefix = type.substring(0, idx);
4655            return checkValidType(prefix, node, message) + postfix;
4656        }
4657        if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) {
4658            return type;
4659        }
4660        String JavaDoc original = type;
4661        type = resolveClassName(type);
4662        if (type != null) {
4663            return type;
4664        }
4665
4666        throw new MissingClassException(original, node, message + " for class: " + classNode.getName());
4667    }
4668
4669    protected String JavaDoc resolveClassName(String JavaDoc type) {
4670        return classNode.resolveClassName(type);
4671    }
4672
4673    protected String JavaDoc createVariableName(String JavaDoc type) {
4674        return "__" + type + (++tempVariableNameCounter);
4675    }
4676
4677    /**
4678     * @return if the type of the expression can be determined at compile time
4679     * then this method returns the type - otherwise null
4680     */

4681    protected String JavaDoc getExpressionType(Expression expression) {
4682        if (isComparisonExpression(expression)) {
4683            return "boolean";
4684        }
4685        if (expression instanceof VariableExpression) {
4686            VariableExpression varExpr = (VariableExpression) expression;
4687            Variable variable = (Variable) variableStack.get(varExpr.getVariable());
4688            if (variable != null && !variable.isHolder()) {
4689                Type type = variable.getType();
4690                if (! type.isDynamic()) {
4691                    return type.getName();
4692                }
4693            }
4694        }
4695        return null;
4696    }
4697
4698    /**
4699     * @return true if the value is an Integer, a Float, a Long, a Double or a
4700     * String .
4701     */

4702    protected static boolean isPrimitiveFieldType(String JavaDoc type) {
4703        return type.equals("java.lang.String")
4704            || type.equals("java.lang.Integer")
4705            || type.equals("java.lang.Double")
4706            || type.equals("java.lang.Long")
4707            || type.equals("java.lang.Float");
4708    }
4709
4710    protected boolean isInClosureConstructor() {
4711        return constructorNode != null
4712            && classNode.getOuterClass() != null
4713            && classNode.getSuperClass().equals(Closure.class.getName());
4714    }
4715
4716    protected boolean isStaticMethod() {
4717        if (methodNode == null) { // we're in a constructor
4718
return false;
4719        }
4720        return methodNode.isStatic();
4721    }
4722
4723    Map classCache = new HashMap();
4724    {
4725        classCache.put("int", Integer.TYPE);
4726        classCache.put("byte", Byte.TYPE);
4727        classCache.put("short", Short.TYPE);
4728        classCache.put("char", Character.TYPE);
4729        classCache.put("boolean", Boolean.TYPE);
4730        classCache.put("long", Long.TYPE);
4731        classCache.put("double", Double.TYPE);
4732        classCache.put("float", Float.TYPE);
4733        classCache.put("void", Void.TYPE);
4734    }
4735    /**
4736     * @return loads the given type name
4737     */

4738    protected Class JavaDoc loadClass(String JavaDoc name) {
4739
4740        if (name.equals(this.classNode.getName())) {
4741            return Object JavaDoc.class;
4742        }
4743
4744        if (name == null) {
4745            return null;
4746        }
4747        else if (name.length() == 0) {
4748            return Object JavaDoc.class;
4749        }
4750
4751        name = BytecodeHelper.formatNameForClassLoading(name);
4752
4753        try {
4754            Class JavaDoc cls = (Class JavaDoc)classCache.get(name);
4755            if (cls != null)
4756                return cls;
4757
4758            CompileUnit compileUnit = getCompileUnit();
4759            if (compileUnit != null) {
4760                cls = compileUnit.loadClass(name);
4761                classCache.put(name, cls);
4762                return cls;
4763            }
4764            else {
4765                throw new ClassGeneratorException("Could not load class: " + name);
4766            }
4767        }
4768        catch (ClassNotFoundException JavaDoc e) {
4769            throw new ClassGeneratorException("Error when compiling class: " + classNode.getName() + ". Reason: could not load class: " + name + " reason: " + e, e);
4770        }
4771    }
4772
4773    protected CompileUnit getCompileUnit() {
4774        CompileUnit answer = classNode.getCompileUnit();
4775        if (answer == null) {
4776            answer = context.getCompileUnit();
4777        }
4778        return answer;
4779    }
4780
4781    /**
4782     * attemtp to identify the exact runtime method call the expression is intended for, for possible early binding.
4783     * @param call
4784     */

4785    public void resolve(MethodCallExpression call) {
4786        if (call.isResolveFailed()) {
4787            return;
4788        }
4789        else if (call.isTypeResolved()) {
4790            return;
4791        }
4792
4793        Expression obj = call.getObjectExpression();
4794        String JavaDoc meth = call.getMethod();
4795        Class JavaDoc ownerClass = null;
4796        boolean isStaticCall = false;
4797        boolean isSuperCall = false;
4798
4799        List arglist = new ArrayList();
4800        Expression args = call.getArguments();
4801        if (args instanceof TupleExpression) {
4802            TupleExpression tupleExpression = (TupleExpression) args;
4803            List argexps = tupleExpression.getExpressions();
4804            for (int i = 0; i < argexps.size(); i++) {
4805                Expression expression = (Expression) argexps.get(i);
4806                Class JavaDoc cls = expression.getTypeClass();
4807                if (cls == null) {
4808                    call.setResolveFailed(true);
4809                    return ;
4810                }
4811                else {
4812                    arglist.add(cls);
4813                }
4814            }
4815        } else if (args instanceof ClosureExpression) {
4816            call.setResolveFailed(true);
4817            return ;// todo
4818
} else {
4819            call.setResolveFailed(true);
4820            return ;
4821        }
4822
4823
4824        Class JavaDoc[] argsArray = new Class JavaDoc[arglist.size()];
4825        arglist.toArray(argsArray);
4826
4827
4828        if (obj instanceof ClassExpression) {
4829            // static call
4830
//ClassExpression cls = (ClassExpression)obj;
4831
//String type = cls.getType();
4832
ownerClass = obj.getTypeClass(); //loadClass(type);
4833
isStaticCall = true;
4834        } else if (obj instanceof VariableExpression) {
4835            VariableExpression var = (VariableExpression) obj;
4836            if (var.getVariable().equals("this") && (methodNode == null? true : !methodNode.isStatic()) ) {
4837                isStaticCall = false;
4838                if (methodNode != null) {
4839                    isStaticCall = Modifier.isStatic(methodNode.getModifiers());
4840                }
4841                MetaMethod mmeth = getMethodOfThisAndSuper(meth, argsArray, isStaticCall);
4842                if (mmeth != null) {
4843                    call.setMethod(mmeth);
4844                    return ;
4845                }
4846                else {
4847                    call.setResolveFailed(true);
4848                    return ;
4849                }
4850            }
4851            else if (var.getVariable().equals("super") ) {
4852                isSuperCall = true;
4853                ownerClass = var.getTypeClass();
4854            }
4855            else {
4856                ownerClass = var.getTypeClass();
4857            }
4858        }
4859        else /*if (obj instanceof PropertyExpression)*/ {
4860            ownerClass = obj.getTypeClass();
4861            if (ownerClass == null) {
4862                call.setResolveFailed(true);
4863                call.setFailure("target class is null");
4864                return ; // take care other cases later version
4865
}
4866        }
4867
4868        if (ownerClass == Object JavaDoc.class) {
4869            call.setResolveFailed(true);
4870            return ; // use late binding for dynamic types
4871
}
4872        else if (ownerClass == null) {
4873            call.setResolveFailed(true);
4874            return ; // use dynamic dispatching for GroovyObject
4875
}
4876        else
4877            if (!isSuperCall && !isStaticCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { // not optimize GroovyObject meth call for now
4878
call.setResolveFailed(true);
4879            return ;
4880        }
4881        else
4882            if (ownerClass.isPrimitive()) {
4883            call.setResolveFailed(true);
4884            return ; // todo handle primitives
4885
}
4886
4887
4888        //MetaMethod mmethod = InvokerHelper.getInstance().getMetaRegistry().getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
4889
// todo is this thread safe?
4890
MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
4891        if (mmethod!= null) {
4892            call.setMethod(mmethod);
4893        }
4894        else {
4895            call.setResolveFailed(true);
4896        }
4897        return ;
4898    }
4899    /**
4900     * attemtp to identify the exact runtime method call the expression is intended for, for possible early binding.
4901     * @param call
4902     */

4903    public void resolve(ConstructorCallExpression call) {
4904        if (call.isResolveFailed()) {
4905            return ;
4906        }
4907        else if (call.isTypeResolved()) {
4908            return ;
4909        }
4910
4911        String JavaDoc declaredType = call.getTypeToSet();
4912        if (declaredType.equals(classNode.getName())) {
4913            call.setResolveFailed(true);
4914            call.setFailure("cannot resolve on the current class itself. ");
4915            return;
4916        }
4917        else {
4918            call.setType(declaredType);
4919            if (call.getTypeClass() == null) {
4920                call.setResolveFailed(true);
4921                call.setFailure("type name cannot be resolved. ");
4922                return;
4923            }
4924        }
4925
4926        boolean isSuperCall = false;
4927
4928        List arglist = new ArrayList();
4929        Expression args = call.getArguments();
4930        if (args instanceof TupleExpression) {
4931            TupleExpression tupleExpression = (TupleExpression) args;
4932            List argexps = tupleExpression.getExpressions();
4933            for (int i = 0; i < argexps.size(); i++) {
4934                Expression expression = (Expression) argexps.get(i);
4935                Class JavaDoc cls = expression.getTypeClass();
4936                if (cls == null) {
4937                    call.setResolveFailed(true);
4938                    return ;
4939                }
4940                else {
4941                    arglist.add(cls);
4942                }
4943            }
4944        } else if (args instanceof ClosureExpression) {
4945            call.setResolveFailed(true);
4946            call.setFailure("don't know how to handle closure arg. ");
4947            return ;// todo
4948
} else {
4949            call.setResolveFailed(true);
4950            call.setFailure("unknown arg type: " + args.getClass().getName());
4951            return ;
4952        }
4953
4954
4955        Class JavaDoc[] argsArray = new Class JavaDoc[arglist.size()];
4956        arglist.toArray(argsArray);
4957
4958        Class JavaDoc ownerClass = call.getTypeClass();
4959        if (ownerClass == null) {
4960            String JavaDoc typeName = call.getType();
4961            if (typeName.equals(this.classNode.getName())) {
4962                // this is a ctor call to this class
4963
call.setResolveFailed(true);
4964                call.setFailure("invoke constructor for this. no optimization for now");
4965                return ;
4966            }
4967            else {
4968                try {
4969                    ownerClass = loadClass(typeName);
4970                    if (ownerClass == null) {
4971                        call.setResolveFailed(true);
4972                        call.setFailure("owner class type is null. ");
4973                        return ;
4974                    }
4975                }
4976                catch (Throwable JavaDoc th) {
4977                    call.setResolveFailed(true);
4978                    call.setFailure("Exception: " + th);
4979                    return ;
4980                }
4981            }
4982        }
4983
4984        if (ownerClass == Object JavaDoc.class) {
4985            call.setResolveFailed(true);
4986            call.setFailure("owner class type java.lang.Object. use late binding for dynamic types");
4987            return ; //
4988
}
4989        else if (ownerClass == null) {
4990            call.setResolveFailed(true);
4991            call.setFailure("owner class type is null. use dynamic dispatching for GroovyObject");
4992            return; // use dynamic dispatching for GroovyObject
4993
}
4994// safe to call groovyobject ctor
4995
// else if (!isSuperCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { // ie, to allow early binding for a super call
4996
// call.setResolveFailed(true);
4997
// return null;
4998
// }
4999
else if (ownerClass.isPrimitive()) {
5000            call.setResolveFailed(true);
5001            throwException("The owner of the constructor is primitive.");
5002            return ;
5003        }
5004
5005        Constructor JavaDoc ctor = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedConstructor(ownerClass, argsArray);
5006        if (ctor!= null) {
5007            call.setConstructor(ctor);
5008        }
5009        else {
5010            call.setResolveFailed(true);
5011        }
5012        return ;
5013    }
5014
5015    public void resolve(PropertyExpression propertyExpression) {
5016        if (propertyExpression.getTypeClass() != null)
5017            return ;
5018        if (propertyExpression.isResolveFailed())
5019            return ;
5020
5021        Expression ownerExp = propertyExpression.getObjectExpression();
5022        Class JavaDoc ownerClass = ownerExp.getTypeClass();
5023        String JavaDoc propName = propertyExpression.getProperty();
5024        if (propName.equals("class")) {
5025            propertyExpression.setTypeClass(Class JavaDoc.class);
5026            return ;
5027        }
5028
5029        // handle arraylength
5030
if (ownerClass != null && ownerClass.isArray() && propName.equals("length")) {
5031            propertyExpression.setTypeClass(int.class);
5032            return;
5033        }
5034
5035        if (isThisExpression(ownerExp)) {
5036            // lets use the field expression if its available
5037
if (classNode == null) {
5038                propertyExpression.setResolveFailed(true);
5039                return ;
5040            }
5041            FieldNode field = null;
5042            ownerExp.setType(classNode.getName());
5043            try {
5044                if( (field = classNode.getField(propName)) != null ) {
5045// Class cls =loadClass(field.getType());
5046
// propertyExpression.setAccess(PropertyExpression.LOCAL_FIELD_ACCESS);
5047
// propertyExpression.setTypeClass(cls);
5048
// local property access. to be determined in the future
5049
propertyExpression.setResolveFailed(true);
5050                    propertyExpression.setFailure("local property access. to be determined in the future.");
5051                    return ;
5052                } else {
5053                    // search for super classes/interface
5054
// interface first first
5055
String JavaDoc[] interfaces = classNode.getInterfaces();
5056                    String JavaDoc[] supers = new String JavaDoc[interfaces.length + 1];
5057
5058                    int i = 0;
5059                    for (; i < interfaces.length; i++) {
5060                        supers[i] = interfaces[i];
5061                    }
5062                    supers[i] = classNode.getSuperClass();
5063                    for (int j = 0; j < supers.length; j++) {
5064                        String JavaDoc aSuper = supers[j];
5065                        Class JavaDoc superClass = loadClass(aSuper);
5066                        Field JavaDoc fld = superClass.getDeclaredField(propName);
5067                        if (fld != null && !Modifier.isPrivate(fld.getModifiers())) {
5068                            propertyExpression.setField(fld);
5069                            return ;
5070                        }
5071                    }
5072                }
5073            } catch (Exception JavaDoc e) {
5074                propertyExpression.setResolveFailed(true);
5075                propertyExpression.setFailure(e.getMessage());
5076                return ;
5077            }
5078        }
5079        else if (ownerExp instanceof ClassExpression) {
5080            if (ownerClass != null) {
5081                Field JavaDoc fld = null;
5082                try {
5083                    fld = ownerClass.getDeclaredField(propName);
5084                    if (!Modifier.isPrivate(fld.getModifiers())) {
5085                        propertyExpression.setField(fld);
5086                        return ;
5087                    }
5088                } catch (NoSuchFieldException JavaDoc e) {
5089                    propertyExpression.setResolveFailed(true);
5090                    return ;
5091                }
5092            }
5093        }
5094        else { // search public field and then setter/getter
5095
if (ownerClass != null) {
5096                propertyExpression.setResolveFailed(true); // will get reset if property/getter/setter were found
5097
Field JavaDoc fld = null;
5098                try {
5099                    fld = ownerClass.getDeclaredField(propName);
5100                } catch (NoSuchFieldException JavaDoc e) {}
5101
5102                if (fld != null && Modifier.isPublic(fld.getModifiers())) {
5103                    propertyExpression.setField(fld);
5104                }
5105
5106                // let's get getter and setter
5107
String JavaDoc getterName = "get" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
5108                String JavaDoc setterName = "set" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
5109
5110                Method JavaDoc[] meths = ownerClass.getMethods();
5111                for (int i = 0; i < meths.length; i++) {
5112                    Method JavaDoc method = meths[i];
5113                    String JavaDoc methName =method.getName();
5114                    Class JavaDoc[] paramClasses = method.getParameterTypes();
5115                    if (methName.equals(getterName) && paramClasses.length == 0) {
5116                        propertyExpression.setGetter(method);
5117                    } else if (methName.equals(setterName) && paramClasses.length == 1) {
5118                        propertyExpression.setSetter(method);
5119                    }
5120                }
5121                return ;
5122            }
5123        }
5124        propertyExpression.setResolveFailed(true);
5125        return ;
5126    }
5127    /** search in the current classNode and super class for matching method */
5128    private MetaMethod getMethodOfThisAndSuper(String JavaDoc methName, Class JavaDoc[] argsArray, boolean isStaticCall) {
5129        MethodNode candidate = null;
5130        List meths = classNode.getMethods();
5131        Class JavaDoc[] candidateParamClasses = null;
5132        for (int i = 0; i < meths.size(); i++) {
5133            MethodNode meth = (MethodNode) meths.get(i);
5134            if (meth.getName().equals(methName)) {
5135                Parameter[] params = meth.getParameters();
5136                if (params.length == argsArray.length) {
5137                    Class JavaDoc[] paramClasses = new Class JavaDoc[params.length];
5138                    for (int j = 0; j < params.length; j++) {
5139                        Parameter param = params[j];
5140                        String JavaDoc type = param.getType();
5141                        Class JavaDoc paramClass = null;
5142                        try {
5143                            paramClass = loadClass(type);
5144                        } catch (Exception JavaDoc e) {
5145                            log.warning(e.getMessage());
5146                            return null;
5147                        }
5148                        paramClasses[j] = paramClass;
5149                    }
5150                    if (MetaClass.isValidMethod(paramClasses, argsArray, false)) {
5151                        candidateParamClasses = paramClasses;
5152                        candidate = meth;
5153                        break;
5154                    }
5155                    else {
5156                        if (MetaClass.isValidMethod(paramClasses, argsArray, true)){
5157                            candidateParamClasses = paramClasses;
5158                            candidate = meth;
5159                            break;
5160                        }
5161                    }
5162                }
5163            }
5164        }
5165
5166        if (candidate != null && candidateParamClasses != null) {
5167            // let's synth a MetaMethod from the MethodNode
5168
try {
5169                return new MetaMethod(methName, null, candidateParamClasses, loadClass(candidate.getReturnType()), candidate.getModifiers());
5170            } catch (Exception JavaDoc e) {
5171                log.warning(e.getMessage());
5172                return null;
5173            }
5174        }
5175        else {
5176            // try super class
5177
Class JavaDoc superClass = null;
5178            try {
5179                superClass = loadClass(classNode.getSuperClass());
5180            }
5181            catch(Exception JavaDoc e) {
5182                // the super may be a groovy class that's not compiled yet
5183
log.warning(e.getMessage());
5184            }
5185            // should I filter out GroovyObject super class here?
5186
if (superClass != null ) {
5187                MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(superClass, methName, argsArray, isStaticCall);
5188                if (mmethod == null)
5189                    return null;
5190                int modies = mmethod.getModifiers();
5191                if (Modifier.isPrivate(modies)) {
5192                    return null;
5193                }
5194                else if(modies == 0) {
5195                    // match package
5196
int pThis = classNode.getName().lastIndexOf(".");
5197                    String JavaDoc packageNameThis = pThis > 0? classNode.getName().substring(0, pThis) : "";
5198
5199                    int pSuper = classNode.getSuperClass().lastIndexOf(".");
5200                    String JavaDoc packageNameSuper = pSuper > 0? classNode.getSuperClass().substring(0, pSuper) : "";
5201                    if (packageNameThis.equals(packageNameSuper)) {
5202                        return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers());
5203                    }
5204                    else {
5205                        return null;
5206                    }
5207                }
5208                else {
5209                    // let changes the declaring class back to null (meaning "this"), so that proper class inheritance permission control is obeyed
5210
return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers());
5211                }
5212            }
5213            return null;
5214        }
5215    }
5216
5217
5218    /**
5219     * to find out the real type of a Variable Object
5220     */

5221    public void resolve(VariableExpression expression) {
5222
5223        String JavaDoc variableName = expression.getVariable();
5224// todo process arrays!
5225
//-----------------------------------------------------------------------
5226
// SPECIAL CASES
5227

5228        //
5229
// "this" for static methods is the Class instance
5230

5231        if (isStaticMethod() && variableName.equals("this")) {
5232            expression.setTypeClass(Class JavaDoc.class);
5233            return;
5234        } else if (variableName.equals("super")) {
5235            if (isStaticMethod() ) {
5236                expression.setTypeClass(Class JavaDoc.class);
5237                return;
5238            }
5239            else {
5240                try {
5241                    Class JavaDoc cls = loadClass(classNode.getSuperClass());
5242                    expression.setTypeClass(cls);
5243                    return ;
5244                }
5245                catch (Exception JavaDoc e) {
5246                    expression.setResolveFailed(true);
5247                    expression.setFailure(e.getMessage());
5248                    return ;
5249                }
5250            }
5251        } else if (variableName.equals("this")){
5252            return ;
5253        } else {
5254// String className = resolveClassName(variableName);
5255
// if (className != null) {
5256
// return loadClass(className);
5257
// }
5258
}
5259
5260
5261      //-----------------------------------------------------------------------
5262
// GENERAL VARIABLE LOOKUP
5263

5264        //
5265
// We are handling only unqualified variables here. Therefore,
5266
// we do not care about accessors, because local access doesn't
5267
// go through them. Therefore, precedence is as follows:
5268
// 1) local variables, nearest block first
5269
// 2) class fields
5270
// 3) repeat search from 2) in next outer class
5271

5272        boolean handled = false;
5273        Variable variable = (Variable)variableStack.get( variableName );
5274
5275        try {
5276            if( variable != null ) {
5277                Type t = variable.getType();
5278                if (t.getRealName().length() == 0) {
5279                    String JavaDoc tname = t.getName();
5280                    if (tname.endsWith("[]")) {
5281                        expression.setResolveFailed(true);
5282                        expression.setFailure("array type to be supported later");
5283                        return ; // todo hanlde array
5284
}
5285                    else if (tname.equals(classNode.getName())){
5286                        expression.setResolveFailed(true);
5287                        return ;
5288                    }
5289                    else if (classNode.getOuterClass() != null && tname.equals(classNode.getOuterClass().getName())){
5290                        expression.setResolveFailed(true);
5291                        return ;
5292                    }
5293                    Class JavaDoc cls = loadClass(tname);
5294                    expression.setTypeClass(cls);
5295                    expression.setDynamic(t.isDynamic());
5296                    return ;
5297                } else {
5298                    String JavaDoc tname = t.getRealName();
5299                    if (tname.endsWith("[]")) {
5300                        expression.setResolveFailed(true);
5301                        expression.setFailure("array type to be supported later");
5302                        return ; // todo hanlde array
5303
}
5304                    Class JavaDoc cls = loadClass(tname);
5305                    expression.setTypeClass(cls);
5306                    expression.setDynamic(t.isDynamic());
5307                    return ;
5308                }
5309
5310// if( variable.isProperty() ) {
5311
// processPropertyVariable(variable );
5312
// }
5313
// else {
5314
// processStackVariable(variable );
5315
// }
5316
//
5317
} else {
5318                int steps = 0;
5319                ClassNode currentClassNode = classNode;
5320                FieldNode field = null;
5321                do {
5322                    if( (field = currentClassNode.getField(variableName)) != null ) {
5323                        if (methodNode == null || !methodNode.isStatic() || field.isStatic() ) {
5324                            if (/*field.isDynamicType() || */field.isHolder()) {
5325                                expression.setResolveFailed(true);
5326                                expression.setFailure("reference type to be supported later");
5327                                return ;
5328                            } else {
5329                                String JavaDoc type = field.getType();
5330                                Class JavaDoc cls = loadClass(type);
5331                                expression.setTypeClass(cls);
5332                                expression.setDynamic(field.isDynamicType());
5333                                return ;
5334                            }
5335                        }
5336                    }
5337                    steps++;
5338                } while( (currentClassNode = currentClassNode.getOuterClass()) != null );
5339            }
5340
5341            //
5342
// Finally, a new variable
5343

5344            String JavaDoc variableType = expression.getType();
5345            if (variableType.length() > 0 && !variableType.equals("java.lang.Object")) {
5346                Class JavaDoc cls = loadClass(variableType);
5347                expression.setTypeClass(cls);
5348                return ;
5349            }
5350        } catch (Exception JavaDoc e) {
5351            log.warning(e.getMessage());
5352            expression.setResolveFailed(true);
5353            expression.setFailure(e.getMessage());
5354        }
5355        return ;
5356    }
5357
5358    public MetaMethod resolve(StaticMethodCallExpression staticCall) {
5359       if (staticCall.isResolveFailed()) {
5360            return null;
5361        }
5362        else if (staticCall.isTypeResolved()) {
5363            return staticCall.getMetaMethod();
5364        }
5365
5366        String JavaDoc ownerTypeName = staticCall.getOwnerType();
5367        String JavaDoc meth = staticCall.getMethod();
5368        Class JavaDoc ownerClass = null;
5369        try {
5370            ownerClass = loadClass(ownerTypeName);
5371        } catch (Exception JavaDoc e) {
5372            staticCall.setResolveFailed(true);
5373            staticCall.setFailure("Owner type could not be resolved: " + e);
5374            return null;
5375        }
5376
5377        boolean isStaticCall = true;
5378        boolean isSuperCall = false;
5379
5380        List arglist = new ArrayList();
5381        Expression args = staticCall.getArguments();
5382        if (args instanceof TupleExpression) {
5383            TupleExpression tupleExpression = (TupleExpression) args;
5384            List argexps = tupleExpression.getExpressions();
5385            for (int i = 0; i < argexps.size(); i++) {
5386                Expression expression = (Expression) argexps.get(i);
5387                Class JavaDoc cls = expression.getTypeClass();
5388                if (cls == null) {
5389                    staticCall.setResolveFailed(true);
5390                    staticCall.setFailure("Argument type could not be resolved.");
5391                    return null;
5392                }
5393                else {
5394                    arglist.add(cls);
5395                }
5396            }
5397        } else if (args instanceof ClosureExpression) {
5398            staticCall.setResolveFailed(true);
5399            staticCall.setFailure("Resolving on Closure call not implemented yet. ");
5400            return null;// todo
5401
} else {
5402            staticCall.setResolveFailed(true);
5403            staticCall.setFailure("Unknown argument expression type.");
5404            return null;
5405        }
5406
5407
5408        Class JavaDoc[] argsArray = new Class JavaDoc[arglist.size()];
5409        arglist.toArray(argsArray);
5410
5411        if (ownerClass == Object JavaDoc.class) {
5412            staticCall.setResolveFailed(true);
5413            staticCall.setFailure("Resolving on java.lang.Object static call not supported. ");
5414            return null; // use late binding for dynamic types
5415
}
5416        else if (ownerClass == null) {
5417            staticCall.setResolveFailed(true);
5418            staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. ");
5419            return null; // use dynamic dispatching for GroovyObject
5420
}
5421        else if (!isSuperCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { // ie, to allow early binding for a super call
5422
staticCall.setResolveFailed(true);
5423            staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. ");
5424            return null;
5425        }
5426        else if (ownerClass.isPrimitive()) {
5427            staticCall.setResolveFailed(true);
5428            staticCall.setFailure("Could not use primitive as method owner");
5429            return null; // todo handle primitives
5430
}
5431
5432
5433        //MetaMethod mmethod = InvokerHelper.getInstance().getMetaRegistry().getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
5434
// todo is this thread safe?
5435
MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
5436        if (mmethod!= null) {
5437            staticCall.setMetaMethod(mmethod);
5438        }
5439        else {
5440            staticCall.setResolveFailed(true);
5441            staticCall.setFailure("Could not find MetaMethod in the MetaClass.");
5442        }
5443        return mmethod;
5444    }
5445
5446    // the fowllowing asXXX() methods are copied from the Invoker class, to avoid initilization of an invoker instance,
5447
// which has lots of baggage with it, notably the meta class stuff.
5448
private static Object JavaDoc asType(Object JavaDoc object, Class JavaDoc type) {
5449        if (object == null) {
5450            return null;
5451        }
5452        if (type.isInstance(object)) {
5453            return object;
5454        }
5455        if (type.equals(String JavaDoc.class)) {
5456            return object.toString();
5457        }
5458        if (type.equals(Character JavaDoc.class)) {
5459            if (object instanceof Number JavaDoc) {
5460                return asCharacter((Number JavaDoc) object);
5461            }
5462            else {
5463                String JavaDoc text = object.toString();
5464                if (text.length() == 1) {
5465                    return new Character JavaDoc(text.charAt(0));
5466                }
5467                else {
5468                    throw new ClassCastException JavaDoc("Cannot cast: " + text + " to a Character");
5469                }
5470            }
5471        }
5472        if (Number JavaDoc.class.isAssignableFrom(type)) {
5473            if (object instanceof Character JavaDoc) {
5474                return new Integer JavaDoc(((Character JavaDoc) object).charValue());
5475            }
5476            else if (object instanceof String JavaDoc) {
5477                String JavaDoc c = (String JavaDoc) object;
5478                if (c.length() == 1) {
5479                    return new Integer JavaDoc(c.charAt(0));
5480                }
5481                else {
5482                    throw new ClassCastException JavaDoc("Cannot cast: '" + c + "' to an Integer");
5483                }
5484            }
5485        }
5486        if (object instanceof Number JavaDoc) {
5487            Number JavaDoc n = (Number JavaDoc) object;
5488            if (type.isPrimitive()) {
5489                if (type == byte.class) {
5490                    return new Byte JavaDoc(n.byteValue());
5491                }
5492                if (type == char.class) {
5493                    return new Character JavaDoc((char) n.intValue());
5494                }
5495                if (type == short.class) {
5496                    return new Short JavaDoc(n.shortValue());
5497                }
5498                if (type == int.class) {
5499                    return new Integer JavaDoc(n.intValue());
5500                }
5501                if (type == long.class) {
5502                    return new Long JavaDoc(n.longValue());
5503                }
5504                if (type == float.class) {
5505                    return new Float JavaDoc(n.floatValue());
5506                }
5507                if (type == double.class) {
5508                    Double JavaDoc answer = new Double JavaDoc(n.doubleValue());
5509                    //throw a runtime exception if conversion would be out-of-range for the type.
5510
if (!(n instanceof Double JavaDoc) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
5511                            || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
5512                        throw new GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
5513                                +" value "+n+" to double failed. Value is out of range.");
5514                    }
5515                    return answer;
5516                }
5517            }
5518            else {
5519                if (Number JavaDoc.class.isAssignableFrom(type)) {
5520                    if (type == Byte JavaDoc.class) {
5521                        return new Byte JavaDoc(n.byteValue());
5522                    }
5523                    if (type == Character JavaDoc.class) {
5524                        return new Character JavaDoc((char) n.intValue());
5525                    }
5526                    if (type == Short JavaDoc.class) {
5527                        return new Short JavaDoc(n.shortValue());
5528                    }
5529                    if (type == Integer JavaDoc.class) {
5530                        return new Integer JavaDoc(n.intValue());
5531                    }
5532                    if (type == Long JavaDoc.class) {
5533                        return new Long JavaDoc(n.longValue());
5534                    }
5535                    if (type == Float JavaDoc.class) {
5536                        return new Float JavaDoc(n.floatValue());
5537                    }
5538                    if (type == Double JavaDoc.class) {
5539                        Double JavaDoc answer = new Double JavaDoc(n.doubleValue());
5540                        //throw a runtime exception if conversion would be out-of-range for the type.
5541
if (!(n instanceof Double JavaDoc) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
5542                                || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
5543                            throw new GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
5544                                    +" value "+n+" to double failed. Value is out of range.");
5545                        }
5546                        return answer;
5547                    }
5548
5549                }
5550            }
5551        }
5552        if (type == Boolean