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