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