KickJava   Java API By Example, From Geeks To Geeks.

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


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

34 package org.codehaus.groovy.classgen;
35
36 import groovy.lang.Closure;
37 import groovy.lang.GString;
38 import groovy.lang.GroovyRuntimeException;
39 import groovy.lang.MissingClassException;
40 import groovy.lang.Reference;
41
42 import java.math.BigDecimal JavaDoc;
43 import java.math.BigInteger JavaDoc;
44 import java.security.AccessControlException JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.HashSet JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.LinkedList JavaDoc;
50 import java.util.List JavaDoc;
51 import java.util.Map JavaDoc;
52 import java.util.Set JavaDoc;
53 import java.util.logging.Logger JavaDoc;
54
55 import org.codehaus.groovy.ast.ASTNode;
56 import org.codehaus.groovy.ast.ClassNode;
57 import org.codehaus.groovy.ast.CodeVisitorSupport;
58 import org.codehaus.groovy.ast.CompileUnit;
59 import org.codehaus.groovy.ast.ConstructorNode;
60 import org.codehaus.groovy.ast.FieldNode;
61 import org.codehaus.groovy.ast.GroovyClassVisitor;
62 import org.codehaus.groovy.ast.GroovyCodeVisitor;
63 import org.codehaus.groovy.ast.InnerClassNode;
64 import org.codehaus.groovy.ast.MethodNode;
65 import org.codehaus.groovy.ast.Parameter;
66 import org.codehaus.groovy.ast.PropertyNode;
67 import org.codehaus.groovy.ast.Type;
68 import org.codehaus.groovy.ast.VariableScope;
69 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
70 import org.codehaus.groovy.ast.expr.ArrayExpression;
71 import org.codehaus.groovy.ast.expr.BinaryExpression;
72 import org.codehaus.groovy.ast.expr.BooleanExpression;
73 import org.codehaus.groovy.ast.expr.CastExpression;
74 import org.codehaus.groovy.ast.expr.ClassExpression;
75 import org.codehaus.groovy.ast.expr.ClosureExpression;
76 import org.codehaus.groovy.ast.expr.ConstantExpression;
77 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
78 import org.codehaus.groovy.ast.expr.Expression;
79 import org.codehaus.groovy.ast.expr.ExpressionTransformer;
80 import org.codehaus.groovy.ast.expr.FieldExpression;
81 import org.codehaus.groovy.ast.expr.GStringExpression;
82 import org.codehaus.groovy.ast.expr.ListExpression;
83 import org.codehaus.groovy.ast.expr.MapEntryExpression;
84 import org.codehaus.groovy.ast.expr.MapExpression;
85 import org.codehaus.groovy.ast.expr.MethodCallExpression;
86 import org.codehaus.groovy.ast.expr.NegationExpression;
87 import org.codehaus.groovy.ast.expr.NotExpression;
88 import org.codehaus.groovy.ast.expr.PostfixExpression;
89 import org.codehaus.groovy.ast.expr.PrefixExpression;
90 import org.codehaus.groovy.ast.expr.PropertyExpression;
91 import org.codehaus.groovy.ast.expr.RangeExpression;
92 import org.codehaus.groovy.ast.expr.RegexExpression;
93 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
94 import org.codehaus.groovy.ast.expr.TernaryExpression;
95 import org.codehaus.groovy.ast.expr.TupleExpression;
96 import org.codehaus.groovy.ast.expr.VariableExpression;
97 import org.codehaus.groovy.ast.stmt.AssertStatement;
98 import org.codehaus.groovy.ast.stmt.BlockStatement;
99 import org.codehaus.groovy.ast.stmt.BreakStatement;
100 import org.codehaus.groovy.ast.stmt.CaseStatement;
101 import org.codehaus.groovy.ast.stmt.CatchStatement;
102 import org.codehaus.groovy.ast.stmt.ContinueStatement;
103 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
104 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
105 import org.codehaus.groovy.ast.stmt.ForStatement;
106 import org.codehaus.groovy.ast.stmt.IfStatement;
107 import org.codehaus.groovy.ast.stmt.ReturnStatement;
108 import org.codehaus.groovy.ast.stmt.Statement;
109 import org.codehaus.groovy.ast.stmt.SwitchStatement;
110 import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
111 import org.codehaus.groovy.ast.stmt.ThrowStatement;
112 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
113 import org.codehaus.groovy.ast.stmt.WhileStatement;
114 import org.codehaus.groovy.runtime.InvokerHelper;
115 import org.codehaus.groovy.syntax.Token;
116 import org.codehaus.groovy.syntax.Types;
117 import org.codehaus.groovy.syntax.parser.RuntimeParserException;
118 import org.objectweb.asm.ClassVisitor;
119 import org.objectweb.asm.CodeVisitor;
120 import org.objectweb.asm.Constants;
121 import org.objectweb.asm.Label;
122
123 /**
124  * Generates Java class versions of Groovy classes using ASM
125  *
126  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
127  * @version $Revision: 1.8 $
128  * @deprecated AsmClassGenerator2 contains code for static method bindings.
129  */

130 public class AsmClassGenerator extends ClassGenerator {
131
132     private Logger JavaDoc log = Logger.getLogger(getClass().getName());
133
134     private ClassVisitor cw;
135     private CodeVisitor cv;
136     private GeneratorContext context;
137
138     private String JavaDoc sourceFile;
139
140     // current class details
141
private ClassNode classNode;
142     private ClassNode outermostClass;
143     private String JavaDoc internalClassName;
144     private String JavaDoc internalBaseClassName;
145
146     /** maps the variable names to the JVM indices */
147     private Map JavaDoc variableStack = new HashMap JavaDoc();
148
149     /** have we output a return statement yet */
150     private boolean outputReturn;
151
152     /** are we on the left or right of an expression */
153     private boolean leftHandExpression;
154
155     // cached values
156
MethodCaller invokeMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethod");
157     MethodCaller invokeMethodSafeMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethodSafe");
158     MethodCaller invokeStaticMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticMethod");
159     MethodCaller invokeConstructorMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructor");
160     MethodCaller invokeConstructorOfMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructorOf");
161     MethodCaller invokeNoArgumentsConstructorOf = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsConstructorOf");
162     MethodCaller invokeClosureMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeClosure");
163     MethodCaller invokeSuperMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeSuperMethod");
164     MethodCaller invokeNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsMethod");
165     MethodCaller invokeStaticNoArgumentsMethod =
166         MethodCaller.newStatic(InvokerHelper.class, "invokeStaticNoArgumentsMethod");
167
168     MethodCaller asIntMethod = MethodCaller.newStatic(InvokerHelper.class, "asInt");
169     MethodCaller asTypeMethod = MethodCaller.newStatic(InvokerHelper.class, "asType");
170     MethodCaller getPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getProperty");
171     MethodCaller getPropertySafeMethod = MethodCaller.newStatic(InvokerHelper.class, "getPropertySafe");
172     MethodCaller setPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setProperty");
173     MethodCaller setPropertyMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setProperty2");
174     MethodCaller setPropertySafeMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setPropertySafe2");
175     MethodCaller getGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getGroovyObjectProperty");
176     MethodCaller setGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setGroovyObjectProperty");
177     MethodCaller asIteratorMethod = MethodCaller.newStatic(InvokerHelper.class, "asIterator");
178     MethodCaller asBool = MethodCaller.newStatic(InvokerHelper.class, "asBool");
179     MethodCaller notBoolean = MethodCaller.newStatic(InvokerHelper.class, "notBoolean");
180     MethodCaller notObject = MethodCaller.newStatic(InvokerHelper.class, "notObject");
181     MethodCaller regexPattern = MethodCaller.newStatic(InvokerHelper.class, "regexPattern");
182     MethodCaller negation = MethodCaller.newStatic(InvokerHelper.class, "negate");
183
184     MethodCaller compareIdenticalMethod = MethodCaller.newStatic(InvokerHelper.class, "compareIdentical");
185     MethodCaller compareEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareEqual");
186     MethodCaller compareNotEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareNotEqual");
187     MethodCaller compareToMethod = MethodCaller.newStatic(InvokerHelper.class, "compareTo");
188     MethodCaller findRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "findRegex");
189     MethodCaller matchRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "matchRegex");
190     MethodCaller compareLessThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThan");
191     MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThanEqual");
192     MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThan");
193     MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThanEqual");
194     MethodCaller isCaseMethod = MethodCaller.newStatic(InvokerHelper.class, "isCase");
195
196     MethodCaller createListMethod = MethodCaller.newStatic(InvokerHelper.class, "createList");
197     MethodCaller createTupleMethod = MethodCaller.newStatic(InvokerHelper.class, "createTuple");
198     MethodCaller createMapMethod = MethodCaller.newStatic(InvokerHelper.class, "createMap");
199     MethodCaller createRangeMethod = MethodCaller.newStatic(InvokerHelper.class, "createRange");
200
201     MethodCaller assertFailedMethod = MethodCaller.newStatic(InvokerHelper.class, "assertFailed");
202
203     MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator JavaDoc.class, "next");
204     MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator JavaDoc.class, "hasNext");
205
206     // current stack index
207
private int lastVariableIndex;
208     private static int tempVariableNameCounter;
209
210     // exception blocks list
211
private List JavaDoc exceptionBlocks = new ArrayList JavaDoc();
212
213     private boolean definingParameters;
214     private Set JavaDoc syntheticStaticFields = new HashSet JavaDoc();
215     private Set JavaDoc mutableVars = new HashSet JavaDoc();
216     private boolean passingClosureParams;
217
218     private ConstructorNode constructorNode;
219     private MethodNode methodNode;
220     //private PropertyNode propertyNode;
221
private BlockScope scope;
222     private BytecodeHelper helper = new BytecodeHelper(null);
223
224     private VariableScope variableScope;
225
226     public AsmClassGenerator(
227         GeneratorContext context,
228         ClassVisitor classVisitor,
229         ClassLoader JavaDoc classLoader,
230         String JavaDoc sourceFile) {
231         super(classLoader);
232         this.context = context;
233         this.cw = classVisitor;
234         this.sourceFile = sourceFile;
235     }
236
237     // GroovyClassVisitor interface
238
//-------------------------------------------------------------------------
239
public void visitClass(ClassNode classNode) {
240         try {
241             syntheticStaticFields.clear();
242             this.classNode = classNode;
243             this.outermostClass = null;
244             this.internalClassName = BytecodeHelper.getClassInternalName(classNode.getName());
245
246             //System.out.println("Generating class: " + classNode.getName());
247

248             // lets check that the classes are all valid
249
classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class"));
250             String JavaDoc[] interfaces = classNode.getInterfaces();
251             for (int i = 0; i < interfaces.length; i++ ) {
252                 interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name");
253             }
254
255             this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
256
257             cw.visit(
258                 asmJDKVersion,
259                 classNode.getModifiers(),
260                 internalClassName,
261                 internalBaseClassName,
262                 BytecodeHelper.getClassInternalNames(classNode.getInterfaces()),
263                 sourceFile);
264
265             // set the optional enclosing method attribute of the current inner class
266
// br comment out once Groovy uses the latest CVS HEAD of ASM
267
// MethodNode enclosingMethod = classNode.getEnclosingMethod();
268
// String ownerName = BytecodeHelper.getClassInternalName(enclosingMethod.getDeclaringClass().getName());
269
// String descriptor = BytecodeHelper.getMethodDescriptor(enclosingMethod.getReturnType(), enclosingMethod.getParameters());
270
// EnclosingMethodAttribute attr = new EnclosingMethodAttribute(ownerName,enclosingMethod.getName(),descriptor);
271
// cw.visitAttribute(attr);
272

273             classNode.visitContents(this);
274
275             createSyntheticStaticFields();
276
277             for (Iterator JavaDoc iter = innerClasses.iterator(); iter.hasNext();) {
278                 ClassNode innerClass = (ClassNode) iter.next();
279                 String JavaDoc innerClassName = innerClass.getName();
280                 String JavaDoc innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
281                 String JavaDoc outerClassName = internalClassName; // default for inner classes
282
MethodNode enclosingMethod = innerClass.getEnclosingMethod();
283                 if (enclosingMethod != null) {
284                     // local inner classes do not specify the outer class name
285
outerClassName = null;
286                 }
287                 cw.visitInnerClass(
288                     innerClassInternalName,
289                     outerClassName,
290                     innerClassName,
291                     innerClass.getModifiers());
292             }
293 // br TODO an inner class should have an entry of itself
294
cw.visitEnd();
295         }
296         catch (GroovyRuntimeException e) {
297             e.setModule(classNode.getModule());
298             throw e;
299         }
300     }
301
302     public void visitConstructor(ConstructorNode node) {
303         // creates a MethodWriter for the (implicit) constructor
304
//String methodType = Type.getMethodDescriptor(VOID_TYPE, )
305

306         this.constructorNode = node;
307         this.methodNode = null;
308         this.variableScope = null;
309
310         visitParameters(node, node.getParameters());
311
312         String JavaDoc methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters());
313         cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null);
314         helper = new BytecodeHelper(cv);
315
316         findMutableVariables();
317         resetVariableStack(node.getParameters());
318
319         Statement code = node.getCode();
320         if (code == null || !firstStatementIsSuperInit(code)) {
321             // invokes the super class constructor
322
cv.visitVarInsn(ALOAD, 0);
323             cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "()V");
324         }
325         if (code != null) {
326             code.visit(this);
327         }
328
329         cv.visitInsn(RETURN);
330         cv.visitMaxs(0, 0);
331     }
332
333     public void visitMethod(MethodNode node) {
334         //System.out.println("Visiting method: " + node.getName() + " with
335
// return type: " + node.getReturnType());
336
this.constructorNode = null;
337         this.methodNode = node;
338         this.variableScope = null;
339
340         visitParameters(node, node.getParameters());
341         node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type"));
342
343         String JavaDoc methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
344         cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null);
345         Label labelStart = new Label();
346         cv.visitLabel(labelStart);
347         helper = new BytecodeHelper(cv);
348
349         findMutableVariables();
350         resetVariableStack(node.getParameters());
351
352         outputReturn = false;
353
354         node.getCode().visit(this);
355
356         if (!outputReturn) {
357             cv.visitInsn(RETURN);
358         }
359
360         // lets do all the exception blocks
361
for (Iterator JavaDoc iter = exceptionBlocks.iterator(); iter.hasNext();) {
362             Runnable JavaDoc runnable = (Runnable JavaDoc) iter.next();
363             runnable.run();
364         }
365         exceptionBlocks.clear();
366
367         Label labelEnd = new Label();
368         cv.visitLabel(labelEnd);
369
370         // br experiment with local var table so debugers can retrieve variable names
371
// Set vars = this.variableStack.keySet();
372
// for (Iterator iterator = vars.iterator(); iterator.hasNext();) {
373
// String varName = (String) iterator.next();
374
// Variable v = (Variable)variableStack.get(varName);
375
// String type = v.getTypeName();
376
// type = BytecodeHelper.getTypeDescription(type);
377
// cv.visitLocalVariable(varName, type, labelStart, labelEnd, v.getIndex()); // the start and end should be fine-pined
378
// }
379

