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