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