380         cv.visitMaxs(0, 0);
381     }
382
383     protected void visitParameters(ASTNode node, Parameter[] parameters) {
384         for (int i = 0, size = parameters.length; i < size; i++ ) {
385             visitParameter(node, parameters[i]);
386         }
387     }
388
389     protected void visitParameter(ASTNode node, Parameter parameter) {
390         if (! parameter.isDynamicType()) {
391             parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class"));
392         }
393     }
394
395     public void visitField(FieldNode fieldNode) {
396         onLineNumber(fieldNode);
397
398         // lets check that the classes are all valid
399
fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName()));
400
401         //System.out.println("Visiting field: " + fieldNode.getName() + " on
402
// class: " + classNode.getName());
403

404         Object JavaDoc fieldValue = null;
405         Expression expression = fieldNode.getInitialValueExpression();
406         if (expression instanceof ConstantExpression) {
407             ConstantExpression constantExp = (ConstantExpression) expression;
408             Object JavaDoc value = constantExp.getValue();
409             if (isPrimitiveFieldType(fieldNode.getType())) {
410                 // lets convert any primitive types
411
Class JavaDoc type = null;
412                 try {
413                     type = loadClass(fieldNode.getType());
414                     fieldValue = InvokerHelper.asType(value, type);
415                 }
416                 catch (Exception JavaDoc e) {
417                     log.warning("Caught unexpected: " + e);
418                 }
419             }
420         }
421         cw.visitField(
422             fieldNode.getModifiers(),
423             fieldNode.getName(),
424             BytecodeHelper.getTypeDescription(fieldNode.getType()),
425             fieldValue,
426             null);
427     }
428
429     /**
430      * Creates a getter, setter and field
431      */

432     public void visitProperty(PropertyNode statement) {
433         onLineNumber(statement);
434         //this.propertyNode = statement;
435
this.methodNode = null;
436     }
437
438     // GroovyCodeVisitor interface
439
//-------------------------------------------------------------------------
440

441     // Statements
442
//-------------------------------------------------------------------------
443

444     public void visitForLoop(ForStatement loop) {
445         onLineNumber(loop);
446
447
448         //
449
// Declare the loop counter.
450

451         Type variableType = checkValidType(loop.getVariableType(), loop, "for loop variable");
452         Variable variable = defineVariable(loop.getVariable(), variableType, true);
453
454         if( isInScriptBody() ) {
455             variable.setProperty( true );
456         }
457
458
459         //
460
// Then initialize the iterator and generate the loop control
461

462         loop.getCollectionExpression().visit(this);
463
464         asIteratorMethod.call(cv);
465
466         final int iteratorIdx = defineVariable(createVariableName("iterator"), "java.util.Iterator", false).getIndex();
467         cv.visitVarInsn(ASTORE, iteratorIdx);
468
469         pushBlockScope();
470
471         Label continueLabel = scope.getContinueLabel();
472         cv.visitJumpInsn(GOTO, continueLabel);
473         Label label2 = new Label();
474         cv.visitLabel(label2);
475
476         BytecodeExpression expression = new BytecodeExpression() {
477             public void visit(GroovyCodeVisitor visitor) {
478                 cv.visitVarInsn(ALOAD, iteratorIdx);
479
480                 iteratorNextMethod.call(cv);
481             }
482         };
483
484         evaluateEqual( BinaryExpression.newAssignmentExpression(loop.getVariable(), expression) );
485
486
487         //
488
// Generate the loop body
489

490         loop.getLoopBlock().visit(this);
491
492
493         //
494
// Generate the loop tail
495

496         cv.visitLabel(continueLabel);
497         cv.visitVarInsn(ALOAD, iteratorIdx);
498
499         iteratorHasNextMethod.call(cv);
500
501         cv.visitJumpInsn(IFNE, label2);
502
503         cv.visitLabel(scope.getBreakLabel());
504         popScope();
505     }
506
507     public void visitWhileLoop(WhileStatement loop) {
508         onLineNumber(loop);
509
510         /*
511          * // quick hack if (!methodNode.isStatic()) { cv.visitVarInsn(ALOAD,
512          * 0); }
513          */

514
515         pushBlockScope();
516
517         Label continueLabel = scope.getContinueLabel();
518
519         cv.visitJumpInsn(GOTO, continueLabel);
520         Label l1 = new Label();
521         cv.visitLabel(l1);
522
523         loop.getLoopBlock().visit(this);
524
525         cv.visitLabel(continueLabel);
526         //cv.visitVarInsn(ALOAD, 0);
527

528         loop.getBooleanExpression().visit(this);
529
530         cv.visitJumpInsn(IFNE, l1);
531
532         cv.visitLabel(scope.getBreakLabel());
533         popScope();
534     }
535
536     public void visitDoWhileLoop(DoWhileStatement loop) {
537         onLineNumber(loop);
538
539         pushBlockScope();
540
541         Label breakLabel = scope.getBreakLabel();
542
543         Label continueLabel = scope.getContinueLabel();
544         cv.visitLabel(continueLabel);
545         Label l1 = new Label();
546
547         loop.getLoopBlock().visit(this);
548
549         cv.visitLabel(l1);
550
551         loop.getBooleanExpression().visit(this);
552
553         cv.visitJumpInsn(IFNE, continueLabel);
554
555         cv.visitLabel(breakLabel);
556         popScope();
557     }
558
559     public void visitIfElse(IfStatement ifElse) {
560         onLineNumber(ifElse);
561
562         ifElse.getBooleanExpression().visit(this);
563
564         Label l0 = new Label();
565         cv.visitJumpInsn(IFEQ, l0);
566         ifElse.getIfBlock().visit(this);
567
568         Label l1 = new Label();
569         cv.visitJumpInsn(GOTO, l1);
570         cv.visitLabel(l0);
571
572         ifElse.getElseBlock().visit(this);
573         cv.visitLabel(l1);
574     }
575
576     public void visitTernaryExpression(TernaryExpression expression) {
577         onLineNumber(expression);
578
579         expression.getBooleanExpression().visit(this);
580
581         Label l0 = new Label();
582         cv.visitJumpInsn(IFEQ, l0);
583         expression.getTrueExpression().visit(this);
584
585         Label l1 = new Label();
586         cv.visitJumpInsn(GOTO, l1);
587         cv.visitLabel(l0);
588
589         expression.getFalseExpression().visit(this);
590         cv.visitLabel(l1);
591     }
592
593     public void visitAssertStatement(AssertStatement statement) {
594         onLineNumber(statement);
595
596         //System.out.println("Assert: " + statement.getLineNumber() + " for: "
597
// + statement.getText());
598

599         BooleanExpression booleanExpression = statement.getBooleanExpression();
600         booleanExpression.visit(this);
601
602         Label l0 = new Label();
603         cv.visitJumpInsn(IFEQ, l0);
604
605         // do nothing
606

607         Label l1 = new Label();
608         cv.visitJumpInsn(GOTO, l1);
609         cv.visitLabel(l0);
610
611         // push expression string onto stack
612
String JavaDoc expressionText = booleanExpression.getText();
613         List JavaDoc list = new ArrayList JavaDoc();
614         addVariableNames(booleanExpression, list);
615         if (list.isEmpty()) {
616             cv.visitLdcInsn(expressionText);
617         }
618         else {
619             boolean first = true;
620
621             // lets create a new expression
622
cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
623             cv.visitInsn(DUP);
624             cv.visitLdcInsn(expressionText + ". Values: ");
625
626             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
627
628             int tempIndex = defineVariable(createVariableName("assert"), "java.lang.Object", false).getIndex();
629
630             cv.visitVarInsn(ASTORE, tempIndex);
631
632             for (Iterator JavaDoc iter = list.iterator(); iter.hasNext();) {
633                 String JavaDoc name = (String JavaDoc) iter.next();
634                 String JavaDoc text = name + " = ";
635                 if (first) {
636                     first = false;
637                 }
638                 else {
639                     text = ", " + text;
640                 }
641
642                 cv.visitVarInsn(ALOAD, tempIndex);
643                 cv.visitLdcInsn(text);
644                 cv.visitMethodInsn(
645                     INVOKEVIRTUAL,
646                     "java/lang/StringBuffer",
647                     "append",
648                     "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
649                 cv.visitInsn(POP);
650
651                 cv.visitVarInsn(ALOAD, tempIndex);
652                 new VariableExpression(name).visit(this);
653                 cv.visitMethodInsn(
654                     INVOKEVIRTUAL,
655                     "java/lang/StringBuffer",
656                     "append",
657                     "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
658                 cv.visitInsn(POP);
659
660             }
661             cv.visitVarInsn(ALOAD, tempIndex);
662         }
663
664         // now the optional exception expression
665
statement.getMessageExpression().visit(this);
666
667         assertFailedMethod.call(cv);
668         cv.visitLabel(l1);
669     }
670
671     private void addVariableNames(Expression expression, List JavaDoc list) {
672         if (expression instanceof BooleanExpression) {
673             BooleanExpression boolExp = (BooleanExpression) expression;
674             addVariableNames(boolExp.getExpression(), list);
675         }
676         else if (expression instanceof BinaryExpression) {
677             BinaryExpression binExp = (BinaryExpression) expression;
678             addVariableNames(binExp.getLeftExpression(), list);
679             addVariableNames(binExp.getRightExpression(), list);
680         }
681         else if (expression instanceof VariableExpression) {
682             VariableExpression varExp = (VariableExpression) expression;
683             list.add(varExp.getVariable());
684         }
685     }
686
687     public void visitTryCatchFinally(TryCatchStatement statement) {
688         onLineNumber(statement);
689
690         CatchStatement catchStatement = statement.getCatchStatement(0);
691
692         Statement tryStatement = statement.getTryStatement();
693
694         if (tryStatement.isEmpty() || catchStatement == null) {
695             final Label l0 = new Label();
696             cv.visitLabel(l0);
697
698             tryStatement.visit(this);
699
700             int index1 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
701             int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
702
703             final Label l1 = new Label();
704             cv.visitJumpInsn(JSR, l1);
705             final Label l2 = new Label();
706             cv.visitLabel(l2);
707             final Label l3 = new Label();
708             cv.visitJumpInsn(GOTO, l3);
709             final Label l4 = new Label();
710             cv.visitLabel(l4);
711             cv.visitVarInsn(ASTORE, index1);
712             cv.visitJumpInsn(JSR, l1);
713             final Label l5 = new Label();
714             cv.visitLabel(l5);
715             cv.visitVarInsn(ALOAD, index1);
716             cv.visitInsn(ATHROW);
717             cv.visitLabel(l1);
718             cv.visitVarInsn(ASTORE, index2);
719
720             statement.getFinallyStatement().visit(this);
721
722             cv.visitVarInsn(RET, index2);
723             cv.visitLabel(l3);
724
725             exceptionBlocks.add(new Runnable JavaDoc() {
726                 public void run() {
727                     cv.visitTryCatchBlock(l0, l2, l4, null);
728                     cv.visitTryCatchBlock(l4, l5, l4, null);
729                 }
730             });
731
732         }
733         else {
734             String JavaDoc exceptionVar = catchStatement.getVariable();
735             String JavaDoc exceptionType =
736                 checkValidType(catchStatement.getExceptionType(), catchStatement, "in catch statement");
737
738             int exceptionIndex = defineVariable(exceptionVar, exceptionType, false).getIndex();
739             int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
740             int index3 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
741
742             final Label l0 = new Label();
743             cv.visitLabel(l0);
744
745             tryStatement.visit(this);
746
747             final Label l1 = new Label();
748             cv.visitLabel(l1);
749             Label l2 = new Label();
750             cv.visitJumpInsn(JSR, l2);
751             final Label l3 = new Label();
752             cv.visitLabel(l3);
753             Label l4 = new Label();
754             cv.visitJumpInsn(GOTO, l4);
755             final Label l5 = new Label();
756             cv.visitLabel(l5);
757
758             cv.visitVarInsn(ASTORE, exceptionIndex);
759
760             if (catchStatement != null) {
761                 catchStatement.visit(this);
762             }
763
764             cv.visitJumpInsn(JSR, l2);
765             final Label l6 = new Label();
766             cv.visitLabel(l6);
767             cv.visitJumpInsn(GOTO, l4);
768
769             final Label l7 = new Label();
770             cv.visitLabel(l7);
771             cv.visitVarInsn(ASTORE, index2);
772             cv.visitJumpInsn(JSR, l2);
773
774             final Label l8 = new Label();
775             cv.visitLabel(l8);
776             cv.visitVarInsn(ALOAD, index2);
777             cv.visitInsn(ATHROW);
778             cv.visitLabel(l2);
779             cv.visitVarInsn(ASTORE, index3);
780
781             statement.getFinallyStatement().visit(this);
782
783             cv.visitVarInsn(RET, index3);
784             cv.visitLabel(l4);
785
786             // rest of code goes here...
787

788             //final String exceptionTypeInternalName = (catchStatement !=
789
// null) ?
790
// getTypeDescription(exceptionType) : null;
791
final String JavaDoc exceptionTypeInternalName =
792                 (catchStatement != null) ? BytecodeHelper.getClassInternalName(exceptionType) : null;
793
794             exceptionBlocks.add(new Runnable JavaDoc() {
795                 public void run() {
796                     cv.visitTryCatchBlock(l0, l1, l5, exceptionTypeInternalName);
797                     cv.visitTryCatchBlock(l0, l3, l7, null);
798                     cv.visitTryCatchBlock(l5, l6, l7, null);
799                     cv.visitTryCatchBlock(l7, l8, l7, null);
800                 }
801             });
802         }
803     }
804
805     public void visitSwitch(SwitchStatement statement) {
806         onLineNumber(statement);
807
808         statement.getExpression().visit(this);
809
810         // switch does not have a continue label. use its parent's for continue
811
pushBlockScope(false, true);
812         scope.setContinueLabel(scope.getParent().getContinueLabel());
813
814
815         int switchVariableIndex = defineVariable(createVariableName("switch"), "java.lang.Object").getIndex();
816         cv.visitVarInsn(ASTORE, switchVariableIndex);
817
818         List JavaDoc caseStatements = statement.getCaseStatements();
819         int caseCount = caseStatements.size();
820         Label[] labels = new Label[caseCount + 1];
821         for (int i = 0; i < caseCount; i++) {
822             labels[i] = new Label();
823         }
824
825         int i = 0;
826         for (Iterator JavaDoc iter = caseStatements.iterator(); iter.hasNext(); i++) {
827             CaseStatement caseStatement = (CaseStatement) iter.next();
828             visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
829         }
830
831         statement.getDefaultStatement().visit(this);
832
833         cv.visitLabel(scope.getBreakLabel());
834
835         popScope();
836     }
837
838     public void visitCaseStatement(CaseStatement statement) {
839     }
840
841     public void visitCaseStatement(
842         CaseStatement statement,
843         int switchVariableIndex,
844         Label thisLabel,
845         Label nextLabel) {
846
847         onLineNumber(statement);
848
849         cv.visitVarInsn(ALOAD, switchVariableIndex);
850         statement.getExpression().visit(this);
851
852         isCaseMethod.call(cv);
853
854         Label l0 = new Label();
855         cv.visitJumpInsn(IFEQ, l0);
856
857         cv.visitLabel(thisLabel);
858
859         statement.getCode().visit(this);
860
861         // now if we don't finish with a break we need to jump past
862
// the next comparison
863
if (nextLabel != null) {
864             cv.visitJumpInsn(GOTO, nextLabel);
865         }
866
867         cv.visitLabel(l0);
868     }
869
870     public void visitBreakStatement(BreakStatement statement) {
871         onLineNumber(statement);
872
873         cv.visitJumpInsn(GOTO, scope.getBreakLabel());
874     }
875
876     public void visitContinueStatement(ContinueStatement statement) {
877         onLineNumber(statement);
878
879         cv.visitJumpInsn(GOTO, scope.getContinueLabel());
880     }
881
882     public void visitSynchronizedStatement(SynchronizedStatement statement) {
883         onLineNumber(statement);
884
885         statement.getExpression().visit(this);
886
887         int index = defineVariable(createVariableName("synchronized"), "java.lang.Integer").getIndex();
888
889         cv.visitVarInsn(ASTORE, index);
890         cv.visitInsn(MONITORENTER);
891         final Label l0 = new Label();
892         cv.visitLabel(l0);
893
894         statement.getCode().visit(this);
895
896         cv.visitVarInsn(ALOAD, index);
897         cv.visitInsn(MONITOREXIT);
898         final Label l1 = new Label();
899         cv.visitJumpInsn(GOTO, l1);
900         final Label l2 = new Label();
901         cv.visitLabel(l2);
902         cv.visitVarInsn(ALOAD, index);
903         cv.visitInsn(MONITOREXIT);
904         cv.visitInsn(ATHROW);
905         cv.visitLabel(l1);
906
907         exceptionBlocks.add(new Runnable JavaDoc() {
908             public void run() {
909                 cv.visitTryCatchBlock(l0, l2, l2, null);
910             }
911         });
912     }
913
914     public void visitThrowStatement(ThrowStatement statement) {
915         statement.getExpression().visit(this);
916
917         // we should infer the type of the exception from the expression
918
cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
919
920         cv.visitInsn(ATHROW);
921     }
922
923     public void visitReturnStatement(ReturnStatement statement) {
924         onLineNumber(statement);
925         String JavaDoc returnType = methodNode.getReturnType();
926         if (returnType.equals("void")) {
927             if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) {
928                 throw new RuntimeParserException(
929                         "Cannot use return statement with an expression on a method that returns void",
930                         statement);
931
932             }
933             cv.visitInsn(RETURN);
934             outputReturn = true;
935             return;
936         }
937
938         Expression expression = statement.getExpression();
939         evaluateExpression(expression);
940
941         //return is based on class type
942
//TODO: make work with arrays
943
// we may need to cast
944
helper.unbox(returnType);
945         if (returnType.equals("double")) {
946             cv.visitInsn(DRETURN);
947         }
948         else if (returnType.equals("float")) {
949             cv.visitInsn(FRETURN);
950         }
951         else if (returnType.equals("long")) {
952             cv.visitInsn(LRETURN);
953         }
954         else if (returnType.equals("boolean")) {
955             cv.visitInsn(IRETURN);
956         }
957         else if (
958             returnType.equals("char")
959                 || returnType.equals("byte")
960                 || returnType.equals("int")
961                 || returnType.equals("short")) { //byte,short,boolean,int are
962
// all IRETURN
963
cv.visitInsn(IRETURN);
964         }
965         else {
966             doConvertAndCast(returnType, expression);
967             cv.visitInsn(ARETURN);
968
969             /*
970             if (c == Boolean.class) {
971                 Label l0 = new Label();
972                 cv.visitJumpInsn(IFEQ, l0);
973                 cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
974                 cv.visitInsn(ARETURN);
975                 cv.visitLabel(l0);
976                 cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
977                 cv.visitInsn(ARETURN);
978             }
979             else {
980                 if (isValidTypeForCast(returnType) && !returnType.equals(c.getName())) {
981                     doConvertAndCast(returnType, expression);
982                 }
983                 cv.visitInsn(ARETURN);
984             }
985             */

986         }
987
988         outputReturn = true;
989     }
990
991     /**
992      * Casts to the given type unless it can be determined that the cast is unnecessary
993      */

994     protected void doConvertAndCast(String JavaDoc type, Expression expression) {
995         String JavaDoc expType = getExpressionType(expression);
996
997         if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) {
998             doConvertAndCast(type);
999         }
1000    }
1001
1002    /**
1003     * @param expression
1004     */

