Source Code Cross Referenced for AsmClassGenerator.java in  » Scripting » groovy-1.0 » org » codehaus » groovy » classgen » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » groovy 1.0 » org.codehaus.groovy.classgen 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:        $Id: AsmClassGenerator.java 4598 2006-12-22 20:21:21Z blackdrag $
0003:
0004:        Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
0005:
0006:        Redistribution and use of this software and associated documentation
0007:        ("Software"), with or without modification, are permitted provided
0008:        that the following conditions are met:
0009:
0010:        1. Redistributions of source code must retain copyright
0011:           statements and notices.  Redistributions must also contain a
0012:           copy of this document.
0013:
0014:        2. Redistributions in binary form must reproduce the
0015:           above copyright notice, this list of conditions and the
0016:           following disclaimer in the documentation and/or other
0017:           materials provided with the distribution.
0018:
0019:        3. The name "groovy" must not be used to endorse or promote
0020:           products derived from this Software without prior written
0021:           permission of The Codehaus.  For written permission,
0022:           please contact info@codehaus.org.
0023:
0024:        4. Products derived from this Software may not be called "groovy"
0025:           nor may "groovy" appear in their names without prior written
0026:           permission of The Codehaus. "groovy" is a registered
0027:           trademark of The Codehaus.
0028:
0029:        5. Due credit should be given to The Codehaus -
0030:           http://groovy.codehaus.org/
0031:
0032:        THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
0033:        ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
0034:        NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
0035:        FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
0036:        THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
0037:        INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0038:        (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
0039:        SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0040:        HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
0041:        STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0042:        ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
0043:        OF THE POSSIBILITY OF SUCH DAMAGE.
0044:         */
0045:
0046:        package org.codehaus.groovy.classgen;
0047:
0048:        import groovy.lang.GroovyObject;
0049:        import groovy.lang.GroovyRuntimeException;
0050:
0051:        import java.util.ArrayList;
0052:        import java.util.Collections;
0053:        import java.util.Comparator;
0054:        import java.util.HashSet;
0055:        import java.util.Iterator;
0056:        import java.util.LinkedList;
0057:        import java.util.List;
0058:        import java.util.Map;
0059:        import java.util.Set;
0060:        import java.util.logging.Logger;
0061:
0062:        import org.codehaus.groovy.GroovyBugError;
0063:        import org.codehaus.groovy.ast.ASTNode;
0064:        import org.codehaus.groovy.ast.AnnotatedNode;
0065:        import org.codehaus.groovy.ast.AnnotationNode;
0066:        import org.codehaus.groovy.ast.ClassHelper;
0067:        import org.codehaus.groovy.ast.ClassNode;
0068:        import org.codehaus.groovy.ast.CompileUnit;
0069:        import org.codehaus.groovy.ast.ConstructorNode;
0070:        import org.codehaus.groovy.ast.FieldNode;
0071:        import org.codehaus.groovy.ast.InnerClassNode;
0072:        import org.codehaus.groovy.ast.MethodNode;
0073:        import org.codehaus.groovy.ast.Parameter;
0074:        import org.codehaus.groovy.ast.PropertyNode;
0075:        import org.codehaus.groovy.ast.VariableScope;
0076:        import org.codehaus.groovy.ast.expr.ArgumentListExpression;
0077:        import org.codehaus.groovy.ast.expr.ArrayExpression;
0078:        import org.codehaus.groovy.ast.expr.AttributeExpression;
0079:        import org.codehaus.groovy.ast.expr.BinaryExpression;
0080:        import org.codehaus.groovy.ast.expr.BitwiseNegExpression;
0081:        import org.codehaus.groovy.ast.expr.BooleanExpression;
0082:        import org.codehaus.groovy.ast.expr.CastExpression;
0083:        import org.codehaus.groovy.ast.expr.ClassExpression;
0084:        import org.codehaus.groovy.ast.expr.ClosureExpression;
0085:        import org.codehaus.groovy.ast.expr.ConstantExpression;
0086:        import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
0087:        import org.codehaus.groovy.ast.expr.DeclarationExpression;
0088:        import org.codehaus.groovy.ast.expr.Expression;
0089:        import org.codehaus.groovy.ast.expr.ExpressionTransformer;
0090:        import org.codehaus.groovy.ast.expr.FieldExpression;
0091:        import org.codehaus.groovy.ast.expr.GStringExpression;
0092:        import org.codehaus.groovy.ast.expr.ListExpression;
0093:        import org.codehaus.groovy.ast.expr.MapEntryExpression;
0094:        import org.codehaus.groovy.ast.expr.MapExpression;
0095:        import org.codehaus.groovy.ast.expr.MethodCallExpression;
0096:        import org.codehaus.groovy.ast.expr.MethodPointerExpression;
0097:        import org.codehaus.groovy.ast.expr.NegationExpression;
0098:        import org.codehaus.groovy.ast.expr.NotExpression;
0099:        import org.codehaus.groovy.ast.expr.PostfixExpression;
0100:        import org.codehaus.groovy.ast.expr.PrefixExpression;
0101:        import org.codehaus.groovy.ast.expr.PropertyExpression;
0102:        import org.codehaus.groovy.ast.expr.RangeExpression;
0103:        import org.codehaus.groovy.ast.expr.RegexExpression;
0104:        import org.codehaus.groovy.ast.expr.SpreadExpression;
0105:        import org.codehaus.groovy.ast.expr.SpreadMapExpression;
0106:        import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
0107:        import org.codehaus.groovy.ast.expr.TernaryExpression;
0108:        import org.codehaus.groovy.ast.expr.TupleExpression;
0109:        import org.codehaus.groovy.ast.expr.VariableExpression;
0110:        import org.codehaus.groovy.ast.stmt.AssertStatement;
0111:        import org.codehaus.groovy.ast.stmt.BlockStatement;
0112:        import org.codehaus.groovy.ast.stmt.BreakStatement;
0113:        import org.codehaus.groovy.ast.stmt.CaseStatement;
0114:        import org.codehaus.groovy.ast.stmt.CatchStatement;
0115:        import org.codehaus.groovy.ast.stmt.ContinueStatement;
0116:        import org.codehaus.groovy.ast.stmt.DoWhileStatement;
0117:        import org.codehaus.groovy.ast.stmt.ExpressionStatement;
0118:        import org.codehaus.groovy.ast.stmt.ForStatement;
0119:        import org.codehaus.groovy.ast.stmt.IfStatement;
0120:        import org.codehaus.groovy.ast.stmt.ReturnStatement;
0121:        import org.codehaus.groovy.ast.stmt.Statement;
0122:        import org.codehaus.groovy.ast.stmt.SwitchStatement;
0123:        import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
0124:        import org.codehaus.groovy.ast.stmt.ThrowStatement;
0125:        import org.codehaus.groovy.ast.stmt.TryCatchStatement;
0126:        import org.codehaus.groovy.ast.stmt.WhileStatement;
0127:        import org.codehaus.groovy.control.SourceUnit;
0128:        import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
0129:        import org.codehaus.groovy.syntax.RuntimeParserException;
0130:        import org.codehaus.groovy.syntax.Types;
0131:        import org.objectweb.asm.AnnotationVisitor;
0132:        import org.objectweb.asm.ClassVisitor;
0133:        import org.objectweb.asm.ClassWriter;
0134:        import org.objectweb.asm.Label;
0135:        import org.objectweb.asm.MethodVisitor;
0136:        import org.objectweb.asm.Opcodes;
0137:
0138:        /**
0139:         * Generates Java class versions of Groovy classes using ASM.
0140:         *
0141:         * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
0142:         * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
0143:         * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
0144:         *
0145:         * @version $Revision: 4598 $
0146:         */
0147:        public class AsmClassGenerator extends ClassGenerator {
0148:
0149:            private Logger log = Logger.getLogger(getClass().getName());
0150:
0151:            private ClassVisitor cw;
0152:            private MethodVisitor cv;
0153:            private GeneratorContext context;
0154:
0155:            private String sourceFile;
0156:
0157:            // current class details
0158:            private ClassNode classNode;
0159:            private ClassNode outermostClass;
0160:            private String internalClassName;
0161:            private String internalBaseClassName;
0162:
0163:            /** maps the variable names to the JVM indices */
0164:            private CompileStack compileStack;
0165:
0166:            /** have we output a return statement yet */
0167:            private boolean outputReturn;
0168:
0169:            /** are we on the left or right of an expression */
0170:            private boolean leftHandExpression = false;
0171:            /**
0172:             * Notes for leftHandExpression:
0173:             * The default is false, that menas the right side is default.
0174:             * The right side means that variables are read and not written.
0175:             * Any change of leftHandExpression to true, should be made carefully.
0176:             * If such a change is needed, then it should be set to false as soon as
0177:             * possible, but most important in the same method. Setting 
0178:             * leftHandExpression to false is needed for writing variables.
0179:             */
0180:
0181:            // method invocation
0182:            MethodCallerMultiAdapter invokeMethodOnCurrent = MethodCallerMultiAdapter
0183:                    .newStatic(ScriptBytecodeAdapter.class,
0184:                            "invokeMethodOnCurrent", true, false);
0185:            MethodCallerMultiAdapter invokeMethodOnSuper = MethodCallerMultiAdapter
0186:                    .newStatic(ScriptBytecodeAdapter.class,
0187:                            "invokeMethodOnSuper", true, false);
0188:            MethodCallerMultiAdapter invokeMethod = MethodCallerMultiAdapter
0189:                    .newStatic(ScriptBytecodeAdapter.class, "invokeMethod",
0190:                            true, false);
0191:            MethodCallerMultiAdapter invokeStaticMethod = MethodCallerMultiAdapter
0192:                    .newStatic(ScriptBytecodeAdapter.class,
0193:                            "invokeStaticMethod", true, true);
0194:            MethodCallerMultiAdapter invokeNew = MethodCallerMultiAdapter
0195:                    .newStatic(ScriptBytecodeAdapter.class, "invokeNew", true,
0196:                            true);
0197:
0198:            // fields & properties
0199:            MethodCallerMultiAdapter setField = MethodCallerMultiAdapter
0200:                    .newStatic(ScriptBytecodeAdapter.class, "setField", false,
0201:                            false);
0202:            MethodCallerMultiAdapter getField = MethodCallerMultiAdapter
0203:                    .newStatic(ScriptBytecodeAdapter.class, "getField", false,
0204:                            false);
0205:            MethodCallerMultiAdapter setGroovyObjectField = MethodCallerMultiAdapter
0206:                    .newStatic(ScriptBytecodeAdapter.class,
0207:                            "setGroovyObjectField", false, false);
0208:            MethodCallerMultiAdapter getGroovyObjectField = MethodCallerMultiAdapter
0209:                    .newStatic(ScriptBytecodeAdapter.class,
0210:                            "getGroovyObjectField", false, false);
0211:            MethodCallerMultiAdapter setFieldOnSuper = MethodCallerMultiAdapter
0212:                    .newStatic(ScriptBytecodeAdapter.class, "setFieldOnSuper",
0213:                            false, false);
0214:            MethodCallerMultiAdapter getFieldOnSuper = MethodCallerMultiAdapter
0215:                    .newStatic(ScriptBytecodeAdapter.class, "getFieldOnSuper",
0216:                            false, false);
0217:
0218:            MethodCallerMultiAdapter setProperty = MethodCallerMultiAdapter
0219:                    .newStatic(ScriptBytecodeAdapter.class, "setProperty",
0220:                            false, false);
0221:            MethodCallerMultiAdapter getProperty = MethodCallerMultiAdapter
0222:                    .newStatic(ScriptBytecodeAdapter.class, "getProperty",
0223:                            false, false);
0224:            MethodCallerMultiAdapter setGroovyObjectProperty = MethodCallerMultiAdapter
0225:                    .newStatic(ScriptBytecodeAdapter.class,
0226:                            "setGroovyObjectProperty", false, false);
0227:            MethodCallerMultiAdapter getGroovyObjectProperty = MethodCallerMultiAdapter
0228:                    .newStatic(ScriptBytecodeAdapter.class,
0229:                            "getGroovyObjectProperty", false, false);
0230:            MethodCallerMultiAdapter setPropertyOnSuper = MethodCallerMultiAdapter
0231:                    .newStatic(ScriptBytecodeAdapter.class,
0232:                            "setPropertyOnSuper", false, false);
0233:            MethodCallerMultiAdapter getPropertyOnSuper = MethodCallerMultiAdapter
0234:                    .newStatic(ScriptBytecodeAdapter.class,
0235:                            "getPropertyOnSuper", false, false);
0236:
0237:            // iterator
0238:            MethodCaller iteratorNextMethod = MethodCaller.newInterface(
0239:                    Iterator.class, "next");
0240:            MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(
0241:                    Iterator.class, "hasNext");
0242:            // assert
0243:            MethodCaller assertFailedMethod = MethodCaller.newStatic(
0244:                    ScriptBytecodeAdapter.class, "assertFailed");
0245:            // isCase
0246:            MethodCaller isCaseMethod = MethodCaller.newStatic(
0247:                    ScriptBytecodeAdapter.class, "isCase");
0248:            //compare
0249:            MethodCaller compareIdenticalMethod = MethodCaller.newStatic(
0250:                    ScriptBytecodeAdapter.class, "compareIdentical");
0251:            MethodCaller compareEqualMethod = MethodCaller.newStatic(
0252:                    ScriptBytecodeAdapter.class, "compareEqual");
0253:            MethodCaller compareNotEqualMethod = MethodCaller.newStatic(
0254:                    ScriptBytecodeAdapter.class, "compareNotEqual");
0255:            MethodCaller compareToMethod = MethodCaller.newStatic(
0256:                    ScriptBytecodeAdapter.class, "compareTo");
0257:            MethodCaller compareLessThanMethod = MethodCaller.newStatic(
0258:                    ScriptBytecodeAdapter.class, "compareLessThan");
0259:            MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(
0260:                    ScriptBytecodeAdapter.class, "compareLessThanEqual");
0261:            MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(
0262:                    ScriptBytecodeAdapter.class, "compareGreaterThan");
0263:            MethodCaller compareGreaterThanEqualMethod = MethodCaller
0264:                    .newStatic(ScriptBytecodeAdapter.class,
0265:                            "compareGreaterThanEqual");
0266:            //regexpr
0267:            MethodCaller findRegexMethod = MethodCaller.newStatic(
0268:                    ScriptBytecodeAdapter.class, "findRegex");
0269:            MethodCaller matchRegexMethod = MethodCaller.newStatic(
0270:                    ScriptBytecodeAdapter.class, "matchRegex");
0271:            MethodCaller regexPattern = MethodCaller.newStatic(
0272:                    ScriptBytecodeAdapter.class, "regexPattern");
0273:            // spread expressions
0274:            MethodCaller spreadMap = MethodCaller.newStatic(
0275:                    ScriptBytecodeAdapter.class, "spreadMap");
0276:            MethodCaller despreadList = MethodCaller.newStatic(
0277:                    ScriptBytecodeAdapter.class, "despreadList");
0278:            // Closure
0279:            MethodCaller getMethodPointer = MethodCaller.newStatic(
0280:                    ScriptBytecodeAdapter.class, "getMethodPointer");
0281:            MethodCaller invokeClosureMethod = MethodCaller.newStatic(
0282:                    ScriptBytecodeAdapter.class, "invokeClosure");
0283:            //negation
0284:            MethodCaller negation = MethodCaller.newStatic(
0285:                    ScriptBytecodeAdapter.class, "negate");
0286:            MethodCaller bitNegation = MethodCaller.newStatic(
0287:                    ScriptBytecodeAdapter.class, "bitNegate");
0288:
0289:            // type converions
0290:            MethodCaller asTypeMethod = MethodCaller.newStatic(
0291:                    ScriptBytecodeAdapter.class, "asType");
0292:            MethodCaller castToTypeMethod = MethodCaller.newStatic(
0293:                    ScriptBytecodeAdapter.class, "castToType");
0294:            MethodCaller createListMethod = MethodCaller.newStatic(
0295:                    ScriptBytecodeAdapter.class, "createList");
0296:            MethodCaller createTupleMethod = MethodCaller.newStatic(
0297:                    ScriptBytecodeAdapter.class, "createTuple");
0298:            MethodCaller createMapMethod = MethodCaller.newStatic(
0299:                    ScriptBytecodeAdapter.class, "createMap");
0300:            MethodCaller createRangeMethod = MethodCaller.newStatic(
0301:                    ScriptBytecodeAdapter.class, "createRange");
0302:
0303:            // wrapper creation methods
0304:            MethodCaller createPojoWrapperMethod = MethodCaller.newStatic(
0305:                    ScriptBytecodeAdapter.class, "createPojoWrapper");
0306:            MethodCaller createGroovyObjectWrapperMethod = MethodCaller
0307:                    .newStatic(ScriptBytecodeAdapter.class,
0308:                            "createGroovyObjectWrapper");
0309:
0310:            // constructor calls with this() and super()
0311:            MethodCaller selectConstructorAndTransformArguments = MethodCaller
0312:                    .newStatic(ScriptBytecodeAdapter.class,
0313:                            "selectConstructorAndTransformArguments");
0314:
0315:            // exception blocks list
0316:            private List exceptionBlocks = new ArrayList();
0317:
0318:            private Set syntheticStaticFields = new HashSet();
0319:            private boolean passingClosureParams;
0320:
0321:            private ConstructorNode constructorNode;
0322:            private MethodNode methodNode;
0323:            private BytecodeHelper helper = new BytecodeHelper(null);
0324:
0325:            public static final boolean CREATE_DEBUG_INFO = true;
0326:            public static final boolean CREATE_LINE_NUMBER_INFO = true;
0327:            private static final boolean MARK_START = true;
0328:
0329:            public static final boolean ASM_DEBUG = false; // add marker in the bytecode to show source-byecode relationship
0330:            private int lineNumber = -1;
0331:            private int columnNumber = -1;
0332:            private ASTNode currentASTNode = null;
0333:
0334:            private DummyClassGenerator dummyGen = null;
0335:            private ClassWriter dummyClassWriter = null;
0336:
0337:            private ClassNode interfaceClassLoadingClass;
0338:
0339:            private boolean implicitThis = false;
0340:
0341:            public AsmClassGenerator(GeneratorContext context,
0342:                    ClassVisitor classVisitor, ClassLoader classLoader,
0343:                    String sourceFile) {
0344:                super (classLoader);
0345:                this .context = context;
0346:                this .cw = classVisitor;
0347:                this .sourceFile = sourceFile;
0348:
0349:                this .dummyClassWriter = new ClassWriter(true);
0350:                dummyGen = new DummyClassGenerator(context, dummyClassWriter,
0351:                        classLoader, sourceFile);
0352:                compileStack = new CompileStack();
0353:
0354:            }
0355:
0356:            protected SourceUnit getSourceUnit() {
0357:                return null;
0358:            }
0359:
0360:            // GroovyClassVisitor interface
0361:            //-------------------------------------------------------------------------
0362:            public void visitClass(ClassNode classNode) {
0363:                // todo to be tested
0364:                // createDummyClass(classNode);
0365:
0366:                try {
0367:                    syntheticStaticFields.clear();
0368:                    this .classNode = classNode;
0369:                    this .outermostClass = null;
0370:                    this .internalClassName = BytecodeHelper
0371:                            .getClassInternalName(classNode);
0372:
0373:                    this .internalBaseClassName = BytecodeHelper
0374:                            .getClassInternalName(classNode.getSuperClass());
0375:
0376:                    cw.visit(asmJDKVersion, classNode.getModifiers(),
0377:                            internalClassName, null, internalBaseClassName,
0378:                            BytecodeHelper.getClassInternalNames(classNode
0379:                                    .getInterfaces()));
0380:                    cw.visitSource(sourceFile, null);
0381:
0382:                    if (classNode.isInterface()) {
0383:                        ClassNode owner = classNode;
0384:                        if (owner instanceof  InnerClassNode) {
0385:                            owner = owner.getOuterClass();
0386:                        }
0387:                        String outerClassName = owner.getName();
0388:                        String name = outerClassName + "$"
0389:                                + context.getNextInnerClassIdx();
0390:                        interfaceClassLoadingClass = new InnerClassNode(owner,
0391:                                name, 4128, ClassHelper.OBJECT_TYPE);
0392:
0393:                        super .visitClass(classNode);
0394:                        createInterfaceSyntheticStaticFields();
0395:                    } else {
0396:                        super .visitClass(classNode);
0397:                        createMopMethods();
0398:                        createSyntheticStaticFields();
0399:                    }
0400:
0401:                    for (Iterator iter = innerClasses.iterator(); iter
0402:                            .hasNext();) {
0403:                        ClassNode innerClass = (ClassNode) iter.next();
0404:                        String innerClassName = innerClass.getName();
0405:                        String innerClassInternalName = BytecodeHelper
0406:                                .getClassInternalName(innerClassName);
0407:                        {
0408:                            int index = innerClassName.lastIndexOf('$');
0409:                            if (index >= 0)
0410:                                innerClassName = innerClassName
0411:                                        .substring(index + 1);
0412:                        }
0413:                        String outerClassName = internalClassName; // default for inner classes
0414:                        MethodNode enclosingMethod = innerClass
0415:                                .getEnclosingMethod();
0416:                        if (enclosingMethod != null) {
0417:                            // local inner classes do not specify the outer class name
0418:                            outerClassName = null;
0419:                            innerClassName = null;
0420:                        }
0421:                        cw.visitInnerClass(innerClassInternalName,
0422:                                outerClassName, innerClassName, innerClass
0423:                                        .getModifiers());
0424:                    }
0425:                    //TODO: an inner class should have an entry of itself
0426:                    cw.visitEnd();
0427:                } catch (GroovyRuntimeException e) {
0428:                    e.setModule(classNode.getModule());
0429:                    throw e;
0430:                }
0431:            }
0432:
0433:            private void createMopMethods() {
0434:                visitMopMethodList(classNode.getMethods(), true);
0435:                visitMopMethodList(classNode.getSuperClass()
0436:                        .getAllDeclaredMethods(), false);
0437:            }
0438:
0439:            private String[] buildExceptions(ClassNode[] exceptions) {
0440:                if (exceptions == null)
0441:                    return null;
0442:                String[] ret = new String[exceptions.length];
0443:                for (int i = 0; i < exceptions.length; i++) {
0444:                    ret[i] = BytecodeHelper.getClassInternalName(exceptions[i]);
0445:                }
0446:                return ret;
0447:            }
0448:
0449:            /**
0450:             * filters a list of method for MOP methods. For all methods that are no 
0451:             * MOP methods a MOP method is created if the method is not public and the
0452:             * call would be a call on "this" (isThis == true). If the call is not on
0453:             * "this", then the call is a call on "super" and all methods are used, 
0454:             * unless they are already a MOP method
0455:             *  
0456:             * @see #generateMopCalls(LinkedList, boolean)
0457:             *  
0458:             * @param methods unfiltered list of methods for MOP 
0459:             * @param isThis  if true, then we are creating a MOP method on "this", "super" else 
0460:             */
0461:            private void visitMopMethodList(List methods, boolean isThis) {
0462:                LinkedList mopCalls = new LinkedList();
0463:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
0464:                    MethodNode mn = (MethodNode) iter.next();
0465:                    if ((mn.getModifiers() & ACC_ABSTRACT) != 0)
0466:                        continue;
0467:                    // no this$ methods for protected/public isThis=true
0468:                    // super$ method for protected/public isThis=false
0469:                    // --> results in XOR
0470:                    if (isThis
0471:                            ^ (mn.getModifiers() & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
0472:                        continue;
0473:                    String methodName = mn.getName();
0474:                    if (isMopMethod(methodName) || methodName.startsWith("<"))
0475:                        continue;
0476:                    String name = getMopMethodName(mn, isThis);
0477:                    if (containsMethod(methods, name, mn.getParameters()))
0478:                        continue;
0479:                    mopCalls.add(mn);
0480:                }
0481:                generateMopCalls(mopCalls, isThis);
0482:                mopCalls.clear();
0483:            }
0484:
0485:            private boolean containsMethod(List methods, String name,
0486:                    Parameter[] paras) {
0487:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
0488:                    MethodNode element = (MethodNode) iter.next();
0489:                    if (element.getName().equals(name)
0490:                            && equalParameterTypes(paras, element
0491:                                    .getParameters()))
0492:                        return true;
0493:                }
0494:                return false;
0495:            }
0496:
0497:            private boolean equalParameterTypes(Parameter[] p1, Parameter[] p2) {
0498:                if (p1.length != p2.length)
0499:                    return false;
0500:                for (int i = 0; i < p1.length; i++) {
0501:                    if (!p1[i].getType().equals(p2[i].getType()))
0502:                        return false;
0503:                }
0504:                return true;
0505:            }
0506:
0507:            /**
0508:             * generates a Meta Object Protocoll method, that is used to call a non public
0509:             * method, or to make a call to super.
0510:             * @param mopCalls list of methods a mop call method should be generated for
0511:             * @param useThis true if "this" should be used for the naming
0512:             */
0513:            private void generateMopCalls(LinkedList mopCalls, boolean useThis) {
0514:                for (Iterator iter = mopCalls.iterator(); iter.hasNext();) {
0515:                    MethodNode method = (MethodNode) iter.next();
0516:                    String name = getMopMethodName(method, useThis);
0517:                    Parameter[] parameters = method.getParameters();
0518:                    String methodDescriptor = BytecodeHelper
0519:                            .getMethodDescriptor(method.getReturnType(), method
0520:                                    .getParameters());
0521:                    cv = cw.visitMethod(Opcodes.ACC_PUBLIC
0522:                            & Opcodes.ACC_SYNTHETIC, name, methodDescriptor,
0523:                            null, null);
0524:                    cv.visitVarInsn(ALOAD, 0);
0525:                    BytecodeHelper helper = new BytecodeHelper(cv);
0526:                    int newRegister = 1;
0527:                    for (int i = 0; i < parameters.length; i++) {
0528:                        ClassNode type = parameters[i].getType();
0529:                        helper.load(parameters[i].getType(), newRegister);
0530:                        // increment to next register, double/long are using two places
0531:                        newRegister++;
0532:                        if (type == ClassHelper.double_TYPE
0533:                                || type == ClassHelper.long_TYPE)
0534:                            newRegister++;
0535:                    }
0536:                    cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper
0537:                            .getClassInternalName(method.getDeclaringClass()),
0538:                            method.getName(), methodDescriptor);
0539:                    helper.doReturn(method.getReturnType());
0540:                    cv.visitMaxs(0, 0);
0541:                    cv.visitEnd();
0542:                    classNode.addMethod(name, Opcodes.ACC_PUBLIC
0543:                            & Opcodes.ACC_SYNTHETIC, method.getReturnType(),
0544:                            parameters, null, null);
0545:                }
0546:            }
0547:
0548:            /**
0549:             * creates a MOP method name from a method
0550:             * @param method the method to be called by the mop method
0551:             * @param useThis if true, then it is a call on "this", "super" else
0552:             * @return the mop method name
0553:             */
0554:            public static String getMopMethodName(MethodNode method,
0555:                    boolean useThis) {
0556:                ClassNode declaringNode = method.getDeclaringClass();
0557:                int distance = 0;
0558:                for (; declaringNode != null; declaringNode = declaringNode
0559:                        .getSuperClass()) {
0560:                    distance++;
0561:                }
0562:                return (useThis ? "this" : "super") + "$" + distance + "$"
0563:                        + method.getName();
0564:            }
0565:
0566:            /**
0567:             * method to determine if a method is a MOP method. This is done by the
0568:             * method name. If the name starts with "this$" or "super$", then it is
0569:             * a MOP method
0570:             * @param methodName name of the method to test
0571:             * @return true if the method is a MOP method
0572:             */
0573:            public static boolean isMopMethod(String methodName) {
0574:                return methodName.startsWith("this$")
0575:                        || methodName.startsWith("super$");
0576:            }
0577:
0578:            protected void visitConstructorOrMethod(MethodNode node,
0579:                    boolean isConstructor) {
0580:                String methodType = BytecodeHelper.getMethodDescriptor(node
0581:                        .getReturnType(), node.getParameters());
0582:
0583:                cv = cw
0584:                        .visitMethod(node.getModifiers(), node.getName(),
0585:                                methodType, null, buildExceptions(node
0586:                                        .getExceptions()));
0587:                helper = new BytecodeHelper(cv);
0588:                if (!node.isAbstract()) {
0589:                    Statement code = node.getCode();
0590:                    if (isConstructor
0591:                            && (code == null || !firstStatementIsSpecialConstructorCall(node))) {
0592:                        // invokes the super class constructor
0593:                        cv.visitVarInsn(ALOAD, 0);
0594:                        cv.visitMethodInsn(INVOKESPECIAL,
0595:                                BytecodeHelper.getClassInternalName(classNode
0596:                                        .getSuperClass()), "<init>", "()V");
0597:                    }
0598:
0599:                    compileStack.init(node.getVariableScope(), node
0600:                            .getParameters(), cv, classNode);
0601:
0602:                    // ensure we save the current (meta) class in a register
0603:                    (new ClassExpression(classNode)).visit(this );
0604:                    cv.visitInsn(POP);
0605:                    (new ClassExpression(ClassHelper.METACLASS_TYPE))
0606:                            .visit(this );
0607:                    cv.visitInsn(POP);
0608:
0609:                    // handle body
0610:                    super .visitConstructorOrMethod(node, isConstructor);
0611:                    if (!outputReturn || node.isVoidMethod()) {
0612:                        cv.visitInsn(RETURN);
0613:                    }
0614:                    compileStack.clear();
0615:
0616:                    // lets do all the exception blocks
0617:                    for (Iterator iter = exceptionBlocks.iterator(); iter
0618:                            .hasNext();) {
0619:                        Runnable runnable = (Runnable) iter.next();
0620:                        runnable.run();
0621:                    }
0622:                    exceptionBlocks.clear();
0623:
0624:                    cv.visitMaxs(0, 0);
0625:                }
0626:            }
0627:
0628:            private boolean firstStatementIsSpecialConstructorCall(
0629:                    MethodNode node) {
0630:                Statement code = node.getFirstStatement();
0631:                if (code == null || !(code instanceof  ExpressionStatement))
0632:                    return false;
0633:
0634:                Expression expression = ((ExpressionStatement) code)
0635:                        .getExpression();
0636:                if (!(expression instanceof  ConstructorCallExpression))
0637:                    return false;
0638:                ConstructorCallExpression cce = (ConstructorCallExpression) expression;
0639:                return cce.isSpecialCall();
0640:            }
0641:
0642:            public void visitConstructor(ConstructorNode node) {
0643:                this .constructorNode = node;
0644:                this .methodNode = null;
0645:                outputReturn = false;
0646:                super .visitConstructor(node);
0647:            }
0648:
0649:            public void visitMethod(MethodNode node) {
0650:                this .constructorNode = null;
0651:                this .methodNode = node;
0652:                outputReturn = false;
0653:
0654:                super .visitMethod(node);
0655:            }
0656:
0657:            public void visitField(FieldNode fieldNode) {
0658:                onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
0659:                ClassNode t = fieldNode.getType();
0660:                cw.visitField(fieldNode.getModifiers(), fieldNode.getName(),
0661:                        BytecodeHelper.getTypeDescription(t), null, //fieldValue,  //br  all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
0662:                        null);
0663:                visitAnnotations(fieldNode);
0664:            }
0665:
0666:            public void visitProperty(PropertyNode statement) {
0667:                // the verifyer created the field and the setter/getter methods, so here is
0668:                // not really something to do
0669:                onLineNumber(statement, "visitProperty:"
0670:                        + statement.getField().getName());
0671:                this .methodNode = null;
0672:            }
0673:
0674:            // GroovyCodeVisitor interface
0675:            //-------------------------------------------------------------------------
0676:
0677:            // Statements
0678:            //-------------------------------------------------------------------------
0679:
0680:            protected void visitStatement(Statement statement) {
0681:                String name = statement.getStatementLabel();
0682:                if (name != null) {
0683:                    Label label = compileStack.createLocalLabel(name);
0684:                    cv.visitLabel(label);
0685:                }
0686:            }
0687:
0688:            public void visitBlockStatement(BlockStatement block) {
0689:                onLineNumber(block, "visitBlockStatement");
0690:                visitStatement(block);
0691:
0692:                compileStack.pushVariableScope(block.getVariableScope());
0693:                super .visitBlockStatement(block);
0694:                compileStack.pop();
0695:            }
0696:
0697:            public void visitForLoop(ForStatement loop) {
0698:                onLineNumber(loop, "visitForLoop");
0699:                visitStatement(loop);
0700:
0701:                compileStack.pushLoop(loop.getVariableScope(), loop
0702:                        .getStatementLabel());
0703:
0704:                //
0705:                // Declare the loop counter.
0706:                Variable variable = compileStack.defineVariable(loop
0707:                        .getVariable(), false);
0708:
0709:                //
0710:                // Then get the iterator and generate the loop control
0711:                MethodCallExpression iterator = new MethodCallExpression(loop
0712:                        .getCollectionExpression(), "iterator",
0713:                        new ArgumentListExpression());
0714:                iterator.visit(this );
0715:
0716:                final int iteratorIdx = compileStack.defineTemporaryVariable(
0717:                        "iterator", ClassHelper.make(java.util.Iterator.class),
0718:                        true);
0719:
0720:                Label continueLabel = compileStack.getContinueLabel();
0721:                Label breakLabel = compileStack.getBreakLabel();
0722:
0723:                cv.visitLabel(continueLabel);
0724:                cv.visitVarInsn(ALOAD, iteratorIdx);
0725:                iteratorHasNextMethod.call(cv);
0726:                // note: ifeq tests for ==0, a boolean is 0 if it is false
0727:                cv.visitJumpInsn(IFEQ, breakLabel);
0728:
0729:                cv.visitVarInsn(ALOAD, iteratorIdx);
0730:                iteratorNextMethod.call(cv);
0731:                helper.storeVar(variable);
0732:
0733:                // Generate the loop body
0734:                loop.getLoopBlock().visit(this );
0735:
0736:                cv.visitJumpInsn(GOTO, continueLabel);
0737:                cv.visitLabel(breakLabel);
0738:
0739:                compileStack.pop();
0740:            }
0741:
0742:            public void visitWhileLoop(WhileStatement loop) {
0743:                onLineNumber(loop, "visitWhileLoop");
0744:                visitStatement(loop);
0745:
0746:                compileStack.pushLoop(loop.getStatementLabel());
0747:                Label continueLabel = compileStack.getContinueLabel();
0748:                Label breakLabel = compileStack.getBreakLabel();
0749:
0750:                cv.visitLabel(continueLabel);
0751:                loop.getBooleanExpression().visit(this );
0752:                cv.visitJumpInsn(IFEQ, breakLabel);
0753:
0754:                loop.getLoopBlock().visit(this );
0755:
0756:                cv.visitJumpInsn(GOTO, continueLabel);
0757:                cv.visitLabel(breakLabel);
0758:
0759:                compileStack.pop();
0760:            }
0761:
0762:            public void visitDoWhileLoop(DoWhileStatement loop) {
0763:                onLineNumber(loop, "visitDoWhileLoop");
0764:                visitStatement(loop);
0765:
0766:                compileStack.pushLoop(loop.getStatementLabel());
0767:                Label breakLabel = compileStack.getBreakLabel();
0768:                Label continueLabel = compileStack.getContinueLabel();
0769:                cv.visitLabel(continueLabel);
0770:
0771:                loop.getLoopBlock().visit(this );
0772:
0773:                loop.getBooleanExpression().visit(this );
0774:                cv.visitJumpInsn(IFEQ, continueLabel);
0775:                cv.visitLabel(breakLabel);
0776:
0777:                compileStack.pop();
0778:            }
0779:
0780:            public void visitIfElse(IfStatement ifElse) {
0781:                onLineNumber(ifElse, "visitIfElse");
0782:                visitStatement(ifElse);
0783:                ifElse.getBooleanExpression().visit(this );
0784:
0785:                Label l0 = new Label();
0786:                cv.visitJumpInsn(IFEQ, l0);
0787:
0788:                ifElse.getIfBlock().visit(this );
0789:
0790:                Label l1 = new Label();
0791:                cv.visitJumpInsn(GOTO, l1);
0792:                cv.visitLabel(l0);
0793:
0794:                ifElse.getElseBlock().visit(this );
0795:                cv.visitLabel(l1);
0796:            }
0797:
0798:            public void visitTernaryExpression(TernaryExpression expression) {
0799:                onLineNumber(expression, "visitTernaryExpression");
0800:
0801:                expression.getBooleanExpression().visit(this );
0802:
0803:                Label l0 = new Label();
0804:                cv.visitJumpInsn(IFEQ, l0);
0805:                visitAndAutoboxBoolean(expression.getTrueExpression());
0806:
0807:                Label l1 = new Label();
0808:                cv.visitJumpInsn(GOTO, l1);
0809:                cv.visitLabel(l0);
0810:
0811:                visitAndAutoboxBoolean(expression.getFalseExpression());
0812:                cv.visitLabel(l1);
0813:            }
0814:
0815:            public void visitAssertStatement(AssertStatement statement) {
0816:                onLineNumber(statement, "visitAssertStatement");
0817:                visitStatement(statement);
0818:
0819:                BooleanExpression booleanExpression = statement
0820:                        .getBooleanExpression();
0821:                booleanExpression.visit(this );
0822:
0823:                Label l0 = new Label();
0824:                cv.visitJumpInsn(IFEQ, l0);
0825:
0826:                // do nothing
0827:
0828:                Label l1 = new Label();
0829:                cv.visitJumpInsn(GOTO, l1);
0830:                cv.visitLabel(l0);
0831:
0832:                // push expression string onto stack
0833:                String expressionText = booleanExpression.getText();
0834:                List list = new ArrayList();
0835:                addVariableNames(booleanExpression, list);
0836:                if (list.isEmpty()) {
0837:                    cv.visitLdcInsn(expressionText);
0838:                } else {
0839:                    boolean first = true;
0840:
0841:                    // lets create a new expression
0842:                    cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
0843:                    cv.visitInsn(DUP);
0844:                    cv.visitLdcInsn(expressionText + ". Values: ");
0845:
0846:                    cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer",
0847:                            "<init>", "(Ljava/lang/String;)V");
0848:
0849:                    int tempIndex = compileStack.defineTemporaryVariable(
0850:                            "assert", true);
0851:
0852:                    for (Iterator iter = list.iterator(); iter.hasNext();) {
0853:                        String name = (String) iter.next();
0854:                        String text = name + " = ";
0855:                        if (first) {
0856:                            first = false;
0857:                        } else {
0858:                            text = ", " + text;
0859:                        }
0860:
0861:                        cv.visitVarInsn(ALOAD, tempIndex);
0862:                        cv.visitLdcInsn(text);
0863:                        cv.visitMethodInsn(INVOKEVIRTUAL,
0864:                                "java/lang/StringBuffer", "append",
0865:                                "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
0866:                        cv.visitInsn(POP);
0867:
0868:                        cv.visitVarInsn(ALOAD, tempIndex);
0869:                        new VariableExpression(name).visit(this );
0870:                        cv.visitMethodInsn(INVOKEVIRTUAL,
0871:                                "java/lang/StringBuffer", "append",
0872:                                "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
0873:                        cv.visitInsn(POP);
0874:
0875:                    }
0876:                    cv.visitVarInsn(ALOAD, tempIndex);
0877:                    compileStack.removeVar(tempIndex);
0878:                }
0879:                // now the optional exception expression
0880:                statement.getMessageExpression().visit(this );
0881:
0882:                assertFailedMethod.call(cv);
0883:                cv.visitLabel(l1);
0884:            }
0885:
0886:            private void addVariableNames(Expression expression, List list) {
0887:                if (expression instanceof  BooleanExpression) {
0888:                    BooleanExpression boolExp = (BooleanExpression) expression;
0889:                    addVariableNames(boolExp.getExpression(), list);
0890:                } else if (expression instanceof  BinaryExpression) {
0891:                    BinaryExpression binExp = (BinaryExpression) expression;
0892:                    addVariableNames(binExp.getLeftExpression(), list);
0893:                    addVariableNames(binExp.getRightExpression(), list);
0894:                } else if (expression instanceof  VariableExpression) {
0895:                    VariableExpression varExp = (VariableExpression) expression;
0896:                    list.add(varExp.getName());
0897:                }
0898:            }
0899:
0900:            public void visitTryCatchFinally(TryCatchStatement statement) {
0901:                onLineNumber(statement, "visitTryCatchFinally");
0902:                visitStatement(statement);
0903:
0904:                CatchStatement catchStatement = statement.getCatchStatement(0);
0905:                Statement tryStatement = statement.getTryStatement();
0906:                final Statement finallyStatement = statement
0907:                        .getFinallyStatement();
0908:
0909:                int anyExceptionIndex = compileStack.defineTemporaryVariable(
0910:                        "exception", false);
0911:                if (!finallyStatement.isEmpty()) {
0912:                    compileStack.pushFinallyBlock(new Runnable() {
0913:                        public void run() {
0914:                            finallyStatement.visit(AsmClassGenerator.this );
0915:                        }
0916:                    });
0917:                }
0918:
0919:                // start try block, label needed for exception table
0920:                final Label tryStart = new Label();
0921:                cv.visitLabel(tryStart);
0922:                tryStatement.visit(this );
0923:                // goto finally part
0924:                final Label finallyStart = new Label();
0925:                cv.visitJumpInsn(GOTO, finallyStart);
0926:                // marker needed for Exception table
0927:                final Label tryEnd = new Label();
0928:                cv.visitLabel(tryEnd);
0929:
0930:                for (Iterator it = statement.getCatchStatements().iterator(); it
0931:                        .hasNext();) {
0932:                    catchStatement = (CatchStatement) it.next();
0933:                    ClassNode exceptionType = catchStatement.getExceptionType();
0934:                    // start catch block, label needed for exception table
0935:                    final Label catchStart = new Label();
0936:                    cv.visitLabel(catchStart);
0937:                    // create exception variable and store the exception 
0938:                    compileStack.defineVariable(catchStatement.getVariable(),
0939:                            true);
0940:                    // handle catch body
0941:                    catchStatement.visit(this );
0942:                    // goto finally start
0943:                    cv.visitJumpInsn(GOTO, finallyStart);
0944:                    // add exception to table
0945:                    final String exceptionTypeInternalName = BytecodeHelper
0946:                            .getClassInternalName(exceptionType);
0947:                    exceptionBlocks.add(new Runnable() {
0948:                        public void run() {
0949:                            cv.visitTryCatchBlock(tryStart, tryEnd, catchStart,
0950:                                    exceptionTypeInternalName);
0951:                        }
0952:                    });
0953:                }
0954:
0955:                // marker needed for the exception table
0956:                final Label endOfAllCatches = new Label();
0957:                cv.visitLabel(endOfAllCatches);
0958:
0959:                // remove the finally, don't let it visit itself
0960:                if (!finallyStatement.isEmpty())
0961:                    compileStack.popFinallyBlock();
0962:
0963:                // start finally
0964:                cv.visitLabel(finallyStart);
0965:                finallyStatement.visit(this );
0966:                // goto end of finally
0967:                Label afterFinally = new Label();
0968:                cv.visitJumpInsn(GOTO, afterFinally);
0969:
0970:                // start a block catching any Exception
0971:                final Label catchAny = new Label();
0972:                cv.visitLabel(catchAny);
0973:                //store exception
0974:                cv.visitVarInsn(ASTORE, anyExceptionIndex);
0975:                finallyStatement.visit(this );
0976:                // load the exception and rethrow it
0977:                cv.visitVarInsn(ALOAD, anyExceptionIndex);
0978:                cv.visitInsn(ATHROW);
0979:
0980:                // end of all catches and finally parts
0981:                cv.visitLabel(afterFinally);
0982:
0983:                // add catch any block to exception table
0984:                exceptionBlocks.add(new Runnable() {
0985:                    public void run() {
0986:                        cv.visitTryCatchBlock(tryStart, endOfAllCatches,
0987:                                catchAny, null);
0988:                    }
0989:                });
0990:            }
0991:
0992:            public void visitSwitch(SwitchStatement statement) {
0993:                onLineNumber(statement, "visitSwitch");
0994:                visitStatement(statement);
0995:
0996:                statement.getExpression().visit(this );
0997:
0998:                // switch does not have a continue label. use its parent's for continue
0999:                Label breakLabel = compileStack.pushSwitch();
1000:
1001:                int switchVariableIndex = compileStack.defineTemporaryVariable(
1002:                        "switch", true);
1003:
1004:                List caseStatements = statement.getCaseStatements();
1005:                int caseCount = caseStatements.size();
1006:                Label[] labels = new Label[caseCount + 1];
1007:                for (int i = 0; i < caseCount; i++) {
1008:                    labels[i] = new Label();
1009:                }
1010:
1011:                int i = 0;
1012:                for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
1013:                    CaseStatement caseStatement = (CaseStatement) iter.next();
1014:                    visitCaseStatement(caseStatement, switchVariableIndex,
1015:                            labels[i], labels[i + 1]);
1016:                }
1017:
1018:                statement.getDefaultStatement().visit(this );
1019:
1020:                cv.visitLabel(breakLabel);
1021:
1022:                compileStack.pop();
1023:            }
1024:
1025:            public void visitCaseStatement(CaseStatement statement) {
1026:            }
1027:
1028:            public void visitCaseStatement(CaseStatement statement,
1029:                    int switchVariableIndex, Label this Label, Label nextLabel) {
1030:
1031:                onLineNumber(statement, "visitCaseStatement");
1032:
1033:                cv.visitVarInsn(ALOAD, switchVariableIndex);
1034:                statement.getExpression().visit(this );
1035:
1036:                isCaseMethod.call(cv);
1037:
1038:                Label l0 = new Label();
1039:                cv.visitJumpInsn(IFEQ, l0);
1040:
1041:                cv.visitLabel(this Label);
1042:
1043:                statement.getCode().visit(this );
1044:
1045:                // now if we don't finish with a break we need to jump past
1046:                // the next comparison
1047:                if (nextLabel != null) {
1048:                    cv.visitJumpInsn(GOTO, nextLabel);
1049:                }
1050:
1051:                cv.visitLabel(l0);
1052:            }
1053:
1054:            public void visitBreakStatement(BreakStatement statement) {
1055:                onLineNumber(statement, "visitBreakStatement");
1056:                visitStatement(statement);
1057:
1058:                String name = statement.getLabel();
1059:                Label breakLabel = compileStack.getNamedBreakLabel(name);
1060:                compileStack.applyFinallyBlocks(breakLabel, true);
1061:
1062:                cv.visitJumpInsn(GOTO, breakLabel);
1063:            }
1064:
1065:            public void visitContinueStatement(ContinueStatement statement) {
1066:                onLineNumber(statement, "visitContinueStatement");
1067:                visitStatement(statement);
1068:
1069:                String name = statement.getLabel();
1070:                Label continueLabel = compileStack.getContinueLabel();
1071:                if (name != null)
1072:                    continueLabel = compileStack.getNamedContinueLabel(name);
1073:                compileStack.applyFinallyBlocks(continueLabel, false);
1074:                cv.visitJumpInsn(GOTO, continueLabel);
1075:            }
1076:
1077:            public void visitSynchronizedStatement(
1078:                    SynchronizedStatement statement) {
1079:                onLineNumber(statement, "visitSynchronizedStatement");
1080:                visitStatement(statement);
1081:
1082:                statement.getExpression().visit(this );
1083:                final int index = compileStack.defineTemporaryVariable(
1084:                        "synchronized", ClassHelper.Integer_TYPE, true);
1085:
1086:                final Label synchronizedStart = new Label();
1087:                final Label synchronizedEnd = new Label();
1088:                final Label catchAll = new Label();
1089:
1090:                cv.visitVarInsn(ALOAD, index);
1091:                cv.visitInsn(MONITORENTER);
1092:                cv.visitLabel(synchronizedStart);
1093:
1094:                Runnable finallyPart = new Runnable() {
1095:                    public void run() {
1096:                        cv.visitVarInsn(ALOAD, index);
1097:                        cv.visitInsn(MONITOREXIT);
1098:                    }
1099:                };
1100:                compileStack.pushFinallyBlock(finallyPart);
1101:                statement.getCode().visit(this );
1102:
1103:                finallyPart.run();
1104:                cv.visitJumpInsn(GOTO, synchronizedEnd);
1105:                cv.visitLabel(catchAll);
1106:                finallyPart.run();
1107:                cv.visitInsn(ATHROW);
1108:                cv.visitLabel(synchronizedEnd);
1109:
1110:                compileStack.popFinallyBlock();
1111:                exceptionBlocks.add(new Runnable() {
1112:                    public void run() {
1113:                        cv.visitTryCatchBlock(synchronizedStart, catchAll,
1114:                                catchAll, null);
1115:                    }
1116:                });
1117:            }
1118:
1119:            public void visitThrowStatement(ThrowStatement statement) {
1120:                onLineNumber(statement, "visitThrowStatement");
1121:                visitStatement(statement);
1122:
1123:                statement.getExpression().visit(this );
1124:
1125:                // we should infer the type of the exception from the expression
1126:                cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
1127:
1128:                cv.visitInsn(ATHROW);
1129:            }
1130:
1131:            public void visitReturnStatement(ReturnStatement statement) {
1132:                onLineNumber(statement, "visitReturnStatement");
1133:                visitStatement(statement);
1134:
1135:                ClassNode returnType = methodNode.getReturnType();
1136:                if (returnType == ClassHelper.VOID_TYPE) {
1137:                    if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) {
1138:                        throwException("Cannot use return statement with an expression on a method that returns void");
1139:                    }
1140:                    compileStack.applyFinallyBlocks();
1141:                    cv.visitInsn(RETURN);
1142:                    outputReturn = true;
1143:                    return;
1144:                }
1145:
1146:                Expression expression = statement.getExpression();
1147:                evaluateExpression(expression);
1148:                if (returnType == ClassHelper.OBJECT_TYPE
1149:                        && expression.getType() != null
1150:                        && expression.getType() == ClassHelper.VOID_TYPE) {
1151:                    cv.visitInsn(ACONST_NULL); // cheat the caller
1152:                } else {
1153:                    // return is based on class type
1154:                    // we may need to cast
1155:                    doConvertAndCast(returnType, expression, false, true, false);
1156:                    helper.unbox(returnType);
1157:                }
1158:                if (compileStack.hasFinallyBlocks()) {
1159:                    int returnValueIdx = compileStack.defineTemporaryVariable(
1160:                            "returnValue", returnType, true);
1161:                    compileStack.applyFinallyBlocks();
1162:                    helper.load(returnType, returnValueIdx);
1163:                }
1164:                helper.doReturn(returnType);
1165:                outputReturn = true;
1166:            }
1167:
1168:            /**
1169:             * Casts to the given type unless it can be determined that the cast is unnecessary
1170:             */
1171:            protected void doConvertAndCast(ClassNode type,
1172:                    Expression expression, boolean ignoreAutoboxing,
1173:                    boolean forceCast, boolean coerce) {
1174:                ClassNode expType = getExpressionType(expression);
1175:                // temp resolution: convert all primitive casting to corresponsing Object type
1176:                if (!ignoreAutoboxing && ClassHelper.isPrimitiveType(type)) {
1177:                    type = ClassHelper.getWrapper(type);
1178:                }
1179:                if (forceCast || (type != null && !type.equals(expType))) {
1180:                    doConvertAndCast(type, coerce);
1181:                }
1182:            }
1183:
1184:            /**
1185:             * @param expression
1186:             */
1187:            protected void evaluateExpression(Expression expression) {
1188:                visitAndAutoboxBoolean(expression);
1189:
1190:                Expression assignExpr = createReturnLHSExpression(expression);
1191:                if (assignExpr != null) {
1192:                    leftHandExpression = false;
1193:                    assignExpr.visit(this );
1194:                }
1195:            }
1196:
1197:            public void visitExpressionStatement(ExpressionStatement statement) {
1198:                onLineNumber(statement, "visitExpressionStatement: "
1199:                        + statement.getExpression().getClass().getName());
1200:                visitStatement(statement);
1201:
1202:                Expression expression = statement.getExpression();
1203:
1204:                visitAndAutoboxBoolean(expression);
1205:
1206:                if (isPopRequired(expression)) {
1207:                    cv.visitInsn(POP);
1208:                }
1209:            }
1210:
1211:            // Expressions
1212:            //-------------------------------------------------------------------------
1213:
1214:            public void visitDeclarationExpression(
1215:                    DeclarationExpression expression) {
1216:                onLineNumber(expression, "visitDeclarationExpression: \""
1217:                        + expression.getVariableExpression().getName() + "\"");
1218:
1219:                Expression rightExpression = expression.getRightExpression();
1220:                // no need to visit left side, just get the variable name
1221:                VariableExpression vex = expression.getVariableExpression();
1222:                ClassNode type = vex.getType();
1223:
1224:                // lets not cast for primitive types as we handle these in field setting etc
1225:                if (ClassHelper.isPrimitiveType(type)) {
1226:                    rightExpression.visit(this );
1227:                } else {
1228:                    if (type != ClassHelper.OBJECT_TYPE) {
1229:                        visitCastExpression(new CastExpression(type,
1230:                                rightExpression));
1231:                    } else {
1232:                        visitAndAutoboxBoolean(rightExpression);
1233:                    }
1234:                }
1235:                compileStack.defineVariable(vex, true);
1236:            }
1237:
1238:            public void visitBinaryExpression(BinaryExpression expression) {
1239:                onLineNumber(expression, "visitBinaryExpression: \""
1240:                        + expression.getOperation().getText() + "\" ");
1241:                switch (expression.getOperation().getType()) {
1242:                case Types.EQUAL: // = assignment
1243:                    evaluateEqual(expression);
1244:                    break;
1245:
1246:                case Types.COMPARE_IDENTICAL: // ===
1247:                    evaluateBinaryExpression(compareIdenticalMethod, expression);
1248:                    break;
1249:
1250:                case Types.COMPARE_EQUAL: // ==
1251:                    evaluateBinaryExpression(compareEqualMethod, expression);
1252:                    break;
1253:
1254:                case Types.COMPARE_NOT_EQUAL:
1255:                    evaluateBinaryExpression(compareNotEqualMethod, expression);
1256:                    break;
1257:
1258:                case Types.COMPARE_TO:
1259:                    evaluateCompareTo(expression);
1260:                    break;
1261:
1262:                case Types.COMPARE_GREATER_THAN:
1263:                    evaluateBinaryExpression(compareGreaterThanMethod,
1264:                            expression);
1265:                    break;
1266:
1267:                case Types.COMPARE_GREATER_THAN_EQUAL:
1268:                    evaluateBinaryExpression(compareGreaterThanEqualMethod,
1269:                            expression);
1270:                    break;
1271:
1272:                case Types.COMPARE_LESS_THAN:
1273:                    evaluateBinaryExpression(compareLessThanMethod, expression);
1274:                    break;
1275:
1276:                case Types.COMPARE_LESS_THAN_EQUAL:
1277:                    evaluateBinaryExpression(compareLessThanEqualMethod,
1278:                            expression);
1279:                    break;
1280:
1281:                case Types.LOGICAL_AND:
1282:                    evaluateLogicalAndExpression(expression);
1283:                    break;
1284:
1285:                case Types.LOGICAL_OR:
1286:                    evaluateLogicalOrExpression(expression);
1287:                    break;
1288:
1289:                case Types.BITWISE_AND:
1290:                    evaluateBinaryExpression("and", expression);
1291:                    break;
1292:
1293:                case Types.BITWISE_AND_EQUAL:
1294:                    evaluateBinaryExpressionWithAsignment("and", expression);
1295:                    break;
1296:
1297:                case Types.BITWISE_OR:
1298:                    evaluateBinaryExpression("or", expression);
1299:                    break;
1300:
1301:                case Types.BITWISE_OR_EQUAL:
1302:                    evaluateBinaryExpressionWithAsignment("or", expression);
1303:                    break;
1304:
1305:                case Types.BITWISE_XOR:
1306:                    evaluateBinaryExpression("xor", expression);
1307:                    break;
1308:
1309:                case Types.BITWISE_XOR_EQUAL:
1310:                    evaluateBinaryExpressionWithAsignment("xor", expression);
1311:                    break;
1312:
1313:                case Types.PLUS:
1314:                    evaluateBinaryExpression("plus", expression);
1315:                    break;
1316:
1317:                case Types.PLUS_EQUAL:
1318:                    evaluateBinaryExpressionWithAsignment("plus", expression);
1319:                    break;
1320:
1321:                case Types.MINUS:
1322:                    evaluateBinaryExpression("minus", expression);
1323:                    break;
1324:
1325:                case Types.MINUS_EQUAL:
1326:                    evaluateBinaryExpressionWithAsignment("minus", expression);
1327:                    break;
1328:
1329:                case Types.MULTIPLY:
1330:                    evaluateBinaryExpression("multiply", expression);
1331:                    break;
1332:
1333:                case Types.MULTIPLY_EQUAL:
1334:                    evaluateBinaryExpressionWithAsignment("multiply",
1335:                            expression);
1336:                    break;
1337:
1338:                case Types.DIVIDE:
1339:                    evaluateBinaryExpression("div", expression);
1340:                    break;
1341:
1342:                case Types.DIVIDE_EQUAL:
1343:                    //SPG don't use divide since BigInteger implements directly
1344:                    //and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
1345:                    evaluateBinaryExpressionWithAsignment("div", expression);
1346:                    break;
1347:
1348:                case Types.INTDIV:
1349:                    evaluateBinaryExpression("intdiv", expression);
1350:                    break;
1351:
1352:                case Types.INTDIV_EQUAL:
1353:                    evaluateBinaryExpressionWithAsignment("intdiv", expression);
1354:                    break;
1355:
1356:                case Types.MOD:
1357:                    evaluateBinaryExpression("mod", expression);
1358:                    break;
1359:
1360:                case Types.MOD_EQUAL:
1361:                    evaluateBinaryExpressionWithAsignment("mod", expression);
1362:                    break;
1363:
1364:                case Types.POWER:
1365:                    evaluateBinaryExpression("power", expression);
1366:                    break;
1367:
1368:                case Types.POWER_EQUAL:
1369:                    evaluateBinaryExpressionWithAsignment("power", expression);
1370:                    break;
1371:
1372:                case Types.LEFT_SHIFT:
1373:                    evaluateBinaryExpression("leftShift", expression);
1374:                    break;
1375:
1376:                case Types.LEFT_SHIFT_EQUAL:
1377:                    evaluateBinaryExpressionWithAsignment("leftShift",
1378:                            expression);
1379:                    break;
1380:
1381:                case Types.RIGHT_SHIFT:
1382:                    evaluateBinaryExpression("rightShift", expression);
1383:                    break;
1384:
1385:                case Types.RIGHT_SHIFT_EQUAL:
1386:                    evaluateBinaryExpressionWithAsignment("rightShift",
1387:                            expression);
1388:                    break;
1389:
1390:                case Types.RIGHT_SHIFT_UNSIGNED:
1391:                    evaluateBinaryExpression("rightShiftUnsigned", expression);
1392:                    break;
1393:
1394:                case Types.RIGHT_SHIFT_UNSIGNED_EQUAL:
1395:                    evaluateBinaryExpressionWithAsignment("rightShiftUnsigned",
1396:                            expression);
1397:                    break;
1398:
1399:                case Types.KEYWORD_INSTANCEOF:
1400:                    evaluateInstanceof(expression);
1401:                    break;
1402:
1403:                case Types.FIND_REGEX:
1404:                    evaluateBinaryExpression(findRegexMethod, expression);
1405:                    break;
1406:
1407:                case Types.MATCH_REGEX:
1408:                    evaluateBinaryExpression(matchRegexMethod, expression);
1409:                    break;
1410:
1411:                case Types.LEFT_SQUARE_BRACKET:
1412:                    if (leftHandExpression) {
1413:                        throwException("Should not be called here. Possible reason: postfix operation on array.");
1414:                        // This is handled right now in the evaluateEqual()
1415:                        // should support this here later
1416:                        //evaluateBinaryExpression("putAt", expression);
1417:                    } else {
1418:                        evaluateBinaryExpression("getAt", expression);
1419:                    }
1420:                    break;
1421:
1422:                case Types.KEYWORD_IN:
1423:                    evaluateBinaryExpression(isCaseMethod, expression);
1424:                    break;
1425:
1426:                default:
1427:                    throwException("Operation: " + expression.getOperation()
1428:                            + " not supported");
1429:                }
1430:            }
1431:
1432:            private void load(Expression exp) {
1433:
1434:                boolean wasLeft = leftHandExpression;
1435:                leftHandExpression = false;
1436:                //        if (CREATE_DEBUG_INFO)
1437:                //            helper.mark("-- loading expression: " + exp.getClass().getName() +
1438:                //                    " at [" + exp.getLineNumber() + ":" + exp.getColumnNumber() + "]");
1439:                //exp.visit(this);
1440:                visitAndAutoboxBoolean(exp);
1441:                //        if (CREATE_DEBUG_INFO)
1442:                //            helper.mark(" -- end of loading --");
1443:
1444:                leftHandExpression = wasLeft;
1445:            }
1446:
1447:            public void visitPostfixExpression(PostfixExpression expression) {
1448:                switch (expression.getOperation().getType()) {
1449:                case Types.PLUS_PLUS:
1450:                    evaluatePostfixMethod("next", expression.getExpression());
1451:                    break;
1452:                case Types.MINUS_MINUS:
1453:                    evaluatePostfixMethod("previous", expression
1454:                            .getExpression());
1455:                    break;
1456:                }
1457:            }
1458:
1459:            private void throwException(String s) {
1460:                throw new RuntimeParserException(s, currentASTNode);
1461:            }
1462:
1463:            public void visitPrefixExpression(PrefixExpression expression) {
1464:                switch (expression.getOperation().getType()) {
1465:                case Types.PLUS_PLUS:
1466:                    evaluatePrefixMethod("next", expression.getExpression());
1467:                    break;
1468:                case Types.MINUS_MINUS:
1469:                    evaluatePrefixMethod("previous", expression.getExpression());
1470:                    break;
1471:                }
1472:            }
1473:
1474:            public void visitClosureExpression(ClosureExpression expression) {
1475:                ClassNode innerClass = createClosureClass(expression);
1476:                addInnerClass(innerClass);
1477:                String innerClassinternalName = BytecodeHelper
1478:                        .getClassInternalName(innerClass);
1479:
1480:                passingClosureParams = true;
1481:                List constructors = innerClass.getDeclaredConstructors();
1482:                ConstructorNode node = (ConstructorNode) constructors.get(0);
1483:
1484:                Parameter[] localVariableParams = node.getParameters();
1485:
1486:                cv.visitTypeInsn(NEW, innerClassinternalName);
1487:                cv.visitInsn(DUP);
1488:                if (isStaticMethod() || classNode.isStaticClass()) {
1489:                    visitClassExpression(new ClassExpression(classNode));
1490:                    visitClassExpression(new ClassExpression(
1491:                            getOutermostClass()));
1492:                } else {
1493:                    cv.visitVarInsn(ALOAD, 0);
1494:                    loadThis();
1495:                }
1496:
1497:                // now lets load the various parameters we're passing
1498:                // we start at index 1 because the first variable we pass
1499:                // is the owner instance and at this point it is already 
1500:                // on the stack
1501:                for (int i = 2; i < localVariableParams.length; i++) {
1502:                    Parameter param = localVariableParams[i];
1503:                    String name = param.getName();
1504:
1505:                    // compileStack.containsVariable(name) means to ask if the variable is already declared
1506:                    // compileStack.getScope().isReferencedClassVariable(name) means to ask if the variable is a field
1507:                    // If it is no field and is not yet declared, then it is either a closure shared variable or 
1508:                    // an already declared variable. 
1509:                    if (!compileStack.containsVariable(name)
1510:                            && compileStack.getScope()
1511:                                    .isReferencedClassVariable(name)) {
1512:                        visitFieldExpression(new FieldExpression(classNode
1513:                                .getField(name)));
1514:                    } else {
1515:                        Variable v = compileStack.getVariable(name, classNode
1516:                                .getSuperClass() != ClassHelper.CLOSURE_TYPE);
1517:                        if (v == null) {
1518:                            // variable is not on stack because we are
1519:                            // inside a nested Closure and this variable
1520:                            // was not used before
1521:                            // then load it from the Closure field
1522:                            FieldNode field = classNode.getField(name);
1523:                            cv.visitVarInsn(ALOAD, 0);
1524:                            cv.visitFieldInsn(GETFIELD, internalClassName,
1525:                                    name,
1526:                                    BytecodeHelper.getTypeDescription(field
1527:                                            .getType()));
1528:                            // and define it
1529:                            // Note:
1530:                            // we can simply define it here and don't have to
1531:                            // be afraid about name problems because a second
1532:                            // variable with that name is not allowed inside the closure
1533:                            param.setClosureSharedVariable(false);
1534:                            v = compileStack.defineVariable(param, true);
1535:                            param.setClosureSharedVariable(true);
1536:                            v.setHolder(true);
1537:                        }
1538:                        cv.visitVarInsn(ALOAD, v.getIndex());
1539:                    }
1540:                }
1541:                passingClosureParams = false;
1542:
1543:                // we may need to pass in some other constructors
1544:                //cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
1545:                cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName,
1546:                        "<init>", BytecodeHelper.getMethodDescriptor(
1547:                                ClassHelper.VOID_TYPE, localVariableParams));
1548:            }
1549:
1550:            /**
1551:             * Loads either this object or if we're inside a closure then load the top level owner
1552:             */
1553:            protected void loadThisOrOwner() {
1554:                if (isInnerClass()) {
1555:                    visitFieldExpression(new FieldExpression(classNode
1556:                            .getField("owner")));
1557:                } else {
1558:                    loadThis();
1559:                }
1560:            }
1561:
1562:            public void visitRegexExpression(RegexExpression expression) {
1563:                expression.getRegex().visit(this );
1564:                regexPattern.call(cv);
1565:            }
1566:
1567:            /**
1568:             * Generate byte code for constants
1569:             * @see <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a>
1570:             */
1571:            public void visitConstantExpression(ConstantExpression expression) {
1572:                Object value = expression.getValue();
1573:                helper.loadConstant(value);
1574:            }
1575:
1576:            public void visitSpreadExpression(SpreadExpression expression) {
1577:                throw new GroovyBugError(
1578:                        "SpreadExpression should not be visited here");
1579:            }
1580:
1581:            public void visitSpreadMapExpression(SpreadMapExpression expression) {
1582:                Expression subExpression = expression.getExpression();
1583:                subExpression.visit(this );
1584:                spreadMap.call(cv);
1585:            }
1586:
1587:            public void visitMethodPointerExpression(
1588:                    MethodPointerExpression expression) {
1589:                Expression subExpression = expression.getExpression();
1590:                subExpression.visit(this );
1591:                helper.loadConstant(expression.getMethodName());
1592:                getMethodPointer.call(cv);
1593:            }
1594:
1595:            public void visitNegationExpression(NegationExpression expression) {
1596:                Expression subExpression = expression.getExpression();
1597:                subExpression.visit(this );
1598:                negation.call(cv);
1599:            }
1600:
1601:            public void visitBitwiseNegExpression(
1602:                    BitwiseNegExpression expression) {
1603:                Expression subExpression = expression.getExpression();
1604:                subExpression.visit(this );
1605:                bitNegation.call(cv);
1606:            }
1607:
1608:            public void visitCastExpression(CastExpression expression) {
1609:                ClassNode type = expression.getType();
1610:                visitAndAutoboxBoolean(expression.getExpression());
1611:                doConvertAndCast(type, expression.getExpression(), expression
1612:                        .isIgnoringAutoboxing(), false, expression.isCoerce());
1613:            }
1614:
1615:            public void visitNotExpression(NotExpression expression) {
1616:                Expression subExpression = expression.getExpression();
1617:                subExpression.visit(this );
1618:                // if we do !object, then the cast to boolean will
1619:                // do the conversion of Object to boolean. so a simple
1620:                // call to unbox is enough here.
1621:                if (!isComparisonExpression(subExpression)
1622:                        && !(subExpression instanceof  BooleanExpression)) {
1623:                    helper.unbox(boolean.class);
1624:                }
1625:                helper.negateBoolean();
1626:            }
1627:
1628:            /**
1629:             * return a primitive boolean value of the BooleanExpresion.
1630:             * @param expression
1631:             */
1632:            public void visitBooleanExpression(BooleanExpression expression) {
1633:                compileStack.pushBooleanExpression();
1634:                expression.getExpression().visit(this );
1635:
1636:                if (!isComparisonExpression(expression.getExpression())) {
1637:                    // comment out for optimization when boolean values are not autoboxed for eg. function calls.
1638:                    //           Class typeClass = expression.getExpression().getTypeClass();
1639:                    //           if (typeClass != null && typeClass != boolean.class) {
1640:                    helper.unbox(boolean.class); // to return a primitive boolean
1641:                    //            }
1642:                }
1643:                compileStack.pop();
1644:            }
1645:
1646:            private void makeInvokeMethodCall(MethodCallExpression call,
1647:                    boolean useSuper, MethodCallerMultiAdapter adapter) {
1648:                // receiver
1649:                // we operate on GroovyObject if possible
1650:                Expression objectExpression = call.getObjectExpression();
1651:                if (!isStaticMethod() && !isStaticContext()
1652:                        && isThisExpression(call.getObjectExpression())) {
1653:                    objectExpression = new CastExpression(ClassHelper
1654:                            .make(GroovyObject.class), objectExpression);
1655:                }
1656:                // message name
1657:                Expression messageName = new CastExpression(
1658:                        ClassHelper.STRING_TYPE, call.getMethod());
1659:                if (useSuper) {
1660:                    makeCall(new ClassExpression(getOutermostClass()
1661:                            .getSuperClass()), objectExpression, messageName,
1662:                            call.getArguments(), adapter, call.isSafe(), call
1663:                                    .isSpreadSafe(), false);
1664:                } else {
1665:                    makeCall(objectExpression, messageName,
1666:                            call.getArguments(), adapter, call.isSafe(), call
1667:                                    .isSpreadSafe(), call.isImplicitThis());
1668:                }
1669:            }
1670:
1671:            private void makeCall(Expression receiver, Expression message,
1672:                    Expression arguments, MethodCallerMultiAdapter adapter,
1673:                    boolean safe, boolean spreadSafe, boolean implicitThis) {
1674:                ClassNode cn = classNode;
1675:                if (isInClosure() && !implicitThis) {
1676:                    cn = getOutermostClass();
1677:                }
1678:                makeCall(new ClassExpression(cn), receiver, message, arguments,
1679:                        adapter, safe, spreadSafe, implicitThis);
1680:            }
1681:
1682:            private void makeCall(ClassExpression sender, Expression receiver,
1683:                    Expression message, Expression arguments,
1684:                    MethodCallerMultiAdapter adapter, boolean safe,
1685:                    boolean spreadSafe, boolean implicitThis) {
1686:                // ensure VariableArguments are read, not stored
1687:                boolean lhs = leftHandExpression;
1688:                leftHandExpression = false;
1689:
1690:                // sender
1691:                sender.visit(this );
1692:                // receiver
1693:                boolean oldVal = this .implicitThis;
1694:                this .implicitThis = implicitThis;
1695:                receiver.visit(this );
1696:                this .implicitThis = oldVal;
1697:                // message
1698:                if (message != null)
1699:                    message.visit(this );
1700:
1701:                // arguments
1702:                boolean containsSpreadExpression = containsSpreadExpression(arguments);
1703:                int numberOfArguments = containsSpreadExpression ? -1
1704:                        : argumentSize(arguments);
1705:                if (numberOfArguments > adapter.maxArgs
1706:                        || containsSpreadExpression) {
1707:                    ArgumentListExpression ae;
1708:                    if (arguments instanceof  ArgumentListExpression) {
1709:                        ae = (ArgumentListExpression) arguments;
1710:                    } else if (arguments instanceof  TupleExpression) {
1711:                        TupleExpression te = (TupleExpression) arguments;
1712:                        ae = new ArgumentListExpression(te.getExpressions());
1713:                    } else {
1714:                        ae = new ArgumentListExpression();
1715:                        ae.addExpression(arguments);
1716:                    }
1717:                    if (containsSpreadExpression) {
1718:                        despreadList(ae.getExpressions(), true);
1719:                    } else {
1720:                        ae.visit(this );
1721:                    }
1722:                } else if (numberOfArguments > 0) {
1723:                    TupleExpression te = (TupleExpression) arguments;
1724:                    for (int i = 0; i < numberOfArguments; i++) {
1725:                        Expression argument = te.getExpression(i);
1726:                        visitAndAutoboxBoolean(argument);
1727:                        if (argument instanceof  CastExpression)
1728:                            loadWrapper(argument);
1729:                    }
1730:                }
1731:
1732:                adapter.call(cv, numberOfArguments, safe, spreadSafe);
1733:
1734:                leftHandExpression = lhs;
1735:            }
1736:
1737:            private void despreadList(List expressions, boolean wrap) {
1738:
1739:                ArrayList spreadIndexes = new ArrayList();
1740:                ArrayList spreadExpressions = new ArrayList();
1741:                ArrayList normalArguments = new ArrayList();
1742:                for (int i = 0; i < expressions.size(); i++) {
1743:                    Object expr = expressions.get(i);
1744:                    if (!(expr instanceof  SpreadExpression)) {
1745:                        normalArguments.add(expr);
1746:                    } else {
1747:                        spreadIndexes.add(new ConstantExpression(new Integer(i
1748:                                - spreadExpressions.size())));
1749:                        spreadExpressions.add(((SpreadExpression) expr)
1750:                                .getExpression());
1751:                    }
1752:                }
1753:
1754:                //load normal arguments as array
1755:                visitTupleExpression(
1756:                        new ArgumentListExpression(normalArguments), wrap);
1757:                //load spread expressions as array
1758:                (new TupleExpression(spreadExpressions)).visit(this );
1759:                //load insertion index
1760:                (new ArrayExpression(ClassHelper.int_TYPE, spreadIndexes, null))
1761:                        .visit(this );
1762:                despreadList.call(cv);
1763:            }
1764:
1765:            public void visitMethodCallExpression(MethodCallExpression call) {
1766:                onLineNumber(call, "visitMethodCallExpression: \""
1767:                        + call.getMethod() + "\":");
1768:
1769:                Expression arguments = call.getArguments();
1770:                String methodName = call.getMethodAsString();
1771:                boolean isSuperMethodCall = usesSuper(call);
1772:                boolean isThisExpression = isThisExpression(call
1773:                        .getObjectExpression());
1774:
1775:                // are we a local variable
1776:                if (methodName != null && isThisExpression
1777:                        && isFieldOrVariable(methodName)
1778:                        && !classNode.hasPossibleMethod(methodName, arguments)) {
1779:                    // lets invoke the closure method
1780:                    visitVariableExpression(new VariableExpression(methodName));
1781:                    arguments.visit(this );
1782:                    invokeClosureMethod.call(cv);
1783:                } else {
1784:                    MethodCallerMultiAdapter adapter = invokeMethod;
1785:                    if (isThisExpression)
1786:                        adapter = invokeMethodOnCurrent;
1787:                    if (isSuperMethodCall)
1788:                        adapter = invokeMethodOnSuper;
1789:                    if (isStaticInvocation(call))
1790:                        adapter = invokeStaticMethod;
1791:                    makeInvokeMethodCall(call, isSuperMethodCall, adapter);
1792:                }
1793:            }
1794:
1795:            private boolean isStaticInvocation(MethodCallExpression call) {
1796:                if (!isThisExpression(call.getObjectExpression()))
1797:                    return false;
1798:                if (isStaticMethod())
1799:                    return true;
1800:                return isStaticContext() && !call.isImplicitThis();
1801:            }
1802:
1803:            protected boolean emptyArguments(Expression arguments) {
1804:                return argumentSize(arguments) == 0;
1805:            }
1806:
1807:            protected static boolean containsSpreadExpression(
1808:                    Expression arguments) {
1809:                List args = null;
1810:                if (arguments instanceof  TupleExpression) {
1811:                    TupleExpression tupleExpression = (TupleExpression) arguments;
1812:                    args = tupleExpression.getExpressions();
1813:                } else if (arguments instanceof  ListExpression) {
1814:                    ListExpression le = (ListExpression) arguments;
1815:                    args = le.getExpressions();
1816:                } else {
1817:                    return arguments instanceof  SpreadExpression;
1818:                }
1819:                for (Iterator iter = args.iterator(); iter.hasNext();) {
1820:                    if (iter.next() instanceof  SpreadExpression)
1821:                        return true;
1822:                }
1823:                return false;
1824:            }
1825:
1826:            protected static int argumentSize(Expression arguments) {
1827:                if (arguments instanceof  TupleExpression) {
1828:                    TupleExpression tupleExpression = (TupleExpression) arguments;
1829:                    int size = tupleExpression.getExpressions().size();
1830:                    return size;
1831:                }
1832:                return 1;
1833:            }
1834:
1835:            public void visitStaticMethodCallExpression(
1836:                    StaticMethodCallExpression call) {
1837:                onLineNumber(call, "visitStaticMethodCallExpression: \""
1838:                        + call.getMethod() + "\":");
1839:
1840:                makeCall(new ClassExpression(call.getOwnerType()),
1841:                        new ConstantExpression(call.getMethod()), call
1842:                                .getArguments(), invokeStaticMethod, false,
1843:                        false, false);
1844:            }
1845:
1846:            private void visitSpecialConstructorCall(
1847:                    ConstructorCallExpression call) {
1848:                ClassNode callNode = classNode;
1849:                if (call.isSuperCall())
1850:                    callNode = callNode.getSuperClass();
1851:                List constructors = sortConstructors(call, callNode);
1852:                call.getArguments().visit(this );
1853:                // keep Objet[] on stack
1854:                cv.visitInsn(DUP);
1855:                // to select the constructor we need also the number of
1856:                // available constructors and the class we want to make
1857:                // the call on
1858:                helper.pushConstant(constructors.size());
1859:                visitClassExpression(new ClassExpression(callNode));
1860:                // removes one Object[] leaves the int containing the 
1861:                // call flags and the construtcor number
1862:                selectConstructorAndTransformArguments.call(cv);
1863:                // Object[],int -> int,Object[],int
1864:                // we need to examine the flags and maybe change the 
1865:                // Object[] later, so this reordering will do the job
1866:                cv.visitInsn(DUP_X1);
1867:                // test if rewrap flag is set
1868:                cv.visitInsn(ICONST_1);
1869:                cv.visitInsn(IAND);
1870:                Label afterIf = new Label();
1871:                cv.visitJumpInsn(IFEQ, afterIf);
1872:                // true part, so rewrap using the first argument
1873:                cv.visitInsn(ICONST_0);
1874:                cv.visitInsn(AALOAD);
1875:                cv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
1876:                cv.visitLabel(afterIf);
1877:                // here the stack is int,Object[], but we need the
1878:                // the int for our table, so swap it
1879:                cv.visitInsn(SWAP);
1880:                //load "this"
1881:                cv.visitVarInsn(ALOAD, 0);
1882:                cv.visitInsn(SWAP);
1883:                //prepare switch with >>8        
1884:                cv.visitIntInsn(BIPUSH, 8);
1885:                cv.visitInsn(ISHR);
1886:                Label[] targets = new Label[constructors.size()];
1887:                int[] indices = new int[constructors.size()];
1888:                for (int i = 0; i < targets.length; i++) {
1889:                    targets[i] = new Label();
1890:                    indices[i] = i;
1891:                }
1892:                // create switch targets
1893:                Label defaultLabel = new Label();
1894:                Label afterSwitch = new Label();
1895:                cv.visitLookupSwitchInsn(defaultLabel, indices, targets);
1896:                for (int i = 0; i < targets.length; i++) {
1897:                    cv.visitLabel(targets[i]);
1898:                    // to keep the stack height, we need to leave
1899:                    // one Object[] on the stack as last element. At the 
1900:                    // same time, we need the Object[] on top of the stack
1901:                    // to extract the parameters. So a SWAP will exchange 
1902:                    // "this" and Object[], a DUP_X1 will then copy the Object[]
1903:                    /// to the last place in the stack: 
1904:                    //     Object[],this -SWAP-> this,Object[]
1905:                    //     this,Object[] -DUP_X1-> Object[],this,Object[] 
1906:                    cv.visitInsn(SWAP);
1907:                    cv.visitInsn(DUP_X1);
1908:
1909:                    ConstructorNode cn = (ConstructorNode) constructors.get(i);
1910:                    String descriptor = helper.getMethodDescriptor(
1911:                            ClassHelper.VOID_TYPE, cn.getParameters());
1912:                    // unwrap the Object[] and make transformations if needed
1913:                    // that means, to duplicate the Object[], make a cast with possible
1914:                    // unboxing and then swap it with the Object[] for each parameter
1915:                    Parameter[] parameters = cn.getParameters();
1916:                    for (int p = 0; p < parameters.length; p++) {
1917:                        cv.visitInsn(DUP);
1918:                        helper.pushConstant(p);
1919:                        cv.visitInsn(AALOAD);
1920:                        ClassNode type = parameters[p].getType();
1921:                        if (ClassHelper.isPrimitiveType(type)) {
1922:                            helper.unbox(type);
1923:                        } else {
1924:                            helper.doCast(type);
1925:                        }
1926:                        helper.swapWithObject(type);
1927:                    }
1928:                    // at the end we remove the Object[]
1929:                    cv.visitInsn(POP);
1930:                    // make the constructor call
1931:                    cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper
1932:                            .getClassInternalName(callNode), "<init>",
1933:                            descriptor);
1934:                    cv.visitJumpInsn(GOTO, afterSwitch);
1935:                }
1936:                cv.visitLabel(defaultLabel);
1937:                // this part should never be reached!
1938:                cv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
1939:                cv.visitInsn(DUP);
1940:                cv.visitLdcInsn("illegal constructor number");
1941:                cv.visitMethodInsn(INVOKESPECIAL,
1942:                        "java/lang/IllegalArgumentException", "<init>",
1943:                        "(Ljava/lang/String;)V");
1944:                cv.visitInsn(ATHROW);
1945:                cv.visitLabel(afterSwitch);
1946:            }
1947:
1948:            private List sortConstructors(ConstructorCallExpression call,
1949:                    ClassNode callNode) {
1950:                // sort in a new list to prevent side effects
1951:                List constructors = new ArrayList(callNode
1952:                        .getDeclaredConstructors());
1953:                Comparator comp = new Comparator() {
1954:                    public int compare(Object arg0, Object arg1) {
1955:                        ConstructorNode c0 = (ConstructorNode) arg0;
1956:                        ConstructorNode c1 = (ConstructorNode) arg1;
1957:                        String descriptor0 = helper.getMethodDescriptor(
1958:                                ClassHelper.VOID_TYPE, c0.getParameters());
1959:                        String descriptor1 = helper.getMethodDescriptor(
1960:                                ClassHelper.VOID_TYPE, c1.getParameters());
1961:                        return descriptor0.compareTo(descriptor1);
1962:                    }
1963:                };
1964:                Collections.sort(constructors, comp);
1965:                return constructors;
1966:            }
1967:
1968:            public void visitConstructorCallExpression(
1969:                    ConstructorCallExpression call) {
1970:                onLineNumber(call, "visitConstructorCallExpression: \""
1971:                        + call.getType().getName() + "\":");
1972:
1973:                if (call.isSpecialCall()) {
1974:                    visitSpecialConstructorCall(call);
1975:                    return;
1976:                }
1977:
1978:                Expression arguments = call.getArguments();
1979:                if (arguments instanceof  TupleExpression) {
1980:                    TupleExpression tupleExpression = (TupleExpression) arguments;
1981:                    int size = tupleExpression.getExpressions().size();
1982:                    if (size == 0) {
1983:                        arguments = MethodCallExpression.NO_ARGUMENTS;
1984:                    }
1985:                }
1986:
1987:                Expression receiverClass = new ClassExpression(call.getType());
1988:                makeCall(receiverClass, null, arguments, invokeNew, false,
1989:                        false, false);
1990:            }
1991:
1992:            private static String makeFieldClassName(ClassNode type) {
1993:                String internalName = BytecodeHelper.getClassInternalName(type);
1994:                StringBuffer ret = new StringBuffer(internalName.length());
1995:                for (int i = 0; i < internalName.length(); i++) {
1996:                    char c = internalName.charAt(i);
1997:                    if (c == '/') {
1998:                        ret.append('$');
1999:                    } else if (c == ';') {
2000:                        //append nothing -> delete ';'
2001:                    } else {
2002:                        ret.append(c);
2003:                    }
2004:                }
2005:                return ret.toString();
2006:            }
2007:
2008:            private static String getStaticFieldName(ClassNode type) {
2009:                ClassNode componentType = type;
2010:                String prefix = "";
2011:                for (; componentType.isArray(); componentType = componentType
2012:                        .getComponentType()) {
2013:                    prefix += "$";
2014:                }
2015:                if (prefix.length() != 0)
2016:                    prefix = "array" + prefix;
2017:                String name = prefix + "class$"
2018:                        + makeFieldClassName(componentType);
2019:                return name;
2020:            }
2021:
2022:            private void visitAttributeOrProperty(
2023:                    PropertyExpression expression,
2024:                    MethodCallerMultiAdapter adapter) {
2025:                Expression objectExpression = expression.getObjectExpression();
2026:                if (isThisExpression(objectExpression)) {
2027:                    // lets use the field expression if its available
2028:                    String name = expression.getPropertyAsString();
2029:                    if (name != null) {
2030:                        FieldNode field = classNode.getField(name);
2031:                        if (field != null) {
2032:                            visitFieldExpression(new FieldExpression(field));
2033:                            return;
2034:                        }
2035:                    }
2036:                }
2037:
2038:                // arguments already on stack if any
2039:                makeCall(
2040:                        objectExpression, // receiver
2041:                        new CastExpression(ClassHelper.STRING_TYPE, expression
2042:                                .getProperty()), // messageName
2043:                        MethodCallExpression.NO_ARGUMENTS, adapter, expression
2044:                                .isSafe(), expression.isSpreadSafe(),
2045:                        expression.isImplicitThis());
2046:            }
2047:
2048:            private boolean isStaticContext() {
2049:                if (!isInClosure())
2050:                    return false;
2051:                if (constructorNode != null)
2052:                    return false;
2053:                return classNode.isStaticClass() || methodNode.isStatic();
2054:            }
2055:
2056:            public void visitPropertyExpression(PropertyExpression expression) {
2057:                Expression objectExpression = expression.getObjectExpression();
2058:                MethodCallerMultiAdapter adapter;
2059:                if (leftHandExpression) {
2060:                    adapter = setProperty;
2061:                    if (isGroovyObject(objectExpression))
2062:                        adapter = setGroovyObjectProperty;
2063:                    if (isStaticContext() && isThisOrSuper(objectExpression))
2064:                        adapter = setProperty;
2065:                } else {
2066:                    adapter = getProperty;
2067:                    if (isGroovyObject(objectExpression))
2068:                        adapter = getGroovyObjectProperty;
2069:                    if (isStaticContext() && isThisOrSuper(objectExpression))
2070:                        adapter = getProperty;
2071:                }
2072:                visitAttributeOrProperty(expression, adapter);
2073:            }
2074:
2075:            public void visitAttributeExpression(AttributeExpression expression) {
2076:                Expression objectExpression = expression.getObjectExpression();
2077:                MethodCallerMultiAdapter adapter;
2078:                if (leftHandExpression) {
2079:                    adapter = setField;
2080:                    if (isGroovyObject(objectExpression))
2081:                        adapter = setGroovyObjectField;
2082:                    if (usesSuper(expression))
2083:                        adapter = getFieldOnSuper;
2084:                } else {
2085:                    adapter = getField;
2086:                    if (isGroovyObject(objectExpression))
2087:                        adapter = getGroovyObjectField;
2088:                    if (usesSuper(expression))
2089:                        adapter = getFieldOnSuper;
2090:                }
2091:                visitAttributeOrProperty(expression, adapter);
2092:            }
2093:
2094:            protected boolean isGroovyObject(Expression objectExpression) {
2095:                return isThisExpression(objectExpression);
2096:            }
2097:
2098:            public void visitFieldExpression(FieldExpression expression) {
2099:                FieldNode field = expression.getField();
2100:
2101:                if (field.isStatic()) {
2102:                    if (leftHandExpression) {
2103:                        storeStaticField(expression);
2104:                    } else {
2105:                        loadStaticField(expression);
2106:                    }
2107:                } else {
2108:                    if (leftHandExpression) {
2109:                        storeThisInstanceField(expression);
2110:                    } else {
2111:                        loadInstanceField(expression);
2112:                    }
2113:                }
2114:            }
2115:
2116:            /**
2117:             *
2118:             * @param fldExp
2119:             */
2120:            public void loadStaticField(FieldExpression fldExp) {
2121:                FieldNode field = fldExp.getField();
2122:                boolean holder = field.isHolder() && !isInClosureConstructor();
2123:                ClassNode type = field.getType();
2124:
2125:                String ownerName = (field.getOwner().equals(classNode)) ? internalClassName
2126:                        : BytecodeHelper.getClassInternalName(field.getOwner());
2127:                if (holder) {
2128:                    cv.visitFieldInsn(GETSTATIC, ownerName, fldExp
2129:                            .getFieldName(), BytecodeHelper
2130:                            .getTypeDescription(type));
2131:                    cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference",
2132:                            "get", "()Ljava/lang/Object;");
2133:                } else {
2134:                    cv.visitFieldInsn(GETSTATIC, ownerName, fldExp
2135:                            .getFieldName(), BytecodeHelper
2136:                            .getTypeDescription(type));
2137:                    if (ClassHelper.isPrimitiveType(type)) {
2138:                        helper.box(type);
2139:                    } else {
2140:                    }
2141:                }
2142:            }
2143:
2144:            /**
2145:             * RHS instance field. should move most of the code in the BytecodeHelper
2146:             * @param fldExp
2147:             */
2148:            public void loadInstanceField(FieldExpression fldExp) {
2149:                FieldNode field = fldExp.getField();
2150:                boolean holder = field.isHolder() && !isInClosureConstructor();
2151:                ClassNode type = field.getType();
2152:                String ownerName = (field.getOwner().equals(classNode)) ? internalClassName
2153:                        : helper.getClassInternalName(field.getOwner());
2154:
2155:                cv.visitVarInsn(ALOAD, 0);
2156:                cv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(),
2157:                        BytecodeHelper.getTypeDescription(type));
2158:
2159:                if (holder) {
2160:                    cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference",
2161:                            "get", "()Ljava/lang/Object;");
2162:                } else {
2163:                    if (ClassHelper.isPrimitiveType(type)) {
2164:                        helper.box(type);
2165:                    } else {
2166:                    }
2167:                }
2168:            }
2169:
2170:            public void storeThisInstanceField(FieldExpression expression) {
2171:                FieldNode field = expression.getField();
2172:
2173:                boolean holder = field.isHolder() && !isInClosureConstructor();
2174:                ClassNode type = field.getType();
2175:
2176:                String ownerName = (field.getOwner().equals(classNode)) ? internalClassName
2177:                        : BytecodeHelper.getClassInternalName(field.getOwner());
2178:                if (holder) {
2179:                    cv.visitVarInsn(ALOAD, 0);
2180:                    cv.visitFieldInsn(GETFIELD, ownerName, expression
2181:                            .getFieldName(), BytecodeHelper
2182:                            .getTypeDescription(type));
2183:                    cv.visitInsn(SWAP);
2184:                    cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference",
2185:                            "set", "(Ljava/lang/Object;)V");
2186:                } else {
2187:                    if (isInClosureConstructor()) {
2188:                        helper.doCast(type);
2189:                    } else if (!ClassHelper.isPrimitiveType(type)) {
2190:                        doConvertAndCast(type);
2191:                    }
2192:                    cv.visitVarInsn(ALOAD, 0);
2193:                    //helper.swapObjectWith(type);
2194:                    cv.visitInsn(SWAP);
2195:                    helper.unbox(type);
2196:                    helper.putField(field, ownerName);
2197:                }
2198:            }
2199:
2200:            public void storeStaticField(FieldExpression expression) {
2201:                FieldNode field = expression.getField();
2202:
2203:                boolean holder = field.isHolder() && !isInClosureConstructor();
2204:
2205:                ClassNode type = field.getType();
2206:
2207:                String ownerName = (field.getOwner().equals(classNode)) ? internalClassName
2208:                        : helper.getClassInternalName(field.getOwner());
2209:                if (holder) {
2210:                    cv.visitFieldInsn(GETSTATIC, ownerName, expression
2211:                            .getFieldName(), BytecodeHelper
2212:                            .getTypeDescription(type));
2213:                    cv.visitInsn(SWAP);
2214:                    cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference",
2215:                            "set", "(Ljava/lang/Object;)V");
2216:                } else {
2217:                    helper.doCast(type);
2218:                    cv.visitFieldInsn(PUTSTATIC, ownerName, expression
2219:                            .getFieldName(), BytecodeHelper
2220:                            .getTypeDescription(type));
2221:                }
2222:            }
2223:
2224:            protected void visitOuterFieldExpression(
2225:                    FieldExpression expression, ClassNode outerClassNode,
2226:                    int steps, boolean first) {
2227:                FieldNode field = expression.getField();
2228:                boolean isStatic = field.isStatic();
2229:
2230:                int tempIdx = compileStack.defineTemporaryVariable(field,
2231:                        leftHandExpression && first);
2232:
2233:                if (steps > 1 || !isStatic) {
2234:                    cv.visitVarInsn(ALOAD, 0);
2235:                    cv.visitFieldInsn(GETFIELD, internalClassName, "owner",
2236:                            BytecodeHelper.getTypeDescription(outerClassNode));
2237:                }
2238:
2239:                if (steps == 1) {
2240:                    int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC
2241:                            : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD);
2242:                    String ownerName = BytecodeHelper
2243:                            .getClassInternalName(outerClassNode);
2244:
2245:                    if (leftHandExpression) {
2246:                        cv.visitVarInsn(ALOAD, tempIdx);
2247:                        boolean holder = field.isHolder()
2248:                                && !isInClosureConstructor();
2249:                        if (!holder) {
2250:                            doConvertAndCast(field.getType());
2251:                        }
2252:                    }
2253:                    cv.visitFieldInsn(opcode, ownerName, expression
2254:                            .getFieldName(), BytecodeHelper
2255:                            .getTypeDescription(field.getType()));
2256:                    if (!leftHandExpression) {
2257:                        if (ClassHelper.isPrimitiveType(field.getType())) {
2258:                            helper.box(field.getType());
2259:                        }
2260:                    }
2261:                }
2262:
2263:                else {
2264:                    visitOuterFieldExpression(expression, outerClassNode
2265:                            .getOuterClass(), steps - 1, false);
2266:                }
2267:            }
2268:
2269:            /**
2270:             *  Visits a bare (unqualified) variable expression.
2271:             */
2272:
2273:            public void visitVariableExpression(VariableExpression expression) {
2274:
2275:                String variableName = expression.getName();
2276:
2277:                //-----------------------------------------------------------------------
2278:                // SPECIAL CASES
2279:
2280:                //
2281:                // "this" for static methods is the Class instance
2282:
2283:                ClassNode classNode = this .classNode;
2284:                if (isInClosure())
2285:                    classNode = getOutermostClass();
2286:
2287:                if (variableName.equals("this")) {
2288:                    if (isStaticMethod()
2289:                            || (!implicitThis && isStaticContext())) {
2290:                        visitClassExpression(new ClassExpression(classNode));
2291:                    } else {
2292:                        loadThis();
2293:                    }
2294:                    return;
2295:                }
2296:
2297:                //
2298:                // "super" also requires special handling
2299:
2300:                if (variableName.equals("super")) {
2301:                    if (isStaticMethod()) {
2302:                        visitClassExpression(new ClassExpression(classNode
2303:                                .getSuperClass()));
2304:                    } else {
2305:                        loadThis();
2306:                    }
2307:                    return; // <<< FLOW CONTROL <<<<<<<<<
2308:                }
2309:
2310:                Variable variable = compileStack.getVariable(variableName,
2311:                        false);
2312:
2313:                VariableScope scope = compileStack.getScope();
2314:                if (variable == null) {
2315:                    processClassVariable(variableName);
2316:                } else {
2317:                    processStackVariable(variable);
2318:                }
2319:            }
2320:
2321:            private void loadThis() {
2322:                cv.visitVarInsn(ALOAD, 0);
2323:                if (!implicitThis && isInClosure()) {
2324:                    cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Closure",
2325:                            "getThisObject", "()Ljava/lang/Object;");
2326:                }
2327:            }
2328:
2329:            protected void processStackVariable(Variable variable) {
2330:                if (leftHandExpression) {
2331:                    helper.storeVar(variable);
2332:                } else {
2333:                    helper.loadVar(variable);
2334:                }
2335:                if (ASM_DEBUG) {
2336:                    helper.mark("var: " + variable.getName());
2337:                }
2338:            }
2339:
2340:            protected void processClassVariable(String name) {
2341:                if (passingClosureParams && isInScriptBody()) {
2342:                    // lets create a ScriptReference to pass into the closure
2343:                    cv.visitTypeInsn(NEW,
2344:                            "org/codehaus/groovy/runtime/ScriptReference");
2345:                    cv.visitInsn(DUP);
2346:
2347:                    loadThisOrOwner();
2348:                    cv.visitLdcInsn(name);
2349:
2350:                    cv.visitMethodInsn(INVOKESPECIAL,
2351:                            "org/codehaus/groovy/runtime/ScriptReference",
2352:                            "<init>",
2353:                            "(Lgroovy/lang/Script;Ljava/lang/String;)V");
2354:                } else {
2355:                    PropertyExpression pexp = new PropertyExpression(
2356:                            VariableExpression.THIS_EXPRESSION, name);
2357:                    pexp.setImplicitThis(true);
2358:                    visitPropertyExpression(pexp);
2359:                }
2360:            }
2361:
2362:            protected void processFieldAccess(String name, FieldNode field,
2363:                    int steps) {
2364:                FieldExpression expression = new FieldExpression(field);
2365:
2366:                if (steps == 0) {
2367:                    visitFieldExpression(expression);
2368:                } else {
2369:                    visitOuterFieldExpression(expression, classNode
2370:                            .getOuterClass(), steps, true);
2371:                }
2372:            }
2373:
2374:            /**
2375:             * @return true if we are in a script body, where all variables declared are no longer
2376:             * local variables but are properties
2377:             */
2378:            protected boolean isInScriptBody() {
2379:                if (classNode.isScriptBody()) {
2380:                    return true;
2381:                } else {
2382:                    return classNode.isScript() && methodNode != null
2383:                            && methodNode.getName().equals("run");
2384:                }
2385:            }
2386:
2387:            /**
2388:             * @return true if this expression will have left a value on the stack
2389:             * that must be popped
2390:             */
2391:            protected boolean isPopRequired(Expression expression) {
2392:                if (expression instanceof  MethodCallExpression) {
2393:                    if (expression.getType() == ClassHelper.VOID_TYPE) { // nothing on the stack
2394:                        return false;
2395:                    } else {
2396:                        return !usesSuper((MethodCallExpression) expression);
2397:                    }
2398:                }
2399:                if (expression instanceof  DeclarationExpression) {
2400:                    return false;
2401:                }
2402:                if (expression instanceof  BinaryExpression) {
2403:                    BinaryExpression binExp = (BinaryExpression) expression;
2404:                    switch (binExp.getOperation().getType()) { // br todo should leave a copy of the value on the stack for all the assignemnt.
2405:                    //                case Types.EQUAL :   // br a copy of the right value is left on the stack (see evaluateEqual()) so a pop is required for a standalone assignment
2406:                    //                case Types.PLUS_EQUAL : // this and the following are related to evaluateBinaryExpressionWithAsignment()
2407:                    //                case Types.MINUS_EQUAL :
2408:                    //                case Types.MULTIPLY_EQUAL :
2409:                    //                case Types.DIVIDE_EQUAL :
2410:                    //                case Types.INTDIV_EQUAL :
2411:                    //                case Types.MOD_EQUAL :
2412:                    //                    return false;
2413:                    }
2414:                }
2415:                if (expression instanceof  ConstructorCallExpression) {
2416:                    ConstructorCallExpression cce = (ConstructorCallExpression) expression;
2417:                    return !cce.isSpecialCall();
2418:                }
2419:                return true;
2420:            }
2421:
2422:            protected void createInterfaceSyntheticStaticFields() {
2423:                if (syntheticStaticFields.isEmpty())
2424:                    return;
2425:
2426:                addInnerClass(interfaceClassLoadingClass);
2427:
2428:                for (Iterator iter = syntheticStaticFields.iterator(); iter
2429:                        .hasNext();) {
2430:                    String staticFieldName = (String) iter.next();
2431:                    // generate a field node
2432:                    interfaceClassLoadingClass.addField(staticFieldName,
2433:                            ACC_STATIC + ACC_SYNTHETIC, ClassHelper.CLASS_Type,
2434:                            null);
2435:                }
2436:            }
2437:
2438:            protected void createSyntheticStaticFields() {
2439:                for (Iterator iter = syntheticStaticFields.iterator(); iter
2440:                        .hasNext();) {
2441:                    String staticFieldName = (String) iter.next();
2442:                    // generate a field node
2443:                    FieldNode fn = classNode.getField(staticFieldName);
2444:                    if (fn != null) {
2445:                        boolean type = fn.getType() == ClassHelper.CLASS_Type;
2446:                        boolean modifiers = fn.getModifiers() == ACC_STATIC
2447:                                + ACC_SYNTHETIC;
2448:                        if (type && modifiers)
2449:                            continue;
2450:                        String text = "";
2451:                        if (!type)
2452:                            text = " with wrong type: " + fn.getType()
2453:                                    + " (java.lang.Class needed)";
2454:                        if (!modifiers)
2455:                            text = " with wrong modifiers: "
2456:                                    + fn.getModifiers() + " ("
2457:                                    + (ACC_STATIC + ACC_SYNTHETIC) + " needed)";
2458:                        throwException("tried to set a static syntethic field "
2459:                                + staticFieldName
2460:                                + " in "
2461:                                + classNode.getName()
2462:                                + " for class resolving, but found alreeady a node of that"
2463:                                + " name " + text);
2464:                    } else {
2465:                        cw.visitField(ACC_STATIC + ACC_SYNTHETIC,
2466:                                staticFieldName, "Ljava/lang/Class;", null,
2467:                                null);
2468:                    }
2469:                }
2470:
2471:                cv = cw.visitMethod(ACC_STATIC + ACC_SYNTHETIC, "class$",
2472:                        "(Ljava/lang/String;)Ljava/lang/Class;", null, null);
2473:                Label l0 = new Label();
2474:                cv.visitLabel(l0);
2475:                cv.visitVarInsn(ALOAD, 0);
2476:                cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName",
2477:                        "(Ljava/lang/String;)Ljava/lang/Class;");
2478:                Label l1 = new Label();
2479:                cv.visitLabel(l1);
2480:                cv.visitInsn(ARETURN);
2481:                Label l2 = new Label();
2482:                cv.visitLabel(l2);
2483:                cv.visitVarInsn(ASTORE, 1);
2484:                cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
2485:                cv.visitInsn(DUP);
2486:                cv.visitVarInsn(ALOAD, 1);
2487:                cv.visitMethodInsn(INVOKEVIRTUAL,
2488:                        "java/lang/ClassNotFoundException", "getMessage",
2489:                        "()Ljava/lang/String;");
2490:                cv.visitMethodInsn(INVOKESPECIAL,
2491:                        "java/lang/NoClassDefFoundError", "<init>",
2492:                        "(Ljava/lang/String;)V");
2493:                cv.visitInsn(ATHROW);
2494:                cv.visitTryCatchBlock(l0, l2, l2,
2495:                        "java/lang/ClassNotFoundException"); // br using l2 as the 2nd param seems create the right table entry
2496:                cv.visitMaxs(3, 2);
2497:            }
2498:
2499:            /** load class object on stack */
2500:            public void visitClassExpression(ClassExpression expression) {
2501:                ClassNode type = expression.getType();
2502:
2503:                if (ClassHelper.isPrimitiveType(type)) {
2504:                    ClassNode objectType = ClassHelper.getWrapper(type);
2505:                    cv.visitFieldInsn(GETSTATIC, BytecodeHelper
2506:                            .getClassInternalName(objectType), "TYPE",
2507:                            "Ljava/lang/Class;");
2508:                } else {
2509:                    String staticFieldName;
2510:                    if (type.equals(classNode)) {
2511:                        staticFieldName = "class$0";
2512:                        if (compileStack.getCurrentClassIndex() != -1) {
2513:                            cv.visitVarInsn(ALOAD, compileStack
2514:                                    .getCurrentClassIndex());
2515:                            return;
2516:                        }
2517:                    } else if (type.equals(ClassHelper.METACLASS_TYPE)) {
2518:                        staticFieldName = getStaticFieldName(type);
2519:                        if (compileStack.getCurrentMetaClassIndex() != -1) {
2520:                            cv.visitVarInsn(ALOAD, compileStack
2521:                                    .getCurrentMetaClassIndex());
2522:                            return;
2523:                        }
2524:                    } else {
2525:                        staticFieldName = getStaticFieldName(type);
2526:                    }
2527:
2528:                    syntheticStaticFields.add(staticFieldName);
2529:
2530:                    String internalClassName = this .internalClassName;
2531:                    if (classNode.isInterface()) {
2532:                        internalClassName = BytecodeHelper
2533:                                .getClassInternalName(interfaceClassLoadingClass);
2534:                    }
2535:
2536:                    cv.visitFieldInsn(GETSTATIC, internalClassName,
2537:                            staticFieldName, "Ljava/lang/Class;");
2538:
2539:                    Label l0 = new Label();
2540:                    cv.visitJumpInsn(IFNONNULL, l0);
2541:                    cv.visitLdcInsn(BytecodeHelper
2542:                            .getClassLoadingTypeDescription(type));
2543:                    cv.visitMethodInsn(INVOKESTATIC, internalClassName,
2544:                            "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
2545:                    cv.visitInsn(DUP);
2546:                    cv.visitFieldInsn(PUTSTATIC, internalClassName,
2547:                            staticFieldName, "Ljava/lang/Class;");
2548:                    Label l1 = new Label();
2549:                    cv.visitJumpInsn(GOTO, l1);
2550:                    cv.visitLabel(l0);
2551:                    cv.visitFieldInsn(GETSTATIC, internalClassName,
2552:                            staticFieldName, "Ljava/lang/Class;");
2553:                    cv.visitLabel(l1);
2554:
2555:                    if (type.equals(classNode)) {
2556:                        cv.visitInsn(DUP);
2557:                        int index = compileStack.defineTemporaryVariable(
2558:                                "class$0", ClassHelper.CLASS_Type, true);
2559:                        compileStack.setCurrentClassIndex(index);
2560:                    } else if (type.equals(ClassHelper.METACLASS_TYPE)) {
2561:                        cv.visitInsn(DUP);
2562:                        int index = compileStack.defineTemporaryVariable(
2563:                                "meta$class$0", ClassHelper.CLASS_Type, true);
2564:                        compileStack.setCurrentMetaClassIndex(index);
2565:                    }
2566:                }
2567:            }
2568:
2569:            public void visitRangeExpression(RangeExpression expression) {
2570:                expression.getFrom().visit(this );
2571:                expression.getTo().visit(this );
2572:
2573:                helper.pushConstant(expression.isInclusive());
2574:
2575:                createRangeMethod.call(cv);
2576:            }
2577:
2578:            public void visitMapEntryExpression(MapEntryExpression expression) {
2579:                throw new GroovyBugError(
2580:                        "MapEntryExpression should not be visited here");
2581:            }
2582:
2583:            public void visitMapExpression(MapExpression expression) {
2584:                List entries = expression.getMapEntryExpressions();
2585:                int size = entries.size();
2586:                helper.pushConstant(size * 2);
2587:
2588:                cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2589:
2590:                int i = 0;
2591:                for (Iterator iter = entries.iterator(); iter.hasNext();) {
2592:                    Object object = iter.next();
2593:                    MapEntryExpression entry = (MapEntryExpression) object;
2594:
2595:                    cv.visitInsn(DUP);
2596:                    helper.pushConstant(i++);
2597:                    visitAndAutoboxBoolean(entry.getKeyExpression());
2598:                    cv.visitInsn(AASTORE);
2599:
2600:                    cv.visitInsn(DUP);
2601:                    helper.pushConstant(i++);
2602:                    visitAndAutoboxBoolean(entry.getValueExpression());
2603:                    cv.visitInsn(AASTORE);
2604:                }
2605:                createMapMethod.call(cv);
2606:            }
2607:
2608:            public void visitArgumentlistExpression(ArgumentListExpression ale) {
2609:                if (containsSpreadExpression(ale)) {
2610:                    despreadList(ale.getExpressions(), true);
2611:                } else {
2612:                    visitTupleExpression(ale, true);
2613:                }
2614:            }
2615:
2616:            public void visitTupleExpression(TupleExpression expression) {
2617:                visitTupleExpression(expression, false);
2618:            }
2619:
2620:            private void visitTupleExpression(TupleExpression expression,
2621:                    boolean useWrapper) {
2622:                int size = expression.getExpressions().size();
2623:
2624:                helper.pushConstant(size);
2625:
2626:                cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2627:
2628:                for (int i = 0; i < size; i++) {
2629:                    cv.visitInsn(DUP);
2630:                    helper.pushConstant(i);
2631:                    Expression argument = expression.getExpression(i);
2632:                    visitAndAutoboxBoolean(argument);
2633:                    if (useWrapper && argument instanceof  CastExpression)
2634:                        loadWrapper(argument);
2635:
2636:                    cv.visitInsn(AASTORE);
2637:                }
2638:            }
2639:
2640:            private void loadWrapper(Expression argument) {
2641:                ClassNode goalClass = argument.getType();
2642:                visitClassExpression(new ClassExpression(goalClass));
2643:                if (goalClass.isDerivedFromGroovyObject()) {
2644:                    createGroovyObjectWrapperMethod.call(cv);
2645:                } else {
2646:                    createPojoWrapperMethod.call(cv);
2647:                }
2648:            }
2649:
2650:            public void visitArrayExpression(ArrayExpression expression) {
2651:                ClassNode elementType = expression.getElementType();
2652:                String arrayTypeName = BytecodeHelper
2653:                        .getClassInternalName(elementType);
2654:                List sizeExpression = expression.getSizeExpression();
2655:
2656:                int size = 0;
2657:                int dimensions = 0;
2658:                if (sizeExpression != null) {
2659:                    for (Iterator iter = sizeExpression.iterator(); iter
2660:                            .hasNext();) {
2661:                        Expression element = (Expression) iter.next();
2662:                        if (element == ConstantExpression.EMTPY_EXPRESSION)
2663:                            break;
2664:                        dimensions++;
2665:                        // lets convert to an int
2666:                        visitAndAutoboxBoolean(element);
2667:                        helper.unbox(int.class);
2668:                    }
2669:                } else {
2670:                    size = expression.getExpressions().size();
2671:                    helper.pushConstant(size);
2672:                }
2673:
2674:                int storeIns = AASTORE;
2675:                if (sizeExpression != null) {
2676:                    arrayTypeName = BytecodeHelper
2677:                            .getTypeDescription(expression.getType());
2678:                    cv.visitMultiANewArrayInsn(arrayTypeName, dimensions);
2679:                } else if (ClassHelper.isPrimitiveType(elementType)) {
2680:                    int primType = 0;
2681:                    if (elementType == ClassHelper.boolean_TYPE) {
2682:                        primType = T_BOOLEAN;
2683:                        storeIns = BASTORE;
2684:                    } else if (elementType == ClassHelper.char_TYPE) {
2685:                        primType = T_CHAR;
2686:                        storeIns = CASTORE;
2687:                    } else if (elementType == ClassHelper.float_TYPE) {
2688:                        primType = T_FLOAT;
2689:                        storeIns = FASTORE;
2690:                    } else if (elementType == ClassHelper.double_TYPE) {
2691:                        primType = T_DOUBLE;
2692:                        storeIns = DASTORE;
2693:                    } else if (elementType == ClassHelper.byte_TYPE) {
2694:                        primType = T_BYTE;
2695:                        storeIns = BASTORE;
2696:                    } else if (elementType == ClassHelper.short_TYPE) {
2697:                        primType = T_SHORT;
2698:                        storeIns = SASTORE;
2699:                    } else if (elementType == ClassHelper.int_TYPE) {
2700:                        primType = T_INT;
2701:                        storeIns = IASTORE;
2702:                    } else if (elementType == ClassHelper.long_TYPE) {
2703:                        primType = T_LONG;
2704:                        storeIns = LASTORE;
2705:                    }
2706:                    cv.visitIntInsn(NEWARRAY, primType);
2707:                } else {
2708:                    cv.visitTypeInsn(ANEWARRAY, arrayTypeName);
2709:                }
2710:
2711:                for (int i = 0; i < size; i++) {
2712:                    cv.visitInsn(DUP);
2713:                    helper.pushConstant(i);
2714:                    Expression elementExpression = expression.getExpression(i);
2715:                    if (elementExpression == null) {
2716:                        ConstantExpression.NULL.visit(this );
2717:                    } else {
2718:                        if (!elementType.equals(elementExpression.getType())) {
2719:                            visitCastExpression(new CastExpression(elementType,
2720:                                    elementExpression, true));
2721:                        } else {
2722:                            visitAndAutoboxBoolean(elementExpression);
2723:                        }
2724:                    }
2725:                    cv.visitInsn(storeIns);
2726:                }
2727:
2728:                if (sizeExpression == null
2729:                        && ClassHelper.isPrimitiveType(elementType)) {
2730:                    int par = compileStack.defineTemporaryVariable("par", true);
2731:                    cv.visitVarInsn(ALOAD, par);
2732:                }
2733:            }
2734:
2735:            public void visitListExpression(ListExpression expression) {
2736:                int size = expression.getExpressions().size();
2737:                boolean containsSpreadExpression = containsSpreadExpression(expression);
2738:                if (!containsSpreadExpression) {
2739:                    helper.pushConstant(size);
2740:
2741:                    cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2742:
2743:                    for (int i = 0; i < size; i++) {
2744:                        cv.visitInsn(DUP);
2745:                        helper.pushConstant(i);
2746:                        visitAndAutoboxBoolean(expression.getExpression(i));
2747:                        cv.visitInsn(AASTORE);
2748:                    }
2749:                } else {
2750:                    despreadList(expression.getExpressions(), false);
2751:                }
2752:                createListMethod.call(cv);
2753:            }
2754:
2755:            public void visitGStringExpression(GStringExpression expression) {
2756:                int size = expression.getValues().size();
2757:                helper.pushConstant(size);
2758:
2759:                cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
2760:
2761:                for (int i = 0; i < size; i++) {
2762:                    cv.visitInsn(DUP);
2763:                    helper.pushConstant(i);
2764:                    visitAndAutoboxBoolean(expression.getValue(i));
2765:                    cv.visitInsn(AASTORE);
2766:                }
2767:
2768:                int paramIdx = compileStack.defineTemporaryVariable("iterator",
2769:                        true);
2770:
2771:                ClassNode innerClass = createGStringClass(expression);
2772:                addInnerClass(innerClass);
2773:                String innerClassinternalName = BytecodeHelper
2774:                        .getClassInternalName(innerClass);
2775:
2776:                cv.visitTypeInsn(NEW, innerClassinternalName);
2777:                cv.visitInsn(DUP);
2778:                cv.visitVarInsn(ALOAD, paramIdx);
2779:
2780:                cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName,
2781:                        "<init>", "([Ljava/lang/Object;)V");
2782:                compileStack.removeVar(paramIdx);
2783:            }
2784:
2785:            public void visitAnnotations(AnnotatedNode node) {
2786:                Map annotionMap = node.getAnnotations();
2787:                if (annotionMap.isEmpty())
2788:                    return;
2789:                Iterator it = annotionMap.values().iterator();
2790:                while (it.hasNext()) {
2791:                    AnnotationNode an = (AnnotationNode) it.next();
2792:                    //skip builtin properties
2793:                    if (an.isBuiltIn())
2794:                        continue;
2795:                    ClassNode type = an.getClassNode();
2796:
2797:                    String clazz = type.getName();
2798:                    AnnotationVisitor av = cw.visitAnnotation(BytecodeHelper
2799:                            .formatNameForClassLoading(clazz), false);
2800:
2801:                    Iterator mIt = an.getMembers().keySet().iterator();
2802:                    while (mIt.hasNext()) {
2803:                        String name = (String) mIt.next();
2804:                        ConstantExpression exp = (ConstantExpression) an
2805:                                .getMember(name);
2806:                        av.visit(name, exp.getValue());
2807:                    }
2808:                    av.visitEnd();
2809:                }
2810:            }
2811:
2812:            // Implementation methods
2813:            //-------------------------------------------------------------------------
2814:            protected boolean addInnerClass(ClassNode innerClass) {
2815:                innerClass.setModule(classNode.getModule());
2816:                return innerClasses.add(innerClass);
2817:            }
2818:
2819:            protected ClassNode createClosureClass(ClosureExpression expression) {
2820:                ClassNode outerClass = getOutermostClass();
2821:                String name = outerClass.getName()
2822:                        + "$"
2823:                        + context.getNextClosureInnerName(outerClass,
2824:                                classNode, methodNode); // br added a more infomative name
2825:                boolean staticMethodOrInStaticClass = isStaticMethod()
2826:                        || classNode.isStaticClass();
2827:
2828:                Parameter[] parameters = expression.getParameters();
2829:                if (parameters == null) {
2830:                    parameters = new Parameter[0];
2831:                } else if (parameters.length == 0) {
2832:                    // lets create a default 'it' parameter
2833:                    parameters = new Parameter[] { new Parameter(
2834:                            ClassHelper.OBJECT_TYPE, "it",
2835:                            ConstantExpression.NULL) };
2836:                }
2837:
2838:                Parameter[] localVariableParams = getClosureSharedVariables(expression);
2839:
2840:                InnerClassNode answer = new InnerClassNode(outerClass, name, 0,
2841:                        ClassHelper.CLOSURE_TYPE); // closures are local inners and not public
2842:                answer.setEnclosingMethod(this .methodNode);
2843:                answer.setSynthetic(true);
2844:
2845:                if (staticMethodOrInStaticClass) {
2846:                    answer.setStaticClass(true);
2847:                }
2848:                if (isInScriptBody()) {
2849:                    answer.setScriptBody(true);
2850:                }
2851:                MethodNode method = answer.addMethod("doCall", ACC_PUBLIC,
2852:                        ClassHelper.OBJECT_TYPE, parameters,
2853:                        ClassNode.EMPTY_ARRAY, expression.getCode());
2854:                method.setSourcePosition(expression);
2855:
2856:                VariableScope varScope = expression.getVariableScope();
2857:                if (varScope == null) {
2858:                    throw new RuntimeException(
2859:                            "Must have a VariableScope by now! for expression: "
2860:                                    + expression + " class: " + name);
2861:                } else {
2862:                    method.setVariableScope(varScope.copy());
2863:                }
2864:                if (parameters.length > 1
2865:                        || (parameters.length == 1
2866:                                && parameters[0].getType() != null && parameters[0]
2867:                                .getType() != ClassHelper.OBJECT_TYPE)) {
2868:
2869:                    // lets add a typesafe call method
2870:                    MethodNode call = answer.addMethod("call", ACC_PUBLIC,
2871:                            ClassHelper.OBJECT_TYPE, parameters,
2872:                            ClassNode.EMPTY_ARRAY, new ReturnStatement(
2873:                                    new MethodCallExpression(
2874:                                            VariableExpression.THIS_EXPRESSION,
2875:                                            "doCall",
2876:                                            new ArgumentListExpression(
2877:                                                    parameters))));
2878:                    call.setSourcePosition(expression);
2879:                }
2880:
2881:                // lets make the constructor
2882:                BlockStatement block = new BlockStatement();
2883:                block.setSourcePosition(expression);
2884:                VariableExpression outer = new VariableExpression(
2885:                        "_outerInstance");
2886:                outer.setSourcePosition(expression);
2887:                block.getVariableScope().getReferencedLocalVariables().put(
2888:                        "_outerInstance", outer);
2889:                VariableExpression this Object = new VariableExpression(
2890:                        "_thisObject");
2891:                this Object.setSourcePosition(expression);
2892:                block.getVariableScope().getReferencedLocalVariables().put(
2893:                        "_thisObject", this Object);
2894:                TupleExpression conArgs = new TupleExpression();
2895:                conArgs.addExpression(outer);
2896:                conArgs.addExpression(this Object);
2897:                block
2898:                        .addStatement(new ExpressionStatement(
2899:                                new ConstructorCallExpression(ClassNode.SUPER,
2900:                                        conArgs)));
2901:
2902:                // lets assign all the parameter fields from the outer context
2903:                for (int i = 0; i < localVariableParams.length; i++) {
2904:                    Parameter param = localVariableParams[i];
2905:                    String paramName = param.getName();
2906:                    Expression initialValue = null;
2907:                    ClassNode type = param.getType();
2908:                    FieldNode paramField = null;
2909:                    if (true) {
2910:                        initialValue = new VariableExpression(paramName);
2911:                        ClassNode realType = type;
2912:                        type = ClassHelper.makeReference();
2913:                        param.setType(type);
2914:                        paramField = answer.addField(paramName, ACC_PRIVATE,
2915:                                type, initialValue);
2916:                        paramField.setHolder(true);
2917:                        String methodName = Verifier.capitalize(paramName);
2918:
2919:                        // lets add a getter & setter
2920:                        Expression fieldExp = new FieldExpression(paramField);
2921:                        answer.addMethod("get" + methodName, ACC_PUBLIC,
2922:                                realType, Parameter.EMPTY_ARRAY,
2923:                                ClassNode.EMPTY_ARRAY, new ReturnStatement(
2924:                                        fieldExp));
2925:
2926:                        /*
2927:                        answer.addMethod(
2928:                            "set" + methodName,
2929:                            ACC_PUBLIC,
2930:                            "void",
2931:                            new Parameter[] { new Parameter(realType, "__value") },
2932:                            new ExpressionStatement(
2933:                                new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("__value"))));
2934:                         */
2935:                    }
2936:                }
2937:
2938:                Parameter[] params = new Parameter[2 + localVariableParams.length];
2939:                params[0] = new Parameter(ClassHelper.OBJECT_TYPE,
2940:                        "_outerInstance");
2941:                params[1] = new Parameter(ClassHelper.OBJECT_TYPE,
2942:                        "_thisObject");
2943:                System.arraycopy(localVariableParams, 0, params, 2,
2944:                        localVariableParams.length);
2945:
2946:                ASTNode sn = answer.addConstructor(ACC_PUBLIC, params,
2947:                        ClassNode.EMPTY_ARRAY, block);
2948:                sn.setSourcePosition(expression);
2949:                return answer;
2950:            }
2951:
2952:            protected Parameter[] getClosureSharedVariables(ClosureExpression ce) {
2953:                VariableScope scope = ce.getVariableScope();
2954:                Map references = scope.getReferencedLocalVariables();
2955:                Parameter[] ret = new Parameter[references.size()];
2956:                int index = 0;
2957:                for (Iterator iter = references.values().iterator(); iter
2958:                        .hasNext();) {
2959:                    org.codehaus.groovy.ast.Variable element = (org.codehaus.groovy.ast.Variable) iter
2960:                            .next();
2961:                    if (element instanceof  Parameter) {
2962:                        ret[index] = (Parameter) element;
2963:                    } else {
2964:                        Parameter p = new Parameter(element.getType(), element
2965:                                .getName());
2966:                        ret[index] = p;
2967:                    }
2968:                    index++;
2969:                }
2970:                return ret;
2971:            }
2972:
2973:            protected ClassNode getOutermostClass() {
2974:                if (outermostClass == null) {
2975:                    outermostClass = classNode;
2976:                    while (outermostClass instanceof  InnerClassNode) {
2977:                        outermostClass = outermostClass.getOuterClass();
2978:                    }
2979:                }
2980:                return outermostClass;
2981:            }
2982:
2983:            protected ClassNode createGStringClass(GStringExpression expression) {
2984:                ClassNode owner = classNode;
2985:                if (owner instanceof  InnerClassNode) {
2986:                    owner = owner.getOuterClass();
2987:                }
2988:                String outerClassName = owner.getName();
2989:                String name = outerClassName + "$"
2990:                        + context.getNextInnerClassIdx();
2991:                InnerClassNode answer = new InnerClassNode(owner, name, 0,
2992:                        ClassHelper.GSTRING_TYPE);
2993:                answer.setEnclosingMethod(this .methodNode);
2994:                FieldNode stringsField = answer.addField("strings",
2995:                        ACC_PRIVATE /*| ACC_STATIC*/, ClassHelper.STRING_TYPE
2996:                                .makeArray(), new ArrayExpression(
2997:                                ClassHelper.STRING_TYPE, expression
2998:                                        .getStrings()));
2999:                answer.addMethod("getStrings", ACC_PUBLIC,
3000:                        ClassHelper.STRING_TYPE.makeArray(),
3001:                        Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY,
3002:                        new ReturnStatement(new FieldExpression(stringsField)));
3003:                // lets make the constructor
3004:                BlockStatement block = new BlockStatement();
3005:                block.addStatement(new ExpressionStatement(
3006:                        new ConstructorCallExpression(ClassNode.SUPER,
3007:                                new VariableExpression("values"))));
3008:                Parameter[] contructorParams = new Parameter[] { new Parameter(
3009:                        ClassHelper.OBJECT_TYPE.makeArray(), "values") };
3010:                answer.addConstructor(ACC_PUBLIC, contructorParams,
3011:                        ClassNode.EMPTY_ARRAY, block);
3012:                return answer;
3013:            }
3014:
3015:            protected void doConvertAndCast(ClassNode type) {
3016:                doConvertAndCast(type, false);
3017:            }
3018:
3019:            protected void doConvertAndCast(ClassNode type, boolean coerce) {
3020:                if (type == ClassHelper.OBJECT_TYPE)
3021:                    return;
3022:                if (isValidTypeForCast(type)) {
3023:                    visitClassExpression(new ClassExpression(type));
3024:                    if (coerce) {
3025:                        asTypeMethod.call(cv);
3026:                    } else {
3027:                        castToTypeMethod.call(cv);
3028:                    }
3029:                }
3030:                helper.doCast(type);
3031:            }
3032:
3033:            protected void evaluateLogicalOrExpression(
3034:                    BinaryExpression expression) {
3035:                visitBooleanExpression(new BooleanExpression(expression
3036:                        .getLeftExpression()));
3037:                Label l0 = new Label();
3038:                Label l2 = new Label();
3039:                cv.visitJumpInsn(IFEQ, l0);
3040:
3041:                cv.visitLabel(l2);
3042:
3043:                visitConstantExpression(ConstantExpression.TRUE);
3044:
3045:                Label l1 = new Label();
3046:                cv.visitJumpInsn(GOTO, l1);
3047:                cv.visitLabel(l0);
3048:
3049:                visitBooleanExpression(new BooleanExpression(expression
3050:                        .getRightExpression()));
3051:
3052:                cv.visitJumpInsn(IFNE, l2);
3053:
3054:                visitConstantExpression(ConstantExpression.FALSE);
3055:                cv.visitLabel(l1);
3056:            }
3057:
3058:            // todo: optimization: change to return primitive boolean. need to adjust the BinaryExpression and isComparisonExpression for
3059:            // consistancy.
3060:            protected void evaluateLogicalAndExpression(
3061:                    BinaryExpression expression) {
3062:                visitBooleanExpression(new BooleanExpression(expression
3063:                        .getLeftExpression()));
3064:                Label l0 = new Label();
3065:                cv.visitJumpInsn(IFEQ, l0);
3066:
3067:                visitBooleanExpression(new BooleanExpression(expression
3068:                        .getRightExpression()));
3069:
3070:                cv.visitJumpInsn(IFEQ, l0);
3071:
3072:                visitConstantExpression(ConstantExpression.TRUE);
3073:
3074:                Label l1 = new Label();
3075:                cv.visitJumpInsn(GOTO, l1);
3076:                cv.visitLabel(l0);
3077:
3078:                visitConstantExpression(ConstantExpression.FALSE);
3079:
3080:                cv.visitLabel(l1);
3081:            }
3082:
3083:            protected void evaluateBinaryExpression(String method,
3084:                    BinaryExpression expression) {
3085:                makeCall(expression.getLeftExpression(),
3086:                        new ConstantExpression(method),
3087:                        new ArgumentListExpression().addExpression(expression
3088:                                .getRightExpression()), invokeMethod, false,
3089:                        false, false);
3090:            }
3091:
3092:            protected void evaluateCompareTo(BinaryExpression expression) {
3093:                Expression leftExpression = expression.getLeftExpression();
3094:                leftExpression.visit(this );
3095:                if (isComparisonExpression(leftExpression)) {
3096:                    helper.boxBoolean();
3097:                }
3098:
3099:                // if the right hand side is a boolean expression, we need to autobox
3100:                Expression rightExpression = expression.getRightExpression();
3101:                rightExpression.visit(this );
3102:                if (isComparisonExpression(rightExpression)) {
3103:                    helper.boxBoolean();
3104:                }
3105:                compareToMethod.call(cv);
3106:            }
3107:
3108:            protected void evaluateBinaryExpressionWithAsignment(String method,
3109:                    BinaryExpression expression) {
3110:                Expression leftExpression = expression.getLeftExpression();
3111:                if (leftExpression instanceof  BinaryExpression) {
3112:                    BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
3113:                    if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
3114:                        // lets replace this assignment to a subscript operator with a
3115:                        // method call
3116:                        // e.g. x[5] += 10
3117:                        // -> (x, [], 5), =, x[5] + 10
3118:                        // -> methodCall(x, "putAt", [5, methodCall(x[5], "plus", 10)])
3119:
3120:                        MethodCallExpression methodCall = new MethodCallExpression(
3121:                                expression.getLeftExpression(), method,
3122:                                new ArgumentListExpression(
3123:                                        new Expression[] { expression
3124:                                                .getRightExpression() }));
3125:
3126:                        Expression safeIndexExpr = createReusableExpression(leftBinExpr
3127:                                .getRightExpression());
3128:
3129:                        visitMethodCallExpression(new MethodCallExpression(
3130:                                leftBinExpr.getLeftExpression(), "putAt",
3131:                                new ArgumentListExpression(new Expression[] {
3132:                                        safeIndexExpr, methodCall })));
3133:                        //cv.visitInsn(POP);
3134:                        return;
3135:                    }
3136:                }
3137:
3138:                evaluateBinaryExpression(method, expression);
3139:
3140:                // br to leave a copy of rvalue on the stack. see also isPopRequired()
3141:                cv.visitInsn(DUP);
3142:
3143:                leftHandExpression = true;
3144:                evaluateExpression(leftExpression);
3145:                leftHandExpression = false;
3146:            }
3147:
3148:            private void evaluateBinaryExpression(MethodCaller compareMethod,
3149:                    BinaryExpression expression) {
3150:                Expression leftExp = expression.getLeftExpression();
3151:                Expression rightExp = expression.getRightExpression();
3152:                load(leftExp);
3153:                load(rightExp);
3154:                compareMethod.call(cv);
3155:            }
3156:
3157:            protected void evaluateEqual(BinaryExpression expression) {
3158:                Expression leftExpression = expression.getLeftExpression();
3159:                if (leftExpression instanceof  BinaryExpression) {
3160:                    BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
3161:                    if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
3162:                        // lets replace this assignment to a subscript operator with a
3163:                        // method call
3164:                        // e.g. x[5] = 10
3165:                        // -> (x, [], 5), =, 10
3166:                        // -> methodCall(x, "putAt", [5, 10])
3167:
3168:                        visitMethodCallExpression(new MethodCallExpression(
3169:                                leftBinExpr.getLeftExpression(), "putAt",
3170:                                new ArgumentListExpression(new Expression[] {
3171:                                        leftBinExpr.getRightExpression(),
3172:                                        expression.getRightExpression() })));
3173:                        // cv.visitInsn(POP); //this is realted to isPopRequired()
3174:                        return;
3175:                    }
3176:                }
3177:
3178:                // lets evaluate the RHS then hopefully the LHS will be a field
3179:                Expression rightExpression = expression.getRightExpression();
3180:                ClassNode type = getLHSType(leftExpression);
3181:                // lets not cast for primitive types as we handle these in field setting etc
3182:                if (ClassHelper.isPrimitiveType(type)) {
3183:                    visitAndAutoboxBoolean(rightExpression);
3184:                } else if (type != ClassHelper.OBJECT_TYPE) {
3185:                    visitCastExpression(new CastExpression(type,
3186:                            rightExpression));
3187:                } else {
3188:                    visitAndAutoboxBoolean(rightExpression);
3189:                }
3190:
3191:                cv.visitInsn(DUP); // to leave a copy of the rightexpression value on the stack after the assignment.
3192:                leftHandExpression = true;
3193:                leftExpression.visit(this );
3194:                leftHandExpression = false;
3195:            }
3196:
3197:            /**
3198:             * Deduces the type name required for some casting
3199:             *
3200:             * @return the type of the given (LHS) expression or null if it is java.lang.Object or it cannot be deduced
3201:             */
3202:            protected ClassNode getLHSType(Expression leftExpression) {
3203:                if (leftExpression instanceof  VariableExpression) {
3204:                    VariableExpression varExp = (VariableExpression) leftExpression;
3205:                    ClassNode type = varExp.getType();
3206:                    if (isValidTypeForCast(type)) {
3207:                        return type;
3208:                    }
3209:                    String variableName = varExp.getName();
3210:                    Variable variable = compileStack.getVariable(variableName,
3211:                            false);
3212:                    if (variable != null) {
3213:                        if (variable.isHolder()) {
3214:                            return type;
3215:                        }
3216:                        if (variable.isProperty())
3217:                            return variable.getType();
3218:                        type = variable.getType();
3219:                        if (isValidTypeForCast(type)) {
3220:                            return type;
3221:                        }
3222:                    } else {
3223:                        FieldNode field = classNode.getField(variableName);
3224:                        if (field == null) {
3225:                            field = classNode.getOuterField(variableName);
3226:                        }
3227:                        if (field != null) {
3228:                            type = field.getType();
3229:                            if (!field.isHolder() && isValidTypeForCast(type)) {
3230:                                return type;
3231:                            }
3232:                        }
3233:                    }
3234:                } else if (leftExpression instanceof  FieldExpression) {
3235:                    FieldExpression fieldExp = (FieldExpression) leftExpression;
3236:                    ClassNode type = fieldExp.getType();
3237:                    if (isValidTypeForCast(type)) {
3238:                        return type;
3239:                    }
3240:                }
3241:                return ClassHelper.DYNAMIC_TYPE;
3242:            }
3243:
3244:            protected boolean isValidTypeForCast(ClassNode type) {
3245:                return type != ClassHelper.DYNAMIC_TYPE
3246:                        && type != ClassHelper.REFERENCE_TYPE;
3247:            }
3248:
3249:            protected void visitAndAutoboxBoolean(Expression expression) {
3250:                expression.visit(this );
3251:
3252:                if (isComparisonExpression(expression)) {
3253:                    helper.boxBoolean(); // convert boolean to Boolean
3254:                }
3255:            }
3256:
3257:            protected void evaluatePrefixMethod(String method,
3258:                    Expression expression) {
3259:                // execute method
3260:                makeCall(expression, new ConstantExpression(method),
3261:                        MethodCallExpression.NO_ARGUMENTS, invokeMethod, false,
3262:                        false, false);
3263:
3264:                // store 
3265:                leftHandExpression = true;
3266:                expression.visit(this );
3267:
3268:                // reload new value
3269:                leftHandExpression = false;
3270:                expression.visit(this );
3271:            }
3272:
3273:            protected void evaluatePostfixMethod(String method,
3274:                    Expression expression) {
3275:                // load 
3276:                expression.visit(this );
3277:
3278:                // save value for later
3279:                int tempIdx = compileStack.defineTemporaryVariable("postfix_"
3280:                        + method, true);
3281:
3282:                //execute method
3283:                makeCall(expression, new ConstantExpression(method),
3284:                        MethodCallExpression.NO_ARGUMENTS, invokeMethod, false,
3285:                        false, false);
3286:
3287:                // store
3288:                leftHandExpression = true;
3289:                expression.visit(this );
3290:                leftHandExpression = false;
3291:
3292:                //reload saved value
3293:                cv.visitVarInsn(ALOAD, tempIdx);
3294:                compileStack.removeVar(tempIdx);
3295:            }
3296:
3297:            protected void evaluateInstanceof(BinaryExpression expression) {
3298:                visitAndAutoboxBoolean(expression.getLeftExpression());
3299:                Expression rightExp = expression.getRightExpression();
3300:                ClassNode classType = ClassHelper.DYNAMIC_TYPE;
3301:                if (rightExp instanceof  ClassExpression) {
3302:                    ClassExpression classExp = (ClassExpression) rightExp;
3303:                    classType = classExp.getType();
3304:                } else {
3305:                    throw new RuntimeException(
3306:                            "Right hand side of the instanceof keyword must be a class name, not: "
3307:                                    + rightExp);
3308:                }
3309:                String classInternalName = BytecodeHelper
3310:                        .getClassInternalName(classType);
3311:                cv.visitTypeInsn(INSTANCEOF, classInternalName);
3312:            }
3313:
3314:            /**
3315:             * @return true if the given argument expression requires the stack, in
3316:             *         which case the arguments are evaluated first, stored in the
3317:             *         variable stack and then reloaded to make a method call
3318:             */
3319:            protected boolean argumentsUseStack(Expression arguments) {
3320:                return arguments instanceof  TupleExpression
3321:                        || arguments instanceof  ClosureExpression;
3322:            }
3323:
3324:            /**
3325:             * @return true if the given expression represents a non-static field
3326:             */
3327:            protected boolean isNonStaticField(Expression expression) {
3328:                FieldNode field = null;
3329:                if (expression instanceof  VariableExpression) {
3330:                    VariableExpression varExp = (VariableExpression) expression;
3331:                    field = classNode.getField(varExp.getName());
3332:                } else if (expression instanceof  FieldExpression) {
3333:                    FieldExpression fieldExp = (FieldExpression) expression;
3334:                    field = classNode.getField(fieldExp.getFieldName());
3335:                } else if (expression.getClass() == PropertyExpression.class) {
3336:                    PropertyExpression fieldExp = (PropertyExpression) expression;
3337:                    String possibleField = fieldExp.getPropertyAsString();
3338:                    if (possibleField != null)
3339:                        field = classNode.getField(possibleField);
3340:                }
3341:                if (field != null) {
3342:                    return !field.isStatic();
3343:                }
3344:                return false;
3345:            }
3346:
3347:            private static boolean isThisExpression(Expression expression) {
3348:                if (expression instanceof  VariableExpression) {
3349:                    VariableExpression varExp = (VariableExpression) expression;
3350:                    return varExp.getName().equals("this");
3351:                }
3352:                return false;
3353:            }
3354:
3355:            private static boolean isSuperExpression(Expression expression) {
3356:                if (expression instanceof  VariableExpression) {
3357:                    VariableExpression varExp = (VariableExpression) expression;
3358:                    return varExp.getName().equals("super");
3359:                }
3360:                return false;
3361:            }
3362:
3363:            private static boolean isThisOrSuper(Expression expression) {
3364:                return isThisExpression(expression)
3365:                        || isSuperExpression(expression);
3366:            }
3367:
3368:            /**
3369:             * For assignment expressions, return a safe expression for the LHS we can use
3370:             * to return the value
3371:             */
3372:            protected Expression createReturnLHSExpression(Expression expression) {
3373:                if (expression instanceof  BinaryExpression) {
3374:                    BinaryExpression binExpr = (BinaryExpression) expression;
3375:                    if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) {
3376:                        return createReusableExpression(binExpr
3377:                                .getLeftExpression());
3378:                    }
3379:                }
3380:                return null;
3381:            }
3382:
3383:            protected Expression createReusableExpression(Expression expression) {
3384:                ExpressionTransformer transformer = new ExpressionTransformer() {
3385:                    public Expression transform(Expression expression) {
3386:                        if (expression instanceof  PostfixExpression) {
3387:                            PostfixExpression postfixExp = (PostfixExpression) expression;
3388:                            return postfixExp.getExpression();
3389:                        } else if (expression instanceof  PrefixExpression) {
3390:                            PrefixExpression prefixExp = (PrefixExpression) expression;
3391:                            return prefixExp.getExpression();
3392:                        }
3393:                        return expression;
3394:                    }
3395:                };
3396:
3397:                // could just be a postfix / prefix expression or nested inside some other expression
3398:                return transformer.transform(expression
3399:                        .transformExpression(transformer));
3400:            }
3401:
3402:            protected boolean isComparisonExpression(Expression expression) {
3403:                if (expression instanceof  BinaryExpression) {
3404:                    BinaryExpression binExpr = (BinaryExpression) expression;
3405:                    switch (binExpr.getOperation().getType()) {
3406:                    case Types.COMPARE_EQUAL:
3407:                    case Types.MATCH_REGEX:
3408:                    case Types.COMPARE_GREATER_THAN:
3409:                    case Types.COMPARE_GREATER_THAN_EQUAL:
3410:                    case Types.COMPARE_LESS_THAN:
3411:                    case Types.COMPARE_LESS_THAN_EQUAL:
3412:                    case Types.COMPARE_IDENTICAL:
3413:                    case Types.COMPARE_NOT_EQUAL:
3414:                    case Types.KEYWORD_INSTANCEOF:
3415:                    case Types.KEYWORD_IN:
3416:                        return true;
3417:                    }
3418:                } else if (expression instanceof  BooleanExpression) {
3419:                    return true;
3420:                }
3421:                return false;
3422:            }
3423:
3424:            protected void onLineNumber(ASTNode statement, String message) {
3425:                int line = statement.getLineNumber();
3426:                int col = statement.getColumnNumber();
3427:                this .currentASTNode = statement;
3428:
3429:                if (line >= 0) {
3430:                    lineNumber = line;
3431:                    columnNumber = col;
3432:                }
3433:                if (CREATE_LINE_NUMBER_INFO && line >= 0 && cv != null) {
3434:                    Label l = new Label();
3435:                    cv.visitLabel(l);
3436:                    cv.visitLineNumber(line, l);
3437:                    if (ASM_DEBUG) {
3438:                        helper.mark(message + "[" + statement.getLineNumber()
3439:                                + ":" + statement.getColumnNumber() + "]");
3440:                    }
3441:                }
3442:            }
3443:
3444:            private boolean isInnerClass() {
3445:                return classNode instanceof  InnerClassNode;
3446:            }
3447:
3448:            /** @return true if the given name is a local variable or a field */
3449:            protected boolean isFieldOrVariable(String name) {
3450:                return compileStack.containsVariable(name)
3451:                        || classNode.getField(name) != null;
3452:            }
3453:
3454:            /**
3455:             * @return if the type of the expression can be determined at compile time
3456:             *         then this method returns the type - otherwise null
3457:             */
3458:            protected ClassNode getExpressionType(Expression expression) {
3459:                if (isComparisonExpression(expression)) {
3460:                    return ClassHelper.boolean_TYPE;
3461:                }
3462:                if (expression instanceof  VariableExpression) {
3463:                    if (expression == VariableExpression.THIS_EXPRESSION) {
3464:                        return classNode;
3465:                    } else if (expression == VariableExpression.SUPER_EXPRESSION) {
3466:                        return classNode.getSuperClass();
3467:                    }
3468:
3469:                    VariableExpression varExpr = (VariableExpression) expression;
3470:                    Variable variable = compileStack.getVariable(varExpr
3471:                            .getName(), false);
3472:                    if (variable != null && !variable.isHolder()) {
3473:                        ClassNode type = variable.getType();
3474:                        if (!variable.isDynamicTyped())
3475:                            return type;
3476:                    }
3477:                    if (variable == null) {
3478:                        org.codehaus.groovy.ast.Variable var = (org.codehaus.groovy.ast.Variable) compileStack
3479:                                .getScope().getReferencedClassVariables().get(
3480:                                        varExpr.getName());
3481:                        if (var != null && !var.isDynamicTyped())
3482:                            return var.getType();
3483:                    }
3484:                }
3485:                return expression.getType();
3486:            }
3487:
3488:            protected boolean isInClosureConstructor() {
3489:                return constructorNode != null
3490:                        && classNode.getOuterClass() != null
3491:                        && classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE;
3492:            }
3493:
3494:            protected boolean isInClosure() {
3495:                return classNode.getOuterClass() != null
3496:                        && classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE;
3497:            }
3498:
3499:            protected boolean isStaticMethod() {
3500:                if (methodNode == null) { // we're in a constructor
3501:                    return false;
3502:                }
3503:                return methodNode.isStatic();
3504:            }
3505:
3506:            protected CompileUnit getCompileUnit() {
3507:                CompileUnit answer = classNode.getCompileUnit();
3508:                if (answer == null) {
3509:                    answer = context.getCompileUnit();
3510:                }
3511:                return answer;
3512:            }
3513:
3514:            protected boolean isHolderVariable(Expression expression) {
3515:                if (expression instanceof  FieldExpression) {
3516:                    FieldExpression fieldExp = (FieldExpression) expression;
3517:                    return fieldExp.getField().isHolder();
3518:                }
3519:                if (expression instanceof  VariableExpression) {
3520:                    VariableExpression varExp = (VariableExpression) expression;
3521:                    Variable variable = compileStack.getVariable(varExp
3522:                            .getName(), false);
3523:                    if (variable != null) {
3524:                        return variable.isHolder();
3525:                    }
3526:                    FieldNode field = classNode.getField(varExp.getName());
3527:                    if (field != null) {
3528:                        return field.isHolder();
3529:                    }
3530:                }
3531:                return false;
3532:            }
3533:
3534:            public static boolean usesSuper(MethodCallExpression call) {
3535:                Expression expression = call.getObjectExpression();
3536:                if (expression instanceof  VariableExpression) {
3537:                    VariableExpression varExp = (VariableExpression) expression;
3538:                    String variable = varExp.getName();
3539:                    return variable.equals("super");
3540:                }
3541:                return false;
3542:            }
3543:
3544:            public static boolean usesSuper(PropertyExpression pe) {
3545:                Expression expression = pe.getObjectExpression();
3546:                if (expression instanceof  VariableExpression) {
3547:                    VariableExpression varExp = (VariableExpression) expression;
3548:                    String variable = varExp.getName();
3549:                    return variable.equals("super");
3550:                }
3551:                return false;
3552:            }
3553:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.