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.7 $
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 = false;
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 if (text != null && text.endsWith(".class")) {
2581 text = text.substring(0, text.length() - 6);
2582 }
2583 try {
2584 return resolveClassName(text);
2585 }
2586 catch (Exception e) {
2587 return null;
2588 }
2589 }
2590
2591 public void visitFieldExpression(FieldExpression expression) {
2592 FieldNode field = expression.getField();
2593
2594
2595 if (field.isStatic()) {
2596 if (leftHandExpression) {
2597 storeStaticField(expression);
2598 }
2599 else {
2600 loadStaticField(expression);
2601 }
2602 } else {
2603 if (leftHandExpression) {
2604 storeThisInstanceField(expression);
2605 }
2606 else {
2607 loadInstanceField(expression);
2608 }
2609 }
2610 }
2611
2612 /***
2613 *
2614 * @param fldExp
2615 */
2616 public void loadStaticField(FieldExpression fldExp) {
2617 FieldNode field = fldExp.getField();
2618 boolean holder = field.isHolder() && !isInClosureConstructor();
2619 String type = field.getType();
2620
2621 String ownerName = (field.getOwner().equals(classNode.getName()))
2622 ? internalClassName
2623 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2624 if (holder) {
2625 cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
2626 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
2627 }
2628 else {
2629 cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
2630 if (BytecodeHelper.isPrimitiveType(type)) {
2631 helper.box(type);
2632 } else {
2633 }
2634 }
2635 }
2636
2637 /***
2638 * RHS instance field. should move most of the code in the BytecodeHelper
2639 * @param fldExp
2640 */
2641 public void loadInstanceField(FieldExpression fldExp) {
2642 FieldNode field = fldExp.getField();
2643 boolean holder = field.isHolder() && !isInClosureConstructor();
2644 String type = field.getType();
2645 String ownerName = (field.getOwner().equals(classNode.getName()))
2646 ? internalClassName
2647 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2648
2649 cv.visitVarInsn(ALOAD, 0);
2650 cv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
2651
2652 if (holder) {
2653 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
2654 } else {
2655 if (BytecodeHelper.isPrimitiveType(type)) {
2656 helper.box(type);
2657 } else {
2658 }
2659 }
2660 }
2661
2662 public void storeThisInstanceField(FieldExpression expression) {
2663 FieldNode field = expression.getField();
2664
2665 boolean holder = field.isHolder() && !isInClosureConstructor();
2666 String type = field.getType();
2667
2668 String ownerName = (field.getOwner().equals(classNode.getName())) ?
2669 internalClassName : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2670 if (holder) {
2671 Variable tv = visitASTOREInTemp(field.getName());
2672 int tempIndex = tv.getIndex();
2673 cv.visitVarInsn(ALOAD, 0);
2674 cv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
2675 cv.visitVarInsn(ALOAD, tempIndex);
2676 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
2677 removeVar(tv);
2678 }
2679 else {
2680 if (isInClosureConstructor()) {
2681 helper.doCast(type);
2682 }
2683 else {
2684 if (ENABLE_EARLY_BINDING) {
2685 helper.doCast(type);
2686 }
2687 else {
2688
2689 doConvertAndCast(type);
2690 }
2691 }
2692
2693 Variable tmpVar = defineVariable(createVariableName(field.getName()), field.getType(), false);
2694
2695
2696 helper.store(tmpVar, MARK_START);
2697 helper.loadThis();
2698 helper.load(tmpVar);
2699 helper.putField(field, ownerName);
2700
2701
2702 removeVar(tmpVar);
2703 }
2704 }
2705
2706
2707 public void storeStaticField(FieldExpression expression) {
2708 FieldNode field = expression.getField();
2709
2710 boolean holder = field.isHolder() && !isInClosureConstructor();
2711
2712 String type = field.getType();
2713
2714 String ownerName = (field.getOwner().equals(classNode.getName()))
2715 ? internalClassName
2716 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner()));
2717 if (holder) {
2718 Variable tv = visitASTOREInTemp(field.getName());
2719 int tempIndex = tv.getIndex();
2720 cv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
2721 cv.visitVarInsn(ALOAD, tempIndex);
2722 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
2723 removeVar(tv);
2724 }
2725 else {
2726 if (isInClosureConstructor()) {
2727 helper.doCast(type);
2728 }
2729 else {
2730 if (ENABLE_EARLY_BINDING) {
2731 helper.doCast(type);
2732 }
2733 else {
2734
2735
2736
2737 helper.doCast(type);
2738 }
2739 }
2740 cv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
2741 }
2742 }
2743
2744 protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) {
2745 FieldNode field = expression.getField();
2746 boolean isStatic = field.isStatic();
2747
2748 Variable fieldTemp = defineVariable(createVariableName(field.getName()), "java.lang.Object", false);
2749 int valueIdx = fieldTemp.getIndex();
2750
2751 if (leftHandExpression && first) {
2752 cv.visitVarInsn(ASTORE, valueIdx);
2753 visitVariableStartLabel(fieldTemp);
2754 }
2755
2756 if (steps > 1 || !isStatic) {
2757 cv.visitVarInsn(ALOAD, 0);
2758 cv.visitFieldInsn(
2759 GETFIELD,
2760 internalClassName,
2761 "owner",
2762 BytecodeHelper.getTypeDescription(outerClassNode.getName()));
2763 }
2764
2765 if( steps == 1 ) {
2766 int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD);
2767 String ownerName = BytecodeHelper.getClassInternalName(outerClassNode.getName());
2768
2769 if (leftHandExpression) {
2770 cv.visitVarInsn(ALOAD, valueIdx);
2771 boolean holder = field.isHolder() && !isInClosureConstructor();
2772 if ( !holder) {
2773 doConvertAndCast(field.getType());
2774 }
2775 }
2776 cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
2777 if (!leftHandExpression) {
2778 if (BytecodeHelper.isPrimitiveType(field.getType())) {
2779 helper.box(field.getType());
2780 }
2781 }
2782 }
2783
2784 else {
2785 visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false );
2786 }
2787 }
2788
2789
2790
2791 /***
2792 * Visits a bare (unqualified) variable expression.
2793 */
2794
2795 public void visitVariableExpression(VariableExpression expression) {
2796
2797 String variableName = expression.getVariable();
2798
2799
2800
2801
2802
2803
2804
2805 if (isStaticMethod() && variableName.equals("this")) {
2806 visitClassExpression(new ClassExpression(classNode.getName()));
2807 return;
2808 }
2809
2810
2811
2812
2813 if (variableName.equals("super")) {
2814 visitClassExpression(new ClassExpression(classNode.getSuperClass()));
2815 return;
2816 }
2817
2818
2819
2820
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 boolean handled = false;
2849 Variable variable = (Variable)variableStack.get( variableName );
2850
2851 if( variable != null ) {
2852
2853 if( variable.isProperty() ) {
2854 processPropertyVariable(variable );
2855 }
2856 else {
2857 if (ENABLE_EARLY_BINDING && expression.isTypeResolved() && leftHandExpression) {
2858
2859 String typeName = expression.getType();
2860 Type varOldType = variable.getType();
2861 if (varOldType.isDynamic()) {
2862 variable.setType(new Type(typeName, true));
2863 }
2864 else if (!varOldType.getName().equals(typeName)){
2865 new GroovyRuntimeException("VariableExpression data type conflicts with the existing variable. "
2866 + "[" + expression.getLineNumber() + ":" + expression.getColumnNumber() + "]");
2867 }
2868 }
2869 processStackVariable(variable );
2870 }
2871
2872 handled = true;
2873 } else {
2874
2875
2876
2877 int steps = 0;
2878 ClassNode currentClassNode = classNode;
2879 FieldNode field = null;
2880
2881 do {
2882 if( (field = currentClassNode.getField(variableName)) != null ) {
2883 if (methodNode == null || !methodNode.isStatic() || field.isStatic() )
2884 break;
2885 }
2886 steps++;
2887
2888 } while( (currentClassNode = currentClassNode.getOuterClass()) != null );
2889
2890 if( field != null ) {
2891 processFieldAccess( variableName, field, steps );
2892 handled = true;
2893 }
2894 }
2895
2896
2897
2898 if (!handled && !variableName.equals("this")) {
2899 String className = resolveClassName(variableName);
2900 if (className != null) {
2901 if (leftHandExpression) {
2902 throwException("Cannot use a class expression on the left hand side of an assignment");
2903 }
2904 visitClassExpression(new ClassExpression(className));
2905 return;
2906 }
2907 }
2908
2909
2910
2911
2912
2913
2914
2915
2916 if( !handled ) {
2917 String variableType = expression.getType();
2918 variable = defineVariable( variableName, variableType );
2919
2920 if (leftHandExpression && expression.isDynamic()) {
2921 variable.setDynamic(true);
2922 }
2923 else {
2924 variable.setDynamic(false);
2925 }
2926
2927 if( isInScriptBody() || !leftHandExpression ) {
2928 variable.setProperty( true );
2929 processPropertyVariable(variable );
2930 }
2931 else {
2932 processStackVariable(variable );
2933 }
2934 }
2935 }
2936
2937
2938 protected void processStackVariable(Variable variable ) {
2939 boolean holder = variable.isHolder() && !passingClosureParams;
2940
2941 if( leftHandExpression ) {
2942 helper.storeVar(variable, holder);
2943 }
2944 else {
2945 helper.loadVar(variable, holder);
2946 }
2947 if (ASM_DEBUG) {
2948 helper.mark("var: " + variable.getName());
2949 }
2950 }
2951
2952 private void visitVariableStartLabel(Variable variable) {
2953 if (CREATE_DEBUG_INFO) {
2954 Label l = variable.getStartLabel();
2955 if (l != null) {
2956 cv.visitLabel(l);
2957 } else {
2958 System.out.println("start label == null! what to do about this?");
2959 }
2960 }
2961 }
2962
2963 protected void processPropertyVariable(Variable variable ) {
2964 String name = variable.getName();
2965 if (variable.isHolder() && passingClosureParams && isInScriptBody() ) {
2966
2967 cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference");
2968 cv.visitInsn(DUP);
2969
2970 loadThisOrOwner();
2971 cv.visitLdcInsn(name);
2972
2973 cv.visitMethodInsn(
2974 INVOKESPECIAL,
2975 "org/codehaus/groovy/runtime/ScriptReference",
2976 "<init>",
2977 "(Lgroovy/lang/Script;Ljava/lang/String;)V");
2978 }
2979 else {
2980 visitPropertyExpression(new PropertyExpression(VariableExpression.THIS_EXPRESSION, name));
2981 }
2982 }
2983
2984
2985 protected void processFieldAccess( String name, FieldNode field, int steps ) {
2986 FieldExpression expression = new FieldExpression(field);
2987
2988 if( steps == 0 ) {
2989 visitFieldExpression( expression );
2990 }
2991 else {
2992 visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true );
2993 }
2994 }
2995
2996
2997
2998 /***
2999 * @return true if we are in a script body, where all variables declared are no longer
3000 * local variables but are properties
3001 */
3002 protected boolean isInScriptBody() {
3003 if (classNode.isScriptBody()) {
3004 return true;
3005 }
3006 else {
3007 return classNode.isScript() && methodNode != null && methodNode.getName().equals("run");
3008 }
3009 }
3010
3011 /***
3012 * @return true if this expression will have left a value on the stack
3013 * that must be popped
3014 */
3015 protected boolean isPopRequired(Expression expression) {
3016 if (expression instanceof MethodCallExpression) {
3017 if (expression.getType() != null && expression.getType().equals("void")) {
3018 return false;
3019 } else {
3020 return !MethodCallExpression.isSuperMethodCall((MethodCallExpression) expression);
3021 }
3022 }
3023 if (expression instanceof BinaryExpression) {
3024 BinaryExpression binExp = (BinaryExpression) expression;
3025 switch (binExp.getOperation().getType()) {
3026
3027
3028
3029
3030
3031
3032
3033
3034 }
3035 }
3036 return true;
3037 }
3038
3039 protected boolean firstStatementIsSuperInit(Statement code) {
3040 ExpressionStatement expStmt = null;
3041 if (code instanceof ExpressionStatement) {
3042 expStmt = (ExpressionStatement) code;
3043 }
3044 else if (code instanceof BlockStatement) {
3045 BlockStatement block = (BlockStatement) code;
3046 if (!block.getStatements().isEmpty()) {
3047 Object expr = block.getStatements().get(0);
3048 if (expr instanceof ExpressionStatement) {
3049 expStmt = (ExpressionStatement) expr;
3050 }
3051 }
3052 }
3053 if (expStmt != null) {
3054 Expression expr = expStmt.getExpression();
3055 if (expr instanceof MethodCallExpression) {
3056 MethodCallExpression call = (MethodCallExpression) expr;
3057 if (MethodCallExpression.isSuperMethodCall(call)) {
3058
3059 return call.getMethod().equals("<init>") || call.getMethod().equals("super");
3060 }
3061 }
3062 }
3063 return false;
3064 }
3065
3066 protected void createSyntheticStaticFields() {
3067 for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) {
3068 String staticFieldName = (String) iter.next();
3069
3070 cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null);
3071 }
3072
3073 if (!syntheticStaticFields.isEmpty()) {
3074 cv =
3075 cw.visitMethod(
3076 ACC_STATIC + ACC_SYNTHETIC,
3077 "class$",
3078 "(Ljava/lang/String;)Ljava/lang/Class;",
3079 null,
3080 null);
3081 helper = new BytecodeHelper(cv);
3082
3083 Label l0 = new Label();
3084 cv.visitLabel(l0);
3085 cv.visitVarInsn(ALOAD, 0);
3086 cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
3087 Label l1 = new Label();
3088 cv.visitLabel(l1);
3089 cv.visitInsn(ARETURN);
3090 Label l2 = new Label();
3091 cv.visitLabel(l2);
3092 cv.visitVarInsn(ASTORE, 1);
3093 cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
3094 cv.visitInsn(DUP);
3095 cv.visitVarInsn(ALOAD, 1);
3096 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;");
3097 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
3098 cv.visitInsn(ATHROW);
3099 cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException");
3100 cv.visitMaxs(3, 2);
3101
3102 cw.visitEnd();
3103 }
3104 }
3105 /*** load class object on stack */
3106 public void visitClassExpression(ClassExpression expression) {
3107 String type = expression.getText();
3108
3109
3110
3111 if (BytecodeHelper.isPrimitiveType(type)) {
3112 String objectType = BytecodeHelper.getObjectTypeForPrimitive(type);
3113 cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;");
3114 }
3115 else {
3116 final String staticFieldName =
3117 (type.equals(classNode.getName())) ? "class$0" : "class$" + type.replace('.', '$').replace('[', '_').replace(';', '_');
3118
3119 syntheticStaticFields.add(staticFieldName);
3120
3121 cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
3122 Label l0 = new Label();
3123 cv.visitJumpInsn(IFNONNULL, l0);
3124 cv.visitLdcInsn(type);
3125 cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
3126 cv.visitInsn(DUP);
3127 cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
3128 Label l1 = new Label();
3129 cv.visitJumpInsn(GOTO, l1);
3130 cv.visitLabel(l0);
3131 cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
3132 cv.visitLabel(l1);
3133 }
3134 }
3135
3136 public void visitRangeExpression(RangeExpression expression) {
3137 leftHandExpression = false;
3138 expression.getFrom().visit(this);
3139
3140 leftHandExpression = false;
3141 expression.getTo().visit(this);
3142
3143 helper.pushConstant(expression.isInclusive());
3144
3145 createRangeMethod.call(cv);
3146 }
3147
3148 public void visitMapEntryExpression(MapEntryExpression expression) {
3149 }
3150
3151 public void visitMapExpression(MapExpression expression) {
3152 List entries = expression.getMapEntryExpressions();
3153 int size = entries.size();
3154 helper.pushConstant(size * 2);
3155
3156 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3157
3158 int i = 0;
3159 for (Iterator iter = entries.iterator(); iter.hasNext();) {
3160 MapEntryExpression entry = (MapEntryExpression) iter.next();
3161
3162 cv.visitInsn(DUP);
3163 helper.pushConstant(i++);
3164 visitAndAutoboxBoolean(entry.getKeyExpression());
3165 cv.visitInsn(AASTORE);
3166
3167 cv.visitInsn(DUP);
3168 helper.pushConstant(i++);
3169 visitAndAutoboxBoolean(entry.getValueExpression());
3170 cv.visitInsn(AASTORE);
3171 }
3172 createMapMethod.call(cv);
3173 }
3174
3175 public void visitTupleExpression(TupleExpression expression) {
3176 int size = expression.getExpressions().size();
3177
3178 helper.pushConstant(size);
3179
3180 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3181
3182 for (int i = 0; i < size; i++) {
3183 cv.visitInsn(DUP);
3184 helper.pushConstant(i);
3185 visitAndAutoboxBoolean(expression.getExpression(i));
3186 cv.visitInsn(AASTORE);
3187 }
3188
3189 }
3190
3191 public void visitArrayExpression(ArrayExpression expression) {
3192 String type = expression.getElementType();
3193 String typeName = BytecodeHelper.getClassInternalName(type);
3194 Expression sizeExpression = expression.getSizeExpression();
3195 if (sizeExpression != null) {
3196
3197 visitAndAutoboxBoolean(sizeExpression);
3198 asIntMethod.call(cv);
3199
3200 cv.visitTypeInsn(ANEWARRAY, typeName);
3201 }
3202 else {
3203 int size = expression.getExpressions().size();
3204 helper.pushConstant(size);
3205
3206 cv.visitTypeInsn(ANEWARRAY, typeName);
3207
3208 for (int i = 0; i < size; i++) {
3209 cv.visitInsn(DUP);
3210 helper.pushConstant(i);
3211 Expression elementExpression = expression.getExpression(i);
3212 if (elementExpression == null) {
3213 ConstantExpression.NULL.visit(this);
3214 }
3215 else {
3216
3217 if(!type.equals(elementExpression.getClass().getName())) {
3218 visitCastExpression(new CastExpression(type, elementExpression));
3219 }
3220 else {
3221 visitAndAutoboxBoolean(elementExpression);
3222 }
3223 }
3224 cv.visitInsn(AASTORE);
3225 }
3226 }
3227 }
3228
3229 public void visitListExpression(ListExpression expression) {
3230 int size = expression.getExpressions().size();
3231 helper.pushConstant(size);
3232
3233 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3234
3235 for (int i = 0; i < size; i++) {
3236 cv.visitInsn(DUP);
3237 helper.pushConstant(i);
3238 visitAndAutoboxBoolean(expression.getExpression(i));
3239 cv.visitInsn(AASTORE);
3240 }
3241 createListMethod.call(cv);
3242 }
3243
3244 public void visitGStringExpression(GStringExpression expression) {
3245 int size = expression.getValues().size();
3246 helper.pushConstant(size);
3247
3248 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
3249
3250 for (int i = 0; i < size; i++) {
3251 cv.visitInsn(DUP);
3252 helper.pushConstant(i);
3253 visitAndAutoboxBoolean(expression.getValue(i));
3254 cv.visitInsn(AASTORE);
3255 }
3256
3257 Variable tv = visitASTOREInTemp("iterator");
3258 int paramIdx = tv.getIndex();
3259
3260 ClassNode innerClass = createGStringClass(expression);
3261 addInnerClass(innerClass);
3262 String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName());
3263
3264 cv.visitTypeInsn(NEW, innerClassinternalName);
3265 cv.visitInsn(DUP);
3266 cv.visitVarInsn(ALOAD, paramIdx);
3267
3268 cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V");
3269 removeVar(tv);
3270 }
3271
3272 private Variable visitASTOREInTemp(String s) {
3273 return storeInTemp(s, "java.lang.Object");
3274 }
3275
3276
3277
3278 protected boolean addInnerClass(ClassNode innerClass) {
3279 innerClass.setModule(classNode.getModule());
3280 return innerClasses.add(innerClass);
3281 }
3282
3283 protected ClassNode createClosureClass(ClosureExpression expression) {
3284 ClassNode owner = getOutermostClass();
3285 boolean parentIsInnerClass = owner instanceof InnerClassNode;
3286 String outerClassName = owner.getName();
3287 String name = outerClassName + "$"
3288 + context.getNextClosureInnerName(owner, classNode, methodNode);
3289 boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass();
3290 if (staticMethodOrInStaticClass) {
3291 outerClassName = "java.lang.Class";
3292 }
3293 Parameter[] parameters = expression.getParameters();
3294 if (parameters == null || parameters.length == 0) {
3295
3296 parameters = new Parameter[] { new Parameter("it")};
3297 }
3298
3299 Parameter[] localVariableParams = getClosureSharedVariables(expression);
3300
3301 InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, "groovy.lang.Closure");
3302 answer.setEnclosingMethod(this.methodNode);
3303 if (staticMethodOrInStaticClass) {
3304 answer.setStaticClass(true);
3305 }
3306 if (isInScriptBody()) {
3307 answer.setScriptBody(true);
3308 }
3309 MethodNode method =
3310 answer.addMethod("doCall", ACC_PUBLIC, "java.lang.Object", parameters, expression.getCode());
3311
3312 method.setLineNumber(expression.getLineNumber());
3313 method.setColumnNumber(expression.getColumnNumber());
3314
3315 VariableScope varScope = expression.getVariableScope();
3316 if (varScope == null) {
3317 throw new RuntimeException(
3318 "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
3319 }
3320 else {
3321 method.setVariableScope(varScope);
3322 }
3323 if (parameters.length > 1
3324 || (parameters.length == 1
3325 && parameters[0].getType() != null
3326 && !parameters[0].getType().equals("java.lang.Object"))) {
3327
3328
3329 answer.addMethod(
3330 "call",
3331 ACC_PUBLIC,
3332 "java.lang.Object",
3333 parameters,
3334 new ReturnStatement(
3335 new MethodCallExpression(
3336 VariableExpression.THIS_EXPRESSION,
3337 "doCall",
3338 new ArgumentListExpression(parameters))));
3339 }
3340
3341 FieldNode ownerField = answer.addField("owner", ACC_PRIVATE, outerClassName, null);
3342
3343
3344 BlockStatement block = new BlockStatement();
3345 block.addStatement(
3346 new ExpressionStatement(
3347 new MethodCallExpression(
3348 new VariableExpression("super"),
3349 "<init>",
3350 new VariableExpression("_outerInstance"))));
3351 block.addStatement(
3352 new ExpressionStatement(
3353 new BinaryExpression(
3354 new FieldExpression(ownerField),
3355 Token.newSymbol(Types.EQUAL, -1, -1),
3356 new VariableExpression("_outerInstance"))));
3357
3358
3359 for (int i = 0; i < localVariableParams.length; i++) {
3360 Parameter param = localVariableParams[i];
3361 String paramName = param.getName();
3362 boolean holder = mutableVars.contains(paramName);
3363 Expression initialValue = null;
3364 String type = param.getType();
3365 FieldNode paramField = null;
3366 if (holder) {
3367 initialValue = new VariableExpression(paramName);
3368 type = Reference.class.getName();
3369 param.makeReference();
3370 paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue);
3371 paramField.setHolder(true);
3372 String realType = param.getRealType();
3373 String methodName = Verifier.capitalize(paramName);
3374
3375
3376 Expression fieldExp = new FieldExpression(paramField);
3377 answer.addMethod(
3378 "get" + methodName,
3379 ACC_PUBLIC,
3380 realType,
3381 Parameter.EMPTY_ARRAY,
3382 new ReturnStatement(fieldExp));
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393 }
3394 else {
3395 PropertyNode propertyNode = answer.addProperty(paramName, ACC_PUBLIC, type, initialValue, null, null);
3396 paramField = propertyNode.getField();
3397 block.addStatement(
3398 new ExpressionStatement(
3399 new BinaryExpression(
3400 new FieldExpression(paramField),
3401 Token.newSymbol(Types.EQUAL, -1, -1),
3402 new VariableExpression(paramName))));
3403 }
3404 }
3405
3406 Parameter[] params = new Parameter[2 + localVariableParams.length];
3407 params[0] = new Parameter(outerClassName, "_outerInstance");
3408 params[1] = new Parameter("java.lang.Object", "_delegate");
3409 System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
3410
3411 answer.addConstructor(ACC_PUBLIC, params, block);
3412 return answer;
3413 }
3414
3415 protected ClassNode getOutermostClass() {
3416 if (outermostClass == null) {
3417 outermostClass = classNode;
3418 while (outermostClass instanceof InnerClassNode) {
3419 outermostClass = outermostClass.getOuterClass();
3420 }
3421 }
3422 return outermostClass;
3423 }
3424
3425 protected ClassNode createGStringClass(GStringExpression expression) {
3426 ClassNode owner = classNode;
3427 if (owner instanceof InnerClassNode) {
3428 owner = owner.getOuterClass();
3429 }
3430 String outerClassName = owner.getName();
3431 String name = outerClassName + "$" + context.getNextInnerClassIdx();
3432 InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, GString.class.getName());
3433 answer.setEnclosingMethod(this.methodNode);
3434 FieldNode stringsField =
3435 answer.addField(
3436 "strings",
3437 ACC_PRIVATE
3438 "java.lang.String[]",
3439 new ArrayExpression("java.lang.String", expression.getStrings()));
3440 answer.addMethod(
3441 "getStrings",
3442 ACC_PUBLIC,
3443 "java.lang.String[]",
3444 Parameter.EMPTY_ARRAY,
3445 new ReturnStatement(new FieldExpression(stringsField)));
3446
3447 BlockStatement block = new BlockStatement();
3448 block.addStatement(
3449 new ExpressionStatement(
3450 new MethodCallExpression(new VariableExpression("super"), "<init>", new VariableExpression("values"))));
3451 Parameter[] contructorParams = new Parameter[] { new Parameter("java.lang.Object[]", "values")};
3452 answer.addConstructor(ACC_PUBLIC, contructorParams, block);
3453 return answer;
3454 }
3455
3456 protected void doConvertAndCast(String type) {
3457 if (!type.equals("java.lang.Object")) {
3458 /*** todo should probably support array coercions */
3459 if (!type.endsWith("[]") && isValidTypeForCast(type)) {
3460 visitClassExpression(new ClassExpression(type));
3461 asTypeMethod.call(cv);
3462 }
3463
3464 helper.doCast(type);
3465 }
3466 }
3467
3468 protected void evaluateLogicalOrExpression(BinaryExpression expression) {
3469 visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
3470 Label l0 = new Label();
3471 Label l2 = new Label();
3472 cv.visitJumpInsn(IFEQ, l0);
3473
3474 cv.visitLabel(l2);
3475
3476 visitConstantExpression(ConstantExpression.TRUE);
3477
3478 Label l1 = new Label();
3479 cv.visitJumpInsn(GOTO, l1);
3480 cv.visitLabel(l0);
3481
3482 visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
3483
3484 cv.visitJumpInsn(IFNE, l2);
3485
3486 visitConstantExpression(ConstantExpression.FALSE);
3487 cv.visitLabel(l1);
3488 }
3489
3490
3491
3492 protected void evaluateLogicalAndExpression(BinaryExpression expression) {
3493 visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
3494 Label l0 = new Label();
3495 cv.visitJumpInsn(IFEQ, l0);
3496
3497 visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
3498
3499 cv.visitJumpInsn(IFEQ, l0);
3500
3501 visitConstantExpression(ConstantExpression.TRUE);
3502
3503 Label l1 = new Label();
3504 cv.visitJumpInsn(GOTO, l1);
3505 cv.visitLabel(l0);
3506
3507 visitConstantExpression(ConstantExpression.FALSE);
3508
3509 cv.visitLabel(l1);
3510 }
3511
3512 protected void evaluateBinaryExpression(String method, BinaryExpression expression) {
3513 Expression leftExpression = expression.getLeftExpression();
3514 leftHandExpression = false;
3515 leftExpression.visit(this);
3516 cv.visitLdcInsn(method);
3517 leftHandExpression = false;
3518 new ArgumentListExpression(new Expression[] { expression.getRightExpression()}).visit(this);
3519
3520 invokeMethodMethod.call(cv);
3521 }
3522
3523 protected void evaluateCompareTo(BinaryExpression expression) {
3524 Expression leftExpression = expression.getLeftExpression();
3525 leftHandExpression = false;
3526 leftExpression.visit(this);
3527 expression.getRightExpression().visit(this);
3528 compareToMethod.call(cv);
3529 }
3530
3531 protected void evaluateBinaryExpressionWithAsignment(String method, BinaryExpression expression) {
3532 Expression leftExpression = expression.getLeftExpression();
3533 if (leftExpression instanceof BinaryExpression) {
3534 BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
3535 if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
3536
3537
3538
3539
3540
3541
3542 MethodCallExpression methodCall =
3543 new MethodCallExpression(
3544 expression.getLeftExpression(),
3545 method,
3546 new ArgumentListExpression(new Expression[] { expression.getRightExpression()}));
3547
3548 Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression());
3549
3550 visitMethodCallExpression(
3551 new MethodCallExpression(
3552 leftBinExpr.getLeftExpression(),
3553 "putAt",
3554 new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall })));
3555
3556 return;
3557 }
3558 }
3559
3560 evaluateBinaryExpression(method, expression);
3561
3562
3563 cv.visitInsn(DUP);
3564
3565 leftHandExpression = true;
3566 evaluateExpression(leftExpression);
3567 leftHandExpression = false;
3568 }
3569
3570 private void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression bin) {
3571 if (ENABLE_EARLY_BINDING && true) {
3572 evalBinaryExp_EarlyBinding(compareMethod, bin);
3573 }
3574 else {
3575 evalBinaryExp_LateBinding(compareMethod, bin);
3576 }
3577 }
3578
3579 protected void evalBinaryExp_LateBinding(MethodCaller compareMethod, BinaryExpression expression) {
3580 Expression leftExp = expression.getLeftExpression();
3581 Expression rightExp = expression.getRightExpression();
3582 load(leftExp);
3583 load(rightExp);
3584 compareMethod.call(cv);
3585 }
3586
3587 /***
3588 * note: leave the primitive boolean on staock for comparison expressions. All the result types need to match the
3589 * utility methods in the InvokerHelper.
3590 * @param compareMethod
3591 * @param expression
3592 */
3593 protected void evalBinaryExp_EarlyBinding(MethodCaller compareMethod, BinaryExpression expression) {
3594 Expression leftExp = expression.getLeftExpression();
3595 Expression rightExp = expression.getRightExpression();
3596
3597 expression.resolve(this);
3598 if (expression.isResolveFailed() || expression.getTypeClass() == null){
3599 evalBinaryExp_LateBinding(compareMethod, expression);
3600 return;
3601 }
3602 else {
3603 Class lclass = leftExp.getTypeClass();
3604 Class rclass = rightExp.getTypeClass();
3605 if (lclass == null || rclass == null) {
3606 if ((lclass == null && rclass != null) || (lclass != null && rclass == null)) {
3607
3608 if (leftExp == ConstantExpression.NULL && !rclass.isPrimitive() ||
3609 rightExp == ConstantExpression.NULL && !lclass.isPrimitive()) {
3610 Expression exp = leftExp == ConstantExpression.NULL? rightExp : leftExp;
3611 int type = expression.getOperation().getType();
3612 switch (type) {
3613 case Types.COMPARE_EQUAL :
3614 load(exp);
3615 cv.visitInsn(ICONST_1);
3616 cv.visitInsn(SWAP);
3617 Label l1 = new Label();
3618 cv.visitJumpInsn(IFNULL, l1);
3619 cv.visitInsn(POP);
3620 cv.visitInsn(ICONST_0);
3621 cv.visitLabel(l1);
3622 return;
3623 case Types.COMPARE_NOT_EQUAL :
3624 load(exp);
3625 cv.visitInsn(ICONST_1);
3626 cv.visitInsn(SWAP);
3627 Label l2 = new Label();
3628 cv.visitJumpInsn(IFNONNULL, l2);
3629 cv.visitInsn(POP);
3630 cv.visitInsn(ICONST_0);
3631 cv.visitLabel(l2);
3632 return;
3633 default:
3634 evalBinaryExp_LateBinding(compareMethod, expression);
3635 return;
3636 }
3637 }
3638 else {
3639 evalBinaryExp_LateBinding(compareMethod, expression);
3640 return;
3641 }
3642 }
3643 else {
3644 evalBinaryExp_LateBinding(compareMethod, expression);
3645 return;
3646 }
3647 }
3648 else if (lclass == String.class && rclass == String.class) {
3649 int type = expression.getOperation().getType();
3650 switch (type) {
3651 case Types.COMPARE_EQUAL :
3652 load(leftExp); cast(String.class);
3653 load(rightExp); cast(String.class);
3654 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
3655
3656 return;
3657 case Types.COMPARE_NOT_EQUAL :
3658 load(leftExp);cast(String.class);
3659 load(rightExp); cast(String.class);
3660 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
3661 cv.visitInsn(ICONST_1);
3662 cv.visitInsn(IXOR);
3663
3664 return;
3665 case Types.COMPARE_TO :
3666 load(leftExp);cast(String.class);
3667 load(rightExp); cast(String.class);
3668 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I");
3669 helper.quickBoxIfNecessary(int.class);
3670 return;
3671 case Types.COMPARE_GREATER_THAN :
3672 case Types.COMPARE_GREATER_THAN_EQUAL :
3673 case Types.COMPARE_LESS_THAN :
3674 case Types.COMPARE_LESS_THAN_EQUAL :
3675 {
3676 int op;
3677 switch (type) {
3678 case Types.COMPARE_GREATER_THAN :
3679 op = IFLE;
3680 break;
3681 case Types.COMPARE_GREATER_THAN_EQUAL :
3682 op = IFLT;
3683 break;
3684 case Types.COMPARE_LESS_THAN :
3685 op = IFGE;
3686 break;
3687 case Types.COMPARE_LESS_THAN_EQUAL :
3688 op = IFGT;
3689 break;
3690 default:
3691 System.err.println("flow control error: should not be here. type: " + type);
3692 return;
3693 }
3694 load(leftExp);cast(String.class);
3695 load(rightExp); cast(String.class);
3696 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I");
3697
3698
3699 Label l4 = new Label();
3700 cv.visitJumpInsn(op, l4);
3701
3702 cv.visitInsn(ICONST_1);
3703 Label l5 = new Label();
3704 cv.visitJumpInsn(GOTO, l5);
3705 cv.visitLabel(l4);
3706 cv.visitInsn(ICONST_0);
3707 cv.visitLabel(l5);
3708 }
3709 return;
3710
3711 default:
3712 evalBinaryExp_LateBinding(compareMethod, expression);
3713 return;
3714 }
3715 }
3716 else if (Integer.class == lclass && Integer.class == rclass) {
3717 int type = expression.getOperation().getType();
3718 switch (type) {
3719 case Types.COMPARE_EQUAL :
3720 load(leftExp); cast(Integer.class);
3721 load(rightExp);
3722 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z");
3723
3724 return;
3725 case Types.COMPARE_NOT_EQUAL :
3726 load(leftExp); cast(Integer.class);
3727 load(rightExp);
3728 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z");
3729 cv.visitInsn(ICONST_1);
3730 cv.visitInsn(IXOR);
3731
3732 return;
3733 case Types.COMPARE_TO :
3734 load(leftExp); cast(Integer.class);
3735 load(rightExp);
3736 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I");
3737 helper.quickBoxIfNecessary(int.class);
3738 return;
3739 case Types.COMPARE_GREATER_THAN :
3740 case Types.COMPARE_GREATER_THAN_EQUAL :
3741 case Types.COMPARE_LESS_THAN :
3742 case Types.COMPARE_LESS_THAN_EQUAL :
3743 {
3744 int op;
3745 switch (type) {
3746 case Types.COMPARE_GREATER_THAN :
3747 op = IFLE;
3748 break;
3749 case Types.COMPARE_GREATER_THAN_EQUAL :
3750 op = IFLT;
3751 break;
3752 case Types.COMPARE_LESS_THAN :
3753 op = IFGE;
3754 break;
3755 case Types.COMPARE_LESS_THAN_EQUAL :
3756 op = IFGT;
3757 break;
3758 default:
3759 System.err.println("flow control error: should not be here. type: " + type);
3760 return;
3761 }
3762 load(leftExp); cast(Integer.class);
3763 load(rightExp);
3764 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I");
3765
3766 Label l4 = new Label();
3767 cv.visitJumpInsn(op, l4);
3768 cv.visitInsn(ICONST_1);
3769 Label l5 = new Label();
3770 cv.visitJumpInsn(GOTO, l5);
3771 cv.visitLabel(l4);
3772 cv.visitInsn(ICONST_0);
3773 cv.visitLabel(l5);
3774 }
3775 return;
3776
3777 default:
3778 evalBinaryExp_LateBinding(compareMethod, expression);
3779 return;
3780 }
3781 }
3782 else {
3783 evalBinaryExp_LateBinding(compareMethod, expression);
3784 return;
3785 }
3786 }
3787 }
3788
3789 private void cast(Class aClass) {
3790 if (!aClass.isPrimitive() && aClass != Object.class) {
3791 cv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(aClass.getName()));
3792 }
3793 }
3794
3795 protected void evaluateEqual(BinaryExpression expression) {
3796 if (ENABLE_EARLY_BINDING) {
3797 expression.resolve(this);
3798 if (expression.isTypeResolved()) {
3799 if (expression.getRightExpression().getTypeClass() == Void.TYPE) {
3800 throwException("void value appeared on right hand side of assignment. ");
3801 }
3802 }
3803 }
3804
3805 Expression leftExpression = expression.getLeftExpression();
3806 if (leftExpression instanceof BinaryExpression) {
3807 BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
3808 if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
3809
3810
3811
3812
3813
3814 do {
3815 if (true && ENABLE_EARLY_BINDING){
3816 Class typeclass = leftBinExpr.getLeftExpression().getTypeClass();
3817 if (typeclass == null) {
3818 break;
3819 }
3820
3821 if (typeclass == Map.class) {
3822 load(expression.getRightExpression());
3823
3824 cv.visitInsn(DUP);
3825 final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType());
3826
3827 final Class rclass = expression.getRightExpression().getTypeClass();
3828 BytecodeExpression loadTempByteCode = new BytecodeExpression() {
3829 public void visit(GroovyCodeVisitor visitor) {
3830 cv.visitVarInsn(ALOAD, rightTemp.getIndex());
3831 }
3832 protected void resolveType(AsmClassGenerator2 resolver) {
3833 setTypeClass(rclass);
3834 }
3835 };
3836
3837 visitMethodCallExpression(
3838 new MethodCallExpression(
3839 leftBinExpr.getLeftExpression(),
3840 "put",
3841 new ArgumentListExpression(
3842 new Expression[] {
3843 leftBinExpr.getRightExpression(),
3844 loadTempByteCode})));
3845 cv.visitInsn(POP);
3846 removeVar(rightTemp);
3847 return;
3848 }
3849 else if (typeclass == List.class){
3850
3851
3852
3853
3854 load(expression.getRightExpression());
3855
3856 cv.visitInsn(DUP);
3857 final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType());
3858
3859 final Class rclass = expression.getRightExpression().getTypeClass();
3860 BytecodeExpression loadTempBytes = new BytecodeExpression() {
3861 public void visit(GroovyCodeVisitor visitor) {
3862 cv.visitVarInsn(ALOAD, rightTemp.getIndex());
3863 }
3864 protected void resolveType(AsmClassGenerator2 resolver) {
3865 setTypeClass(rclass);
3866 }
3867 };
3868
3869 visitMethodCallExpression(
3870 new MethodCallExpression(
3871 new ClassExpression(DefaultGroovyMethods.class),
3872 "putAt",
3873 new ArgumentListExpression(
3874 new Expression[] {
3875 leftBinExpr.getLeftExpression(),
3876 leftBinExpr.getRightExpression(),
3877 loadTempBytes })));
3878 removeVar(rightTemp);
3879 return;
3880
3881 }
3882 else {
3883 break;
3884 }
3885 }
3886 } while (false);
3887
3888 visitMethodCallExpression(
3889 new MethodCallExpression(
3890 leftBinExpr.getLeftExpression(),
3891 "putAt",
3892 new ArgumentListExpression(
3893 new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()})));
3894
3895 return;
3896 }
3897 }
3898
3899
3900 leftHandExpression = false;
3901 Expression rightExpression = expression.getRightExpression();
3902
3903 String type = getLHSType(leftExpression);
3904 if (type != null) {
3905
3906
3907
3908
3909 if (BytecodeHelper.isPrimitiveType(type)) {
3910 rightExpression.visit(this);
3911 }
3912 else {
3913 if (ENABLE_EARLY_BINDING) {
3914 if (leftExpression.isDynamic()) {
3915 visitAndAutoboxBoolean(rightExpression);
3916 }
3917 else {
3918 if (type.equals(rightExpression.getType())) {
3919 visitAndAutoboxBoolean(rightExpression);
3920 }
3921 else {
3922 if (rightExpression instanceof ConstantExpression &&
3923 ((ConstantExpression)rightExpression).getValue() == null) {
3924 cv.visitInsn(ACONST_NULL);
3925 }
3926 else {
3927 visitCastExpression(new CastExpression(type, rightExpression));
3928 }
3929 }
3930 }
3931 }
3932 else if (!type.equals("java.lang.Object")){
3933 visitCastExpression(new CastExpression(type, rightExpression));
3934 }
3935 else {
3936 visitAndAutoboxBoolean(rightExpression);
3937 }
3938 }
3939 }
3940 else {
3941 visitAndAutoboxBoolean(rightExpression);
3942 }
3943
3944
3945
3946 if (ENABLE_EARLY_BINDING) {
3947 Class rc = rightExpression.getTypeClass();
3948 if (rc != null && rc.isArray()) {
3949 Class elemType = rc.getComponentType();
3950 if (elemType.isPrimitive()) {
3951 visitClassExpression(new ClassExpression(elemType));
3952 convertPrimitiveArray.call(cv);
3953 cast(loadClass(BytecodeHelper.getObjectArrayTypeForPrimitiveArray(elemType.getName() + "[]")));
3954 }
3955 }
3956
3957
3958 if (leftExpression.isDynamic() ) {
3959
3960 if (!(leftExpression instanceof FieldExpression ) && !(leftExpression instanceof PropertyExpression))
3961 copyTypeClass(leftExpression, rightExpression);
3962 }
3963 else {
3964 Class lc = leftExpression.getTypeClass();
3965
3966 if (lc != null && rc != null && !lc.isAssignableFrom(rc) && !lc.isPrimitive()) {
3967
3968 if (!lc.isArray()) {
3969 visitClassExpression(new ClassExpression(lc));
3970 asTypeMethod.call(cv);
3971 helper.doCast(lc);
3972 }
3973 else {
3974
3975 Class elemType = lc.getComponentType();
3976 if (elemType.isPrimitive()) {
3977
3978 copyTypeClass(leftExpression, rightExpression);
3979 }
3980 }
3981 }
3982 }
3983 }
3984 cv.visitInsn(DUP);
3985 leftHandExpression = true;
3986 leftExpression.visit(this);
3987 leftHandExpression = false;
3988 }
3989
3990 private void copyTypeClass(Expression leftExpression, Expression rightExpression) {
3991
3992 Class rclass = rightExpression.getTypeClass();
3993 if (rightExpression instanceof ClassExpression) {
3994 leftExpression.setTypeClass(Class.class);
3995 }
3996 else {
3997 rclass = BytecodeHelper.boxOnPrimitive(rclass);
3998 leftExpression.setTypeClass(rclass);
3999 }
4000 }
4001
4002 private boolean canBeAssignedFrom(String ltype, String rtype) {
4003 if (rtype == null) {
4004 return false;
4005 }
4006 else if (ltype == null || ltype.equals("java.lang.Object")) {
4007 return true;
4008 } else {
4009 return false;
4010 }
4011 }
4012
4013 private boolean canBeAssignedFrom(Expression l, Expression r) {
4014 if (r.getTypeClass() == null) {
4015 return false;
4016 }
4017 else if (l.isDynamic()){
4018 return true;
4019 } else {
4020 return false;
4021 }
4022 }
4023 private boolean canBeAssignedFrom(Class l, Class r) {
4024 if (r == null) {
4025 return false;
4026 }
4027 else if (l == null || l == Object.class){
4028 return true;
4029 } else {
4030 return false;
4031 }
4032 }
4033
4034 /***
4035 * Deduces the type name required for some casting
4036 *
4037 * @return the type of the given (LHS) expression or null if it is java.lang.Object or it cannot be deduced
4038 */
4039 protected String getLHSType(Expression leftExpression) {
4040 do {
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050 } while (false);
4051
4052 if (leftExpression instanceof VariableExpression) {
4053 VariableExpression varExp = (VariableExpression) leftExpression;
4054 String type = varExp.getType();
4055 if (isValidTypeForCast(type)) {
4056 return type;
4057 }
4058 String variableName = varExp.getVariable();
4059 Variable variable = (Variable) variableStack.get(variableName);
4060 if (variable != null) {
4061 if (variable.isHolder() || variable.isProperty()) {
4062 return null;
4063 }
4064 type = variable.getTypeName();
4065 if (isValidTypeForCast(type)) {
4066 return type;
4067 }
4068 }
4069 else {
4070 FieldNode field = classNode.getField(variableName);
4071 if (field == null) {
4072 field = classNode.getOuterField(variableName);
4073 }
4074 if (field != null) {
4075 type = field.getType();
4076 if (!field.isHolder() && isValidTypeForCast(type)) {
4077 return type;
4078 }
4079 }
4080 }
4081 }
4082 return null;
4083 }
4084
4085 protected boolean isValidTypeForCast(String type) {
4086 return type != null && !type.equals("java.lang.Object") && !type.equals("groovy.lang.Reference") && !BytecodeHelper.isPrimitiveType(type);
4087 }
4088
4089 protected void visitAndAutoboxBoolean(Expression expression) {
4090 expression.visit(this);
4091
4092 if (isComparisonExpression(expression)) {
4093 helper.boxBoolean();
4094 }
4095 }
4096
4097 protected void evaluatePrefixMethod(String method, Expression expression) {
4098 if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) {
4099 cv.visitVarInsn(ALOAD, 0);
4100 }
4101 expression.visit(this);
4102 cv.visitLdcInsn(method);
4103 invokeNoArgumentsMethod.call(cv);
4104
4105 leftHandExpression = true;
4106 expression.visit(this);
4107 leftHandExpression = false;
4108 expression.visit(this);
4109 }
4110
4111 protected void evaluatePostfixMethod(String method, Expression expression) {
4112 leftHandExpression = false;
4113 expression.visit(this);
4114
4115 Variable tv = visitASTOREInTemp("postfix_" + method);
4116 int tempIdx = tv.getIndex();
4117 cv.visitVarInsn(ALOAD, tempIdx);
4118
4119 cv.visitLdcInsn(method);
4120 invokeNoArgumentsMethod.call(cv);
4121
4122 store(expression);
4123
4124 cv.visitVarInsn(ALOAD, tempIdx);
4125 removeVar(tv);
4126 }
4127
4128 protected boolean isHolderVariable(Expression expression) {
4129 if (expression instanceof FieldExpression) {
4130 FieldExpression fieldExp = (FieldExpression) expression;
4131 return fieldExp.getField().isHolder();
4132 }
4133 if (expression instanceof VariableExpression) {
4134 VariableExpression varExp = (VariableExpression) expression;
4135 Variable variable = (Variable) variableStack.get(varExp.getVariable());
4136 if (variable != null) {
4137 return variable.isHolder();
4138 }
4139 FieldNode field = classNode.getField(varExp.getVariable());
4140 if (field != null) {
4141 return field.isHolder();
4142 }
4143 }
4144 return false;
4145 }
4146
4147 protected void evaluateInstanceof(BinaryExpression expression) {
4148 expression.getLeftExpression().visit(this);
4149 Expression rightExp = expression.getRightExpression();
4150 String className = null;
4151 if (rightExp instanceof ClassExpression) {
4152 ClassExpression classExp = (ClassExpression) rightExp;
4153 className = classExp.getType();
4154 }
4155 else {
4156 throw new RuntimeException(
4157 "Right hand side of the instanceof keyworld must be a class name, not: " + rightExp);
4158 }
4159 className = checkValidType(className, expression, "Must be a valid type name for an instanceof statement");
4160 String classInternalName = BytecodeHelper.getClassInternalName(className);
4161 cv.visitTypeInsn(INSTANCEOF, classInternalName);
4162 }
4163
4164 /***
4165 * @return true if the given argument expression requires the stack, in
4166 * which case the arguments are evaluated first, stored in the
4167 * variable stack and then reloaded to make a method call
4168 */
4169 protected boolean argumentsUseStack(Expression arguments) {
4170 return arguments instanceof TupleExpression || arguments instanceof ClosureExpression;
4171 }
4172
4173 /***
4174 * @return true if the given expression represents a non-static field
4175 */
4176 protected boolean isNonStaticField(Expression expression) {
4177 FieldNode field = null;
4178 if (expression instanceof VariableExpression) {
4179 VariableExpression varExp = (VariableExpression) expression;
4180 field = classNode.getField(varExp.getVariable());
4181 }
4182 else if (expression instanceof FieldExpression) {
4183 FieldExpression fieldExp = (FieldExpression) expression;
4184 field = classNode.getField(fieldExp.getFieldName());
4185 }
4186 else if (expression instanceof PropertyExpression) {
4187 PropertyExpression fieldExp = (PropertyExpression) expression;
4188 field = classNode.getField(fieldExp.getProperty());
4189 }
4190 if (field != null) {
4191 return !field.isStatic();
4192 }
4193 return false;
4194 }
4195
4196 protected boolean isThisExpression(Expression expression) {
4197 if (expression instanceof VariableExpression) {
4198 VariableExpression varExp = (VariableExpression) expression;
4199 return varExp.getVariable().equals("this");
4200 }
4201 return false;
4202 }
4203
4204 /***
4205 * For assignment expressions, return a safe expression for the LHS we can use
4206 * to return the value
4207 */
4208 protected Expression createReturnLHSExpression(Expression expression) {
4209 if (expression instanceof BinaryExpression) {
4210 BinaryExpression binExpr = (BinaryExpression) expression;
4211 if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) {
4212 return createReusableExpression(binExpr.getLeftExpression());
4213 }
4214 }
4215 return null;
4216 }
4217
4218 protected Expression createReusableExpression(Expression expression) {
4219 ExpressionTransformer transformer = new ExpressionTransformer() {
4220 public Expression transform(Expression expression) {
4221 if (expression instanceof PostfixExpression) {
4222 PostfixExpression postfixExp = (PostfixExpression) expression;
4223 return postfixExp.getExpression();
4224 }
4225 else if (expression instanceof PrefixExpression) {
4226 PrefixExpression prefixExp = (PrefixExpression) expression;
4227 return prefixExp.getExpression();
4228 }
4229 return expression;
4230 }
4231 };
4232
4233
4234 return transformer.transform(expression.transformExpression(transformer));
4235 }
4236
4237 protected boolean isComparisonExpression(Expression expression) {
4238 if (expression instanceof BinaryExpression) {
4239 BinaryExpression binExpr = (BinaryExpression) expression;
4240 switch (binExpr.getOperation().getType()) {
4241 case Types.COMPARE_EQUAL :
4242 case Types.MATCH_REGEX :
4243 case Types.COMPARE_GREATER_THAN :
4244 case Types.COMPARE_GREATER_THAN_EQUAL :
4245 case Types.COMPARE_LESS_THAN :
4246 case Types.COMPARE_LESS_THAN_EQUAL :
4247 case Types.COMPARE_IDENTICAL :
4248 case Types.COMPARE_NOT_EQUAL :
4249 case Types.KEYWORD_INSTANCEOF :
4250 return true;
4251 }
4252 }
4253 else if (expression instanceof BooleanExpression) {
4254 return true;
4255 }
4256 return false;
4257 }
4258
4259 protected void onLineNumber(ASTNode statement, String message) {
4260 int line = statement.getLineNumber();
4261 int col = statement.getColumnNumber();
4262 this.currentASTNode = statement;
4263
4264 if (line >=0) {
4265 lineNumber = line;
4266 columnNumber = col;
4267 }
4268 if (CREATE_DEBUG_INFO && line >= 0 && cv != null) {
4269 Label l = new Label();
4270 cv.visitLabel(l);
4271 cv.visitLineNumber(line, l);
4272 if (ASM_DEBUG) {
4273 helper.mark(message + "[" + statement.getLineNumber() + ":" + statement.getColumnNumber() + "]");
4274 }
4275 }
4276 }
4277
4278 protected VariableScope getVariableScope() {
4279 if (variableScope == null) {
4280 if (methodNode != null) {
4281
4282 variableScope = methodNode.getVariableScope();
4283 if (variableScope == null) {
4284 variableScope = new VariableScope();
4285 methodNode.setVariableScope(variableScope);
4286 VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
4287 visitor.setParameters(methodNode.getParameters());
4288 Statement code = methodNode.getCode();
4289 if (code != null) {
4290 code.visit(visitor);
4291 }
4292 }
4293 addFieldsToVisitor(variableScope);
4294 }
4295 else if (constructorNode != null) {
4296 variableScope = new VariableScope();
4297 constructorNode.setVariableScope(variableScope);
4298 VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
4299 visitor.setParameters(constructorNode.getParameters());
4300 Statement code = constructorNode.getCode();
4301 if (code != null) {
4302 code.visit(visitor);
4303 }
4304 addFieldsToVisitor(variableScope);
4305 }
4306 else {
4307 throw new RuntimeException("Can't create a variable scope outside of a method or constructor");
4308 }
4309 }
4310 return variableScope;
4311 }
4312
4313 /***
4314 * @return a list of parameters for each local variable which needs to be
4315 * passed into a closure
4316 */
4317 protected Parameter[] getClosureSharedVariables(ClosureExpression expression) {
4318 List vars = new ArrayList();
4319
4320
4321
4322
4323
4324
4325 VariableScope outerScope = getVariableScope().createRecursiveParentScope();
4326 VariableScope innerScope = expression.getVariableScope();
4327 if (innerScope == null) {
4328 System.out.println(
4329 "No variable scope for: " + expression + " method: " + methodNode + " constructor: " + constructorNode);
4330 innerScope = new VariableScope(getVariableScope());
4331 }
4332 else {
4333 innerScope = innerScope.createRecursiveChildScope();
4334 }
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346 Set outerDecls = outerScope.getDeclaredVariables();
4347 Set outerRefs = outerScope.getReferencedVariables();
4348 Set innerDecls = innerScope.getDeclaredVariables();
4349 Set innerRefs = innerScope.getReferencedVariables();
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366 Set varSet = new HashSet();
4367 for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
4368 String var = (String) iter.next();
4369
4370 if (outerDecls.contains(var) && (isNotFieldOfOutermostClass(var))) {
4371 String type = getVariableType(var);
4372 vars.add(new Parameter(type, var));
4373 varSet.add(var);
4374 }
4375 }
4376 for (Iterator iter = outerRefs.iterator(); iter.hasNext();) {
4377 String var = (String) iter.next();
4378
4379 if (innerDecls.contains(var) && (isNotFieldOfOutermostClass(var)) && !varSet.contains(var)) {
4380 String type = getVariableType(var);
4381 vars.add(new Parameter(type, var));
4382 }
4383 }
4384
4385
4386 Parameter[] answer = new Parameter[vars.size()];
4387 vars.toArray(answer);
4388 return answer;
4389 }
4390
4391 protected boolean isNotFieldOfOutermostClass(String var) {
4392
4393 return getOutermostClass().getField(var) == null;
4394 }
4395
4396 protected void findMutableVariables() {
4397
4398
4399
4400
4401
4402
4403
4404
4405 VariableScope outerScope = getVariableScope();
4406
4407
4408 VariableScope innerScope = outerScope.createCompositeChildScope();
4409
4410 Set outerDecls = outerScope.getDeclaredVariables();
4411 Set outerRefs = outerScope.getReferencedVariables();
4412 Set innerDecls = innerScope.getDeclaredVariables();
4413 Set innerRefs = innerScope.getReferencedVariables();
4414
4415 mutableVars.clear();
4416
4417 for (Iterator iter = innerDecls.iterator(); iter.hasNext();) {
4418 String var = (String) iter.next();
4419 if ((outerDecls.contains(var) || outerRefs.contains(var)) && classNode.getField(var) == null) {
4420 mutableVars.add(var);
4421 }
4422 }
4423
4424
4425
4426 for (Iterator iter = innerRefs.iterator(); iter.hasNext();) {
4427 String var = (String) iter.next();
4428 if (outerDecls.contains(var) && classNode.getField(var) == null) {
4429 mutableVars.add(var);
4430 }
4431 }
4432
4433
4434
4435
4436
4437
4438
4439
4440 }
4441
4442 protected void addFieldsToVisitor(VariableScope scope) {
4443 for (Iterator iter = classNode.getFields().iterator(); iter.hasNext();) {
4444 FieldNode field = (FieldNode) iter.next();
4445 String name = field.getName();
4446
4447 scope.getDeclaredVariables().add(name);
4448 scope.getReferencedVariables().add(name);
4449 }
4450 }
4451
4452 private boolean isInnerClass() {
4453 return classNode instanceof InnerClassNode;
4454 }
4455
4456 protected String getVariableType(String name) {
4457 Variable variable = (Variable) variableStack.get(name);
4458 if (variable != null) {
4459 return variable.getTypeName();
4460 }
4461 return null;
4462 }
4463
4464 protected void resetVariableStack(Parameter[] parameters) {
4465 lastVariableIndex = -1;
4466 variableStack.clear();
4467
4468 scope = new BlockScope(null);
4469
4470
4471
4472 definingParameters = true;
4473 if (!isStaticMethod()) {
4474 defineVariable("this", classNode.getName()).getIndex();
4475 }
4476 for (int i = 0; i < parameters.length; i++) {
4477 Parameter parameter = parameters[i];
4478 String type = parameter.getType();
4479 Variable v = defineVariable(parameter.getName(), type);
4480 int idx = v.getIndex();
4481 if (BytecodeHelper.isPrimitiveType(type)) {
4482 helper.load(type, idx);
4483 helper.box(type);
4484 cv.visitVarInsn(ASTORE, idx);
4485 }
4486 }
4487 definingParameters = false;
4488 }
4489
4490 protected void popScope() {
4491 int lastID = scope.getFirstVariableIndex();
4492
4493 List removeKeys = new ArrayList();
4494 for (Iterator iter = variableStack.entrySet().iterator(); iter.hasNext();) {
4495 Map.Entry entry = (Map.Entry) iter.next();
4496 String name = (String) entry.getKey();
4497 Variable value = (Variable) entry.getValue();
4498 if (value.getIndex() >= lastID) {
4499 removeKeys.add(name);
4500 }
4501 }
4502 for (Iterator iter = removeKeys.iterator(); iter.hasNext();) {
4503 Variable v = (Variable) variableStack.remove(iter.next());
4504 if (CREATE_DEBUG_INFO) {
4505 if (v != null) {
4506 visitVariableEndLabel(v);
4507 cv.visitLocalVariable(
4508 v.getName(),
4509 BytecodeHelper.getTypeDescription(v.getTypeName()),
4510 v.getStartLabel(),
4511 v.getEndLabel(),
4512 v.getIndex()
4513 );
4514 }
4515 }
4516 }
4517 scope = scope.getParent();
4518 }
4519
4520 void removeVar(Variable v ) {
4521 variableStack.remove(v.getName());
4522 if (CREATE_DEBUG_INFO) {
4523 Label endl = new Label();
4524 cv.visitLabel(endl);
4525 cv.visitLocalVariable(
4526 v.getName(),
4527 BytecodeHelper.getTypeDescription(v.getTypeName()),
4528 v.getStartLabel(),
4529 endl,
4530 v.getIndex()
4531 );
4532 }
4533 }
4534 private void visitVariableEndLabel(Variable v) {
4535 if (CREATE_DEBUG_INFO) {
4536 if(v.getEndLabel() == null) {
4537 Label end = new Label();
4538 v.setEndLabel(end);
4539 }
4540 cv.visitLabel(v.getEndLabel());
4541 }
4542 }
4543
4544 protected void pushBlockScope() {
4545 pushBlockScope(true, true);
4546 }
4547
4548 /***
4549 * create a new scope. Set break/continue label if the canXXX parameter is true. Otherwise
4550 * inherit parent's label.
4551 * @param canContinue true if the start of the scope can take continue label
4552 * @param canBreak true if the end of the scope can take break label
4553 */
4554 protected void pushBlockScope(boolean canContinue, boolean canBreak) {
4555 BlockScope parentScope = scope;
4556 scope = new BlockScope(parentScope);
4557 scope.setContinueLabel(canContinue ? new Label() : (parentScope == null ? null : parentScope.getContinueLabel()));
4558 scope.setBreakLabel(canBreak? new Label() : (parentScope == null ? null : parentScope.getBreakLabel()));
4559 scope.setFirstVariableIndex(getNextVariableID());
4560 }
4561
4562 /***
4563 * Defines the given variable in scope and assigns it to the stack
4564 */
4565 protected Variable defineVariable(String name, String type) {
4566 return defineVariable(name, type, true);
4567 }
4568
4569 protected Variable defineVariable(String name, String type, boolean define) {
4570 return defineVariable(name, new Type(type), define);
4571 }
4572
4573 private Variable defineVariable(String name, Type type, boolean define) {
4574 Variable answer = (Variable) variableStack.get(name);
4575 if (answer == null) {
4576 lastVariableIndex = getNextVariableID();
4577 answer = new Variable(lastVariableIndex, type, name);
4578 if (mutableVars.contains(name)) {
4579 answer.setHolder(true);
4580 }
4581 variableStack.put(name, answer);
4582 Label startLabel = new Label();
4583 answer.setStartLabel(startLabel);
4584 if (define) {
4585 if (definingParameters) {
4586 if (answer.isHolder()) {
4587 cv.visitTypeInsn(NEW, "groovy/lang/Reference");
4588 cv.visitInsn(DUP);
4589 cv.visitVarInsn(ALOAD, lastVariableIndex);
4590 cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V");
4591 cv.visitVarInsn(ASTORE, lastVariableIndex);
4592 cv.visitLabel(startLabel);
4593 }
4594 }
4595 else {
4596
4597
4598 if (answer.isHolder() && !isInScriptBody()) {
4599
4600
4601 cv.visitTypeInsn(NEW, "groovy/lang/Reference");
4602 cv.visitInsn(DUP);
4603 cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "()V");
4604
4605 cv.visitVarInsn(ASTORE, lastVariableIndex);
4606 cv.visitLabel(startLabel);
4607
4608 }
4609 else {
4610 if (!leftHandExpression) {
4611 cv.visitInsn(ACONST_NULL);
4612 cv.visitVarInsn(ASTORE, lastVariableIndex);
4613 cv.visitLabel(startLabel);
4614 }
4615 }
4616 }
4617 }
4618 }
4619 return answer;
4620 }
4621
4622 private int getNextVariableID() {
4623
4624 return variableStack.size();
4625 }
4626
4627 /*** @return true if the given name is a local variable or a field */
4628 protected boolean isFieldOrVariable(String name) {
4629 return variableStack.containsKey(name) || classNode.getField(name) != null;
4630 }
4631
4632 protected Type checkValidType(Type type, ASTNode node, String message) {
4633 if (type.isDynamic()) {
4634 return type;
4635 }
4636 String name = checkValidType(type.getName(), node, message);
4637 if (type.getName().equals(name)) {
4638 return type;
4639 }
4640 return new Type(name);
4641 }
4642
4643 protected String checkValidType(String type, ASTNode node, String message) {
4644 if (type!= null && type.length() == 0)
4645 return "java.lang.Object";
4646 if (type.endsWith("[]")) {
4647 String postfix = "[]";
4648 String prefix = type.substring(0, type.length() - 2);
4649 return checkValidType(prefix, node, message) + postfix;
4650 }
4651 int idx = type.indexOf('$');
4652 if (idx > 0) {
4653 String postfix = type.substring(idx);
4654 String prefix = type.substring(0, idx);
4655 return checkValidType(prefix, node, message) + postfix;
4656 }
4657 if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) {
4658 return type;
4659 }
4660 String original = type;
4661 type = resolveClassName(type);
4662 if (type != null) {
4663 return type;
4664 }
4665
4666 throw new MissingClassException(original, node, message + " for class: " + classNode.getName());
4667 }
4668
4669 protected String resolveClassName(String type) {
4670 return classNode.resolveClassName(type);
4671 }
4672
4673 protected String createVariableName(String type) {
4674 return "__" + type + (++tempVariableNameCounter);
4675 }
4676
4677 /***
4678 * @return if the type of the expression can be determined at compile time
4679 * then this method returns the type - otherwise null
4680 */
4681 protected String getExpressionType(Expression expression) {
4682 if (isComparisonExpression(expression)) {
4683 return "boolean";
4684 }
4685 if (expression instanceof VariableExpression) {
4686 VariableExpression varExpr = (VariableExpression) expression;
4687 Variable variable = (Variable) variableStack.get(varExpr.getVariable());
4688 if (variable != null && !variable.isHolder()) {
4689 Type type = variable.getType();
4690 if (! type.isDynamic()) {
4691 return type.getName();
4692 }
4693 }
4694 }
4695 return null;
4696 }
4697
4698 /***
4699 * @return true if the value is an Integer, a Float, a Long, a Double or a
4700 * String .
4701 */
4702 protected static boolean isPrimitiveFieldType(String type) {
4703 return type.equals("java.lang.String")
4704 || type.equals("java.lang.Integer")
4705 || type.equals("java.lang.Double")
4706 || type.equals("java.lang.Long")
4707 || type.equals("java.lang.Float");
4708 }
4709
4710 protected boolean isInClosureConstructor() {
4711 return constructorNode != null
4712 && classNode.getOuterClass() != null
4713 && classNode.getSuperClass().equals(Closure.class.getName());
4714 }
4715
4716 protected boolean isStaticMethod() {
4717 if (methodNode == null) {
4718 return false;
4719 }
4720 return methodNode.isStatic();
4721 }
4722
4723 Map classCache = new HashMap();
4724 {
4725 classCache.put("int", Integer.TYPE);
4726 classCache.put("byte", Byte.TYPE);
4727 classCache.put("short", Short.TYPE);
4728 classCache.put("char", Character.TYPE);
4729 classCache.put("boolean", Boolean.TYPE);
4730 classCache.put("long", Long.TYPE);
4731 classCache.put("double", Double.TYPE);
4732 classCache.put("float", Float.TYPE);
4733 classCache.put("void", Void.TYPE);
4734 }
4735 /***
4736 * @return loads the given type name
4737 */
4738 protected Class loadClass(String name) {
4739
4740 if (name.equals(this.classNode.getName())) {
4741 return Object.class;
4742 }
4743
4744 if (name == null) {
4745 return null;
4746 }
4747 else if (name.length() == 0) {
4748 return Object.class;
4749 }
4750
4751 name = BytecodeHelper.formatNameForClassLoading(name);
4752
4753 try {
4754 Class cls = (Class)classCache.get(name);
4755 if (cls != null)
4756 return cls;
4757
4758 CompileUnit compileUnit = getCompileUnit();
4759 if (compileUnit != null) {
4760 cls = compileUnit.loadClass(name);
4761 classCache.put(name, cls);
4762 return cls;
4763 }
4764 else {
4765 throw new ClassGeneratorException("Could not load class: " + name);
4766 }
4767 }
4768 catch (ClassNotFoundException e) {
4769 throw new ClassGeneratorException("Error when compiling class: " + classNode.getName() + ". Reason: could not load class: " + name + " reason: " + e, e);
4770 }
4771 }
4772
4773 protected CompileUnit getCompileUnit() {
4774 CompileUnit answer = classNode.getCompileUnit();
4775 if (answer == null) {
4776 answer = context.getCompileUnit();
4777 }
4778 return answer;
4779 }
4780
4781 /***
4782 * attemtp to identify the exact runtime method call the expression is intended for, for possible early binding.
4783 * @param call
4784 */
4785 public void resolve(MethodCallExpression call) {
4786 if (call.isResolveFailed()) {
4787 return;
4788 }
4789 else if (call.isTypeResolved()) {
4790 return;
4791 }
4792
4793 Expression obj = call.getObjectExpression();
4794 String meth = call.getMethod();
4795 Class ownerClass = null;
4796 boolean isStaticCall = false;
4797 boolean isSuperCall = false;
4798
4799 List arglist = new ArrayList();
4800 Expression args = call.getArguments();
4801 if (args instanceof TupleExpression) {
4802 TupleExpression tupleExpression = (TupleExpression) args;
4803 List argexps = tupleExpression.getExpressions();
4804 for (int i = 0; i < argexps.size(); i++) {
4805 Expression expression = (Expression) argexps.get(i);
4806 Class cls = expression.getTypeClass();
4807 if (cls == null) {
4808 call.setResolveFailed(true);
4809 return ;
4810 }
4811 else {
4812 arglist.add(cls);
4813 }
4814 }
4815 } else if (args instanceof ClosureExpression) {
4816 call.setResolveFailed(true);
4817 return ;
4818 } else {
4819 call.setResolveFailed(true);
4820 return ;
4821 }
4822
4823
4824 Class[] argsArray = new Class[arglist.size()];
4825 arglist.toArray(argsArray);
4826
4827
4828 if (obj instanceof ClassExpression) {
4829
4830
4831
4832 ownerClass = obj.getTypeClass();
4833 isStaticCall = true;
4834 } else if (obj instanceof VariableExpression) {
4835 VariableExpression var = (VariableExpression) obj;
4836 if (var.getVariable().equals("this") && (methodNode == null? true : !methodNode.isStatic()) ) {
4837 isStaticCall = false;
4838 if (methodNode != null) {
4839 isStaticCall = Modifier.isStatic(methodNode.getModifiers());
4840 }
4841 MetaMethod mmeth = getMethodOfThisAndSuper(meth, argsArray, isStaticCall);
4842 if (mmeth != null) {
4843 call.setMethod(mmeth);
4844 return ;
4845 }
4846 else {
4847 call.setResolveFailed(true);
4848 return ;
4849 }
4850 }
4851 else if (var.getVariable().equals("super") ) {
4852 isSuperCall = true;
4853 ownerClass = var.getTypeClass();
4854 }
4855 else {
4856 ownerClass = var.getTypeClass();
4857 }
4858 }
4859 else
4860 ownerClass = obj.getTypeClass();
4861 if (ownerClass == null) {
4862 call.setResolveFailed(true);
4863 call.setFailure("target class is null");
4864 return ;
4865 }
4866 }
4867
4868 if (ownerClass == Object.class) {
4869 call.setResolveFailed(true);
4870 return ;
4871 }
4872 else if (ownerClass == null) {
4873 call.setResolveFailed(true);
4874 return ;
4875 }
4876 else
4877 if (!isSuperCall && !isStaticCall && GroovyObject.class.isAssignableFrom(ownerClass) ) {
4878 call.setResolveFailed(true);
4879 return ;
4880 }
4881 else
4882 if (ownerClass.isPrimitive()) {
4883 call.setResolveFailed(true);
4884 return ;
4885 }
4886
4887
4888
4889
4890 MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
4891 if (mmethod!= null) {
4892 call.setMethod(mmethod);
4893 }
4894 else {
4895 call.setResolveFailed(true);
4896 }
4897 return ;
4898 }
4899 /***
4900 * attemtp to identify the exact runtime method call the expression is intended for, for possible early binding.
4901 * @param call
4902 */
4903 public void resolve(ConstructorCallExpression call) {
4904 if (call.isResolveFailed()) {
4905 return ;
4906 }
4907 else if (call.isTypeResolved()) {
4908 return ;
4909 }
4910
4911 String declaredType = call.getTypeToSet();
4912 if (declaredType.equals(classNode.getName())) {
4913 call.setResolveFailed(true);
4914 call.setFailure("cannot resolve on the current class itself. ");
4915 return;
4916 }
4917 else {
4918 call.setType(declaredType);
4919 if (call.getTypeClass() == null) {
4920 call.setResolveFailed(true);
4921 call.setFailure("type name cannot be resolved. ");
4922 return;
4923 }
4924 }
4925
4926 boolean isSuperCall = false;
4927
4928 List arglist = new ArrayList();
4929 Expression args = call.getArguments();
4930 if (args instanceof TupleExpression) {
4931 TupleExpression tupleExpression = (TupleExpression) args;
4932 List argexps = tupleExpression.getExpressions();
4933 for (int i = 0; i < argexps.size(); i++) {
4934 Expression expression = (Expression) argexps.get(i);
4935 Class cls = expression.getTypeClass();
4936 if (cls == null) {
4937 call.setResolveFailed(true);
4938 return ;
4939 }
4940 else {
4941 arglist.add(cls);
4942 }
4943 }
4944 } else if (args instanceof ClosureExpression) {
4945 call.setResolveFailed(true);
4946 call.setFailure("don't know how to handle closure arg. ");
4947 return ;
4948 } else {
4949 call.setResolveFailed(true);
4950 call.setFailure("unknown arg type: " + args.getClass().getName());
4951 return ;
4952 }
4953
4954
4955 Class[] argsArray = new Class[arglist.size()];
4956 arglist.toArray(argsArray);
4957
4958 Class ownerClass = call.getTypeClass();
4959 if (ownerClass == null) {
4960 String typeName = call.getType();
4961 if (typeName.equals(this.classNode.getName())) {
4962
4963 call.setResolveFailed(true);
4964 call.setFailure("invoke constructor for this. no optimization for now");
4965 return ;
4966 }
4967 else {
4968 try {
4969 ownerClass = loadClass(typeName);
4970 if (ownerClass == null) {
4971 call.setResolveFailed(true);
4972 call.setFailure("owner class type is null. ");
4973 return ;
4974 }
4975 }
4976 catch (Throwable th) {
4977 call.setResolveFailed(true);
4978 call.setFailure("Exception: " + th);
4979 return ;
4980 }
4981 }
4982 }
4983
4984 if (ownerClass == Object.class) {
4985 call.setResolveFailed(true);
4986 call.setFailure("owner class type java.lang.Object. use late binding for dynamic types");
4987 return ;
4988 }
4989 else if (ownerClass == null) {
4990 call.setResolveFailed(true);
4991 call.setFailure("owner class type is null. use dynamic dispatching for GroovyObject");
4992 return;
4993 }
4994
4995
4996
4997
4998
4999 else if (ownerClass.isPrimitive()) {
5000 call.setResolveFailed(true);
5001 throwException("The owner of the constructor is primitive.");
5002 return ;
5003 }
5004
5005 Constructor ctor = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedConstructor(ownerClass, argsArray);
5006 if (ctor!= null) {
5007 call.setConstructor(ctor);
5008 }
5009 else {
5010 call.setResolveFailed(true);
5011 }
5012 return ;
5013 }
5014
5015 public void resolve(PropertyExpression propertyExpression) {
5016 if (propertyExpression.getTypeClass() != null)
5017 return ;
5018 if (propertyExpression.isResolveFailed())
5019 return ;
5020
5021 Expression ownerExp = propertyExpression.getObjectExpression();
5022 Class ownerClass = ownerExp.getTypeClass();
5023 String propName = propertyExpression.getProperty();
5024 if (propName.equals("class")) {
5025 propertyExpression.setTypeClass(Class.class);
5026 return ;
5027 }
5028
5029
5030 if (ownerClass != null && ownerClass.isArray() && propName.equals("length")) {
5031 propertyExpression.setTypeClass(int.class);
5032 return;
5033 }
5034
5035 if (isThisExpression(ownerExp)) {
5036
5037 if (classNode == null) {
5038 propertyExpression.setResolveFailed(true);
5039 return ;
5040 }
5041 FieldNode field = null;
5042 ownerExp.setType(classNode.getName());
5043 try {
5044 if( (field = classNode.getField(propName)) != null ) {
5045
5046
5047
5048
5049 propertyExpression.setResolveFailed(true);
5050 propertyExpression.setFailure("local property access. to be determined in the future.");
5051 return ;
5052 } else {
5053
5054
5055 String[] interfaces = classNode.getInterfaces();
5056 String[] supers = new String[interfaces.length + 1];
5057
5058 int i = 0;
5059 for (; i < interfaces.length; i++) {
5060 supers[i] = interfaces[i];
5061 }
5062 supers[i] = classNode.getSuperClass();
5063 for (int j = 0; j < supers.length; j++) {
5064 String aSuper = supers[j];
5065 Class superClass = loadClass(aSuper);
5066 Field fld = superClass.getDeclaredField(propName);
5067 if (fld != null && !Modifier.isPrivate(fld.getModifiers())) {
5068 propertyExpression.setField(fld);
5069 return ;
5070 }
5071 }
5072 }
5073 } catch (Exception e) {
5074 propertyExpression.setResolveFailed(true);
5075 propertyExpression.setFailure(e.getMessage());
5076 return ;
5077 }
5078 }
5079 else if (ownerExp instanceof ClassExpression) {
5080 if (ownerClass != null) {
5081 Field fld = null;
5082 try {
5083 fld = ownerClass.getDeclaredField(propName);
5084 if (!Modifier.isPrivate(fld.getModifiers())) {
5085 propertyExpression.setField(fld);
5086 return ;
5087 }
5088 } catch (NoSuchFieldException e) {
5089 propertyExpression.setResolveFailed(true);
5090 return ;
5091 }
5092 }
5093 }
5094 else {
5095 if (ownerClass != null) {
5096 propertyExpression.setResolveFailed(true);
5097 Field fld = null;
5098 try {
5099 fld = ownerClass.getDeclaredField(propName);
5100 } catch (NoSuchFieldException e) {}
5101
5102 if (fld != null && Modifier.isPublic(fld.getModifiers())) {
5103 propertyExpression.setField(fld);
5104 }
5105
5106
5107 String getterName = "get" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
5108 String setterName = "set" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
5109
5110 Method[] meths = ownerClass.getMethods();
5111 for (int i = 0; i < meths.length; i++) {
5112 Method method = meths[i];
5113 String methName =method.getName();
5114 Class[] paramClasses = method.getParameterTypes();
5115 if (methName.equals(getterName) && paramClasses.length == 0) {
5116 propertyExpression.setGetter(method);
5117 } else if (methName.equals(setterName) && paramClasses.length == 1) {
5118 propertyExpression.setSetter(method);
5119 }
5120 }
5121 return ;
5122 }
5123 }
5124 propertyExpression.setResolveFailed(true);
5125 return ;
5126 }
5127 /*** search in the current classNode and super class for matching method */
5128 private MetaMethod getMethodOfThisAndSuper(String methName, Class[] argsArray, boolean isStaticCall) {
5129 MethodNode candidate = null;
5130 List meths = classNode.getMethods();
5131 Class[] candidateParamClasses = null;
5132 for (int i = 0; i < meths.size(); i++) {
5133 MethodNode meth = (MethodNode) meths.get(i);
5134 if (meth.getName().equals(methName)) {
5135 Parameter[] params = meth.getParameters();
5136 if (params.length == argsArray.length) {
5137 Class[] paramClasses = new Class[params.length];
5138 for (int j = 0; j < params.length; j++) {
5139 Parameter param = params[j];
5140 String type = param.getType();
5141 Class paramClass = null;
5142 try {
5143 paramClass = loadClass(type);
5144 } catch (Exception e) {
5145 log.warning(e.getMessage());
5146 return null;
5147 }
5148 paramClasses[j] = paramClass;
5149 }
5150 if (MetaClass.isValidMethod(paramClasses, argsArray, false)) {
5151 candidateParamClasses = paramClasses;
5152 candidate = meth;
5153 break;
5154 }
5155 else {
5156 if (MetaClass.isValidMethod(paramClasses, argsArray, true)){
5157 candidateParamClasses = paramClasses;
5158 candidate = meth;
5159 break;
5160 }
5161 }
5162 }
5163 }
5164 }
5165
5166 if (candidate != null && candidateParamClasses != null) {
5167
5168 try {
5169 return new MetaMethod(methName, null, candidateParamClasses, loadClass(candidate.getReturnType()), candidate.getModifiers());
5170 } catch (Exception e) {
5171 log.warning(e.getMessage());
5172 return null;
5173 }
5174 }
5175 else {
5176
5177 Class superClass = null;
5178 try {
5179 superClass = loadClass(classNode.getSuperClass());
5180 }
5181 catch(Exception e) {
5182
5183 log.warning(e.getMessage());
5184 }
5185
5186 if (superClass != null ) {
5187 MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(superClass, methName, argsArray, isStaticCall);
5188 if (mmethod == null)
5189 return null;
5190 int modies = mmethod.getModifiers();
5191 if (Modifier.isPrivate(modies)) {
5192 return null;
5193 }
5194 else if(modies == 0) {
5195
5196 int pThis = classNode.getName().lastIndexOf(".");
5197 String packageNameThis = pThis > 0? classNode.getName().substring(0, pThis) : "";
5198
5199 int pSuper = classNode.getSuperClass().lastIndexOf(".");
5200 String packageNameSuper = pSuper > 0? classNode.getSuperClass().substring(0, pSuper) : "";
5201 if (packageNameThis.equals(packageNameSuper)) {
5202 return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers());
5203 }
5204 else {
5205 return null;
5206 }
5207 }
5208 else {
5209
5210 return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers());
5211 }
5212 }
5213 return null;
5214 }
5215 }
5216
5217
5218 /***
5219 * to find out the real type of a Variable Object
5220 */
5221 public void resolve(VariableExpression expression) {
5222
5223 String variableName = expression.getVariable();
5224
5225
5226
5227
5228
5229
5230
5231 if (isStaticMethod() && variableName.equals("this")) {
5232 expression.setTypeClass(Class.class);
5233 return;
5234 } else if (variableName.equals("super")) {
5235 if (isStaticMethod() ) {
5236 expression.setTypeClass(Class.class);
5237 return;
5238 }
5239 else {
5240 try {
5241 Class cls = loadClass(classNode.getSuperClass());
5242 expression.setTypeClass(cls);
5243 return ;
5244 }
5245 catch (Exception e) {
5246 expression.setResolveFailed(true);
5247 expression.setFailure(e.getMessage());
5248 return ;
5249 }
5250 }
5251 } else if (variableName.equals("this")){
5252 return ;
5253 } else {
5254
5255
5256
5257
5258 }
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272 boolean handled = false;
5273 Variable variable = (Variable)variableStack.get( variableName );
5274
5275 try {
5276 if( variable != null ) {
5277 Type t = variable.getType();
5278 if (t.getRealName().length() == 0) {
5279 String tname = t.getName();
5280 if (tname.endsWith("[]")) {
5281 expression.setResolveFailed(true);
5282 expression.setFailure("array type to be supported later");
5283 return ;
5284 }
5285 else if (tname.equals(classNode.getName())){
5286 expression.setResolveFailed(true);
5287 return ;
5288 }
5289 else if (classNode.getOuterClass() != null && tname.equals(classNode.getOuterClass().getName())){
5290 expression.setResolveFailed(true);
5291 return ;
5292 }
5293 Class cls = loadClass(tname);
5294 expression.setTypeClass(cls);
5295 expression.setDynamic(t.isDynamic());
5296 return ;
5297 } else {
5298 String tname = t.getRealName();
5299 if (tname.endsWith("[]")) {
5300 expression.setResolveFailed(true);
5301 expression.setFailure("array type to be supported later");
5302 return ;
5303 }
5304 Class cls = loadClass(tname);
5305 expression.setTypeClass(cls);
5306 expression.setDynamic(t.isDynamic());
5307 return ;
5308 }
5309
5310
5311
5312
5313
5314
5315
5316
5317 } else {
5318 int steps = 0;
5319 ClassNode currentClassNode = classNode;
5320 FieldNode field = null;
5321 do {
5322 if( (field = currentClassNode.getField(variableName)) != null ) {
5323 if (methodNode == null || !methodNode.isStatic() || field.isStatic() ) {
5324 if (
5325 expression.setResolveFailed(true);
5326 expression.setFailure("reference type to be supported later");
5327 return ;
5328 } else {
5329 String type = field.getType();
5330 Class cls = loadClass(type);
5331 expression.setTypeClass(cls);
5332 expression.setDynamic(field.isDynamicType());
5333 return ;
5334 }
5335 }
5336 }
5337 steps++;
5338 } while( (currentClassNode = currentClassNode.getOuterClass()) != null );
5339 }
5340
5341
5342
5343
5344 String variableType = expression.getType();
5345 if (variableType.length() > 0 && !variableType.equals("java.lang.Object")) {
5346 Class cls = loadClass(variableType);
5347 expression.setTypeClass(cls);
5348 return ;
5349 }
5350 } catch (Exception e) {
5351 log.warning(e.getMessage());
5352 expression.setResolveFailed(true);
5353 expression.setFailure(e.getMessage());
5354 }
5355 return ;
5356 }
5357
5358 public MetaMethod resolve(StaticMethodCallExpression staticCall) {
5359 if (staticCall.isResolveFailed()) {
5360 return null;
5361 }
5362 else if (staticCall.isTypeResolved()) {
5363 return staticCall.getMetaMethod();
5364 }
5365
5366 String ownerTypeName = staticCall.getOwnerType();
5367 String meth = staticCall.getMethod();
5368 Class ownerClass = null;
5369 try {
5370 ownerClass = loadClass(ownerTypeName);
5371 } catch (Exception e) {
5372 staticCall.setResolveFailed(true);
5373 staticCall.setFailure("Owner type could not be resolved: " + e);
5374 return null;
5375 }
5376
5377 boolean isStaticCall = true;
5378 boolean isSuperCall = false;
5379
5380 List arglist = new ArrayList();
5381 Expression args = staticCall.getArguments();
5382 if (args instanceof TupleExpression) {
5383 TupleExpression tupleExpression = (TupleExpression) args;
5384 List argexps = tupleExpression.getExpressions();
5385 for (int i = 0; i < argexps.size(); i++) {
5386 Expression expression = (Expression) argexps.get(i);
5387 Class cls = expression.getTypeClass();
5388 if (cls == null) {
5389 staticCall.setResolveFailed(true);
5390 staticCall.setFailure("Argument type could not be resolved.");
5391 return null;
5392 }
5393 else {
5394 arglist.add(cls);
5395 }
5396 }
5397 } else if (args instanceof ClosureExpression) {
5398 staticCall.setResolveFailed(true);
5399 staticCall.setFailure("Resolving on Closure call not implemented yet. ");
5400 return null;
5401 } else {
5402 staticCall.setResolveFailed(true);
5403 staticCall.setFailure("Unknown argument expression type.");
5404 return null;
5405 }
5406
5407
5408 Class[] argsArray = new Class[arglist.size()];
5409 arglist.toArray(argsArray);
5410
5411 if (ownerClass == Object.class) {
5412 staticCall.setResolveFailed(true);
5413 staticCall.setFailure("Resolving on java.lang.Object static call not supported. ");
5414 return null;
5415 }
5416 else if (ownerClass == null) {
5417 staticCall.setResolveFailed(true);
5418 staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. ");
5419 return null;
5420 }
5421 else if (!isSuperCall && GroovyObject.class.isAssignableFrom(ownerClass) ) {
5422 staticCall.setResolveFailed(true);
5423 staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. ");
5424 return null;
5425 }
5426 else if (ownerClass.isPrimitive()) {
5427 staticCall.setResolveFailed(true);
5428 staticCall.setFailure("Could not use primitive as method owner");
5429 return null;
5430 }
5431
5432
5433
5434
5435 MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall);
5436 if (mmethod!= null) {
5437 staticCall.setMetaMethod(mmethod);
5438 }
5439 else {
5440 staticCall.setResolveFailed(true);
5441 staticCall.setFailure("Could not find MetaMethod in the MetaClass.");
5442 }
5443 return mmethod;
5444 }
5445
5446
5447
5448 private static Object asType(Object object, Class type) {
5449 if (object == null) {
5450 return null;
5451 }
5452 if (type.isInstance(object)) {
5453 return object;
5454 }
5455 if (type.equals(String.class)) {
5456 return object.toString();
5457 }
5458 if (type.equals(Character.class)) {
5459 if (object instanceof Number) {
5460 return asCharacter((Number) object);
5461 }
5462 else {
5463 String text = object.toString();
5464 if (text.length() == 1) {
5465 return new Character(text.charAt(0));
5466 }
5467 else {
5468 throw new ClassCastException("Cannot cast: " + text + " to a Character");
5469 }
5470 }
5471 }
5472 if (Number.class.isAssignableFrom(type)) {
5473 if (object instanceof Character) {
5474 return new Integer(((Character) object).charValue());
5475 }
5476 else if (object instanceof String) {
5477 String c = (String) object;
5478 if (c.length() == 1) {
5479 return new Integer(c.charAt(0));
5480 }
5481 else {
5482 throw new ClassCastException("Cannot cast: '" + c + "' to an Integer");
5483 }
5484 }
5485 }
5486 if (object instanceof Number) {
5487 Number n = (Number) object;
5488 if (type.isPrimitive()) {
5489 if (type == byte.class) {
5490 return new Byte(n.byteValue());
5491 }
5492 if (type == char.class) {
5493 return new Character((char) n.intValue());
5494 }
5495 if (type == short.class) {
5496 return new Short(n.shortValue());
5497 }
5498 if (type == int.class) {
5499 return new Integer(n.intValue());
5500 }
5501 if (type == long.class) {
5502 return new Long(n.longValue());
5503 }
5504 if (type == float.class) {
5505 return new Float(n.floatValue());
5506 }
5507 if (type == double.class) {
5508 Double answer = new Double(n.doubleValue());
5509
5510 if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
5511 || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
5512 throw new GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
5513 +" value "+n+" to double failed. Value is out of range.");
5514 }
5515 return answer;
5516 }
5517 }
5518 else {
5519 if (Number.class.isAssignableFrom(type)) {
5520 if (type == Byte.class) {
5521 return new Byte(n.byteValue());
5522 }
5523 if (type == Character.class) {
5524 return new Character((char) n.intValue());
5525 }
5526 if (type == Short.class) {
5527 return new Short(n.shortValue());
5528 }
5529 if (type == Integer.class) {
5530 return new Integer(n.intValue());
5531 }
5532 if (type == Long.class) {
5533 return new Long(n.longValue());
5534 }
5535 if (type == Float.class) {
5536 return new Float(n.floatValue());
5537 }
5538 if (type == Double.class) {
5539 Double answer = new Double(n.doubleValue());
5540
5541 if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
5542 || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
5543 throw new GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
5544 +" value "+n+" to double failed. Value is out of range.");
5545 }
5546 return answer;
5547 }
5548
5549 }
5550 }
5551 }
5552 if (type == Boolean.class) {
5553 return asBool(object) ? Boolean.TRUE : Boolean.FALSE;
5554 }
5555 return object;
5556 }
5557
5558 private static boolean asBool(Object object) {
5559 if (object instanceof Boolean) {
5560 Boolean booleanValue = (Boolean) object;
5561 return booleanValue.booleanValue();
5562 }
5563 else if (object instanceof Matcher) {
5564 Matcher matcher = (Matcher) object;
5565 RegexSupport.setLastMatcher(matcher);
5566 return matcher.find();
5567 }
5568 else if (object instanceof Collection) {
5569 Collection collection = (Collection) object;
5570 return !collection.isEmpty();
5571 }
5572 else if (object instanceof Number) {
5573 Number n = (Number) object;
5574 return n.intValue() != 0;
5575 }
5576 else {
5577 return object != null;
5578 }
5579 }
5580 private static Character asCharacter(Number value) {
5581 return new Character((char) value.intValue());
5582 }
5583
5584 private static Character asCharacter(String text) {
5585 return new Character(text.charAt(0));
5586 }
5587 }