1005    protected void evaluateExpression(Expression expression) {
1006        visitAndAutobox(expression);
1007        //expression.visit(this);
1008

1009        Expression assignExpr = createReturnLHSExpression(expression);
1010        if (assignExpr != null) {
1011            leftHandExpression = false;
1012            assignExpr.visit(this);
1013        }
1014    }
1015
1016    public void visitExpressionStatement(ExpressionStatement statement) {
1017        onLineNumber(statement);
1018
1019        Expression expression = statement.getExpression();
1020        visitAndAutobox(expression);
1021
1022        if (isPopRequired(expression)) {
1023            cv.visitInsn(POP);
1024        }
1025    }
1026
1027    // Expressions
1028
//-------------------------------------------------------------------------
1029

1030    public void visitBinaryExpression(BinaryExpression expression) {
1031        switch (expression.getOperation().getType()) {
1032            case Types.EQUAL :
1033                evaluateEqual(expression);
1034                break;
1035
1036            case Types.COMPARE_IDENTICAL :
1037                evaluateBinaryExpression(compareIdenticalMethod, expression);
1038                break;
1039
1040            case Types.COMPARE_EQUAL :
1041                evaluateBinaryExpression(compareEqualMethod, expression);
1042                break;
1043
1044            case Types.COMPARE_NOT_EQUAL :
1045                evaluateBinaryExpression(compareNotEqualMethod, expression);
1046                break;
1047
1048            case Types.COMPARE_TO :
1049                evaluateCompareTo(expression);
1050                break;
1051
1052            case Types.COMPARE_GREATER_THAN :
1053                evaluateBinaryExpression(compareGreaterThanMethod, expression);
1054                break;
1055
1056            case Types.COMPARE_GREATER_THAN_EQUAL :
1057                evaluateBinaryExpression(compareGreaterThanEqualMethod, expression);
1058                break;
1059
1060            case Types.COMPARE_LESS_THAN :
1061                evaluateBinaryExpression(compareLessThanMethod, expression);
1062                break;
1063
1064            case Types.COMPARE_LESS_THAN_EQUAL :
1065                evaluateBinaryExpression(compareLessThanEqualMethod, expression);
1066                break;
1067
1068            case Types.LOGICAL_AND :
1069                evaluateLogicalAndExpression(expression);
1070                break;
1071
1072            case Types.LOGICAL_OR :
1073                evaluateLogicalOrExpression(expression);
1074                break;
1075
1076            case Types.PLUS :
1077                evaluateBinaryExpression("plus", expression);
1078                break;
1079
1080            case Types.PLUS_EQUAL :
1081                evaluateBinaryExpressionWithAsignment("plus", expression);
1082                break;
1083
1084            case Types.MINUS :
1085                evaluateBinaryExpression("minus", expression);
1086                break;
1087
1088            case Types.MINUS_EQUAL :
1089                evaluateBinaryExpressionWithAsignment("minus", expression);
1090                break;
1091
1092            case Types.MULTIPLY :
1093                evaluateBinaryExpression("multiply", expression);
1094                break;
1095
1096            case Types.MULTIPLY_EQUAL :
1097                evaluateBinaryExpressionWithAsignment("multiply", expression);
1098                break;
1099
1100            case Types.DIVIDE :
1101                //SPG don't use divide since BigInteger implements directly
1102
//and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
1103
evaluateBinaryExpression("div", expression);
1104                break;
1105
1106            case Types.DIVIDE_EQUAL :
1107                //SPG don't use divide since BigInteger implements directly
1108
//and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
1109
evaluateBinaryExpressionWithAsignment("div", expression);
1110                break;
1111
1112            case Types.INTDIV :
1113                evaluateBinaryExpression("intdiv", expression);
1114                break;
1115
1116            case Types.INTDIV_EQUAL :
1117                evaluateBinaryExpressionWithAsignment("intdiv", expression);
1118                break;
1119
1120            case Types.MOD :
1121                evaluateBinaryExpression("mod", expression);
1122                break;
1123
1124            case Types.MOD_EQUAL :
1125                evaluateBinaryExpressionWithAsignment("mod", expression);
1126                break;
1127
1128            case Types.LEFT_SHIFT :
1129                evaluateBinaryExpression("leftShift", expression);
1130                break;
1131
1132            case Types.RIGHT_SHIFT :
1133                evaluateBinaryExpression("rightShift", expression);
1134                break;
1135
1136            case Types.RIGHT_SHIFT_UNSIGNED :
1137                evaluateBinaryExpression("rightShiftUnsigned", expression);
1138                break;
1139
1140            case Types.KEYWORD_INSTANCEOF :
1141                evaluateInstanceof(expression);
1142                break;
1143
1144            case Types.FIND_REGEX :
1145                evaluateBinaryExpression(findRegexMethod, expression);
1146                break;
1147
1148            case Types.MATCH_REGEX :
1149                evaluateBinaryExpression(matchRegexMethod, expression);
1150                break;
1151
1152            case Types.LEFT_SQUARE_BRACKET :
1153                if (leftHandExpression) {
1154                    throw new RuntimeException JavaDoc("Should not be called");
1155                    //evaluateBinaryExpression("putAt", expression);
1156
}
1157                else {
1158                    evaluateBinaryExpression("getAt", expression);
1159                }
1160                break;
1161
1162            default :
1163                throw new ClassGeneratorException("Operation: " + expression.getOperation() + " not supported");
1164        }
1165    }
1166
1167    public void visitPostfixExpression(PostfixExpression expression) {
1168        switch (expression.getOperation().getType()) {
1169            case Types.PLUS_PLUS :
1170                evaluatePostfixMethod("next", expression.getExpression());
1171                break;
1172            case Types.MINUS_MINUS :
1173                evaluatePostfixMethod("previous", expression.getExpression());
1174                break;
1175        }
1176    }
1177
1178    public void visitPrefixExpression(PrefixExpression expression) {
1179        switch (expression.getOperation().getType()) {
1180            case Types.PLUS_PLUS :
1181                evaluatePrefixMethod("next", expression.getExpression());
1182                break;
1183            case Types.MINUS_MINUS :
1184                evaluatePrefixMethod("previous", expression.getExpression());
1185                break;
1186        }
1187    }
1188
1189    public void visitClosureExpression(ClosureExpression expression) {
1190        ClassNode innerClass = createClosureClass(expression);
1191        addInnerClass(innerClass);
1192        String JavaDoc innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName());
1193
1194        ClassNode owner = innerClass.getOuterClass();
1195        String JavaDoc ownerTypeName = owner.getName();
1196        if (classNode.isStaticClass() || isStaticMethod()) {
1197            ownerTypeName = "java.lang.Class";
1198        }
1199
1200        passingClosureParams = true;
1201        List JavaDoc constructors = innerClass.getDeclaredConstructors();
1202        ConstructorNode node = (ConstructorNode) constructors.get(0);
1203        Parameter[] localVariableParams = node.getParameters();
1204
1205
1206        //
1207
// Define in the context any variables that will be
1208
// created inside the closure. Note that the first two
1209
// parameters are always _outerInstance and _delegate,
1210
// so we don't worry about them.
1211

1212        for (int i = 2; i < localVariableParams.length; i++) {
1213            Parameter param = localVariableParams[i];
1214            String JavaDoc name = param.getName();
1215
1216            if (variableStack.get(name) == null && classNode.getField(name) == null) {
1217                defineVariable(name, "java.lang.Object");
1218            }
1219        }
1220
1221        cv.visitTypeInsn(NEW, innerClassinternalName);
1222        cv.visitInsn(DUP);
1223        if (isStaticMethod() || classNode.isStaticClass()) {
1224            visitClassExpression(new ClassExpression(ownerTypeName));
1225        }
1226        else {
1227            loadThisOrOwner();
1228        }
1229
1230        if (innerClass.getSuperClass().equals("groovy.lang.Closure")) {
1231            if (isStaticMethod()) {
1232                /**
1233                 * todo could maybe stash this expression in a JVM variable
1234                 * from previous statement above
1235                 */

1236                visitClassExpression(new ClassExpression(ownerTypeName));
1237            }
1238            else {
1239                loadThisOrOwner();
1240            }
1241        }
1242
1243        //String prototype = "(L" + BytecodeHelper.getClassInternalName(ownerTypeName) + ";Ljava/lang/Object;";
1244

1245        // now lets load the various parameters we're passing
1246
for (int i = 2; i < localVariableParams.length; i++) {
1247            Parameter param = localVariableParams[i];
1248            String JavaDoc name = param.getName();
1249
1250            if (variableStack.get(name) == null) {
1251                visitFieldExpression(new FieldExpression(classNode.getField(name)));
1252            }
1253            else {
1254                visitVariableExpression(new VariableExpression(name));
1255            }
1256            //prototype = prototype + "L" + BytecodeHelper.getClassInternalName(param.getType()) + ";";
1257
}
1258        passingClosureParams = false;
1259
1260        // we may need to pass in some other constructors
1261
//cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
1262
cv.visitMethodInsn(
1263            INVOKESPECIAL,
1264            innerClassinternalName,
1265            "<init>",
1266            BytecodeHelper.getMethodDescriptor("void", localVariableParams));
1267    }
1268
1269    /**
1270     * Loads either this object or if we're inside a closure then load the top level owner
1271     */

1272    protected void loadThisOrOwner() {
1273        if (isInnerClass()) {
1274            visitFieldExpression(new FieldExpression(classNode.getField("owner")));
1275        }
1276        else {
1277            cv.visitVarInsn(ALOAD, 0);
1278        }
1279    }
1280
1281    public void visitRegexExpression(RegexExpression expression) {
1282        expression.getRegex().visit(this);
1283        regexPattern.call(cv);
1284    }
1285
1286    /**
1287     * Generate byte code for constants
1288     * @see <a HREF="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a>
1289     */

1290    public void visitConstantExpression(ConstantExpression expression) {
1291        Object JavaDoc value = expression.getValue();
1292        if (value == null) {
1293            cv.visitInsn(ACONST_NULL);
1294        }
1295        else if (value instanceof String JavaDoc) {
1296            cv.visitLdcInsn(value);
1297        }
1298        else if (value instanceof Number JavaDoc) {
1299            /** todo it would be more efficient to generate class constants */
1300            Number JavaDoc n = (Number JavaDoc) value;
1301            String JavaDoc className = BytecodeHelper.getClassInternalName(value.getClass().getName());
1302            cv.visitTypeInsn(NEW, className);
1303            cv.visitInsn(DUP);
1304            String JavaDoc methodType;
1305            if (n instanceof Double JavaDoc) {
1306                cv.visitLdcInsn(n);
1307                methodType = "(D)V";
1308            }
1309            else if (n instanceof Float JavaDoc) {
1310                cv.visitLdcInsn(n);
1311                methodType = "(F)V";
1312            }
1313            else if (value instanceof Long JavaDoc) {
1314                cv.visitLdcInsn(n);
1315                methodType = "(J)V";
1316            }
1317            else if (value instanceof BigDecimal JavaDoc) {
1318                cv.visitLdcInsn(n.toString());
1319                methodType = "(Ljava/lang/String;)V";
1320            }
1321            else if (value instanceof BigInteger JavaDoc) {
1322                cv.visitLdcInsn(n.toString());
1323                methodType = "(Ljava/lang/String;)V";
1324            }
1325            else if (value instanceof Integer JavaDoc){
1326                cv.visitLdcInsn(n);
1327                methodType = "(I)V";
1328            }
1329            else
1330            {
1331                throw new ClassGeneratorException(
1332                        "Cannot generate bytecode for constant: " + value
1333                        + " of type: " + value.getClass().getName()
1334                        +". Numeric constant type not supported.");
1335            }
1336
1337            cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
1338        }
1339        else if (value instanceof Boolean JavaDoc) {
1340            Boolean JavaDoc bool = (Boolean JavaDoc) value;
1341            String JavaDoc text = (bool.booleanValue()) ? "TRUE" : "FALSE";
1342            cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
1343        }
1344        else if (value instanceof Class JavaDoc) {
1345            Class JavaDoc vc = (Class JavaDoc) value;
1346            if (!vc.getName().equals("java.lang.Void")) {
1347                throw new ClassGeneratorException(
1348                "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
1349            }
1350        }
1351        else {
1352            throw new ClassGeneratorException(
1353                "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
1354        }
1355    }
1356
1357    public void visitNegationExpression(NegationExpression expression) {
1358        Expression subExpression = expression.getExpression();
1359        subExpression.visit(this);
1360        negation.call(cv);
1361    }
1362
1363    public void visitCastExpression(CastExpression expression) {
1364        String JavaDoc type = expression.getType();
1365        type = checkValidType(type, expression, "in cast");
1366
1367        visitAndAutobox(expression.getExpression());
1368
1369        doConvertAndCast(type, expression.getExpression());
1370    }
1371
1372    public void visitNotExpression(NotExpression expression) {
1373        Expression subExpression = expression.getExpression();
1374        subExpression.visit(this);
1375
1376        // This is not the best way to do this. Javac does it by reversing the
1377
// underlying expressions but that proved
1378
// fairly complicated for not much gain. Instead we'll just use a
1379
// utility function for now.
1380
if (comparisonExpression(expression.getExpression())) {
1381            notBoolean.call(cv);
1382        }
1383        else {
1384            notObject.call(cv);
1385        }
1386    }
1387
1388    public void visitBooleanExpression(BooleanExpression expression) {
1389        expression.getExpression().visit(this);
1390
1391        if (!comparisonExpression(expression.getExpression())) {
1392            asBool.call(cv);
1393        }
1394    }
1395
1396    public void visitMethodCallExpression(MethodCallExpression call) {
1397        this.leftHandExpression = false;
1398
1399        Expression arguments = call.getArguments();
1400        /*
1401         * if (arguments instanceof TupleExpression) { TupleExpression
1402         * tupleExpression = (TupleExpression) arguments; int size =
1403         * tupleExpression.getExpressions().size(); if (size == 0) { arguments =
1404         * ConstantExpression.EMPTY_ARRAY; } }
1405         */

1406        boolean superMethodCall = MethodCallExpression.isSuperMethodCall(call);
1407        String JavaDoc method = call.getMethod();
1408        if (superMethodCall && method.equals("<init>")) {
1409            /** todo handle method types! */
1410            cv.visitVarInsn(ALOAD, 0);
1411            if (isInClosureConstructor()) { // br use the second param to init the super class (Closure)
1412
cv.visitVarInsn(ALOAD, 2);
1413                cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
1414            }
1415            else {
1416                cv.visitVarInsn(ALOAD, 1);
1417                cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V");
1418            }
1419        }
1420        else {
1421            // are we a local variable
1422
if (isThisExpression(call.getObjectExpression()) && isFieldOrVariable(call.getMethod())) {
1423                /*
1424                 * if (arguments instanceof TupleExpression) { TupleExpression
1425                 * tupleExpression = (TupleExpression) arguments; int size =
1426                 * tupleExpression.getExpressions().size(); if (size == 1) {
1427                 * arguments = (Expression)
1428                 * tupleExpression.getExpressions().get(0); } }
1429                 */

1430
1431                // lets invoke the closure method
1432
visitVariableExpression(new VariableExpression(method));
1433                arguments.visit(this);
1434                invokeClosureMethod.call(cv);
1435            }
1436            else {
1437                if (superMethodCall) {
1438                    if (method.equals("super") || method.equals("<init>")) {
1439                        ConstructorNode superConstructorNode = findSuperConstructor(call);
1440
1441                        cv.visitVarInsn(ALOAD, 0);
1442
1443                        loadArguments(superConstructorNode.getParameters(), arguments);
1444
1445                        String JavaDoc descriptor = BytecodeHelper.getMethodDescriptor("void", superConstructorNode.getParameters());
1446                        cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", descriptor);
1447                    }
1448                    else {
1449                        MethodNode superMethodNode = findSuperMethod(call);
1450
1451                        cv.visitVarInsn(ALOAD, 0);
1452
1453                        loadArguments(superMethodNode.getParameters(), arguments);
1454
1455                        String JavaDoc descriptor = BytecodeHelper.getMethodDescriptor(superMethodNode.getReturnType(), superMethodNode.getParameters());
1456                        cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superMethodNode.getDeclaringClass().getName()), method, descriptor);
1457                    }
1458                }
1459                else {
1460                    if (emptyArguments(arguments) && !call.isSafe()) {
1461                        call.getObjectExpression().visit(this);
1462                        cv.visitLdcInsn(method);
1463                        invokeNoArgumentsMethod.call(cv);
1464                    }
1465                    else {
1466                        if (argumentsUseStack(arguments)) {
1467                            int paramIdx =
1468                                defineVariable(createVariableName("temp"), "java.lang.Object", false).getIndex();
1469
1470                            arguments.visit(this);
1471
1472                            cv.visitVarInsn(ASTORE, paramIdx);
1473
1474                            call.getObjectExpression().visit(this);
1475
1476                            cv.visitLdcInsn(method);
1477
1478                            cv.visitVarInsn(ALOAD, paramIdx);
1479                        }
1480                        else {
1481                            call.getObjectExpression().visit(this);
1482                            cv.visitLdcInsn(method);
1483                            arguments.visit(this);
1484                        }
1485
1486                        if (call.isSafe()) {
1487                            invokeMethodSafeMethod.call(cv);
1488                        }
1489                        else {
1490                            invokeMethodMethod.call(cv);
1491                        }
1492                    }
1493                }
1494            }
1495        }
1496    }
1497
1498    /**
1499     * Loads and coerces the argument values for the given method call
1500     */

1501    protected void loadArguments(Parameter[] parameters, Expression expression) {
1502        TupleExpression argListExp = (TupleExpression) expression;
1503        List JavaDoc arguments = argListExp.getExpressions();
1504        for (int i = 0, size = arguments.size(); i < size; i++) {
1505            Expression argExp = argListExp.getExpression(i);
1506            Parameter param = parameters[i];
1507            visitAndAutobox(argExp);
1508
1509            String JavaDoc type = param.getType();
1510            if (BytecodeHelper.isPrimitiveType(type)) {
1511                helper.unbox(type);
1512            }
1513            doConvertAndCast(type, argExp);
1514        }
1515    }
1516
1517    /**
1518     * Attempts to find the method of the given name in a super class
1519     */

1520    protected MethodNode findSuperMethod(MethodCallExpression call) {
1521        String JavaDoc methodName = call.getMethod();
1522        TupleExpression argExpr = (TupleExpression) call.getArguments();
1523        int argCount = argExpr.getExpressions().size();
1524        ClassNode superClassNode = classNode.getSuperClassNode();
1525        if (superClassNode != null) {
1526            List JavaDoc methods = superClassNode.getMethods(methodName);
1527            for (Iterator JavaDoc iter = methods.iterator(); iter.hasNext(); ) {
1528                MethodNode method = (MethodNode) iter.next();
1529                if (method.getParameters().length == argCount) {
1530                    return method;
1531                }
1532            }
1533        }
1534        throw new GroovyRuntimeException("No such method: " + methodName + " for class: " + classNode.getName(), call);
1535    }
1536
1537    /**
1538     * Attempts to find the constructor in a super class
1539     */

1540    protected ConstructorNode findSuperConstructor(MethodCallExpression call) {
1541        TupleExpression argExpr = (TupleExpression) call.getArguments();
1542        int argCount = argExpr.getExpressions().size();
1543        ClassNode superClassNode = classNode.getSuperClassNode();
1544        if (superClassNode != null) {
1545            List JavaDoc constructors = superClassNode.getDeclaredConstructors();
1546            for (Iterator JavaDoc iter = constructors.iterator(); iter.hasNext(); ) {
1547                ConstructorNode constructor = (ConstructorNode) iter.next();
1548                if (constructor.getParameters().length == argCount) {
1549                    return constructor;
1550                }
1551            }
1552        }
1553        throw new GroovyRuntimeException("No such constructor for class: " + classNode.getName(), call);
1554    }
1555
1556    protected boolean emptyArguments(Expression arguments) {
1557        if (arguments instanceof TupleExpression) {
1558            TupleExpression tupleExpression = (TupleExpression) arguments;
1559            int size = tupleExpression.getExpressions().size();
1560            return size == 0;
1561        }
1562        return false;
1563    }
1564
1565    public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
1566        this.leftHandExpression = false;
1567
1568        Expression arguments = call.getArguments();
1569        if (emptyArguments(arguments)) {
1570            cv.visitLdcInsn(call.getType());
1571            cv.visitLdcInsn(call.getMethod());
1572
1573            invokeStaticNoArgumentsMethod.call(cv);
1574        }
1575        else {
1576            if (arguments instanceof TupleExpression) {
1577                TupleExpression tupleExpression = (TupleExpression) arguments;
1578                int size = tupleExpression.getExpressions().size();
1579                if (size == 1) {
1580                    arguments = (Expression) tupleExpression.getExpressions().get(0);
1581                }
1582            }
1583
1584            cv.visitLdcInsn(call.getType());
1585            cv.visitLdcInsn(call.getMethod());
1586            arguments.visit(this);
1587
1588            invokeStaticMethodMethod.call(cv);
1589        }
1590    }
1591
1592    public void visitConstructorCallExpression(ConstructorCallExpression call) {
1593        this.leftHandExpression = false;
1594
1595        Expression arguments = call.getArguments();
1596        if (arguments instanceof TupleExpression) {
1597            TupleExpression tupleExpression = (TupleExpression) arguments;
1598            int size = tupleExpression.getExpressions().size();
1599            if (size == 0) {
1600                arguments = null;
1601            }
1602            else if (size == 1) {
1603                arguments = (Expression) tupleExpression.getExpressions().get(0);
1604            }
1605        }
1606
1607        // lets check that the type exists
1608
String JavaDoc type = checkValidType(call.getType(), call, "in constructor call");
1609
1610        //System.out.println("Constructing: " + type);
1611

1612        visitClassExpression(new ClassExpression(type));
1613        if (arguments !=null) {
1614               arguments.visit(this);
1615            invokeConstructorOfMethod.call(cv);
1616        } else {
1617               invokeNoArgumentsConstructorOf.call(cv);
1618        }
1619        /*
1620         * cv.visitLdcInsn(type);
1621         *
1622         * arguments.visit(this);
1623         *
1624         * invokeConstructorMethod.call(cv);
1625         */

1626    }
1627
1628    public void visitPropertyExpression(PropertyExpression expression) {
1629
1630        // lets check if we're a fully qualified class name
1631
String JavaDoc className = checkForQualifiedClass(expression);
1632        if (className != null) {
1633            visitClassExpression(new ClassExpression(className));
1634            return;
1635        }
1636        Expression objectExpression = expression.getObjectExpression();
1637        if (expression.getProperty().equals("class")) {
1638            if ((objectExpression instanceof ClassExpression)) {
1639                visitClassExpression((ClassExpression) objectExpression);
1640                return;
1641            }
1642            else if (objectExpression instanceof VariableExpression) {
1643                VariableExpression varExp = (VariableExpression) objectExpression;
1644                className = varExp.getVariable();
1645                try {
1646                    className = resolveClassName(className);
1647                    visitClassExpression(new ClassExpression(className));
1648                    return;
1649                }
1650                catch (Exception JavaDoc e) {
1651                    // ignore
1652
}
1653            }
1654        }
1655
1656        if (isThisExpression(objectExpression)) {
1657            // lets use the field expression if its available
1658
String JavaDoc name = expression.getProperty();
1659            FieldNode field = classNode.getField(name);
1660            if (field != null) {
1661                visitFieldExpression(new FieldExpression(field));
1662                return;
1663            }
1664        }
1665
1666        boolean left = leftHandExpression;
1667        // we need to clear the LHS flag to avoid "this." evaluating as ASTORE
1668
// rather than ALOAD
1669
leftHandExpression = false;
1670
1671        objectExpression.visit(this);
1672
1673        cv.visitLdcInsn(expression.getProperty());
1674
1675        if (isGroovyObject(objectExpression) && ! expression.isSafe()) {
1676            if (left) {
1677                setGroovyObjectPropertyMethod.call(cv);
1678            }
1679            else {
1680                getGroovyObjectPropertyMethod.call(cv);
1681            }
1682        }
1683        else {
1684            if (expression.isSafe()) {
1685                if (left) {
1686                    setPropertySafeMethod2.call(cv);
1687                }
1688                else {
1689                    getPropertySafeMethod.call(cv);
1690                }
1691            }
1692            else {
1693                if (left) {
1694                    setPropertyMethod2.call(cv);
1695                }
1696                else {
1697                    getPropertyMethod.call(cv);
1698                }
1699            }
1700        }
1701    }
1702
1703    protected boolean isGroovyObject(Expression objectExpression) {
1704        return isThisExpression(objectExpression);
1705    }
1706
1707    /**
1708     * Checks if the given property expression represents a fully qualified class name
1709     * @return the class name or null if the property is not a valid class name
1710     */

1711    protected String JavaDoc checkForQualifiedClass(PropertyExpression expression) {
1712        String JavaDoc text = expression.getText();
1713        try {
1714            return resolveClassName(text);
1715        }
1716        catch (Exception JavaDoc e) {
1717            if (text.endsWith(".class")) {
1718                text = text.substring(0, text.length() - 6);
1719                try {
1720                    return resolveClassName(text);
1721                }
1722                catch (Exception JavaDoc e2) {
1723                }
1724            }
1725            return null;
1726        }
1727    }
1728
1729    public void visitFieldExpression(FieldExpression expression) {
1730        FieldNode field = expression.getField();
1731        boolean isStatic = field.isStatic();
1732
1733        boolean holder = field.isHolder() && !isInClosureConstructor();
1734        if (!isStatic && !leftHandExpression) {
1735            cv.visitVarInsn(ALOAD, 0);
1736        }
1737        String JavaDoc type = field.getType();
1738        int tempIndex = defineVariable(createVariableName("field"), "java.lang.Object", false).getIndex();
1739
1740        if (leftHandExpression && !holder) {
1741            if (isInClosureConstructor()) {
1742                helper.doCast(type);
1743            }
1744            else {
1745                // this may be superflous
1746
doConvertAndCast(type);
1747            }
1748        }
1749
1750        String JavaDoc ownerName =
1751            (field.getOwner().equals(classNode.getName()))
1752                ? internalClassName
1753                : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
1754        int opcode = isStatic ? GETSTATIC : GETFIELD;
1755        if (holder) {
1756            if (leftHandExpression) {
1757                cv.visitVarInsn(ASTORE, tempIndex);
1758                if (!isStatic)
1759                    cv.visitVarInsn(ALOAD, 0); // br
1760
cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1761                //cv.visitInsn(SWAP); // swap the value and the this pointer . swap is used to save a temp
1762
cv.visitVarInsn(ALOAD, tempIndex);
1763                cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
1764            }
1765            else {
1766                cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1767                cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
1768            }
1769        }
1770        else {
1771            if (leftHandExpression) {
1772                if (!isStatic) {
1773                    opcode = PUTFIELD;
1774                    helper.store(field.getType(), tempIndex);
1775                    cv.visitVarInsn(ALOAD, 0); // static does not need this pointer
1776
//cv.visitInsn(SWAP); // swap the value and the this pointer . swap is not type safe
1777
// cv.visitVarInsn(ALOAD, tempIndex);
1778
helper.load(field.getType(), tempIndex);
1779
1780                } else {
1781                    opcode = PUTSTATIC;
1782                }
1783                cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1784            }else {
1785                cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
1786                if (BytecodeHelper.isPrimitiveType(type)) {
1787                    helper.box(type);
1788                }
1789            }
1790        }
1791    }
1792
1793    protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) {
1794        int valueIdx = defineVariable(createVariableName("temp"), "java.lang.Object", false).getIndex();
1795
1796        if (leftHandExpression && first) {
1797            cv.visitVarInsn(ASTORE, valueIdx);
1798        }
1799
1800        FieldNode field = expression.getField();
1801        boolean isStatic = field.isStatic();
1802
1803        if (steps > 1 || !isStatic) {
1804            cv.visitVarInsn(ALOAD, 0);
1805            cv.visitFieldInsn(
1806                GETFIELD,
1807                internalClassName,
1808                "owner",
1809                BytecodeHelper.getTypeDescription(outerClassNode.getName()));
1810        }
1811
1812        if( steps == 1 ) {
1813            int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD);
1814            String JavaDoc ownerName = BytecodeHelper.getClassInternalName(outerClassNode.getName());
1815
1816            if (leftHandExpression) {
1817                cv.visitVarInsn(ALOAD, valueIdx);
1818                boolean holder = field.isHolder() && !isInClosureConstructor();
1819                if ( !holder) {
1820                    doConvertAndCast(field.getType());
1821                }
1822            }
1823            cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
1824            if (!leftHandExpression) {
1825                if (BytecodeHelper.isPrimitiveType(field.getType())) {
1826                    helper.box(field.getType());
1827                }
1828            }
1829        }
1830
1831        else {
1832            visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false );
1833        }
1834    }
1835
1836
1837
1838    /**
1839     * Visits a bare (unqualified) variable expression.
1840     */

1841
1842    public void visitVariableExpression(VariableExpression expression) {
1843
1844        String JavaDoc variableName = expression.getVariable();
1845
1846      //-----------------------------------------------------------------------
1847
// SPECIAL CASES
1848

1849        //
1850
// "this" for static methods is the Class instance
1851

1852        if (isStaticMethod() && variableName.equals("this")) {
1853            visitClassExpression(new ClassExpression(classNode.getName()));
1854            return; // <<< FLOW CONTROL <<<<<<<<<
1855
}
1856
1857        //
1858
// "super" also requires special handling
1859

1860        if (variableName.equals("super")) {
1861            visitClassExpression(new ClassExpression(classNode.getSuperClass()));
1862            return; // <<< FLOW CONTROL <<<<<<<<<
1863
}
1864
1865
1866        //
1867
// class names return a Class instance, too
1868

1869        if (!variableName.equals("this")) {
1870            String JavaDoc className = resolveClassName(variableName);
1871            if (className != null) {
1872                if (leftHandExpression) {
1873                    throw new RuntimeParserException(
1874                        "Cannot use a class expression on the left hand side of an assignment",
1875                        expression);
1876                }
1877                visitClassExpression(new ClassExpression(className));
1878                return; // <<< FLOW CONTROL <<<<<<<<<
1879
}
1880        }
1881
1882
1883      //-----------------------------------------------------------------------
1884
// GENERAL VARIABLE LOOKUP
1885

1886
1887        //
1888
// We are handling only unqualified variables here. Therefore,
1889
// we do not care about accessors, because local access doesn't
1890
// go through them. Therefore, precedence is as follows:
1891
// 1) local variables, nearest block first
1892
// 2) class fields
1893
// 3) repeat search from 2) in next outer class
1894

1895        boolean handled = false;
1896        Variable variable = (Variable)variableStack.get( variableName );
1897
1898        if( variable != null ) {
1899
1900            if( variable.isProperty() ) {
1901                processPropertyVariable( variableName, variable );
1902            }
1903            else {
1904                processStackVariable( variableName, variable );
1905            }
1906
1907            handled = true;
1908        }
1909
1910        //
1911
// Loop through outer classes for fields
1912

1913        else {
1914
1915            int steps = 0;
1916            ClassNode current = classNode;
1917            FieldNode field = null;
1918
1919            do {
1920                if( (field = current.getField(variableName)) != null ) {
1921                    break;
1922                }
1923                steps++;
1924
1925            } while( (current = current.getOuterClass()) != null );
1926
1927            if( field != null ) {
1928                processFieldAccess( variableName, field, steps );
1929                handled = true;
1930            }
1931        }
1932
1933
1934        //
1935
// Finally, if unhandled, create a variable for it.
1936
// Except there a stack variable should be created,
1937
// we define the variable as a property accessor and
1938
// let other parts of the classgen report the error
1939
// if the property doesn't exist.
1940

1941        if( !handled ) {
1942           String JavaDoc variableType = expression.getType();
1943           variable = defineVariable( variableName, variableType );
1944
1945           if( isInScriptBody() || !leftHandExpression ) {
1946               variable.setProperty( true );
1947               processPropertyVariable( variableName, variable );
1948           }
1949           else {
1950               processStackVariable( variableName, variable );
1951           }
1952        }
1953    }
1954
1955
1956    protected void processStackVariable( String JavaDoc name, Variable variable ) {
1957        String JavaDoc type = variable.getTypeName();
1958        int index = variable.getIndex();
1959        boolean holder = variable.isHolder() && !passingClosureParams;
1960
1961        if( leftHandExpression ) {
1962            if (holder) {
1963                int tempIndex = defineVariable(createVariableName("reference"), type, false).getIndex();
1964                cv.visitVarInsn(ASTORE, tempIndex);
1965                cv.visitVarInsn(ALOAD, index);
1966                //cv.visitInsn(SWAP); // assuming the value is already on the stack
1967
cv.visitVarInsn(ALOAD, tempIndex);
1968                cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
1969            }
1970            else {
1971                helper.store("objref", index); // br seems right hand values on the stack are always object refs, primitives boxed
1972
//cv.visitVarInsn(ASTORE, index);
1973
}
1974        }
1975        else {
1976            if (holder) {
1977                cv.visitVarInsn(ALOAD, index);
1978                cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
1979            }
1980            else {
1981                cv.visitVarInsn(ALOAD, index);
1982            }
1983        }
1984
1985    }
1986
1987    protected void processPropertyVariable( String JavaDoc name, Variable variable ) {
1988        if (variable.isHolder() && passingClosureParams && isInScriptBody() ) {
1989            // lets create a ScriptReference to pass into the closure
1990
cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference");
1991            cv.visitInsn(DUP);
1992
1993            loadThisOrOwner();
1994            cv.visitLdcInsn(name);
1995
1996            cv.visitMethodInsn(
1997                INVOKESPECIAL,
1998                "org/codehaus/groovy/runtime/ScriptReference",
1999                "<init>",
2000                "(Lgroovy/lang/Script;Ljava/lang/String;)V");
2001        }
2002        else {
2003            visitPropertyExpression(new PropertyExpression(VariableExpression.THIS_EXPRESSION, name));
2004        }
2005    }
2006
2007
2008    protected void processFieldAccess( String JavaDoc name, FieldNode field, int steps ) {
2009        FieldExpression expression = new FieldExpression(field);
2010
2011        if( steps == 0 ) {
2012            visitFieldExpression( expression );
2013        }
2014        else {
2015            visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true );
2016        }
2017    }
2018
2019
2020
2021    /**
2022     * @return true if we are in a script body, where all variables declared are no longer
2023     * local variables but are properties
2024     */

2025    protected boolean isInScriptBody() {
2026        if (classNode.isScriptBody()) {
2027            return true;
2028        }
2029        else {
2030            return classNode.isScript() && methodNode != null && methodNode.getName().equals("run");
2031        }
2032    }
2033
2034    /**
2035     * @return true if this expression will have left a value on the stack
2036     * that must be popped
2037     */

2038    protected boolean isPopRequired(Expression expression) {
2039        if (expression instanceof MethodCallExpression) {
2040            return !MethodCallExpression.isSuperMethodCall((MethodCallExpression) expression);
2041        }
2042        if (expression instanceof BinaryExpression) {
2043            BinaryExpression binExp = (BinaryExpression) expression;
2044            switch (binExp.getOperation().getType()) {
2045                case Types.EQUAL :
2046                case Types.PLUS_EQUAL :
2047                case Types.MINUS_EQUAL :
2048                case Types.MULTIPLY_EQUAL :
2049                case Types.DIVIDE_EQUAL :
2050                case Types.INTDIV_EQUAL :
2051                case Types.MOD_EQUAL :
2052                    return false;
2053            }
2054        }
2055        return true;
2056    }
2057
2058    protected boolean firstStatementIsSuperInit(Statement code) {
2059        ExpressionStatement expStmt = null;
2060        if (code instanceof ExpressionStatement) {
2061            expStmt = (ExpressionStatement) code;
2062        }
2063        else if (code instanceof BlockStatement) {
2064            BlockStatement block = (BlockStatement) code;
2065            if (!block.getStatements().isEmpty()) {
2066                Object JavaDoc expr = block.getStatements().get(0);
2067                if (expr instanceof ExpressionStatement) {
2068                    expStmt = (ExpressionStatement) expr;
2069                }
2070            }
2071        }
2072        if (expStmt != null) {
2073            Expression expr = expStmt.getExpression();
2074            if (expr instanceof MethodCallExpression) {
2075                MethodCallExpression call = (MethodCallExpression) expr;
2076                if (MethodCallExpression.isSuperMethodCall(call)) {
2077                    // not sure which one is constantly used as the super class ctor call. To cover both for now
2078
return call.getMethod().equals("<init>") || call.getMethod().equals("super");
2079                }
2080            }
2081        }
2082        return false;
2083    }
2084
2085    protected void createSyntheticStaticFields() {
2086        for (Iterator JavaDoc iter = syntheticStaticFields.iterator(); iter.hasNext();) {
2087            String JavaDoc staticFieldName = (String JavaDoc) iter.next();
2088            // generate a field node
2089
cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null);
2090        }
2091
2092        if (!syntheticStaticFields.isEmpty()) {
2093            cv =
2094                cw.visitMethod(
2095                    ACC_STATIC + ACC_SYNTHETIC,
2096                    "class$",
2097                    "(Ljava/lang/String;)Ljava/lang/Class;",
2098                    null,
2099                    null);
2100            helper = new BytecodeHelper(cv);
2101
2102            Label l0 = new Label();
2103            cv.visitLabel(l0);
2104            cv.visitVarInsn(ALOAD, 0);
2105            cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
2106            Label l1 = new Label();
2107            cv.visitLabel(l1);
2108            cv.visitInsn(ARETURN);
2109            Label l2 = new Label();
2110            cv.visitLabel(l2);
2111            cv.visitVarInsn(ASTORE, 1);
2112            cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
2113            cv.visitInsn(DUP);
2114            cv.visitVarInsn(ALOAD, 1);
2115            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;");
2116            cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
2117            cv.visitInsn(ATHROW);
2118            cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); // br using l2 as the 2nd param seems create the right table entry
2119
cv.visitMaxs(3, 2);
2120
2121            cw.visitEnd();
2122        }
2123    }
2124
2125    public void visitClassExpression(ClassExpression expression) {
2126        String JavaDoc type = expression.getText();
2127        //type = checkValidType(type, expression, "Must be a valid type name for a constructor call");
2128

2129
2130        if (BytecodeHelper.isPrimitiveType(type)) {
2131            String JavaDoc objectType = BytecodeHelper.getObjectTypeForPrimitive(type);
2132            cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;");
2133        }
2134        else {
2135            final String JavaDoc staticFieldName =
2136                (type.equals(classNode.getName())) ? "class$0" : "class$" + type.replace('.', '$');
2137
2138            syntheticStaticFields.add(staticFieldName);
2139
2140            cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
2141            Label l0 = new Label();
2142            cv.visitJumpInsn(IFNONNULL, l0);
2143            cv.visitLdcInsn(type);
2144            cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
2145            cv.visitInsn(DUP);
2146            cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
2147            Label l1 = new Label();
2148            cv.visitJumpInsn(GOTO, l1);
2149            cv.visitLabel(l0);
2150            cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
2151            cv.visitLabel(l1);
2152        }
2153    }
2154
2155    public void visitRangeExpression(RangeExpression expression) {
2156        leftHandExpression = false;
2157        expression.getFrom().visit(this);
2158
2159        leftHandExpression = false;
2160        expression.getTo().visit(this);
2161
2162        helper.pushConstant(expression.isInclusive());
2163
2164        createRangeMethod.call(cv);
2165    }
2166
2167    public void visitMapEntryExpression(MapEntryExpression expression) {
2168    }
2169
2170    public void visitMapExpression(MapExpression expression) {
2171        List JavaDoc entries = expression.getMapEntryExpressions();
2172        int size = entries.size();
2173        helper.pushConstant(size * 2);
2174
2175        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2176
2177        int i = 0;
2178        for (Iterator JavaDoc iter = entries.iterator(); iter.hasNext();) {
2179            MapEntryExpression entry = (MapEntryExpression) iter.next();
2180
2181            cv.visitInsn(DUP);
2182            helper.pushConstant(i++);
2183            visitAndAutobox(entry.getKeyExpression());
2184            cv.visitInsn(AASTORE);
2185
2186            cv.visitInsn(DUP);
2187            helper.pushConstant(i++);
2188            visitAndAutobox(entry.getValueExpression());
2189            cv.visitInsn(AASTORE);
2190        }
2191        createMapMethod.call(cv);
2192    }
2193
2194    public void visitTupleExpression(TupleExpression expression) {
2195        int size = expression.getExpressions().size();
2196
2197        helper.pushConstant(size);
2198
2199        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2200
2201        for (int i = 0; i < size; i++) {
2202            cv.visitInsn(DUP);
2203            helper.pushConstant(i);
2204            visitAndAutobox(expression.getExpression(i));
2205            cv.visitInsn(AASTORE);
2206        }
2207        //createTupleMethod.call(cv);
2208
}
2209
2210    public void visitArrayExpression(ArrayExpression expression) {
2211        String JavaDoc type = expression.getType();
2212        String JavaDoc typeName = BytecodeHelper.getClassInternalName(type);
2213        Expression sizeExpression = expression.getSizeExpression();
2214        if (sizeExpression != null) {
2215            // lets convert to an int
2216
visitAndAutobox(sizeExpression);
2217            asIntMethod.call(cv);
2218
2219            cv.visitTypeInsn(ANEWARRAY, typeName);
2220        }
2221        else {
2222            int size = expression.getExpressions().size();
2223            helper.pushConstant(size);
2224
2225            cv.visitTypeInsn(ANEWARRAY, typeName);
2226
2227            for (int i = 0; i < size; i++) {
2228                cv.visitInsn(DUP);
2229                helper.pushConstant(i);
2230                Expression elementExpression = expression.getExpression(i);
2231                if (elementExpression == null) {
2232                    ConstantExpression.NULL.visit(this);
2233                }
2234                else {
2235
2236                    if(!type.equals(elementExpression.getClass().getName())) {
2237                        visitCastExpression(new CastExpression(type, elementExpression));
2238                    }
2239                    else {
2240                        visitAndAutobox(elementExpression);
2241                    }
2242                }
2243                cv.visitInsn(AASTORE);
2244            }
2245        }
2246    }
2247
2248    public void visitListExpression(ListExpression expression) {
2249        int size = expression.getExpressions().size();
2250        helper.pushConstant(size);
2251
2252        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2253
2254        for (int i = 0; i < size; i++) {
2255            cv.visitInsn(DUP);
2256            helper.pushConstant(i);
2257            visitAndAutobox(expression.getExpression(i));
2258            cv.visitInsn(AASTORE);
2259        }
2260        createListMethod.call(cv);
2261    }
2262
2263    public void visitGStringExpression(GStringExpression expression) {
2264        int size = expression.getValues().size();
2265        helper.pushConstant(size);
2266
2267        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2268
2269        for (int i = 0; i < size; i++) {
2270            cv.visitInsn(DUP);
2271            helper.pushConstant(i);
2272            visitAndAutobox(expression.getValue(i));
2273            cv.visitInsn(AASTORE);
2274        }
2275
2276        int paramIdx = defineVariable(createVariableName("iterator"), "java.lang.Object", false).getIndex();
2277        cv.visitVarInsn(ASTORE, paramIdx);
2278
2279        ClassNode innerClass = createGStringClass(expression);
2280        addInnerClass(innerClass);
2281        String JavaDoc innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName());
2282
2283        cv.visitTypeInsn(NEW, innerClassinternalName);
2284        cv.visitInsn(DUP);
2285        cv.visitVarInsn(ALOAD, paramIdx);
2286
2287        cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V");
2288    }
2289
2290    // Implementation methods
2291
//-------------------------------------------------------------------------
2292
protected boolean addInnerClass(ClassNode innerClass) {
2293        innerClass.setModule(classNode.getModule());
2294        return innerClasses.add(innerClass);
2295    }
2296
2297    protected ClassNode createClosureClass(ClosureExpression expression) {
2298        ClassNode owner = getOutermostClass();
2299        boolean parentIsInnerClass = owner instanceof InnerClassNode;
2300        String JavaDoc outerClassName = owner.getName();
2301        String JavaDoc name = outerClassName + "$"
2302                + context.getNextClosureInnerName(owner, classNode, methodNode); // br added a more infomative name
2303
boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass();
2304        if (staticMethodOrInStaticClass) {
2305            outerClassName = "java.lang.Class";
2306        }
2307        Parameter[] parameters = expression.getParameters();
2308        if (parameters == null || parameters.length == 0) {
2309            // lets create a default 'it' parameter
2310
parameters = new Parameter[] { new Parameter("it")};
2311        }
2312
2313        Parameter[] localVariableParams = getClosureSharedVariables(expression);
2314
2315        InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, "groovy.lang.Closure"); // clsures are local inners and not public
2316
answer.setEnclosingMethod(this.methodNode);
2317        if (staticMethodOrInStaticClass) {
2318            answer.setStaticClass(true);
2319        }
2320        if (isInScriptBody()) {
2321            answer.setScriptBody(true);
2322        }
2323        MethodNode method =
2324            answer.addMethod("doCall", ACC_PUBLIC, "java.lang.Object", parameters, expression.getCode());
2325
2326        method.setLineNumber(expression.getLineNumber());
2327        method.setColumnNumber(expression.getColumnNumber());
2328
2329        VariableScope varScope = expression.getVariableScope();
2330        if (varScope == null) {
2331            throw new RuntimeException JavaDoc(
2332                "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
2333        }
2334        else {
2335            method.setVariableScope(varScope);
2336        }
2337        if (parameters.length > 1
2338            || (parameters.length == 1
2339                && parameters[0].getType() != null
2340                && !parameters[0].getType().equals("java.lang.Object"))) {
2341
2342            // lets add a typesafe call method
2343
answer.addMethod(
2344                "call",
2345                ACC_PUBLIC,
2346                "java.lang.Object",
2347                parameters,
2348                new ReturnStatement(
2349                    new MethodCallExpression(
2350                        VariableExpression.THIS_EXPRESSION,
2351                        "doCall",
2352                        new ArgumentListExpression(parameters))));
2353        }
2354
2355        FieldNode ownerField = answer.addField("owner", ACC_PRIVATE, outerClassName, null);
2356
2357        // lets make the constructor
2358
BlockStatement block = new BlockStatement();
2359        block.addStatement(
2360            new ExpressionStatement(
2361                new MethodCallExpression(
2362                    new VariableExpression("super"),
2363                    "<init>",
2364                    new VariableExpression("_outerInstance"))));
2365        block.addStatement(
2366            new ExpressionStatement(
2367                new BinaryExpression(
2368                    new FieldExpression(ownerField),
2369                    Token.newSymbol(Types.EQUAL, -1, -1),
2370                    new VariableExpression("_outerInstance"))));
2371
2372        // lets assign all the parameter fields from the outer context
2373
for (int i = 0; i < localVariableParams.length; i++) {
2374            Parameter param = localVariableParams[i];
2375            String JavaDoc paramName = param.getName();
2376            boolean holder = mutableVars.contains(paramName);
2377            Expression initialValue = null;
2378            String JavaDoc type = param.getType();
2379            FieldNode paramField = null;
2380            if (holder) {
2381                initialValue = new VariableExpression(paramName);
2382                type = Reference.class.getName();
2383                param.makeReference();
2384                paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue);
2385                paramField.setHolder(true);
2386                String JavaDoc realType = param.getRealType();
2387                String JavaDoc methodName = Verifier.capitalize(paramName);
2388
2389                // lets add a getter & setter
2390
Expression fieldExp = new FieldExpression(paramField);
2391                answer.addMethod(
2392                    "get" + methodName,
2393                    ACC_PUBLIC,
2394                    realType,
2395                    Parameter.EMPTY_ARRAY,
2396                    new ReturnStatement(fieldExp));
2397
2398                /*
2399                answer.addMethod(
2400                    "set" + methodName,
2401                    ACC_PUBLIC,
2402                    "void",
2403                    new Parameter[] { new Parameter(realType, "__value") },
2404                    new ExpressionStatement(
2405                        new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("__value"))));
2406                        */

2407            }
2408            else {
2409                PropertyNode propertyNode = answer.addProperty(paramName, ACC_PUBLIC, type, initialValue, null, null);
2410                paramField = propertyNode.getField();
2411                block.addStatement(
2412                    new ExpressionStatement(
2413                        new BinaryExpression(
2414                            new FieldExpression(paramField),
2415                            Token.newSymbol(Types.EQUAL, -1, -1),
2416                            new VariableExpression(paramName))));
2417            }
2418        }
2419
2420        Parameter[] params = new Parameter[2 + localVariableParams.length];
2421        params[0] = new Parameter(outerClassName, "_outerInstance");
2422        params[1] = new Parameter("java.lang.Object", "_delegate");
2423        System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
2424
2425        answer.addConstructor(ACC_PUBLIC, params, block);
2426        return answer;
2427    }
2428
2429    protected ClassNode getOutermostClass() {
2430        if (outermostClass == null) {
2431            outermostClass = classNode;
2432            while (outermostClass instanceof InnerClassNode) {
2433                outermostClass = outermostClass.getOuterClass();
2434            }
2435        }
2436        return outermostClass;
2437    }
2438
2439    protected ClassNode createGStringClass(GStringExpression expression) {
2440        ClassNode owner = classNode;
2441        if (owner instanceof InnerClassNode) {
2442            owner = owner.getOuterClass();
2443        }
2444        String JavaDoc outerClassName = owner.getName();
2445        String JavaDoc name = outerClassName + "$" + context.getNextInnerClassIdx();
2446        InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, GString.class.getName());
2447        answer.setEnclosingMethod(this.methodNode);
2448        FieldNode stringsField =
2449            answer.addField(
2450                "strings",
2451                ACC_PRIVATE /*| ACC_STATIC*/,
2452                "java.lang.String[]",
2453                new ArrayExpression("java.lang.String", expression.getStrings()));
2454        answer.addMethod(
2455            "getStrings",
2456            ACC_PUBLIC,
2457            "java.lang.String[]",
2458            Parameter.EMPTY_ARRAY,
2459            new ReturnStatement(new FieldExpression(stringsField)));
2460        // lets make the constructor
2461
BlockStatement block = new BlockStatement();
2462        block.addStatement(
2463            new ExpressionStatement(
2464                new MethodCallExpression(new VariableExpression("super"), "<init>", new VariableExpression("values"))));
2465        Parameter[] contructorParams = new Parameter[] { new Parameter("java.lang.Object[]", "values")};
2466        answer.addConstructor(ACC_PUBLIC, contructorParams, block);
2467        return answer;
2468    }
2469
2470    protected void doConvertAndCast(String JavaDoc type) {
2471        if (!type.equals("java.lang.Object")) {
2472            /** todo should probably support array coercions */
2473            if (!type.endsWith("[]") && isValidTypeForCast(type)) {
2474                visitClassExpression(new ClassExpression(type));
2475                asTypeMethod.call(cv);
2476            }
2477
2478            helper.doCast(type);
2479        }
2480    }
2481
2482    protected void evaluateLogicalOrExpression(BinaryExpression expression) {
2483        visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
2484        Label l0 = new Label();
2485        Label l2 = new Label();
2486        cv.visitJumpInsn(IFEQ, l0);
2487
2488        cv.visitLabel(l2);
2489
2490        visitConstantExpression(ConstantExpression.TRUE);
2491
2492        Label l1 = new Label();
2493        cv.visitJumpInsn(GOTO, l1);
2494        cv.visitLabel(l0);
2495
2496        visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
2497
2498        cv.visitJumpInsn(IFNE, l2);
2499
2500        visitConstantExpression(ConstantExpression.FALSE);
2501        cv.visitLabel(l1);
2502    }
2503
2504    protected void evaluateLogicalAndExpression(BinaryExpression expression) {
2505        visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
2506        Label l0 = new Label();
2507        cv.visitJumpInsn(IFEQ, l0);
2508
2509        visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
2510
2511        cv.visitJumpInsn(IFEQ, l0);
2512
2513        visitConstantExpression(ConstantExpression.TRUE);
2514
2515        Label l1 = new Label();
2516        cv.visitJumpInsn(GOTO, l1);
2517        cv.visitLabel(l0);
2518
2519        visitConstantExpression(ConstantExpression.FALSE);
2520
2521        cv.visitLabel(l1);
2522    }
2523
2524    protected void evaluateBinaryExpression(String JavaDoc method, BinaryExpression expression) {
2525        Expression leftExpression = expression.getLeftExpression();
2526        leftHandExpression = false;
2527        leftExpression.visit(this);
2528        cv.visitLdcInsn(method);
2529        leftHandExpression = false;
2530        new ArgumentListExpression(new Expression[] { expression.getRightExpression()}).visit(this);
2531        // expression.getRightExpression().visit(this);
2532
invokeMethodMethod.call(cv);
2533    }
2534
2535    protected void evaluateCompareTo(BinaryExpression expression) {
2536        Expression leftExpression = expression.getLeftExpression();
2537        leftHandExpression = false;
2538        leftExpression.visit(this);
2539        expression.getRightExpression().visit(this);
2540        compareToMethod.call(cv);
2541    }
2542
2543    protected void evaluateBinaryExpressionWithAsignment(String JavaDoc method, BinaryExpression expression) {
2544        Expression leftExpression = expression.getLeftExpression();
2545        if (leftExpression instanceof BinaryExpression) {
2546            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
2547            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
2548                // lets replace this assignment to a subscript operator with a
2549
// method call
2550
// e.g. x[5] += 10
2551
// -> (x, [], 5), =, x[5] + 10
2552
// -> methodCall(x, "putAt", [5, methodCall(x[5], "plus", 10)])
2553

2554                MethodCallExpression methodCall =
2555                    new MethodCallExpression(
2556                        expression.getLeftExpression(),
2557                        method,
2558                        new ArgumentListExpression(new Expression[] { expression.getRightExpression()}));
2559
2560                Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression());
2561
2562                visitMethodCallExpression(
2563                    new MethodCallExpression(
2564                        leftBinExpr.getLeftExpression(),
2565                        "putAt",
2566                        new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall })));
2567                cv.visitInsn(POP);
2568                return;
2569            }
2570        }
2571
2572        evaluateBinaryExpression(method, expression);
2573
2574        leftHandExpression = true;
2575        evaluateExpression(leftExpression);
2576        leftHandExpression = false;
2577    }
2578
2579    protected void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression expression) {
2580        Expression leftExpression = expression.getLeftExpression();
2581        /*
2582        if (isNonStaticField(leftExpression)) {
2583            cv.visitVarInsn(ALOAD, 0);
2584        }
2585        */

2586
2587        leftHandExpression = false;
2588
2589        evaluateExpression(leftExpression);
2590        leftHandExpression = false;
2591        evaluateExpression(expression.getRightExpression());
2592        // now lets invoke the method
2593
compareMethod.call(cv);
2594    }
2595
2596    protected void evaluateEqual(BinaryExpression expression) {
2597        Expression leftExpression = expression.getLeftExpression();
2598        if (leftExpression instanceof BinaryExpression) {
2599            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
2600            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
2601                // lets replace this assignment to a subscript operator with a
2602
// method call
2603
// e.g. x[5] = 10
2604
// -> (x, [], 5), =, 10
2605
// -> methodCall(x, "putAt", [5, 10])
2606
visitMethodCallExpression(
2607                    new MethodCallExpression(
2608                        leftBinExpr.getLeftExpression(),
2609                        "putAt",
2610                        new ArgumentListExpression(
2611                            new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()})));
2612                cv.visitInsn(POP);
2613                return;
2614            }
2615        }
2616        // br we'll load this pointer later right where we really need it
2617

2618        // lets evaluate the RHS then hopefully the LHS will be a field
2619
leftHandExpression = false;
2620        Expression rightExpression = expression.getRightExpression();
2621
2622        String JavaDoc type = getLHSType(leftExpression);
2623        if (type != null) {
2624            //System.out.println("### expression: " + leftExpression);
2625
//System.out.println("### type: " + type);
2626

2627            // lets not cast for primitive types as we handle these in field setting etc
2628
if (BytecodeHelper.isPrimitiveType(type)) {
2629                rightExpression.visit(this);
2630            }
2631            else {
2632                visitCastExpression(new CastExpression(type, rightExpression));
2633            }
2634        }
2635        else {
2636            visitAndAutobox(rightExpression);
2637        }
2638
2639        leftHandExpression = true;
2640        leftExpression.visit(this);
2641        leftHandExpression = false;
2642    }
2643
2644    /**
2645     * Deduces the type name required for some casting
2646     *
2647     * @return the type of the given (LHS) expression or null if it is java.lang.Object or it cannot be deduced
2648     */

2649    protected String JavaDoc getLHSType(Expression leftExpression) {
2650        if (leftExpression instanceof VariableExpression) {
2651            VariableExpression varExp = (VariableExpression) leftExpression;
2652            String JavaDoc type = varExp.getType();
2653            if (isValidTypeForCast(type)) {
2654                return type;
2655            }
2656            String JavaDoc variableName = varExp.getVariable();
2657            Variable variable = (Variable) variableStack.get(variableName);
2658            if (variable != null) {
2659                if (variable.isHolder() || variable.isProperty()) {
2660                    return null;
2661                }
2662                type = variable.getTypeName();
2663                if (isValidTypeForCast(type)) {
2664                    return type;
2665                }
2666            }
2667            else {
2668                FieldNode field = classNode.getField(variableName);
2669                if (field == null) {
2670                    field = classNode.getOuterField(variableName);
2671                }
2672                if (field != null) {
2673                    type = field.getType();
2674                    if (!field.isHolder() && isValidTypeForCast(type)) {
2675                        return type;
2676                    }
2677                }
2678            }
2679        }
2680        return null;
2681    }
2682
2683    protected boolean isValidTypeForCast(String JavaDoc type) {
2684        return type != null && !type.equals("java.lang.Object") && !type.equals("groovy.lang.Reference") && !BytecodeHelper.isPrimitiveType(type);
2685    }
2686
2687    protected void visitAndAutobox(Expression expression) {
2688        expression.visit(this);
2689
2690        if (comparisonExpression(expression)) {
2691            Label l0 = new Label();
2692            cv.visitJumpInsn(IFEQ, l0);
2693            cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
2694            Label l1 = new Label();
2695            cv.visitJumpInsn(GOTO, l1);
2696            cv.visitLabel(l0);
2697            cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
2698            cv.visitLabel(l1);
2699        }
2700    }
2701
2702    protected void evaluatePrefixMethod(String JavaDoc method, Expression expression) {
2703        if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) {
2704            cv.visitVarInsn(ALOAD, 0);
2705        }
2706        expression.visit(this);
2707        cv.visitLdcInsn(method);
2708        invokeNoArgumentsMethod.call(cv);
2709
2710        leftHandExpression = true;
2711        expression.visit(this);
2712        leftHandExpression = false;
2713        expression.visit(this);
2714    }
2715
2716    protected void evaluatePostfixMethod(String JavaDoc method, Expression expression) {
2717// if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) {
2718
// cv.visitVarInsn(ALOAD, 0); // br again, loading this pointer is moved to staying close to variable
2719
// }
2720
leftHandExpression = false;
2721        expression.visit(this);
2722
2723        int tempIdx = defineVariable(createVariableName("postfix"), "java.lang.Object", false).getIndex();
2724        cv.visitVarInsn(ASTORE, tempIdx);
2725        cv.visitVarInsn(ALOAD, tempIdx);
2726
2727        cv.visitLdcInsn(method);
2728        invokeNoArgumentsMethod.call(cv);
2729
2730        leftHandExpression = true;
2731        expression.visit(this);
2732        leftHandExpression = false;
2733
2734        cv.visitVarInsn(ALOAD, tempIdx);
2735    }
2736
2737    protected boolean isHolderVariable(Expression expression) {
2738        if (expression instanceof FieldExpression) {
2739            FieldExpression fieldExp = (FieldExpression) expression;
2740            return fieldExp.getField().isHolder();
2741        }
2742        if (expression instanceof VariableExpression) {
2743            VariableExpression varExp = (VariableExpression) expression;
2744            Variable variable = (Variable) variableStack.get(varExp.getVariable());
2745            if (variable != null) {
2746                return variable.isHolder();
2747            }
2748            FieldNode field = classNode.getField(varExp.getVariable());
2749            if (field != null) {
2750                return field.isHolder();
2751            }
2752        }
2753        return false;
2754    }
2755
2756    protected void evaluateInstanceof(BinaryExpression expression) {
2757        expression.getLeftExpression().visit(this);
2758        Expression rightExp = expression.getRightExpression();
2759        String JavaDoc className = null;
2760        if (rightExp instanceof ClassExpression) {
2761            ClassExpression classExp = (ClassExpression) rightExp;
2762            className = classExp.getType();
2763        }
2764        else {
2765            throw new RuntimeException JavaDoc(
2766                "Right hand side of the instanceof keyworld must be a class name, not: " + rightExp);
2767        }
2768        className = checkValidType(className, expression, "Must be a valid type name for an instanceof statement");
2769        String JavaDoc classInternalName = BytecodeHelper.getClassInternalName(className);
2770        cv.visitTypeInsn(INSTANCEOF, classInternalName);
2771    }
2772
2773    /**
2774     * @return true if the given argument expression requires the stack, in
2775     * which case the arguments are evaluated first, stored in the
2776     * variable stack and then reloaded to make a method call
2777     */

2778    protected boolean argumentsUseStack(Expression arguments) {
2779        return arguments instanceof TupleExpression || arguments instanceof ClosureExpression;
2780    }
2781
2782    /**
2783     * @return true if the given expression represents a non-static field
2784     */

2785    protected boolean isNonStaticField(Expression expression) {
2786        FieldNode field = null;
2787        if (expression instanceof VariableExpression) {
2788            VariableExpression varExp = (VariableExpression) expression;
2789            field = classNode.getField(varExp.getVariable());
2790        }
2791        else if (expression instanceof FieldExpression) {
2792            FieldExpression fieldExp = (FieldExpression) expression;
2793            field = classNode.getField(fieldExp.getFieldName());
2794        }
2795        else if (expression instanceof PropertyExpression) {
2796            PropertyExpression fieldExp = (PropertyExpression) expression;
2797            field = classNode.getField(fieldExp.getProperty());
2798        }
2799        if (field != null) {
2800            return !field.isStatic();
2801        }
2802        return false;
2803    }
2804
2805    protected boolean isThisExpression(Expression expression) {
2806        if (expression instanceof VariableExpression) {
2807            VariableExpression varExp = (VariableExpression) expression;
2808            return varExp.getVariable().equals("this");
2809        }
2810        return false;
2811    }
2812
2813    /**
2814     * For assignment expressions, return a safe expression for the LHS we can use
2815     * to return the value
2816     */

2817    protected Expression createReturnLHSExpression(Expression expression) {
2818        if (expression instanceof BinaryExpression) {
2819            BinaryExpression binExpr = (BinaryExpression) expression;
2820            if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) {
2821                return createReusableExpression(binExpr.getLeftExpression());
2822            }
2823        }
2824        return null;
2825    }
2826
2827    protected Expression createReusableExpression(Expression expression) {
2828        ExpressionTransformer transformer = new ExpressionTransformer() {
2829            public Expression transform(Expression expression) {
2830                if (expression instanceof PostfixExpression) {
2831                    PostfixExpression postfixExp = (PostfixExpression) expression;
2832                    return postfixExp.getExpression();
2833                }
2834                else if (expression instanceof PrefixExpression) {
2835                    PrefixExpression prefixExp = (PrefixExpression) expression;
2836                    return prefixExp.getExpression();
2837                }
2838                return expression;
2839            }
2840        };
2841
2842        // could just be a postfix / prefix expression or nested inside some other expression
2843
return transformer.transform(expression.transformExpression(transformer));
2844    }
2845
2846    protected boolean comparisonExpression(Expression expression) {
2847        if (expression instanceof BinaryExpression) {
2848            BinaryExpression binExpr = (BinaryExpression) expression;
2849            switch (binExpr.getOperation().getType()) {
2850                case Types.COMPARE_EQUAL :
2851                case Types.MATCH_REGEX :
2852                case Types.COMPARE_GREATER_THAN :
2853                case Types.COMPARE_GREATER_THAN_EQUAL :
2854                case Types.COMPARE_LESS_THAN :
2855                case Types.COMPARE_LESS_THAN_EQUAL :
2856                case Types.COMPARE_IDENTICAL :
2857                case Types.COMPARE_NOT_EQUAL :
2858                case Types.KEYWORD_INSTANCEOF :
2859                    return true;
2860            }
2861        }
2862        else if (expression instanceof BooleanExpression) {
2863            return true;
2864        }
2865        return false;
2866    }
2867
2868    protected void onLineNumber(ASTNode statement) {
2869        int number = statement.getLineNumber();
2870        if (number >= 0 && cv != null) {
2871            Label l = new Label();
2872            cv.visitLabel(l);
2873            cv.visitLineNumber(number, l);
2874        }
2875    }
2876
2877    protected VariableScope getVariableScope() {
2878        if (variableScope == null) {
2879            if (methodNode != null) {
2880                // if we're a closure method we'll have our variable scope already created
2881
variableScope = methodNode.getVariableScope();
2882                if (variableScope == null) {
2883                    variableScope = new VariableScope();
2884                    methodNode.setVariableScope(variableScope);
2885                    VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
2886                    visitor.setParameters(methodNode.getParameters());
2887                    Statement code = methodNode.getCode();
2888                    if (code != null) {
2889                        code.visit(visitor);
2890                    }
2891                }
2892                addFieldsToVisitor(variableScope);
2893            }
2894            else if (constructorNode != null) {
2895                variableScope = new VariableScope();
2896                constructorNode.setVariableScope(variableScope);
2897                VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
2898                visitor.setParameters(constructorNode.getParameters());
2899                Statement code = constructorNode.getCode();
2900                if (code != null) {
2901                    code.visit(visitor);
2902                }
2903                addFieldsToVisitor(variableScope);
2904            }
2905            else {
2906                throw new RuntimeException JavaDoc("Can't create a variable scope outside of a method or constructor");
2907            }
2908        }
2909        return variableScope;
2910    }
2911
2912    /**
2913     * @return a list of parameters for each local variable which needs to be
2914     * passed into a closure
2915     */

2916    protected Parameter[] getClosureSharedVariables(ClosureExpression expression) {
2917        List JavaDoc vars = new ArrayList JavaDoc();
2918
2919        //
2920
// First up, get the scopes for outside and inside the closure.
2921
// The inner scope must cover all nested closures, as well, as
2922
// everything that will be needed must be imported.
2923

2924        VariableScope outerScope = getVariableScope().createRecursiveParentScope();
2925        VariableScope innerScope = expression.getVariableScope();
2926        if (innerScope == null) {
2927            System.out.println(
2928                "No variable scope for: " + expression + " method: " + methodNode + " constructor: " + constructorNode);
2929            innerScope = new VariableScope(getVariableScope());
2930        }
2931        else {
2932            innerScope = innerScope.createRecursiveChildScope();
2933        }
2934
2935
2936        //
2937
// DeclaredVariables include any name that was assigned to within
2938
// the scope. ReferencedVariables include any name that was read
2939
// from within the scope. We get the sets from each and must piece
2940
// together the stack variable import list for the closure. Note
2941
// that we don't worry about field variables here, as we don't have
2942
// to do anything special with them. Stack variables, on the other
2943
// hand, have to be wrapped up in References for use.
2944

2945        Set JavaDoc outerDecls = outerScope.getDeclaredVariables();
2946        Set JavaDoc outerRefs = outerScope.getReferencedVariables();
2947        Set JavaDoc innerDecls = innerScope.getDeclaredVariables();
2948        Set JavaDoc innerRefs = innerScope.getReferencedVariables();
2949
2950
2951        //
2952
// So, we care about any name referenced in the closure UNLESS:
2953
// 1) it's not declared in the outer context;
2954
// 2) it's a parameter;
2955
// 3) it's a field in the context class that isn't overridden
2956
// by a stack variable in the outer context.
2957
//
2958
// BUG: We don't actually have the necessary information to do
2959
// this right! The outer declarations don't distinguish
2960
// between assignments and variable declarations. Therefore
2961
// we can't tell when field variables have been overridden
2962
// by stack variables in the outer context. This must
2963
// be fixed!
2964

2965        Set JavaDoc varSet = new HashSet JavaDoc();
2966        for (Iterator JavaDoc iter = innerRefs.iterator(); iter.hasNext();) {
2967            String JavaDoc var = (String JavaDoc) iter.next();
2968            // lets not pass in fields from the most-outer class, but pass in values from an outer closure
2969
if (outerDecls.contains(var) && (isNotFieldOfOutermostClass(var))) {
2970                String JavaDoc type = getVariableType(var);
2971                vars.add(new Parameter(type, var));
2972                varSet.add(var);
2973            }
2974        }
2975        for (Iterator JavaDoc iter = outerRefs.iterator(); iter.hasNext();) {
2976            String JavaDoc var = (String JavaDoc) iter.next();
2977            // lets not pass in fields from the most-outer class, but pass in values from an outer closure
2978
if (innerDecls.contains(var) && (isNotFieldOfOutermostClass(var)) && !varSet.contains(var)) {
2979                String JavaDoc type = getVariableType(var);
2980                vars.add(new Parameter(type, var));
2981            }
2982        }
2983
2984
2985        Parameter[] answer = new Parameter[vars.size()];
2986        vars.toArray(answer);
2987        return answer;
2988    }
2989
2990    protected boolean isNotFieldOfOutermostClass(String JavaDoc var) {
2991        //return classNode.getField(var) == null || isInnerClass();
2992
return getOutermostClass().getField(var) == null;
2993    }
2994
2995    protected void findMutableVariables() {
2996        /*
2997        VariableScopeCodeVisitor outerVisitor = new VariableScopeCodeVisitor(true);
2998        node.getCode().visit(outerVisitor);
2999
3000        addFieldsToVisitor(outerVisitor);
3001
3002        VariableScopeCodeVisitor innerVisitor = outerVisitor.getClosureVisitor();
3003        */

3004        VariableScope outerScope = getVariableScope();
3005
3006        // lets create a scope concatenating all the closure expressions
3007
VariableScope innerScope = outerScope.createCompositeChildScope();
3008
3009        Set JavaDoc outerDecls = outerScope.getDeclaredVariables();
3010        Set JavaDoc outerRefs = outerScope.getReferencedVariables();
3011        Set JavaDoc innerDecls = innerScope.getDeclaredVariables();
3012        Set JavaDoc innerRefs = innerScope.getReferencedVariables();
3013
3014        mutableVars.clear();
3015
3016        for (Iterator JavaDoc iter = innerDecls.iterator(); iter.hasNext();) {
3017            String JavaDoc var = (String JavaDoc) iter.next();
3018            if ((outerDecls.contains(var) || outerRefs.contains(var)) && classNode.getField(var) == null) {
3019                mutableVars.add(var);
3020            }
3021        }
3022
3023        // we may call the closure twice and modify the variable in the outer scope
3024
// so for now lets assume that all variables are mutable
3025
for (Iterator JavaDoc iter = innerRefs.iterator(); iter.hasNext();) {
3026            String JavaDoc var = (String JavaDoc) iter.next();
3027            if (outerDecls.contains(var) && classNode.getField(var) == null) {
3028                mutableVars.add(var);
3029            }
3030        }
3031
3032        // System.out.println();
3033
// System.out.println("method: " + methodNode + " classNode: " + classNode);
3034
// System.out.println("child scopes: " + outerScope.getChildren());
3035
// System.out.println("outerDecls: " + outerDecls);
3036
// System.out.println("outerRefs: " + outerRefs);
3037
// System.out.println("innerDecls: " + innerDecls);
3038
// System.out.println("innerRefs: " + innerRefs);
3039
}
3040
3041    protected void addFieldsToVisitor(VariableScope scope) {
3042        for (Iterator JavaDoc iter = classNode.getFields().iterator(); iter.hasNext();) {
3043            FieldNode field = (FieldNode) iter.next();
3044            String JavaDoc name = field.getName();
3045
3046            scope.getDeclaredVariables().add(name);
3047            scope.getReferencedVariables().add(name);
3048        }
3049    }
3050
3051    private boolean isInnerClass() {
3052        return classNode instanceof InnerClassNode;
3053    }
3054
3055    protected String JavaDoc getVariableType(String JavaDoc name) {
3056        Variable variable = (Variable) variableStack.get(name);
3057        if (variable != null) {
3058            return variable.getTypeName();
3059        }
3060        return null;
3061    }
3062
3063    protected void resetVariableStack(Parameter[] parameters) {
3064        lastVariableIndex = -1;
3065        variableStack.clear();
3066
3067        scope = null;
3068        pushBlockScope();
3069
3070        // lets push this onto the stack
3071
definingParameters = true;
3072        if (!isStaticMethod()) {
3073            defineVariable("this", classNode.getName()).getIndex();
3074        } // now lets create indices for the parameteres
3075
for (int i = 0; i < parameters.length; i++) {
3076            Parameter parameter = parameters[i];
3077            String JavaDoc type = parameter.getType();
3078            int idx = defineVariable(parameter.getName(), type).getIndex();
3079            if (BytecodeHelper.isPrimitiveType(type)) {
3080                helper.load(type, idx);
3081                helper.box(type);
3082                cv.visitVarInsn(ASTORE, idx);
3083            }
3084        }
3085        definingParameters = false;
3086    }
3087
3088    protected void popScope() {
3089        int lastID = scope.getLastVariableIndex();
3090
3091        List JavaDoc removeKeys = new ArrayList JavaDoc();
3092        for (Iterator JavaDoc iter = variableStack.entrySet().iterator(); iter.hasNext();) {
3093            Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
3094            String JavaDoc name = (String JavaDoc) entry.getKey();
3095            Variable value = (Variable) entry.getValue();
3096            if (value.getIndex() >= lastID) {
3097                removeKeys.add(name);
3098            }
3099        }
3100        for (Iterator JavaDoc iter = removeKeys.iterator(); iter.hasNext();) {
3101            variableStack.remove(iter.next());
3102        }
3103        /*
3104               */

3105        scope = scope.getParent();
3106    }
3107
3108
3109    protected void pushBlockScope() {
3110        pushBlockScope(true, true);
3111    }
3112
3113    protected void pushBlockScope(boolean canContinue, boolean canBreak) {
3114        scope = new BlockScope(scope);
3115        scope.setContinueLabel(canContinue ? new Label() : null);
3116        scope.setBreakLabel(canBreak? new Label() : null);
3117        scope.setLastVariableIndex(getNextVariableID());
3118    }
3119
3120    /**
3121     * Defines the given variable in scope and assigns it to the stack
3122     */

3123    protected Variable defineVariable(String JavaDoc name, String JavaDoc type) {
3124        return defineVariable(name, type, true);
3125    }
3126
3127    protected Variable defineVariable(String JavaDoc name, String JavaDoc type, boolean define) {
3128        return defineVariable(name, new Type(type), define);
3129    }
3130
3131    private Variable defineVariable(String JavaDoc name, Type type, boolean define) {
3132        Variable answer = (Variable) variableStack.get(name);
3133        if (answer == null) {
3134            lastVariableIndex = getNextVariableID();
3135            answer = new Variable(lastVariableIndex, type, name);
3136            if (mutableVars.contains(name)) {
3137                answer.setHolder(true);
3138            }
3139            variableStack.put(name, answer);
3140            if (define) {
3141                if (definingParameters) {
3142                    if (answer.isHolder()) {
3143                        cv.visitTypeInsn(NEW, "groovy/lang/Reference"); // br todo to associate a label with the variable
3144
cv.visitInsn(DUP);
3145                        cv.visitVarInsn(ALOAD, lastVariableIndex);
3146                        cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V"); // br wrap the param in a ref
3147
cv.visitVarInsn(ASTORE, lastVariableIndex);
3148                    }
3149                }
3150                else {
3151                    // using new variable inside a comparison expression
3152
// so lets initialize it too
3153
if (answer.isHolder() && !isInScriptBody()) { // br doesn't seem to need different treatment, in script or not
3154
//cv.visitVarInsn(ASTORE, lastVariableIndex + 1); // I might need this to set the reference value
3155

3156                        cv.visitTypeInsn(NEW, "groovy/lang/Reference");
3157                        cv.visitInsn(DUP);
3158                        cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "()V");
3159
3160                        cv.visitVarInsn(ASTORE, lastVariableIndex);
3161                        //cv.visitVarInsn(ALOAD, idx + 1);
3162
}
3163                    else {
3164                        if (!leftHandExpression) {
3165                            cv.visitInsn(ACONST_NULL);
3166                            cv.visitVarInsn(ASTORE, lastVariableIndex);
3167                        }
3168                    }
3169                }
3170            }
3171        }
3172        return answer;
3173    }
3174
3175    private int getNextVariableID() {
3176        return Math.max(lastVariableIndex + 1, variableStack.size());
3177    }
3178
3179    /** @return true if the given name is a local variable or a field */
3180    protected boolean isFieldOrVariable(String JavaDoc name) {
3181        return variableStack.containsKey(name) || classNode.getField(name) != null;
3182    }
3183
3184    protected Type checkValidType(Type type, ASTNode node, String JavaDoc message) {
3185        if (type.isDynamic()) {
3186            return type;
3187        }
3188        String JavaDoc name = checkValidType(type.getName(), node, message);
3189        if (type.getName().equals(name)) {
3190            return type;
3191        }
3192        return new Type(name);
3193    }
3194
3195    protected String JavaDoc checkValidType(String JavaDoc type, ASTNode node, String JavaDoc message) {
3196        if (type.endsWith("[]")) {
3197            String JavaDoc postfix = "[]";
3198            String JavaDoc prefix = type.substring(0, type.length() - 2);
3199            return checkValidType(prefix, node, message) + postfix;
3200        }
3201        int idx = type.indexOf('$');
3202        if (idx > 0) {
3203            String JavaDoc postfix = type.substring(idx);
3204            String JavaDoc prefix = type.substring(0, idx);
3205            return checkValidType(prefix, node, message) + postfix;
3206        }
3207        if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) {
3208            return type;
3209        }
3210        String JavaDoc original = type;
3211        type = resolveClassName(type);
3212        if (type != null) {
3213            return type;
3214        }
3215        throw new MissingClassException(original, node, message + " for class: " + classNode.getName());
3216    }
3217
3218    protected String JavaDoc resolveClassName(String JavaDoc type) {
3219        return classNode.resolveClassName(type);
3220    }
3221
3222    protected String JavaDoc createVariableName(String JavaDoc type) {
3223        return "__" + type + (++tempVariableNameCounter);
3224    }
3225
3226    /**
3227     * @return if the type of the expression can be determined at compile time
3228     * then this method returns the type - otherwise null
3229     */

3230    protected String JavaDoc getExpressionType(Expression expression) {
3231        if (comparisonExpression(expression)) {
3232            return "boolean";
3233        }
3234        if (expression instanceof VariableExpression) {
3235            VariableExpression varExpr = (VariableExpression) expression;
3236            Variable variable = (Variable) variableStack.get(varExpr.getVariable());
3237            if (variable != null && !variable.isHolder()) {
3238                Type type = variable.getType();
3239                if (! type.isDynamic()) {
3240                    return type.getName();
3241                }
3242            }
3243        }
3244        return null;
3245    }
3246
3247    /**
3248     * @return true if the value is an Integer, a Float, a Long, a Double or a
3249     * String .
3250     */

3251    protected boolean isPrimitiveFieldType(String JavaDoc type) {
3252        return type.equals("java.lang.String")
3253            || type.equals("java.lang.Integer")
3254            || type.equals("java.lang.Double")
3255            || type.equals("java.lang.Long")
3256            || type.equals("java.lang.Float");
3257    }
3258
3259    protected boolean isInClosureConstructor() {
3260        return constructorNode != null
3261            && classNode.getOuterClass() != null
3262            && classNode.getSuperClass().equals(Closure.class.getName());
3263    }
3264
3265    protected boolean isStaticMethod() {
3266        if (methodNode == null) { // we're in a constructor
3267
return false;
3268        }
3269        return methodNode.isStatic();
3270    }
3271
3272    /**
3273     * @return loads the given type name
3274     */

3275    protected Class JavaDoc loadClass(String JavaDoc name) {
3276        try {
3277            CompileUnit compileUnit = getCompileUnit();
3278            if (compileUnit != null) {
3279                return compileUnit.loadClass(name);
3280            }
3281            else {
3282                throw new ClassGeneratorException("Could not load class: " + name);
3283            }
3284        }
3285        catch (ClassNotFoundException JavaDoc e) {
3286            throw new ClassGeneratorException("Could not load class: " + name + " reason: " + e, e);
3287        }
3288    }
3289
3290    protected CompileUnit getCompileUnit() {
3291        CompileUnit answer = classNode.getCompileUnit();
3292        if (answer == null) {
3293            answer = context.getCompileUnit();
3294        }
3295        return answer;
3296    }
3297}
3298
Popular Tags