Source Code Cross Referenced for UnitCompiler.java in  » Scripting » janino-2.5.11 » org » codehaus » janino » 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 » janino 2.5.11 » org.codehaus.janino 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


00001:        /*
00002:         * Janino - An embedded Java[TM] compiler
00003:         *
00004:         * Copyright (c) 2001-2007, Arno Unkrig
00005:         * All rights reserved.
00006:         *
00007:         * Redistribution and use in source and binary forms, with or without
00008:         * modification, are permitted provided that the following conditions
00009:         * are met:
00010:         *
00011:         *    1. Redistributions of source code must retain the above copyright
00012:         *       notice, this list of conditions and the following disclaimer.
00013:         *    2. Redistributions in binary form must reproduce the above
00014:         *       copyright notice, this list of conditions and the following
00015:         *       disclaimer in the documentation and/or other materials
00016:         *       provided with the distribution.
00017:         *    3. The name of the author may not be used to endorse or promote
00018:         *       products derived from this software without specific prior
00019:         *       written permission.
00020:         *
00021:         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00022:         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00023:         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024:         * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00025:         * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026:         * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00027:         * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028:         * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00029:         * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00030:         * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00031:         * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032:         */
00033:
00034:        package org.codehaus.janino;
00035:
00036:        import java.io.*;
00037:        import java.util.*;
00038:
00039:        import org.codehaus.janino.IClass.*;
00040:        import org.codehaus.janino.Java.*;
00041:        import org.codehaus.janino.Java.CompilationUnit.*;
00042:        import org.codehaus.janino.Visitor.*;
00043:        import org.codehaus.janino.util.*;
00044:        import org.codehaus.janino.util.enumerator.*;
00045:
00046:        /**
00047:         * This class actually implements the Java<sup>TM</sup> compiler. It is
00048:         * associated with exactly one compilation unit which it compiles.
00049:         */
00050:        public class UnitCompiler {
00051:            private static final boolean DEBUG = false;
00052:
00053:            /**
00054:             * This constant determines the number of operands up to which the
00055:             *
00056:             *      a.concat(b).concat(c)
00057:             *
00058:             * strategy is used to implement string concatenation. For more operands, the
00059:             *
00060:             *      new StringBuffer(a).append(b).append(c).append(d).toString()
00061:             *
00062:             * strategy is chosen.
00063:             *
00064:             * A very good article from Tom Gibara
00065:             *
00066:             *    http://www.tomgibara.com/janino-evaluation/string-concatenation-benchmark
00067:             *
00068:             * analyzes the impact of this decision and recommends a value of three.
00069:             */
00070:            private static final int STRING_CONCAT_LIMIT = 3;
00071:
00072:            public UnitCompiler(Java.CompilationUnit compilationUnit,
00073:                    IClassLoader iClassLoader) throws CompileException {
00074:                this .compilationUnit = compilationUnit;
00075:                this .iClassLoader = iClassLoader;
00076:
00077:                try {
00078:                    if (iClassLoader.loadIClass(Descriptor.STRING_BUILDER) != null) {
00079:                        this .isStringBuilderAvailable = true;
00080:                    } else if (iClassLoader
00081:                            .loadIClass(Descriptor.STRING_BUFFER) != null) {
00082:                        this .isStringBuilderAvailable = false;
00083:                    } else {
00084:                        throw new RuntimeException(
00085:                                "SNO: Could neither load \"StringBuffer\" nor \"StringBuilder\"");
00086:                    }
00087:                } catch (ClassNotFoundException ex) {
00088:                    throw new RuntimeException(
00089:                            "SNO: Error loading \"StringBuffer\" or \"StringBuilder\": "
00090:                                    + ex.getMessage());
00091:                }
00092:
00093:                // Compile non-static import declarations. (Must be done here in the constructor and not
00094:                // down in "compileUnit()" because otherwise "resolve()" cannot resolve type names.)
00095:                this .typeImportsOnDemand = new ArrayList();
00096:                this .typeImportsOnDemand.add(new String[] { "java", "lang" });
00097:                for (Iterator it = this .compilationUnit.importDeclarations
00098:                        .iterator(); it.hasNext();) {
00099:                    ImportDeclaration id = (ImportDeclaration) it.next();
00100:                    class UCE extends RuntimeException {
00101:                        final CompileException ce;
00102:
00103:                        UCE(CompileException ce) {
00104:                            this .ce = ce;
00105:                        }
00106:                    }
00107:                    try {
00108:                        id.accept(new ImportVisitor() {
00109:                            public void visitSingleTypeImportDeclaration(
00110:                                    SingleTypeImportDeclaration stid) {
00111:                                try {
00112:                                    UnitCompiler.this .import2(stid);
00113:                                } catch (CompileException e) {
00114:                                    throw new UCE(e);
00115:                                }
00116:                            }
00117:
00118:                            public void visitTypeImportOnDemandDeclaration(
00119:                                    TypeImportOnDemandDeclaration tiodd) {
00120:                                UnitCompiler.this .import2(tiodd);
00121:                            }
00122:
00123:                            public void visitSingleStaticImportDeclaration(
00124:                                    SingleStaticImportDeclaration ssid) {
00125:                            }
00126:
00127:                            public void visitStaticImportOnDemandDeclaration(
00128:                                    StaticImportOnDemandDeclaration siodd) {
00129:                            }
00130:                        });
00131:                    } catch (UCE uce) {
00132:                        throw uce.ce;
00133:                    }
00134:                }
00135:            }
00136:
00137:            private void import2(SingleTypeImportDeclaration stid)
00138:                    throws CompileException {
00139:                String[] ids = stid.identifiers;
00140:                String name = last(ids);
00141:
00142:                String[] prev = (String[]) UnitCompiler.this .singleTypeImports
00143:                        .put(name, ids);
00144:
00145:                // Check for re-import of same name.
00146:                if (prev != null && !Arrays.equals(prev, ids)) {
00147:                    this .compileError("Class \"" + name
00148:                            + "\" was previously imported as \""
00149:                            + Java.join(prev, ".") + "\", now as \""
00150:                            + Java.join(ids, ".") + "\"");
00151:                }
00152:            }
00153:
00154:            private void import2(TypeImportOnDemandDeclaration tiodd) {
00155:
00156:                // Duplicate type-imports-on-demand are not an error, so no checks here.
00157:                UnitCompiler.this .typeImportsOnDemand.add(tiodd.identifiers);
00158:            }
00159:
00160:            private void import2(SingleStaticImportDeclaration ssid)
00161:                    throws CompileException {
00162:                String name = last(ssid.identifiers);
00163:                Object importedObject;
00164:
00165:                FIND_IMPORTED_OBJECT: {
00166:
00167:                    // Type?
00168:                    {
00169:                        IClass iClass = this 
00170:                                .loadFullyQualifiedClass(ssid.identifiers);
00171:                        if (iClass != null) {
00172:                            importedObject = iClass;
00173:                            break FIND_IMPORTED_OBJECT;
00174:                        }
00175:                    }
00176:
00177:                    String[] typeName = allButLast(ssid.identifiers);
00178:                    IClass iClass = this .loadFullyQualifiedClass(typeName);
00179:                    if (iClass == null) {
00180:                        this .compileError("Could not load \""
00181:                                + Java.join(typeName, ".") + "\"", ssid
00182:                                .getLocation());
00183:                        return;
00184:                    }
00185:
00186:                    // Static field?
00187:                    IField[] flds = iClass.getDeclaredIFields();
00188:                    for (int i = 0; i < flds.length; ++i) {
00189:                        IField iField = flds[i];
00190:                        if (iField.getName().equals(name)) {
00191:                            if (!iField.isStatic()) {
00192:                                this .compileError("Filed \"" + name
00193:                                        + "\" of \"" + Java.join(typeName, ".")
00194:                                        + "\" must be static", ssid
00195:                                        .getLocation());
00196:                            }
00197:                            importedObject = iField;
00198:                            break FIND_IMPORTED_OBJECT;
00199:                        }
00200:                    }
00201:
00202:                    // Static method?
00203:                    IMethod[] ms = iClass.getDeclaredIMethods(name);
00204:                    if (ms.length > 0) {
00205:                        importedObject = Arrays.asList(ms);
00206:                        break FIND_IMPORTED_OBJECT;
00207:                    }
00208:
00209:                    // Give up.
00210:                    this .compileError("\"" + Java.join(typeName, ".")
00211:                            + "\" has no static member \"" + name + "\"", ssid
00212:                            .getLocation());
00213:                    return;
00214:                }
00215:
00216:                Object prev = this .singleStaticImports
00217:                        .put(name, importedObject);
00218:
00219:                // Check for re-import of same name.
00220:                if (prev != null && !prev.equals(importedObject)) {
00221:                    UnitCompiler.this .compileError("\"" + name
00222:                            + "\" was previously statically imported as \""
00223:                            + prev.toString() + "\", now as \""
00224:                            + importedObject.toString() + "\"", ssid
00225:                            .getLocation());
00226:                }
00227:            }
00228:
00229:            private void import2(StaticImportOnDemandDeclaration siodd)
00230:                    throws CompileException {
00231:                IClass iClass = this .loadFullyQualifiedClass(siodd.identifiers);
00232:                if (iClass == null) {
00233:                    this .compileError("Could not load \""
00234:                            + Java.join(siodd.identifiers, ".") + "\"", siodd
00235:                            .getLocation());
00236:                    return;
00237:                }
00238:                UnitCompiler.this .staticImportsOnDemand.add(iClass);
00239:            }
00240:
00241:            /**
00242:             * Generates an array of {@link ClassFile} objects which represent the classes and
00243:             * interfaces defined in the compilation unit.
00244:             */
00245:            public ClassFile[] compileUnit(EnumeratorSet debuggingInformation)
00246:                    throws CompileException {
00247:
00248:                // Compile static import declarations.
00249:                for (Iterator it = this .compilationUnit.importDeclarations
00250:                        .iterator(); it.hasNext();) {
00251:                    ImportDeclaration id = (ImportDeclaration) it.next();
00252:                    class UCE extends RuntimeException {
00253:                        final CompileException ce;
00254:
00255:                        UCE(CompileException ce) {
00256:                            this .ce = ce;
00257:                        }
00258:                    }
00259:                    try {
00260:                        id.accept(new ImportVisitor() {
00261:                            public void visitSingleTypeImportDeclaration(
00262:                                    SingleTypeImportDeclaration stid) {
00263:                            }
00264:
00265:                            public void visitTypeImportOnDemandDeclaration(
00266:                                    TypeImportOnDemandDeclaration tiodd) {
00267:                            }
00268:
00269:                            public void visitSingleStaticImportDeclaration(
00270:                                    SingleStaticImportDeclaration ssid) {
00271:                                try {
00272:                                    UnitCompiler.this .import2(ssid);
00273:                                } catch (CompileException e) {
00274:                                    throw new UCE(e);
00275:                                }
00276:                            }
00277:
00278:                            public void visitStaticImportOnDemandDeclaration(
00279:                                    StaticImportOnDemandDeclaration siodd) {
00280:                                try {
00281:                                    UnitCompiler.this .import2(siodd);
00282:                                } catch (CompileException e) {
00283:                                    throw new UCE(e);
00284:                                }
00285:                            }
00286:                        });
00287:                    } catch (UCE uce) {
00288:                        throw uce.ce;
00289:                    }
00290:                }
00291:
00292:                this .generatedClassFiles = new ArrayList();
00293:                this .debuggingInformation = debuggingInformation;
00294:
00295:                for (Iterator it = this .compilationUnit.packageMemberTypeDeclarations
00296:                        .iterator(); it.hasNext();) {
00297:                    UnitCompiler.this 
00298:                            .compile((Java.PackageMemberTypeDeclaration) it
00299:                                    .next());
00300:                }
00301:
00302:                if (this .compileErrorCount > 0)
00303:                    throw new CompileException(this .compileErrorCount
00304:                            + " error(s) while compiling unit \""
00305:                            + this .compilationUnit.optionalFileName + "\"",
00306:                            null);
00307:
00308:                List l = this .generatedClassFiles;
00309:                return (ClassFile[]) l.toArray(new ClassFile[l.size()]);
00310:            }
00311:
00312:            // ------------ TypeDeclaration.compile() -------------
00313:
00314:            private void compile(Java.TypeDeclaration td)
00315:                    throws CompileException {
00316:                class UCE extends RuntimeException {
00317:                    final CompileException ce;
00318:
00319:                    UCE(CompileException ce) {
00320:                        this .ce = ce;
00321:                    }
00322:                }
00323:                Visitor.TypeDeclarationVisitor tdv = new Visitor.TypeDeclarationVisitor() {
00324:                    public void visitAnonymousClassDeclaration(
00325:                            Java.AnonymousClassDeclaration acd) {
00326:                        try {
00327:                            UnitCompiler.this .compile2(acd);
00328:                        } catch (CompileException e) {
00329:                            throw new UCE(e);
00330:                        }
00331:                    }
00332:
00333:                    public void visitLocalClassDeclaration(
00334:                            Java.LocalClassDeclaration lcd) {
00335:                        try {
00336:                            UnitCompiler.this .compile2(lcd);
00337:                        } catch (CompileException e) {
00338:                            throw new UCE(e);
00339:                        }
00340:                    }
00341:
00342:                    public void visitPackageMemberClassDeclaration(
00343:                            Java.PackageMemberClassDeclaration pmcd) {
00344:                        try {
00345:                            UnitCompiler.this 
00346:                                    .compile2((Java.PackageMemberTypeDeclaration) pmcd);
00347:                        } catch (CompileException e) {
00348:                            throw new UCE(e);
00349:                        }
00350:                    }
00351:
00352:                    public void visitMemberInterfaceDeclaration(
00353:                            Java.MemberInterfaceDeclaration mid) {
00354:                        try {
00355:                            UnitCompiler.this .compile2(mid);
00356:                        } catch (CompileException e) {
00357:                            throw new UCE(e);
00358:                        }
00359:                    }
00360:
00361:                    public void visitPackageMemberInterfaceDeclaration(
00362:                            Java.PackageMemberInterfaceDeclaration pmid) {
00363:                        try {
00364:                            UnitCompiler.this 
00365:                                    .compile2((Java.PackageMemberTypeDeclaration) pmid);
00366:                        } catch (CompileException e) {
00367:                            throw new UCE(e);
00368:                        }
00369:                    }
00370:
00371:                    public void visitMemberClassDeclaration(
00372:                            Java.MemberClassDeclaration mcd) {
00373:                        try {
00374:                            UnitCompiler.this .compile2(mcd);
00375:                        } catch (CompileException e) {
00376:                            throw new UCE(e);
00377:                        }
00378:                    }
00379:                };
00380:                try {
00381:                    td.accept(tdv);
00382:                } catch (UCE uce) {
00383:                    throw uce.ce;
00384:                }
00385:            }
00386:
00387:            public void compile2(Java.PackageMemberTypeDeclaration pmtd)
00388:                    throws CompileException {
00389:                Java.CompilationUnit declaringCompilationUnit = pmtd
00390:                        .getDeclaringCompilationUnit();
00391:
00392:                // Check for conflict with single-type-import (7.6).
00393:                {
00394:                    String[] ss = this .getSingleTypeImport(pmtd.getName());
00395:                    if (ss != null)
00396:                        this 
00397:                                .compileError(
00398:                                        "Package member type declaration \""
00399:                                                + pmtd.getName()
00400:                                                + "\" conflicts with single-type-import \""
00401:                                                + Java.join(ss, ".") + "\"",
00402:                                        pmtd.getLocation());
00403:                }
00404:
00405:                // Check for redefinition within compilation unit (7.6).
00406:                {
00407:                    Java.PackageMemberTypeDeclaration otherPMTD = declaringCompilationUnit
00408:                            .getPackageMemberTypeDeclaration(pmtd.getName());
00409:                    if (otherPMTD != pmtd)
00410:                        this .compileError("Redeclaration of type \""
00411:                                + pmtd.getName()
00412:                                + "\", previously declared in "
00413:                                + otherPMTD.getLocation(), pmtd.getLocation());
00414:                }
00415:
00416:                if (pmtd instanceof  Java.NamedClassDeclaration) {
00417:                    this .compile2((Java.NamedClassDeclaration) pmtd);
00418:                } else if (pmtd instanceof  Java.InterfaceDeclaration) {
00419:                    this .compile2((Java.InterfaceDeclaration) pmtd);
00420:                } else {
00421:                    throw new RuntimeException("PMTD of unexpected type "
00422:                            + pmtd.getClass().getName());
00423:                }
00424:            }
00425:
00426:            public void compile2(Java.ClassDeclaration cd)
00427:                    throws CompileException {
00428:                IClass iClass = this .resolve(cd);
00429:
00430:                // Check that all methods are implemented.
00431:                if ((cd.modifiers & Mod.ABSTRACT) == 0) {
00432:                    IMethod[] ms = iClass.getIMethods();
00433:                    for (int i = 0; i < ms.length; ++i) {
00434:                        if (ms[i].isAbstract())
00435:                            this .compileError("Non-abstract class \"" + iClass
00436:                                    + "\" must implement method \"" + ms[i]
00437:                                    + "\"", cd.getLocation());
00438:                    }
00439:                }
00440:
00441:                // Create "ClassFile" object.
00442:                ClassFile cf = new ClassFile(
00443:                        (short) (cd.modifiers | Mod.SUPER), // accessFlags
00444:                        iClass.getDescriptor(), // thisClassFD
00445:                        iClass.getSuperclass().getDescriptor(), // superClassFD
00446:                        IClass.getDescriptors(iClass.getInterfaces()) // interfaceFDs
00447:                );
00448:
00449:                // Add InnerClasses attribute entry for this class declaration.
00450:                if (cd.getEnclosingScope() instanceof  Java.CompilationUnit) {
00451:                    ;
00452:                } else if (cd.getEnclosingScope() instanceof  Java.Block) {
00453:                    short innerClassInfoIndex = cf.addConstantClassInfo(iClass
00454:                            .getDescriptor());
00455:                    short innerNameIndex = (this  instanceof  Java.NamedTypeDeclaration ? cf
00456:                            .addConstantUtf8Info(((Java.NamedTypeDeclaration) this )
00457:                                    .getName())
00458:                            : (short) 0);
00459:                    cf
00460:                            .addInnerClassesAttributeEntry(new ClassFile.InnerClassesAttribute.Entry(
00461:                                    innerClassInfoIndex, // innerClassInfoIndex
00462:                                    (short) 0, // outerClassInfoIndex
00463:                                    innerNameIndex, // innerNameIndex
00464:                                    cd.modifiers // innerClassAccessFlags
00465:                            ));
00466:                } else if (cd.getEnclosingScope() instanceof  Java.AbstractTypeDeclaration) {
00467:                    short innerClassInfoIndex = cf.addConstantClassInfo(iClass
00468:                            .getDescriptor());
00469:                    short outerClassInfoIndex = cf.addConstantClassInfo(this 
00470:                            .resolve(
00471:                                    ((Java.AbstractTypeDeclaration) cd
00472:                                            .getEnclosingScope()))
00473:                            .getDescriptor());
00474:                    short innerNameIndex = cf
00475:                            .addConstantUtf8Info(((Java.MemberTypeDeclaration) cd)
00476:                                    .getName());
00477:                    cf
00478:                            .addInnerClassesAttributeEntry(new ClassFile.InnerClassesAttribute.Entry(
00479:                                    innerClassInfoIndex, // innerClassInfoIndex
00480:                                    outerClassInfoIndex, // outerClassInfoIndex
00481:                                    innerNameIndex, // innerNameIndex
00482:                                    cd.modifiers // innerClassAccessFlags
00483:                            ));
00484:                }
00485:
00486:                // Set "SourceFile" attribute.
00487:                if (this .debuggingInformation
00488:                        .contains(DebuggingInformation.SOURCE)) {
00489:                    String sourceFileName;
00490:                    {
00491:                        String s = cd.getLocation().getFileName();
00492:                        if (s != null) {
00493:                            sourceFileName = new File(s).getName();
00494:                        } else if (cd instanceof  Java.NamedTypeDeclaration) {
00495:                            sourceFileName = ((Java.NamedTypeDeclaration) cd)
00496:                                    .getName()
00497:                                    + ".java";
00498:                        } else {
00499:                            sourceFileName = "ANONYMOUS.java";
00500:                        }
00501:                    }
00502:                    cf.addSourceFileAttribute(sourceFileName);
00503:                }
00504:
00505:                // Add "Deprecated" attribute (JVMS 4.7.10)
00506:                if (cd instanceof  Java.DocCommentable) {
00507:                    if (((Java.DocCommentable) cd).hasDeprecatedDocTag())
00508:                        cf.addDeprecatedAttribute();
00509:                }
00510:
00511:                // Optional: Generate and compile class initialization method.
00512:                {
00513:                    Java.Block b = new Java.Block(cd.getLocation());
00514:                    for (Iterator it = cd.variableDeclaratorsAndInitializers
00515:                            .iterator(); it.hasNext();) {
00516:                        Java.TypeBodyDeclaration tbd = (Java.TypeBodyDeclaration) it
00517:                                .next();
00518:                        if (tbd.isStatic())
00519:                            b
00520:                                    .addButDontEncloseStatement((Java.BlockStatement) tbd);
00521:                    }
00522:
00523:                    // Create class initialization method iff there is any initialization code.
00524:                    Java.MethodDeclarator classInitializationMethod = new Java.MethodDeclarator(
00525:                            cd.getLocation(), // location
00526:                            null, // optionalDocComment
00527:                            (short) ( // modifiers
00528:                            Mod.STATIC | Mod.PUBLIC), new Java.BasicType( // type
00529:                                    cd.getLocation(), Java.BasicType.VOID),
00530:                            "<clinit>", // name
00531:                            new Java.FunctionDeclarator.FormalParameter[0], // formalParameters
00532:                            new Java.ReferenceType[0], // thrownExceptions
00533:                            b // optionalBody
00534:                    );
00535:                    if (this .generatesCode(b)) {
00536:                        classInitializationMethod.setDeclaringType(cd);
00537:                        this .compile(classInitializationMethod, cf);
00538:                    }
00539:                }
00540:
00541:                // Compile declared methods.
00542:                // (As a side effects, this fills the "syntheticFields" map.)
00543:                for (int i = 0; i < cd.declaredMethods.size(); ++i) {
00544:                    this .compile(((Java.MethodDeclarator) cd.declaredMethods
00545:                            .get(i)), cf);
00546:                }
00547:
00548:                // Compile declared constructors.
00549:                int declaredMethodCount = cd.declaredMethods.size();
00550:                {
00551:                    int syntheticFieldCount = cd.syntheticFields.size();
00552:                    Java.ConstructorDeclarator[] cds = cd.getConstructors();
00553:                    for (int i = 0; i < cds.length; ++i) {
00554:                        this .compile(cds[i], cf);
00555:                        if (syntheticFieldCount != cd.syntheticFields.size())
00556:                            throw new RuntimeException(
00557:                                    "SNO: Compilation of constructor \""
00558:                                            + cds[i] + "\" ("
00559:                                            + cds[i].getLocation()
00560:                                            + ") added synthetic fields!?");
00561:                    }
00562:                }
00563:
00564:                // As a side effect of compiling methods and constructors, synthetic "class-dollar"
00565:                // methods (which implement class literals) are generated on-the fly. Compile these.
00566:                for (int i = declaredMethodCount; i < cd.declaredMethods.size(); ++i) {
00567:                    this .compile(((Java.MethodDeclarator) cd.declaredMethods
00568:                            .get(i)), cf);
00569:                }
00570:
00571:                // Class and instance variables.
00572:                for (Iterator it = cd.variableDeclaratorsAndInitializers
00573:                        .iterator(); it.hasNext();) {
00574:                    Java.TypeBodyDeclaration tbd = (Java.TypeBodyDeclaration) it
00575:                            .next();
00576:                    if (!(tbd instanceof  Java.FieldDeclaration))
00577:                        continue;
00578:                    this .addFields((Java.FieldDeclaration) tbd, cf);
00579:                }
00580:
00581:                // Synthetic fields.
00582:                for (Iterator it = cd.syntheticFields.values().iterator(); it
00583:                        .hasNext();) {
00584:                    IClass.IField f = (IClass.IField) it.next();
00585:                    cf.addFieldInfo(Mod.PACKAGE, // modifiers,
00586:                            f.getName(), // fieldName,
00587:                            f.getType().getDescriptor(), // fieldTypeFD,
00588:                            null // optionalConstantValue
00589:                            );
00590:                }
00591:
00592:                // Member types.
00593:                for (Iterator it = cd.getMemberTypeDeclarations().iterator(); it
00594:                        .hasNext();) {
00595:                    Java.AbstractTypeDeclaration atd = ((Java.AbstractTypeDeclaration) it
00596:                            .next());
00597:                    this .compile(atd);
00598:
00599:                    // Add InnerClasses attribute entry for member type declaration.
00600:                    short innerClassInfoIndex = cf.addConstantClassInfo(this 
00601:                            .resolve(atd).getDescriptor());
00602:                    short outerClassInfoIndex = cf.addConstantClassInfo(iClass
00603:                            .getDescriptor());
00604:                    short innerNameIndex = cf
00605:                            .addConstantUtf8Info(((Java.MemberTypeDeclaration) atd)
00606:                                    .getName());
00607:                    cf
00608:                            .addInnerClassesAttributeEntry(new ClassFile.InnerClassesAttribute.Entry(
00609:                                    innerClassInfoIndex, // innerClassInfoIndex
00610:                                    outerClassInfoIndex, // outerClassInfoIndex
00611:                                    innerNameIndex, // innerNameIndex
00612:                                    atd.modifiers // innerClassAccessFlags
00613:                            ));
00614:                }
00615:
00616:                // Add the generated class file to a thread-local store.
00617:                this .generatedClassFiles.add(cf);
00618:            }
00619:
00620:            /**
00621:             * Create {@link ClassFile.FieldInfo}s for all fields declared by the
00622:             * given {@link Java.FieldDeclaration}.
00623:             */
00624:            private void addFields(Java.FieldDeclaration fd, ClassFile cf)
00625:                    throws CompileException {
00626:                for (int j = 0; j < fd.variableDeclarators.length; ++j) {
00627:                    Java.VariableDeclarator vd = fd.variableDeclarators[j];
00628:                    Java.Type type = fd.type;
00629:                    for (int k = 0; k < vd.brackets; ++k)
00630:                        type = new Java.ArrayType(type);
00631:
00632:                    Object ocv = null;
00633:                    if ((fd.modifiers & Mod.FINAL) != 0
00634:                            && vd.optionalInitializer != null) {
00635:                        if (vd.optionalInitializer instanceof  Java.Rvalue)
00636:                            ocv = this 
00637:                                    .getConstantValue((Java.Rvalue) vd.optionalInitializer);
00638:                        if (ocv == Java.Rvalue.CONSTANT_VALUE_NULL)
00639:                            ocv = null;
00640:                    }
00641:
00642:                    ClassFile.FieldInfo fi;
00643:                    if (Mod.isPrivateAccess(fd.modifiers)) {
00644:
00645:                        // To make the private field accessible for enclosing types, enclosed types and types
00646:                        // enclosed by the same type, it is modified as follows:
00647:                        //  + Access is changed from PRIVATE to PACKAGE
00648:                        fi = cf.addFieldInfo(Mod.changeAccess(fd.modifiers,
00649:                                Mod.PACKAGE), // modifiers
00650:                                vd.name, // fieldName
00651:                                this .getType(type).getDescriptor(), // fieldTypeFD
00652:                                ocv // optionalConstantValue
00653:                                );
00654:                    } else {
00655:                        fi = cf.addFieldInfo(fd.modifiers, // modifiers
00656:                                vd.name, // fieldName
00657:                                this .getType(type).getDescriptor(), // fieldTypeFD
00658:                                ocv // optionalConstantValue
00659:                                );
00660:                    }
00661:
00662:                    // Add "Deprecated" attribute (JVMS 4.7.10)
00663:                    if (fd.hasDeprecatedDocTag()) {
00664:                        fi.addAttribute(new ClassFile.DeprecatedAttribute(cf
00665:                                .addConstantUtf8Info("Deprecated")));
00666:                    }
00667:                }
00668:            }
00669:
00670:            public void compile2(Java.AnonymousClassDeclaration acd)
00671:                    throws CompileException {
00672:                this .compile2((Java.InnerClassDeclaration) acd);
00673:            }
00674:
00675:            public void compile2(Java.LocalClassDeclaration lcd)
00676:                    throws CompileException {
00677:                this .compile2((Java.InnerClassDeclaration) lcd);
00678:            }
00679:
00680:            public void compile2(Java.InnerClassDeclaration icd)
00681:                    throws CompileException {
00682:
00683:                // Define a synthetic "this$..." field if there is an enclosing instance.
00684:                {
00685:                    List ocs = UnitCompiler.getOuterClasses(icd);
00686:                    final int nesting = ocs.size();
00687:                    if (nesting >= 2) {
00688:                        icd.defineSyntheticField(new SimpleIField(this 
00689:                                .resolve(icd), "this$" + (nesting - 2), this 
00690:                                .resolve((Java.AbstractTypeDeclaration) ocs
00691:                                        .get(1))));
00692:                    }
00693:                }
00694:
00695:                this .compile2((Java.ClassDeclaration) icd);
00696:            }
00697:
00698:            public void compile2(final Java.MemberClassDeclaration mcd)
00699:                    throws CompileException {
00700:                this .compile2((Java.InnerClassDeclaration) mcd);
00701:            }
00702:
00703:            public void compile2(Java.InterfaceDeclaration id)
00704:                    throws CompileException {
00705:
00706:                // Determine extended interfaces.
00707:                id.interfaces = new IClass[id.extendedTypes.length];
00708:                String[] interfaceDescriptors = new String[id.interfaces.length];
00709:                for (int i = 0; i < id.extendedTypes.length; ++i) {
00710:                    id.interfaces[i] = this .getType(id.extendedTypes[i]);
00711:                    interfaceDescriptors[i] = id.interfaces[i].getDescriptor();
00712:                }
00713:
00714:                // Create "ClassFile" object.
00715:                ClassFile cf = new ClassFile(
00716:                        (short) ( // accessFlags
00717:                        id.modifiers | Mod.SUPER | Mod.INTERFACE | Mod.ABSTRACT),
00718:                        this .resolve(id).getDescriptor(), // thisClassFD
00719:                        Descriptor.OBJECT, // superClassFD
00720:                        interfaceDescriptors // interfaceFDs
00721:                );
00722:
00723:                // Set "SourceFile" attribute.
00724:                if (this .debuggingInformation
00725:                        .contains(DebuggingInformation.SOURCE)) {
00726:                    String sourceFileName;
00727:                    {
00728:                        String s = id.getLocation().getFileName();
00729:                        if (s != null) {
00730:                            sourceFileName = new File(s).getName();
00731:                        } else {
00732:                            sourceFileName = id.getName() + ".java";
00733:                        }
00734:                    }
00735:                    cf.addSourceFileAttribute(sourceFileName);
00736:                }
00737:
00738:                // Add "Deprecated" attribute (JVMS 4.7.10)
00739:                if (id.hasDeprecatedDocTag())
00740:                    cf.addDeprecatedAttribute();
00741:
00742:                // Interface initialization method.
00743:                if (!id.constantDeclarations.isEmpty()) {
00744:                    Java.Block b = new Java.Block(id.getLocation());
00745:                    b.addButDontEncloseStatements(id.constantDeclarations);
00746:
00747:                    // Create interface initialization method iff there is any initialization code.
00748:                    if (this .generatesCode(b)) {
00749:                        Java.MethodDeclarator md = new Java.MethodDeclarator(
00750:                                id.getLocation(), // location
00751:                                null, // optionalDocComment
00752:                                (short) (Mod.STATIC | Mod.PUBLIC), // modifiers
00753:                                new Java.BasicType( // type
00754:                                        id.getLocation(), Java.BasicType.VOID),
00755:                                "<clinit>", // name
00756:                                new Java.FunctionDeclarator.FormalParameter[0], // formalParameters
00757:                                new Java.ReferenceType[0], // thrownExcaptions
00758:                                b // optionalBody
00759:                        );
00760:                        md.setDeclaringType(id);
00761:                        this .compile(md, cf);
00762:                    }
00763:                }
00764:
00765:                // Methods.
00766:                // Notice that as a side effect of compiling methods, synthetic "class-dollar"
00767:                // methods (which implement class literals) are generated on-the fly. Hence, we
00768:                // must not use an Iterator here.
00769:                for (int i = 0; i < id.declaredMethods.size(); ++i) {
00770:                    this .compile(((Java.MethodDeclarator) id.declaredMethods
00771:                            .get(i)), cf);
00772:                }
00773:
00774:                // Class variables.
00775:                for (int i = 0; i < id.constantDeclarations.size(); ++i) {
00776:                    Java.BlockStatement bs = (Java.BlockStatement) id.constantDeclarations
00777:                            .get(i);
00778:                    if (!(bs instanceof  Java.FieldDeclaration))
00779:                        continue;
00780:                    this .addFields((Java.FieldDeclaration) bs, cf);
00781:                }
00782:
00783:                // Member types.
00784:                for (Iterator it = id.getMemberTypeDeclarations().iterator(); it
00785:                        .hasNext();) {
00786:                    Java.AbstractTypeDeclaration atd = ((Java.AbstractTypeDeclaration) it
00787:                            .next());
00788:                    this .compile(atd);
00789:
00790:                    // Add InnerClasses attribute entry for member type declaration.
00791:                    short innerClassInfoIndex = cf.addConstantClassInfo(this 
00792:                            .resolve(atd).getDescriptor());
00793:                    short outerClassInfoIndex = cf.addConstantClassInfo(this 
00794:                            .resolve(id).getDescriptor());
00795:                    short innerNameIndex = cf
00796:                            .addConstantUtf8Info(((Java.MemberTypeDeclaration) atd)
00797:                                    .getName());
00798:                    cf
00799:                            .addInnerClassesAttributeEntry(new ClassFile.InnerClassesAttribute.Entry(
00800:                                    innerClassInfoIndex, // innerClassInfoIndex
00801:                                    outerClassInfoIndex, // outerClassInfoIndex
00802:                                    innerNameIndex, // innerNameIndex
00803:                                    id.modifiers // innerClassAccessFlags
00804:                            ));
00805:                }
00806:
00807:                // Add the generated class file to a thread-local store.
00808:                this .generatedClassFiles.add(cf);
00809:            }
00810:
00811:            /**
00812:             * @return <tt>false</tt> if this statement cannot complete normally (JLS2
00813:             * 14.20)
00814:             */
00815:            private boolean compile(Java.BlockStatement bs)
00816:                    throws CompileException {
00817:                final boolean[] res = new boolean[1];
00818:                class UCE extends RuntimeException {
00819:                    final CompileException ce;
00820:
00821:                    UCE(CompileException ce) {
00822:                        this .ce = ce;
00823:                    }
00824:                }
00825:                Visitor.BlockStatementVisitor bsv = new Visitor.BlockStatementVisitor() {
00826:                    public void visitInitializer(Java.Initializer i) {
00827:                        try {
00828:                            res[0] = UnitCompiler.this .compile2(i);
00829:                        } catch (CompileException e) {
00830:                            throw new UCE(e);
00831:                        }
00832:                    }
00833:
00834:                    public void visitFieldDeclaration(Java.FieldDeclaration fd) {
00835:                        try {
00836:                            res[0] = UnitCompiler.this .compile2(fd);
00837:                        } catch (CompileException e) {
00838:                            throw new UCE(e);
00839:                        }
00840:                    }
00841:
00842:                    public void visitLabeledStatement(Java.LabeledStatement ls) {
00843:                        try {
00844:                            res[0] = UnitCompiler.this .compile2(ls);
00845:                        } catch (CompileException e) {
00846:                            throw new UCE(e);
00847:                        }
00848:                    }
00849:
00850:                    public void visitBlock(Java.Block b) {
00851:                        try {
00852:                            res[0] = UnitCompiler.this .compile2(b);
00853:                        } catch (CompileException e) {
00854:                            throw new UCE(e);
00855:                        }
00856:                    }
00857:
00858:                    public void visitExpressionStatement(
00859:                            Java.ExpressionStatement es) {
00860:                        try {
00861:                            res[0] = UnitCompiler.this .compile2(es);
00862:                        } catch (CompileException e) {
00863:                            throw new UCE(e);
00864:                        }
00865:                    }
00866:
00867:                    public void visitIfStatement(Java.IfStatement is) {
00868:                        try {
00869:                            res[0] = UnitCompiler.this .compile2(is);
00870:                        } catch (CompileException e) {
00871:                            throw new UCE(e);
00872:                        }
00873:                    }
00874:
00875:                    public void visitForStatement(Java.ForStatement fs) {
00876:                        try {
00877:                            res[0] = UnitCompiler.this .compile2(fs);
00878:                        } catch (CompileException e) {
00879:                            throw new UCE(e);
00880:                        }
00881:                    }
00882:
00883:                    public void visitWhileStatement(Java.WhileStatement ws) {
00884:                        try {
00885:                            res[0] = UnitCompiler.this .compile2(ws);
00886:                        } catch (CompileException e) {
00887:                            throw new UCE(e);
00888:                        }
00889:                    }
00890:
00891:                    public void visitTryStatement(Java.TryStatement ts) {
00892:                        try {
00893:                            res[0] = UnitCompiler.this .compile2(ts);
00894:                        } catch (CompileException e) {
00895:                            throw new UCE(e);
00896:                        }
00897:                    }
00898:
00899:                    public void visitSwitchStatement(Java.SwitchStatement ss) {
00900:                        try {
00901:                            res[0] = UnitCompiler.this .compile2(ss);
00902:                        } catch (CompileException e) {
00903:                            throw new UCE(e);
00904:                        }
00905:                    }
00906:
00907:                    public void visitSynchronizedStatement(
00908:                            Java.SynchronizedStatement ss) {
00909:                        try {
00910:                            res[0] = UnitCompiler.this .compile2(ss);
00911:                        } catch (CompileException e) {
00912:                            throw new UCE(e);
00913:                        }
00914:                    }
00915:
00916:                    public void visitDoStatement(Java.DoStatement ds) {
00917:                        try {
00918:                            res[0] = UnitCompiler.this .compile2(ds);
00919:                        } catch (CompileException e) {
00920:                            throw new UCE(e);
00921:                        }
00922:                    }
00923:
00924:                    public void visitLocalVariableDeclarationStatement(
00925:                            Java.LocalVariableDeclarationStatement lvds) {
00926:                        try {
00927:                            res[0] = UnitCompiler.this .compile2(lvds);
00928:                        } catch (CompileException e) {
00929:                            throw new UCE(e);
00930:                        }
00931:                    }
00932:
00933:                    public void visitReturnStatement(Java.ReturnStatement rs) {
00934:                        try {
00935:                            res[0] = UnitCompiler.this .compile2(rs);
00936:                        } catch (CompileException e) {
00937:                            throw new UCE(e);
00938:                        }
00939:                    }
00940:
00941:                    public void visitThrowStatement(Java.ThrowStatement ts) {
00942:                        try {
00943:                            res[0] = UnitCompiler.this .compile2(ts);
00944:                        } catch (CompileException e) {
00945:                            throw new UCE(e);
00946:                        }
00947:                    }
00948:
00949:                    public void visitBreakStatement(Java.BreakStatement bs) {
00950:                        try {
00951:                            res[0] = UnitCompiler.this .compile2(bs);
00952:                        } catch (CompileException e) {
00953:                            throw new UCE(e);
00954:                        }
00955:                    }
00956:
00957:                    public void visitContinueStatement(Java.ContinueStatement cs) {
00958:                        try {
00959:                            res[0] = UnitCompiler.this .compile2(cs);
00960:                        } catch (CompileException e) {
00961:                            throw new UCE(e);
00962:                        }
00963:                    }
00964:
00965:                    public void visitEmptyStatement(Java.EmptyStatement es) {
00966:                        res[0] = UnitCompiler.this .compile2(es);
00967:                    }
00968:
00969:                    public void visitLocalClassDeclarationStatement(
00970:                            Java.LocalClassDeclarationStatement lcds) {
00971:                        try {
00972:                            res[0] = UnitCompiler.this .compile2(lcds);
00973:                        } catch (CompileException e) {
00974:                            throw new UCE(e);
00975:                        }
00976:                    }
00977:
00978:                    public void visitAlternateConstructorInvocation(
00979:                            Java.AlternateConstructorInvocation aci) {
00980:                        try {
00981:                            res[0] = UnitCompiler.this .compile2(aci);
00982:                        } catch (CompileException e) {
00983:                            throw new UCE(e);
00984:                        }
00985:                    }
00986:
00987:                    public void visitSuperConstructorInvocation(
00988:                            Java.SuperConstructorInvocation sci) {
00989:                        try {
00990:                            res[0] = UnitCompiler.this .compile2(sci);
00991:                        } catch (CompileException e) {
00992:                            throw new UCE(e);
00993:                        }
00994:                    }
00995:                };
00996:                try {
00997:                    bs.accept(bsv);
00998:                    return res[0];
00999:                } catch (UCE uce) {
01000:                    throw uce.ce;
01001:                }
01002:            }
01003:
01004:            private boolean compile2(Java.Initializer i)
01005:                    throws CompileException {
01006:                return this .compile(i.block);
01007:            }
01008:
01009:            private boolean compile2(Java.Block b) throws CompileException {
01010:                this .codeContext.saveLocalVariables();
01011:                try {
01012:                    boolean previousStatementCanCompleteNormally = true;
01013:                    for (int i = 0; i < b.statements.size(); ++i) {
01014:                        Java.BlockStatement bs = (Java.BlockStatement) b.statements
01015:                                .get(i);
01016:                        if (!previousStatementCanCompleteNormally) {
01017:                            this .compileError("Statement is unreachable", bs
01018:                                    .getLocation());
01019:                            break;
01020:                        }
01021:                        previousStatementCanCompleteNormally = this .compile(bs);
01022:                    }
01023:                    return previousStatementCanCompleteNormally;
01024:                } finally {
01025:                    this .codeContext.restoreLocalVariables();
01026:                }
01027:            }
01028:
01029:            private boolean compile2(Java.DoStatement ds)
01030:                    throws CompileException {
01031:                Object cvc = this .getConstantValue(ds.condition);
01032:                if (cvc != null) {
01033:                    if (Boolean.TRUE.equals(cvc)) {
01034:                        this 
01035:                                .warning(
01036:                                        "DSTC",
01037:                                        "Condition of DO statement is always TRUE; the proper way of declaring an unconditional loop is \"for (;;)\"",
01038:                                        ds.getLocation());
01039:                        return this .compileUnconditionalLoop(ds, ds.body, null);
01040:                    } else {
01041:                        this .warning("DSNR", "DO statement never repeats", ds
01042:                                .getLocation());
01043:                    }
01044:                }
01045:
01046:                ds.whereToContinue = this .codeContext.new Offset();
01047:                ds.bodyHasContinue = false;
01048:
01049:                CodeContext.Offset bodyOffset = this .codeContext.newOffset();
01050:
01051:                // Compile body.
01052:                if (!this .compile(ds.body) && !ds.bodyHasContinue) {
01053:                    this .warning("DSNTC",
01054:                            "\"do\" statement never tests its condition", ds
01055:                                    .getLocation());
01056:                    if (ds.whereToBreak == null)
01057:                        return false;
01058:                    ds.whereToBreak.set();
01059:                    return true;
01060:                }
01061:
01062:                // Compile condition.
01063:                ds.whereToContinue.set();
01064:                this .compileBoolean(ds.condition, bodyOffset,
01065:                        Java.Rvalue.JUMP_IF_TRUE);
01066:
01067:                if (ds.whereToBreak != null)
01068:                    ds.whereToBreak.set();
01069:
01070:                return true;
01071:            }
01072:
01073:            private boolean compile2(Java.ForStatement fs)
01074:                    throws CompileException {
01075:                this .codeContext.saveLocalVariables();
01076:                try {
01077:
01078:                    // Compile init.
01079:                    if (fs.optionalInit != null)
01080:                        this .compile(fs.optionalInit);
01081:
01082:                    if (fs.optionalCondition == null) {
01083:                        return this .compileUnconditionalLoop(fs, fs.body,
01084:                                fs.optionalUpdate);
01085:                    } else {
01086:                        Object cvc = this 
01087:                                .getConstantValue(fs.optionalCondition);
01088:                        if (cvc != null) {
01089:                            if (Boolean.TRUE.equals(cvc)) {
01090:                                this 
01091:                                        .warning(
01092:                                                "FSTC",
01093:                                                "Condition of FOR statement is always TRUE; the proper way of declaring an unconditional loop is \"for (;;)\"",
01094:                                                fs.getLocation());
01095:                                return this .compileUnconditionalLoop(fs,
01096:                                        fs.body, fs.optionalUpdate);
01097:                            } else {
01098:                                this .warning("FSNR",
01099:                                        "FOR statement never repeats", fs
01100:                                                .getLocation());
01101:                            }
01102:                        }
01103:                    }
01104:
01105:                    CodeContext.Offset toCondition = this .codeContext.new Offset();
01106:                    this .writeBranch(fs, Opcode.GOTO, toCondition);
01107:
01108:                    // Compile body.
01109:                    fs.whereToContinue = this .codeContext.new Offset();
01110:                    fs.bodyHasContinue = false;
01111:                    CodeContext.Offset bodyOffset = this .codeContext
01112:                            .newOffset();
01113:                    boolean bodyCCN = this .compile(fs.body);
01114:
01115:                    // Compile update.
01116:                    fs.whereToContinue.set();
01117:                    if (fs.optionalUpdate != null) {
01118:                        if (!bodyCCN && !fs.bodyHasContinue) {
01119:                            this .warning("FUUR", "For update is unreachable",
01120:                                    fs.getLocation());
01121:                        } else {
01122:                            for (int i = 0; i < fs.optionalUpdate.length; ++i) {
01123:                                this .compile(fs.optionalUpdate[i]);
01124:                            }
01125:                        }
01126:                    }
01127:
01128:                    // Compile condition.
01129:                    toCondition.set();
01130:                    this .compileBoolean(fs.optionalCondition, bodyOffset,
01131:                            Java.Rvalue.JUMP_IF_TRUE);
01132:                } finally {
01133:                    this .codeContext.restoreLocalVariables();
01134:                }
01135:
01136:                if (fs.whereToBreak != null)
01137:                    fs.whereToBreak.set();
01138:
01139:                return true;
01140:            }
01141:
01142:            private boolean compile2(Java.WhileStatement ws)
01143:                    throws CompileException {
01144:                Object cvc = this .getConstantValue(ws.condition);
01145:                if (cvc != null) {
01146:                    if (Boolean.TRUE.equals(cvc)) {
01147:                        this 
01148:                                .warning(
01149:                                        "WSTC",
01150:                                        "Condition of WHILE statement is always TRUE; the proper way of declaring an unconditional loop is \"for (;;)\"",
01151:                                        ws.getLocation());
01152:                        return this .compileUnconditionalLoop(ws, ws.body, null);
01153:                    } else {
01154:                        this .warning("WSNR", "WHILE statement never repeats",
01155:                                ws.getLocation());
01156:                    }
01157:                }
01158:
01159:                ws.whereToContinue = this .codeContext.new Offset();
01160:                ws.bodyHasContinue = false;
01161:                this .writeBranch(ws, Opcode.GOTO, ws.whereToContinue);
01162:
01163:                // Compile body.
01164:                CodeContext.Offset bodyOffset = this .codeContext.newOffset();
01165:                this .compile(ws.body); // Return value (CCN) is ignored.
01166:
01167:                // Compile condition.
01168:                ws.whereToContinue.set();
01169:                this .compileBoolean(ws.condition, bodyOffset,
01170:                        Java.Rvalue.JUMP_IF_TRUE);
01171:
01172:                if (ws.whereToBreak != null)
01173:                    ws.whereToBreak.set();
01174:                return true;
01175:            }
01176:
01177:            private boolean compileUnconditionalLoop(
01178:                    Java.ContinuableStatement cs, Java.BlockStatement body,
01179:                    Java.Rvalue[] optionalUpdate) throws CompileException {
01180:                if (optionalUpdate != null)
01181:                    return this .compileUnconditionalLoopWithUpdate(cs, body,
01182:                            optionalUpdate);
01183:
01184:                cs.whereToContinue = this .codeContext.newOffset();
01185:                cs.bodyHasContinue = false;
01186:
01187:                // Compile body.
01188:                if (this .compile(body))
01189:                    this .writeBranch(cs, Opcode.GOTO, cs.whereToContinue);
01190:
01191:                if (cs.whereToBreak == null)
01192:                    return false;
01193:                cs.whereToBreak.set();
01194:                return true;
01195:            }
01196:
01197:            private boolean compileUnconditionalLoopWithUpdate(
01198:                    Java.ContinuableStatement cs, Java.BlockStatement body,
01199:                    Java.Rvalue[] update) throws CompileException {
01200:                cs.whereToContinue = this .codeContext.new Offset();
01201:                cs.bodyHasContinue = false;
01202:
01203:                // Compile body.
01204:                CodeContext.Offset bodyOffset = this .codeContext.newOffset();
01205:                boolean bodyCCN = this .compile(body);
01206:
01207:                // Compile the "update".
01208:                cs.whereToContinue.set();
01209:                if (!bodyCCN && !cs.bodyHasContinue) {
01210:                    this .warning("LUUR", "Loop update is unreachable",
01211:                            update[0].getLocation());
01212:                } else {
01213:                    for (int i = 0; i < update.length; ++i)
01214:                        this .compile(update[i]);
01215:                    this .writeBranch(cs, Opcode.GOTO, bodyOffset);
01216:                }
01217:
01218:                if (cs.whereToBreak == null)
01219:                    return false;
01220:                cs.whereToBreak.set();
01221:                return true;
01222:            }
01223:
01224:            private final boolean compile2(Java.LabeledStatement ls)
01225:                    throws CompileException {
01226:                boolean canCompleteNormally = this .compile(ls.body);
01227:                if (ls.whereToBreak != null) {
01228:                    ls.whereToBreak.set();
01229:                    canCompleteNormally = true;
01230:                }
01231:                return canCompleteNormally;
01232:            }
01233:
01234:            private boolean compile2(Java.SwitchStatement ss)
01235:                    throws CompileException {
01236:
01237:                // Compute condition.
01238:                IClass switchExpressionType = this 
01239:                        .compileGetValue(ss.condition);
01240:                this .assignmentConversion((Locatable) ss, // l
01241:                        switchExpressionType, // sourceType
01242:                        IClass.INT, // targetType
01243:                        null // optionalConstantValue
01244:                        );
01245:
01246:                // Prepare the map of case labels to code offsets.
01247:                TreeMap caseLabelMap = new TreeMap(); // Integer => Offset
01248:                CodeContext.Offset defaultLabelOffset = null;
01249:                CodeContext.Offset[] sbsgOffsets = new CodeContext.Offset[ss.sbsgs
01250:                        .size()];
01251:                for (int i = 0; i < ss.sbsgs.size(); ++i) {
01252:                    Java.SwitchStatement.SwitchBlockStatementGroup sbsg = (Java.SwitchStatement.SwitchBlockStatementGroup) ss.sbsgs
01253:                            .get(i);
01254:                    sbsgOffsets[i] = this .codeContext.new Offset();
01255:                    for (int j = 0; j < sbsg.caseLabels.size(); ++j) {
01256:
01257:                        // Verify that case label value is a constant.
01258:                        Java.Rvalue rv = (Java.Rvalue) sbsg.caseLabels.get(j);
01259:                        Object cv = this .getConstantValue(rv);
01260:                        if (cv == null) {
01261:                            this 
01262:                                    .compileError(
01263:                                            "Value of \"case\" label does not pose a constant value",
01264:                                            rv.getLocation());
01265:                            cv = new Integer(99);
01266:                        }
01267:
01268:                        // Verify that case label is assignable to the type of the switch expression.
01269:                        IClass rvType = this .getType(rv);
01270:                        this .assignmentConversion((Locatable) ss, // l
01271:                                rvType, // sourceType
01272:                                switchExpressionType, // targetType
01273:                                cv // optionalConstantValue
01274:                                );
01275:
01276:                        // Convert char, byte, short, int to "Integer".
01277:                        Integer civ;
01278:                        if (cv instanceof  Integer) {
01279:                            civ = (Integer) cv;
01280:                        } else if (cv instanceof  Number) {
01281:                            civ = new Integer(((Number) cv).intValue());
01282:                        } else if (cv instanceof  Character) {
01283:                            civ = new Integer(((Character) cv).charValue());
01284:                        } else {
01285:                            this 
01286:                                    .compileError(
01287:                                            "Value of case label must be a char, byte, short or int constant",
01288:                                            rv.getLocation());
01289:                            civ = new Integer(99);
01290:                        }
01291:
01292:                        // Store in case label map.
01293:                        if (caseLabelMap.containsKey(civ))
01294:                            this .compileError(
01295:                                    "Duplicate \"case\" switch label value", rv
01296:                                            .getLocation());
01297:                        caseLabelMap.put(civ, sbsgOffsets[i]);
01298:                    }
01299:                    if (sbsg.hasDefaultLabel) {
01300:                        if (defaultLabelOffset != null)
01301:                            this .compileError(
01302:                                    "Duplicate \"default\" switch label", sbsg
01303:                                            .getLocation());
01304:                        defaultLabelOffset = sbsgOffsets[i];
01305:                    }
01306:                }
01307:                if (defaultLabelOffset == null)
01308:                    defaultLabelOffset = this .getWhereToBreak(ss);
01309:
01310:                // Generate TABLESWITCH or LOOKUPSWITCH instruction.
01311:                CodeContext.Offset switchOffset = this .codeContext.newOffset();
01312:                if (caseLabelMap.isEmpty()) {
01313:                    // Special case: SWITCH statement without CASE labels (but maybe a DEFAULT label).
01314:                    ;
01315:                } else if (((Integer) caseLabelMap.firstKey()).intValue()
01316:                        + caseLabelMap.size() >= // Beware of INT overflow!
01317:                ((Integer) caseLabelMap.lastKey()).intValue()
01318:                        - caseLabelMap.size()) {
01319:                    int low = ((Integer) caseLabelMap.firstKey()).intValue();
01320:                    int high = ((Integer) caseLabelMap.lastKey()).intValue();
01321:
01322:                    this .writeOpcode(ss, Opcode.TABLESWITCH);
01323:                    new Java.Padder(this .codeContext).set();
01324:                    this .writeOffset(switchOffset, defaultLabelOffset);
01325:                    this .writeInt(low);
01326:                    this .writeInt(high);
01327:                    Iterator si = caseLabelMap.entrySet().iterator();
01328:                    int cur = low;
01329:                    while (si.hasNext()) {
01330:                        Map.Entry me = (Map.Entry) si.next();
01331:                        int val = ((Integer) me.getKey()).intValue();
01332:                        while (cur < val) {
01333:                            this .writeOffset(switchOffset, defaultLabelOffset);
01334:                            ++cur;
01335:                        }
01336:                        this .writeOffset(switchOffset, (CodeContext.Offset) me
01337:                                .getValue());
01338:                        ++cur;
01339:                    }
01340:                } else {
01341:                    this .writeOpcode(ss, Opcode.LOOKUPSWITCH);
01342:                    new Java.Padder(this .codeContext).set();
01343:                    this .writeOffset(switchOffset, defaultLabelOffset);
01344:                    this .writeInt(caseLabelMap.size());
01345:                    Iterator si = caseLabelMap.entrySet().iterator();
01346:                    while (si.hasNext()) {
01347:                        Map.Entry me = (Map.Entry) si.next();
01348:                        this .writeInt(((Integer) me.getKey()).intValue());
01349:                        this .writeOffset(switchOffset, (CodeContext.Offset) me
01350:                                .getValue());
01351:                    }
01352:                }
01353:
01354:                // Compile statement groups.
01355:                boolean canCompleteNormally = true;
01356:                for (int i = 0; i < ss.sbsgs.size(); ++i) {
01357:                    Java.SwitchStatement.SwitchBlockStatementGroup sbsg = (Java.SwitchStatement.SwitchBlockStatementGroup) ss.sbsgs
01358:                            .get(i);
01359:                    sbsgOffsets[i].set();
01360:                    canCompleteNormally = true;
01361:                    for (int j = 0; j < sbsg.blockStatements.size(); ++j) {
01362:                        Java.BlockStatement bs = (Java.BlockStatement) sbsg.blockStatements
01363:                                .get(j);
01364:                        if (!canCompleteNormally) {
01365:                            this .compileError("Statement is unreachable", bs
01366:                                    .getLocation());
01367:                            break;
01368:                        }
01369:                        canCompleteNormally = this .compile(bs);
01370:                    }
01371:                }
01372:                if (ss.whereToBreak != null) {
01373:                    ss.whereToBreak.set();
01374:                    canCompleteNormally = true;
01375:                }
01376:                return canCompleteNormally;
01377:            }
01378:
01379:            private boolean compile2(Java.BreakStatement bs)
01380:                    throws CompileException {
01381:
01382:                // Find the broken statement.
01383:                Java.BreakableStatement brokenStatement = null;
01384:                if (bs.optionalLabel == null) {
01385:                    for (Java.Scope s = bs.getEnclosingScope(); s instanceof  Java.Statement
01386:                            || s instanceof  Java.CatchClause; s = s
01387:                            .getEnclosingScope()) {
01388:                        if (s instanceof  Java.BreakableStatement) {
01389:                            brokenStatement = (Java.BreakableStatement) s;
01390:                            break;
01391:                        }
01392:                    }
01393:                    if (brokenStatement == null) {
01394:                        this 
01395:                                .compileError(
01396:                                        "\"break\" statement is not enclosed by a breakable statement",
01397:                                        bs.getLocation());
01398:                        return false;
01399:                    }
01400:                } else {
01401:                    for (Java.Scope s = bs.getEnclosingScope(); s instanceof  Java.Statement
01402:                            || s instanceof  Java.CatchClause; s = s
01403:                            .getEnclosingScope()) {
01404:                        if (s instanceof  Java.LabeledStatement) {
01405:                            Java.LabeledStatement ls = (Java.LabeledStatement) s;
01406:                            if (ls.label.equals(bs.optionalLabel)) {
01407:                                brokenStatement = ls;
01408:                                break;
01409:                            }
01410:                        }
01411:                    }
01412:                    if (brokenStatement == null) {
01413:                        this 
01414:                                .compileError(
01415:                                        "Statement \"break "
01416:                                                + bs.optionalLabel
01417:                                                + "\" is not enclosed by a breakable statement with label \""
01418:                                                + bs.optionalLabel + "\"", bs
01419:                                                .getLocation());
01420:                        return false;
01421:                    }
01422:                }
01423:
01424:                this .leaveStatements(bs.getEnclosingScope(), // from
01425:                        brokenStatement.getEnclosingScope(), // to
01426:                        null // optionalStackValueType
01427:                        );
01428:                this .writeBranch(bs, Opcode.GOTO, this 
01429:                        .getWhereToBreak(brokenStatement));
01430:                return false;
01431:            }
01432:
01433:            private boolean compile2(Java.ContinueStatement cs)
01434:                    throws CompileException {
01435:
01436:                // Find the continued statement.
01437:                Java.ContinuableStatement continuedStatement = null;
01438:                if (cs.optionalLabel == null) {
01439:                    for (Java.Scope s = cs.getEnclosingScope(); s instanceof  Java.Statement
01440:                            || s instanceof  Java.CatchClause; s = s
01441:                            .getEnclosingScope()) {
01442:                        if (s instanceof  Java.ContinuableStatement) {
01443:                            continuedStatement = (Java.ContinuableStatement) s;
01444:                            break;
01445:                        }
01446:                    }
01447:                    if (continuedStatement == null) {
01448:                        this 
01449:                                .compileError(
01450:                                        "\"continue\" statement is not enclosed by a continuable statement",
01451:                                        cs.getLocation());
01452:                        return false;
01453:                    }
01454:                } else {
01455:                    for (Java.Scope s = cs.getEnclosingScope(); s instanceof  Java.Statement
01456:                            || s instanceof  Java.CatchClause; s = s
01457:                            .getEnclosingScope()) {
01458:                        if (s instanceof  Java.LabeledStatement) {
01459:                            Java.LabeledStatement ls = (Java.LabeledStatement) s;
01460:                            if (ls.label.equals(cs.optionalLabel)) {
01461:                                Java.Statement st = ls.body;
01462:                                while (st instanceof  Java.LabeledStatement)
01463:                                    st = ((Java.LabeledStatement) st).body;
01464:                                if (!(st instanceof  Java.ContinuableStatement)) {
01465:                                    this 
01466:                                            .compileError(
01467:                                                    "Labeled statement is not continuable",
01468:                                                    st.getLocation());
01469:                                    return false;
01470:                                }
01471:                                continuedStatement = (Java.ContinuableStatement) st;
01472:                                break;
01473:                            }
01474:                        }
01475:                    }
01476:                    if (continuedStatement == null) {
01477:                        this 
01478:                                .compileError(
01479:                                        "Statement \"continue "
01480:                                                + cs.optionalLabel
01481:                                                + "\" is not enclosed by a continuable statement with label \""
01482:                                                + cs.optionalLabel + "\"", cs
01483:                                                .getLocation());
01484:                        return false;
01485:                    }
01486:                }
01487:
01488:                continuedStatement.bodyHasContinue = true;
01489:                this .leaveStatements(cs.getEnclosingScope(), // from
01490:                        continuedStatement.getEnclosingScope(), // to
01491:                        null // optionalStackValueType
01492:                        );
01493:                this .writeBranch(cs, Opcode.GOTO,
01494:                        continuedStatement.whereToContinue);
01495:                return false;
01496:            }
01497:
01498:            private boolean compile2(Java.EmptyStatement es) {
01499:                return true;
01500:            }
01501:
01502:            private boolean compile2(Java.ExpressionStatement ee)
01503:                    throws CompileException {
01504:                this .compile(ee.rvalue);
01505:                return true;
01506:            }
01507:
01508:            private boolean compile2(Java.FieldDeclaration fd)
01509:                    throws CompileException {
01510:                for (int i = 0; i < fd.variableDeclarators.length; ++i) {
01511:                    Java.VariableDeclarator vd = fd.variableDeclarators[i];
01512:
01513:                    Java.ArrayInitializerOrRvalue initializer = this 
01514:                            .getNonConstantFinalInitializer(fd, vd);
01515:                    if (initializer == null)
01516:                        continue;
01517:
01518:                    if ((fd.modifiers & Mod.STATIC) == 0) {
01519:                        this .writeOpcode(fd, Opcode.ALOAD_0);
01520:                    }
01521:                    IClass fieldType = this .getType(fd.type);
01522:                    if (initializer instanceof  Java.Rvalue) {
01523:                        Java.Rvalue rvalue = (Java.Rvalue) initializer;
01524:                        IClass initializerType = this .compileGetValue(rvalue);
01525:                        fieldType = fieldType.getArrayIClass(vd.brackets,
01526:                                this .iClassLoader.OBJECT);
01527:                        this .assignmentConversion((Locatable) fd, // l
01528:                                initializerType, // sourceType
01529:                                fieldType, // destinationType
01530:                                this .getConstantValue(rvalue) // optionalConstantValue
01531:                                );
01532:                    } else if (initializer instanceof  Java.ArrayInitializer) {
01533:                        this .compileGetValue(
01534:                                (Java.ArrayInitializer) initializer, fieldType);
01535:                    } else {
01536:                        throw new RuntimeException(
01537:                                "Unexpected array initializer or rvalue class "
01538:                                        + initializer.getClass().getName());
01539:                    }
01540:
01541:                    // No need to check accessibility here.
01542:                    ;
01543:
01544:                    if ((fd.modifiers & Mod.STATIC) != 0) {
01545:                        this .writeOpcode(fd, Opcode.PUTSTATIC);
01546:                    } else {
01547:                        this .writeOpcode(fd, Opcode.PUTFIELD);
01548:                    }
01549:                    this .writeConstantFieldrefInfo(this .resolve(
01550:                            fd.getDeclaringType()).getDescriptor(), vd.name, // classFD
01551:                            fieldType.getDescriptor() // fieldFD
01552:                            );
01553:                }
01554:                return true;
01555:            }
01556:
01557:            private boolean compile2(Java.IfStatement is)
01558:                    throws CompileException {
01559:                Object cv = this .getConstantValue(is.condition);
01560:                Java.BlockStatement es = (is.optionalElseStatement != null ? is.optionalElseStatement
01561:                        : new Java.EmptyStatement(is.thenStatement
01562:                                .getLocation()));
01563:                if (cv instanceof  Boolean) {
01564:
01565:                    // Constant condition.
01566:                    this .fakeCompile(is.condition);
01567:                    Java.BlockStatement seeingStatement, blindStatement;
01568:                    if (((Boolean) cv).booleanValue()) {
01569:                        seeingStatement = is.thenStatement;
01570:                        blindStatement = es;
01571:                    } else {
01572:                        seeingStatement = es;
01573:                        blindStatement = is.thenStatement;
01574:                    }
01575:
01576:                    // Compile the seeing statement.
01577:                    CodeContext.Inserter ins = this .codeContext.newInserter();
01578:                    boolean ssccn = this .compile(seeingStatement);
01579:                    if (ssccn)
01580:                        return true;
01581:
01582:                    // Hm... the "seeing statement" cannot complete normally. Things are getting
01583:                    // complicated here! The robust solution is to compile the constant-condition-IF
01584:                    // statement as a non-constant-condition-IF statement. As an optimization, iff the
01585:                    // IF-statement is enclosed ONLY by blocks, then the remaining bytecode can be
01586:                    // written to a "fake" code context, i.e. be thrown away.
01587:
01588:                    // Constant-condition-IF statement only enclosed by blocks?
01589:                    Java.Scope s = is.getEnclosingScope();
01590:                    while (s instanceof  Java.Block)
01591:                        s = s.getEnclosingScope();
01592:                    if (s instanceof  Java.FunctionDeclarator) {
01593:
01594:                        // Yes, compile rest of method to /dev/null.
01595:                        throw UnitCompiler.STOP_COMPILING_CODE;
01596:                    } else {
01597:
01598:                        // Compile constant-condition-IF statement as non-constant-condition-IF statement.
01599:                        CodeContext.Offset off = this .codeContext.newOffset();
01600:                        this .codeContext.pushInserter(ins);
01601:                        try {
01602:                            this .pushConstant(is, new Integer(0));
01603:                            this .writeBranch((Locatable) is, Opcode.IFNE, off);
01604:                        } finally {
01605:                            this .codeContext.popInserter();
01606:                        }
01607:                    }
01608:                    return this .compile(blindStatement);
01609:                }
01610:
01611:                // Non-constant condition.
01612:                if (this .generatesCode(is.thenStatement)) {
01613:                    if (this .generatesCode(es)) {
01614:
01615:                        // if (expr) stmt else stmt
01616:                        CodeContext.Offset eso = this .codeContext.new Offset();
01617:                        CodeContext.Offset end = this .codeContext.new Offset();
01618:                        this .compileBoolean(is.condition, eso,
01619:                                Java.Rvalue.JUMP_IF_FALSE);
01620:                        boolean tsccn = this .compile(is.thenStatement);
01621:                        if (tsccn)
01622:                            this .writeBranch((Locatable) is, Opcode.GOTO, end);
01623:                        eso.set();
01624:                        boolean esccn = this .compile(es);
01625:                        end.set();
01626:                        return tsccn || esccn;
01627:                    } else {
01628:
01629:                        // if (expr) stmt else ;
01630:                        CodeContext.Offset end = this .codeContext.new Offset();
01631:                        this .compileBoolean(is.condition, end,
01632:                                Java.Rvalue.JUMP_IF_FALSE);
01633:                        this .compile(is.thenStatement);
01634:                        end.set();
01635:                        return true;
01636:                    }
01637:                } else {
01638:                    if (this .generatesCode(es)) {
01639:
01640:                        // if (expr) ; else stmt
01641:                        CodeContext.Offset end = this .codeContext.new Offset();
01642:                        this .compileBoolean(is.condition, end,
01643:                                Java.Rvalue.JUMP_IF_TRUE);
01644:                        this .compile(es);
01645:                        end.set();
01646:                        return true;
01647:                    } else {
01648:
01649:                        // if (expr) ; else ;
01650:                        IClass conditionType = this 
01651:                                .compileGetValue(is.condition);
01652:                        if (conditionType != IClass.BOOLEAN)
01653:                            this .compileError("Not a boolean expression", is
01654:                                    .getLocation());
01655:                        this .pop((Locatable) is, conditionType);
01656:                        return true;
01657:                    }
01658:                }
01659:            }
01660:
01661:            private static final RuntimeException STOP_COMPILING_CODE = new RuntimeException(
01662:                    "SNO: This exception should have been caught and processed");
01663:
01664:            private boolean compile2(Java.LocalClassDeclarationStatement lcds)
01665:                    throws CompileException {
01666:
01667:                // Check for redefinition.
01668:                Java.LocalClassDeclaration otherLCD = this 
01669:                        .findLocalClassDeclaration(lcds, lcds.lcd.name);
01670:                if (otherLCD != lcds.lcd)
01671:                    this .compileError("Redeclaration of local class \""
01672:                            + lcds.lcd.name + "\"; previously declared in "
01673:                            + otherLCD.getLocation());
01674:
01675:                this .compile(lcds.lcd);
01676:                return true;
01677:            }
01678:
01679:            /**
01680:             * Find a local class declared in any block enclosing the given block statement.
01681:             */
01682:            private Java.LocalClassDeclaration findLocalClassDeclaration(
01683:                    Java.Scope s, String name) {
01684:                for (;;) {
01685:                    Java.Scope es = s.getEnclosingScope();
01686:                    if (es instanceof  Java.CompilationUnit)
01687:                        break;
01688:                    if (s instanceof  Java.BlockStatement
01689:                            && es instanceof  Java.Block) {
01690:                        Java.BlockStatement bs = (Java.BlockStatement) s;
01691:                        Java.Block b = (Java.Block) es;
01692:                        for (Iterator it = b.statements.iterator();;) {
01693:                            Java.BlockStatement bs2 = (Java.BlockStatement) it
01694:                                    .next();
01695:                            if (bs2 instanceof  Java.LocalClassDeclarationStatement) {
01696:                                Java.LocalClassDeclarationStatement lcds = ((Java.LocalClassDeclarationStatement) bs2);
01697:                                if (lcds.lcd.name.equals(name))
01698:                                    return lcds.lcd;
01699:                            }
01700:                            if (bs2 == bs)
01701:                                break;
01702:                        }
01703:                    }
01704:                    s = es;
01705:                }
01706:                return null;
01707:            }
01708:
01709:            private boolean compile2(Java.LocalVariableDeclarationStatement lvds)
01710:                    throws CompileException {
01711:                if ((lvds.modifiers & ~Mod.FINAL) != 0)
01712:                    this 
01713:                            .compileError(
01714:                                    "The only allowed modifier in local variable declarations is \"final\"",
01715:                                    lvds.getLocation());
01716:
01717:                for (int j = 0; j < lvds.variableDeclarators.length; ++j) {
01718:                    Java.VariableDeclarator vd = lvds.variableDeclarators[j];
01719:
01720:                    Java.LocalVariable lv = this .getLocalVariable(lvds, vd);
01721:
01722:                    // Check for local variable redefinition.
01723:                    if (this .findLocalVariable((Java.BlockStatement) lvds,
01724:                            vd.name) != lv)
01725:                        this .compileError("Redefinition of local variable \""
01726:                                + vd.name + "\" ", vd.getLocation());
01727:
01728:                    lv.localVariableArrayIndex = this .codeContext
01729:                            .allocateLocalVariable(Descriptor.size(lv.type
01730:                                    .getDescriptor()));
01731:
01732:                    if (vd.optionalInitializer != null) {
01733:                        if (vd.optionalInitializer instanceof  Java.Rvalue) {
01734:                            Java.Rvalue rhs = (Java.Rvalue) vd.optionalInitializer;
01735:                            this .assignmentConversion((Locatable) lvds, // l
01736:                                    this .compileGetValue(rhs), // sourceType
01737:                                    lv.type, // targetType
01738:                                    this .getConstantValue(rhs) // optionalConstantValue
01739:                                    );
01740:                        } else if (vd.optionalInitializer instanceof  Java.ArrayInitializer) {
01741:                            this 
01742:                                    .compileGetValue(
01743:                                            (Java.ArrayInitializer) vd.optionalInitializer,
01744:                                            lv.type);
01745:                        } else {
01746:                            throw new RuntimeException(
01747:                                    "Unexpected rvalue or array initialized class "
01748:                                            + vd.optionalInitializer.getClass()
01749:                                                    .getName());
01750:                        }
01751:                        this .store((Locatable) lvds, // l
01752:                                lv.type, // valueType
01753:                                lv // localVariable
01754:                                );
01755:                    }
01756:                }
01757:                return true;
01758:            }
01759:
01760:            public Java.LocalVariable getLocalVariable(
01761:                    Java.LocalVariableDeclarationStatement lvds,
01762:                    Java.VariableDeclarator vd) throws CompileException {
01763:                if (vd.localVariable == null) {
01764:
01765:                    // Determine variable type.
01766:                    Java.Type variableType = lvds.type;
01767:                    for (int k = 0; k < vd.brackets; ++k)
01768:                        variableType = new Java.ArrayType(variableType);
01769:
01770:                    vd.localVariable = new Java.LocalVariable(
01771:                            (lvds.modifiers & Mod.FINAL) != 0, this 
01772:                                    .getType(variableType));
01773:                }
01774:                return vd.localVariable;
01775:            }
01776:
01777:            private boolean compile2(Java.ReturnStatement rs)
01778:                    throws CompileException {
01779:
01780:                // Determine enclosing block, function and compilation Unit.
01781:                Java.FunctionDeclarator enclosingFunction = null;
01782:                {
01783:                    Java.Scope s = rs.getEnclosingScope();
01784:                    for (s = s.getEnclosingScope(); s instanceof  Java.Statement
01785:                            || s instanceof  Java.CatchClause; s = s
01786:                            .getEnclosingScope())
01787:                        ;
01788:                    enclosingFunction = (Java.FunctionDeclarator) s;
01789:                }
01790:
01791:                IClass returnType = this .getReturnType(enclosingFunction);
01792:                if (returnType == IClass.VOID) {
01793:                    if (rs.optionalReturnValue != null)
01794:                        this .compileError("Method must not return a value", rs
01795:                                .getLocation());
01796:                    this .leaveStatements(rs.getEnclosingScope(), // from
01797:                            enclosingFunction, // to
01798:                            null // optionalStackValueType
01799:                            );
01800:                    this .writeOpcode(rs, Opcode.RETURN);
01801:                    return false;
01802:                }
01803:                if (rs.optionalReturnValue == null) {
01804:                    this .compileError("Method must return a value", rs
01805:                            .getLocation());
01806:                    return false;
01807:                }
01808:                IClass type = this .compileGetValue(rs.optionalReturnValue);
01809:                this .assignmentConversion((Locatable) rs, // l
01810:                        type, // sourceType
01811:                        returnType, // targetType
01812:                        this .getConstantValue(rs.optionalReturnValue) // optionalConstantValue
01813:                        );
01814:
01815:                this .leaveStatements(rs.getEnclosingScope(), // from
01816:                        enclosingFunction, // to
01817:                        returnType // optionalStackValueType
01818:                        );
01819:                this .writeOpcode(rs, Opcode.IRETURN + this .ilfda(returnType));
01820:                return false;
01821:            }
01822:
01823:            private boolean compile2(Java.SynchronizedStatement ss)
01824:                    throws CompileException {
01825:
01826:                // Evaluate monitor object expression.
01827:                if (!this .iClassLoader.OBJECT.isAssignableFrom(this 
01828:                        .compileGetValue(ss.expression)))
01829:                    this 
01830:                            .compileError(
01831:                                    "Monitor object of \"synchronized\" statement is not a subclass of \"Object\"",
01832:                                    ss.getLocation());
01833:
01834:                this .codeContext.saveLocalVariables();
01835:                boolean canCompleteNormally = false;
01836:                try {
01837:
01838:                    // Allocate a local variable for the monitor object.
01839:                    ss.monitorLvIndex = this .codeContext
01840:                            .allocateLocalVariable((short) 1);
01841:
01842:                    // Store the monitor object.
01843:                    this .writeOpcode(ss, Opcode.DUP);
01844:                    this .store((Locatable) ss, this .iClassLoader.OBJECT,
01845:                            ss.monitorLvIndex);
01846:
01847:                    // Create lock on the monitor object.
01848:                    this .writeOpcode(ss, Opcode.MONITORENTER);
01849:
01850:                    // Compile the statement body.
01851:                    CodeContext.Offset monitorExitOffset = this .codeContext.new Offset();
01852:                    CodeContext.Offset beginningOfBody = this .codeContext
01853:                            .newOffset();
01854:                    canCompleteNormally = this .compile(ss.body);
01855:                    if (canCompleteNormally) {
01856:                        this .writeBranch(ss, Opcode.GOTO, monitorExitOffset);
01857:                    }
01858:
01859:                    // Generate the exception handler.
01860:                    CodeContext.Offset here = this .codeContext.newOffset();
01861:                    this .codeContext.addExceptionTableEntry(beginningOfBody, // startPC
01862:                            here, // endPC
01863:                            here, // handlerPC
01864:                            null // catchTypeFD
01865:                            );
01866:                    this .leave(ss, this .iClassLoader.THROWABLE);
01867:                    this .writeOpcode(ss, Opcode.ATHROW);
01868:
01869:                    // Unlock monitor object.
01870:                    if (canCompleteNormally) {
01871:                        monitorExitOffset.set();
01872:                        this .leave(ss, null);
01873:                    }
01874:                } finally {
01875:                    this .codeContext.restoreLocalVariables();
01876:                }
01877:
01878:                return canCompleteNormally;
01879:            }
01880:
01881:            private boolean compile2(Java.ThrowStatement ts)
01882:                    throws CompileException {
01883:                IClass expressionType = this .compileGetValue(ts.expression);
01884:                this .checkThrownException((Locatable) ts, // l
01885:                        expressionType, // type
01886:                        ts.getEnclosingScope() // scope
01887:                        );
01888:                this .writeOpcode(ts, Opcode.ATHROW);
01889:                return false;
01890:            }
01891:
01892:            private boolean compile2(Java.TryStatement ts)
01893:                    throws CompileException {
01894:                if (ts.optionalFinally != null)
01895:                    ts.finallyOffset = this .codeContext.new Offset();
01896:
01897:                CodeContext.Offset beginningOfBody = this .codeContext
01898:                        .newOffset();
01899:                CodeContext.Offset afterStatement = this .codeContext.new Offset();
01900:
01901:                this .codeContext.saveLocalVariables();
01902:                try {
01903:
01904:                    // Allocate a LV for the JSR of the FINALLY clause.
01905:                    //
01906:                    // Notice:
01907:                    //   For unclear reasons, this variable must not overlap with any of the body's
01908:                    //   variables (although the body's variables are out of scope when it comes to the
01909:                    //   FINALLY clause!?), otherwise you get
01910:                    //     java.lang.VerifyError: ... Accessing value from uninitialized localvariable 4
01911:                    //   See bug #56.
01912:                    short pcLVIndex = ts.optionalFinally != null ? this .codeContext
01913:                            .allocateLocalVariable((short) 1)
01914:                            : (short) 0;
01915:
01916:                    boolean canCompleteNormally = this .compile(ts.body);
01917:                    CodeContext.Offset afterBody = this .codeContext.newOffset();
01918:                    if (canCompleteNormally) {
01919:                        this .writeBranch(ts, Opcode.GOTO, afterStatement);
01920:                    }
01921:
01922:                    if (beginningOfBody.offset != afterBody.offset) { // Avoid zero-length exception table entries.
01923:                        this .codeContext.saveLocalVariables();
01924:                        try {
01925:
01926:                            // Allocate the "exception variable".
01927:                            short evi = this .codeContext
01928:                                    .allocateLocalVariable((short) 1);
01929:
01930:                            for (int i = 0; i < ts.catchClauses.size(); ++i) {
01931:                                Java.CatchClause cc = (Java.CatchClause) ts.catchClauses
01932:                                        .get(i);
01933:                                IClass caughtExceptionType = this 
01934:                                        .getType(cc.caughtException.type);
01935:                                this .codeContext.addExceptionTableEntry(
01936:                                        beginningOfBody, // startPC
01937:                                        afterBody, // endPC
01938:                                        this .codeContext.newOffset(), // handlerPC
01939:                                        caughtExceptionType.getDescriptor() // catchTypeFD
01940:                                        );
01941:                                this .store((Locatable) cc, // l
01942:                                        caughtExceptionType, // lvType
01943:                                        evi // lvIndex
01944:                                        );
01945:
01946:                                // Kludge: Treat the exception variable like a local
01947:                                // variable of the catch clause body.
01948:                                UnitCompiler.this 
01949:                                        .getLocalVariable(cc.caughtException).localVariableArrayIndex = evi;
01950:
01951:                                if (this .compile(cc.body)) {
01952:                                    canCompleteNormally = true;
01953:                                    if (i < ts.catchClauses.size() - 1
01954:                                            || ts.optionalFinally != null)
01955:                                        this .writeBranch(cc, Opcode.GOTO,
01956:                                                afterStatement);
01957:                                }
01958:                            }
01959:                        } finally {
01960:                            this .codeContext.restoreLocalVariables();
01961:                        }
01962:                    }
01963:
01964:                    if (ts.optionalFinally != null) {
01965:                        CodeContext.Offset here = this .codeContext.newOffset();
01966:                        this .codeContext.addExceptionTableEntry(
01967:                                beginningOfBody, // startPC
01968:                                here, // endPC
01969:                                here, // handlerPC
01970:                                null // catchTypeFD
01971:                                );
01972:
01973:                        this .codeContext.saveLocalVariables();
01974:                        try {
01975:
01976:                            // Save the exception object in an anonymous local variable.
01977:                            short evi = this .codeContext
01978:                                    .allocateLocalVariable((short) 1);
01979:                            this .store((Locatable) ts.optionalFinally, // l
01980:                                    this .iClassLoader.OBJECT, // valueType
01981:                                    evi // localVariableIndex
01982:                                    );
01983:                            this .writeBranch(ts.optionalFinally, Opcode.JSR,
01984:                                    ts.finallyOffset);
01985:                            this .load((Locatable) ts.optionalFinally, // l
01986:                                    this .iClassLoader.OBJECT, // valueType
01987:                                    evi // localVariableIndex
01988:                                    );
01989:                            this .writeOpcode(ts.optionalFinally, Opcode.ATHROW);
01990:
01991:                            // Compile the "finally" body.
01992:                            ts.finallyOffset.set();
01993:                            this .store((Locatable) ts.optionalFinally, // l
01994:                                    this .iClassLoader.OBJECT, // valueType
01995:                                    pcLVIndex // localVariableIndex
01996:                                    );
01997:                            if (this .compile(ts.optionalFinally)) {
01998:                                this 
01999:                                        .writeOpcode(ts.optionalFinally,
02000:                                                Opcode.RET);
02001:                                this .writeByte(pcLVIndex);
02002:                            }
02003:                        } finally {
02004:
02005:                            // The exception object local variable allocated above MUST NOT BE RELEASED
02006:                            // until after the FINALLY block is compiled, for otherwise you get
02007:                            //   java.lang.VerifyError: ... Accessing value from uninitialized register 7
02008:                            this .codeContext.restoreLocalVariables();
02009:                        }
02010:                    }
02011:
02012:                    afterStatement.set();
02013:                    if (canCompleteNormally)
02014:                        this .leave(ts, null);
02015:                    return canCompleteNormally;
02016:                } finally {
02017:                    this .codeContext.restoreLocalVariables();
02018:                }
02019:            }
02020:
02021:            // ------------ FunctionDeclarator.compile() -------------
02022:
02023:            private void compile(Java.FunctionDeclarator fd,
02024:                    final ClassFile classFile) throws CompileException {
02025:                ClassFile.MethodInfo mi;
02026:
02027:                if (Mod.isPrivateAccess(fd.modifiers)) {
02028:                    if (fd instanceof  Java.MethodDeclarator && !fd.isStatic()) {
02029:
02030:                        // To make the non-static private method invocable for enclosing types, enclosed types
02031:                        // and types enclosed by the same type, it is modified as follows:
02032:                        //  + Access is changed from PRIVATE to PACKAGE
02033:                        //  + The name is appended with "$"
02034:                        //  + It is made static
02035:                        //  + A parameter of type "declaring class" is prepended to the signature
02036:                        mi = classFile.addMethodInfo((short) (Mod.changeAccess(
02037:                                fd.modifiers, Mod.PACKAGE) | Mod.STATIC), // accessFlags
02038:                                fd.name + '$', // name
02039:                                MethodDescriptor.prependParameter( // methodMD
02040:                                        this .toIMethod(
02041:                                                (Java.MethodDeclarator) fd)
02042:                                                .getDescriptor(), this .resolve(
02043:                                                fd.getDeclaringType())
02044:                                                .getDescriptor()));
02045:                    } else {
02046:
02047:                        // To make the static private method or private constructor invocable for enclosing
02048:                        // types, enclosed types and types enclosed by the same type, it is modified as
02049:                        // follows:
02050:                        //  + Access is changed from PRIVATE to PACKAGE
02051:                        mi = classFile.addMethodInfo(Mod.changeAccess(
02052:                                fd.modifiers, Mod.PACKAGE), // accessFlags
02053:                                fd.name, // name
02054:                                this .toIInvocable(fd).getDescriptor() // methodMD
02055:                                );
02056:                    }
02057:                } else {
02058:                    mi = classFile.addMethodInfo(fd.modifiers, // accessFlags
02059:                            fd.name, // name
02060:                            this .toIInvocable(fd).getDescriptor() // methodMD
02061:                            );
02062:                }
02063:
02064:                // Add "Exceptions" attribute (JVMS 4.7.4).
02065:                {
02066:                    final short eani = classFile
02067:                            .addConstantUtf8Info("Exceptions");
02068:                    short[] tecciis = new short[fd.thrownExceptions.length];
02069:                    for (int i = 0; i < fd.thrownExceptions.length; ++i) {
02070:                        tecciis[i] = classFile.addConstantClassInfo(this 
02071:                                .getType(fd.thrownExceptions[i])
02072:                                .getDescriptor());
02073:                    }
02074:                    mi.addAttribute(new ClassFile.ExceptionsAttribute(eani,
02075:                            tecciis));
02076:                }
02077:
02078:                // Add "Deprecated" attribute (JVMS 4.7.10)
02079:                if (fd.hasDeprecatedDocTag()) {
02080:                    mi.addAttribute(new ClassFile.DeprecatedAttribute(classFile
02081:                            .addConstantUtf8Info("Deprecated")));
02082:                }
02083:
02084:                if ((fd.modifiers & (Mod.ABSTRACT | Mod.NATIVE)) != 0)
02085:                    return;
02086:
02087:                // Create CodeContext.
02088:                final CodeContext codeContext = new CodeContext(mi
02089:                        .getClassFile());
02090:
02091:                CodeContext savedCodeContext = this 
02092:                        .replaceCodeContext(codeContext);
02093:                try {
02094:
02095:                    // Define special parameter "this".
02096:                    if ((fd.modifiers & Mod.STATIC) == 0) {
02097:                        this .codeContext.allocateLocalVariable((short) 1);
02098:                    }
02099:
02100:                    if (fd instanceof  Java.ConstructorDeclarator) {
02101:                        Java.ConstructorDeclarator constructorDeclarator = (Java.ConstructorDeclarator) fd;
02102:
02103:                        // Reserve space for synthetic parameters ("this$...", "val$...").
02104:                        for (Iterator it = constructorDeclarator
02105:                                .getDeclaringClass().syntheticFields.values()
02106:                                .iterator(); it.hasNext();) {
02107:                            IClass.IField sf = (IClass.IField) it.next();
02108:                            Java.LocalVariable lv = new Java.LocalVariable(
02109:                                    true, sf.getType());
02110:                            lv.localVariableArrayIndex = this .codeContext
02111:                                    .allocateLocalVariable(Descriptor.size(sf
02112:                                            .getDescriptor()));
02113:                            constructorDeclarator.syntheticParameters.put(sf
02114:                                    .getName(), lv);
02115:                        }
02116:                    }
02117:
02118:                    // Add function parameters.
02119:                    Set usedParameterNames = new HashSet();
02120:                    for (int i = 0; i < fd.formalParameters.length; ++i) {
02121:                        Java.FunctionDeclarator.FormalParameter fp = fd.formalParameters[i];
02122:                        if (usedParameterNames.contains(fp.name))
02123:                            this .compileError(
02124:                                    "Redefinition of formal parameter \""
02125:                                            + fp.name + "\"", fd.getLocation());
02126:                        Java.LocalVariable lv = UnitCompiler.this 
02127:                                .getLocalVariable(fp);
02128:                        lv.localVariableArrayIndex = this .codeContext
02129:                                .allocateLocalVariable(Descriptor.size(lv.type
02130:                                        .getDescriptor()));
02131:                        usedParameterNames.add(fp.name);
02132:                    }
02133:
02134:                    // Compile the constructor preamble.
02135:                    if (fd instanceof  Java.ConstructorDeclarator) {
02136:                        Java.ConstructorDeclarator cd = (Java.ConstructorDeclarator) fd;
02137:                        if (cd.optionalConstructorInvocation != null) {
02138:                            this .compile(cd.optionalConstructorInvocation);
02139:                            if (cd.optionalConstructorInvocation instanceof  Java.SuperConstructorInvocation) {
02140:                                this 
02141:                                        .assignSyntheticParametersToSyntheticFields(cd);
02142:                                this 
02143:                                        .initializeInstanceVariablesAndInvokeInstanceInitializers(cd);
02144:                            }
02145:                        } else {
02146:
02147:                            // Determine qualification for superconstructor invocation.
02148:                            Java.QualifiedThisReference qualification = null;
02149:                            IClass outerClassOfSuperclass = this .resolve(
02150:                                    cd.getDeclaringClass()).getSuperclass()
02151:                                    .getOuterIClass();
02152:                            if (outerClassOfSuperclass != null) {
02153:                                //                        qualification = new Java.QualifiedThisReference(
02154:                                //                            cd.getLocation(),        // location
02155:                                //                            cd.getDeclaringClass(),  // declaringClass
02156:                                //                            cd,                      // declaringTypeBodyDeclaration
02157:                                //                            outerClassOfSuperclass   // targetIClass
02158:                                //                        );
02159:                                qualification = new Java.QualifiedThisReference(
02160:                                        cd.getLocation(), // location
02161:                                        new Java.SimpleType(
02162:                                                // qualification
02163:                                                cd.getLocation(),
02164:                                                outerClassOfSuperclass));
02165:                            }
02166:
02167:                            // Invoke the superconstructor.
02168:                            Java.SuperConstructorInvocation sci = new Java.SuperConstructorInvocation(
02169:                                    cd.getLocation(), // location
02170:                                    qualification, // optionalQualification
02171:                                    new Java.Rvalue[0] // arguments
02172:                            );
02173:                            sci.setEnclosingScope(fd);
02174:                            this .compile(sci);
02175:                            this .assignSyntheticParametersToSyntheticFields(cd);
02176:                            this 
02177:                                    .initializeInstanceVariablesAndInvokeInstanceInitializers(cd);
02178:                        }
02179:                    }
02180:
02181:                    // Compile the function body.
02182:                    try {
02183:                        boolean canCompleteNormally = this 
02184:                                .compile(fd.optionalBody);
02185:                        if (canCompleteNormally) {
02186:                            if (this .getReturnType(fd) != IClass.VOID)
02187:                                this .compileError("Method must return a value",
02188:                                        fd.getLocation());
02189:                            this .writeOpcode(fd, Opcode.RETURN);
02190:                        }
02191:                    } catch (RuntimeException ex) {
02192:                        if (ex != UnitCompiler.STOP_COMPILING_CODE)
02193:                            throw ex;
02194:
02195:                        // In very special circumstances (e.g. "if (true) return;"), code generation is
02196:                        // terminated abruptly by throwing STOP_COMPILING_CODE.
02197:                        ;
02198:                    }
02199:                } finally {
02200:                    this .replaceCodeContext(savedCodeContext);
02201:                }
02202:
02203:                // Don't continue code attribute generation if we had compile errors.
02204:                if (this .compileErrorCount > 0)
02205:                    return;
02206:
02207:                // Fix up.
02208:                codeContext.fixUp();
02209:
02210:                // Relocate.
02211:                codeContext.relocate();
02212:
02213:                // Do flow analysis.
02214:                if (UnitCompiler.DEBUG) {
02215:                    try {
02216:                        codeContext.flowAnalysis(fd.toString());
02217:                    } catch (RuntimeException ex) {
02218:                        ex.printStackTrace();
02219:                        ;
02220:                    }
02221:                } else {
02222:                    codeContext.flowAnalysis(fd.toString());
02223:                }
02224:
02225:                // Add the code context as a code attribute to the MethodInfo.
02226:                final short lntani = (this .debuggingInformation
02227:                        .contains(DebuggingInformation.LINES) ? classFile
02228:                        .addConstantUtf8Info("LineNumberTable") : (short) 0);
02229:                mi.addAttribute(new ClassFile.AttributeInfo(classFile
02230:                        .addConstantUtf8Info("Code")) {
02231:                    protected void storeBody(DataOutputStream dos)
02232:                            throws IOException {
02233:                        codeContext.storeCodeAttributeBody(dos, lntani);
02234:                    }
02235:                });
02236:            }
02237:
02238:            public Java.LocalVariable getLocalVariable(
02239:                    Java.FunctionDeclarator.FormalParameter fp)
02240:                    throws CompileException {
02241:                if (fp.localVariable == null) {
02242:                    fp.localVariable = new Java.LocalVariable(fp.finaL, this 
02243:                            .getType(fp.type));
02244:                }
02245:                return fp.localVariable;
02246:            }
02247:
02248:            // ------------------ Rvalue.compile() ----------------
02249:
02250:            /**
02251:             * Call to check whether the given {@link Java.Rvalue} compiles or not.
02252:             */
02253:            private void fakeCompile(Java.Rvalue rv) throws CompileException {
02254:                CodeContext savedCodeContext = this .replaceCodeContext(this 
02255:                        .createDummyCodeContext());
02256:                try {
02257:                    this .compileContext(rv);
02258:                    this .compileGet(rv);
02259:                } finally {
02260:                    this .replaceCodeContext(savedCodeContext);
02261:                }
02262:            }
02263:
02264:            /**
02265:             * Some {@link Java.Rvalue}s compile more efficiently when their value
02266:             * is not needed, e.g. "i++".
02267:             */
02268:            private void compile(Java.Rvalue rv) throws CompileException {
02269:                class UCE extends RuntimeException {
02270:                    final CompileException ce;
02271:
02272:                    UCE(CompileException ce) {
02273:                        this .ce = ce;
02274:                    }
02275:                }
02276:                Visitor.RvalueVisitor rvv = new Visitor.RvalueVisitor() {
02277:                    public void visitArrayLength(Java.ArrayLength al) {
02278:                        try {
02279:                            UnitCompiler.this .compile2(al);
02280:                        } catch (CompileException e) {
02281:                            throw new UCE(e);
02282:                        }
02283:                    }
02284:
02285:                    public void visitAssignment(Java.Assignment a) {
02286:                        try {
02287:                            UnitCompiler.this .compile2(a);
02288:                        } catch (CompileException e) {
02289:                            throw new UCE(e);
02290:                        }
02291:                    }
02292:
02293:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
02294:                        try {
02295:                            UnitCompiler.this .compile2(uo);
02296:                        } catch (CompileException e) {
02297:                            throw new UCE(e);
02298:                        }
02299:                    }
02300:
02301:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
02302:                        try {
02303:                            UnitCompiler.this .compile2(bo);
02304:                        } catch (CompileException e) {
02305:                            throw new UCE(e);
02306:                        }
02307:                    }
02308:
02309:                    public void visitCast(Java.Cast c) {
02310:                        try {
02311:                            UnitCompiler.this .compile2(c);
02312:                        } catch (CompileException e) {
02313:                            throw new UCE(e);
02314:                        }
02315:                    }
02316:
02317:                    public void visitClassLiteral(Java.ClassLiteral cl) {
02318:                        try {
02319:                            UnitCompiler.this .compile2(cl);
02320:                        } catch (CompileException e) {
02321:                            throw new UCE(e);
02322:                        }
02323:                    }
02324:
02325:                    public void visitConditionalExpression(
02326:                            Java.ConditionalExpression ce) {
02327:                        try {
02328:                            UnitCompiler.this .compile2(ce);
02329:                        } catch (CompileException e) {
02330:                            throw new UCE(e);
02331:                        }
02332:                    }
02333:
02334:                    public void visitConstantValue(Java.ConstantValue cv) {
02335:                        try {
02336:                            UnitCompiler.this .compile2(cv);
02337:                        } catch (CompileException e) {
02338:                            throw new UCE(e);
02339:                        }
02340:                    }
02341:
02342:                    public void visitCrement(Java.Crement c) {
02343:                        try {
02344:                            UnitCompiler.this .compile2(c);
02345:                        } catch (CompileException e) {
02346:                            throw new UCE(e);
02347:                        }
02348:                    }
02349:
02350:                    public void visitInstanceof(Java.Instanceof io) {
02351:                        try {
02352:                            UnitCompiler.this .compile2(io);
02353:                        } catch (CompileException e) {
02354:                            throw new UCE(e);
02355:                        }
02356:                    }
02357:
02358:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
02359:                        try {
02360:                            UnitCompiler.this .compile2(mi);
02361:                        } catch (CompileException e) {
02362:                            throw new UCE(e);
02363:                        }
02364:                    }
02365:
02366:                    public void visitSuperclassMethodInvocation(
02367:                            Java.SuperclassMethodInvocation smi) {
02368:                        try {
02369:                            UnitCompiler.this .compile2(smi);
02370:                        } catch (CompileException e) {
02371:                            throw new UCE(e);
02372:                        }
02373:                    }
02374:
02375:                    public void visitLiteral(Java.Literal l) {
02376:                        try {
02377:                            UnitCompiler.this .compile2(l);
02378:                        } catch (CompileException e) {
02379:                            throw new UCE(e);
02380:                        }
02381:                    }
02382:
02383:                    public void visitNewAnonymousClassInstance(
02384:                            Java.NewAnonymousClassInstance naci) {
02385:                        try {
02386:                            UnitCompiler.this .compile2(naci);
02387:                        } catch (CompileException e) {
02388:                            throw new UCE(e);
02389:                        }
02390:                    }
02391:
02392:                    public void visitNewArray(Java.NewArray na) {
02393:                        try {
02394:                            UnitCompiler.this .compile2(na);
02395:                        } catch (CompileException e) {
02396:                            throw new UCE(e);
02397:                        }
02398:                    }
02399:
02400:                    public void visitNewInitializedArray(
02401:                            Java.NewInitializedArray nia) {
02402:                        try {
02403:                            UnitCompiler.this .compile2(nia);
02404:                        } catch (CompileException e) {
02405:                            throw new UCE(e);
02406:                        }
02407:                    }
02408:
02409:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
02410:                        try {
02411:                            UnitCompiler.this .compile2(nci);
02412:                        } catch (CompileException e) {
02413:                            throw new UCE(e);
02414:                        }
02415:                    }
02416:
02417:                    public void visitParameterAccess(Java.ParameterAccess pa) {
02418:                        try {
02419:                            UnitCompiler.this .compile2(pa);
02420:                        } catch (CompileException e) {
02421:                            throw new UCE(e);
02422:                        }
02423:                    }
02424:
02425:                    public void visitQualifiedThisReference(
02426:                            Java.QualifiedThisReference qtr) {
02427:                        try {
02428:                            UnitCompiler.this .compile2(qtr);
02429:                        } catch (CompileException e) {
02430:                            throw new UCE(e);
02431:                        }
02432:                    }
02433:
02434:                    public void visitThisReference(Java.ThisReference tr) {
02435:                        try {
02436:                            UnitCompiler.this .compile2(tr);
02437:                        } catch (CompileException e) {
02438:                            throw new UCE(e);
02439:                        }
02440:                    }
02441:
02442:                    public void visitAmbiguousName(Java.AmbiguousName an) {
02443:                        try {
02444:                            UnitCompiler.this .compile2(an);
02445:                        } catch (CompileException e) {
02446:                            throw new UCE(e);
02447:                        }
02448:                    }
02449:
02450:                    public void visitArrayAccessExpression(
02451:                            Java.ArrayAccessExpression aae) {
02452:                        try {
02453:                            UnitCompiler.this .compile2(aae);
02454:                        } catch (CompileException e) {
02455:                            throw new UCE(e);
02456:                        }
02457:                    };
02458:
02459:                    public void visitFieldAccess(Java.FieldAccess fa) {
02460:                        try {
02461:                            UnitCompiler.this .compile2(fa);
02462:                        } catch (CompileException e) {
02463:                            throw new UCE(e);
02464:                        }
02465:                    }
02466:
02467:                    public void visitFieldAccessExpression(
02468:                            Java.FieldAccessExpression fae) {
02469:                        try {
02470:                            UnitCompiler.this .compile2(fae);
02471:                        } catch (CompileException e) {
02472:                            throw new UCE(e);
02473:                        }
02474:                    }
02475:
02476:                    public void visitSuperclassFieldAccessExpression(
02477:                            SuperclassFieldAccessExpression scfae) {
02478:                        try {
02479:                            UnitCompiler.this .compile2(scfae);
02480:                        } catch (CompileException e) {
02481:                            throw new UCE(e);
02482:                        }
02483:                    }
02484:
02485:                    public void visitLocalVariableAccess(
02486:                            Java.LocalVariableAccess lva) {
02487:                        try {
02488:                            UnitCompiler.this .compile2(lva);
02489:                        } catch (CompileException e) {
02490:                            throw new UCE(e);
02491:                        }
02492:                    }
02493:
02494:                    public void visitParenthesizedExpression(
02495:                            Java.ParenthesizedExpression pe) {
02496:                        try {
02497:                            UnitCompiler.this .compile2(pe);
02498:                        } catch (CompileException e) {
02499:                            throw new UCE(e);
02500:                        }
02501:                    }
02502:                };
02503:                try {
02504:                    rv.accept(rvv);
02505:                } catch (UCE uce) {
02506:                    throw uce.ce;
02507:                }
02508:            }
02509:
02510:            private void compile2(Java.Rvalue rv) throws CompileException {
02511:                this .pop((Locatable) rv, this .compileGetValue(rv));
02512:            }
02513:
02514:            private void compile2(Java.Assignment a) throws CompileException {
02515:                if (a.operator == "=") {
02516:                    this .compileContext(a.lhs);
02517:                    this .assignmentConversion((Locatable) a, // l
02518:                            this .compileGetValue(a.rhs), // sourceType
02519:                            this .getType(a.lhs), // targetType
02520:                            this .getConstantValue(a.rhs) // optionalConstantValue
02521:                            );
02522:                    this .compileSet(a.lhs);
02523:                    return;
02524:                }
02525:
02526:                // Implement "|= ^= &= *= /= %= += -= <<= >>= >>>=".
02527:                int lhsCS = this .compileContext(a.lhs);
02528:                this .dup((Locatable) a, lhsCS);
02529:                IClass lhsType = this .compileGet(a.lhs);
02530:                IClass resultType = this .compileArithmeticBinaryOperation(
02531:                        (Locatable) a, // l
02532:                        lhsType, // lhsType
02533:                        a.operator.substring( // operator
02534:                                0, a.operator.length() - 1).intern(), // <= IMPORTANT!
02535:                        a.rhs // rhs
02536:                        );
02537:                // Convert the result to LHS type (JLS2 15.26.2).
02538:                if (!this .tryIdentityConversion(resultType, lhsType)
02539:                        && !this .tryNarrowingPrimitiveConversion((Locatable) a, // l
02540:                                resultType, // sourceType
02541:                                lhsType // destinationType
02542:                                ))
02543:                    throw new RuntimeException("SNO: \"" + a.operator
02544:                            + "\" reconversion failed");
02545:                this .compileSet(a.lhs);
02546:            }
02547:
02548:            private void compile2(Java.Crement c) throws CompileException {
02549:
02550:                // Optimized crement of integer local variable.
02551:                Java.LocalVariable lv = this .isIntLV(c);
02552:                if (lv != null) {
02553:                    this .writeOpcode(c, Opcode.IINC);
02554:                    this .writeByte(lv.localVariableArrayIndex);
02555:                    this .writeByte(c.operator == "++" ? 1 : -1);
02556:                    return;
02557:                }
02558:
02559:                int cs = this .compileContext(c.operand);
02560:                this .dup((Locatable) c, cs);
02561:                IClass type = this .compileGet(c.operand);
02562:                IClass promotedType = this .unaryNumericPromotion((Locatable) c,
02563:                        type);
02564:                this .writeOpcode(c, UnitCompiler.ilfd(promotedType,
02565:                        Opcode.ICONST_1, Opcode.LCONST_1, Opcode.FCONST_1,
02566:                        Opcode.DCONST_1));
02567:                if (c.operator == "++") {
02568:                    this .writeOpcode(c, Opcode.IADD
02569:                            + UnitCompiler.ilfd(promotedType));
02570:                } else if (c.operator == "--") {
02571:                    this .writeOpcode(c, Opcode.ISUB
02572:                            + UnitCompiler.ilfd(promotedType));
02573:                } else {
02574:                    this .compileError("Unexpected operator \"" + c.operator
02575:                            + "\"", c.getLocation());
02576:                }
02577:
02578:                this .reverseUnaryNumericPromotion((Locatable) c, promotedType,
02579:                        type);
02580:                this .compileSet(c.operand);
02581:            }
02582:
02583:            private void compile2(Java.ParenthesizedExpression pe)
02584:                    throws CompileException {
02585:                this .compile(pe.value);
02586:            }
02587:
02588:            private boolean compile2(Java.AlternateConstructorInvocation aci)
02589:                    throws CompileException {
02590:                Java.ConstructorDeclarator declaringConstructor = (Java.ConstructorDeclarator) aci
02591:                        .getEnclosingScope();
02592:                IClass declaringIClass = this .resolve(declaringConstructor
02593:                        .getDeclaringClass());
02594:
02595:                this .writeOpcode(aci, Opcode.ALOAD_0);
02596:                if (declaringIClass.getOuterIClass() != null)
02597:                    this .writeOpcode(aci, Opcode.ALOAD_1);
02598:                this .invokeConstructor((Locatable) aci, // l
02599:                        (Java.Scope) declaringConstructor, // scope
02600:                        (Java.Rvalue) null, // optionalEnclosingInstance
02601:                        declaringIClass, // targetClass
02602:                        aci.arguments // arguments
02603:                        );
02604:                return true;
02605:            }
02606:
02607:            private boolean compile2(Java.SuperConstructorInvocation sci)
02608:                    throws CompileException {
02609:                Java.ConstructorDeclarator declaringConstructor = (Java.ConstructorDeclarator) sci
02610:                        .getEnclosingScope();
02611:                this .writeOpcode(sci, Opcode.ALOAD_0);
02612:                Java.ClassDeclaration declaringClass = declaringConstructor
02613:                        .getDeclaringClass();
02614:                IClass super class = this .resolve(declaringClass)
02615:                        .getSuperclass();
02616:
02617:                Java.Rvalue optionalEnclosingInstance;
02618:                if (sci.optionalQualification != null) {
02619:                    optionalEnclosingInstance = sci.optionalQualification;
02620:                } else {
02621:                    IClass outerIClassOfSuperclass = super class
02622:                            .getOuterIClass();
02623:                    if (outerIClassOfSuperclass == null) {
02624:                        optionalEnclosingInstance = null;
02625:                    } else {
02626:                        //                optionalEnclosingInstance = new Java.QualifiedThisReference(
02627:                        //                    sci.getLocation(),      // location
02628:                        //                    declaringClass,         // declaringClass
02629:                        //                    declaringConstructor,   // declaringTypeBodyDeclaration
02630:                        //                    outerIClassOfSuperclass // targetClass
02631:                        //                );
02632:                        optionalEnclosingInstance = new Java.QualifiedThisReference(
02633:                                sci.getLocation(), // location
02634:                                new Java.SimpleType(
02635:                                        // qualification
02636:                                        sci.getLocation(),
02637:                                        outerIClassOfSuperclass));
02638:                        optionalEnclosingInstance
02639:                                .setEnclosingBlockStatement(sci);
02640:                    }
02641:                }
02642:                this .invokeConstructor((Locatable) sci, // l
02643:                        (Java.Scope) declaringConstructor, // scope
02644:                        optionalEnclosingInstance, // optionalEnclosingInstance
02645:                        super class, // targetClass
02646:                        sci.arguments // arguments
02647:                        );
02648:                return true;
02649:            }
02650:
02651:            /**
02652:             * Some {@link Java.Rvalue}s compile more efficiently when their value is the
02653:             * condition for a branch.<br>
02654:             *
02655:             * Notice that if "this" is a constant, then either "dst" is never
02656:             * branched to, or it is unconditionally branched to. "Unexamined code"
02657:             * errors may result during bytecode validation.
02658:             */
02659:            private void compileBoolean(Java.Rvalue rv,
02660:                    final CodeContext.Offset dst, // Where to jump.
02661:                    final boolean orientation // JUMP_IF_TRUE or JUMP_IF_FALSE.
02662:            ) throws CompileException {
02663:                class UCE extends RuntimeException {
02664:                    final CompileException ce;
02665:
02666:                    UCE(CompileException ce) {
02667:                        this .ce = ce;
02668:                    }
02669:                }
02670:                Visitor.RvalueVisitor rvv = new Visitor.RvalueVisitor() {
02671:                    public void visitArrayLength(Java.ArrayLength al) {
02672:                        try {
02673:                            UnitCompiler.this .compileBoolean2(al, dst,
02674:                                    orientation);
02675:                        } catch (CompileException e) {
02676:                            throw new UCE(e);
02677:                        }
02678:                    }
02679:
02680:                    public void visitAssignment(Java.Assignment a) {
02681:                        try {
02682:                            UnitCompiler.this .compileBoolean2(a, dst,
02683:                                    orientation);
02684:                        } catch (CompileException e) {
02685:                            throw new UCE(e);
02686:                        }
02687:                    }
02688:
02689:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
02690:                        try {
02691:                            UnitCompiler.this .compileBoolean2(uo, dst,
02692:                                    orientation);
02693:                        } catch (CompileException e) {
02694:                            throw new UCE(e);
02695:                        }
02696:                    }
02697:
02698:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
02699:                        try {
02700:                            UnitCompiler.this .compileBoolean2(bo, dst,
02701:                                    orientation);
02702:                        } catch (CompileException e) {
02703:                            throw new UCE(e);
02704:                        }
02705:                    }
02706:
02707:                    public void visitCast(Java.Cast c) {
02708:                        try {
02709:                            UnitCompiler.this .compileBoolean2(c, dst,
02710:                                    orientation);
02711:                        } catch (CompileException e) {
02712:                            throw new UCE(e);
02713:                        }
02714:                    }
02715:
02716:                    public void visitClassLiteral(Java.ClassLiteral cl) {
02717:                        try {
02718:                            UnitCompiler.this .compileBoolean2(cl, dst,
02719:                                    orientation);
02720:                        } catch (CompileException e) {
02721:                            throw new UCE(e);
02722:                        }
02723:                    }
02724:
02725:                    public void visitConditionalExpression(
02726:                            Java.ConditionalExpression ce) {
02727:                        try {
02728:                            UnitCompiler.this .compileBoolean2(ce, dst,
02729:                                    orientation);
02730:                        } catch (CompileException e) {
02731:                            throw new UCE(e);
02732:                        }
02733:                    }
02734:
02735:                    public void visitConstantValue(Java.ConstantValue cv) {
02736:                        try {
02737:                            UnitCompiler.this .compileBoolean2(cv, dst,
02738:                                    orientation);
02739:                        } catch (CompileException e) {
02740:                            throw new UCE(e);
02741:                        }
02742:                    }
02743:
02744:                    public void visitCrement(Java.Crement c) {
02745:                        try {
02746:                            UnitCompiler.this .compileBoolean2(c, dst,
02747:                                    orientation);
02748:                        } catch (CompileException e) {
02749:                            throw new UCE(e);
02750:                        }
02751:                    }
02752:
02753:                    public void visitInstanceof(Java.Instanceof io) {
02754:                        try {
02755:                            UnitCompiler.this .compileBoolean2(io, dst,
02756:                                    orientation);
02757:                        } catch (CompileException e) {
02758:                            throw new UCE(e);
02759:                        }
02760:                    }
02761:
02762:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
02763:                        try {
02764:                            UnitCompiler.this .compileBoolean2(mi, dst,
02765:                                    orientation);
02766:                        } catch (CompileException e) {
02767:                            throw new UCE(e);
02768:                        }
02769:                    }
02770:
02771:                    public void visitSuperclassMethodInvocation(
02772:                            Java.SuperclassMethodInvocation smi) {
02773:                        try {
02774:                            UnitCompiler.this .compileBoolean2(smi, dst,
02775:                                    orientation);
02776:                        } catch (CompileException e) {
02777:                            throw new UCE(e);
02778:                        }
02779:                    }
02780:
02781:                    public void visitLiteral(Java.Literal l) {
02782:                        try {
02783:                            UnitCompiler.this .compileBoolean2(l, dst,
02784:                                    orientation);
02785:                        } catch (CompileException e) {
02786:                            throw new UCE(e);
02787:                        }
02788:                    }
02789:
02790:                    public void visitNewAnonymousClassInstance(
02791:                            Java.NewAnonymousClassInstance naci) {
02792:                        try {
02793:                            UnitCompiler.this .compileBoolean2(naci, dst,
02794:                                    orientation);
02795:                        } catch (CompileException e) {
02796:                            throw new UCE(e);
02797:                        }
02798:                    }
02799:
02800:                    public void visitNewArray(Java.NewArray na) {
02801:                        try {
02802:                            UnitCompiler.this .compileBoolean2(na, dst,
02803:                                    orientation);
02804:                        } catch (CompileException e) {
02805:                            throw new UCE(e);
02806:                        }
02807:                    }
02808:
02809:                    public void visitNewInitializedArray(
02810:                            Java.NewInitializedArray nia) {
02811:                        try {
02812:                            UnitCompiler.this .compileBoolean2(nia, dst,
02813:                                    orientation);
02814:                        } catch (CompileException e) {
02815:                            throw new UCE(e);
02816:                        }
02817:                    }
02818:
02819:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
02820:                        try {
02821:                            UnitCompiler.this .compileBoolean2(nci, dst,
02822:                                    orientation);
02823:                        } catch (CompileException e) {
02824:                            throw new UCE(e);
02825:                        }
02826:                    }
02827:
02828:                    public void visitParameterAccess(Java.ParameterAccess pa) {
02829:                        try {
02830:                            UnitCompiler.this .compileBoolean2(pa, dst,
02831:                                    orientation);
02832:                        } catch (CompileException e) {
02833:                            throw new UCE(e);
02834:                        }
02835:                    }
02836:
02837:                    public void visitQualifiedThisReference(
02838:                            Java.QualifiedThisReference qtr) {
02839:                        try {
02840:                            UnitCompiler.this .compileBoolean2(qtr, dst,
02841:                                    orientation);
02842:                        } catch (CompileException e) {
02843:                            throw new UCE(e);
02844:                        }
02845:                    }
02846:
02847:                    public void visitThisReference(Java.ThisReference tr) {
02848:                        try {
02849:                            UnitCompiler.this .compileBoolean2(tr, dst,
02850:                                    orientation);
02851:                        } catch (CompileException e) {
02852:                            throw new UCE(e);
02853:                        }
02854:                    }
02855:
02856:                    public void visitAmbiguousName(Java.AmbiguousName an) {
02857:                        try {
02858:                            UnitCompiler.this .compileBoolean2(an, dst,
02859:                                    orientation);
02860:                        } catch (CompileException e) {
02861:                            throw new UCE(e);
02862:                        }
02863:                    }
02864:
02865:                    public void visitArrayAccessExpression(
02866:                            Java.ArrayAccessExpression aae) {
02867:                        try {
02868:                            UnitCompiler.this .compileBoolean2(aae, dst,
02869:                                    orientation);
02870:                        } catch (CompileException e) {
02871:                            throw new UCE(e);
02872:                        }
02873:                    };
02874:
02875:                    public void visitFieldAccess(Java.FieldAccess fa) {
02876:                        try {
02877:                            UnitCompiler.this .compileBoolean2(fa, dst,
02878:                                    orientation);
02879:                        } catch (CompileException e) {
02880:                            throw new UCE(e);
02881:                        }
02882:                    }
02883:
02884:                    public void visitFieldAccessExpression(
02885:                            Java.FieldAccessExpression fae) {
02886:                        try {
02887:                            UnitCompiler.this .compileBoolean2(fae, dst,
02888:                                    orientation);
02889:                        } catch (CompileException e) {
02890:                            throw new UCE(e);
02891:                        }
02892:                    }
02893:
02894:                    public void visitSuperclassFieldAccessExpression(
02895:                            Java.SuperclassFieldAccessExpression scfae) {
02896:                        try {
02897:                            UnitCompiler.this .compileBoolean2(scfae, dst,
02898:                                    orientation);
02899:                        } catch (CompileException e) {
02900:                            throw new UCE(e);
02901:                        }
02902:                    }
02903:
02904:                    public void visitLocalVariableAccess(
02905:                            Java.LocalVariableAccess lva) {
02906:                        try {
02907:                            UnitCompiler.this .compileBoolean2(lva, dst,
02908:                                    orientation);
02909:                        } catch (CompileException e) {
02910:                            throw new UCE(e);
02911:                        }
02912:                    }
02913:
02914:                    public void visitParenthesizedExpression(
02915:                            Java.ParenthesizedExpression pe) {
02916:                        try {
02917:                            UnitCompiler.this .compileBoolean2(pe, dst,
02918:                                    orientation);
02919:                        } catch (CompileException e) {
02920:                            throw new UCE(e);
02921:                        }
02922:                    }
02923:                };
02924:                try {
02925:                    rv.accept(rvv);
02926:                } catch (UCE uce) {
02927:                    throw uce.ce;
02928:                }
02929:            }
02930:
02931:            private void compileBoolean2(Java.Rvalue rv,
02932:                    CodeContext.Offset dst, // Where to jump.
02933:                    boolean orientation // JUMP_IF_TRUE or JUMP_IF_FALSE.
02934:            ) throws CompileException {
02935:                IClass type = this .compileGetValue(rv);
02936:                IClassLoader icl = this .iClassLoader;
02937:                if (type == icl.BOOLEAN) {
02938:                    this .unboxingConversion((Locatable) rv, icl.BOOLEAN,
02939:                            IClass.BOOLEAN);
02940:                } else if (type != IClass.BOOLEAN) {
02941:                    this .compileError("Not a boolean expression", rv
02942:                            .getLocation());
02943:                }
02944:                this .writeBranch(rv,
02945:                        orientation == Java.Rvalue.JUMP_IF_TRUE ? Opcode.IFNE
02946:                                : Opcode.IFEQ, dst);
02947:            }
02948:
02949:            private void compileBoolean2(Java.UnaryOperation ue,
02950:                    CodeContext.Offset dst, // Where to jump.
02951:                    boolean orientation // JUMP_IF_TRUE or JUMP_IF_FALSE.
02952:            ) throws CompileException {
02953:                if (ue.operator == "!") {
02954:                    this .compileBoolean(ue.operand, dst, !orientation);
02955:                    return;
02956:                }
02957:
02958:                this .compileError("Boolean expression expected", ue
02959:                        .getLocation());
02960:            }
02961:
02962:            private void compileBoolean2(Java.BinaryOperation bo,
02963:                    CodeContext.Offset dst, // Where to jump.
02964:                    boolean orientation // JUMP_IF_TRUE or JUMP_IF_FALSE.
02965:            ) throws CompileException {
02966:
02967:                if (bo.op == "|" || bo.op == "^" || bo.op == "&") {
02968:                    this .compileBoolean2((Java.Rvalue) bo, dst, orientation);
02969:                    return;
02970:                }
02971:
02972:                if (bo.op == "||" || bo.op == "&&") {
02973:                    Object lhsCV = this .getConstantValue(bo.lhs);
02974:                    if (lhsCV instanceof  Boolean) {
02975:                        if (((Boolean) lhsCV).booleanValue() ^ bo.op == "||") {
02976:                            // "true && a", "false || a"
02977:                            this 
02978:                                    .compileBoolean(
02979:                                            bo.rhs,
02980:                                            dst,
02981:                                            Java.Rvalue.JUMP_IF_TRUE
02982:                                                    ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
02983:                        } else {
02984:                            // "false && a", "true || a"
02985:                            this 
02986:                                    .compileBoolean(
02987:                                            bo.lhs,
02988:                                            dst,
02989:                                            Java.Rvalue.JUMP_IF_TRUE
02990:                                                    ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
02991:                            this .fakeCompile(bo.rhs);
02992:                        }
02993:                        return;
02994:                    }
02995:                    Object rhsCV = this .getConstantValue(bo.rhs);
02996:                    if (rhsCV instanceof  Boolean) {
02997:                        if (((Boolean) rhsCV).booleanValue() ^ bo.op == "||") {
02998:                            // "a && true", "a || false"
02999:                            this 
03000:                                    .compileBoolean(
03001:                                            bo.lhs,
03002:                                            dst,
03003:                                            Java.Rvalue.JUMP_IF_TRUE
03004:                                                    ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
03005:                        } else {
03006:                            // "a && false", "a || true"
03007:                            this .pop((Locatable) bo.lhs, this 
03008:                                    .compileGetValue(bo.lhs));
03009:                            this 
03010:                                    .compileBoolean(
03011:                                            bo.rhs,
03012:                                            dst,
03013:                                            Java.Rvalue.JUMP_IF_TRUE
03014:                                                    ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
03015:                        }
03016:                        return;
03017:                    }
03018:                    if (bo.op == "||"
03019:                            ^ orientation == Java.Rvalue.JUMP_IF_FALSE) {
03020:                        this 
03021:                                .compileBoolean(
03022:                                        bo.lhs,
03023:                                        dst,
03024:                                        Java.Rvalue.JUMP_IF_TRUE
03025:                                                ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
03026:                        this 
03027:                                .compileBoolean(
03028:                                        bo.rhs,
03029:                                        dst,
03030:                                        Java.Rvalue.JUMP_IF_TRUE
03031:                                                ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
03032:                    } else {
03033:                        CodeContext.Offset end = this .codeContext.new Offset();
03034:                        this 
03035:                                .compileBoolean(
03036:                                        bo.lhs,
03037:                                        end,
03038:                                        Java.Rvalue.JUMP_IF_FALSE
03039:                                                ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
03040:                        this 
03041:                                .compileBoolean(
03042:                                        bo.rhs,
03043:                                        dst,
03044:                                        Java.Rvalue.JUMP_IF_TRUE
03045:                                                ^ orientation == Java.Rvalue.JUMP_IF_FALSE);
03046:                        end.set();
03047:                    }
03048:                    return;
03049:                }
03050:
03051:                if (bo.op == "==" || bo.op == "!=" || bo.op == "<="
03052:                        || bo.op == ">=" || bo.op == "<" || bo.op == ">") {
03053:                    int opIdx = (bo.op == "==" ? 0 : bo.op == "!=" ? 1
03054:                            : bo.op == "<" ? 2 : bo.op == ">=" ? 3
03055:                                    : bo.op == ">" ? 4 : bo.op == "<=" ? 5
03056:                                            : Integer.MIN_VALUE);
03057:                    if (orientation == Java.Rvalue.JUMP_IF_FALSE)
03058:                        opIdx ^= 1;
03059:
03060:                    // Comparison with "null".
03061:                    {
03062:                        boolean lhsIsNull = this .getConstantValue(bo.lhs) == Java.Rvalue.CONSTANT_VALUE_NULL;
03063:                        boolean rhsIsNull = this .getConstantValue(bo.rhs) == Java.Rvalue.CONSTANT_VALUE_NULL;
03064:
03065:                        if (lhsIsNull || rhsIsNull) {
03066:                            if (bo.op != "==" && bo.op != "!=")
03067:                                this .compileError("Operator \"" + bo.op
03068:                                        + "\" not allowed on operand \"null\"",
03069:                                        bo.getLocation());
03070:
03071:                            // null == x
03072:                            // x == null
03073:                            IClass ohsType = this 
03074:                                    .compileGetValue(lhsIsNull ? bo.rhs
03075:                                            : bo.lhs);
03076:                            if (ohsType.isPrimitive())
03077:                                this .compileError(
03078:                                        "Cannot compare \"null\" with primitive type \""
03079:                                                + ohsType.toString() + "\"", bo
03080:                                                .getLocation());
03081:                            this .writeBranch(bo, Opcode.IFNULL + opIdx, dst);
03082:                            return;
03083:                        }
03084:                    }
03085:
03086:                    IClass lhsType = this .compileGetValue(bo.lhs);
03087:                    CodeContext.Inserter convertLhsInserter = this .codeContext
03088:                            .newInserter();
03089:                    IClass rhsType = this .compileGetValue(bo.rhs);
03090:
03091:                    // 15.20.1 Numerical comparison.
03092:                    if (this .getUnboxedType(lhsType).isPrimitiveNumeric()
03093:                            && this .getUnboxedType(rhsType)
03094:                                    .isPrimitiveNumeric()
03095:                            && !((bo.op == "==" || bo.op == "!=")
03096:                                    && !lhsType.isPrimitive() && !rhsType
03097:                                    .isPrimitive())) {
03098:                        IClass promotedType = this .binaryNumericPromotion(
03099:                                (Locatable) bo, lhsType, convertLhsInserter,
03100:                                rhsType);
03101:                        if (promotedType == IClass.INT) {
03102:                            this .writeBranch(bo, Opcode.IF_ICMPEQ + opIdx, dst);
03103:                        } else if (promotedType == IClass.LONG) {
03104:                            this .writeOpcode(bo, Opcode.LCMP);
03105:                            this .writeBranch(bo, Opcode.IFEQ + opIdx, dst);
03106:                        } else if (promotedType == IClass.FLOAT) {
03107:                            this .writeOpcode(bo, Opcode.FCMPG);
03108:                            this .writeBranch(bo, Opcode.IFEQ + opIdx, dst);
03109:                        } else if (promotedType == IClass.DOUBLE) {
03110:                            this .writeOpcode(bo, Opcode.DCMPG);
03111:                            this .writeBranch(bo, Opcode.IFEQ + opIdx, dst);
03112:                        } else {
03113:                            throw new RuntimeException(
03114:                                    "Unexpected promoted type \""
03115:                                            + promotedType + "\"");
03116:                        }
03117:                        return;
03118:                    }
03119:
03120:                    // JLS3 15.21.2 Boolean Equality Operators == and !=
03121:                    if ((lhsType == IClass.BOOLEAN && this 
03122:                            .getUnboxedType(rhsType) == IClass.BOOLEAN)
03123:                            || (rhsType == IClass.BOOLEAN && this 
03124:                                    .getUnboxedType(lhsType) == IClass.BOOLEAN)) {
03125:                        if (bo.op != "==" && bo.op != "!=")
03126:                            this .compileError("Operator \"" + bo.op
03127:                                    + "\" not allowed on boolean operands", bo
03128:                                    .getLocation());
03129:                        IClassLoader icl = this .iClassLoader;
03130:
03131:                        // Unbox LHS if necessary.
03132:                        if (lhsType == icl.BOOLEAN) {
03133:                            this .codeContext.pushInserter(convertLhsInserter);
03134:                            try {
03135:                                this .unboxingConversion((Locatable) bo,
03136:                                        icl.BOOLEAN, IClass.BOOLEAN);
03137:                            } finally {
03138:                                this .codeContext.popInserter();
03139:                            }
03140:                        }
03141:
03142:                        // Unbox RHS if necessary.
03143:                        if (rhsType == icl.BOOLEAN) {
03144:                            this .unboxingConversion((Locatable) bo,
03145:                                    icl.BOOLEAN, IClass.BOOLEAN);
03146:                        }
03147:
03148:                        this .writeBranch(bo, Opcode.IF_ICMPEQ + opIdx, dst);
03149:                        return;
03150:                    }
03151:
03152:                    // Reference comparison.
03153:                    // Note: Comparison with "null" is already handled above.
03154:                    if (!lhsType.isPrimitive() && !rhsType.isPrimitive()) {
03155:                        if (bo.op != "==" && bo.op != "!=")
03156:                            this .compileError("Operator \"" + bo.op
03157:                                    + "\" not allowed on reference operands",
03158:                                    bo.getLocation());
03159:                        this .writeBranch(bo, Opcode.IF_ACMPEQ + opIdx, dst);
03160:                        return;
03161:                    }
03162:
03163:                    this .compileError("Cannot compare types \"" + lhsType
03164:                            + "\" and \"" + rhsType + "\"", bo.getLocation());
03165:                }
03166:
03167:                this .compileError("Boolean expression expected", bo
03168:                        .getLocation());
03169:            }
03170:
03171:            private void compileBoolean2(Java.ParenthesizedExpression pe,
03172:                    CodeContext.Offset dst, boolean orientation)
03173:                    throws CompileException {
03174:                this .compileBoolean(pe.value, dst, orientation);
03175:            }
03176:
03177:            /**
03178:             * Generates code that determines the context of the {@link
03179:             * Java.Rvalue} and puts it on the operand stack. Most expressions
03180:             * do not have a "context", but some do. E.g. for "x[y]", the context
03181:             * is "x, y". The bottom line is that for statements like "x[y] += 3"
03182:             * the context is only evaluated once.
03183:             *
03184:             * @return The size of the context on the operand stack
03185:             */
03186:            private int compileContext(Java.Rvalue rv) throws CompileException {
03187:                final int[] res = new int[1];
03188:                class UCE extends RuntimeException {
03189:                    final CompileException ce;
03190:
03191:                    UCE(CompileException ce) {
03192:                        this .ce = ce;
03193:                    }
03194:                }
03195:                Visitor.RvalueVisitor rvv = new Visitor.RvalueVisitor() {
03196:                    public void visitArrayLength(Java.ArrayLength al) {
03197:                        try {
03198:                            res[0] = UnitCompiler.this .compileContext2(al);
03199:                        } catch (CompileException e) {
03200:                            throw new UCE(e);
03201:                        }
03202:                    }
03203:
03204:                    public void visitAssignment(Java.Assignment a) {
03205:                        res[0] = UnitCompiler.this .compileContext2(a);
03206:                    }
03207:
03208:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
03209:                        res[0] = UnitCompiler.this .compileContext2(uo);
03210:                    }
03211:
03212:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
03213:                        res[0] = UnitCompiler.this .compileContext2(bo);
03214:                    }
03215:
03216:                    public void visitCast(Java.Cast c) {
03217:                        res[0] = UnitCompiler.this .compileContext2(c);
03218:                    }
03219:
03220:                    public void visitClassLiteral(Java.ClassLiteral cl) {
03221:                        res[0] = UnitCompiler.this .compileContext2(cl);
03222:                    }
03223:
03224:                    public void visitConditionalExpression(
03225:                            Java.ConditionalExpression ce) {
03226:                        res[0] = UnitCompiler.this .compileContext2(ce);
03227:                    }
03228:
03229:                    public void visitConstantValue(Java.ConstantValue cv) {
03230:                        res[0] = UnitCompiler.this .compileContext2(cv);
03231:                    }
03232:
03233:                    public void visitCrement(Java.Crement c) {
03234:                        res[0] = UnitCompiler.this .compileContext2(c);
03235:                    }
03236:
03237:                    public void visitInstanceof(Java.Instanceof io) {
03238:                        res[0] = UnitCompiler.this .compileContext2(io);
03239:                    }
03240:
03241:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
03242:                        res[0] = UnitCompiler.this .compileContext2(mi);
03243:                    }
03244:
03245:                    public void visitSuperclassMethodInvocation(
03246:                            Java.SuperclassMethodInvocation smi) {
03247:                        res[0] = UnitCompiler.this .compileContext2(smi);
03248:                    }
03249:
03250:                    public void visitLiteral(Java.Literal l) {
03251:                        res[0] = UnitCompiler.this .compileContext2(l);
03252:                    }
03253:
03254:                    public void visitNewAnonymousClassInstance(
03255:                            Java.NewAnonymousClassInstance naci) {
03256:                        res[0] = UnitCompiler.this .compileContext2(naci);
03257:                    }
03258:
03259:                    public void visitNewArray(Java.NewArray na) {
03260:                        res[0] = UnitCompiler.this .compileContext2(na);
03261:                    }
03262:
03263:                    public void visitNewInitializedArray(
03264:                            Java.NewInitializedArray nia) {
03265:                        res[0] = UnitCompiler.this .compileContext2(nia);
03266:                    }
03267:
03268:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
03269:                        res[0] = UnitCompiler.this .compileContext2(nci);
03270:                    }
03271:
03272:                    public void visitParameterAccess(Java.ParameterAccess pa) {
03273:                        res[0] = UnitCompiler.this .compileContext2(pa);
03274:                    }
03275:
03276:                    public void visitQualifiedThisReference(
03277:                            Java.QualifiedThisReference qtr) {
03278:                        res[0] = UnitCompiler.this .compileContext2(qtr);
03279:                    }
03280:
03281:                    public void visitThisReference(Java.ThisReference tr) {
03282:                        res[0] = UnitCompiler.this .compileContext2(tr);
03283:                    }
03284:
03285:                    public void visitAmbiguousName(Java.AmbiguousName an) {
03286:                        try {
03287:                            res[0] = UnitCompiler.this .compileContext2(an);
03288:                        } catch (CompileException e) {
03289:                            throw new UCE(e);
03290:                        }
03291:                    }
03292:
03293:                    public void visitArrayAccessExpression(
03294:                            Java.ArrayAccessExpression aae) {
03295:                        try {
03296:                            res[0] = UnitCompiler.this .compileContext2(aae);
03297:                        } catch (CompileException e) {
03298:                            throw new UCE(e);
03299:                        }
03300:                    };
03301:
03302:                    public void visitFieldAccess(Java.FieldAccess fa) {
03303:                        try {
03304:                            res[0] = UnitCompiler.this .compileContext2(fa);
03305:                        } catch (CompileException e) {
03306:                            throw new UCE(e);
03307:                        }
03308:                    }
03309:
03310:                    public void visitFieldAccessExpression(
03311:                            Java.FieldAccessExpression fae) {
03312:                        try {
03313:                            res[0] = UnitCompiler.this .compileContext2(fae);
03314:                        } catch (CompileException e) {
03315:                            throw new UCE(e);
03316:                        }
03317:                    }
03318:
03319:                    public void visitSuperclassFieldAccessExpression(
03320:                            Java.SuperclassFieldAccessExpression scfae) {
03321:                        try {
03322:                            res[0] = UnitCompiler.this .compileContext2(scfae);
03323:                        } catch (CompileException e) {
03324:                            throw new UCE(e);
03325:                        }
03326:                    }
03327:
03328:                    public void visitLocalVariableAccess(
03329:                            Java.LocalVariableAccess lva) {
03330:                        res[0] = UnitCompiler.this .compileContext2(lva);
03331:                    }
03332:
03333:                    public void visitParenthesizedExpression(
03334:                            Java.ParenthesizedExpression pe) {
03335:                        try {
03336:                            res[0] = UnitCompiler.this .compileContext2(pe);
03337:                        } catch (CompileException e) {
03338:                            throw new UCE(e);
03339:                        }
03340:                    }
03341:                };
03342:                try {
03343:                    rv.accept(rvv);
03344:                    return res[0];
03345:                } catch (UCE uce) {
03346:                    throw uce.ce;
03347:                }
03348:            }
03349:
03350:            private int compileContext2(Java.Rvalue rv) {
03351:                return 0;
03352:            }
03353:
03354:            private int compileContext2(Java.AmbiguousName an)
03355:                    throws CompileException {
03356:                return this .compileContext(this .toRvalueOrCE(this 
03357:                        .reclassify(an)));
03358:            }
03359:
03360:            private int compileContext2(Java.FieldAccess fa)
03361:                    throws CompileException {
03362:                if (fa.field.isStatic()) {
03363:                    this .getType(this .toTypeOrCE(fa.lhs));
03364:                    return 0;
03365:                } else {
03366:                    this .compileGetValue(this .toRvalueOrCE(fa.lhs));
03367:                    return 1;
03368:                }
03369:            }
03370:
03371:            private int compileContext2(Java.ArrayLength al)
03372:                    throws CompileException {
03373:                if (!this .compileGetValue(al.lhs).isArray())
03374:                    this .compileError(
03375:                            "Cannot determine length of non-array type", al
03376:                                    .getLocation());
03377:                return 1;
03378:            }
03379:
03380:            private int compileContext2(Java.ArrayAccessExpression aae)
03381:                    throws CompileException {
03382:                IClass lhsType = this .compileGetValue(aae.lhs);
03383:                if (!lhsType.isArray())
03384:                    this .compileError(
03385:                            "Subscript not allowed on non-array type \""
03386:                                    + lhsType.toString() + "\"", aae
03387:                                    .getLocation());
03388:
03389:                IClass indexType = this .compileGetValue(aae.index);
03390:                if (!this .tryIdentityConversion(indexType, IClass.INT)
03391:                        && !this .tryWideningPrimitiveConversion(
03392:                                (Locatable) aae, // l
03393:                                indexType, // sourceType
03394:                                IClass.INT // targetType
03395:                                ))
03396:                    this .compileError("Index expression of type \"" + indexType
03397:                            + "\" cannot be widened to \"int\"", aae
03398:                            .getLocation());
03399:
03400:                return 2;
03401:            }
03402:
03403:            private int compileContext2(Java.FieldAccessExpression fae)
03404:                    throws CompileException {
03405:                this .determineValue(fae);
03406:                return this .compileContext(fae.value);
03407:            }
03408:
03409:            private int compileContext2(
03410:                    Java.SuperclassFieldAccessExpression scfae)
03411:                    throws CompileException {
03412:                this .determineValue(scfae);
03413:                return this .compileContext(scfae.value);
03414:            }
03415:
03416:            private int compileContext2(Java.ParenthesizedExpression pe)
03417:                    throws CompileException {
03418:                return this .compileContext(pe.value);
03419:            }
03420:
03421:            /**
03422:             * Generates code that determines the value of the {@link Java.Rvalue}
03423:             * and puts it on the operand stack. This method relies on that the
03424:             * "context" of the {@link Java.Rvalue} is on top of the operand stack
03425:             * (see {@link #compileContext(Java.Rvalue)}).
03426:             *
03427:             * @return The type of the {@link Java.Rvalue}
03428:             */
03429:            private IClass compileGet(Java.Rvalue rv) throws CompileException {
03430:                final IClass[] res = new IClass[1];
03431:                class UCE extends RuntimeException {
03432:                    final CompileException ce;
03433:
03434:                    UCE(CompileException ce) {
03435:                        this .ce = ce;
03436:                    }
03437:                }
03438:                Visitor.RvalueVisitor rvv = new Visitor.RvalueVisitor() {
03439:                    public void visitArrayLength(Java.ArrayLength al) {
03440:                        res[0] = UnitCompiler.this .compileGet2(al);
03441:                    }
03442:
03443:                    public void visitAssignment(Java.Assignment a) {
03444:                        try {
03445:                            res[0] = UnitCompiler.this .compileGet2(a);
03446:                        } catch (CompileException e) {
03447:                            throw new UCE(e);
03448:                        }
03449:                    }
03450:
03451:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
03452:                        try {
03453:                            res[0] = UnitCompiler.this .compileGet2(uo);
03454:                        } catch (CompileException e) {
03455:                            throw new UCE(e);
03456:                        }
03457:                    }
03458:
03459:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
03460:                        try {
03461:                            res[0] = UnitCompiler.this .compileGet2(bo);
03462:                        } catch (CompileException e) {
03463:                            throw new UCE(e);
03464:                        }
03465:                    }
03466:
03467:                    public void visitCast(Java.Cast c) {
03468:                        try {
03469:                            res[0] = UnitCompiler.this .compileGet2(c);
03470:                        } catch (CompileException e) {
03471:                            throw new UCE(e);
03472:                        }
03473:                    }
03474:
03475:                    public void visitClassLiteral(Java.ClassLiteral cl) {
03476:                        try {
03477:                            res[0] = UnitCompiler.this .compileGet2(cl);
03478:                        } catch (CompileException e) {
03479:                            throw new UCE(e);
03480:                        }
03481:                    }
03482:
03483:                    public void visitConditionalExpression(
03484:                            Java.ConditionalExpression ce) {
03485:                        try {
03486:                            res[0] = UnitCompiler.this .compileGet2(ce);
03487:                        } catch (CompileException e) {
03488:                            throw new UCE(e);
03489:                        }
03490:                    }
03491:
03492:                    public void visitConstantValue(Java.ConstantValue cv) {
03493:                        res[0] = UnitCompiler.this .compileGet2(cv);
03494:                    }
03495:
03496:                    public void visitCrement(Java.Crement c) {
03497:                        try {
03498:                            res[0] = UnitCompiler.this .compileGet2(c);
03499:                        } catch (CompileException e) {
03500:                            throw new UCE(e);
03501:                        }
03502:                    }
03503:
03504:                    public void visitInstanceof(Java.Instanceof io) {
03505:                        try {
03506:                            res[0] = UnitCompiler.this .compileGet2(io);
03507:                        } catch (CompileException e) {
03508:                            throw new UCE(e);
03509:                        }
03510:                    }
03511:
03512:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
03513:                        try {
03514:                            res[0] = UnitCompiler.this .compileGet2(mi);
03515:                        } catch (CompileException e) {
03516:                            throw new UCE(e);
03517:                        }
03518:                    }
03519:
03520:                    public void visitSuperclassMethodInvocation(
03521:                            Java.SuperclassMethodInvocation smi) {
03522:                        try {
03523:                            res[0] = UnitCompiler.this .compileGet2(smi);
03524:                        } catch (CompileException e) {
03525:                            throw new UCE(e);
03526:                        }
03527:                    }
03528:
03529:                    public void visitLiteral(Java.Literal l) {
03530:                        try {
03531:                            res[0] = UnitCompiler.this .compileGet2(l);
03532:                        } catch (CompileException e) {
03533:                            throw new UCE(e);
03534:                        }
03535:                    }
03536:
03537:                    public void visitNewAnonymousClassInstance(
03538:                            Java.NewAnonymousClassInstance naci) {
03539:                        try {
03540:                            res[0] = UnitCompiler.this .compileGet2(naci);
03541:                        } catch (CompileException e) {
03542:                            throw new UCE(e);
03543:                        }
03544:                    }
03545:
03546:                    public void visitNewArray(Java.NewArray na) {
03547:                        try {
03548:                            res[0] = UnitCompiler.this .compileGet2(na);
03549:                        } catch (CompileException e) {
03550:                            throw new UCE(e);
03551:                        }
03552:                    }
03553:
03554:                    public void visitNewInitializedArray(
03555:                            Java.NewInitializedArray nia) {
03556:                        try {
03557:                            res[0] = UnitCompiler.this .compileGet2(nia);
03558:                        } catch (CompileException e) {
03559:                            throw new UCE(e);
03560:                        }
03561:                    }
03562:
03563:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
03564:                        try {
03565:                            res[0] = UnitCompiler.this .compileGet2(nci);
03566:                        } catch (CompileException e) {
03567:                            throw new UCE(e);
03568:                        }
03569:                    }
03570:
03571:                    public void visitParameterAccess(Java.ParameterAccess pa) {
03572:                        try {
03573:                            res[0] = UnitCompiler.this .compileGet2(pa);
03574:                        } catch (CompileException e) {
03575:                            throw new UCE(e);
03576:                        }
03577:                    }
03578:
03579:                    public void visitQualifiedThisReference(
03580:                            Java.QualifiedThisReference qtr) {
03581:                        try {
03582:                            res[0] = UnitCompiler.this .compileGet2(qtr);
03583:                        } catch (CompileException e) {
03584:                            throw new UCE(e);
03585:                        }
03586:                    }
03587:
03588:                    public void visitThisReference(Java.ThisReference tr) {
03589:                        try {
03590:                            res[0] = UnitCompiler.this .compileGet2(tr);
03591:                        } catch (CompileException e) {
03592:                            throw new UCE(e);
03593:                        }
03594:                    }
03595:
03596:                    public void visitAmbiguousName(Java.AmbiguousName an) {
03597:                        try {
03598:                            res[0] = UnitCompiler.this .compileGet2(an);
03599:                        } catch (CompileException e) {
03600:                            throw new UCE(e);
03601:                        }
03602:                    }
03603:
03604:                    public void visitArrayAccessExpression(
03605:                            Java.ArrayAccessExpression aae) {
03606:                        try {
03607:                            res[0] = UnitCompiler.this .compileGet2(aae);
03608:                        } catch (CompileException e) {
03609:                            throw new UCE(e);
03610:                        }
03611:                    };
03612:
03613:                    public void visitFieldAccess(Java.FieldAccess fa) {
03614:                        try {
03615:                            res[0] = UnitCompiler.this .compileGet2(fa);
03616:                        } catch (CompileException e) {
03617:                            throw new UCE(e);
03618:                        }
03619:                    }
03620:
03621:                    public void visitFieldAccessExpression(
03622:                            Java.FieldAccessExpression fae) {
03623:                        try {
03624:                            res[0] = UnitCompiler.this .compileGet2(fae);
03625:                        } catch (CompileException e) {
03626:                            throw new UCE(e);
03627:                        }
03628:                    }
03629:
03630:                    public void visitSuperclassFieldAccessExpression(
03631:                            Java.SuperclassFieldAccessExpression scfae) {
03632:                        try {
03633:                            res[0] = UnitCompiler.this .compileGet2(scfae);
03634:                        } catch (CompileException e) {
03635:                            throw new UCE(e);
03636:                        }
03637:                    }
03638:
03639:                    public void visitLocalVariableAccess(
03640:                            Java.LocalVariableAccess lva) {
03641:                        res[0] = UnitCompiler.this .compileGet2(lva);
03642:                    }
03643:
03644:                    public void visitParenthesizedExpression(
03645:                            Java.ParenthesizedExpression pe) {
03646:                        try {
03647:                            res[0] = UnitCompiler.this .compileGet2(pe);
03648:                        } catch (CompileException e) {
03649:                            throw new UCE(e);
03650:                        }
03651:                    }
03652:                };
03653:                try {
03654:                    rv.accept(rvv);
03655:                    return res[0];
03656:                } catch (UCE uce) {
03657:                    throw uce.ce;
03658:                }
03659:            }
03660:
03661:            private IClass compileGet2(Java.BooleanRvalue brv)
03662:                    throws CompileException {
03663:                CodeContext.Offset isTrue = this .codeContext.new Offset();
03664:                this .compileBoolean(brv, isTrue, Java.Rvalue.JUMP_IF_TRUE);
03665:                this .writeOpcode(brv, Opcode.ICONST_0);
03666:                CodeContext.Offset end = this .codeContext.new Offset();
03667:                this .writeBranch(brv, Opcode.GOTO, end);
03668:                isTrue.set();
03669:                this .writeOpcode(brv, Opcode.ICONST_1);
03670:                end.set();
03671:
03672:                return IClass.BOOLEAN;
03673:            }
03674:
03675:            private IClass compileGet2(Java.AmbiguousName an)
03676:                    throws CompileException {
03677:                return this .compileGet(this .toRvalueOrCE(this .reclassify(an)));
03678:            }
03679:
03680:            private IClass compileGet2(Java.LocalVariableAccess lva) {
03681:                return this .load((Locatable) lva, lva.localVariable);
03682:            }
03683:
03684:            private IClass compileGet2(Java.FieldAccess fa)
03685:                    throws CompileException {
03686:                this .checkAccessible(fa.field, fa.getEnclosingBlockStatement());
03687:                if (fa.field.isStatic()) {
03688:                    this .writeOpcode(fa, Opcode.GETSTATIC);
03689:                } else {
03690:                    this .writeOpcode(fa, Opcode.GETFIELD);
03691:                }
03692:                this .writeConstantFieldrefInfo(fa.field.getDeclaringIClass()
03693:                        .getDescriptor(), fa.field.getName(), // classFD
03694:                        fa.field.getType().getDescriptor() // fieldFD
03695:                        );
03696:                return fa.field.getType();
03697:            }
03698:
03699:            private IClass compileGet2(Java.ArrayLength al) {
03700:                this .writeOpcode(al, Opcode.ARRAYLENGTH);
03701:                return IClass.INT;
03702:            }
03703:
03704:            private IClass compileGet2(Java.ThisReference tr)
03705:                    throws CompileException {
03706:                this .referenceThis((Locatable) tr);
03707:                return this .getIClass(tr);
03708:            }
03709:
03710:            private IClass compileGet2(Java.QualifiedThisReference qtr)
03711:                    throws CompileException {
03712:                this .referenceThis((Locatable) qtr, // l
03713:                        this .getDeclaringClass(qtr), // declaringClass
03714:                        this .getDeclaringTypeBodyDeclaration(qtr), // declaringTypeBodyDeclaration
03715:                        this .getTargetIClass(qtr) // targetIClass
03716:                        );
03717:                return this .getTargetIClass(qtr);
03718:            }
03719:
03720:            private IClass compileGet2(Java.ClassLiteral cl)
03721:                    throws CompileException {
03722:                Location loc = cl.getLocation();
03723:                final IClassLoader icl = this .iClassLoader;
03724:                IClass iClass = this .getType(cl.type);
03725:
03726:                if (iClass.isPrimitive()) {
03727:
03728:                    // Primitive class literal.
03729:                    this .writeOpcode(cl, Opcode.GETSTATIC);
03730:                    String wrapperClassDescriptor = (iClass == IClass.VOID ? "Ljava/lang/Void;"
03731:                            : iClass == IClass.BYTE ? "Ljava/lang/Byte;"
03732:                                    : iClass == IClass.CHAR ? "Ljava/lang/Character;"
03733:                                            : iClass == IClass.DOUBLE ? "Ljava/lang/Double;"
03734:                                                    : iClass == IClass.FLOAT ? "Ljava/lang/Float;"
03735:                                                            : iClass == IClass.INT ? "Ljava/lang/Integer;"
03736:                                                                    : iClass == IClass.LONG ? "Ljava/lang/Long;"
03737:                                                                            : iClass == IClass.SHORT ? "Ljava/lang/Short;"
03738:                                                                                    : iClass == IClass.BOOLEAN ? "Ljava/lang/Boolean;"
03739:                                                                                            : null);
03740:                    if (wrapperClassDescriptor == null)
03741:                        throw new RuntimeException(
03742:                                "SNO: Unidentifiable primitive type \""
03743:                                        + iClass + "\"");
03744:
03745:                    this .writeConstantFieldrefInfo(wrapperClassDescriptor,
03746:                            "TYPE", // classFD
03747:                            "Ljava/lang/Class;" // fieldFD
03748:                    );
03749:                    return icl.CLASS;
03750:                }
03751:
03752:                // Non-primitive class literal.
03753:
03754:                Java.AbstractTypeDeclaration declaringType;
03755:                for (Java.Scope s = cl.getEnclosingBlockStatement();; s = s
03756:                        .getEnclosingScope()) {
03757:                    if (s instanceof  Java.TypeDeclaration) {
03758:                        declaringType = (Java.AbstractTypeDeclaration) s;
03759:                        break;
03760:                    }
03761:                }
03762:
03763:                // Check if synthetic method "static Class class$(String className)" is already
03764:                // declared.
03765:                boolean classDollarMethodDeclared = false;
03766:                {
03767:                    for (Iterator it = declaringType.declaredMethods.iterator(); it
03768:                            .hasNext();) {
03769:                        Java.MethodDeclarator md = (Java.MethodDeclarator) it
03770:                                .next();
03771:                        if (md.name.equals("class$")) {
03772:                            classDollarMethodDeclared = true;
03773:                            break;
03774:                        }
03775:                    }
03776:                }
03777:                if (!classDollarMethodDeclared)
03778:                    this .declareClassDollarMethod(cl);
03779:
03780:                // Determine the statics of the declaring class (this is where static fields
03781:                // declarations are found).
03782:                List statics; // TypeBodyDeclaration
03783:                if (declaringType instanceof  Java.ClassDeclaration) {
03784:                    statics = ((Java.ClassDeclaration) declaringType).variableDeclaratorsAndInitializers;
03785:                } else if (declaringType instanceof  Java.InterfaceDeclaration) {
03786:                    statics = ((Java.InterfaceDeclaration) declaringType).constantDeclarations;
03787:                } else {
03788:                    throw new RuntimeException(
03789:                            "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration");
03790:                }
03791:
03792:                String className = Descriptor.toClassName(iClass
03793:                        .getDescriptor());
03794:
03795:                // Compose the "class-dollar" field name. This i done as follows:
03796:                //   Type         Class-name           Field-name
03797:                //   String       java.lang.String     class$java$lang$String
03798:                //   String[]     [Ljava.lang.String;  array$Ljava$lang$String
03799:                //   String[][]   [[Ljava.lang.String; array$$Ljava$lang$String
03800:                //   String[][][] [[[java.lang.String; array$$$Ljava$lang$String
03801:                //   int[]        [I                   array$I
03802:                //   int[][]      [[I                  array$$I
03803:                String classDollarFieldName;
03804:                {
03805:                    if (className.startsWith("[")) {
03806:                        classDollarFieldName = "array"
03807:                                + className.replace('.', '$').replace('[', '$');
03808:                        if (classDollarFieldName.endsWith(";"))
03809:                            classDollarFieldName = classDollarFieldName
03810:                                    .substring(0,
03811:                                            classDollarFieldName.length() - 1);
03812:                    } else {
03813:                        classDollarFieldName = "class$"
03814:                                + className.replace('.', '$');
03815:                    }
03816:                }
03817:
03818:                // Declare the static "class dollar field" if not already done.
03819:                {
03820:                    boolean hasClassDollarField = false;
03821:                    BLOCK_STATEMENTS: for (Iterator it = statics.iterator(); it
03822:                            .hasNext();) {
03823:                        Java.TypeBodyDeclaration tbd = (Java.TypeBodyDeclaration) it
03824:                                .next();
03825:                        if (!tbd.isStatic())
03826:                            continue;
03827:                        if (tbd instanceof  Java.FieldDeclaration) {
03828:                            Java.FieldDeclaration fd = (Java.FieldDeclaration) tbd;
03829:                            IClass.IField[] fds = this .getIFields(fd);
03830:                            for (int j = 0; j < fds.length; ++j) {
03831:                                if (fds[j].getName().equals(
03832:                                        classDollarFieldName)) {
03833:                                    hasClassDollarField = true;
03834:                                    break BLOCK_STATEMENTS;
03835:                                }
03836:                            }
03837:                        }
03838:                    }
03839:                    if (!hasClassDollarField) {
03840:                        Java.Type classType = new Java.SimpleType(loc,
03841:                                icl.CLASS);
03842:                        Java.FieldDeclaration fd = new Java.FieldDeclaration(
03843:                                loc, // location
03844:                                null, // optionalDocComment
03845:                                Mod.STATIC, // modifiers
03846:                                classType, // type
03847:                                new Java.VariableDeclarator[] { // variableDeclarators
03848:                                new Java.VariableDeclarator(loc, // location
03849:                                        classDollarFieldName, // name
03850:                                        0, // brackets
03851:                                        (Java.Rvalue) null // optionalInitializer
03852:                                ) });
03853:                        if (declaringType instanceof  Java.ClassDeclaration) {
03854:                            ((Java.ClassDeclaration) declaringType)
03855:                                    .addVariableDeclaratorOrInitializer(fd);
03856:                        } else if (declaringType instanceof  Java.InterfaceDeclaration) {
03857:                            ((Java.InterfaceDeclaration) declaringType)
03858:                                    .addConstantDeclaration(fd);
03859:                        } else {
03860:                            throw new RuntimeException(
03861:                                    "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration");
03862:                        }
03863:                    }
03864:                }
03865:
03866:                // return (class$X != null) ? class$X : (class$X = class$("X"));
03867:                Java.Type declaringClassOrInterfaceType = new Java.SimpleType(
03868:                        loc, this .resolve(declaringType));
03869:                Java.Lvalue classDollarFieldAccess = new Java.FieldAccessExpression(
03870:                        loc, // location
03871:                        declaringClassOrInterfaceType, // lhs
03872:                        classDollarFieldName // fieldName
03873:                );
03874:                Java.ConditionalExpression ce = new Java.ConditionalExpression(
03875:                        loc, // location
03876:                        new Java.BinaryOperation( // lhs
03877:                                loc, // location
03878:                                classDollarFieldAccess, // lhs
03879:                                "!=", // op
03880:                                new Java.ConstantValue(loc, null) // rhs
03881:                        ), classDollarFieldAccess, // mhs
03882:                        new Java.Assignment( // rhs
03883:                                loc, // location
03884:                                classDollarFieldAccess, // lhs
03885:                                "=", // operator
03886:                                new Java.MethodInvocation( // rhs
03887:                                        loc, // location
03888:                                        declaringClassOrInterfaceType, // optionalTarget
03889:                                        "class$", // methodName
03890:                                        new Java.Rvalue[] { // arguments
03891:                                        new Java.ConstantValue(loc, // location
03892:                                                className // constantValue
03893:                                        ) })));
03894:                ce.setEnclosingBlockStatement(cl.getEnclosingBlockStatement());
03895:                return this .compileGet(ce);
03896:            }
03897:
03898:            private IClass compileGet2(Java.Assignment a)
03899:                    throws CompileException {
03900:                if (a.operator == "=") {
03901:                    int lhsCS = this .compileContext(a.lhs);
03902:                    IClass rhsType = this .compileGetValue(a.rhs);
03903:                    IClass lhsType = this .getType(a.lhs);
03904:                    Object rhsCV = this .getConstantValue(a.rhs);
03905:                    this .assignmentConversion((Locatable) a, // l
03906:                            rhsType, // sourceType
03907:                            lhsType, // targetType
03908:                            rhsCV // optionalConstantValue
03909:                            );
03910:                    this .dupx((Locatable) a, // l
03911:                            lhsType, // type
03912:                            lhsCS // x
03913:                            );
03914:                    this .compileSet(a.lhs);
03915:                    return lhsType;
03916:                }
03917:
03918:                // Implement "|= ^= &= *= /= %= += -= <<= >>= >>>=".
03919:                int lhsCS = this .compileContext(a.lhs);
03920:                this .dup((Locatable) a, lhsCS);
03921:                IClass lhsType = this .compileGet(a.lhs);
03922:                IClass resultType = this .compileArithmeticBinaryOperation(
03923:                        (Locatable) a, // l
03924:                        lhsType, // lhsType
03925:                        a.operator.substring( // operator
03926:                                0, a.operator.length() - 1).intern(), // <= IMPORTANT!
03927:                        a.rhs // rhs
03928:                        );
03929:                // Convert the result to LHS type (JLS2 15.26.2).
03930:                if (!this .tryIdentityConversion(resultType, lhsType)
03931:                        && !this .tryNarrowingPrimitiveConversion((Locatable) a, // l
03932:                                resultType, // sourceType
03933:                                lhsType // destinationType
03934:                                ))
03935:                    throw new RuntimeException("SNO: \"" + a.operator
03936:                            + "\" reconversion failed");
03937:                this .dupx((Locatable) a, // l
03938:                        lhsType, // type
03939:                        lhsCS // x
03940:                        );
03941:                this .compileSet(a.lhs);
03942:                return lhsType;
03943:            }
03944:
03945:            private IClass compileGet2(Java.ConditionalExpression ce)
03946:                    throws CompileException {
03947:                IClass mhsType, rhsType;
03948:                CodeContext.Inserter mhsConvertInserter, rhsConvertInserter;
03949:                CodeContext.Offset toEnd = this .codeContext.new Offset();
03950:                Object cv = this .getConstantValue(ce.lhs);
03951:                if (cv instanceof  Boolean) {
03952:                    if (((Boolean) cv).booleanValue()) {
03953:                        mhsType = this .compileGetValue(ce.mhs);
03954:                        mhsConvertInserter = this .codeContext.newInserter();
03955:                        rhsType = this .getType(ce.rhs);
03956:                        rhsConvertInserter = null;
03957:                    } else {
03958:                        mhsType = this .getType(ce.mhs);
03959:                        mhsConvertInserter = null;
03960:                        rhsType = this .compileGetValue(ce.rhs);
03961:                        rhsConvertInserter = this .codeContext.currentInserter();
03962:                    }
03963:                } else {
03964:                    CodeContext.Offset toRhs = this .codeContext.new Offset();
03965:
03966:                    this .compileBoolean(ce.lhs, toRhs,
03967:                            Java.Rvalue.JUMP_IF_FALSE);
03968:                    mhsType = this .compileGetValue(ce.mhs);
03969:                    mhsConvertInserter = this .codeContext.newInserter();
03970:                    this .writeBranch(ce, Opcode.GOTO, toEnd);
03971:                    toRhs.set();
03972:                    rhsType = this .compileGetValue(ce.rhs);
03973:                    rhsConvertInserter = this .codeContext.currentInserter();
03974:                }
03975:
03976:                IClass expressionType;
03977:                if (mhsType == rhsType) {
03978:
03979:                    // JLS 15.25.1.1
03980:                    expressionType = mhsType;
03981:                } else if (mhsType.isPrimitiveNumeric()
03982:                        && rhsType.isPrimitiveNumeric()) {
03983:
03984:                    // JLS 15.25.1.2
03985:
03986:                    // TODO JLS 15.25.1.2.1
03987:
03988:                    // TODO JLS 15.25.1.2.2
03989:
03990:                    // JLS 15.25.1.2.3
03991:                    expressionType = this .binaryNumericPromotion(
03992:                            (Locatable) ce, // l
03993:                            mhsType, // type1
03994:                            mhsConvertInserter, // convertInserter1
03995:                            rhsType, // type2
03996:                            rhsConvertInserter // convertInserter2
03997:                            );
03998:                } else if (this .getConstantValue(ce.mhs) == Java.Rvalue.CONSTANT_VALUE_NULL
03999:                        && !rhsType.isPrimitive()) {
04000:
04001:                    // JLS 15.25.1.3 (null : ref)
04002:                    expressionType = rhsType;
04003:                } else if (!mhsType.isPrimitive()
04004:                        && this .getConstantValue(ce.rhs) == Java.Rvalue.CONSTANT_VALUE_NULL) {
04005:
04006:                    // JLS 15.25.1.3 (ref : null)
04007:                    expressionType = mhsType;
04008:                } else if (!mhsType.isPrimitive() && !rhsType.isPrimitive()) {
04009:                    if (mhsType.isAssignableFrom(rhsType)) {
04010:                        expressionType = mhsType;
04011:                    } else if (rhsType.isAssignableFrom(mhsType)) {
04012:                        expressionType = rhsType;
04013:                    } else {
04014:                        this .compileError("Reference types \"" + mhsType
04015:                                + "\" and \"" + rhsType + "\" don't match", ce
04016:                                .getLocation());
04017:                        return this .iClassLoader.OBJECT;
04018:                    }
04019:                } else {
04020:                    this .compileError("Incompatible expression types \""
04021:                            + mhsType + "\" and \"" + rhsType + "\"", ce
04022:                            .getLocation());
04023:                    return this .iClassLoader.OBJECT;
04024:                }
04025:                toEnd.set();
04026:
04027:                return expressionType;
04028:            }
04029:
04030:            private IClass compileGet2(Java.Crement c) throws CompileException {
04031:
04032:                // Optimized crement of integer local variable.
04033:                Java.LocalVariable lv = this .isIntLV(c);
04034:                if (lv != null) {
04035:                    if (!c.pre)
04036:                        this .load((Locatable) c, lv);
04037:                    this .writeOpcode(c, Opcode.IINC);
04038:                    this .writeByte(lv.localVariableArrayIndex);
04039:                    this .writeByte(c.operator == "++" ? 1 : -1);
04040:                    if (c.pre)
04041:                        this .load((Locatable) c, lv);
04042:                    return lv.type;
04043:                }
04044:
04045:                // Compile operand context.
04046:                int cs = this .compileContext(c.operand);
04047:                // DUP operand context.
04048:                this .dup((Locatable) c, cs);
04049:                // Get operand value.
04050:                IClass type = this .compileGet(c.operand);
04051:                // DUPX operand value.
04052:                if (!c.pre)
04053:                    this .dupx((Locatable) c, type, cs);
04054:                // Apply "unary numeric promotion".
04055:                IClass promotedType = this .unaryNumericPromotion((Locatable) c,
04056:                        type);
04057:                // Crement.
04058:                this .writeOpcode(c, UnitCompiler.ilfd(promotedType,
04059:                        Opcode.ICONST_1, Opcode.LCONST_1, Opcode.FCONST_1,
04060:                        Opcode.DCONST_1));
04061:                if (c.operator == "++") {
04062:                    this .writeOpcode(c, Opcode.IADD
04063:                            + UnitCompiler.ilfd(promotedType));
04064:                } else if (c.operator == "--") {
04065:                    this .writeOpcode(c, Opcode.ISUB
04066:                            + UnitCompiler.ilfd(promotedType));
04067:                } else {
04068:                    this .compileError("Unexpected operator \"" + c.operator
04069:                            + "\"", c.getLocation());
04070:                }
04071:                this .reverseUnaryNumericPromotion((Locatable) c, promotedType,
04072:                        type);
04073:                // DUPX cremented operand value.
04074:                if (c.pre)
04075:                    this .dupx((Locatable) c, type, cs);
04076:                // Set operand.
04077:                this .compileSet(c.operand);
04078:
04079:                return type;
04080:            }
04081:
04082:            private IClass compileGet2(Java.ArrayAccessExpression aae)
04083:                    throws CompileException {
04084:                IClass lhsComponentType = this .getType(aae);
04085:                this .writeOpcode(aae, Opcode.IALOAD
04086:                        + UnitCompiler.ilfdabcs(lhsComponentType));
04087:                return lhsComponentType;
04088:            }
04089:
04090:            private IClass compileGet2(Java.FieldAccessExpression fae)
04091:                    throws CompileException {
04092:                this .determineValue(fae);
04093:                return this .compileGet(fae.value);
04094:            }
04095:
04096:            private IClass compileGet2(
04097:                    Java.SuperclassFieldAccessExpression scfae)
04098:                    throws CompileException {
04099:                this .determineValue(scfae);
04100:                return this .compileGet(scfae.value);
04101:            }
04102:
04103:            private IClass compileGet2(Java.UnaryOperation uo)
04104:                    throws CompileException {
04105:                if (uo.operator == "!") {
04106:                    return this .compileGet2((Java.BooleanRvalue) uo);
04107:                }
04108:
04109:                if (uo.operator == "+") {
04110:                    return this .unaryNumericPromotion((Locatable) uo, this 
04111:                            .convertToPrimitiveNumericType((Locatable) uo, this 
04112:                                    .compileGetValue(uo.operand)));
04113:                }
04114:
04115:                if (uo.operator == "-") {
04116:
04117:                    // Special handling for negated literals.
04118:                    if (uo.operand instanceof  Java.Literal) {
04119:                        Java.Literal l = (Java.Literal) uo.operand;
04120:                        this .pushConstant((Locatable) uo, this 
04121:                                .getNegatedConstantValue2(l));
04122:                        return this .unaryNumericPromotion((Locatable) uo, this 
04123:                                .getType2(l));
04124:                    }
04125:
04126:                    IClass promotedType = this .unaryNumericPromotion(
04127:                            (Locatable) uo, this .convertToPrimitiveNumericType(
04128:                                    (Locatable) uo, this 
04129:                                            .compileGetValue(uo.operand)));
04130:                    this .writeOpcode(uo, Opcode.INEG
04131:                            + UnitCompiler.ilfd(promotedType));
04132:                    return promotedType;
04133:                }
04134:
04135:                if (uo.operator == "~") {
04136:                    IClass operandType = this .compileGetValue(uo.operand);
04137:
04138:                    IClass promotedType = this .unaryNumericPromotion(
04139:                            (Locatable) uo, operandType);
04140:                    if (promotedType == IClass.INT) {
04141:                        this .writeOpcode(uo, Opcode.ICONST_M1);
04142:                        this .writeOpcode(uo, Opcode.IXOR);
04143:                        return IClass.INT;
04144:                    }
04145:                    if (promotedType == IClass.LONG) {
04146:                        this .writeOpcode(uo, Opcode.LDC2_W);
04147:                        this .writeConstantLongInfo(-1L);
04148:                        this .writeOpcode(uo, Opcode.LXOR);
04149:                        return IClass.LONG;
04150:                    }
04151:                    this .compileError(
04152:                            "Operator \"~\" not applicable to type \""
04153:                                    + promotedType + "\"", uo.getLocation());
04154:                }
04155:
04156:                this .compileError(
04157:                        "Unexpected operator \"" + uo.operator + "\"", uo
04158:                                .getLocation());
04159:                return this .iClassLoader.OBJECT;
04160:            }
04161:
04162:            private IClass compileGet2(Java.Instanceof io)
04163:                    throws CompileException {
04164:                IClass lhsType = this .compileGetValue(io.lhs);
04165:                IClass rhsType = this .getType(io.rhs);
04166:
04167:                if (rhsType.isAssignableFrom(lhsType)) {
04168:                    this .pop((Locatable) io, lhsType);
04169:                    this .writeOpcode(io, Opcode.ICONST_1);
04170:                } else if (lhsType.isInterface() || rhsType.isInterface()
04171:                        || lhsType.isAssignableFrom(rhsType)) {
04172:                    this .writeOpcode(io, Opcode.INSTANCEOF);
04173:                    this .writeConstantClassInfo(rhsType.getDescriptor());
04174:                } else {
04175:                    this .compileError("\"" + lhsType
04176:                            + "\" can never be an instance of \"" + rhsType
04177:                            + "\"", io.getLocation());
04178:                }
04179:                return IClass.BOOLEAN;
04180:            }
04181:
04182:            private IClass compileGet2(Java.BinaryOperation bo)
04183:                    throws CompileException {
04184:                if (bo.op == "||" || bo.op == "&&" || bo.op == "=="
04185:                        || bo.op == "!=" || bo.op == "<" || bo.op == ">"
04186:                        || bo.op == "<=" || bo.op == ">=") {
04187:                    // Eventually calls "compileBoolean()".
04188:                    return this .compileGet2((Java.BooleanRvalue) bo);
04189:                }
04190:
04191:                // Implements "| ^ & * / % + - << >> >>>".
04192:                return this .compileArithmeticOperation((Locatable) bo, // l
04193:                        null, // type
04194:                        bo.unrollLeftAssociation(), // operands
04195:                        bo.op // operator
04196:                        );
04197:            }
04198:
04199:            private IClass compileGet2(Java.Cast c) throws CompileException {
04200:
04201:                // JLS3 5.5 Casting Conversion
04202:                IClass tt = this .getType(c.targetType);
04203:                IClass vt = this .compileGetValue(c.value);
04204:                if (!this .tryIdentityConversion(vt, tt)
04205:                        && !this .tryWideningPrimitiveConversion((Locatable) c,
04206:                                vt, tt)
04207:                        && !this .tryNarrowingPrimitiveConversion((Locatable) c,
04208:                                vt, tt)
04209:                        && !this .tryWideningReferenceConversion(vt, tt)
04210:                        && !this .tryNarrowingReferenceConversion((Locatable) c,
04211:                                vt, tt)
04212:                        && !this .tryBoxingConversion((Locatable) c, vt, tt)
04213:                        && !this .tryUnboxingConversion((Locatable) c, vt, tt))
04214:                    this .compileError("Cannot cast \"" + vt + "\" to \"" + tt
04215:                            + "\"", c.getLocation());
04216:                return tt;
04217:            }
04218:
04219:            private IClass compileGet2(Java.ParenthesizedExpression pe)
04220:                    throws CompileException {
04221:                return this .compileGet(pe.value);
04222:            }
04223:
04224:            private IClass compileGet2(Java.MethodInvocation mi)
04225:                    throws CompileException {
04226:                IClass.IMethod iMethod = this .findIMethod(mi);
04227:
04228:                if (mi.optionalTarget == null) {
04229:
04230:                    // JLS2 6.5.7.1, 15.12.4.1.1.1
04231:                    Java.TypeBodyDeclaration scopeTBD;
04232:                    Java.ClassDeclaration scopeClassDeclaration;
04233:                    {
04234:                        Java.Scope s;
04235:                        for (s = mi.getEnclosingBlockStatement(); !(s instanceof  Java.TypeBodyDeclaration); s = s
04236:                                .getEnclosingScope())
04237:                            ;
04238:                        scopeTBD = (Java.TypeBodyDeclaration) s;
04239:                        if (!(s instanceof  Java.ClassDeclaration))
04240:                            s = s.getEnclosingScope();
04241:                        scopeClassDeclaration = (Java.ClassDeclaration) s;
04242:                    }
04243:                    if (iMethod.isStatic()) {
04244:                        this .warning("IASM",
04245:                                "Implicit access to static method \""
04246:                                        + iMethod.toString() + "\"", mi
04247:                                        .getLocation());
04248:                        // JLS2 15.12.4.1.1.1.1
04249:                        ;
04250:                    } else {
04251:                        this .warning("IANSM",
04252:                                "Implicit access to non-static method \""
04253:                                        + iMethod.toString() + "\"", mi
04254:                                        .getLocation());
04255:                        // JLS2 15.12.4.1.1.1.2
04256:                        if (scopeTBD.isStatic())
04257:                            this .compileError("Instance method \""
04258:                                    + iMethod.toString()
04259:                                    + "\" cannot be invoked in static context",
04260:                                    mi.getLocation());
04261:                        this .referenceThis((Locatable) mi, // l
04262:                                scopeClassDeclaration, // declaringClass
04263:                                scopeTBD, // declaringTypeBodyDeclaration
04264:                                iMethod.getDeclaringIClass() // targetIClass
04265:                                );
04266:                    }
04267:                } else {
04268:
04269:                    // 6.5.7.2
04270:                    boolean staticContext = this .isType(mi.optionalTarget);
04271:                    if (staticContext) {
04272:                        this .getType(this .toTypeOrCE(mi.optionalTarget));
04273:                    } else {
04274:                        this .compileGetValue(this 
04275:                                .toRvalueOrCE(mi.optionalTarget));
04276:                    }
04277:                    if (iMethod.isStatic()) {
04278:                        if (!staticContext) {
04279:                            // JLS2 15.12.4.1.2.1
04280:                            this .pop((Locatable) mi.optionalTarget, this 
04281:                                    .getType(mi.optionalTarget));
04282:                        }
04283:                    } else {
04284:                        if (staticContext)
04285:                            this .compileError("Instance method \""
04286:                                    + mi.methodName
04287:                                    + "\" cannot be invoked in static context",
04288:                                    mi.getLocation());
04289:                    }
04290:                }
04291:
04292:                // Evaluate method parameters.
04293:                IClass[] parameterTypes = iMethod.getParameterTypes();
04294:                for (int i = 0; i < mi.arguments.length; ++i) {
04295:                    this .assignmentConversion((Locatable) mi, // l
04296:                            this .compileGetValue(mi.arguments[i]), // sourceType
04297:                            parameterTypes[i], // targetType
04298:                            this .getConstantValue(mi.arguments[i]) // optionalConstantValue
04299:                            );
04300:                }
04301:
04302:                // Invoke!
04303:                this .checkAccessible(iMethod, mi.getEnclosingBlockStatement());
04304:                if (iMethod.getDeclaringIClass().isInterface()) {
04305:                    this .writeOpcode(mi, Opcode.INVOKEINTERFACE);
04306:                    this .writeConstantInterfaceMethodrefInfo(iMethod
04307:                            .getDeclaringIClass().getDescriptor(), // locatable
04308:                            iMethod.getName(), // classFD
04309:                            iMethod.getDescriptor() // methodMD
04310:                            );
04311:                    IClass[] pts = iMethod.getParameterTypes();
04312:                    int count = 1;
04313:                    for (int i = 0; i < pts.length; ++i)
04314:                        count += Descriptor.size(pts[i].getDescriptor());
04315:                    this .writeByte(count);
04316:                    this .writeByte(0);
04317:                } else {
04318:                    if (!iMethod.isStatic()
04319:                            && iMethod.getAccess() == Access.PRIVATE) {
04320:
04321:                        // In order to make a non-static private method invocable for enclosing types,
04322:                        // enclosed types and types enclosed by the same type, "compile(FunctionDeclarator)"
04323:                        // modifies it on-the-fly as follows:
04324:                        //  + Access is changed from PRIVATE to PACKAGE
04325:                        //  + The name is appended with "$"
04326:                        //  + It is made static
04327:                        //  + A parameter of type "declaring class" is prepended to the signature
04328:                        // Hence, the invocation of such a method must be modified accordingly.
04329:                        this .writeOpcode(mi, Opcode.INVOKESTATIC);
04330:                        this .writeConstantMethodrefInfo(iMethod
04331:                                .getDeclaringIClass().getDescriptor(), // locatable
04332:                                iMethod.getName() + '$', // classFD
04333:                                MethodDescriptor.prependParameter( // methodMD
04334:                                        iMethod.getDescriptor(), iMethod
04335:                                                .getDeclaringIClass()
04336:                                                .getDescriptor()));
04337:                    } else {
04338:                        byte opcode = iMethod.isStatic() ? Opcode.INVOKESTATIC
04339:                                : Opcode.INVOKEVIRTUAL;
04340:                        this .writeOpcode(mi, opcode);
04341:                        this .writeConstantMethodrefInfo(iMethod
04342:                                .getDeclaringIClass().getDescriptor(), // classFD
04343:                                iMethod.getName(), // methodName
04344:                                iMethod.getDescriptor() // methodMD
04345:                                );
04346:                    }
04347:                }
04348:                return iMethod.getReturnType();
04349:            }
04350:
04351:            private IClass compileGet2(Java.SuperclassMethodInvocation scmi)
04352:                    throws CompileException {
04353:                IClass.IMethod iMethod = this .findIMethod(scmi);
04354:
04355:                Java.Scope s;
04356:                for (s = scmi.getEnclosingBlockStatement(); s instanceof  Java.Statement
04357:                        || s instanceof  Java.CatchClause; s = s
04358:                        .getEnclosingScope())
04359:                    ;
04360:                Java.FunctionDeclarator fd = s instanceof  Java.FunctionDeclarator ? (Java.FunctionDeclarator) s
04361:                        : null;
04362:                if (fd == null) {
04363:                    this 
04364:                            .compileError(
04365:                                    "Cannot invoke superclass method in non-method scope",
04366:                                    scmi.getLocation());
04367:                    return IClass.INT;
04368:                }
04369:                if ((fd.modifiers & Mod.STATIC) != 0)
04370:                    this 
04371:                            .compileError(
04372:                                    "Cannot invoke superclass method in static context",
04373:                                    scmi.getLocation());
04374:                this .load((Locatable) scmi,
04375:                        this .resolve(fd.getDeclaringType()), 0);
04376:
04377:                // Evaluate method parameters.
04378:                IClass[] parameterTypes = iMethod.getParameterTypes();
04379:                for (int i = 0; i < scmi.arguments.length; ++i) {
04380:                    this .assignmentConversion((Locatable) scmi, // l
04381:                            this .compileGetValue(scmi.arguments[i]), // sourceType
04382:                            parameterTypes[i], // targetType
04383:                            this .getConstantValue(scmi.arguments[i]) // optionalConstantValue
04384:                            );
04385:                }
04386:
04387:                // Invoke!
04388:                this .writeOpcode(scmi, Opcode.INVOKESPECIAL);
04389:                this .writeConstantMethodrefInfo(iMethod.getDeclaringIClass()
04390:                        .getDescriptor(), // classFD
04391:                        scmi.methodName, // methodName
04392:                        iMethod.getDescriptor() // methodMD
04393:                        );
04394:                return iMethod.getReturnType();
04395:            }
04396:
04397:            private IClass compileGet2(Java.NewClassInstance nci)
04398:                    throws CompileException {
04399:                if (nci.iClass == null)
04400:                    nci.iClass = this .getType(nci.type);
04401:
04402:                this .writeOpcode(nci, Opcode.NEW);
04403:                this .writeConstantClassInfo(nci.iClass.getDescriptor());
04404:                this .writeOpcode(nci, Opcode.DUP);
04405:
04406:                if (nci.iClass.isInterface())
04407:                    this .compileError("Cannot instantiate \"" + nci.iClass
04408:                            + "\"", nci.getLocation());
04409:                this .checkAccessible(nci.iClass, nci
04410:                        .getEnclosingBlockStatement());
04411:                if (nci.iClass.isAbstract())
04412:                    this .compileError("Cannot instantiate abstract \""
04413:                            + nci.iClass + "\"", nci.getLocation());
04414:
04415:                // Determine the enclosing instance for the new object.
04416:                Java.Rvalue optionalEnclosingInstance;
04417:                if (nci.optionalQualification != null) {
04418:                    if (nci.iClass.getOuterIClass() == null)
04419:                        this 
04420:                                .compileError("Static member class cannot be instantiated with qualified NEW");
04421:
04422:                    // Enclosing instance defined by qualification (JLS 15.9.2.BL1.B3.B2).
04423:                    optionalEnclosingInstance = nci.optionalQualification;
04424:                } else {
04425:                    Java.Scope s = nci.getEnclosingBlockStatement();
04426:                    for (; !(s instanceof  Java.TypeBodyDeclaration); s = s
04427:                            .getEnclosingScope())
04428:                        ;
04429:                    Java.TypeBodyDeclaration enclosingTypeBodyDeclaration = (Java.TypeBodyDeclaration) s;
04430:                    Java.TypeDeclaration enclosingTypeDeclaration = (Java.TypeDeclaration) s
04431:                            .getEnclosingScope();
04432:
04433:                    if (!(enclosingTypeDeclaration instanceof  Java.ClassDeclaration)
04434:                            || enclosingTypeBodyDeclaration.isStatic()) {
04435:
04436:                        // No enclosing instance in
04437:                        //  + interface method declaration or
04438:                        //  + static type body declaration (here: method or initializer or field declarator)
04439:                        // context (JLS 15.9.2.BL1.B3.B1.B1).
04440:                        if (nci.iClass.getOuterIClass() != null)
04441:                            this .compileError("Instantiation of \"" + nci.type
04442:                                    + "\" requires an enclosing instance", nci
04443:                                    .getLocation());
04444:                        optionalEnclosingInstance = null;
04445:                    } else {
04446:
04447:                        // Determine the type of the enclosing instance for the new object.
04448:                        IClass optionalOuterIClass = nci.iClass
04449:                                .getDeclaringIClass();
04450:                        if (optionalOuterIClass == null) {
04451:
04452:                            // No enclosing instance needed for a top-level class object.
04453:                            optionalEnclosingInstance = null;
04454:                        } else {
04455:
04456:                            // Find an appropriate enclosing instance for the new inner class object among
04457:                            // the enclosing instances of the current object (JLS
04458:                            // 15.9.2.BL1.B3.B1.B2).
04459:                            //                    Java.ClassDeclaration outerClassDeclaration = (Java.ClassDeclaration) enclosingTypeDeclaration;
04460:                            //                    optionalEnclosingInstance = new Java.QualifiedThisReference(
04461:                            //                        nci.getLocation(),            // location
04462:                            //                        outerClassDeclaration,        // declaringClass
04463:                            //                        enclosingTypeBodyDeclaration, // declaringTypeBodyDeclaration
04464:                            //                        optionalOuterIClass           // targetIClass
04465:                            //                    );
04466:                            optionalEnclosingInstance = new Java.QualifiedThisReference(
04467:                                    nci.getLocation(), // location
04468:                                    new Java.SimpleType(
04469:                                            // qualification
04470:                                            nci.getLocation(),
04471:                                            optionalOuterIClass));
04472:                            optionalEnclosingInstance
04473:                                    .setEnclosingBlockStatement(nci
04474:                                            .getEnclosingBlockStatement());
04475:                        }
04476:                    }
04477:                }
04478:
04479:                this .invokeConstructor((Locatable) nci, // l
04480:                        nci.getEnclosingBlockStatement(), // scope
04481:                        optionalEnclosingInstance, // optionalEnclosingInstance
04482:                        nci.iClass, // targetClass
04483:                        nci.arguments // arguments
04484:                        );
04485:                return nci.iClass;
04486:            }
04487:
04488:            private IClass compileGet2(Java.NewAnonymousClassInstance naci)
04489:                    throws CompileException {
04490:
04491:                // Find constructors.
04492:                Java.AnonymousClassDeclaration acd = naci.anonymousClassDeclaration;
04493:                IClass sc = this .resolve(acd).getSuperclass();
04494:                IClass.IConstructor[] iConstructors = sc
04495:                        .getDeclaredIConstructors();
04496:                if (iConstructors.length == 0)
04497:                    throw new RuntimeException(
04498:                            "SNO: Base class has no constructors");
04499:
04500:                // Determine most specific constructor.
04501:                IClass.IConstructor iConstructor = (IClass.IConstructor) this 
04502:                        .findMostSpecificIInvocable((Locatable) naci, // l
04503:                                iConstructors, // iInvocables
04504:                                naci.arguments // arguments
04505:                        );
04506:
04507:                IClass[] pts = iConstructor.getParameterTypes();
04508:
04509:                // Determine formal parameters of anonymous constructor.
04510:                Java.FunctionDeclarator.FormalParameter[] fps;
04511:                Location loc = naci.getLocation();
04512:                {
04513:                    List l = new ArrayList(); // FormalParameter
04514:
04515:                    // Pass the enclosing instance of the base class as parameter #1.
04516:                    if (naci.optionalQualification != null)
04517:                        l.add(new Java.FunctionDeclarator.FormalParameter(loc, // location
04518:                                true, // finaL
04519:                                new Java.SimpleType(loc, this 
04520:                                        .getType(naci.optionalQualification)), // type
04521:                                "this$base" // name
04522:                        ));
04523:                    for (int i = 0; i < pts.length; ++i)
04524:                        l.add(new Java.FunctionDeclarator.FormalParameter(loc, // location
04525:                                true, // finaL
04526:                                new Java.SimpleType(loc, pts[i]), // type
04527:                                "p" + i // name
04528:                        ));
04529:                    fps = (Java.FunctionDeclarator.FormalParameter[]) l
04530:                            .toArray(new Java.FunctionDeclarator.FormalParameter[l
04531:                                    .size()]);
04532:                }
04533:
04534:                // Determine thrown exceptions of anonymous constructor.
04535:                IClass[] tes = iConstructor.getThrownExceptions();
04536:                Java.Type[] tets = new Java.Type[tes.length];
04537:                for (int i = 0; i < tes.length; ++i)
04538:                    tets[i] = new Java.SimpleType(loc, tes[i]);
04539:
04540:                // The anonymous constructor merely invokes the constructor of its superclass.
04541:                int j = 0;
04542:                Java.Rvalue optionalQualificationAccess;
04543:                if (naci.optionalQualification == null) {
04544:                    optionalQualificationAccess = null;
04545:                } else {
04546:                    optionalQualificationAccess = new Java.ParameterAccess(loc,
04547:                            fps[j++]);
04548:                }
04549:                Java.Rvalue[] parameterAccesses = new Java.Rvalue[pts.length];
04550:                for (int i = 0; i < pts.length; ++i) {
04551:                    parameterAccesses[i] = new Java.ParameterAccess(loc,
04552:                            fps[j++]);
04553:                }
04554:
04555:                // Generate the anonymous constructor for the anonymous class (JLS 15.9.5.1).
04556:                acd.addConstructor(new Java.ConstructorDeclarator(loc, // location
04557:                        null, // optionalDocComment
04558:                        Mod.PACKAGE, // modifiers
04559:                        fps, // formalParameters
04560:                        tets, // thrownExceptions
04561:                        new Java.SuperConstructorInvocation( // optionalExplicitConstructorInvocation
04562:                                loc, // location
04563:                                optionalQualificationAccess, // optionalQualification
04564:                                parameterAccesses // arguments
04565:                        ), new Java.Block(loc) // optionalBody
04566:                        ));
04567:
04568:                // Compile the anonymous class.
04569:                this .compile(acd);
04570:
04571:                // Instantiate the anonymous class.
04572:                this .writeOpcode(naci, Opcode.NEW);
04573:                this .writeConstantClassInfo(this .resolve(
04574:                        naci.anonymousClassDeclaration).getDescriptor());
04575:
04576:                // Invoke the anonymous constructor.
04577:                this .writeOpcode(naci, Opcode.DUP);
04578:                Java.Rvalue[] arguments2;
04579:                if (naci.optionalQualification == null) {
04580:                    arguments2 = naci.arguments;
04581:                } else {
04582:                    arguments2 = new Java.Rvalue[naci.arguments.length + 1];
04583:                    arguments2[0] = naci.optionalQualification;
04584:                    System.arraycopy(naci.arguments, 0, arguments2, 1,
04585:                            naci.arguments.length);
04586:                }
04587:
04588:                // Notice: The enclosing instance of the anonymous class is "this", not the
04589:                // qualification of the NewAnonymousClassInstance.
04590:                Java.Scope s;
04591:                for (s = naci.getEnclosingBlockStatement(); !(s instanceof  Java.TypeBodyDeclaration); s = s
04592:                        .getEnclosingScope())
04593:                    ;
04594:                Java.ThisReference oei;
04595:                if (((Java.TypeBodyDeclaration) s).isStatic()) {
04596:                    oei = null;
04597:                } else {
04598:                    oei = new Java.ThisReference(loc);
04599:                    oei.setEnclosingBlockStatement(naci
04600:                            .getEnclosingBlockStatement());
04601:                }
04602:                this .invokeConstructor((Locatable) naci, // l
04603:                        (Java.Scope) naci.getEnclosingBlockStatement(), // scope
04604:                        oei, // optionalEnclosingInstance
04605:                        this .resolve(naci.anonymousClassDeclaration), // targetClass
04606:                        arguments2 // arguments
04607:                        );
04608:                return this .resolve(naci.anonymousClassDeclaration);
04609:            }
04610:
04611:            private IClass compileGet2(Java.ParameterAccess pa)
04612:                    throws CompileException {
04613:                Java.LocalVariable lv = this 
04614:                        .getLocalVariable(pa.formalParameter);
04615:                this .load((Locatable) pa, lv);
04616:                return lv.type;
04617:            }
04618:
04619:            private IClass compileGet2(Java.NewArray na)
04620:                    throws CompileException {
04621:                for (int i = 0; i < na.dimExprs.length; ++i) {
04622:                    IClass dimType = this .compileGetValue(na.dimExprs[i]);
04623:                    if (dimType != IClass.INT
04624:                            && this .unaryNumericPromotion((Locatable) na, // l
04625:                                    dimType // type
04626:                                    ) != IClass.INT)
04627:                        this .compileError("Invalid array size expression type",
04628:                                na.getLocation());
04629:                }
04630:
04631:                return this .newArray((Locatable) na, // l
04632:                        na.dimExprs.length, // dimExprCount
04633:                        na.dims, // dims
04634:                        this .getType(na.type) // componentType
04635:                        );
04636:            }
04637:
04638:            private IClass compileGet2(Java.NewInitializedArray nia)
04639:                    throws CompileException {
04640:                IClass at = this .getType(nia.arrayType);
04641:                this .compileGetValue(nia.arrayInitializer, at);
04642:                return at;
04643:            }
04644:
04645:            private void compileGetValue(Java.ArrayInitializer ai,
04646:                    IClass arrayType) throws CompileException {
04647:                if (!arrayType.isArray())
04648:                    this 
04649:                            .compileError("Array initializer not allowed for non-array type \""
04650:                                    + arrayType.toString() + "\"");
04651:                IClass ct = arrayType.getComponentType();
04652:
04653:                this 
04654:                        .pushConstant((Locatable) ai, new Integer(
04655:                                ai.values.length));
04656:                this .newArray((Locatable) ai, // l
04657:                        1, // dimExprCount,
04658:                        0, // dims,
04659:                        ct // componentType
04660:                        );
04661:
04662:                for (int i = 0; i < ai.values.length; ++i) {
04663:                    this .writeOpcode(ai, Opcode.DUP);
04664:                    this .pushConstant((Locatable) ai, new Integer(i));
04665:                    Java.ArrayInitializerOrRvalue aiorv = ai.values[i];
04666:                    if (aiorv instanceof  Java.Rvalue) {
04667:                        Java.Rvalue rv = (Java.Rvalue) aiorv;
04668:                        this .assignmentConversion((Locatable) ai, // l
04669:                                this .compileGetValue(rv), // sourceType
04670:                                ct, // targetType
04671:                                this .getConstantValue(rv) // optionalConstantValue
04672:                                );
04673:                    } else if (aiorv instanceof  Java.ArrayInitializer) {
04674:                        this .compileGetValue((Java.ArrayInitializer) aiorv, ct);
04675:                    } else {
04676:                        throw new RuntimeException(
04677:                                "Unexpected array initializer or rvalue class "
04678:                                        + aiorv.getClass().getName());
04679:                    }
04680:                    this .writeOpcode(ai, Opcode.IASTORE
04681:                            + UnitCompiler.ilfdabcs(ct));
04682:                }
04683:            }
04684:
04685:            private IClass compileGet2(Java.Literal l) throws CompileException {
04686:                if (l.value == Scanner.MAGIC_INTEGER
04687:                        || l.value == Scanner.MAGIC_LONG)
04688:                    this 
04689:                            .compileError(
04690:                                    "This literal value may only appear in a negated context",
04691:                                    l.getLocation());
04692:                return this .pushConstant((Locatable) l,
04693:                        l.value == null ? Java.Rvalue.CONSTANT_VALUE_NULL
04694:                                : l.value);
04695:            }
04696:
04697:            private IClass compileGet2(Java.ConstantValue cv) {
04698:                return this .pushConstant((Locatable) cv, cv.constantValue);
04699:            }
04700:
04701:            /**
04702:             * Convenience function that calls {@link #compileContext(Java.Rvalue)}
04703:             * and {@link #compileGet(Java.Rvalue)}.
04704:             * @return The type of the Rvalue
04705:             */
04706:            private IClass compileGetValue(Java.Rvalue rv)
04707:                    throws CompileException {
04708:                Object cv = this .getConstantValue(rv);
04709:                if (cv != null) {
04710:                    this .fakeCompile(rv); // To check that, e.g., "a" compiles in "true || a".
04711:                    this .pushConstant((Locatable) rv, cv);
04712:                    return this .getType(rv);
04713:                }
04714:
04715:                this .compileContext(rv);
04716:                return this .compileGet(rv);
04717:            }
04718:
04719:            // -------------------- Rvalue.getConstantValue() -----------------
04720:
04721:            /**
04722:             * Attempts to evaluate as a constant expression.
04723:             * <p>
04724:             * <table>
04725:             *   <tr><th>Expression type</th><th>Return value type</th></tr>
04726:             *   <tr><td>String</td><td>String</td></tr>
04727:             *   <tr><td>byte</td><td>Byte</td></tr>
04728:             *   <tr><td>short</td><td>Chort</td></tr>
04729:             *   <tr><td>int</td><td>Integer</td></tr>
04730:             *   <tr><td>boolean</td><td>Boolean</td></tr>
04731:             *   <tr><td>char</td><td>Character</td></tr>
04732:             *   <tr><td>float</td><td>Float</td></tr>
04733:             *   <tr><td>long</td><td>Long</td></tr>
04734:             *   <tr><td>double</td><td>Double</td></tr>
04735:             *   <tr><td>null</td><td>{@link Java.Rvalue#CONSTANT_VALUE_NULL}</td></tr>
04736:             * </table>
04737:             */
04738:            public final Object getConstantValue(Java.Rvalue rv)
04739:                    throws CompileException {
04740:                if (rv.constantValue != Java.Rvalue.CONSTANT_VALUE_UNKNOWN)
04741:                    return rv.constantValue;
04742:
04743:                final Object[] res = new Object[1];
04744:                class UCE extends RuntimeException {
04745:                    final CompileException ce;
04746:
04747:                    UCE(CompileException ce) {
04748:                        this .ce = ce;
04749:                    }
04750:                }
04751:                Visitor.RvalueVisitor rvv = new Visitor.RvalueVisitor() {
04752:                    public void visitArrayLength(Java.ArrayLength al) {
04753:                        res[0] = UnitCompiler.this .getConstantValue2(al);
04754:                    }
04755:
04756:                    public void visitAssignment(Java.Assignment a) {
04757:                        res[0] = UnitCompiler.this .getConstantValue2(a);
04758:                    }
04759:
04760:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
04761:                        try {
04762:                            res[0] = UnitCompiler.this .getConstantValue2(uo);
04763:                        } catch (CompileException e) {
04764:                            throw new UCE(e);
04765:                        }
04766:                    }
04767:
04768:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
04769:                        try {
04770:                            res[0] = UnitCompiler.this .getConstantValue2(bo);
04771:                        } catch (CompileException e) {
04772:                            throw new UCE(e);
04773:                        }
04774:                    }
04775:
04776:                    public void visitCast(Java.Cast c) {
04777:                        try {
04778:                            res[0] = UnitCompiler.this .getConstantValue2(c);
04779:                        } catch (CompileException e) {
04780:                            throw new UCE(e);
04781:                        }
04782:                    }
04783:
04784:                    public void visitClassLiteral(Java.ClassLiteral cl) {
04785:                        res[0] = UnitCompiler.this .getConstantValue2(cl);
04786:                    }
04787:
04788:                    public void visitConditionalExpression(
04789:                            Java.ConditionalExpression ce) {
04790:                        res[0] = UnitCompiler.this .getConstantValue2(ce);
04791:                    }
04792:
04793:                    public void visitConstantValue(Java.ConstantValue cv) {
04794:                        res[0] = UnitCompiler.this .getConstantValue2(cv);
04795:                    }
04796:
04797:                    public void visitCrement(Java.Crement c) {
04798:                        res[0] = UnitCompiler.this .getConstantValue2(c);
04799:                    }
04800:
04801:                    public void visitInstanceof(Java.Instanceof io) {
04802:                        res[0] = UnitCompiler.this .getConstantValue2(io);
04803:                    }
04804:
04805:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
04806:                        res[0] = UnitCompiler.this .getConstantValue2(mi);
04807:                    }
04808:
04809:                    public void visitSuperclassMethodInvocation(
04810:                            Java.SuperclassMethodInvocation smi) {
04811:                        res[0] = UnitCompiler.this .getConstantValue2(smi);
04812:                    }
04813:
04814:                    public void visitLiteral(Java.Literal l) {
04815:                        try {
04816:                            res[0] = UnitCompiler.this .getConstantValue2(l);
04817:                        } catch (CompileException e) {
04818:                            throw new UCE(e);
04819:                        }
04820:                    }
04821:
04822:                    public void visitNewAnonymousClassInstance(
04823:                            Java.NewAnonymousClassInstance naci) {
04824:                        res[0] = UnitCompiler.this .getConstantValue2(naci);
04825:                    }
04826:
04827:                    public void visitNewArray(Java.NewArray na) {
04828:                        res[0] = UnitCompiler.this .getConstantValue2(na);
04829:                    }
04830:
04831:                    public void visitNewInitializedArray(
04832:                            Java.NewInitializedArray nia) {
04833:                        res[0] = UnitCompiler.this .getConstantValue2(nia);
04834:                    }
04835:
04836:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
04837:                        res[0] = UnitCompiler.this .getConstantValue2(nci);
04838:                    }
04839:
04840:                    public void visitParameterAccess(Java.ParameterAccess pa) {
04841:                        res[0] = UnitCompiler.this .getConstantValue2(pa);
04842:                    }
04843:
04844:                    public void visitQualifiedThisReference(
04845:                            Java.QualifiedThisReference qtr) {
04846:                        res[0] = UnitCompiler.this .getConstantValue2(qtr);
04847:                    }
04848:
04849:                    public void visitThisReference(Java.ThisReference tr) {
04850:                        res[0] = UnitCompiler.this .getConstantValue2(tr);
04851:                    }
04852:
04853:                    public void visitAmbiguousName(Java.AmbiguousName an) {
04854:                        try {
04855:                            res[0] = UnitCompiler.this .getConstantValue2(an);
04856:                        } catch (CompileException e) {
04857:                            throw new UCE(e);
04858:                        }
04859:                    }
04860:
04861:                    public void visitArrayAccessExpression(
04862:                            Java.ArrayAccessExpression aae) {
04863:                        res[0] = UnitCompiler.this .getConstantValue2(aae);
04864:                    }
04865:
04866:                    public void visitFieldAccess(Java.FieldAccess fa) {
04867:                        try {
04868:                            res[0] = UnitCompiler.this .getConstantValue2(fa);
04869:                        } catch (CompileException e) {
04870:                            throw new UCE(e);
04871:                        }
04872:                    }
04873:
04874:                    public void visitFieldAccessExpression(
04875:                            Java.FieldAccessExpression fae) {
04876:                        res[0] = UnitCompiler.this .getConstantValue2(fae);
04877:                    }
04878:
04879:                    public void visitSuperclassFieldAccessExpression(
04880:                            Java.SuperclassFieldAccessExpression scfae) {
04881:                        res[0] = UnitCompiler.this .getConstantValue2(scfae);
04882:                    }
04883:
04884:                    public void visitLocalVariableAccess(
04885:                            Java.LocalVariableAccess lva) {
04886:                        res[0] = UnitCompiler.this .getConstantValue2(lva);
04887:                    }
04888:
04889:                    public void visitParenthesizedExpression(
04890:                            Java.ParenthesizedExpression pe) {
04891:                        try {
04892:                            res[0] = UnitCompiler.this .getConstantValue2(pe);
04893:                        } catch (CompileException e) {
04894:                            throw new UCE(e);
04895:                        }
04896:                    }
04897:                };
04898:                try {
04899:                    rv.accept(rvv);
04900:                    rv.constantValue = res[0];
04901:                    return rv.constantValue;
04902:                } catch (UCE uce) {
04903:                    throw uce.ce;
04904:                }
04905:            }
04906:
04907:            private Object getConstantValue2(Java.Rvalue rv) {
04908:                return null;
04909:            }
04910:
04911:            private Object getConstantValue2(Java.AmbiguousName an)
04912:                    throws CompileException {
04913:                return this .getConstantValue(this .toRvalueOrCE(this 
04914:                        .reclassify(an)));
04915:            }
04916:
04917:            private Object getConstantValue2(Java.FieldAccess fa)
04918:                    throws CompileException {
04919:                return fa.field.getConstantValue();
04920:            }
04921:
04922:            private Object getConstantValue2(Java.UnaryOperation uo)
04923:                    throws CompileException {
04924:                if (uo.operator.equals("+"))
04925:                    return this .getConstantValue(uo.operand);
04926:                if (uo.operator.equals("-"))
04927:                    return this .getNegatedConstantValue(uo.operand);
04928:                if (uo.operator.equals("!")) {
04929:                    Object cv = this .getConstantValue(uo.operand);
04930:                    return cv instanceof  Boolean ? (((Boolean) cv)
04931:                            .booleanValue() ? Boolean.FALSE : Boolean.TRUE)
04932:                            : null;
04933:                }
04934:                return null;
04935:            }
04936:
04937:            private Object getConstantValue2(Java.BinaryOperation bo)
04938:                    throws CompileException {
04939:
04940:                // null == null
04941:                // null != null
04942:                if ((bo.op == "==" || bo.op == "!=")
04943:                        && this .getConstantValue(bo.lhs) == Java.Rvalue.CONSTANT_VALUE_NULL
04944:                        && this .getConstantValue(bo.rhs) == Java.Rvalue.CONSTANT_VALUE_NULL)
04945:                    return bo.op == "==" ? Boolean.TRUE : Boolean.FALSE;
04946:
04947:                // "|", "^", "&", "*", "/", "%", "+", "-".
04948:                if (bo.op == "|" || bo.op == "^" || bo.op == "&"
04949:                        || bo.op == "*" || bo.op == "/" || bo.op == "%"
04950:                        || bo.op == "+" || bo.op == "-") {
04951:
04952:                    // Unroll the constant operands.
04953:                    List cvs = new ArrayList();
04954:                    for (Iterator it = bo.unrollLeftAssociation(); it.hasNext();) {
04955:                        Object cv = this .getConstantValue(((Java.Rvalue) it
04956:                                .next()));
04957:                        if (cv == null)
04958:                            return null;
04959:                        cvs.add(cv);
04960:                    }
04961:
04962:                    // Compute the constant value of the unrolled binary operation.
04963:                    Iterator it = cvs.iterator();
04964:                    Object lhs = it.next();
04965:                    while (it.hasNext()) {
04966:                        Object rhs = it.next();
04967:
04968:                        // String concatenation?
04969:                        if (bo.op == "+"
04970:                                && (lhs instanceof  String || rhs instanceof  String)) {
04971:                            StringBuffer sb = new StringBuffer();
04972:                            sb.append(lhs.toString()).append(rhs.toString());
04973:                            while (it.hasNext())
04974:                                sb.append(it.next().toString());
04975:                            return sb.toString();
04976:                        }
04977:
04978:                        if (!(lhs instanceof  Number)
04979:                                || !(rhs instanceof  Number))
04980:                            return null;
04981:
04982:                        // Numeric binary operation.
04983:                        if (lhs instanceof  Double || rhs instanceof  Double) {
04984:                            double lhsD = ((Number) lhs).doubleValue();
04985:                            double rhsD = ((Number) rhs).doubleValue();
04986:                            double cvD;
04987:                            if (bo.op == "*")
04988:                                cvD = lhsD * rhsD;
04989:                            else if (bo.op == "/")
04990:                                cvD = lhsD / rhsD;
04991:                            else if (bo.op == "%")
04992:                                cvD = lhsD % rhsD;
04993:                            else if (bo.op == "+")
04994:                                cvD = lhsD + rhsD;
04995:                            else if (bo.op == "-")
04996:                                cvD = lhsD - rhsD;
04997:                            else
04998:                                return null;
04999:                            lhs = new Double(cvD);
05000:                        } else if (lhs instanceof  Float || rhs instanceof  Float) {
05001:                            float lhsF = ((Number) lhs).floatValue();
05002:                            float rhsF = ((Number) rhs).floatValue();
05003:                            float cvF;
05004:                            if (bo.op == "*")
05005:                                cvF = lhsF * rhsF;
05006:                            else if (bo.op == "/")
05007:                                cvF = lhsF / rhsF;
05008:                            else if (bo.op == "%")
05009:                                cvF = lhsF % rhsF;
05010:                            else if (bo.op == "+")
05011:                                cvF = lhsF + rhsF;
05012:                            else if (bo.op == "-")
05013:                                cvF = lhsF - rhsF;
05014:                            else
05015:                                return null;
05016:                            lhs = new Float(cvF);
05017:                        } else if (lhs instanceof  Long || rhs instanceof  Long) {
05018:                            long lhsL = ((Number) lhs).longValue();
05019:                            long rhsL = ((Number) rhs).longValue();
05020:                            long cvL;
05021:                            if (bo.op == "|")
05022:                                cvL = lhsL | rhsL;
05023:                            else if (bo.op == "^")
05024:                                cvL = lhsL ^ rhsL;
05025:                            else if (bo.op == "&")
05026:                                cvL = lhsL & rhsL;
05027:                            else if (bo.op == "*")
05028:                                cvL = lhsL * rhsL;
05029:                            else if (bo.op == "/")
05030:                                cvL = lhsL / rhsL;
05031:                            else if (bo.op == "%")
05032:                                cvL = lhsL % rhsL;
05033:                            else if (bo.op == "+")
05034:                                cvL = lhsL + rhsL;
05035:                            else if (bo.op == "-")
05036:                                cvL = lhsL - rhsL;
05037:                            else
05038:                                return null;
05039:                            lhs = new Long(cvL);
05040:                        } else {
05041:                            int lhsI = ((Number) lhs).intValue();
05042:                            int rhsI = ((Number) rhs).intValue();
05043:                            int cvI;
05044:                            if (bo.op == "|")
05045:                                cvI = lhsI | rhsI;
05046:                            else if (bo.op == "^")
05047:                                cvI = lhsI ^ rhsI;
05048:                            else if (bo.op == "&")
05049:                                cvI = lhsI & rhsI;
05050:                            else if (bo.op == "*")
05051:                                cvI = lhsI * rhsI;
05052:                            else if (bo.op == "/")
05053:                                cvI = lhsI / rhsI;
05054:                            else if (bo.op == "%")
05055:                                cvI = lhsI % rhsI;
05056:                            else if (bo.op == "+")
05057:                                cvI = lhsI + rhsI;
05058:                            else if (bo.op == "-")
05059:                                cvI = lhsI - rhsI;
05060:                            else
05061:                                return null;
05062:                            lhs = new Integer(cvI);
05063:                        }
05064:                    }
05065:                    return lhs;
05066:                }
05067:
05068:                // "&&" and "||" with constant LHS operand.
05069:                if (bo.op == "&&" || bo.op == "||") {
05070:                    Object lhsValue = this .getConstantValue(bo.lhs);
05071:                    if (lhsValue instanceof  Boolean) {
05072:                        boolean lhsBV = ((Boolean) lhsValue).booleanValue();
05073:                        return (bo.op == "&&" ? (lhsBV ? this 
05074:                                .getConstantValue(bo.rhs) : Boolean.FALSE)
05075:                                : (lhsBV ? Boolean.TRUE : this 
05076:                                        .getConstantValue(bo.rhs)));
05077:                    }
05078:                }
05079:
05080:                return null;
05081:            }
05082:
05083:            private Object getConstantValue2(Java.Cast c)
05084:                    throws CompileException {
05085:                Object cv = this .getConstantValue(c.value);
05086:                if (cv == null)
05087:                    return null;
05088:
05089:                if (cv instanceof  Number) {
05090:                    IClass tt = this .getType(c.targetType);
05091:                    if (tt == IClass.BYTE)
05092:                        return new Byte(((Number) cv).byteValue());
05093:                    if (tt == IClass.SHORT)
05094:                        return new Short(((Number) cv).shortValue());
05095:                    if (tt == IClass.INT)
05096:                        return new Integer(((Number) cv).intValue());
05097:                    if (tt == IClass.LONG)
05098:                        return new Long(((Number) cv).longValue());
05099:                    if (tt == IClass.FLOAT)
05100:                        return new Float(((Number) cv).floatValue());
05101:                    if (tt == IClass.DOUBLE)
05102:                        return new Double(((Number) cv).doubleValue());
05103:                }
05104:
05105:                return null;
05106:            }
05107:
05108:            private Object getConstantValue2(Java.ParenthesizedExpression pe)
05109:                    throws CompileException {
05110:                return this .getConstantValue(pe.value);
05111:            }
05112:
05113:            private Object getConstantValue2(Java.Literal l)
05114:                    throws CompileException {
05115:                if (l.value == Scanner.MAGIC_INTEGER
05116:                        || l.value == Scanner.MAGIC_LONG)
05117:                    this 
05118:                            .compileError(
05119:                                    "This literal value may only appear in a negated context",
05120:                                    l.getLocation());
05121:                return l.value == null ? Java.Rvalue.CONSTANT_VALUE_NULL
05122:                        : l.value;
05123:            }
05124:
05125:            private Object getConstantValue2(Java.ConstantValue cv) {
05126:                return cv.constantValue;
05127:            }
05128:
05129:            /**
05130:             * Attempts to evaluate the negated value of a constant {@link Java.Rvalue}.
05131:             * This is particularly relevant for the smallest value of an integer or
05132:             * long literal.
05133:             *
05134:             * @return null if value is not constant; otherwise a String, Byte,
05135:             * Short, Integer, Boolean, Character, Float, Long or Double
05136:             */
05137:            private final Object getNegatedConstantValue(Java.Rvalue rv)
05138:                    throws CompileException {
05139:                final Object[] res = new Object[1];
05140:                class UCE extends RuntimeException {
05141:                    final CompileException ce;
05142:
05143:                    UCE(CompileException ce) {
05144:                        this .ce = ce;
05145:                    }
05146:                }
05147:                Visitor.RvalueVisitor rvv = new Visitor.RvalueVisitor() {
05148:                    public void visitArrayLength(Java.ArrayLength al) {
05149:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(al);
05150:                    }
05151:
05152:                    public void visitAssignment(Java.Assignment a) {
05153:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(a);
05154:                    }
05155:
05156:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
05157:                        try {
05158:                            res[0] = UnitCompiler.this 
05159:                                    .getNegatedConstantValue2(uo);
05160:                        } catch (CompileException e) {
05161:                            throw new UCE(e);
05162:                        }
05163:                    }
05164:
05165:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
05166:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(bo);
05167:                    }
05168:
05169:                    public void visitCast(Java.Cast c) {
05170:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(c);
05171:                    }
05172:
05173:                    public void visitClassLiteral(Java.ClassLiteral cl) {
05174:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(cl);
05175:                    }
05176:
05177:                    public void visitConditionalExpression(
05178:                            Java.ConditionalExpression ce) {
05179:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(ce);
05180:                    }
05181:
05182:                    public void visitConstantValue(Java.ConstantValue cv) {
05183:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(cv);
05184:                    }
05185:
05186:                    public void visitCrement(Java.Crement c) {
05187:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(c);
05188:                    }
05189:
05190:                    public void visitInstanceof(Java.Instanceof io) {
05191:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(io);
05192:                    }
05193:
05194:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
05195:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(mi);
05196:                    }
05197:
05198:                    public void visitSuperclassMethodInvocation(
05199:                            Java.SuperclassMethodInvocation smi) {
05200:                        res[0] = UnitCompiler.this 
05201:                                .getNegatedConstantValue2(smi);
05202:                    }
05203:
05204:                    public void visitLiteral(Java.Literal l) {
05205:                        try {
05206:                            res[0] = UnitCompiler.this 
05207:                                    .getNegatedConstantValue2(l);
05208:                        } catch (CompileException e) {
05209:                            throw new UCE(e);
05210:                        }
05211:                    }
05212:
05213:                    public void visitNewAnonymousClassInstance(
05214:                            Java.NewAnonymousClassInstance naci) {
05215:                        res[0] = UnitCompiler.this 
05216:                                .getNegatedConstantValue2(naci);
05217:                    }
05218:
05219:                    public void visitNewArray(Java.NewArray na) {
05220:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(na);
05221:                    }
05222:
05223:                    public void visitNewInitializedArray(
05224:                            Java.NewInitializedArray nia) {
05225:                        res[0] = UnitCompiler.this 
05226:                                .getNegatedConstantValue2(nia);
05227:                    }
05228:
05229:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
05230:                        res[0] = UnitCompiler.this 
05231:                                .getNegatedConstantValue2(nci);
05232:                    }
05233:
05234:                    public void visitParameterAccess(Java.ParameterAccess pa) {
05235:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(pa);
05236:                    }
05237:
05238:                    public void visitQualifiedThisReference(
05239:                            Java.QualifiedThisReference qtr) {
05240:                        res[0] = UnitCompiler.this 
05241:                                .getNegatedConstantValue2(qtr);
05242:                    }
05243:
05244:                    public void visitThisReference(Java.ThisReference tr) {
05245:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(tr);
05246:                    }
05247:
05248:                    public void visitAmbiguousName(Java.AmbiguousName an) {
05249:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(an);
05250:                    }
05251:
05252:                    public void visitArrayAccessExpression(
05253:                            Java.ArrayAccessExpression aae) {
05254:                        res[0] = UnitCompiler.this 
05255:                                .getNegatedConstantValue2(aae);
05256:                    }
05257:
05258:                    public void visitFieldAccess(Java.FieldAccess fa) {
05259:                        res[0] = UnitCompiler.this .getNegatedConstantValue2(fa);
05260:                    }
05261:
05262:                    public void visitFieldAccessExpression(
05263:                            Java.FieldAccessExpression fae) {
05264:                        res[0] = UnitCompiler.this 
05265:                                .getNegatedConstantValue2(fae);
05266:                    }
05267:
05268:                    public void visitSuperclassFieldAccessExpression(
05269:                            Java.SuperclassFieldAccessExpression scfae) {
05270:                        res[0] = UnitCompiler.this 
05271:                                .getNegatedConstantValue2(scfae);
05272:                    }
05273:
05274:                    public void visitLocalVariableAccess(
05275:                            Java.LocalVariableAccess lva) {
05276:                        res[0] = UnitCompiler.this 
05277:                                .getNegatedConstantValue2(lva);
05278:                    }
05279:
05280:                    public void visitParenthesizedExpression(
05281:                            Java.ParenthesizedExpression pe) {
05282:                        try {
05283:                            res[0] = UnitCompiler.this 
05284:                                    .getNegatedConstantValue2(pe);
05285:                        } catch (CompileException e) {
05286:                            throw new UCE(e);
05287:                        }
05288:                    }
05289:                };
05290:                try {
05291:                    rv.accept(rvv);
05292:                    return res[0];
05293:                } catch (UCE uce) {
05294:                    throw uce.ce;
05295:                }
05296:            }
05297:
05298:            private Object getNegatedConstantValue2(Java.Rvalue rv) {
05299:                return null;
05300:            }
05301:
05302:            private Object getNegatedConstantValue2(Java.UnaryOperation uo)
05303:                    throws CompileException {
05304:                return (uo.operator.equals("+") ? this 
05305:                        .getNegatedConstantValue(uo.operand) : uo.operator
05306:                        .equals("-") ? this .getConstantValue(uo.operand) : null);
05307:            }
05308:
05309:            private Object getNegatedConstantValue2(
05310:                    Java.ParenthesizedExpression pe) throws CompileException {
05311:                return this .getNegatedConstantValue(pe.value);
05312:            }
05313:
05314:            private Object getNegatedConstantValue2(Java.Literal l)
05315:                    throws CompileException {
05316:                if (l.value instanceof  Integer)
05317:                    return new Integer(-((Integer) l.value).intValue());
05318:                if (l.value instanceof  Long)
05319:                    return new Long(-((Long) l.value).longValue());
05320:                if (l.value instanceof  Float)
05321:                    return new Float(-((Float) l.value).floatValue());
05322:                if (l.value instanceof  Double)
05323:                    return new Double(-((Double) l.value).doubleValue());
05324:
05325:                this 
05326:                        .compileError("Cannot negate this literal", l
05327:                                .getLocation());
05328:                return null;
05329:            }
05330:
05331:            // ------------ BlockStatement.generatesCode() -------------
05332:
05333:            /**
05334:             * Check whether invocation of {@link #compile(Java.BlockStatement)} would
05335:             * generate more than zero code bytes.
05336:             */
05337:            private boolean generatesCode(Java.BlockStatement bs)
05338:                    throws CompileException {
05339:                final boolean[] res = new boolean[1];
05340:                class UCE extends RuntimeException {
05341:                    final CompileException ce;
05342:
05343:                    UCE(CompileException ce) {
05344:                        this .ce = ce;
05345:                    }
05346:                }
05347:                Visitor.BlockStatementVisitor bsv = new Visitor.BlockStatementVisitor() {
05348:                    public void visitInitializer(Java.Initializer i) {
05349:                        try {
05350:                            res[0] = UnitCompiler.this .generatesCode2(i);
05351:                        } catch (CompileException e) {
05352:                            throw new UCE(e);
05353:                        }
05354:                    }
05355:
05356:                    public void visitFieldDeclaration(Java.FieldDeclaration fd) {
05357:                        try {
05358:                            res[0] = UnitCompiler.this .generatesCode2(fd);
05359:                        } catch (CompileException e) {
05360:                            throw new UCE(e);
05361:                        }
05362:                    }
05363:
05364:                    public void visitLabeledStatement(Java.LabeledStatement ls) {
05365:                        res[0] = UnitCompiler.this .generatesCode2(ls);
05366:                    }
05367:
05368:                    public void visitBlock(Java.Block b) {
05369:                        try {
05370:                            res[0] = UnitCompiler.this .generatesCode2(b);
05371:                        } catch (CompileException e) {
05372:                            throw new UCE(e);
05373:                        }
05374:                    }
05375:
05376:                    public void visitExpressionStatement(
05377:                            Java.ExpressionStatement es) {
05378:                        res[0] = UnitCompiler.this .generatesCode2(es);
05379:                    }
05380:
05381:                    public void visitIfStatement(Java.IfStatement is) {
05382:                        res[0] = UnitCompiler.this .generatesCode2(is);
05383:                    }
05384:
05385:                    public void visitForStatement(Java.ForStatement fs) {
05386:                        res[0] = UnitCompiler.this .generatesCode2(fs);
05387:                    }
05388:
05389:                    public void visitWhileStatement(Java.WhileStatement ws) {
05390:                        res[0] = UnitCompiler.this .generatesCode2(ws);
05391:                    }
05392:
05393:                    public void visitTryStatement(Java.TryStatement ts) {
05394:                        res[0] = UnitCompiler.this .generatesCode2(ts);
05395:                    }
05396:
05397:                    public void visitSwitchStatement(Java.SwitchStatement ss) {
05398:                        res[0] = UnitCompiler.this .generatesCode2(ss);
05399:                    }
05400:
05401:                    public void visitSynchronizedStatement(
05402:                            Java.SynchronizedStatement ss) {
05403:                        res[0] = UnitCompiler.this .generatesCode2(ss);
05404:                    }
05405:
05406:                    public void visitDoStatement(Java.DoStatement ds) {
05407:                        res[0] = UnitCompiler.this .generatesCode2(ds);
05408:                    }
05409:
05410:                    public void visitLocalVariableDeclarationStatement(
05411:                            Java.LocalVariableDeclarationStatement lvds) {
05412:                        res[0] = UnitCompiler.this .generatesCode2(lvds);
05413:                    }
05414:
05415:                    public void visitReturnStatement(Java.ReturnStatement rs) {
05416:                        res[0] = UnitCompiler.this .generatesCode2(rs);
05417:                    }
05418:
05419:                    public void visitThrowStatement(Java.ThrowStatement ts) {
05420:                        res[0] = UnitCompiler.this .generatesCode2(ts);
05421:                    }
05422:
05423:                    public void visitBreakStatement(Java.BreakStatement bs) {
05424:                        res[0] = UnitCompiler.this .generatesCode2(bs);
05425:                    }
05426:
05427:                    public void visitContinueStatement(Java.ContinueStatement cs) {
05428:                        res[0] = UnitCompiler.this .generatesCode2(cs);
05429:                    }
05430:
05431:                    public void visitEmptyStatement(Java.EmptyStatement es) {
05432:                        res[0] = UnitCompiler.this .generatesCode2(es);
05433:                    }
05434:
05435:                    public void visitLocalClassDeclarationStatement(
05436:                            Java.LocalClassDeclarationStatement lcds) {
05437:                        res[0] = UnitCompiler.this .generatesCode2(lcds);
05438:                    }
05439:
05440:                    public void visitAlternateConstructorInvocation(
05441:                            Java.AlternateConstructorInvocation aci) {
05442:                        res[0] = UnitCompiler.this .generatesCode2(aci);
05443:                    }
05444:
05445:                    public void visitSuperConstructorInvocation(
05446:                            Java.SuperConstructorInvocation sci) {
05447:                        res[0] = UnitCompiler.this .generatesCode2(sci);
05448:                    }
05449:                };
05450:                try {
05451:                    bs.accept(bsv);
05452:                    return res[0];
05453:                } catch (UCE uce) {
05454:                    throw uce.ce;
05455:                }
05456:            }
05457:
05458:            public boolean generatesCode2(Java.BlockStatement bs) {
05459:                return true;
05460:            }
05461:
05462:            public boolean generatesCode2(Java.EmptyStatement es) {
05463:                return false;
05464:            }
05465:
05466:            public boolean generatesCode2(
05467:                    Java.LocalClassDeclarationStatement lcds) {
05468:                return false;
05469:            }
05470:
05471:            public boolean generatesCode2(Java.Initializer i)
05472:                    throws CompileException {
05473:                return this .generatesCode(i.block);
05474:            }
05475:
05476:            public boolean generatesCode2(Java.Block b) throws CompileException {
05477:                for (int i = 0; i < b.statements.size(); ++i) {
05478:                    if (this .generatesCode(((Java.BlockStatement) b.statements
05479:                            .get(i))))
05480:                        return true;
05481:                }
05482:                return false;
05483:            }
05484:
05485:            public boolean generatesCode2(Java.FieldDeclaration fd)
05486:                    throws CompileException {
05487:                // Code is only generated if at least one of the declared variables has a
05488:                // non-constant-final initializer.
05489:                for (int i = 0; i < fd.variableDeclarators.length; ++i) {
05490:                    Java.VariableDeclarator vd = fd.variableDeclarators[i];
05491:                    if (this .getNonConstantFinalInitializer(fd, vd) != null)
05492:                        return true;
05493:                }
05494:                return false;
05495:            }
05496:
05497:            // ------------ BlockStatement.leave() -------------
05498:
05499:            /**
05500:             * Clean up the statement context. This is currently relevant for
05501:             * "try ... catch ... finally" statements (execute "finally" clause)
05502:             * and "synchronized" statements (monitorexit).
05503:             * <p>
05504:             * Statements like "return", "break", "continue" must call this method
05505:             * for all the statements they terminate.
05506:             * <p>
05507:             * Notice: If <code>optionalStackValueType</code> is <code>null</code>,
05508:             * then the operand stack is empty; otherwise exactly one operand with that
05509:             * type is on the stack. This information is vital to implementations of
05510:             * {@link #leave(Java.BlockStatement, IClass)} that require a specific
05511:             * operand stack state (e.g. an empty operand stack for JSR).
05512:             */
05513:            private void leave(Java.BlockStatement bs,
05514:                    final IClass optionalStackValueType) {
05515:                Visitor.BlockStatementVisitor bsv = new Visitor.BlockStatementVisitor() {
05516:                    public void visitInitializer(Java.Initializer i) {
05517:                        UnitCompiler.this .leave2(i, optionalStackValueType);
05518:                    }
05519:
05520:                    public void visitFieldDeclaration(Java.FieldDeclaration fd) {
05521:                        UnitCompiler.this .leave2(fd, optionalStackValueType);
05522:                    }
05523:
05524:                    public void visitLabeledStatement(Java.LabeledStatement ls) {
05525:                        UnitCompiler.this .leave2(ls, optionalStackValueType);
05526:                    }
05527:
05528:                    public void visitBlock(Java.Block b) {
05529:                        UnitCompiler.this .leave2(b, optionalStackValueType);
05530:                    }
05531:
05532:                    public void visitExpressionStatement(
05533:                            Java.ExpressionStatement es) {
05534:                        UnitCompiler.this .leave2(es, optionalStackValueType);
05535:                    }
05536:
05537:                    public void visitIfStatement(Java.IfStatement is) {
05538:                        UnitCompiler.this .leave2(is, optionalStackValueType);
05539:                    }
05540:
05541:                    public void visitForStatement(Java.ForStatement fs) {
05542:                        UnitCompiler.this .leave2(fs, optionalStackValueType);
05543:                    }
05544:
05545:                    public void visitWhileStatement(Java.WhileStatement ws) {
05546:                        UnitCompiler.this .leave2(ws, optionalStackValueType);
05547:                    }
05548:
05549:                    public void visitTryStatement(Java.TryStatement ts) {
05550:                        UnitCompiler.this .leave2(ts, optionalStackValueType);
05551:                    }
05552:
05553:                    public void visitSwitchStatement(Java.SwitchStatement ss) {
05554:                        UnitCompiler.this .leave2(ss, optionalStackValueType);
05555:                    }
05556:
05557:                    public void visitSynchronizedStatement(
05558:                            Java.SynchronizedStatement ss) {
05559:                        UnitCompiler.this .leave2(ss, optionalStackValueType);
05560:                    }
05561:
05562:                    public void visitDoStatement(Java.DoStatement ds) {
05563:                        UnitCompiler.this .leave2(ds, optionalStackValueType);
05564:                    }
05565:
05566:                    public void visitLocalVariableDeclarationStatement(
05567:                            Java.LocalVariableDeclarationStatement lvds) {
05568:                        UnitCompiler.this .leave2(lvds, optionalStackValueType);
05569:                    }
05570:
05571:                    public void visitReturnStatement(Java.ReturnStatement rs) {
05572:                        UnitCompiler.this .leave2(rs, optionalStackValueType);
05573:                    }
05574:
05575:                    public void visitThrowStatement(Java.ThrowStatement ts) {
05576:                        UnitCompiler.this .leave2(ts, optionalStackValueType);
05577:                    }
05578:
05579:                    public void visitBreakStatement(Java.BreakStatement bs) {
05580:                        UnitCompiler.this .leave2(bs, optionalStackValueType);
05581:                    }
05582:
05583:                    public void visitContinueStatement(Java.ContinueStatement cs) {
05584:                        UnitCompiler.this .leave2(cs, optionalStackValueType);
05585:                    }
05586:
05587:                    public void visitEmptyStatement(Java.EmptyStatement es) {
05588:                        UnitCompiler.this .leave2(es, optionalStackValueType);
05589:                    }
05590:
05591:                    public void visitLocalClassDeclarationStatement(
05592:                            Java.LocalClassDeclarationStatement lcds) {
05593:                        UnitCompiler.this .leave2(lcds, optionalStackValueType);
05594:                    }
05595:
05596:                    public void visitAlternateConstructorInvocation(
05597:                            Java.AlternateConstructorInvocation aci) {
05598:                        UnitCompiler.this .leave2(aci, optionalStackValueType);
05599:                    }
05600:
05601:                    public void visitSuperConstructorInvocation(
05602:                            Java.SuperConstructorInvocation sci) {
05603:                        UnitCompiler.this .leave2(sci, optionalStackValueType);
05604:                    }
05605:                };
05606:                bs.accept(bsv);
05607:            }
05608:
05609:            public void leave2(Java.BlockStatement bs,
05610:                    IClass optionalStackValueType) {
05611:                ;
05612:            }
05613:
05614:            public void leave2(Java.SynchronizedStatement ss,
05615:                    IClass optionalStackValueType) {
05616:                this .load((Locatable) ss, this .iClassLoader.OBJECT,
05617:                        ss.monitorLvIndex);
05618:                this .writeOpcode(ss, Opcode.MONITOREXIT);
05619:            }
05620:
05621:            public void leave2(Java.TryStatement ts,
05622:                    IClass optionalStackValueType) {
05623:                if (ts.finallyOffset != null) {
05624:
05625:                    this .codeContext.saveLocalVariables();
05626:                    try {
05627:                        short sv = 0;
05628:
05629:                        // Obviously, JSR must always be executed with the operand stack being
05630:                        // empty; otherwise we get "java.lang.VerifyError: Inconsistent stack height
05631:                        // 1 != 2"
05632:                        if (optionalStackValueType != null) {
05633:                            sv = this .codeContext
05634:                                    .allocateLocalVariable(Descriptor
05635:                                            .size(optionalStackValueType
05636:                                                    .getDescriptor()));
05637:                            this .store((Locatable) ts, optionalStackValueType,
05638:                                    sv);
05639:                        }
05640:
05641:                        this .writeBranch(ts, Opcode.JSR, ts.finallyOffset);
05642:
05643:                        if (optionalStackValueType != null) {
05644:                            this .load((Locatable) ts, optionalStackValueType,
05645:                                    sv);
05646:                        }
05647:                    } finally {
05648:                        this .codeContext.restoreLocalVariables();
05649:                    }
05650:                }
05651:            }
05652:
05653:            // ---------------- Lvalue.compileSet() -----------------
05654:
05655:            /**
05656:             * Generates code that stores a value in the {@link Java.Lvalue}.
05657:             * Expects the {@link Java.Lvalue}'s context (see {@link
05658:             * #compileContext}) and a value of the {@link Java.Lvalue}'s type
05659:             * on the operand stack.
05660:             */
05661:            private void compileSet(Java.Lvalue lv) throws CompileException {
05662:                class UCE extends RuntimeException {
05663:                    final CompileException ce;
05664:
05665:                    UCE(CompileException ce) {
05666:                        this .ce = ce;
05667:                    }
05668:                }
05669:                Visitor.LvalueVisitor lvv = new Visitor.LvalueVisitor() {
05670:                    public void visitAmbiguousName(Java.AmbiguousName an) {
05671:                        try {
05672:                            UnitCompiler.this .compileSet2(an);
05673:                        } catch (CompileException e) {
05674:                            throw new UCE(e);
05675:                        }
05676:                    }
05677:
05678:                    public void visitArrayAccessExpression(
05679:                            Java.ArrayAccessExpression aae) {
05680:                        try {
05681:                            UnitCompiler.this .compileSet2(aae);
05682:                        } catch (CompileException e) {
05683:                            throw new UCE(e);
05684:                        }
05685:                    }
05686:
05687:                    public void visitFieldAccess(Java.FieldAccess fa) {
05688:                        try {
05689:                            UnitCompiler.this .compileSet2(fa);
05690:                        } catch (CompileException e) {
05691:                            throw new UCE(e);
05692:                        }
05693:                    }
05694:
05695:                    public void visitFieldAccessExpression(
05696:                            Java.FieldAccessExpression fae) {
05697:                        try {
05698:                            UnitCompiler.this .compileSet2(fae);
05699:                        } catch (CompileException e) {
05700:                            throw new UCE(e);
05701:                        }
05702:                    }
05703:
05704:                    public void visitSuperclassFieldAccessExpression(
05705:                            Java.SuperclassFieldAccessExpression scfae) {
05706:                        try {
05707:                            UnitCompiler.this .compileSet2(scfae);
05708:                        } catch (CompileException e) {
05709:                            throw new UCE(e);
05710:                        }
05711:                    }
05712:
05713:                    public void visitLocalVariableAccess(
05714:                            Java.LocalVariableAccess lva) {
05715:                        UnitCompiler.this .compileSet2(lva);
05716:                    }
05717:
05718:                    public void visitParenthesizedExpression(
05719:                            Java.ParenthesizedExpression pe) {
05720:                        try {
05721:                            UnitCompiler.this .compileSet2(pe);
05722:                        } catch (CompileException e) {
05723:                            throw new UCE(e);
05724:                        }
05725:                    }
05726:                };
05727:                try {
05728:                    lv.accept(lvv);
05729:                } catch (UCE uce) {
05730:                    throw uce.ce;
05731:                }
05732:            }
05733:
05734:            private void compileSet2(Java.AmbiguousName an)
05735:                    throws CompileException {
05736:                this .compileSet(this .toLvalueOrCE(this .reclassify(an)));
05737:            }
05738:
05739:            private void compileSet2(Java.LocalVariableAccess lva) {
05740:                this .store((Locatable) lva, lva.localVariable.type,
05741:                        lva.localVariable);
05742:            }
05743:
05744:            private void compileSet2(Java.FieldAccess fa)
05745:                    throws CompileException {
05746:                this .checkAccessible(fa.field, fa.getEnclosingBlockStatement());
05747:                this .writeOpcode(fa, (fa.field.isStatic() ? Opcode.PUTSTATIC
05748:                        : Opcode.PUTFIELD));
05749:                this .writeConstantFieldrefInfo(fa.field.getDeclaringIClass()
05750:                        .getDescriptor(), fa.field.getName(), // classFD
05751:                        fa.field.getDescriptor() // fieldFD
05752:                        );
05753:            }
05754:
05755:            private void compileSet2(Java.ArrayAccessExpression aae)
05756:                    throws CompileException {
05757:                this .writeOpcode(aae, Opcode.IASTORE
05758:                        + UnitCompiler.ilfdabcs(this .getType(aae)));
05759:            }
05760:
05761:            private void compileSet2(Java.FieldAccessExpression fae)
05762:                    throws CompileException {
05763:                this .determineValue(fae);
05764:                this .compileSet(this .toLvalueOrCE(fae.value));
05765:            }
05766:
05767:            private void compileSet2(Java.SuperclassFieldAccessExpression scfae)
05768:                    throws CompileException {
05769:                this .determineValue(scfae);
05770:                this .compileSet(this .toLvalueOrCE(scfae.value));
05771:            }
05772:
05773:            private void compileSet2(Java.ParenthesizedExpression pe)
05774:                    throws CompileException {
05775:                this .compileSet(this .toLvalueOrCE(pe.value));
05776:            }
05777:
05778:            // ---------------- Atom.getType() ----------------
05779:
05780:            private IClass getType(Java.Atom a) throws CompileException {
05781:                final IClass[] res = new IClass[1];
05782:                class UCE extends RuntimeException {
05783:                    final CompileException ce;
05784:
05785:                    UCE(CompileException ce) {
05786:                        this .ce = ce;
05787:                    }
05788:                }
05789:                Visitor.AtomVisitor av = new Visitor.AtomVisitor() {
05790:                    // AtomVisitor
05791:                    public void visitPackage(Java.Package p) {
05792:                        try {
05793:                            res[0] = UnitCompiler.this .getType2(p);
05794:                        } catch (CompileException e) {
05795:                            throw new UCE(e);
05796:                        }
05797:                    }
05798:
05799:                    // TypeVisitor
05800:                    public void visitArrayType(Java.ArrayType at) {
05801:                        try {
05802:                            res[0] = UnitCompiler.this .getType2(at);
05803:                        } catch (CompileException e) {
05804:                            throw new UCE(e);
05805:                        }
05806:                    }
05807:
05808:                    public void visitBasicType(Java.BasicType bt) {
05809:                        res[0] = UnitCompiler.this .getType2(bt);
05810:                    }
05811:
05812:                    public void visitReferenceType(Java.ReferenceType rt) {
05813:                        try {
05814:                            res[0] = UnitCompiler.this .getType2(rt);
05815:                        } catch (CompileException e) {
05816:                            throw new UCE(e);
05817:                        }
05818:                    }
05819:
05820:                    public void visitRvalueMemberType(Java.RvalueMemberType rmt) {
05821:                        try {
05822:                            res[0] = UnitCompiler.this .getType2(rmt);
05823:                        } catch (CompileException e) {
05824:                            throw new UCE(e);
05825:                        }
05826:                    }
05827:
05828:                    public void visitSimpleType(Java.SimpleType st) {
05829:                        res[0] = UnitCompiler.this .getType2(st);
05830:                    }
05831:
05832:                    // RvalueVisitor
05833:                    public void visitArrayLength(Java.ArrayLength al) {
05834:                        res[0] = UnitCompiler.this .getType2(al);
05835:                    }
05836:
05837:                    public void visitAssignment(Java.Assignment a) {
05838:                        try {
05839:                            res[0] = UnitCompiler.this .getType2(a);
05840:                        } catch (CompileException e) {
05841:                            throw new UCE(e);
05842:                        }
05843:                    }
05844:
05845:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
05846:                        try {
05847:                            res[0] = UnitCompiler.this .getType2(uo);
05848:                        } catch (CompileException e) {
05849:                            throw new UCE(e);
05850:                        }
05851:                    }
05852:
05853:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
05854:                        try {
05855:                            res[0] = UnitCompiler.this .getType2(bo);
05856:                        } catch (CompileException e) {
05857:                            throw new UCE(e);
05858:                        }
05859:                    }
05860:
05861:                    public void visitCast(Java.Cast c) {
05862:                        try {
05863:                            res[0] = UnitCompiler.this .getType2(c);
05864:                        } catch (CompileException e) {
05865:                            throw new UCE(e);
05866:                        }
05867:                    }
05868:
05869:                    public void visitClassLiteral(Java.ClassLiteral cl) {
05870:                        res[0] = UnitCompiler.this .getType2(cl);
05871:                    }
05872:
05873:                    public void visitConditionalExpression(
05874:                            Java.ConditionalExpression ce) {
05875:                        try {
05876:                            res[0] = UnitCompiler.this .getType2(ce);
05877:                        } catch (CompileException e) {
05878:                            throw new UCE(e);
05879:                        }
05880:                    }
05881:
05882:                    public void visitConstantValue(Java.ConstantValue cv) {
05883:                        res[0] = UnitCompiler.this .getType2(cv);
05884:                    }
05885:
05886:                    public void visitCrement(Java.Crement c) {
05887:                        try {
05888:                            res[0] = UnitCompiler.this .getType2(c);
05889:                        } catch (CompileException e) {
05890:                            throw new UCE(e);
05891:                        }
05892:                    }
05893:
05894:                    public void visitInstanceof(Java.Instanceof io) {
05895:                        res[0] = UnitCompiler.this .getType2(io);
05896:                    }
05897:
05898:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
05899:                        try {
05900:                            res[0] = UnitCompiler.this .getType2(mi);
05901:                        } catch (CompileException e) {
05902:                            throw new UCE(e);
05903:                        }
05904:                    }
05905:
05906:                    public void visitSuperclassMethodInvocation(
05907:                            Java.SuperclassMethodInvocation smi) {
05908:                        try {
05909:                            res[0] = UnitCompiler.this .getType2(smi);
05910:                        } catch (CompileException e) {
05911:                            throw new UCE(e);
05912:                        }
05913:                    }
05914:
05915:                    public void visitLiteral(Java.Literal l) {
05916:                        res[0] = UnitCompiler.this .getType2(l);
05917:                    }
05918:
05919:                    public void visitNewAnonymousClassInstance(
05920:                            Java.NewAnonymousClassInstance naci) {
05921:                        res[0] = UnitCompiler.this .getType2(naci);
05922:                    }
05923:
05924:                    public void visitNewArray(Java.NewArray na) {
05925:                        try {
05926:                            res[0] = UnitCompiler.this .getType2(na);
05927:                        } catch (CompileException e) {
05928:                            throw new UCE(e);
05929:                        }
05930:                    }
05931:
05932:                    public void visitNewInitializedArray(
05933:                            Java.NewInitializedArray nia) {
05934:                        try {
05935:                            res[0] = UnitCompiler.this .getType2(nia);
05936:                        } catch (CompileException e) {
05937:                            throw new UCE(e);
05938:                        }
05939:                    }
05940:
05941:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
05942:                        try {
05943:                            res[0] = UnitCompiler.this .getType2(nci);
05944:                        } catch (CompileException e) {
05945:                            throw new UCE(e);
05946:                        }
05947:                    }
05948:
05949:                    public void visitParameterAccess(Java.ParameterAccess pa) {
05950:                        try {
05951:                            res[0] = UnitCompiler.this .getType2(pa);
05952:                        } catch (CompileException e) {
05953:                            throw new UCE(e);
05954:                        }
05955:                    }
05956:
05957:                    public void visitQualifiedThisReference(
05958:                            Java.QualifiedThisReference qtr) {
05959:                        try {
05960:                            res[0] = UnitCompiler.this .getType2(qtr);
05961:                        } catch (CompileException e) {
05962:                            throw new UCE(e);
05963:                        }
05964:                    }
05965:
05966:                    public void visitThisReference(Java.ThisReference tr) {
05967:                        try {
05968:                            res[0] = UnitCompiler.this .getType2(tr);
05969:                        } catch (CompileException e) {
05970:                            throw new UCE(e);
05971:                        }
05972:                    }
05973:
05974:                    // LvalueVisitor
05975:                    public void visitAmbiguousName(Java.AmbiguousName an) {
05976:                        try {
05977:                            res[0] = UnitCompiler.this .getType2(an);
05978:                        } catch (CompileException e) {
05979:                            throw new UCE(e);
05980:                        }
05981:                    }
05982:
05983:                    public void visitArrayAccessExpression(
05984:                            Java.ArrayAccessExpression aae) {
05985:                        try {
05986:                            res[0] = UnitCompiler.this .getType2(aae);
05987:                        } catch (CompileException e) {
05988:                            throw new UCE(e);
05989:                        }
05990:                    }
05991:
05992:                    public void visitFieldAccess(Java.FieldAccess fa) {
05993:                        try {
05994:                            res[0] = UnitCompiler.this .getType2(fa);
05995:                        } catch (CompileException e) {
05996:                            throw new UCE(e);
05997:                        }
05998:                    }
05999:
06000:                    public void visitFieldAccessExpression(
06001:                            Java.FieldAccessExpression fae) {
06002:                        try {
06003:                            res[0] = UnitCompiler.this .getType2(fae);
06004:                        } catch (CompileException e) {
06005:                            throw new UCE(e);
06006:                        }
06007:                    }
06008:
06009:                    public void visitSuperclassFieldAccessExpression(
06010:                            Java.SuperclassFieldAccessExpression scfae) {
06011:                        try {
06012:                            res[0] = UnitCompiler.this .getType2(scfae);
06013:                        } catch (CompileException e) {
06014:                            throw new UCE(e);
06015:                        }
06016:                    }
06017:
06018:                    public void visitLocalVariableAccess(
06019:                            Java.LocalVariableAccess lva) {
06020:                        res[0] = UnitCompiler.this .getType2(lva);
06021:                    }
06022:
06023:                    public void visitParenthesizedExpression(
06024:                            Java.ParenthesizedExpression pe) {
06025:                        try {
06026:                            res[0] = UnitCompiler.this .getType2(pe);
06027:                        } catch (CompileException e) {
06028:                            throw new UCE(e);
06029:                        }
06030:                    }
06031:                };
06032:                try {
06033:                    a.accept(av);
06034:                    return res[0] != null ? res[0] : this .iClassLoader.OBJECT;
06035:                } catch (UCE uce) {
06036:                    throw uce.ce;
06037:                }
06038:            }
06039:
06040:            private IClass getType2(Java.SimpleType st) {
06041:                return st.iClass;
06042:            }
06043:
06044:            private IClass getType2(Java.BasicType bt) {
06045:                switch (bt.index) {
06046:                case Java.BasicType.VOID:
06047:                    return IClass.VOID;
06048:                case Java.BasicType.BYTE:
06049:                    return IClass.BYTE;
06050:                case Java.BasicType.SHORT:
06051:                    return IClass.SHORT;
06052:                case Java.BasicType.CHAR:
06053:                    return IClass.CHAR;
06054:                case Java.BasicType.INT:
06055:                    return IClass.INT;
06056:                case Java.BasicType.LONG:
06057:                    return IClass.LONG;
06058:                case Java.BasicType.FLOAT:
06059:                    return IClass.FLOAT;
06060:                case Java.BasicType.DOUBLE:
06061:                    return IClass.DOUBLE;
06062:                case Java.BasicType.BOOLEAN:
06063:                    return IClass.BOOLEAN;
06064:                default:
06065:                    throw new RuntimeException("Invalid index " + bt.index);
06066:                }
06067:            }
06068:
06069:            private IClass getType2(Java.ReferenceType rt)
06070:                    throws CompileException {
06071:                Java.TypeDeclaration scopeTypeDeclaration = null;
06072:                Java.CompilationUnit scopeCompilationUnit;
06073:                for (Java.Scope s = rt.getEnclosingScope();; s = s
06074:                        .getEnclosingScope()) {
06075:                    if (s instanceof  Java.TypeDeclaration
06076:                            && scopeTypeDeclaration == null) {
06077:                        scopeTypeDeclaration = (Java.TypeDeclaration) s;
06078:                    }
06079:                    if (s instanceof  Java.CompilationUnit) {
06080:                        scopeCompilationUnit = (Java.CompilationUnit) s;
06081:                        break;
06082:                    }
06083:                }
06084:
06085:                if (rt.identifiers.length == 1) {
06086:
06087:                    // 6.5.5.1 Simple type name (single identifier).
06088:                    String simpleTypeName = rt.identifiers[0];
06089:
06090:                    // 6.5.5.1.1 Local class.
06091:                    {
06092:                        Java.LocalClassDeclaration lcd = this 
06093:                                .findLocalClassDeclaration(rt
06094:                                        .getEnclosingScope(), simpleTypeName);
06095:                        if (lcd != null)
06096:                            return this .resolve(lcd);
06097:                    }
06098:
06099:                    // 6.5.5.1.2 Member type.
06100:                    if (scopeTypeDeclaration != null) { // If enclosed by another type declaration...
06101:                        for (Java.Scope s = scopeTypeDeclaration; !(s instanceof  Java.CompilationUnit); s = s
06102:                                .getEnclosingScope()) {
06103:                            if (s instanceof  Java.TypeDeclaration) {
06104:                                IClass mt = this 
06105:                                        .findMemberType(
06106:                                                this 
06107:                                                        .resolve((Java.AbstractTypeDeclaration) s),
06108:                                                simpleTypeName, rt
06109:                                                        .getLocation());
06110:                                if (mt != null)
06111:                                    return mt;
06112:                            }
06113:                        }
06114:                    }
06115:
06116:                    if (scopeCompilationUnit != null) {
06117:
06118:                        // 6.5.5.1.4a Single-type import.
06119:                        {
06120:                            IClass importedClass = this .importSingleType(
06121:                                    simpleTypeName, rt.getLocation());
06122:                            if (importedClass != null)
06123:                                return importedClass;
06124:                        }
06125:
06126:                        // 6.5.5.1.4b Type declared in same compilation unit.
06127:                        {
06128:                            Java.PackageMemberTypeDeclaration pmtd = scopeCompilationUnit
06129:                                    .getPackageMemberTypeDeclaration(simpleTypeName);
06130:                            if (pmtd != null)
06131:                                return this 
06132:                                        .resolve((Java.AbstractTypeDeclaration) pmtd);
06133:                        }
06134:                    }
06135:
06136:                    // 6.5.5.1.5 Type declared in other compilation unit of same
06137:                    // package.
06138:                    {
06139:                        String pkg = (scopeCompilationUnit.optionalPackageDeclaration == null ? null
06140:                                : scopeCompilationUnit.optionalPackageDeclaration.packageName);
06141:                        String className = pkg == null ? simpleTypeName : pkg
06142:                                + "." + simpleTypeName;
06143:                        IClass result;
06144:                        try {
06145:                            result = this .iClassLoader.loadIClass(Descriptor
06146:                                    .fromClassName(className));
06147:                        } catch (ClassNotFoundException ex) {
06148:                            if (ex.getException() instanceof  CompileException)
06149:                                throw (CompileException) ex.getException();
06150:                            throw new CompileException(className, rt
06151:                                    .getLocation(), ex);
06152:                        }
06153:                        if (result != null)
06154:                            return result;
06155:                    }
06156:
06157:                    // 6.5.5.1.6 Type-import-on-demand declaration.
06158:                    {
06159:                        IClass importedClass = this .importTypeOnDemand(
06160:                                simpleTypeName, rt.getLocation());
06161:                        if (importedClass != null)
06162:                            return importedClass;
06163:                    }
06164:
06165:                    // JLS3 ???:  Type imported through single static import.
06166:                    {
06167:                        Object o = this .singleStaticImports.get(simpleTypeName);
06168:                        if (o instanceof  IClass)
06169:                            return (IClass) o;
06170:                    }
06171:
06172:                    // JLS3 ???: Type imported through static-import-on-demand.
06173:                    {
06174:                        for (Iterator it = this .staticImportsOnDemand
06175:                                .iterator(); it.hasNext();) {
06176:                            IClass ic = (IClass) it.next();
06177:                            IClass[] memberTypes = ic.getDeclaredIClasses();
06178:                            for (int i = 0; i < memberTypes.length; ++i) {
06179:                                IClass mt = memberTypes[i];
06180:                                if (mt.getDescriptor().endsWith(
06181:                                        '$' + simpleTypeName + ';'))
06182:                                    return mt;
06183:                            }
06184:                        }
06185:                    }
06186:
06187:                    // 6.5.5.1.8 Give up.
06188:                    this .compileError("Cannot determine simple type name \""
06189:                            + simpleTypeName + "\"", rt.getLocation());
06190:                    return this .iClassLoader.OBJECT;
06191:                } else {
06192:
06193:                    // 6.5.5.2 Qualified type name (two or more identifiers).
06194:                    Java.Atom q = this .reclassifyName(rt.getLocation(), rt
06195:                            .getEnclosingScope(), rt.identifiers,
06196:                            rt.identifiers.length - 1);
06197:
06198:                    // 6.5.5.2.1 PACKAGE.CLASS
06199:                    if (q instanceof  Java.Package) {
06200:                        String className = Java.join(rt.identifiers, ".");
06201:                        IClass result;
06202:                        try {
06203:                            result = this .iClassLoader.loadIClass(Descriptor
06204:                                    .fromClassName(className));
06205:                        } catch (ClassNotFoundException ex) {
06206:                            if (ex.getException() instanceof  CompileException)
06207:                                throw (CompileException) ex.getException();
06208:                            throw new CompileException(className, rt
06209:                                    .getLocation(), ex);
06210:                        }
06211:                        if (result != null)
06212:                            return result;
06213:
06214:                        this .compileError("Class \"" + className
06215:                                + "\" not found", rt.getLocation());
06216:                        return this .iClassLoader.OBJECT;
06217:                    }
06218:
06219:                    // 6.5.5.2.2 CLASS.CLASS (member type)
06220:                    String memberTypeName = rt.identifiers[rt.identifiers.length - 1];
06221:                    IClass[] types = this .getType(this .toTypeOrCE(q))
06222:                            .findMemberType(memberTypeName);
06223:                    if (types.length == 1)
06224:                        return types[0];
06225:                    if (types.length == 0) {
06226:                        this .compileError("\"" + q
06227:                                + "\" declares no member type \""
06228:                                + memberTypeName + "\"", rt.getLocation());
06229:                    } else {
06230:                        this 
06231:                                .compileError(
06232:                                        "\""
06233:                                                + q
06234:                                                + "\" and its supertypes declare more than one member type \""
06235:                                                + memberTypeName + "\"", rt
06236:                                                .getLocation());
06237:                    }
06238:                    return this .iClassLoader.OBJECT;
06239:                }
06240:            }
06241:
06242:            private IClass getType2(Java.RvalueMemberType rvmt)
06243:                    throws CompileException {
06244:                IClass rvt = this .getType(rvmt.rvalue);
06245:                IClass memberType = this .findMemberType(rvt, rvmt.identifier,
06246:                        rvmt.getLocation());
06247:                if (memberType == null)
06248:                    this .compileError("\"" + rvt + "\" has no member type \""
06249:                            + rvmt.identifier + "\"", rvmt.getLocation());
06250:                return memberType;
06251:            }
06252:
06253:            private IClass getType2(Java.ArrayType at) throws CompileException {
06254:                return this .getType(at.componentType).getArrayIClass(
06255:                        this .iClassLoader.OBJECT);
06256:            }
06257:
06258:            private IClass getType2(Java.AmbiguousName an)
06259:                    throws CompileException {
06260:                return this .getType(this .reclassify(an));
06261:            }
06262:
06263:            private IClass getType2(Java.Package p) throws CompileException {
06264:                this .compileError(
06265:                        "Unknown variable or type \"" + p.name + "\"", p
06266:                                .getLocation());
06267:                return this .iClassLoader.OBJECT;
06268:            }
06269:
06270:            private IClass getType2(Java.LocalVariableAccess lva) {
06271:                return lva.localVariable.type;
06272:            }
06273:
06274:            private IClass getType2(Java.FieldAccess fa)
06275:                    throws CompileException {
06276:                return fa.field.getType();
06277:            }
06278:
06279:            private IClass getType2(Java.ArrayLength al) {
06280:                return IClass.INT;
06281:            }
06282:
06283:            private IClass getType2(Java.ThisReference tr)
06284:                    throws CompileException {
06285:                return this .getIClass(tr);
06286:            }
06287:
06288:            private IClass getType2(Java.QualifiedThisReference qtr)
06289:                    throws CompileException {
06290:                return this .getTargetIClass(qtr);
06291:            }
06292:
06293:            private IClass getType2(Java.ClassLiteral cl) {
06294:                return this .iClassLoader.CLASS;
06295:            }
06296:
06297:            private IClass getType2(Java.Assignment a) throws CompileException {
06298:                return this .getType(a.lhs);
06299:            }
06300:
06301:            private IClass getType2(Java.ConditionalExpression ce)
06302:                    throws CompileException {
06303:                IClass mhsType = this .getType(ce.mhs);
06304:                IClass rhsType = this .getType(ce.rhs);
06305:
06306:                if (mhsType == rhsType) {
06307:
06308:                    // JLS 15.25.1.1
06309:                    return mhsType;
06310:                } else if (mhsType.isPrimitiveNumeric()
06311:                        && rhsType.isPrimitiveNumeric()) {
06312:
06313:                    // JLS 15.25.1.2
06314:
06315:                    // TODO JLS 15.25.1.2.1
06316:
06317:                    // TODO JLS 15.25.1.2.2
06318:
06319:                    // JLS 15.25.1.2.3
06320:                    return this .binaryNumericPromotionType((Java.Locatable) ce,
06321:                            mhsType, rhsType);
06322:                } else if (this .getConstantValue(ce.mhs) == Java.Rvalue.CONSTANT_VALUE_NULL
06323:                        && !rhsType.isPrimitive()) {
06324:
06325:                    // JLS 15.25.1.3 (null : ref)
06326:                    return rhsType;
06327:                } else if (!mhsType.isPrimitive()
06328:                        && this .getConstantValue(ce.rhs) == Java.Rvalue.CONSTANT_VALUE_NULL) {
06329:
06330:                    // JLS 15.25.1.3 (ref : null)
06331:                    return mhsType;
06332:                } else if (!mhsType.isPrimitive() && !rhsType.isPrimitive()) {
06333:                    if (mhsType.isAssignableFrom(rhsType)) {
06334:                        return mhsType;
06335:                    } else if (rhsType.isAssignableFrom(mhsType)) {
06336:                        return rhsType;
06337:                    } else {
06338:                        this .compileError("Reference types \"" + mhsType
06339:                                + "\" and \"" + rhsType + "\" don't match", ce
06340:                                .getLocation());
06341:                        return this .iClassLoader.OBJECT;
06342:                    }
06343:                } else {
06344:                    this .compileError("Incompatible expression types \""
06345:                            + mhsType + "\" and \"" + rhsType + "\"", ce
06346:                            .getLocation());
06347:                    return this .iClassLoader.OBJECT;
06348:                }
06349:            }
06350:
06351:            private IClass getType2(Java.Crement c) throws CompileException {
06352:                return this .getType(c.operand);
06353:            }
06354:
06355:            private IClass getType2(Java.ArrayAccessExpression aae)
06356:                    throws CompileException {
06357:                return this .getType(aae.lhs).getComponentType();
06358:            }
06359:
06360:            private IClass getType2(Java.FieldAccessExpression fae)
06361:                    throws CompileException {
06362:                this .determineValue(fae);
06363:                return this .getType(fae.value);
06364:            }
06365:
06366:            private IClass getType2(Java.SuperclassFieldAccessExpression scfae)
06367:                    throws CompileException {
06368:                this .determineValue(scfae);
06369:                return this .getType(scfae.value);
06370:            }
06371:
06372:            private IClass getType2(Java.UnaryOperation uo)
06373:                    throws CompileException {
06374:                if (uo.operator == "!")
06375:                    return IClass.BOOLEAN;
06376:
06377:                if (uo.operator == "+" || uo.operator == "-"
06378:                        || uo.operator == "~")
06379:                    return this .unaryNumericPromotionType((Locatable) uo, this 
06380:                            .getUnboxedType(this .getType(uo.operand)));
06381:
06382:                this .compileError(
06383:                        "Unexpected operator \"" + uo.operator + "\"", uo
06384:                                .getLocation());
06385:                return IClass.BOOLEAN;
06386:            }
06387:
06388:            private IClass getType2(Java.Instanceof io) {
06389:                return IClass.BOOLEAN;
06390:            }
06391:
06392:            private IClass getType2(Java.BinaryOperation bo)
06393:                    throws CompileException {
06394:                if (bo.op == "||" || bo.op == "&&" || bo.op == "=="
06395:                        || bo.op == "!=" || bo.op == "<" || bo.op == ">"
06396:                        || bo.op == "<=" || bo.op == ">=")
06397:                    return IClass.BOOLEAN;
06398:
06399:                if (bo.op == "|" || bo.op == "^" || bo.op == "&") {
06400:                    IClass lhsType = this .getType(bo.lhs);
06401:                    return (lhsType == IClass.BOOLEAN
06402:                            || lhsType == this .iClassLoader.BOOLEAN ? IClass.BOOLEAN
06403:                            : this .binaryNumericPromotionType(
06404:                                    (Java.Locatable) bo, lhsType, this 
06405:                                            .getType(bo.rhs)));
06406:                }
06407:
06408:                if (bo.op == "*" || bo.op == "/" || bo.op == "%"
06409:                        || bo.op == "+" || bo.op == "-") {
06410:                    IClassLoader icl = this .iClassLoader;
06411:
06412:                    // Unroll the operands of this binary operation.
06413:                    Iterator ops = bo.unrollLeftAssociation();
06414:
06415:                    // Check the far left operand type.
06416:                    IClass lhsType = this .getUnboxedType(this 
06417:                            .getType(((Java.Rvalue) ops.next())));
06418:                    if (bo.op == "+" && lhsType == icl.STRING)
06419:                        return icl.STRING;
06420:
06421:                    // Determine the expression type.
06422:                    do {
06423:                        IClass rhsType = this .getUnboxedType(this 
06424:                                .getType(((Java.Rvalue) ops.next())));
06425:                        if (bo.op == "+" && rhsType == icl.STRING)
06426:                            return icl.STRING;
06427:                        lhsType = this .binaryNumericPromotionType(
06428:                                (Java.Locatable) bo, lhsType, rhsType);
06429:                    } while (ops.hasNext());
06430:                    return lhsType;
06431:                }
06432:
06433:                if (bo.op == "<<" || bo.op == ">>" || bo.op == ">>>") {
06434:                    IClass lhsType = this .getType(bo.lhs);
06435:                    return this .unaryNumericPromotionType((Locatable) bo,
06436:                            lhsType);
06437:                }
06438:
06439:                this .compileError("Unexpected operator \"" + bo.op + "\"", bo
06440:                        .getLocation());
06441:                return this .iClassLoader.OBJECT;
06442:            }
06443:
06444:            private IClass getUnboxedType(IClass type) {
06445:                IClass c = this .isUnboxingConvertible(type);
06446:                return c != null ? c : type;
06447:            }
06448:
06449:            private IClass getType2(Java.Cast c) throws CompileException {
06450:                return this .getType(c.targetType);
06451:            }
06452:
06453:            private IClass getType2(Java.ParenthesizedExpression pe)
06454:                    throws CompileException {
06455:                return this .getType(pe.value);
06456:            }
06457:
06458:            //    private IClass getType2(Java.ConstructorInvocation ci) {
06459:            //        throw new RuntimeException();
06460:            //    }
06461:            private IClass getType2(Java.MethodInvocation mi)
06462:                    throws CompileException {
06463:                if (mi.iMethod == null) {
06464:                    mi.iMethod = this .findIMethod(mi);
06465:                }
06466:                return mi.iMethod.getReturnType();
06467:            }
06468:
06469:            private IClass getType2(Java.SuperclassMethodInvocation scmi)
06470:                    throws CompileException {
06471:                return this .findIMethod(scmi).getReturnType();
06472:            }
06473:
06474:            private IClass getType2(Java.NewClassInstance nci)
06475:                    throws CompileException {
06476:                if (nci.iClass == null)
06477:                    nci.iClass = this .getType(nci.type);
06478:                return nci.iClass;
06479:            }
06480:
06481:            private IClass getType2(Java.NewAnonymousClassInstance naci) {
06482:                return this .resolve(naci.anonymousClassDeclaration);
06483:            }
06484:
06485:            private IClass getType2(Java.ParameterAccess pa)
06486:                    throws CompileException {
06487:                return this .getLocalVariable(pa.formalParameter).type;
06488:            }
06489:
06490:            private IClass getType2(Java.NewArray na) throws CompileException {
06491:                IClass res = this .getType(na.type);
06492:                return res.getArrayIClass(na.dimExprs.length + na.dims,
06493:                        this .iClassLoader.OBJECT);
06494:            }
06495:
06496:            private IClass getType2(Java.NewInitializedArray nia)
06497:                    throws CompileException {
06498:                return this .getType(nia.arrayType);
06499:            }
06500:
06501:            private IClass getType2(Java.Literal l) {
06502:                if (l.value instanceof  Integer)
06503:                    return IClass.INT;
06504:                if (l.value instanceof  Long)
06505:                    return IClass.LONG;
06506:                if (l.value instanceof  Float)
06507:                    return IClass.FLOAT;
06508:                if (l.value instanceof  Double)
06509:                    return IClass.DOUBLE;
06510:                if (l.value instanceof  String)
06511:                    return this .iClassLoader.STRING;
06512:                if (l.value instanceof  Character)
06513:                    return IClass.CHAR;
06514:                if (l.value instanceof  Boolean)
06515:                    return IClass.BOOLEAN;
06516:                if (l.value == null)
06517:                    return IClass.VOID;
06518:                throw new RuntimeException(
06519:                        "SNO: Unidentifiable literal type \""
06520:                                + l.value.getClass().getName() + "\"");
06521:            }
06522:
06523:            private IClass getType2(Java.ConstantValue cv) {
06524:                IClass res = (cv.constantValue instanceof  Integer ? IClass.INT
06525:                        : cv.constantValue instanceof  Long ? IClass.LONG
06526:                                : cv.constantValue instanceof  Float ? IClass.FLOAT
06527:                                        : cv.constantValue instanceof  Double ? IClass.DOUBLE
06528:                                                : cv.constantValue instanceof  String ? this .iClassLoader.STRING
06529:                                                        : cv.constantValue instanceof  Character ? IClass.CHAR
06530:                                                                : cv.constantValue instanceof  Boolean ? IClass.BOOLEAN
06531:                                                                        : cv.constantValue == Java.Rvalue.CONSTANT_VALUE_NULL ? IClass.VOID
06532:                                                                                : null);
06533:                if (res == null)
06534:                    throw new RuntimeException(
06535:                            "SNO: Unidentifiable constant value type \""
06536:                                    + cv.constantValue.getClass().getName()
06537:                                    + "\"");
06538:                return res;
06539:            }
06540:
06541:            // ---------------- Atom.isType() ---------------
06542:
06543:            private boolean isType(Java.Atom a) throws CompileException {
06544:                final boolean[] res = new boolean[1];
06545:                class UCE extends RuntimeException {
06546:                    final CompileException ce;
06547:
06548:                    UCE(CompileException ce) {
06549:                        this .ce = ce;
06550:                    }
06551:                }
06552:                Visitor.AtomVisitor av = new Visitor.AtomVisitor() {
06553:                    // AtomVisitor
06554:                    public void visitPackage(Java.Package p) {
06555:                        res[0] = UnitCompiler.this .isType2(p);
06556:                    }
06557:
06558:                    // TypeVisitor
06559:                    public void visitArrayType(Java.ArrayType at) {
06560:                        res[0] = UnitCompiler.this .isType2(at);
06561:                    }
06562:
06563:                    public void visitBasicType(Java.BasicType bt) {
06564:                        res[0] = UnitCompiler.this .isType2(bt);
06565:                    }
06566:
06567:                    public void visitReferenceType(Java.ReferenceType rt) {
06568:                        res[0] = UnitCompiler.this .isType2(rt);
06569:                    }
06570:
06571:                    public void visitRvalueMemberType(Java.RvalueMemberType rmt) {
06572:                        res[0] = UnitCompiler.this .isType2(rmt);
06573:                    }
06574:
06575:                    public void visitSimpleType(Java.SimpleType st) {
06576:                        res[0] = UnitCompiler.this .isType2(st);
06577:                    }
06578:
06579:                    // RvalueVisitor
06580:                    public void visitArrayLength(Java.ArrayLength al) {
06581:                        res[0] = UnitCompiler.this .isType2(al);
06582:                    }
06583:
06584:                    public void visitAssignment(Java.Assignment a) {
06585:                        res[0] = UnitCompiler.this .isType2(a);
06586:                    }
06587:
06588:                    public void visitUnaryOperation(Java.UnaryOperation uo) {
06589:                        res[0] = UnitCompiler.this .isType2(uo);
06590:                    }
06591:
06592:                    public void visitBinaryOperation(Java.BinaryOperation bo) {
06593:                        res[0] = UnitCompiler.this .isType2(bo);
06594:                    }
06595:
06596:                    public void visitCast(Java.Cast c) {
06597:                        res[0] = UnitCompiler.this .isType2(c);
06598:                    }
06599:
06600:                    public void visitClassLiteral(Java.ClassLiteral cl) {
06601:                        res[0] = UnitCompiler.this .isType2(cl);
06602:                    }
06603:
06604:                    public void visitConditionalExpression(
06605:                            Java.ConditionalExpression ce) {
06606:                        res[0] = UnitCompiler.this .isType2(ce);
06607:                    }
06608:
06609:                    public void visitConstantValue(Java.ConstantValue cv) {
06610:                        res[0] = UnitCompiler.this .isType2(cv);
06611:                    }
06612:
06613:                    public void visitCrement(Java.Crement c) {
06614:                        res[0] = UnitCompiler.this .isType2(c);
06615:                    }
06616:
06617:                    public void visitInstanceof(Java.Instanceof io) {
06618:                        res[0] = UnitCompiler.this .isType2(io);
06619:                    }
06620:
06621:                    public void visitMethodInvocation(Java.MethodInvocation mi) {
06622:                        res[0] = UnitCompiler.this .isType2(mi);
06623:                    }
06624:
06625:                    public void visitSuperclassMethodInvocation(
06626:                            Java.SuperclassMethodInvocation smi) {
06627:                        res[0] = UnitCompiler.this .isType2(smi);
06628:                    }
06629:
06630:                    public void visitLiteral(Java.Literal l) {
06631:                        res[0] = UnitCompiler.this .isType2(l);
06632:                    }
06633:
06634:                    public void visitNewAnonymousClassInstance(
06635:                            Java.NewAnonymousClassInstance naci) {
06636:                        res[0] = UnitCompiler.this .isType2(naci);
06637:                    }
06638:
06639:                    public void visitNewArray(Java.NewArray na) {
06640:                        res[0] = UnitCompiler.this .isType2(na);
06641:                    }
06642:
06643:                    public void visitNewInitializedArray(
06644:                            Java.NewInitializedArray nia) {
06645:                        res[0] = UnitCompiler.this .isType2(nia);
06646:                    }
06647:
06648:                    public void visitNewClassInstance(Java.NewClassInstance nci) {
06649:                        res[0] = UnitCompiler.this .isType2(nci);
06650:                    }
06651:
06652:                    public void visitParameterAccess(Java.ParameterAccess pa) {
06653:                        res[0] = UnitCompiler.this .isType2(pa);
06654:                    }
06655:
06656:                    public void visitQualifiedThisReference(
06657:                            Java.QualifiedThisReference qtr) {
06658:                        res[0] = UnitCompiler.this .isType2(qtr);
06659:                    }
06660:
06661:                    public void visitThisReference(Java.ThisReference tr) {
06662:                        res[0] = UnitCompiler.this .isType2(tr);
06663:                    }
06664:
06665:                    // LvalueVisitor
06666:                    public void visitAmbiguousName(Java.AmbiguousName an) {
06667:                        try {
06668:                            res[0] = UnitCompiler.this .isType2(an);
06669:                        } catch (CompileException e) {
06670:                            throw new UCE(e);
06671:                        }
06672:                    }
06673:
06674:                    public void visitArrayAccessExpression(
06675:                            Java.ArrayAccessExpression aae) {
06676:                        res[0] = UnitCompiler.this .isType2(aae);
06677:                    }
06678:
06679:                    public void visitFieldAccess(Java.FieldAccess fa) {
06680:                        res[0] = UnitCompiler.this .isType2(fa);
06681:                    }
06682:
06683:                    public void visitFieldAccessExpression(
06684:                            Java.FieldAccessExpression fae) {
06685:                        res[0] = UnitCompiler.this .isType2(fae);
06686:                    }
06687:
06688:                    public void visitSuperclassFieldAccessExpression(
06689:                            Java.SuperclassFieldAccessExpression scfae) {
06690:                        res[0] = UnitCompiler.this .isType2(scfae);
06691:                    }
06692:
06693:                    public void visitLocalVariableAccess(
06694:                            Java.LocalVariableAccess lva) {
06695:                        res[0] = UnitCompiler.this .isType2(lva);
06696:                    }
06697:
06698:                    public void visitParenthesizedExpression(
06699:                            Java.ParenthesizedExpression pe) {
06700:                        res[0] = UnitCompiler.this .isType2(pe);
06701:                    }
06702:                };
06703:                try {
06704:                    a.accept(av);
06705:                    return res[0];
06706:                } catch (UCE uce) {
06707:                    throw uce.ce;
06708:                }
06709:            }
06710:
06711:            private boolean isType2(Java.Atom a) {
06712:                return a instanceof  Java.Type;
06713:            }
06714:
06715:            private boolean isType2(Java.AmbiguousName an)
06716:                    throws CompileException {
06717:                return this .isType(this .reclassify(an));
06718:            }
06719:
06720:            /**
06721:             * Check whether the given {@link IClass.IMember} is accessible in the given context,
06722:             * according to JLS 6.6.1.4. Issues a {@link #compileError(String)} if not.
06723:             */
06724:            private void checkAccessible(IClass.IMember member,
06725:                    Java.BlockStatement contextBlockStatement)
06726:                    throws CompileException {
06727:                this .checkAccessible(member.getDeclaringIClass(), member
06728:                        .getAccess(), contextBlockStatement);
06729:            }
06730:
06731:            /**
06732:             * Verify that a member (class, interface, field or method) declared in a
06733:             * given class is accessible from a given block statement context, according
06734:             * to JLS2 6.6.1.4.
06735:             */
06736:            private void checkAccessible(IClass iClassDeclaringMember,
06737:                    Access memberAccess,
06738:                    Java.BlockStatement contextBlockStatement)
06739:                    throws CompileException {
06740:
06741:                // At this point, memberAccess is PUBLIC, DEFAULT, PROECTEDED or PRIVATE.
06742:
06743:                // PUBLIC members are always accessible.
06744:                if (memberAccess == Access.PUBLIC)
06745:                    return;
06746:
06747:                // At this point, the member is DEFAULT, PROECTEDED or PRIVATE accessible.
06748:
06749:                // Determine the class declaring the context block statement.
06750:                IClass iClassDeclaringContextBlockStatement;
06751:                for (Java.Scope s = contextBlockStatement.getEnclosingScope();; s = s
06752:                        .getEnclosingScope()) {
06753:                    if (s instanceof  Java.TypeDeclaration) {
06754:                        iClassDeclaringContextBlockStatement = this 
06755:                                .resolve((Java.TypeDeclaration) s);
06756:                        break;
06757:                    }
06758:                }
06759:
06760:                // Access is always allowed for block statements declared in the same class as the member.
06761:                if (iClassDeclaringContextBlockStatement == iClassDeclaringMember)
06762:                    return;
06763:
06764:                // Check whether the member and the context block statement are enclosed by the same
06765:                // top-level type.
06766:                {
06767:                    IClass topLevelIClassEnclosingMember = iClassDeclaringMember;
06768:                    for (IClass c = iClassDeclaringMember.getDeclaringIClass(); c != null; c = c
06769:                            .getDeclaringIClass()) {
06770:                        topLevelIClassEnclosingMember = c;
06771:                    }
06772:                    IClass topLevelIClassEnclosingContextBlockStatement = iClassDeclaringContextBlockStatement;
06773:                    for (IClass c = iClassDeclaringContextBlockStatement
06774:                            .getDeclaringIClass(); c != null; c = c
06775:                            .getDeclaringIClass()) {
06776:                        topLevelIClassEnclosingContextBlockStatement = c;
06777:                    }
06778:
06779:                    if (topLevelIClassEnclosingMember == topLevelIClassEnclosingContextBlockStatement)
06780:                        return;
06781:                }
06782:
06783:                if (memberAccess == Access.PRIVATE) {
06784:                    this .compileError(
06785:                            "Private member cannot be accessed from type \""
06786:                                    + iClassDeclaringContextBlockStatement
06787:                                    + "\".", contextBlockStatement
06788:                                    .getLocation());
06789:                    return;
06790:                }
06791:
06792:                // At this point, the member is DEFAULT or PROTECTED accessible.
06793:
06794:                // Check whether the member and the context block statement are declared in the same
06795:                // package.
06796:                if (Descriptor.areInSamePackage(iClassDeclaringMember
06797:                        .getDescriptor(), iClassDeclaringContextBlockStatement
06798:                        .getDescriptor()))
06799:                    return;
06800:
06801:                if (memberAccess == Access.DEFAULT) {
06802:                    this .compileError("Member with \"" + memberAccess
06803:                            + "\" access cannot be accessed from type \""
06804:                            + iClassDeclaringContextBlockStatement + "\".",
06805:                            contextBlockStatement.getLocation());
06806:                    return;
06807:                }
06808:
06809:                // At this point, the member is PROTECTED accessible.
06810:
06811:                // Check whether the class declaring the context block statement is a subclass of the
06812:                // class declaring the member.
06813:                if (!iClassDeclaringMember
06814:                        .isAssignableFrom(iClassDeclaringContextBlockStatement)) {
06815:                    this 
06816:                            .compileError(
06817:                                    "Protected member cannot be accessed from type \""
06818:                                            + iClassDeclaringContextBlockStatement
06819:                                            + "\", which is neither declared in the same package as or is a subclass of \""
06820:                                            + iClassDeclaringMember + "\".",
06821:                                    contextBlockStatement.getLocation());
06822:                    return;
06823:                }
06824:                return;
06825:            }
06826:
06827:            /**
06828:             * Check whether the given {@link IClass} is accessible in the given context,
06829:             * according to JLS2 6.6.1.2 and 6.6.1.4. Issues a
06830:             * {@link #compileError(String)} if not.
06831:             */
06832:            private void checkAccessible(IClass type,
06833:                    Java.BlockStatement contextBlockStatement)
06834:                    throws CompileException {
06835:
06836:                // Determine the type declaring the type.
06837:                IClass iClassDeclaringType = type.getDeclaringIClass();
06838:
06839:                // Check accessibility of package member type.
06840:                if (iClassDeclaringType == null) {
06841:                    if (type.getAccess() == Access.PUBLIC) {
06842:                        return;
06843:                    } else if (type.getAccess() == Access.DEFAULT) {
06844:
06845:                        // Determine the type declaring the context block statement.
06846:                        IClass iClassDeclaringContextBlockStatement;
06847:                        for (Java.Scope s = contextBlockStatement
06848:                                .getEnclosingScope();; s = s
06849:                                .getEnclosingScope()) {
06850:                            if (s instanceof  Java.TypeDeclaration) {
06851:                                iClassDeclaringContextBlockStatement = this 
06852:                                        .resolve((Java.TypeDeclaration) s);
06853:                                break;
06854:                            }
06855:                        }
06856:
06857:                        // Check whether the type is accessed from within the same package.
06858:                        String packageDeclaringType = Descriptor
06859:                                .getPackageName(type.getDescriptor());
06860:                        String contextPackage = Descriptor
06861:                                .getPackageName(iClassDeclaringContextBlockStatement
06862:                                        .getDescriptor());
06863:                        if (!(packageDeclaringType == null ? contextPackage == null
06864:                                : packageDeclaringType.equals(contextPackage)))
06865:                            this .compileError("\"" + type
06866:                                    + "\" is inaccessible from this package");
06867:                        return;
06868:                    } else {
06869:                        throw new RuntimeException("\"" + type
06870:                                + "\" has unexpected access \""
06871:                                + type.getAccess() + "\"");
06872:                    }
06873:                }
06874:
06875:                // "type" is a member type at this point.
06876:
06877:                this .checkAccessible(iClassDeclaringType, type.getAccess(),
06878:                        contextBlockStatement);
06879:            }
06880:
06881:            private final Java.Type toTypeOrCE(Java.Atom a)
06882:                    throws CompileException {
06883:                Java.Type result = a.toType();
06884:                if (result == null) {
06885:                    this .compileError("Expression \"" + a.toString()
06886:                            + "\" is not a type", a.getLocation());
06887:                    return new Java.SimpleType(a.getLocation(),
06888:                            this .iClassLoader.OBJECT);
06889:                }
06890:                return result;
06891:            }
06892:
06893:            private final Java.Rvalue toRvalueOrCE(final Java.Atom a)
06894:                    throws CompileException {
06895:                Java.Rvalue result = a.toRvalue();
06896:                if (result == null) {
06897:                    this .compileError("Expression \"" + a.toString()
06898:                            + "\" is not an rvalue", a.getLocation());
06899:                    return new Java.Literal(a.getLocation(), "X");
06900:                }
06901:                return result;
06902:            }
06903:
06904:            public final Java.Lvalue toLvalueOrCE(final Java.Atom a)
06905:                    throws CompileException {
06906:                Java.Lvalue result = a.toLvalue();
06907:                if (result == null) {
06908:                    this .compileError("Expression \"" + a.toString()
06909:                            + "\" is not an lvalue", a.getLocation());
06910:                    return new Java.Lvalue(a.getLocation()) {
06911:                        public String toString() {
06912:                            return a.toString();
06913:                        }
06914:
06915:                        public void accept(Visitor.AtomVisitor visitor) {
06916:                        }
06917:
06918:                        public void accept(Visitor.RvalueVisitor visitor) {
06919:                        }
06920:
06921:                        public void accept(Visitor.LvalueVisitor visitor) {
06922:                        }
06923:                    };
06924:                }
06925:                return result;
06926:            }
06927:
06928:            /**
06929:             * Copies the values of the synthetic parameters of this constructor ("this$..." and
06930:             * "val$...") to the synthetic fields of the object ("this$..." and "val$...").
06931:             */
06932:            void assignSyntheticParametersToSyntheticFields(
06933:                    Java.ConstructorDeclarator cd) throws CompileException {
06934:                for (Iterator it = cd.getDeclaringClass().syntheticFields
06935:                        .values().iterator(); it.hasNext();) {
06936:                    IClass.IField sf = (IClass.IField) it.next();
06937:                    Java.LocalVariable syntheticParameter = (Java.LocalVariable) cd.syntheticParameters
06938:                            .get(sf.getName());
06939:                    if (syntheticParameter == null)
06940:                        throw new RuntimeException(
06941:                                "SNO: Synthetic parameter for synthetic field \""
06942:                                        + sf.getName() + "\" not found");
06943:                    try {
06944:                        Java.ExpressionStatement es = new Java.ExpressionStatement(
06945:                                new Java.Assignment(cd.getLocation(), // location
06946:                                        new Java.FieldAccess( // lhs
06947:                                                cd.getLocation(), // location
06948:                                                new Java.ThisReference(cd
06949:                                                        .getLocation()), // lhs
06950:                                                sf // field
06951:                                        ), "=", // operator
06952:                                        new Java.LocalVariableAccess( // rhs
06953:                                                cd.getLocation(), // location
06954:                                                syntheticParameter // localVariable
06955:                                        )));
06956:                        es.setEnclosingScope(cd);
06957:                        this .compile(es);
06958:                    } catch (Parser.ParseException e) {
06959:                        throw new RuntimeException("S.N.O.");
06960:                    }
06961:                }
06962:            }
06963:
06964:            /**
06965:             * Compiles the instance variable initializers and the instance initializers in their
06966:             * lexical order.
06967:             */
06968:            void initializeInstanceVariablesAndInvokeInstanceInitializers(
06969:                    Java.ConstructorDeclarator cd) throws CompileException {
06970:                for (int i = 0; i < cd.getDeclaringClass().variableDeclaratorsAndInitializers
06971:                        .size(); ++i) {
06972:                    Java.TypeBodyDeclaration tbd = (Java.TypeBodyDeclaration) cd
06973:                            .getDeclaringClass().variableDeclaratorsAndInitializers
06974:                            .get(i);
06975:                    if (!tbd.isStatic()) {
06976:                        Java.BlockStatement bs = (Java.BlockStatement) tbd;
06977:                        if (!this .compile(bs))
06978:                            this 
06979:                                    .compileError(
06980:                                            "Instance variable declarator or instance initializer does not complete normally",
06981:                                            bs.getLocation());
06982:                    }
06983:                }
06984:            }
06985:
06986:            /**
06987:             * Statements that jump out of blocks ("return", "break", "continue")
06988:             * must call this method to make sure that the "finally" clauses of all
06989:             * "try...catch" statements are executed.
06990:             */
06991:            private void leaveStatements(Java.Scope from, Java.Scope to,
06992:                    IClass optionalStackValueType) {
06993:                for (Java.Scope s = from; s != to; s = s.getEnclosingScope()) {
06994:                    if (s instanceof  Java.BlockStatement) {
06995:                        this .leave((Java.BlockStatement) s,
06996:                                optionalStackValueType);
06997:                    }
06998:                }
06999:            }
07000:
07001:            /**
07002:             * The LHS operand of type <code>lhsType</code> is expected on the stack.
07003:             * <p>
07004:             * The following operators are supported:
07005:             * <code>&nbsp;&nbsp;| ^ & * / % + - &lt;&lt; &gt;&gt; &gt;&gt;&gt;</code>
07006:             */
07007:            private IClass compileArithmeticBinaryOperation(Locatable l,
07008:                    IClass lhsType, String operator, Java.Rvalue rhs)
07009:                    throws CompileException {
07010:                return this 
07011:                        .compileArithmeticOperation(l, lhsType, Arrays.asList(
07012:                                new Java.Rvalue[] { rhs }).iterator(), operator);
07013:            }
07014:
07015:            /**
07016:             * Execute an arithmetic operation on a sequence of <code>operands</code>. If
07017:             * <code>type</code> is non-null, the first operand with that type is already on the stack.
07018:             * <p>
07019:             * The following operators are supported:
07020:             * <code>&nbsp;&nbsp;| ^ &amp; * / % + - &lt;&lt; &gt;&gt; &gt;&gt;&gt;</code>
07021:             */
07022:            private IClass compileArithmeticOperation(final Locatable l,
07023:                    IClass type, Iterator operands, String operator)
07024:                    throws CompileException {
07025:                if (operator == "|" || operator == "^" || operator == "&") {
07026:                    final int iopcode = (operator == "&" ? Opcode.IAND
07027:                            : operator == "|" ? Opcode.IOR
07028:                                    : operator == "^" ? Opcode.IXOR
07029:                                            : Integer.MAX_VALUE);
07030:
07031:                    do {
07032:                        Java.Rvalue operand = (Java.Rvalue) operands.next();
07033:
07034:                        if (type == null) {
07035:                            type = this .compileGetValue(operand);
07036:                        } else {
07037:                            CodeContext.Inserter convertLhsInserter = this .codeContext
07038:                                    .newInserter();
07039:                            IClass rhsType = this .compileGetValue(operand);
07040:
07041:                            if (type.isPrimitiveNumeric()
07042:                                    && rhsType.isPrimitiveNumeric()) {
07043:                                IClass promotedType = this 
07044:                                        .binaryNumericPromotion(l, type,
07045:                                                convertLhsInserter, rhsType);
07046:                                if (promotedType == IClass.INT) {
07047:                                    this .writeOpcode(l, iopcode);
07048:                                } else if (promotedType == IClass.LONG) {
07049:                                    this .writeOpcode(l, iopcode + 1);
07050:                                } else {
07051:                                    this .compileError("Operator \"" + operator
07052:                                            + "\" not defined on types \""
07053:                                            + type + "\" and \"" + rhsType
07054:                                            + "\"", l.getLocation());
07055:                                }
07056:                                type = promotedType;
07057:                            } else if ((type == IClass.BOOLEAN && this 
07058:                                    .getUnboxedType(rhsType) == IClass.BOOLEAN)
07059:                                    || (this .getUnboxedType(type) == IClass.BOOLEAN && rhsType == IClass.BOOLEAN)) {
07060:                                IClassLoader icl = this .iClassLoader;
07061:                                if (type == icl.BOOLEAN) {
07062:                                    this .codeContext
07063:                                            .pushInserter(convertLhsInserter);
07064:                                    try {
07065:                                        this .unboxingConversion(l, icl.BOOLEAN,
07066:                                                IClass.BOOLEAN);
07067:                                    } finally {
07068:                                        this .codeContext.popInserter();
07069:                                    }
07070:                                }
07071:                                if (rhsType == icl.BOOLEAN) {
07072:                                    this .unboxingConversion(l, icl.BOOLEAN,
07073:                                            IClass.BOOLEAN);
07074:                                }
07075:                                this .writeOpcode(l, iopcode);
07076:                                type = IClass.BOOLEAN;
07077:                            } else {
07078:                                this .compileError("Operator \"" + operator
07079:                                        + "\" not defined on types \"" + type
07080:                                        + "\" and \"" + rhsType + "\"", l
07081:                                        .getLocation());
07082:                                type = IClass.INT;
07083:                            }
07084:                        }
07085:                    } while (operands.hasNext());
07086:                    return type;
07087:                }
07088:
07089:                if (operator == "*" || operator == "/" || operator == "%"
07090:                        || operator == "+" || operator == "-") {
07091:                    final int iopcode = (operator == "*" ? Opcode.IMUL
07092:                            : operator == "/" ? Opcode.IDIV
07093:                                    : operator == "%" ? Opcode.IREM
07094:                                            : operator == "+" ? Opcode.IADD
07095:                                                    : operator == "-" ? Opcode.ISUB
07096:                                                            : Integer.MAX_VALUE);
07097:
07098:                    do {
07099:                        Java.Rvalue operand = (Java.Rvalue) operands.next();
07100:
07101:                        IClass operandType = this .getType(operand);
07102:                        IClassLoader icl = this .iClassLoader;
07103:
07104:                        // String concatenation?
07105:                        if (operator == "+"
07106:                                && (type == icl.STRING || operandType == icl.STRING)) {
07107:                            return this .compileStringConcatenation(l, type,
07108:                                    operand, operands);
07109:                        }
07110:
07111:                        if (type == null) {
07112:                            type = this .compileGetValue(operand);
07113:                        } else {
07114:                            CodeContext.Inserter convertLhsInserter = this .codeContext
07115:                                    .newInserter();
07116:                            IClass rhsType = this .compileGetValue(operand);
07117:
07118:                            type = this .binaryNumericPromotion(l, type,
07119:                                    convertLhsInserter, rhsType);
07120:
07121:                            int opcode;
07122:                            if (type == IClass.INT) {
07123:                                opcode = iopcode;
07124:                            } else if (type == IClass.LONG) {
07125:                                opcode = iopcode + 1;
07126:                            } else if (type == IClass.FLOAT) {
07127:                                opcode = iopcode + 2;
07128:                            } else if (type == IClass.DOUBLE) {
07129:                                opcode = iopcode + 3;
07130:                            } else {
07131:                                this .compileError("Unexpected promoted type \""
07132:                                        + type + "\"", l.getLocation());
07133:                                opcode = iopcode;
07134:                            }
07135:                            this .writeOpcode(l, opcode);
07136:                        }
07137:                    } while (operands.hasNext());
07138:                    return type;
07139:                }
07140:
07141:                if (operator == "<<" || operator == ">>" || operator == ">>>") {
07142:                    final int iopcode = (operator == "<<" ? Opcode.ISHL
07143:                            : operator == ">>" ? Opcode.ISHR
07144:                                    : operator == ">>>" ? Opcode.IUSHR
07145:                                            : Integer.MAX_VALUE);
07146:
07147:                    do {
07148:                        Java.Rvalue operand = (Java.Rvalue) operands.next();
07149:
07150:                        if (type == null) {
07151:                            type = this .compileGetValue(operand);
07152:                        } else {
07153:                            CodeContext.Inserter convertLhsInserter = this .codeContext
07154:                                    .newInserter();
07155:                            IClass rhsType = this .compileGetValue(operand);
07156:
07157:                            IClass promotedLhsType;
07158:                            this .codeContext.pushInserter(convertLhsInserter);
07159:                            try {
07160:                                promotedLhsType = this .unaryNumericPromotion(l,
07161:                                        type);
07162:                            } finally {
07163:                                this .codeContext.popInserter();
07164:                            }
07165:                            if (promotedLhsType != IClass.INT
07166:                                    && promotedLhsType != IClass.LONG)
07167:                                this .compileError(
07168:                                        "Shift operation not allowed on operand type \""
07169:                                                + type + "\"", l.getLocation());
07170:
07171:                            IClass promotedRhsType = this 
07172:                                    .unaryNumericPromotion(l, rhsType);
07173:                            if (promotedRhsType != IClass.INT
07174:                                    && promotedRhsType != IClass.LONG)
07175:                                this .compileError("Shift distance of type \""
07176:                                        + rhsType + "\" is not allowed", l
07177:                                        .getLocation());
07178:
07179:                            if (promotedRhsType == IClass.LONG)
07180:                                this .writeOpcode(l, Opcode.L2I);
07181:
07182:                            this 
07183:                                    .writeOpcode(
07184:                                            l,
07185:                                            promotedLhsType == IClass.LONG ? iopcode + 1
07186:                                                    : iopcode);
07187:                            type = promotedLhsType;
07188:                        }
07189:                    } while (operands.hasNext());
07190:                    return type;
07191:                }
07192:
07193:                throw new RuntimeException("Unexpected operator \"" + operator
07194:                        + "\"");
07195:            }
07196:
07197:            /**
07198:             * @param type If non-null, the first operand with that type is already on the stack
07199:             * @param operand The next operand
07200:             * @param operands All following operands ({@link Iterator} over {@link Java.Rvalue}s)
07201:             */
07202:            private IClass compileStringConcatenation(final Locatable l,
07203:                    IClass type, Java.Rvalue operand, Iterator operands)
07204:                    throws CompileException {
07205:                boolean operandOnStack;
07206:                if (type != null) {
07207:                    this .stringConversion(l, type);
07208:                    operandOnStack = true;
07209:                } else {
07210:                    operandOnStack = false;
07211:                }
07212:
07213:                // Compute list of operands and merge consecutive constant operands.
07214:                List tmp = new ArrayList(); // Compilable
07215:                do {
07216:                    Object cv = this .getConstantValue(operand);
07217:                    if (cv == null) {
07218:                        // Non-constant operand.
07219:                        final Java.Rvalue final_operand = operand;
07220:                        tmp.add(new Compilable() {
07221:                            public void compile() throws CompileException {
07222:                                UnitCompiler.this 
07223:                                        .stringConversion(l, UnitCompiler.this 
07224:                                                .compileGetValue(final_operand));
07225:                            }
07226:                        });
07227:
07228:                        operand = operands.hasNext() ? (Java.Rvalue) operands
07229:                                .next() : null;
07230:                    } else {
07231:                        // Constant operand. Check to see whether the next operand is also constant.
07232:                        if (operands.hasNext()) {
07233:                            operand = (Java.Rvalue) operands.next();
07234:                            Object cv2 = this .getConstantValue(operand);
07235:                            if (cv2 != null) {
07236:                                StringBuffer sb = new StringBuffer(cv
07237:                                        .toString()).append(cv2);
07238:                                for (;;) {
07239:                                    if (!operands.hasNext()) {
07240:                                        operand = null;
07241:                                        break;
07242:                                    }
07243:                                    operand = (Java.Rvalue) operands.next();
07244:                                    Object cv3 = this .getConstantValue(operand);
07245:                                    if (cv3 == null)
07246:                                        break;
07247:                                    sb.append(cv3);
07248:                                }
07249:                                cv = sb.toString();
07250:                            }
07251:                        } else {
07252:                            operand = null;
07253:                        }
07254:                        // Break long string constants up into UTF8-able chunks.
07255:                        final String[] ss = UnitCompiler.makeUTF8Able(cv
07256:                                .toString());
07257:                        for (int i = 0; i < ss.length; ++i) {
07258:                            final String s = ss[i];
07259:                            tmp.add(new Compilable() {
07260:                                public void compile() throws CompileException {
07261:                                    UnitCompiler.this .pushConstant(l, s);
07262:                                }
07263:                            });
07264:                        }
07265:                    }
07266:                } while (operand != null);
07267:
07268:                // At this point "tmp" contains an optimized sequence of Strings (representing constant
07269:                // portions) and Rvalues (non-constant portions).
07270:
07271:                if (tmp.size() <= (operandOnStack ? STRING_CONCAT_LIMIT - 1
07272:                        : STRING_CONCAT_LIMIT)) {
07273:
07274:                    // String concatenation through "a.concat(b).concat(c)".
07275:                    for (Iterator it = tmp.iterator(); it.hasNext();) {
07276:                        Compilable c = (Compilable) it.next();
07277:                        c.compile();
07278:
07279:                        // Concatenate.
07280:                        if (operandOnStack) {
07281:                            this .writeOpcode(l, Opcode.INVOKEVIRTUAL);
07282:                            this .writeConstantMethodrefInfo(Descriptor.STRING,
07283:                                    "concat", // classFD
07284:                                    "(" + Descriptor.STRING + ")"
07285:                                            + Descriptor.STRING // methodMD
07286:                            );
07287:                        } else {
07288:                            operandOnStack = true;
07289:                        }
07290:                    }
07291:                    return this .iClassLoader.STRING;
07292:                }
07293:
07294:                // String concatenation through "new StringBuffer(a).append(b).append(c).append(d).toString()".
07295:                Iterator it = tmp.iterator();
07296:
07297:                String stringBuilferFD = this .isStringBuilderAvailable ? Descriptor.STRING_BUILDER
07298:                        : Descriptor.STRING_BUFFER;
07299:                // "new StringBuffer(a)":
07300:                if (operandOnStack) {
07301:                    this .writeOpcode(l, Opcode.NEW);
07302:                    this .writeConstantClassInfo(stringBuilferFD);
07303:                    this .writeOpcode(l, Opcode.DUP_X1);
07304:                    this .writeOpcode(l, Opcode.SWAP);
07305:                } else {
07306:                    this .writeOpcode(l, Opcode.NEW);
07307:                    this .writeConstantClassInfo(stringBuilferFD);
07308:                    this .writeOpcode(l, Opcode.DUP);
07309:                    ((Compilable) it.next()).compile();
07310:                }
07311:                this .writeOpcode(l, Opcode.INVOKESPECIAL);
07312:                this .writeConstantMethodrefInfo(stringBuilferFD, "<init>", // classFD
07313:                        "(" + Descriptor.STRING + ")" + Descriptor.VOID_ // methodMD
07314:                );
07315:                while (it.hasNext()) {
07316:                    ((Compilable) it.next()).compile();
07317:
07318:                    // "StringBuffer.append(b)":
07319:                    this .writeOpcode(l, Opcode.INVOKEVIRTUAL);
07320:                    this .writeConstantMethodrefInfo(stringBuilferFD, "append", // classFD
07321:                            "(" + Descriptor.STRING + ")" + stringBuilferFD // methodMD
07322:                    );
07323:                }
07324:
07325:                // "StringBuffer.toString()":
07326:                this .writeOpcode(l, Opcode.INVOKEVIRTUAL);
07327:                this .writeConstantMethodrefInfo(stringBuilferFD, "toString", // classFD
07328:                        "()" + Descriptor.STRING // methodMD
07329:                );
07330:                return this .iClassLoader.STRING;
07331:            }
07332:
07333:            interface Compilable {
07334:                void compile() throws CompileException;
07335:            }
07336:
07337:            /**
07338:             * Convert object of type "sourceType" to type "String". JLS2 15.18.1.1
07339:             */
07340:            private void stringConversion(Locatable l, IClass sourceType) {
07341:                this .writeOpcode(l, Opcode.INVOKESTATIC);
07342:                this 
07343:                        .writeConstantMethodrefInfo(
07344:                                Descriptor.STRING,
07345:                                "valueOf", // classFD
07346:                                "("
07347:                                        + ( // methodMD
07348:                                        sourceType == IClass.BOOLEAN
07349:                                                || sourceType == IClass.CHAR
07350:                                                || sourceType == IClass.LONG
07351:                                                || sourceType == IClass.FLOAT
07352:                                                || sourceType == IClass.DOUBLE ? sourceType
07353:                                                .getDescriptor()
07354:                                                : sourceType == IClass.BYTE
07355:                                                        || sourceType == IClass.SHORT
07356:                                                        || sourceType == IClass.INT ? Descriptor.INT_
07357:                                                        : Descriptor.OBJECT)
07358:                                        + ")" + Descriptor.STRING);
07359:            }
07360:
07361:            /**
07362:             * Expects the object to initialize on the stack.
07363:             * <p>
07364:             * Notice: This method is used both for explicit constructor invocation (first statement of
07365:             * a constructor body) and implicit constructor invocation (right after NEW).
07366:             *
07367:             * @param optionalEnclosingInstance Used if the target class is an inner class
07368:             */
07369:            private void invokeConstructor(Locatable l, Java.Scope scope,
07370:                    Java.Rvalue optionalEnclosingInstance, IClass targetClass,
07371:                    Java.Rvalue[] arguments) throws CompileException {
07372:
07373:                // Find constructors.
07374:                IClass.IConstructor[] iConstructors = targetClass
07375:                        .getDeclaredIConstructors();
07376:                if (iConstructors.length == 0)
07377:                    throw new RuntimeException("SNO: Target class \""
07378:                            + targetClass.getDescriptor()
07379:                            + "\" has no constructors");
07380:
07381:                IClass.IConstructor iConstructor = (IClass.IConstructor) this 
07382:                        .findMostSpecificIInvocable(l, iConstructors, // iInvocables
07383:                                arguments // arguments
07384:                        );
07385:
07386:                // Check exceptions that the constructor may throw.
07387:                IClass[] thrownExceptions = iConstructor.getThrownExceptions();
07388:                for (int i = 0; i < thrownExceptions.length; ++i) {
07389:                    this .checkThrownException(l, thrownExceptions[i], scope);
07390:                }
07391:
07392:                // Pass enclosing instance as a synthetic parameter.
07393:                if (optionalEnclosingInstance != null) {
07394:                    IClass outerIClass = targetClass.getOuterIClass();
07395:                    if (outerIClass != null) {
07396:                        IClass eiic = this 
07397:                                .compileGetValue(optionalEnclosingInstance);
07398:                        if (!outerIClass.isAssignableFrom(eiic))
07399:                            this .compileError("Type of enclosing instance (\""
07400:                                    + eiic + "\") is not assignable to \""
07401:                                    + outerIClass + "\"", l.getLocation());
07402:                    }
07403:                }
07404:
07405:                // Pass local variables to constructor as synthetic parameters.
07406:                {
07407:                    IClass.IField[] syntheticFields = targetClass
07408:                            .getSyntheticIFields();
07409:
07410:                    // Determine enclosing function declarator and type declaration.
07411:                    Java.TypeBodyDeclaration scopeTBD;
07412:                    Java.TypeDeclaration scopeTypeDeclaration;
07413:                    {
07414:                        Java.Scope s = scope;
07415:                        for (; !(s instanceof  Java.TypeBodyDeclaration); s = s
07416:                                .getEnclosingScope())
07417:                            ;
07418:                        scopeTBD = (Java.TypeBodyDeclaration) s;
07419:                        scopeTypeDeclaration = scopeTBD.getDeclaringType();
07420:                    }
07421:
07422:                    if (!(scopeTypeDeclaration instanceof  Java.ClassDeclaration)) {
07423:                        if (syntheticFields.length > 0)
07424:                            throw new RuntimeException(
07425:                                    "SNO: Target class has synthetic fields");
07426:                    } else {
07427:                        Java.ClassDeclaration scopeClassDeclaration = (Java.ClassDeclaration) scopeTypeDeclaration;
07428:                        for (int i = 0; i < syntheticFields.length; ++i) {
07429:                            IClass.IField sf = syntheticFields[i];
07430:                            if (!sf.getName().startsWith("val$"))
07431:                                continue;
07432:                            IClass.IField eisf = (IClass.IField) scopeClassDeclaration.syntheticFields
07433:                                    .get(sf.getName());
07434:                            if (eisf != null) {
07435:                                if (scopeTBD instanceof  Java.MethodDeclarator) {
07436:                                    this .load(l, this 
07437:                                            .resolve(scopeClassDeclaration), 0);
07438:                                    this .writeOpcode(l, Opcode.GETFIELD);
07439:                                    this .writeConstantFieldrefInfo(this 
07440:                                            .resolve(scopeClassDeclaration)
07441:                                            .getDescriptor(), sf.getName(), // classFD
07442:                                            sf.getDescriptor() // fieldFD
07443:                                            );
07444:                                } else if (scopeTBD instanceof  Java.ConstructorDeclarator) {
07445:                                    Java.ConstructorDeclarator constructorDeclarator = (Java.ConstructorDeclarator) scopeTBD;
07446:                                    Java.LocalVariable syntheticParameter = (Java.LocalVariable) constructorDeclarator.syntheticParameters
07447:                                            .get(sf.getName());
07448:                                    if (syntheticParameter == null) {
07449:                                        this 
07450:                                                .compileError(
07451:                                                        "Compiler limitation: Constructor cannot access local variable \""
07452:                                                                + sf
07453:                                                                        .getName()
07454:                                                                        .substring(
07455:                                                                                4)
07456:                                                                + "\" declared in an enclosing block because none of the methods accesses it. As a workaround, declare a dummy method that accesses the local variable.",
07457:                                                        l.getLocation());
07458:                                        this .writeOpcode(l, Opcode.ACONST_NULL);
07459:                                    } else {
07460:                                        this .load(l, syntheticParameter);
07461:                                    }
07462:                                } else {
07463:                                    this 
07464:                                            .compileError(
07465:                                                    "Compiler limitation: Initializers cannot access local variables declared in an enclosing block.",
07466:                                                    l.getLocation());
07467:                                    this .writeOpcode(l, Opcode.ACONST_NULL);
07468:                                }
07469:                            } else {
07470:                                String localVariableName = sf.getName()
07471:                                        .substring(4);
07472:                                Java.LocalVariable lv;
07473:                                DETERMINE_LV: {
07474:                                    Java.Scope s;
07475:
07476:                                    // Does one of the enclosing blocks declare a local variable with that name?
07477:                                    for (s = scope; s instanceof  Java.BlockStatement; s = s
07478:                                            .getEnclosingScope()) {
07479:                                        Java.BlockStatement bs = (Java.BlockStatement) s;
07480:                                        Java.Scope es = bs.getEnclosingScope();
07481:                                        if (!(es instanceof  Java.Block))
07482:                                            continue;
07483:                                        Java.Block b = (Java.Block) es;
07484:
07485:                                        for (Iterator it = b.statements
07486:                                                .iterator();;) {
07487:                                            Java.BlockStatement bs2 = (Java.BlockStatement) it
07488:                                                    .next();
07489:                                            if (bs2 == bs)
07490:                                                break;
07491:                                            if (bs2 instanceof  Java.LocalVariableDeclarationStatement) {
07492:                                                Java.LocalVariableDeclarationStatement lvds = ((Java.LocalVariableDeclarationStatement) bs2);
07493:                                                Java.VariableDeclarator[] vds = lvds.variableDeclarators;
07494:                                                for (int j = 0; j < vds.length; ++j) {
07495:                                                    if (vds[j].name
07496:                                                            .equals(localVariableName)) {
07497:                                                        lv = this 
07498:                                                                .getLocalVariable(
07499:                                                                        lvds,
07500:                                                                        vds[j]);
07501:                                                        break DETERMINE_LV;
07502:                                                    }
07503:                                                }
07504:                                            }
07505:                                        }
07506:                                    }
07507:
07508:                                    // Does the declaring function declare a parameter with that name?
07509:                                    while (!(s instanceof  Java.FunctionDeclarator))
07510:                                        s = s.getEnclosingScope();
07511:                                    Java.FunctionDeclarator fd = (Java.FunctionDeclarator) s;
07512:                                    for (int j = 0; j < fd.formalParameters.length; ++j) {
07513:                                        Java.FunctionDeclarator.FormalParameter fp = fd.formalParameters[j];
07514:                                        if (fp.name.equals(localVariableName)) {
07515:                                            lv = this .getLocalVariable(fp);
07516:                                            break DETERMINE_LV;
07517:                                        }
07518:                                    }
07519:                                    throw new RuntimeException(
07520:                                            "SNO: Synthetic field \""
07521:                                                    + sf.getName()
07522:                                                    + "\" neither maps a synthetic field of an enclosing instance nor a local variable");
07523:                                }
07524:                                this .load(l, lv);
07525:                            }
07526:                        }
07527:                    }
07528:                }
07529:
07530:                // Evaluate constructor arguments.
07531:                IClass[] parameterTypes = iConstructor.getParameterTypes();
07532:                for (int i = 0; i < arguments.length; ++i) {
07533:                    this .assignmentConversion(l, // l
07534:                            this .compileGetValue(arguments[i]), // sourceType
07535:                            parameterTypes[i], // targetType
07536:                            this .getConstantValue(arguments[i]) // optionalConstantValue
07537:                            );
07538:                }
07539:
07540:                // Invoke!
07541:                // Notice that the method descriptor is "iConstructor.getDescriptor()" prepended with the
07542:                // synthetic parameters.
07543:                this .writeOpcode(l, Opcode.INVOKESPECIAL);
07544:                this .writeConstantMethodrefInfo(targetClass.getDescriptor(),
07545:                        "<init>", // classFD
07546:                        iConstructor.getDescriptor() // methodMD
07547:                        );
07548:            }
07549:
07550:            /*package*/IClass.IField[] getIFields(
07551:                    final Java.FieldDeclaration fd) {
07552:                IClass.IField[] res = new IClass.IField[fd.variableDeclarators.length];
07553:                for (int i = 0; i < res.length; ++i) {
07554:                    final Java.VariableDeclarator vd = fd.variableDeclarators[i];
07555:                    res[i] = this .resolve(fd.getDeclaringType()).new IField() {
07556:
07557:                        // Implement IMember.
07558:                        public Access getAccess() {
07559:                            switch (fd.modifiers & Mod.PPP) {
07560:                            case Mod.PRIVATE:
07561:                                return Access.PRIVATE;
07562:                            case Mod.PROTECTED:
07563:                                return Access.PROTECTED;
07564:                            case Mod.PACKAGE:
07565:                                return Access.DEFAULT;
07566:                            case Mod.PUBLIC:
07567:                                return Access.PUBLIC;
07568:                            default:
07569:                                throw new RuntimeException("Invalid access");
07570:                            }
07571:                        }
07572:
07573:                        // Implement "IField".
07574:                        public boolean isStatic() {
07575:                            return (fd.modifiers & Mod.STATIC) != 0;
07576:                        }
07577:
07578:                        public IClass getType() throws CompileException {
07579:                            return UnitCompiler.this 
07580:                                    .getType(fd.type)
07581:                                    .getArrayIClass(
07582:                                            vd.brackets,
07583:                                            UnitCompiler.this .iClassLoader.OBJECT);
07584:                        }
07585:
07586:                        public String getName() {
07587:                            return vd.name;
07588:                        }
07589:
07590:                        public Object getConstantValue()
07591:                                throws CompileException {
07592:                            if ((fd.modifiers & Mod.FINAL) != 0
07593:                                    && vd.optionalInitializer instanceof  Java.Rvalue) {
07594:                                Object constantInitializerValue = UnitCompiler.this 
07595:                                        .getConstantValue((Java.Rvalue) vd.optionalInitializer);
07596:                                if (constantInitializerValue != null)
07597:                                    return UnitCompiler.this 
07598:                                            .assignmentConversion(
07599:                                                    (Locatable) vd.optionalInitializer, // l
07600:                                                    constantInitializerValue, // value
07601:                                                    this .getType() // targetType
07602:                                            );
07603:                            }
07604:                            return null;
07605:                        }
07606:                    };
07607:                }
07608:                return res;
07609:            }
07610:
07611:            /**
07612:             * Determine the non-constant-final initializer of the given {@link Java.VariableDeclarator}.
07613:             * @return <code>null</code> if the variable is declared without an initializer or if the initializer is constant-final
07614:             */
07615:            Java.ArrayInitializerOrRvalue getNonConstantFinalInitializer(
07616:                    Java.FieldDeclaration fd, Java.VariableDeclarator vd)
07617:                    throws CompileException {
07618:
07619:                // Check if optional initializer exists.
07620:                if (vd.optionalInitializer == null)
07621:                    return null;
07622:
07623:                // Check if initializer is constant-final.
07624:                if ((fd.modifiers & Mod.STATIC) != 0
07625:                        && (fd.modifiers & Mod.FINAL) != 0
07626:                        && vd.optionalInitializer instanceof  Java.Rvalue
07627:                        && this 
07628:                                .getConstantValue((Java.Rvalue) vd.optionalInitializer) != null)
07629:                    return null;
07630:
07631:                return vd.optionalInitializer;
07632:            }
07633:
07634:            private Java.Atom reclassify(Java.AmbiguousName an)
07635:                    throws CompileException {
07636:                if (an.reclassified == null) {
07637:                    an.reclassified = this .reclassifyName(an.getLocation(),
07638:                            (Java.Scope) an.getEnclosingBlockStatement(),
07639:                            an.identifiers, an.n);
07640:                }
07641:                return an.reclassified;
07642:            }
07643:
07644:            /**
07645:             * JLS 6.5.2.2
07646:             * <p>
07647:             * Reclassify the ambiguous name consisting of the first <code>n</code> of the
07648:             * <code>identifers</code>.
07649:             * @param location
07650:             * @param scope
07651:             * @param identifiers
07652:             * @param n
07653:             * @throws CompileException
07654:             */
07655:            private Java.Atom reclassifyName(Location location,
07656:                    Java.Scope scope, final String[] identifiers, int n)
07657:                    throws CompileException {
07658:
07659:                if (n == 1)
07660:                    return this .reclassifyName(location, scope, identifiers[0]);
07661:
07662:                // 6.5.2.2
07663:                Java.Atom lhs = this .reclassifyName(location, scope,
07664:                        identifiers, n - 1);
07665:                String rhs = identifiers[n - 1];
07666:
07667:                // 6.5.2.2.1
07668:                if (UnitCompiler.DEBUG)
07669:                    System.out.println("lhs = " + lhs);
07670:                if (lhs instanceof  Java.Package) {
07671:                    String className = ((Java.Package) lhs).name + '.' + rhs;
07672:                    IClass result;
07673:                    try {
07674:                        result = this .iClassLoader.loadIClass(Descriptor
07675:                                .fromClassName(className));
07676:                    } catch (ClassNotFoundException ex) {
07677:                        if (ex.getException() instanceof  CompileException)
07678:                            throw (CompileException) ex.getException();
07679:                        throw new CompileException(className, location, ex);
07680:                    }
07681:                    if (result != null)
07682:                        return new Java.SimpleType(location, result);
07683:
07684:                    return new Java.Package(location, className);
07685:                }
07686:
07687:                // 6.5.2.2.3.2 EXPRESSION.length
07688:                if (rhs.equals("length") && this .getType(lhs).isArray()) {
07689:                    Java.ArrayLength al = new Java.ArrayLength(location, this 
07690:                            .toRvalueOrCE(lhs));
07691:                    if (!(scope instanceof  Java.BlockStatement)) {
07692:                        this 
07693:                                .compileError("\".length\" only allowed in expression context");
07694:                        return al;
07695:                    }
07696:                    al.setEnclosingBlockStatement((Java.BlockStatement) scope);
07697:                    return al;
07698:                }
07699:
07700:                IClass lhsType = this .getType(lhs);
07701:
07702:                // Notice: Don't need to check for 6.5.2.2.2.1 TYPE.METHOD and 6.5.2.2.3.1
07703:                // EXPRESSION.METHOD here because that has been done before.
07704:
07705:                {
07706:                    IClass.IField field = this .findIField(lhsType, rhs,
07707:                            location);
07708:                    if (field != null) {
07709:                        // 6.5.2.2.2.2 TYPE.FIELD
07710:                        // 6.5.2.2.3.2 EXPRESSION.FIELD
07711:                        Java.FieldAccess fa = new Java.FieldAccess(location,
07712:                                lhs, field);
07713:                        fa
07714:                                .setEnclosingBlockStatement((Java.BlockStatement) scope);
07715:                        return fa;
07716:                    }
07717:                }
07718:
07719:                IClass[] classes = lhsType.getDeclaredIClasses();
07720:                for (int i = 0; i < classes.length; ++i) {
07721:                    final IClass memberType = classes[i];
07722:                    String name = Descriptor.toClassName(memberType
07723:                            .getDescriptor());
07724:                    name = name.substring(name.lastIndexOf('$') + 1);
07725:                    if (name.equals(rhs)) {
07726:
07727:                        // 6.5.2.2.2.3 TYPE.TYPE
07728:                        // 6.5.2.2.3.3 EXPRESSION.TYPE
07729:                        return new Java.SimpleType(location, memberType);
07730:                    }
07731:                }
07732:
07733:                this 
07734:                        .compileError(
07735:                                "\""
07736:                                        + rhs
07737:                                        + "\" is neither a method, a field, nor a member class of \""
07738:                                        + lhsType + "\"", location);
07739:                return new Java.Atom(location) {
07740:                    public String toString() {
07741:                        return Java.join(identifiers, ".");
07742:                    }
07743:
07744:                    public final void accept(Visitor.AtomVisitor visitor) {
07745:                    }
07746:                };
07747:            }
07748:
07749:            /**
07750:             * JLS 6.5.2.1
07751:             * @param location
07752:             * @param scope
07753:             * @param identifier
07754:             * @throws CompileException
07755:             */
07756:            private Java.Atom reclassifyName(Location location,
07757:                    Java.Scope scope, final String identifier)
07758:                    throws CompileException {
07759:
07760:                // Determine scope type body declaration, type and compilation unit.
07761:                Java.TypeBodyDeclaration scopeTBD = null;
07762:                Java.AbstractTypeDeclaration scopeTypeDeclaration = null;
07763:                Java.CompilationUnit scopeCompilationUnit;
07764:                {
07765:                    Java.Scope s = scope;
07766:                    while ((s instanceof  Java.BlockStatement || s instanceof  Java.CatchClause)
07767:                            && !(s instanceof  Java.TypeBodyDeclaration))
07768:                        s = s.getEnclosingScope();
07769:                    if (s instanceof  Java.TypeBodyDeclaration) {
07770:                        scopeTBD = (Java.TypeBodyDeclaration) s;
07771:                        s = s.getEnclosingScope();
07772:                    }
07773:                    if (s instanceof  Java.TypeDeclaration) {
07774:                        scopeTypeDeclaration = (Java.AbstractTypeDeclaration) s;
07775:                        s = s.getEnclosingScope();
07776:                    }
07777:                    while (!(s instanceof  Java.CompilationUnit))
07778:                        s = s.getEnclosingScope();
07779:                    scopeCompilationUnit = (Java.CompilationUnit) s;
07780:                }
07781:
07782:                // 6.5.2.1.BL1
07783:
07784:                // 6.5.2.BL1.B1.B1.1 (JLS3: 6.5.2.BL1.B1.B1.1) / 6.5.6.1.1 Local variable.
07785:                // 6.5.2.BL1.B1.B1.2 (JLS3: 6.5.2.BL1.B1.B1.2) / 6.5.6.1.1 Parameter.
07786:                {
07787:                    Java.Scope s = scope;
07788:                    if (s instanceof  Java.BlockStatement) {
07789:                        Java.LocalVariable lv = this .findLocalVariable(
07790:                                (Java.BlockStatement) s, identifier);
07791:                        if (lv != null) {
07792:                            Java.LocalVariableAccess lva = new Java.LocalVariableAccess(
07793:                                    location, lv);
07794:                            if (!(scope instanceof  Java.BlockStatement))
07795:                                throw new RuntimeException(
07796:                                        "SNO: Local variable access in non-block statement context!?");
07797:                            lva
07798:                                    .setEnclosingBlockStatement((Java.BlockStatement) scope);
07799:                            return lva;
07800:                        }
07801:                        s = s.getEnclosingScope();
07802:                    }
07803:                    while (s instanceof  Java.BlockStatement
07804:                            || s instanceof  Java.CatchClause)
07805:                        s = s.getEnclosingScope();
07806:                    if (s instanceof  Java.FunctionDeclarator) {
07807:                        s = s.getEnclosingScope();
07808:                        if (s instanceof  Java.InnerClassDeclaration) {
07809:                            Java.InnerClassDeclaration icd = (Java.InnerClassDeclaration) s;
07810:                            s = s.getEnclosingScope();
07811:                            if (s instanceof  Java.AnonymousClassDeclaration)
07812:                                s = s.getEnclosingScope();
07813:                            while (s instanceof  Java.BlockStatement) {
07814:                                Java.LocalVariable lv = this .findLocalVariable(
07815:                                        (Java.BlockStatement) s, identifier);
07816:                                if (lv != null) {
07817:                                    if (!lv.finaL)
07818:                                        this 
07819:                                                .compileError("Cannot access non-final local variable \""
07820:                                                        + identifier
07821:                                                        + "\" from inner class");
07822:                                    final IClass lvType = lv.type;
07823:                                    IClass.IField iField = new SimpleIField(
07824:                                            this .resolve(icd), "val$"
07825:                                                    + identifier, lvType);
07826:                                    icd.defineSyntheticField(iField);
07827:                                    Java.FieldAccess fa = new Java.FieldAccess(
07828:                                            location, // location
07829:                                            new Java.QualifiedThisReference( // lhs
07830:                                                    location, // location
07831:                                                    new Java.SimpleType(
07832:                                                            location,
07833:                                                            this .resolve(icd)) // qualification
07834:                                            ), iField // field
07835:                                    );
07836:                                    fa
07837:                                            .setEnclosingBlockStatement((Java.BlockStatement) scope);
07838:                                    return fa;
07839:                                }
07840:                                s = s.getEnclosingScope();
07841:                                while (s instanceof  Java.BlockStatement)
07842:                                    s = s.getEnclosingScope();
07843:                                if (!(s instanceof  Java.FunctionDeclarator))
07844:                                    break;
07845:                                s = s.getEnclosingScope();
07846:                                if (!(s instanceof  Java.InnerClassDeclaration))
07847:                                    break;
07848:                                icd = (Java.InnerClassDeclaration) s;
07849:                                s = s.getEnclosingScope();
07850:                            }
07851:                        }
07852:                    }
07853:                }
07854:
07855:                // 6.5.2.BL1.B1.B1.3 (JLS3: 6.5.2.BL1.B1.B1.3) / 6.5.6.1.2.1 Field.
07856:                Java.BlockStatement enclosingBlockStatement = null;
07857:                for (Java.Scope s = scope; !(s instanceof  Java.CompilationUnit); s = s
07858:                        .getEnclosingScope()) {
07859:                    if (s instanceof  Java.BlockStatement
07860:                            && enclosingBlockStatement == null)
07861:                        enclosingBlockStatement = (Java.BlockStatement) s;
07862:                    if (s instanceof  Java.TypeDeclaration) {
07863:                        final IClass etd = UnitCompiler.this 
07864:                                .resolve((Java.AbstractTypeDeclaration) s);
07865:                        final IClass.IField f = this .findIField(etd,
07866:                                identifier, location);
07867:                        if (f != null) {
07868:                            if (f.isStatic()) {
07869:                                this 
07870:                                        .warning(
07871:                                                "IASF",
07872:                                                "Implicit access to static field \""
07873:                                                        + identifier
07874:                                                        + "\" of declaring class (better write \""
07875:                                                        + f
07876:                                                                .getDeclaringIClass()
07877:                                                        + '.' + f.getName()
07878:                                                        + "\")", location);
07879:                            } else if (f.getDeclaringIClass() == etd) {
07880:                                this 
07881:                                        .warning(
07882:                                                "IANSF",
07883:                                                "Implicit access to non-static field \""
07884:                                                        + identifier
07885:                                                        + "\" of declaring class (better write \"this."
07886:                                                        + f.getName() + "\")",
07887:                                                location);
07888:                            } else {
07889:                                this 
07890:                                        .warning(
07891:                                                "IANSFEI",
07892:                                                "Implicit access to non-static field \""
07893:                                                        + identifier
07894:                                                        + "\" of enclosing instance (better write \""
07895:                                                        + f
07896:                                                                .getDeclaringIClass()
07897:                                                        + ".this."
07898:                                                        + f.getName() + "\")",
07899:                                                location);
07900:                            }
07901:
07902:                            Java.Type ct = new Java.SimpleType(
07903:                                    scopeTypeDeclaration.getLocation(),
07904:                                    (IClass) etd);
07905:                            Java.Atom lhs;
07906:                            if (scopeTBD.isStatic()) {
07907:
07908:                                // Field access in static method context.
07909:                                lhs = ct;
07910:                            } else {
07911:
07912:                                // Field access in non-static method context.
07913:                                if (f.isStatic()) {
07914:
07915:                                    // Access to static field.
07916:                                    lhs = ct;
07917:                                } else {
07918:
07919:                                    // Access to non-static field.
07920:                                    lhs = new Java.QualifiedThisReference(
07921:                                            location, ct);
07922:                                }
07923:                            }
07924:                            Java.FieldAccess fa = new Java.FieldAccess(
07925:                                    location, lhs, f);
07926:                            fa
07927:                                    .setEnclosingBlockStatement(enclosingBlockStatement);
07928:                            return fa;
07929:                        }
07930:                    }
07931:                }
07932:
07933:                // JLS3 6.5.2.BL1.B1.B2.1 Static field imported through single static import.
07934:                {
07935:                    Object o = this .singleStaticImports.get(identifier);
07936:                    if (o instanceof  IField)
07937:                        return new FieldAccess(location, new SimpleType(
07938:                                location, ((IField) o).getDeclaringIClass()),
07939:                                (IField) o);
07940:                }
07941:
07942:                // JLS3 6.5.2.BL1.B1.B2.2 Static field imported through static-import-on-demand.
07943:                for (Iterator it = this .staticImportsOnDemand.iterator(); it
07944:                        .hasNext();) {
07945:                    IClass iClass = (IClass) it.next();
07946:                    IField[] flds = iClass.getDeclaredIFields();
07947:                    for (int i = 0; i < flds.length; ++i) {
07948:                        IField f = flds[i];
07949:                        if (f.getName().equals(identifier))
07950:                            return new FieldAccess(location, new SimpleType(
07951:                                    location, iClass), f);
07952:                    }
07953:                }
07954:
07955:                // Hack: "java" MUST be a package, not a class.
07956:                if (identifier.equals("java"))
07957:                    return new Java.Package(location, identifier);
07958:
07959:                // 6.5.2.BL1.B1.B2.1 (JLS3: 6.5.2.BL1.B1.B3.2) Local class.
07960:                {
07961:                    Java.LocalClassDeclaration lcd = this 
07962:                            .findLocalClassDeclaration(scope, identifier);
07963:                    if (lcd != null)
07964:                        return new Java.SimpleType(location, this .resolve(lcd));
07965:                }
07966:
07967:                // 6.5.2.BL1.B1.B2.2 (JLS3: 6.5.2.BL1.B1.B3.3) Member type.
07968:                if (scopeTypeDeclaration != null) {
07969:                    IClass memberType = this .findMemberType(UnitCompiler.this 
07970:                            .resolve(scopeTypeDeclaration), identifier,
07971:                            location);
07972:                    if (memberType != null)
07973:                        return new Java.SimpleType(location, memberType);
07974:                }
07975:
07976:                // 6.5.2.BL1.B1.B3.1 (JLS3: 6.5.2.BL1.B1.B4.1) Single type import.
07977:                if (scopeCompilationUnit != null) {
07978:                    IClass iClass = this .importSingleType(identifier, location);
07979:                    if (iClass != null)
07980:                        return new Java.SimpleType(location, iClass);
07981:                }
07982:
07983:                // 6.5.2.BL1.B1.B3.2 (JLS3: 6.5.2.BL1.B1.B3.1) Package member class/interface declared in this compilation unit.
07984:                // Notice that JLS2 looks this up AFTER local class, member type, single type import, while
07985:                // JLS3 looks this up BEFORE local class, member type, single type import.
07986:                if (scopeCompilationUnit != null) {
07987:                    Java.PackageMemberTypeDeclaration pmtd = scopeCompilationUnit
07988:                            .getPackageMemberTypeDeclaration(identifier);
07989:                    if (pmtd != null)
07990:                        return new Java.SimpleType(location, this 
07991:                                .resolve((Java.AbstractTypeDeclaration) pmtd));
07992:                }
07993:
07994:                // 6.5.2.BL1.B1.B4 Class or interface declared in same package.
07995:                // Notice: Why is this missing in JLS3?
07996:                if (scopeCompilationUnit != null) {
07997:                    String className = (scopeCompilationUnit.optionalPackageDeclaration == null ? identifier
07998:                            : scopeCompilationUnit.optionalPackageDeclaration.packageName
07999:                                    + '.' + identifier);
08000:                    IClass result;
08001:                    try {
08002:                        result = this .iClassLoader.loadIClass(Descriptor
08003:                                .fromClassName(className));
08004:                    } catch (ClassNotFoundException ex) {
08005:                        if (ex.getException() instanceof  CompileException)
08006:                            throw (CompileException) ex.getException();
08007:                        throw new CompileException(className, location, ex);
08008:                    }
08009:                    if (result != null)
08010:                        return new Java.SimpleType(location, result);
08011:                }
08012:
08013:                // 6.5.2.BL1.B1.B5 (JLS3: 6.5.2.BL1.B1.B4.2), 6.5.2.BL1.B1.B6 Type-import-on-demand.
08014:                if (scopeCompilationUnit != null) {
08015:                    IClass importedClass = this .importTypeOnDemand(identifier,
08016:                            location);
08017:                    if (importedClass != null) {
08018:                        return new Java.SimpleType(location, importedClass);
08019:                    }
08020:                }
08021:
08022:                // JLS3 6.5.2.BL1.B1.B4.3 Type imported through single static import.
08023:                {
08024:                    Object o = this .singleStaticImports.get(identifier);
08025:                    if (o instanceof  IClass)
08026:                        return new SimpleType(null, (IClass) o);
08027:                }
08028:
08029:                // JLS3 6.5.2.BL1.B1.B4.4 Type imported through static-import-on-demand.
08030:                {
08031:                    for (Iterator it = this .staticImportsOnDemand.iterator(); it
08032:                            .hasNext();) {
08033:                        IClass ic = (IClass) it.next();
08034:                        IClass[] memberTypes = ic.getDeclaredIClasses();
08035:                        for (int i = 0; i < memberTypes.length; ++i) {
08036:                            IClass mt = memberTypes[i];
08037:                            if (mt.getDescriptor().endsWith(
08038:                                    '$' + identifier + ';'))
08039:                                return new Java.SimpleType(null, mt);
08040:                        }
08041:                    }
08042:                }
08043:
08044:                // 6.5.2.BL1.B1.B7 Package name
08045:                return new Java.Package(location, identifier);
08046:            }
08047:
08048:            /**
08049:             * Find a local variable declared by the given <code>blockStatement</code> or any enclosing
08050:             * scope up to the {@link Java.FunctionDeclarator}.
08051:             */
08052:            private Java.LocalVariable findLocalVariable(
08053:                    Java.BlockStatement blockStatement, String name)
08054:                    throws CompileException {
08055:                for (Java.Scope s = blockStatement; !(s instanceof  Java.CompilationUnit);) {
08056:                    Java.Scope es = s.getEnclosingScope();
08057:                    {
08058:                        if (s instanceof  Java.ForStatement) {
08059:                            Java.BlockStatement optionalForInit = ((Java.ForStatement) s).optionalInit;
08060:                            if (optionalForInit instanceof  Java.LocalVariableDeclarationStatement) {
08061:                                Java.LocalVariable lv = this 
08062:                                        .findLocalVariable(
08063:                                                (Java.LocalVariableDeclarationStatement) optionalForInit,
08064:                                                name);
08065:                                if (lv != null)
08066:                                    return lv;
08067:                            }
08068:                        }
08069:                        if (es instanceof  Java.Block) {
08070:                            Java.Block b = (Java.Block) es;
08071:                            for (Iterator it = b.statements.iterator();;) {
08072:                                Java.BlockStatement bs2 = (Java.BlockStatement) it
08073:                                        .next();
08074:                                if (bs2 instanceof  Java.LocalVariableDeclarationStatement) {
08075:                                    Java.LocalVariable lv = this 
08076:                                            .findLocalVariable(
08077:                                                    (Java.LocalVariableDeclarationStatement) bs2,
08078:                                                    name);
08079:                                    if (lv != null)
08080:                                        return lv;
08081:                                }
08082:                                if (bs2 == s)
08083:                                    break;
08084:                            }
08085:                        }
08086:                        if (es instanceof  Java.SwitchStatement) {
08087:                            Java.SwitchStatement ss = (Java.SwitchStatement) es;
08088:                            SBSGS: for (Iterator it2 = ss.sbsgs.iterator();;) {
08089:                                Java.SwitchStatement.SwitchBlockStatementGroup sbgs = (Java.SwitchStatement.SwitchBlockStatementGroup) it2
08090:                                        .next();
08091:                                for (Iterator it = sbgs.blockStatements
08092:                                        .iterator(); it.hasNext();) {
08093:                                    Java.BlockStatement bs2 = (Java.BlockStatement) it
08094:                                            .next();
08095:                                    if (bs2 instanceof  Java.LocalVariableDeclarationStatement) {
08096:                                        Java.LocalVariable lv = this 
08097:                                                .findLocalVariable(
08098:                                                        (Java.LocalVariableDeclarationStatement) bs2,
08099:                                                        name);
08100:                                        if (lv != null)
08101:                                            return lv;
08102:                                    }
08103:                                    if (bs2 == s)
08104:                                        break SBSGS;
08105:                                }
08106:                            }
08107:                        }
08108:                        if (s instanceof  Java.FunctionDeclarator) {
08109:                            Java.FunctionDeclarator fd = (Java.FunctionDeclarator) s;
08110:                            Java.FunctionDeclarator.FormalParameter[] fps = fd.formalParameters;
08111:                            for (int i = 0; i < fps.length; ++i) {
08112:                                if (fps[i].name.equals(name))
08113:                                    return this .getLocalVariable(fps[i]);
08114:                            }
08115:                            return null;
08116:                        }
08117:                        if (s instanceof  Java.CatchClause) {
08118:                            Java.CatchClause cc = (Java.CatchClause) s;
08119:                            if (cc.caughtException.name.equals(name))
08120:                                return this 
08121:                                        .getLocalVariable(cc.caughtException);
08122:                        }
08123:                    }
08124:                    s = es;
08125:                }
08126:                return null;
08127:            }
08128:
08129:            /**
08130:             * Check whether the given {@link Java.LocalVariableDeclarationStatement} declares a variable
08131:             * with the given <code>name</code>.
08132:             */
08133:            private Java.LocalVariable findLocalVariable(
08134:                    Java.LocalVariableDeclarationStatement lvds, String name)
08135:                    throws CompileException {
08136:                Java.VariableDeclarator[] vds = lvds.variableDeclarators;
08137:                for (int i = 0; i < vds.length; ++i) {
08138:                    if (vds[i].name.equals(name))
08139:                        return this .getLocalVariable(lvds, vds[i]);
08140:                }
08141:                return null;
08142:            }
08143:
08144:            private void determineValue(Java.FieldAccessExpression fae)
08145:                    throws CompileException {
08146:                if (fae.value != null)
08147:                    return;
08148:
08149:                IClass lhsType = this .getType(fae.lhs);
08150:
08151:                if (fae.fieldName.equals("length") && lhsType.isArray()) {
08152:                    fae.value = new Java.ArrayLength(fae.getLocation(), this 
08153:                            .toRvalueOrCE(fae.lhs));
08154:                } else {
08155:                    IClass.IField iField = this .findIField(lhsType,
08156:                            fae.fieldName, fae.getLocation());
08157:                    if (iField == null) {
08158:                        this .compileError("\""
08159:                                + this .getType(fae.lhs).toString()
08160:                                + "\" has no field \"" + fae.fieldName + "\"",
08161:                                fae.getLocation());
08162:                        fae.value = new Java.Rvalue(fae.getLocation()) {
08163:                            //                    public IClass compileGet() throws CompileException { return this.iClassLoader.OBJECT; }
08164:                            public String toString() {
08165:                                return "???";
08166:                            }
08167:
08168:                            public final void accept(Visitor.AtomVisitor visitor) {
08169:                            }
08170:
08171:                            public final void accept(
08172:                                    Visitor.RvalueVisitor visitor) {
08173:                            }
08174:                        };
08175:                        return;
08176:                    }
08177:                    fae.value = new Java.FieldAccess(fae.getLocation(),
08178:                            fae.lhs, iField);
08179:                }
08180:                fae.value.setEnclosingBlockStatement(fae
08181:                        .getEnclosingBlockStatement());
08182:            }
08183:
08184:            /** "super.fld", "Type.super.fld" */
08185:            private void determineValue(
08186:                    Java.SuperclassFieldAccessExpression scfae)
08187:                    throws CompileException {
08188:                if (scfae.value != null)
08189:                    return;
08190:
08191:                Rvalue lhs;
08192:                {
08193:                    Java.ThisReference tr = new Java.ThisReference(scfae
08194:                            .getLocation());
08195:                    tr.setEnclosingBlockStatement(scfae
08196:                            .getEnclosingBlockStatement());
08197:                    IClass type;
08198:                    if (scfae.optionalQualification != null) {
08199:                        type = UnitCompiler.this 
08200:                                .getType(scfae.optionalQualification);
08201:                    } else {
08202:                        type = this .getType(tr);
08203:                    }
08204:                    lhs = new Java.Cast(scfae.getLocation(), new SimpleType(
08205:                            scfae.getLocation(), type.getSuperclass()), tr);
08206:                }
08207:
08208:                IClass.IField iField = this .findIField(this .getType(lhs),
08209:                        scfae.fieldName, scfae.getLocation());
08210:                if (iField == null) {
08211:                    this .compileError("Class has no field \"" + scfae.fieldName
08212:                            + "\"", scfae.getLocation());
08213:                    scfae.value = new Java.Rvalue(scfae.getLocation()) {
08214:                        public String toString() {
08215:                            return "???";
08216:                        }
08217:
08218:                        public final void accept(Visitor.AtomVisitor visitor) {
08219:                        }
08220:
08221:                        public final void accept(Visitor.RvalueVisitor visitor) {
08222:                        }
08223:                    };
08224:                    return;
08225:                }
08226:                scfae.value = new Java.FieldAccess(scfae.getLocation(), lhs,
08227:                        iField);
08228:                scfae.value.setEnclosingBlockStatement(scfae
08229:                        .getEnclosingBlockStatement());
08230:            }
08231:
08232:            /**
08233:             * Find named methods of "targetType", examine the argument types and choose the
08234:             * most specific method. Check that only the allowed exceptions are thrown.
08235:             * <p>
08236:             * Notice that the returned {@link IClass.IMethod} may be declared in an enclosing type.
08237:             *
08238:             * @return The selected {@link IClass.IMethod} or <code>null</code>
08239:             */
08240:            public IClass.IMethod findIMethod(Java.MethodInvocation mi)
08241:                    throws CompileException {
08242:                IClass.IMethod iMethod;
08243:                FIND_METHOD: {
08244:
08245:                    // Method declared by enclosing type declarations?
08246:                    for (Java.Scope s = mi.getEnclosingBlockStatement(); !(s instanceof  Java.CompilationUnit); s = s
08247:                            .getEnclosingScope()) {
08248:                        if (s instanceof  Java.TypeDeclaration) {
08249:                            Java.TypeDeclaration td = (Java.TypeDeclaration) s;
08250:
08251:                            // Find methods with specified name.
08252:                            iMethod = this .findIMethod(
08253:                                    (Locatable) mi, // l
08254:                                    ( // targetType
08255:                                    mi.optionalTarget == null ? this 
08256:                                            .resolve(td) : this 
08257:                                            .getType(mi.optionalTarget)),
08258:                                    mi.methodName, // methodName
08259:                                    mi.arguments // arguments
08260:                                    );
08261:                            if (iMethod != null)
08262:                                break FIND_METHOD;
08263:                        }
08264:                    }
08265:
08266:                    // Static method declared through single static import?
08267:                    {
08268:                        Object o = this .singleStaticImports.get(mi.methodName);
08269:                        if (o instanceof  List) {
08270:                            IClass declaringIClass = ((IMethod) ((List) o)
08271:                                    .get(0)).getDeclaringIClass();
08272:                            iMethod = this .findIMethod((Locatable) mi, // l
08273:                                    declaringIClass, // targetType
08274:                                    mi.methodName, // methodName
08275:                                    mi.arguments // arguments
08276:                                    );
08277:                            if (iMethod != null)
08278:                                break FIND_METHOD;
08279:                        }
08280:                    }
08281:
08282:                    // Static method declared through static-import-on-demand?
08283:                    for (Iterator it = this .staticImportsOnDemand.iterator(); it
08284:                            .hasNext();) {
08285:                        IClass iClass = (IClass) it.next();
08286:                        iMethod = this .findIMethod((Locatable) mi, // l
08287:                                iClass, // targetType
08288:                                mi.methodName, // methodName
08289:                                mi.arguments // arguments
08290:                                );
08291:                        if (iMethod != null)
08292:                            break FIND_METHOD;
08293:                    }
08294:
08295:                    this 
08296:                            .compileError(
08297:                                    "A method named \""
08298:                                            + mi.methodName
08299:                                            + "\" is not declared in any enclosing class nor any supertype, nor through a static import",
08300:                                    mi.getLocation());
08301:                    return fakeIMethod(this .iClassLoader.OBJECT, mi.methodName,
08302:                            mi.arguments);
08303:                }
08304:
08305:                this .checkThrownExceptions(mi, iMethod);
08306:                return iMethod;
08307:            }
08308:
08309:            /**
08310:             * Find {@link IClass.IMethod} by name and argument types. If more than one such
08311:             * method exists, choose the most specific one (JLS 15.11.2).
08312:             * <p>
08313:             * Notice that the returned {@link IClass.IMethod} may be declared in an enclosing type.
08314:             *
08315:             * @return <code>null</code> if no appropriate method could be found
08316:             */
08317:            private IClass.IMethod findIMethod(Locatable l, IClass targetType,
08318:                    String methodName, Rvalue[] arguments)
08319:                    throws CompileException {
08320:                for (IClass ic = targetType; ic != null; ic = ic
08321:                        .getDeclaringIClass()) {
08322:                    List ms = new ArrayList();
08323:                    this .getIMethods(ic, methodName, ms);
08324:                    if (ms.size() > 0) {
08325:
08326:                        // Determine arguments' types, choose the most specific method
08327:                        IClass.IMethod iMethod = (IClass.IMethod) this 
08328:                                .findMostSpecificIInvocable(l, // l
08329:                                        (IClass.IMethod[]) ms
08330:                                                .toArray(new IClass.IMethod[ms
08331:                                                        .size()]), // iInvocables
08332:                                        arguments // arguments
08333:                                );
08334:                        return iMethod;
08335:                    }
08336:                }
08337:                return null;
08338:            }
08339:
08340:            private IMethod fakeIMethod(IClass targetType, final String name,
08341:                    Rvalue[] arguments) throws CompileException {
08342:                final IClass[] pts = new IClass[arguments.length];
08343:                for (int i = 0; i < arguments.length; ++i)
08344:                    pts[i] = this .getType(arguments[i]);
08345:                return targetType.new IMethod() {
08346:                    public String getName() {
08347:                        return name;
08348:                    }
08349:
08350:                    public IClass getReturnType() throws CompileException {
08351:                        return IClass.INT;
08352:                    }
08353:
08354:                    public boolean isStatic() {
08355:                        return false;
08356:                    }
08357:
08358:                    public boolean isAbstract() {
08359:                        return false;
08360:                    }
08361:
08362:                    public IClass[] getParameterTypes() throws CompileException {
08363:                        return pts;
08364:                    }
08365:
08366:                    public IClass[] getThrownExceptions()
08367:                            throws CompileException {
08368:                        return new IClass[0];
08369:                    }
08370:
08371:                    public Access getAccess() {
08372:                        return Access.PUBLIC;
08373:                    }
08374:                };
08375:            }
08376:
08377:            /**
08378:             * Add all methods with the given <code>methodName</code> that are declared
08379:             * by the <code>type</code>, its superclasses and all their superinterfaces
08380:             * to the result list <code>v</code>.
08381:             * @param type
08382:             * @param methodName
08383:             * @param v
08384:             * @throws CompileException
08385:             */
08386:            public void getIMethods(IClass type, String methodName, List v // IMethod
08387:            ) throws CompileException {
08388:
08389:                // Check methods declared by this type.
08390:                {
08391:                    IClass.IMethod[] ims = type.getDeclaredIMethods(methodName);
08392:                    for (int i = 0; i < ims.length; ++i)
08393:                        v.add(ims[i]);
08394:                }
08395:
08396:                // Check superclass.
08397:                IClass super class = type.getSuperclass();
08398:                if (super class != null)
08399:                    this .getIMethods(super class, methodName, v);
08400:
08401:                // Check superinterfaces.
08402:                IClass[] interfaces = type.getInterfaces();
08403:                for (int i = 0; i < interfaces.length; ++i)
08404:                    this .getIMethods(interfaces[i], methodName, v);
08405:
08406:                // JLS2 6.4.3
08407:                if (super class == null && interfaces.length == 0
08408:                        && type.isInterface()) {
08409:                    IClass.IMethod[] oms = this .iClassLoader.OBJECT
08410:                            .getDeclaredIMethods(methodName);
08411:                    for (int i = 0; i < oms.length; ++i) {
08412:                        IClass.IMethod om = oms[i];
08413:                        if (!om.isStatic() && om.getAccess() == Access.PUBLIC)
08414:                            v.add(om);
08415:                    }
08416:                }
08417:            }
08418:
08419:            public IClass.IMethod findIMethod(
08420:                    Java.SuperclassMethodInvocation scmi)
08421:                    throws CompileException {
08422:                Java.ClassDeclaration declaringClass;
08423:                for (Java.Scope s = scmi.getEnclosingBlockStatement();; s = s
08424:                        .getEnclosingScope()) {
08425:                    if (s instanceof  Java.FunctionDeclarator) {
08426:                        Java.FunctionDeclarator fd = (Java.FunctionDeclarator) s;
08427:                        if ((fd.modifiers & Mod.STATIC) != 0)
08428:                            this 
08429:                                    .compileError(
08430:                                            "Superclass method cannot be invoked in static context",
08431:                                            scmi.getLocation());
08432:                    }
08433:                    if (s instanceof  Java.ClassDeclaration) {
08434:                        declaringClass = (Java.ClassDeclaration) s;
08435:                        break;
08436:                    }
08437:                }
08438:                IClass super class = this .resolve(declaringClass)
08439:                        .getSuperclass();
08440:                IMethod iMethod = this .findIMethod((Locatable) scmi, // l
08441:                        super class, // targetType
08442:                        scmi.methodName, // methodName
08443:                        scmi.arguments // arguments
08444:                        );
08445:                if (iMethod == null) {
08446:                    this .compileError("Class \"" + super class
08447:                            + "\" has no method named \"" + scmi.methodName
08448:                            + "\"", scmi.getLocation());
08449:                    return fakeIMethod(super class, scmi.methodName,
08450:                            scmi.arguments);
08451:                }
08452:                this .checkThrownExceptions(scmi, iMethod);
08453:                return iMethod;
08454:            }
08455:
08456:            /**
08457:             * Determine the arguments' types, determine the applicable invocables and choose the most
08458:             * specific invocable.
08459:             *
08460:             * @param iInvocables Length must be greater than zero
08461:             *
08462:             * @return The selected {@link IClass.IInvocable}
08463:             * @throws CompileException
08464:             */
08465:            private IClass.IInvocable findMostSpecificIInvocable(Locatable l,
08466:                    final IInvocable[] iInvocables, Rvalue[] arguments)
08467:                    throws CompileException {
08468:
08469:                // Determine arguments' types.
08470:                final IClass[] argumentTypes = new IClass[arguments.length];
08471:                for (int i = 0; i < arguments.length; ++i) {
08472:                    argumentTypes[i] = this .getType(arguments[i]);
08473:                }
08474:
08475:                IInvocable ii = this .findMostSpecificIInvocable(l, iInvocables,
08476:                        argumentTypes, false);
08477:                if (ii != null)
08478:                    return ii;
08479:
08480:                ii = this .findMostSpecificIInvocable(l, iInvocables,
08481:                        argumentTypes, true);
08482:                if (ii != null)
08483:                    return ii;
08484:
08485:                // Report a nice compile error.
08486:                StringBuffer sb = new StringBuffer(
08487:                        "No applicable constructor/method found for ");
08488:                if (argumentTypes.length == 0) {
08489:                    sb.append("zero actual parameters");
08490:                } else {
08491:                    sb.append("actual parameters \"").append(argumentTypes[0]);
08492:                    for (int i = 1; i < argumentTypes.length; ++i) {
08493:                        sb.append(", ").append(argumentTypes[i]);
08494:                    }
08495:                    sb.append("\"");
08496:                }
08497:                sb.append("; candidates are: ").append(
08498:                        '"' + iInvocables[0].toString() + '"');
08499:                for (int i = 1; i < iInvocables.length; ++i) {
08500:                    sb.append(", ").append(
08501:                            '"' + iInvocables[i].toString() + '"');
08502:                }
08503:                this .compileError(sb.toString(), l.getLocation());
08504:
08505:                // Well, returning a "fake" IInvocable is a bit tricky, because the iInvocables
08506:                // can be of different types.
08507:                if (iInvocables[0] instanceof  IClass.IConstructor) {
08508:                    return iInvocables[0].getDeclaringIClass().new IConstructor() {
08509:                        public IClass[] getParameterTypes() {
08510:                            return argumentTypes;
08511:                        }
08512:
08513:                        public Access getAccess() {
08514:                            return Access.PUBLIC;
08515:                        }
08516:
08517:                        public IClass[] getThrownExceptions() {
08518:                            return new IClass[0];
08519:                        }
08520:                    };
08521:                } else if (iInvocables[0] instanceof  IClass.IMethod) {
08522:                    return iInvocables[0].getDeclaringIClass().new IMethod() {
08523:                        public boolean isStatic() {
08524:                            return true;
08525:                        }
08526:
08527:                        public boolean isAbstract() {
08528:                            return false;
08529:                        }
08530:
08531:                        public IClass getReturnType() {
08532:                            return IClass.INT;
08533:                        }
08534:
08535:                        public String getName() {
08536:                            return ((IClass.IMethod) iInvocables[0]).getName();
08537:                        }
08538:
08539:                        public Access getAccess() {
08540:                            return Access.PUBLIC;
08541:                        }
08542:
08543:                        public IClass[] getParameterTypes() {
08544:                            return argumentTypes;
08545:                        }
08546:
08547:                        public IClass[] getThrownExceptions() {
08548:                            return new IClass[0];
08549:                        }
08550:                    };
08551:                } else {
08552:                    return iInvocables[0];
08553:                }
08554:            }
08555:
08556:            /**
08557:             * Determine the applicable invocables and choose the most specific invocable.
08558:             * 
08559:             * @return the maximally specific {@link IClass.IInvocable} or <code>null</code> if no {@link IClass.IInvocable} is applicable
08560:             *
08561:             * @throws CompileException
08562:             */
08563:            public IClass.IInvocable findMostSpecificIInvocable(Locatable l,
08564:                    final IInvocable[] iInvocables,
08565:                    final IClass[] argumentTypes, boolean boxingPermitted)
08566:                    throws CompileException {
08567:                if (UnitCompiler.DEBUG) {
08568:                    System.out.println("Argument types:");
08569:                    for (int i = 0; i < argumentTypes.length; ++i) {
08570:                        System.out.println(argumentTypes[i]);
08571:                    }
08572:                }
08573:
08574:                // Select applicable methods (15.12.2.1).
08575:                List applicableIInvocables = new ArrayList();
08576:                NEXT_METHOD: for (int i = 0; i < iInvocables.length; ++i) {
08577:                    IClass.IInvocable ii = iInvocables[i];
08578:
08579:                    // Check parameter count.
08580:                    IClass[] parameterTypes = ii.getParameterTypes();
08581:                    if (parameterTypes.length != argumentTypes.length)
08582:                        continue;
08583:
08584:                    // Check argument types vs. parameter types.
08585:                    if (UnitCompiler.DEBUG)
08586:                        System.out.println("Parameter / argument type check:");
08587:                    for (int j = 0; j < argumentTypes.length; ++j) {
08588:                        // Is method invocation conversion possible (5.3)?
08589:                        if (UnitCompiler.DEBUG)
08590:                            System.out.println(parameterTypes[j] + " <=> "
08591:                                    + argumentTypes[j]);
08592:                        if (!this .isMethodInvocationConvertible(
08593:                                argumentTypes[j], parameterTypes[j],
08594:                                boxingPermitted))
08595:                            continue NEXT_METHOD;
08596:                    }
08597:
08598:                    // Applicable!
08599:                    if (UnitCompiler.DEBUG)
08600:                        System.out.println("Applicable!");
08601:                    applicableIInvocables.add(ii);
08602:                }
08603:                if (applicableIInvocables.size() == 0)
08604:                    return null;
08605:
08606:                // Choose the most specific invocable (15.12.2.2).
08607:                if (applicableIInvocables.size() == 1) {
08608:                    return (IClass.IInvocable) applicableIInvocables.get(0);
08609:                }
08610:
08611:                // Determine the "maximally specific invocables".
08612:                List maximallySpecificIInvocables = new ArrayList();
08613:                for (int i = 0; i < applicableIInvocables.size(); ++i) {
08614:                    IClass.IInvocable applicableIInvocable = (IClass.IInvocable) applicableIInvocables
08615:                            .get(i);
08616:                    int moreSpecific = 0, lessSpecific = 0;
08617:                    for (int j = 0; j < maximallySpecificIInvocables.size(); ++j) {
08618:                        IClass.IInvocable mostSpecificIInvocable = (IClass.IInvocable) maximallySpecificIInvocables
08619:                                .get(j);
08620:                        if (applicableIInvocable
08621:                                .isMoreSpecificThan(mostSpecificIInvocable)) {
08622:                            ++moreSpecific;
08623:                        } else if (applicableIInvocable
08624:                                .isLessSpecificThan(mostSpecificIInvocable)) {
08625:                            ++lessSpecific;
08626:                        }
08627:                    }
08628:                    if (moreSpecific == maximallySpecificIInvocables.size()) {
08629:                        maximallySpecificIInvocables.clear();
08630:                        maximallySpecificIInvocables.add(applicableIInvocable);
08631:                    } else if (lessSpecific < maximallySpecificIInvocables
08632:                            .size()) {
08633:                        maximallySpecificIInvocables.add(applicableIInvocable);
08634:                    } else {
08635:                        ;
08636:                    }
08637:                    if (UnitCompiler.DEBUG)
08638:                        System.out.println("maximallySpecificIInvocables="
08639:                                + maximallySpecificIInvocables);
08640:                }
08641:
08642:                if (maximallySpecificIInvocables.size() == 1)
08643:                    return (IClass.IInvocable) maximallySpecificIInvocables
08644:                            .get(0);
08645:
08646:                ONE_NON_ABSTRACT_INVOCABLE: if (maximallySpecificIInvocables
08647:                        .size() > 1
08648:                        && iInvocables[0] instanceof  IClass.IMethod) {
08649:                    final IClass.IMethod im = (IClass.IMethod) maximallySpecificIInvocables
08650:                            .get(0);
08651:
08652:                    // Check if all methods have the same signature (i.e. the types of all their
08653:                    // parameters are identical) and exactly one of the methods is non-abstract
08654:                    // (JLS 15.12.2.2.BL2.B1).
08655:                    IClass.IMethod theNonAbstractMethod = null;
08656:                    {
08657:                        Iterator it = maximallySpecificIInvocables.iterator();
08658:                        IClass.IMethod m = (IClass.IMethod) it.next();
08659:                        IClass[] parameterTypesOfFirstMethod = m
08660:                                .getParameterTypes();
08661:                        for (;;) {
08662:                            if (!m.isAbstract()) {
08663:                                if (theNonAbstractMethod != null) {
08664:                                    IClass declaringIClass = m
08665:                                            .getDeclaringIClass();
08666:                                    IClass theNonAbstractMethodDeclaringIClass = theNonAbstractMethod
08667:                                            .getDeclaringIClass();
08668:                                    if (declaringIClass
08669:                                            .isAssignableFrom(theNonAbstractMethodDeclaringIClass)) {
08670:                                        ;
08671:                                    } else if (theNonAbstractMethodDeclaringIClass
08672:                                            .isAssignableFrom(declaringIClass)) {
08673:                                        theNonAbstractMethod = m;
08674:                                    } else {
08675:                                        throw new RuntimeException(
08676:                                                "SNO: More than one non-abstract method with same signature and same declaring class!?");
08677:                                    }
08678:                                }
08679:                            }
08680:                            if (!it.hasNext())
08681:                                break;
08682:
08683:                            m = (IClass.IMethod) it.next();
08684:                            IClass[] pts = m.getParameterTypes();
08685:                            for (int i = 0; i < pts.length; ++i) {
08686:                                if (pts[i] != parameterTypesOfFirstMethod[i])
08687:                                    break ONE_NON_ABSTRACT_INVOCABLE;
08688:                            }
08689:                        }
08690:                    }
08691:
08692:                    // JLS 15.12.2.2.BL2.B1.B1
08693:                    if (theNonAbstractMethod != null)
08694:                        return theNonAbstractMethod;
08695:
08696:                    // JLS 15.12.2.2.BL2.B1.B2
08697:                    Set s = new HashSet();
08698:                    {
08699:                        IClass[][] tes = new IClass[maximallySpecificIInvocables
08700:                                .size()][];
08701:                        Iterator it = maximallySpecificIInvocables.iterator();
08702:                        for (int i = 0; i < tes.length; ++i) {
08703:                            tes[i] = ((IClass.IMethod) it.next())
08704:                                    .getThrownExceptions();
08705:                        }
08706:                        for (int i = 0; i < tes.length; ++i) {
08707:                            EACH_EXCEPTION: for (int j = 0; j < tes[i].length; ++j) {
08708:
08709:                                // Check whether "that exception [te1] is declared in the THROWS
08710:                                // clause of each of the maximally specific methods".
08711:                                IClass te1 = tes[i][j];
08712:                                EACH_METHOD: for (int k = 0; k < tes.length; ++k) {
08713:                                    if (k == i)
08714:                                        continue;
08715:                                    for (int m = 0; m < tes[k].length; ++m) {
08716:                                        IClass te2 = tes[k][m];
08717:                                        if (te2.isAssignableFrom(te1))
08718:                                            continue EACH_METHOD;
08719:                                    }
08720:                                    continue EACH_EXCEPTION;
08721:                                }
08722:                                s.add(te1);
08723:                            }
08724:                        }
08725:                    }
08726:
08727:                    final IClass[] tes = (IClass[]) s.toArray(new IClass[s
08728:                            .size()]);
08729:                    return im.getDeclaringIClass().new IMethod() {
08730:                        public String getName() {
08731:                            return im.getName();
08732:                        }
08733:
08734:                        public IClass getReturnType() throws CompileException {
08735:                            return im.getReturnType();
08736:                        }
08737:
08738:                        public boolean isAbstract() {
08739:                            return im.isAbstract();
08740:                        }
08741:
08742:                        public boolean isStatic() {
08743:                            return im.isStatic();
08744:                        }
08745:
08746:                        public Access getAccess() {
08747:                            return im.getAccess();
08748:                        }
08749:
08750:                        public IClass[] getParameterTypes()
08751:                                throws CompileException {
08752:                            return im.getParameterTypes();
08753:                        }
08754:
08755:                        public IClass[] getThrownExceptions() {
08756:                            return tes;
08757:                        }
08758:                    };
08759:                }
08760:
08761:                // JLS 15.12.2.2.BL2.B2
08762:                {
08763:                    StringBuffer sb = new StringBuffer(
08764:                            "Invocation of constructor/method with actual parameter type(s) \"");
08765:                    for (int i = 0; i < argumentTypes.length; ++i) {
08766:                        if (i > 0)
08767:                            sb.append(", ");
08768:                        sb.append(Descriptor.toString(argumentTypes[i]
08769:                                .getDescriptor()));
08770:                    }
08771:                    sb.append("\" is ambiguous: ");
08772:                    for (int i = 0; i < maximallySpecificIInvocables.size(); ++i) {
08773:                        if (i > 0)
08774:                            sb.append(" vs. ");
08775:                        sb.append("\"" + maximallySpecificIInvocables.get(i)
08776:                                + "\"");
08777:                    }
08778:                    this .compileError(sb.toString(), l.getLocation());
08779:                }
08780:
08781:                return (IClass.IMethod) iInvocables[0];
08782:            }
08783:
08784:            /**
08785:             * Check if "method invocation conversion" (5.3) is possible.
08786:             */
08787:            private boolean isMethodInvocationConvertible(IClass sourceType,
08788:                    IClass targetType, boolean boxingPermitted)
08789:                    throws CompileException {
08790:
08791:                // 5.3 Identity conversion.
08792:                if (sourceType == targetType)
08793:                    return true;
08794:
08795:                // 5.3 Widening primitive conversion.
08796:                if (this .isWideningPrimitiveConvertible(sourceType, targetType))
08797:                    return true;
08798:
08799:                // 5.3 Widening reference conversion.
08800:                if (this .isWideningReferenceConvertible(sourceType, targetType))
08801:                    return true;
08802:
08803:                // JLS3 5.3 A boxing conversion (JLS3 5.1.7) optionally followed by widening reference conversion.
08804:                if (boxingPermitted) {
08805:                    IClass boxedType = this .isBoxingConvertible(sourceType);
08806:                    if (boxedType != null) {
08807:                        return (this .isIdentityConvertible(boxedType,
08808:                                targetType) || this 
08809:                                .isWideningReferenceConvertible(boxedType,
08810:                                        targetType));
08811:                    }
08812:                }
08813:
08814:                // JLS3 5.3 An unboxing conversion (JLS3 5.1.8) optionally followed by a widening primitive conversion.
08815:                if (boxingPermitted) {
08816:                    IClass unboxedType = this .isUnboxingConvertible(sourceType);
08817:                    if (unboxedType != null) {
08818:                        return (this .isIdentityConvertible(unboxedType,
08819:                                targetType) || this 
08820:                                .isWideningPrimitiveConvertible(unboxedType,
08821:                                        targetType));
08822:                    }
08823:                }
08824:
08825:                // 5.3 TODO: FLOAT or DOUBLE value set conversion
08826:
08827:                return false;
08828:            }
08829:
08830:            /**
08831:             * @throws CompileException if the {@link Invocation} throws exceptions that are disallowed in the given scope
08832:             */
08833:            private void checkThrownExceptions(Invocation in, IMethod iMethod)
08834:                    throws CompileException {
08835:                IClass[] thrownExceptions = iMethod.getThrownExceptions();
08836:                for (int i = 0; i < thrownExceptions.length; ++i) {
08837:                    this .checkThrownException((Locatable) in, // l
08838:                            thrownExceptions[i], // type
08839:                            (Java.Scope) in.getEnclosingBlockStatement() // scope
08840:                            );
08841:                }
08842:            }
08843:
08844:            /**
08845:             * @throws CompileException if the exception with the given type must not be thrown in the given scope
08846:             */
08847:            private void checkThrownException(Locatable l, IClass type,
08848:                    Java.Scope scope) throws CompileException {
08849:
08850:                // Thrown object must be assignable to "Throwable".
08851:                if (!this .iClassLoader.THROWABLE.isAssignableFrom(type))
08852:                    this .compileError("Thrown object of type \"" + type
08853:                            + "\" is not assignable to \"Throwable\"", l
08854:                            .getLocation());
08855:
08856:                // "RuntimeException" and "Error" are never checked.
08857:                if (this .iClassLoader.RUNTIME_EXCEPTION.isAssignableFrom(type)
08858:                        || this .iClassLoader.ERROR.isAssignableFrom(type))
08859:                    return;
08860:
08861:                for (;; scope = scope.getEnclosingScope()) {
08862:
08863:                    // Match against enclosing "try...catch" blocks.
08864:                    if (scope instanceof  Java.TryStatement) {
08865:                        Java.TryStatement ts = (Java.TryStatement) scope;
08866:                        for (int i = 0; i < ts.catchClauses.size(); ++i) {
08867:                            Java.CatchClause cc = (Java.CatchClause) ts.catchClauses
08868:                                    .get(i);
08869:                            IClass caughtType = this 
08870:                                    .getType(cc.caughtException.type);
08871:                            if (caughtType.isAssignableFrom(type))
08872:                                return;
08873:                        }
08874:                    } else
08875:
08876:                    // Match against "throws" clause of declaring function.
08877:                    if (scope instanceof  Java.FunctionDeclarator) {
08878:                        Java.FunctionDeclarator fd = (Java.FunctionDeclarator) scope;
08879:                        for (int i = 0; i < fd.thrownExceptions.length; ++i) {
08880:                            IClass te = this .getType(fd.thrownExceptions[i]);
08881:                            if (te.isAssignableFrom(type))
08882:                                return;
08883:                        }
08884:                        break;
08885:                    } else
08886:
08887:                    if (scope instanceof  Java.TypeBodyDeclaration) {
08888:                        break;
08889:                    }
08890:                }
08891:
08892:                this 
08893:                        .compileError(
08894:                                "Thrown exception of type \""
08895:                                        + type
08896:                                        + "\" is neither caught by a \"try...catch\" block nor declared in the \"throws\" clause of the declaring function",
08897:                                l.getLocation());
08898:            }
08899:
08900:            private IClass getTargetIClass(Java.QualifiedThisReference qtr)
08901:                    throws CompileException {
08902:
08903:                // Determine target type.
08904:                if (qtr.targetIClass == null) {
08905:                    qtr.targetIClass = this .getType(qtr.qualification);
08906:                }
08907:                return qtr.targetIClass;
08908:            }
08909:
08910:            /**
08911:             * Checks whether the operand is an integer-like local variable.
08912:             */
08913:            Java.LocalVariable isIntLV(Java.Crement c) throws CompileException {
08914:                if (!(c.operand instanceof  Java.AmbiguousName))
08915:                    return null;
08916:                Java.AmbiguousName an = (Java.AmbiguousName) c.operand;
08917:
08918:                Java.Atom rec = this .reclassify(an);
08919:                if (!(rec instanceof  Java.LocalVariableAccess))
08920:                    return null;
08921:                Java.LocalVariableAccess lva = (Java.LocalVariableAccess) rec;
08922:
08923:                Java.LocalVariable lv = lva.localVariable;
08924:                if (lv.finaL)
08925:                    this 
08926:                            .compileError(
08927:                                    "Must not increment or decrement \"final\" local variable",
08928:                                    lva.getLocation());
08929:                if (lv.type == IClass.BYTE || lv.type == IClass.SHORT
08930:                        || lv.type == IClass.INT || lv.type == IClass.CHAR)
08931:                    return lv;
08932:                return null;
08933:            }
08934:
08935:            private IClass resolve(final Java.TypeDeclaration td) {
08936:                final Java.AbstractTypeDeclaration atd = (Java.AbstractTypeDeclaration) td;
08937:                if (atd.resolvedType == null)
08938:                    atd.resolvedType = new IClass() {
08939:                        protected IClass.IMethod[] getDeclaredIMethods2() {
08940:                            IClass.IMethod[] res = new IClass.IMethod[atd.declaredMethods
08941:                                    .size()];
08942:                            int i = 0;
08943:                            for (Iterator it = atd.declaredMethods.iterator(); it
08944:                                    .hasNext();) {
08945:                                res[i++] = UnitCompiler.this 
08946:                                        .toIMethod((Java.MethodDeclarator) it
08947:                                                .next());
08948:                            }
08949:                            return res;
08950:                        }
08951:
08952:                        private IClass[] declaredClasses = null;
08953:
08954:                        protected IClass[] getDeclaredIClasses2() {
08955:                            if (this .declaredClasses == null) {
08956:                                IClass[] mts = new IClass[atd.declaredClassesAndInterfaces
08957:                                        .size()];
08958:                                int i = 0;
08959:                                for (Iterator it = atd.declaredClassesAndInterfaces
08960:                                        .iterator(); it.hasNext();) {
08961:                                    mts[i++] = UnitCompiler.this 
08962:                                            .resolve((Java.AbstractTypeDeclaration) it
08963:                                                    .next());
08964:                                }
08965:                                this .declaredClasses = mts;
08966:                            }
08967:                            return this .declaredClasses;
08968:                        }
08969:
08970:                        protected IClass getDeclaringIClass2() {
08971:                            Java.Scope s = atd;
08972:                            for (; !(s instanceof  Java.TypeBodyDeclaration); s = s
08973:                                    .getEnclosingScope()) {
08974:                                if (s instanceof  Java.CompilationUnit)
08975:                                    return null;
08976:                            }
08977:                            return UnitCompiler.this 
08978:                                    .resolve((Java.AbstractTypeDeclaration) s
08979:                                            .getEnclosingScope());
08980:                        }
08981:
08982:                        protected IClass getOuterIClass2()
08983:                                throws CompileException {
08984:                            Java.AbstractTypeDeclaration oc = (Java.AbstractTypeDeclaration) UnitCompiler
08985:                                    .getOuterClass(atd);
08986:                            if (oc == null)
08987:                                return null;
08988:                            return UnitCompiler.this .resolve(oc);
08989:                        }
08990:
08991:                        protected final String getDescriptor2() {
08992:                            return Descriptor.fromClassName(atd.getClassName());
08993:                        }
08994:
08995:                        public boolean isArray() {
08996:                            return false;
08997:                        }
08998:
08999:                        protected IClass getComponentType2() {
09000:                            throw new RuntimeException(
09001:                                    "SNO: Non-array type has no component type");
09002:                        }
09003:
09004:                        public boolean isPrimitive() {
09005:                            return false;
09006:                        }
09007:
09008:                        public boolean isPrimitiveNumeric() {
09009:                            return false;
09010:                        }
09011:
09012:                        protected IConstructor[] getDeclaredIConstructors2() {
09013:                            if (atd instanceof  Java.ClassDeclaration) {
09014:                                Java.ConstructorDeclarator[] cs = ((Java.ClassDeclaration) atd)
09015:                                        .getConstructors();
09016:
09017:                                IClass.IConstructor[] res = new IClass.IConstructor[cs.length];
09018:                                for (int i = 0; i < cs.length; ++i)
09019:                                    res[i] = UnitCompiler.this 
09020:                                            .toIConstructor(cs[i]);
09021:                                return res;
09022:                            }
09023:                            return new IClass.IConstructor[0];
09024:                        }
09025:
09026:                        protected IField[] getDeclaredIFields2() {
09027:                            if (atd instanceof  Java.ClassDeclaration) {
09028:                                Java.ClassDeclaration cd = (Java.ClassDeclaration) atd;
09029:                                List l = new ArrayList(); // IClass.IField
09030:
09031:                                // Determine variable declarators of type declaration.
09032:                                for (int i = 0; i < cd.variableDeclaratorsAndInitializers
09033:                                        .size(); ++i) {
09034:                                    Java.BlockStatement vdoi = (Java.BlockStatement) cd.variableDeclaratorsAndInitializers
09035:                                            .get(i);
09036:                                    if (vdoi instanceof  Java.FieldDeclaration) {
09037:                                        Java.FieldDeclaration fd = (Java.FieldDeclaration) vdoi;
09038:                                        IClass.IField[] flds = UnitCompiler.this 
09039:                                                .getIFields(fd);
09040:                                        for (int j = 0; j < flds.length; ++j)
09041:                                            l.add(flds[j]);
09042:                                    }
09043:                                }
09044:                                return (IClass.IField[]) l
09045:                                        .toArray(new IClass.IField[l.size()]);
09046:                            } else if (atd instanceof  Java.InterfaceDeclaration) {
09047:                                Java.InterfaceDeclaration id = (Java.InterfaceDeclaration) atd;
09048:                                List l = new ArrayList();
09049:
09050:                                // Determine static fields.
09051:                                for (int i = 0; i < id.constantDeclarations
09052:                                        .size(); ++i) {
09053:                                    Java.BlockStatement bs = (Java.BlockStatement) id.constantDeclarations
09054:                                            .get(i);
09055:                                    if (bs instanceof  Java.FieldDeclaration) {
09056:                                        Java.FieldDeclaration fd = (Java.FieldDeclaration) bs;
09057:                                        IClass.IField[] flds = UnitCompiler.this 
09058:                                                .getIFields(fd);
09059:                                        for (int j = 0; j < flds.length; ++j)
09060:                                            l.add(flds[j]);
09061:                                    }
09062:                                }
09063:                                return (IClass.IField[]) l
09064:                                        .toArray(new IClass.IField[l.size()]);
09065:                            } else {
09066:                                throw new RuntimeException(
09067:                                        "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration");
09068:                            }
09069:                        }
09070:
09071:                        public IField[] getSyntheticIFields() {
09072:                            if (atd instanceof  Java.ClassDeclaration) {
09073:                                Collection c = ((Java.ClassDeclaration) atd).syntheticFields
09074:                                        .values();
09075:                                return (IField[]) c
09076:                                        .toArray(new IField[c.size()]);
09077:                            }
09078:                            return new IField[0];
09079:                        }
09080:
09081:                        protected IClass getSuperclass2()
09082:                                throws CompileException {
09083:                            if (atd instanceof  Java.AnonymousClassDeclaration) {
09084:                                IClass bt = UnitCompiler.this 
09085:                                        .getType(((Java.AnonymousClassDeclaration) atd).baseType);
09086:                                return bt.isInterface() ? UnitCompiler.this .iClassLoader.OBJECT
09087:                                        : bt;
09088:                            }
09089:                            if (atd instanceof  Java.NamedClassDeclaration) {
09090:                                Java.NamedClassDeclaration ncd = (Java.NamedClassDeclaration) atd;
09091:                                if (ncd.optionalExtendedType == null)
09092:                                    return UnitCompiler.this .iClassLoader.OBJECT;
09093:                                IClass super class = UnitCompiler.this 
09094:                                        .getType(ncd.optionalExtendedType);
09095:                                if (super class.isInterface())
09096:                                    UnitCompiler.this 
09097:                                            .compileError(
09098:                                                    "\""
09099:                                                            + super class
09100:                                                                    .toString()
09101:                                                            + "\" is an interface; classes can only extend a class",
09102:                                                    td.getLocation());
09103:                                return super class;
09104:                            }
09105:                            return null;
09106:                        }
09107:
09108:                        public Access getAccess() {
09109:                            return UnitCompiler.modifiers2Access(atd.modifiers);
09110:                        }
09111:
09112:                        public boolean isFinal() {
09113:                            return (atd.modifiers & Mod.FINAL) != 0;
09114:                        }
09115:
09116:                        protected IClass[] getInterfaces2()
09117:                                throws CompileException {
09118:                            if (atd instanceof  Java.AnonymousClassDeclaration) {
09119:                                IClass bt = UnitCompiler.this 
09120:                                        .getType(((Java.AnonymousClassDeclaration) atd).baseType);
09121:                                return bt.isInterface() ? new IClass[] { bt }
09122:                                        : new IClass[0];
09123:                            } else if (atd instanceof  Java.NamedClassDeclaration) {
09124:                                Java.NamedClassDeclaration ncd = (Java.NamedClassDeclaration) atd;
09125:                                IClass[] res = new IClass[ncd.implementedTypes.length];
09126:                                for (int i = 0; i < res.length; ++i) {
09127:                                    res[i] = UnitCompiler.this 
09128:                                            .getType(ncd.implementedTypes[i]);
09129:                                    if (!res[i].isInterface())
09130:                                        UnitCompiler.this 
09131:                                                .compileError(
09132:                                                        "\""
09133:                                                                + res[i]
09134:                                                                        .toString()
09135:                                                                + "\" is not an interface; classes can only implement interfaces",
09136:                                                        td.getLocation());
09137:                                }
09138:                                return res;
09139:                            } else if (atd instanceof  Java.InterfaceDeclaration) {
09140:                                Java.InterfaceDeclaration id = (Java.InterfaceDeclaration) atd;
09141:                                IClass[] res = new IClass[id.extendedTypes.length];
09142:                                for (int i = 0; i < res.length; ++i) {
09143:                                    res[i] = UnitCompiler.this 
09144:                                            .getType(id.extendedTypes[i]);
09145:                                    if (!res[i].isInterface())
09146:                                        UnitCompiler.this 
09147:                                                .compileError(
09148:                                                        "\""
09149:                                                                + res[i]
09150:                                                                        .toString()
09151:                                                                + "\" is not an interface; interfaces can only extend interfaces",
09152:                                                        td.getLocation());
09153:                                }
09154:                                return res;
09155:                            } else {
09156:                                throw new RuntimeException(
09157:                                        "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration");
09158:                            }
09159:                        }
09160:
09161:                        public boolean isAbstract() {
09162:                            return ((atd instanceof  Java.InterfaceDeclaration) || (atd.modifiers & Mod.ABSTRACT) != 0);
09163:                        }
09164:
09165:                        public boolean isInterface() {
09166:                            return atd instanceof  Java.InterfaceDeclaration;
09167:                        }
09168:                    };
09169:
09170:                return atd.resolvedType;
09171:            }
09172:
09173:            private void referenceThis(Locatable l,
09174:                    Java.ClassDeclaration declaringClass,
09175:                    Java.TypeBodyDeclaration declaringTypeBodyDeclaration,
09176:                    IClass targetIClass) throws CompileException {
09177:                List path = UnitCompiler.getOuterClasses(declaringClass);
09178:
09179:                if (declaringTypeBodyDeclaration.isStatic())
09180:                    this .compileError(
09181:                            "No current instance available in static context",
09182:                            l.getLocation());
09183:
09184:                int j;
09185:                TARGET_FOUND: {
09186:                    for (j = 0; j < path.size(); ++j) {
09187:
09188:                        // Notice: JLS 15.9.2.BL1.B3.B1.B2 seems to be wrong: Obviously, JAVAC does not
09189:                        // only allow
09190:                        //
09191:                        //    O is the nth lexically enclosing class
09192:                        //
09193:                        // , but also
09194:                        //
09195:                        //    O is assignable from the nth lexically enclosing class
09196:                        //
09197:                        // However, this strategy bears the risk of ambiguities, because "O" may be
09198:                        // assignable from more than one enclosing class.
09199:                        if (targetIClass.isAssignableFrom(this 
09200:                                .resolve((Java.AbstractTypeDeclaration) path
09201:                                        .get(j))))
09202:                            break TARGET_FOUND;
09203:                    }
09204:                    this .compileError("\"" + declaringClass
09205:                            + "\" is not enclosed by \"" + targetIClass + "\"",
09206:                            l.getLocation());
09207:                }
09208:
09209:                int i;
09210:                if (declaringTypeBodyDeclaration instanceof  Java.ConstructorDeclarator) {
09211:                    if (j == 0) {
09212:                        this .writeOpcode(l, Opcode.ALOAD_0);
09213:                        return;
09214:                    }
09215:
09216:                    Java.ConstructorDeclarator constructorDeclarator = (Java.ConstructorDeclarator) declaringTypeBodyDeclaration;
09217:                    String spn = "this$" + (path.size() - 2);
09218:                    Java.LocalVariable syntheticParameter = (Java.LocalVariable) constructorDeclarator.syntheticParameters
09219:                            .get(spn);
09220:                    if (syntheticParameter == null)
09221:                        throw new RuntimeException(
09222:                                "SNO: Synthetic parameter \"" + spn
09223:                                        + "\" not found");
09224:                    this .load(l, syntheticParameter);
09225:                    i = 1;
09226:                } else {
09227:                    this .writeOpcode(l, Opcode.ALOAD_0);
09228:                    i = 0;
09229:                }
09230:                for (; i < j; ++i) {
09231:                    final String fieldName = "this$" + (path.size() - i - 2);
09232:                    final Java.InnerClassDeclaration inner = (Java.InnerClassDeclaration) path
09233:                            .get(i);
09234:                    IClass iic = this 
09235:                            .resolve((Java.AbstractTypeDeclaration) inner);
09236:                    final Java.TypeDeclaration outer = (Java.TypeDeclaration) path
09237:                            .get(i + 1);
09238:                    final IClass oic = this 
09239:                            .resolve((Java.AbstractTypeDeclaration) outer);
09240:                    inner.defineSyntheticField(new SimpleIField(iic, fieldName,
09241:                            oic));
09242:                    this .writeOpcode(l, Opcode.GETFIELD);
09243:                    this .writeConstantFieldrefInfo(iic.getDescriptor(),
09244:                            fieldName, // classFD
09245:                            oic.getDescriptor() // fieldFD
09246:                            );
09247:                }
09248:            }
09249:
09250:            /**
09251:             * Return a list consisting of the given <code>inner</code> class and all its outer classes.
09252:             * @return {@link List} of {@link Java.TypeDeclaration}
09253:             */
09254:            private static List getOuterClasses(Java.TypeDeclaration inner) {
09255:                List path = new ArrayList();
09256:                for (Java.TypeDeclaration ic = inner; ic != null; ic = UnitCompiler
09257:                        .getOuterClass(ic))
09258:                    path.add(ic);
09259:                return path;
09260:            }
09261:
09262:            /*package*/static Java.TypeDeclaration getOuterClass(
09263:                    Java.TypeDeclaration atd) {
09264:
09265:                // Package member class declaration.
09266:                if (atd instanceof  Java.PackageMemberClassDeclaration)
09267:                    return null;
09268:
09269:                // Local class declaration.
09270:                if (atd instanceof  Java.LocalClassDeclaration) {
09271:                    Java.Scope s = atd.getEnclosingScope();
09272:                    for (; !(s instanceof  Java.FunctionDeclarator); s = s
09273:                            .getEnclosingScope())
09274:                        ;
09275:                    if ((s instanceof  Java.MethodDeclarator)
09276:                            && (((Java.FunctionDeclarator) s).modifiers & Mod.STATIC) != 0)
09277:                        return null;
09278:                    for (; !(s instanceof  Java.TypeDeclaration); s = s
09279:                            .getEnclosingScope())
09280:                        ;
09281:                    Java.TypeDeclaration immediatelyEnclosingTypeDeclaration = (Java.TypeDeclaration) s;
09282:                    return (immediatelyEnclosingTypeDeclaration instanceof  Java.ClassDeclaration) ? immediatelyEnclosingTypeDeclaration
09283:                            : null;
09284:                }
09285:
09286:                // Member class declaration.
09287:                if (atd instanceof  Java.MemberClassDeclaration
09288:                        && (((Java.MemberClassDeclaration) atd).modifiers & Mod.STATIC) != 0)
09289:                    return null;
09290:
09291:                // Anonymous class declaration, interface declaration
09292:                Java.Scope s = atd;
09293:                for (; !(s instanceof  Java.TypeBodyDeclaration); s = s
09294:                        .getEnclosingScope()) {
09295:                    if (s instanceof  Java.ConstructorInvocation)
09296:                        return null;
09297:                    if (s instanceof  Java.CompilationUnit)
09298:                        return null;
09299:                }
09300:                //if (!(s instanceof Java.ClassDeclaration)) return null;
09301:                if (((Java.TypeBodyDeclaration) s).isStatic())
09302:                    return null;
09303:                return (Java.AbstractTypeDeclaration) s.getEnclosingScope();
09304:            }
09305:
09306:            private IClass getIClass(Java.ThisReference tr)
09307:                    throws CompileException {
09308:                if (tr.iClass == null) {
09309:
09310:                    // Compile error if in static function context.
09311:                    Java.Scope s;
09312:                    for (s = tr.getEnclosingBlockStatement(); s instanceof  Java.Statement
09313:                            || s instanceof  Java.CatchClause; s = s
09314:                            .getEnclosingScope())
09315:                        ;
09316:                    if (s instanceof  Java.FunctionDeclarator) {
09317:                        Java.FunctionDeclarator function = (Java.FunctionDeclarator) s;
09318:                        if ((function.modifiers & Mod.STATIC) != 0)
09319:                            this 
09320:                                    .compileError(
09321:                                            "No current instance available in static method",
09322:                                            tr.getLocation());
09323:                    }
09324:
09325:                    // Determine declaring type.
09326:                    while (!(s instanceof  Java.TypeDeclaration))
09327:                        s = s.getEnclosingScope();
09328:                    if (!(s instanceof  Java.ClassDeclaration))
09329:                        this 
09330:                                .compileError(
09331:                                        "Only methods of classes can have a current instance",
09332:                                        tr.getLocation());
09333:                    tr.iClass = this .resolve((Java.ClassDeclaration) s);
09334:                }
09335:                return tr.iClass;
09336:            }
09337:
09338:            private IClass getReturnType(Java.FunctionDeclarator fd)
09339:                    throws CompileException {
09340:                if (fd.returnType == null) {
09341:                    fd.returnType = this .getType(fd.type);
09342:                }
09343:                return fd.returnType;
09344:            }
09345:
09346:            /*package*/IClass.IConstructor toIConstructor(
09347:                    final Java.ConstructorDeclarator cd) {
09348:                if (cd.iConstructor != null)
09349:                    return cd.iConstructor;
09350:
09351:                cd.iConstructor = this 
09352:                        .resolve((Java.AbstractTypeDeclaration) cd
09353:                                .getDeclaringType()).new IConstructor() {
09354:
09355:                    // Implement IMember.
09356:                    public Access getAccess() {
09357:                        switch (cd.modifiers & Mod.PPP) {
09358:                        case Mod.PRIVATE:
09359:                            return Access.PRIVATE;
09360:                        case Mod.PROTECTED:
09361:                            return Access.PROTECTED;
09362:                        case Mod.PACKAGE:
09363:                            return Access.DEFAULT;
09364:                        case Mod.PUBLIC:
09365:                            return Access.PUBLIC;
09366:                        default:
09367:                            throw new RuntimeException("Invalid access");
09368:                        }
09369:                    }
09370:
09371:                    // Implement IInvocable.
09372:                    public String getDescriptor() throws CompileException {
09373:                        if (!(cd.getDeclaringClass() instanceof  Java.InnerClassDeclaration))
09374:                            return super .getDescriptor();
09375:
09376:                        List l = new ArrayList();
09377:
09378:                        // Convert enclosing instance reference into prepended constructor parameters.
09379:                        IClass outerClass = UnitCompiler.this .resolve(
09380:                                cd.getDeclaringClass()).getOuterIClass();
09381:                        if (outerClass != null)
09382:                            l.add(outerClass.getDescriptor());
09383:
09384:                        // Convert synthetic fields into prepended constructor parameters.
09385:                        for (Iterator it = cd.getDeclaringClass().syntheticFields
09386:                                .values().iterator(); it.hasNext();) {
09387:                            IClass.IField sf = (IClass.IField) it.next();
09388:                            if (sf.getName().startsWith("val$"))
09389:                                l.add(sf.getType().getDescriptor());
09390:                        }
09391:                        Java.FunctionDeclarator.FormalParameter[] fps = cd.formalParameters;
09392:                        for (int i = 0; i < fps.length; ++i) {
09393:                            l.add(UnitCompiler.this .getType(fps[i].type)
09394:                                    .getDescriptor());
09395:                        }
09396:                        String[] apd = (String[]) l
09397:                                .toArray(new String[l.size()]);
09398:                        return new MethodDescriptor(apd, Descriptor.VOID_)
09399:                                .toString();
09400:                    }
09401:
09402:                    public IClass[] getParameterTypes() throws CompileException {
09403:                        Java.FunctionDeclarator.FormalParameter[] fps = cd.formalParameters;
09404:                        IClass[] res = new IClass[fps.length];
09405:                        for (int i = 0; i < fps.length; ++i) {
09406:                            res[i] = UnitCompiler.this .getType(fps[i].type);
09407:                        }
09408:                        return res;
09409:                    }
09410:
09411:                    public IClass[] getThrownExceptions()
09412:                            throws CompileException {
09413:                        IClass[] res = new IClass[cd.thrownExceptions.length];
09414:                        for (int i = 0; i < res.length; ++i) {
09415:                            res[i] = UnitCompiler.this 
09416:                                    .getType(cd.thrownExceptions[i]);
09417:                        }
09418:                        return res;
09419:                    }
09420:
09421:                    public String toString() {
09422:                        StringBuffer sb = new StringBuffer();
09423:                        sb.append(cd.getDeclaringType().getClassName());
09424:                        sb.append('(');
09425:                        Java.FunctionDeclarator.FormalParameter[] fps = cd.formalParameters;
09426:                        for (int i = 0; i < fps.length; ++i) {
09427:                            if (i != 0)
09428:                                sb.append(", ");
09429:                            try {
09430:                                sb.append(UnitCompiler.this 
09431:                                        .getType(fps[i].type).toString());
09432:                            } catch (CompileException ex) {
09433:                                sb.append("???");
09434:                            }
09435:                        }
09436:                        return sb.append(')').toString();
09437:                    }
09438:                };
09439:                return cd.iConstructor;
09440:            }
09441:
09442:            public IClass.IMethod toIMethod(final Java.MethodDeclarator md) {
09443:                if (md.iMethod != null)
09444:                    return md.iMethod;
09445:                md.iMethod = this .resolve((Java.AbstractTypeDeclaration) md
09446:                        .getDeclaringType()).new IMethod() {
09447:
09448:                    // Implement IMember.
09449:                    public Access getAccess() {
09450:                        switch (md.modifiers & Mod.PPP) {
09451:                        case Mod.PRIVATE:
09452:                            return Access.PRIVATE;
09453:                        case Mod.PROTECTED:
09454:                            return Access.PROTECTED;
09455:                        case Mod.PACKAGE:
09456:                            return Access.DEFAULT;
09457:                        case Mod.PUBLIC:
09458:                            return Access.PUBLIC;
09459:                        default:
09460:                            throw new RuntimeException("Invalid access");
09461:                        }
09462:                    }
09463:
09464:                    // Implement IInvocable.
09465:                    public IClass[] getParameterTypes() throws CompileException {
09466:                        Java.FunctionDeclarator.FormalParameter[] fps = md.formalParameters;
09467:                        IClass[] res = new IClass[fps.length];
09468:                        for (int i = 0; i < fps.length; ++i) {
09469:                            res[i] = UnitCompiler.this .getType(fps[i].type);
09470:                        }
09471:                        return res;
09472:                    }
09473:
09474:                    public IClass[] getThrownExceptions()
09475:                            throws CompileException {
09476:                        IClass[] res = new IClass[md.thrownExceptions.length];
09477:                        for (int i = 0; i < res.length; ++i) {
09478:                            res[i] = UnitCompiler.this 
09479:                                    .getType(md.thrownExceptions[i]);
09480:                        }
09481:                        return res;
09482:                    }
09483:
09484:                    // Implement IMethod.
09485:                    public boolean isStatic() {
09486:                        return (md.modifiers & Mod.STATIC) != 0;
09487:                    }
09488:
09489:                    public boolean isAbstract() {
09490:                        return (md.getDeclaringType() instanceof  Java.InterfaceDeclaration)
09491:                                || (md.modifiers & Mod.ABSTRACT) != 0;
09492:                    }
09493:
09494:                    public IClass getReturnType() throws CompileException {
09495:                        return UnitCompiler.this .getReturnType(md);
09496:                    }
09497:
09498:                    public String getName() {
09499:                        return md.name;
09500:                    }
09501:                };
09502:                return md.iMethod;
09503:            }
09504:
09505:            private IClass.IInvocable toIInvocable(Java.FunctionDeclarator fd) {
09506:                if (fd instanceof  Java.ConstructorDeclarator) {
09507:                    return this .toIConstructor((Java.ConstructorDeclarator) fd);
09508:                } else if (fd instanceof  Java.MethodDeclarator) {
09509:                    return this .toIMethod((Java.MethodDeclarator) fd);
09510:                } else {
09511:                    throw new RuntimeException(
09512:                            "FunctionDeclarator is neither ConstructorDeclarator nor MethodDeclarator");
09513:                }
09514:            }
09515:
09516:            /**
09517:             * If the given name was declared in a simple type import, load that class.
09518:             */
09519:            private IClass importSingleType(String simpleTypeName,
09520:                    Location location) throws CompileException {
09521:                String[] ss = this .getSingleTypeImport(simpleTypeName);
09522:                if (ss == null)
09523:                    return null;
09524:
09525:                IClass iClass = this .loadFullyQualifiedClass(ss);
09526:                if (iClass == null) {
09527:                    this .compileError("Imported class \"" + Java.join(ss, ".")
09528:                            + "\" could not be loaded", location);
09529:                    return this .iClassLoader.OBJECT;
09530:                }
09531:                return iClass;
09532:            }
09533:
09534:            /**
09535:             * Check if the given name was imported through a "single type import", e.g.<pre>
09536:             *     import java.util.Map</pre>
09537:             * 
09538:             * @return the fully qualified name or <code>null</code>
09539:             */
09540:            public String[] getSingleTypeImport(String name) {
09541:                return (String[]) this .singleTypeImports.get(name);
09542:            }
09543:
09544:            /**
09545:             * 6.5.2.BL1.B1.B5, 6.5.2.BL1.B1.B6 Type-import-on-demand.<br>
09546:             * 6.5.5.1.6 Type-import-on-demand declaration.
09547:             * @return <code>null</code> if the given <code>simpleTypeName</code> cannot be resolved through any of the import-on-demand directives
09548:             */
09549:            public IClass importTypeOnDemand(String simpleTypeName,
09550:                    Location location) throws CompileException {
09551:
09552:                // Check cache. (A cache for unimportable types is not required, because
09553:                // the class is importable 99.9%.)
09554:                IClass importedClass = (IClass) this .onDemandImportableTypes
09555:                        .get(simpleTypeName);
09556:                if (importedClass != null)
09557:                    return importedClass;
09558:
09559:                // Cache miss...
09560:                for (Iterator i = this .typeImportsOnDemand.iterator(); i
09561:                        .hasNext();) {
09562:                    String[] ss = (String[]) i.next();
09563:                    String[] ss2 = concat(ss, simpleTypeName);
09564:                    IClass iClass = this .loadFullyQualifiedClass(ss2);
09565:                    if (iClass != null) {
09566:                        if (importedClass != null && importedClass != iClass)
09567:                            this .compileError("Ambiguous class name: \""
09568:                                    + importedClass + "\" vs. \"" + iClass
09569:                                    + "\"", location);
09570:                        importedClass = iClass;
09571:                    }
09572:                }
09573:                if (importedClass == null)
09574:                    return null;
09575:
09576:                // Put in cache and return.
09577:                this .onDemandImportableTypes.put(simpleTypeName, importedClass);
09578:                return importedClass;
09579:            }
09580:
09581:            private final Map onDemandImportableTypes = new HashMap(); // String simpleTypeName => IClass
09582:
09583:            private void declareClassDollarMethod(Java.ClassLiteral cl) {
09584:
09585:                // Method "class$" is not yet declared; declare it like
09586:                //
09587:                //   static java.lang.Class class$(java.lang.String className) {
09588:                //       try {
09589:                //           return java.lang.Class.forName(className);
09590:                //       } catch (java.lang.ClassNotFoundException ex) {
09591:                //           throw new java.lang.NoClassDefFoundError(ex.getMessage());
09592:                //       }
09593:                //   }
09594:                //
09595:                Location loc = cl.getLocation();
09596:                Java.AbstractTypeDeclaration declaringType;
09597:                for (Java.Scope s = cl.getEnclosingBlockStatement();; s = s
09598:                        .getEnclosingScope()) {
09599:                    if (s instanceof  Java.AbstractTypeDeclaration) {
09600:                        declaringType = (Java.AbstractTypeDeclaration) s;
09601:                        break;
09602:                    }
09603:                }
09604:                Java.Block body = new Java.Block(loc);
09605:
09606:                // try {
09607:                // return Class.forName(className);
09608:                Java.MethodInvocation mi = new Java.MethodInvocation(loc, // location
09609:                        new Java.SimpleType(loc, this .iClassLoader.CLASS), // optionalTarget
09610:                        "forName", // methodName
09611:                        new Java.Rvalue[] { // arguments
09612:                        new Java.AmbiguousName(loc,
09613:                                new String[] { "className" }) });
09614:
09615:                IClass classNotFoundExceptionIClass;
09616:                try {
09617:                    classNotFoundExceptionIClass = this .iClassLoader
09618:                            .loadIClass("Ljava/lang/ClassNotFoundException;");
09619:                } catch (ClassNotFoundException ex) {
09620:                    throw new RuntimeException(
09621:                            "Loading class \"ClassNotFoundException\": "
09622:                                    + ex.getMessage());
09623:                }
09624:                if (classNotFoundExceptionIClass == null)
09625:                    throw new RuntimeException(
09626:                            "SNO: Cannot load \"ClassNotFoundException\"");
09627:
09628:                IClass noClassDefFoundErrorIClass;
09629:                try {
09630:                    noClassDefFoundErrorIClass = this .iClassLoader
09631:                            .loadIClass("Ljava/lang/NoClassDefFoundError;");
09632:                } catch (ClassNotFoundException ex) {
09633:                    throw new RuntimeException(
09634:                            "Loading class \"NoClassDefFoundError\": "
09635:                                    + ex.getMessage());
09636:                }
09637:                if (noClassDefFoundErrorIClass == null)
09638:                    throw new RuntimeException(
09639:                            "SNO: Cannot load \"NoClassFoundError\"");
09640:
09641:                // catch (ClassNotFoundException ex) {
09642:                Java.Block b = new Java.Block(loc);
09643:                // throw new NoClassDefFoundError(ex.getMessage());
09644:                b.addStatement(new Java.ThrowStatement(loc,
09645:                        new Java.NewClassInstance(loc, // location
09646:                                (Java.Rvalue) null, // optionalQualification
09647:                                new Java.SimpleType(loc,
09648:                                        noClassDefFoundErrorIClass), // type
09649:                                new Java.Rvalue[] { // arguments
09650:                                new Java.MethodInvocation(loc, // location
09651:                                        new Java.AmbiguousName(loc,
09652:                                                new String[] { "ex" }), // optionalTarget
09653:                                        "getMessage", // methodName
09654:                                        new Java.Rvalue[0] // arguments
09655:                                ) })));
09656:
09657:                List l = new ArrayList();
09658:                l.add(new Java.CatchClause(loc, // location
09659:                        new Java.FunctionDeclarator.FormalParameter( // caughtException
09660:                                loc, // location
09661:                                true, // finaL
09662:                                new Java.SimpleType(loc,
09663:                                        classNotFoundExceptionIClass), // type
09664:                                "ex" // name
09665:                        ), b // body
09666:                        ));
09667:                Java.TryStatement ts = new Java.TryStatement(loc, // location
09668:                        new Java.ReturnStatement(loc, mi), // body
09669:                        l, // catchClauses
09670:                        null // optionalFinally
09671:                );
09672:
09673:                body.addStatement(ts);
09674:
09675:                // Class class$(String className)
09676:                Java.FunctionDeclarator.FormalParameter fp = new Java.FunctionDeclarator.FormalParameter(
09677:                        loc, // location
09678:                        false, // finaL
09679:                        new Java.SimpleType(loc, this .iClassLoader.STRING), // type
09680:                        "className" // name
09681:                );
09682:                Java.MethodDeclarator cdmd = new Java.MethodDeclarator(loc, // location
09683:                        null, // optionalDocComment
09684:                        Mod.STATIC, // modifiers
09685:                        new Java.SimpleType(loc, this .iClassLoader.CLASS), // type
09686:                        "class$", // name
09687:                        new Java.FunctionDeclarator.FormalParameter[] { fp }, // formalParameters
09688:                        new Java.Type[0], // thrownExceptions
09689:                        body // optionalBody
09690:                );
09691:
09692:                declaringType.addDeclaredMethod(cdmd);
09693:
09694:                // Invalidate several caches.
09695:                if (declaringType.resolvedType != null) {
09696:                    declaringType.resolvedType.declaredIMethods = null;
09697:                    declaringType.resolvedType.declaredIMethodCache = null;
09698:                }
09699:            }
09700:
09701:            private IClass pushConstant(Locatable l, Object value) {
09702:                if (value instanceof  Integer || value instanceof  Short
09703:                        || value instanceof  Character || value instanceof  Byte) {
09704:                    int i = (value instanceof  Character ? ((Character) value)
09705:                            .charValue() : ((Number) value).intValue());
09706:                    if (i >= -1 && i <= 5) {
09707:                        this .writeOpcode(l, Opcode.ICONST_0 + i);
09708:                    } else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
09709:                        this .writeOpcode(l, Opcode.BIPUSH);
09710:                        this .writeByte((byte) i);
09711:                    } else {
09712:                        this .writeLDC(l, this .addConstantIntegerInfo(i));
09713:                    }
09714:                    return IClass.INT;
09715:                }
09716:                if (value instanceof  Long) {
09717:                    long lv = ((Long) value).longValue();
09718:                    if (lv >= 0L && lv <= 1L) {
09719:                        this .writeOpcode(l, Opcode.LCONST_0 + (int) lv);
09720:                    } else {
09721:                        this .writeOpcode(l, Opcode.LDC2_W);
09722:                        this .writeConstantLongInfo(lv);
09723:                    }
09724:                    return IClass.LONG;
09725:                }
09726:                if (value instanceof  Float) {
09727:                    float fv = ((Float) value).floatValue();
09728:                    if (Float.floatToIntBits(fv) == Float.floatToIntBits(0.0F) // POSITIVE zero!
09729:                            || fv == 1.0F || fv == 2.0F) {
09730:                        this .writeOpcode(l, Opcode.FCONST_0 + (int) fv);
09731:                    } else {
09732:                        this .writeLDC(l, this .addConstantFloatInfo(fv));
09733:                    }
09734:                    return IClass.FLOAT;
09735:                }
09736:                if (value instanceof  Double) {
09737:                    double dv = ((Double) value).doubleValue();
09738:                    if (Double.doubleToLongBits(dv) == Double
09739:                            .doubleToLongBits(0.0D) // POSITIVE zero!
09740:                            || dv == 1.0D) {
09741:                        this .writeOpcode(l, Opcode.DCONST_0 + (int) dv);
09742:                    } else {
09743:                        this .writeOpcode(l, Opcode.LDC2_W);
09744:                        this .writeConstantDoubleInfo(dv);
09745:                    }
09746:                    return IClass.DOUBLE;
09747:                }
09748:                if (value instanceof  String) {
09749:                    String s = (String) value;
09750:                    String ss[] = UnitCompiler.makeUTF8Able(s);
09751:                    this .writeLDC(l, this .addConstantStringInfo(ss[0]));
09752:                    for (int i = 1; i < ss.length; ++i) {
09753:                        this .writeLDC(l, this .addConstantStringInfo(ss[i]));
09754:                        this .writeOpcode(l, Opcode.INVOKEVIRTUAL);
09755:                        this .writeConstantMethodrefInfo(Descriptor.STRING,
09756:                                "concat", // classFD
09757:                                "(" + Descriptor.STRING + ")"
09758:                                        + Descriptor.STRING // methodMD
09759:                        );
09760:                    }
09761:                    return this .iClassLoader.STRING;
09762:                }
09763:                if (value instanceof  Boolean) {
09764:                    this .writeOpcode(l,
09765:                            ((Boolean) value).booleanValue() ? Opcode.ICONST_1
09766:                                    : Opcode.ICONST_0);
09767:                    return IClass.BOOLEAN;
09768:                }
09769:                if (value == Java.Rvalue.CONSTANT_VALUE_NULL) {
09770:                    this .writeOpcode(l, Opcode.ACONST_NULL);
09771:                    return IClass.VOID;
09772:                }
09773:                throw new RuntimeException("Unknown literal type \""
09774:                        + value.getClass().getName() + "\"");
09775:            }
09776:
09777:            /**
09778:             * Only strings that can be UTF8-encoded into 65535 bytes can be stored as constant string
09779:             * infos.
09780:             *
09781:             * @param s The string to split into suitable chunks
09782:             * @return the chunks that can be UTF8-encoded into 65535 bytes
09783:             */
09784:            private static String[] makeUTF8Able(String s) {
09785:                if (s.length() < (65536 / 3))
09786:                    return new String[] { s };
09787:
09788:                int sLength = s.length(), uTFLength = 0;
09789:                int from = 0;
09790:                List l = new ArrayList();
09791:                for (int i = 0;; i++) {
09792:                    if (i == sLength) {
09793:                        l.add(s.substring(from));
09794:                        break;
09795:                    }
09796:                    if (uTFLength >= 65532) {
09797:                        l.add(s.substring(from, i));
09798:                        if (i + (65536 / 3) > sLength) {
09799:                            l.add(s.substring(i));
09800:                            break;
09801:                        }
09802:                        from = i;
09803:                        uTFLength = 0;
09804:                    }
09805:                    int c = s.charAt(i);
09806:                    if (c >= 0x0001 && c <= 0x007F) {
09807:                        ++uTFLength;
09808:                    } else if (c > 0x07FF) {
09809:                        uTFLength += 3;
09810:                    } else {
09811:                        uTFLength += 2;
09812:                    }
09813:                }
09814:                return (String[]) l.toArray(new String[l.size()]);
09815:
09816:            }
09817:
09818:            private void writeLDC(Locatable l, short index) {
09819:                if (index <= 255) {
09820:                    this .writeOpcode(l, Opcode.LDC);
09821:                    this .writeByte((byte) index);
09822:                } else {
09823:                    this .writeOpcode(l, Opcode.LDC_W);
09824:                    this .writeShort(index);
09825:                }
09826:            }
09827:
09828:            /**
09829:             * Implements "assignment conversion" (JLS2 5.2).
09830:             */
09831:            private void assignmentConversion(Locatable l, IClass sourceType,
09832:                    IClass targetType, Object optionalConstantValue)
09833:                    throws CompileException {
09834:                if (UnitCompiler.DEBUG)
09835:                    System.out.println("assignmentConversion(" + sourceType
09836:                            + ", " + targetType + ", " + optionalConstantValue
09837:                            + ")");
09838:
09839:                // JLS2 5.1.1 Identity conversion.
09840:                if (this .tryIdentityConversion(sourceType, targetType))
09841:                    return;
09842:
09843:                // JLS2 5.1.2 Widening primitive conversion.
09844:                if (this .tryWideningPrimitiveConversion(l, sourceType,
09845:                        targetType))
09846:                    return;
09847:
09848:                // JLS2 5.1.4 Widening reference conversion.
09849:                if (this .isWideningReferenceConvertible(sourceType, targetType))
09850:                    return;
09851:
09852:                // A boxing conversion (JLS3 5.1.7) optionally followed by a widening reference conversion.
09853:                {
09854:                    IClass boxedType = this .isBoxingConvertible(sourceType);
09855:                    if (boxedType != null) {
09856:                        if (this .tryIdentityConversion(boxedType, targetType)) {
09857:                            this .boxingConversion(l, sourceType, boxedType);
09858:                            return;
09859:                        } else if (this .isWideningReferenceConvertible(
09860:                                boxedType, targetType)) {
09861:                            this .boxingConversion(l, sourceType, boxedType);
09862:                            return;
09863:                        }
09864:                    }
09865:                }
09866:
09867:                // An unboxing conversion (JLS3 5.1.8) optionally followed by a widening primitive conversion.
09868:                {
09869:                    IClass unboxedType = this .isUnboxingConvertible(sourceType);
09870:                    if (unboxedType != null) {
09871:                        if (this .tryIdentityConversion(unboxedType, targetType)) {
09872:                            this .unboxingConversion(l, sourceType, unboxedType);
09873:                            return;
09874:                        } else if (this .isWideningPrimitiveConvertible(
09875:                                unboxedType, targetType)) {
09876:                            this .unboxingConversion(l, sourceType, unboxedType);
09877:                            this .tryWideningPrimitiveConversion(l, unboxedType,
09878:                                    targetType);
09879:                            return;
09880:                        }
09881:                    }
09882:                }
09883:
09884:                // 5.2 Special narrowing primitive conversion.
09885:                if (optionalConstantValue != null) {
09886:                    if (this .tryConstantAssignmentConversion(l,
09887:                            optionalConstantValue, // constantValue
09888:                            targetType // targetType
09889:                            ))
09890:                        return;
09891:                }
09892:
09893:                this .compileError(
09894:                        "Assignment conversion not possible from type \""
09895:                                + sourceType + "\" to type \"" + targetType
09896:                                + "\"", l.getLocation());
09897:            }
09898:
09899:            /**
09900:             * Implements "assignment conversion" (JLS2 5.2) on a constant value.
09901:             */
09902:            private Object assignmentConversion(Locatable l, Object value,
09903:                    IClass targetType) throws CompileException {
09904:                Object result = null;
09905:
09906:                if (targetType == IClass.BOOLEAN) {
09907:                    if (value instanceof  Boolean)
09908:                        result = value;
09909:                } else if (targetType == this .iClassLoader.STRING) {
09910:                    if (value instanceof  String)
09911:                        result = value;
09912:                } else if (targetType == IClass.BYTE) {
09913:                    if (value instanceof  Byte) {
09914:                        result = value;
09915:                    } else if (value instanceof  Short
09916:                            || value instanceof  Integer) {
09917:                        int x = ((Number) value).intValue();
09918:                        if (x >= Byte.MIN_VALUE && x <= Byte.MAX_VALUE)
09919:                            result = new Byte((byte) x);
09920:                    } else if (value instanceof  Character) {
09921:                        int x = ((Character) value).charValue();
09922:                        if (x >= Byte.MIN_VALUE && x <= Byte.MAX_VALUE)
09923:                            result = new Byte((byte) x);
09924:                    }
09925:                } else if (targetType == IClass.SHORT) {
09926:                    if (value instanceof  Byte) {
09927:                        result = new Short(((Number) value).shortValue());
09928:                    } else if (value instanceof  Short) {
09929:                        result = value;
09930:                    } else if (value instanceof  Character) {
09931:                        int x = ((Character) value).charValue();
09932:                        if (x >= Short.MIN_VALUE && x <= Short.MAX_VALUE)
09933:                            result = new Short((short) x);
09934:                    } else if (value instanceof  Integer) {
09935:                        int x = ((Integer) value).intValue();
09936:                        if (x >= Short.MIN_VALUE && x <= Short.MAX_VALUE)
09937:                            result = new Short((short) x);
09938:                    }
09939:                } else if (targetType == IClass.CHAR) {
09940:                    if (value instanceof  Short) {
09941:                        result = value;
09942:                    } else if (value instanceof  Byte || value instanceof  Short
09943:                            || value instanceof  Integer) {
09944:                        int x = ((Number) value).intValue();
09945:                        if (x >= Character.MIN_VALUE
09946:                                && x <= Character.MAX_VALUE)
09947:                            result = new Character((char) x);
09948:                    }
09949:                } else if (targetType == IClass.INT) {
09950:                    if (value instanceof  Integer) {
09951:                        result = value;
09952:                    } else if (value instanceof  Byte || value instanceof  Short) {
09953:                        result = new Integer(((Number) value).intValue());
09954:                    } else if (value instanceof  Character) {
09955:                        result = new Integer(((Character) value).charValue());
09956:                    }
09957:                } else if (targetType == IClass.LONG) {
09958:                    if (value instanceof  Long) {
09959:                        result = value;
09960:                    } else if (value instanceof  Byte || value instanceof  Short
09961:                            || value instanceof  Integer) {
09962:                        result = new Long(((Number) value).longValue());
09963:                    } else if (value instanceof  Character) {
09964:                        result = new Long(((Character) value).charValue());
09965:                    }
09966:                } else if (targetType == IClass.FLOAT) {
09967:                    if (value instanceof  Float) {
09968:                        result = value;
09969:                    } else if (value instanceof  Byte || value instanceof  Short
09970:                            || value instanceof  Integer
09971:                            || value instanceof  Long) {
09972:                        result = new Float(((Number) value).floatValue());
09973:                    } else if (value instanceof  Character) {
09974:                        result = new Float(((Character) value).charValue());
09975:                    }
09976:                } else if (targetType == IClass.DOUBLE) {
09977:                    if (value instanceof  Double) {
09978:                        result = value;
09979:                    } else if (value instanceof  Byte || value instanceof  Short
09980:                            || value instanceof  Integer
09981:                            || value instanceof  Long || value instanceof  Float) {
09982:                        result = new Double(((Number) value).doubleValue());
09983:                    } else if (value instanceof  Character) {
09984:                        result = new Double(((Character) value).charValue());
09985:                    }
09986:                } else if (value == Java.Rvalue.CONSTANT_VALUE_NULL
09987:                        && !targetType.isPrimitive()) {
09988:                    result = value;
09989:                }
09990:                if (result == null)
09991:                    this .compileError("Cannot convert constant of type \""
09992:                            + value.getClass().getName() + "\" to type \""
09993:                            + targetType.toString() + "\"", l.getLocation());
09994:                return result;
09995:            }
09996:
09997:            /**
09998:             * Implements "unary numeric promotion" (JLS3 5.6.1)
09999:             *
10000:             * @return The promoted type.
10001:             */
10002:            private IClass unaryNumericPromotion(Locatable l, IClass type)
10003:                    throws CompileException {
10004:                type = this .convertToPrimitiveNumericType(l, type);
10005:
10006:                IClass promotedType = this .unaryNumericPromotionType(l, type);
10007:
10008:                this .numericPromotion(l, type, promotedType);
10009:                return promotedType;
10010:            }
10011:
10012:            private void reverseUnaryNumericPromotion(Locatable l,
10013:                    IClass sourceType, IClass targetType)
10014:                    throws CompileException {
10015:                IClass unboxedType = this .isUnboxingConvertible(targetType);
10016:                IClass pt = unboxedType != null ? unboxedType : targetType;
10017:                if (!this .tryIdentityConversion(sourceType, pt)
10018:                        && !this .tryNarrowingPrimitiveConversion(l, // locatable
10019:                                sourceType, // sourceType
10020:                                pt // targetType
10021:                                ))
10022:                    throw new RuntimeException(
10023:                            "SNO: reverse unary numeric promotion failed");
10024:                if (unboxedType != null)
10025:                    this .boxingConversion(l, unboxedType, targetType);
10026:            }
10027:
10028:            /**
10029:             * If the given type is a primitive type, return that type.
10030:             * If the given type is a primitive wrapper class, unbox the operand on top of the operand
10031:             * stack and return the primitive type.
10032:             * Otherwise, issue a compile error.
10033:             */
10034:            private IClass convertToPrimitiveNumericType(Locatable l,
10035:                    IClass type) throws CompileException {
10036:                if (type.isPrimitiveNumeric())
10037:                    return type;
10038:                IClass unboxedType = this .isUnboxingConvertible(type);
10039:                if (unboxedType != null) {
10040:                    this .unboxingConversion(l, type, unboxedType);
10041:                    return unboxedType;
10042:                }
10043:                this .compileError("Object of type \"" + type.toString()
10044:                        + "\" cannot be converted to a numeric type", l
10045:                        .getLocation());
10046:                return type;
10047:            }
10048:
10049:            private void numericPromotion(Locatable l, IClass sourceType,
10050:                    IClass targetType) {
10051:                if (!this .tryIdentityConversion(sourceType, targetType)
10052:                        && !this .tryWideningPrimitiveConversion(l, // locatable
10053:                                sourceType, // sourceType
10054:                                targetType // targetType
10055:                                ))
10056:                    throw new RuntimeException("SNO: Conversion failed");
10057:            }
10058:
10059:            private IClass unaryNumericPromotionType(Locatable l, IClass type)
10060:                    throws CompileException {
10061:                if (!type.isPrimitiveNumeric())
10062:                    this .compileError(
10063:                            "Unary numeric promotion not possible on non-numeric-primitive type \""
10064:                                    + type + "\"", l.getLocation());
10065:
10066:                return (type == IClass.DOUBLE ? IClass.DOUBLE
10067:                        : type == IClass.FLOAT ? IClass.FLOAT
10068:                                : type == IClass.LONG ? IClass.LONG
10069:                                        : IClass.INT);
10070:            }
10071:
10072:            /**
10073:             * Implements "binary numeric promotion" (5.6.2)
10074:             *
10075:             * @return The promoted type.
10076:             */
10077:            private IClass binaryNumericPromotion(Locatable locatable,
10078:                    IClass type1, CodeContext.Inserter convertInserter1,
10079:                    IClass type2) throws CompileException {
10080:                return this .binaryNumericPromotion(locatable, type1,
10081:                        convertInserter1, type2, this .codeContext
10082:                                .currentInserter());
10083:            }
10084:
10085:            /**
10086:             * Implements "binary numeric promotion" (5.6.2)
10087:             *
10088:             * @return The promoted type.
10089:             */
10090:            private IClass binaryNumericPromotion(Locatable l, IClass type1,
10091:                    CodeContext.Inserter convertInserter1, IClass type2,
10092:                    CodeContext.Inserter convertInserter2)
10093:                    throws CompileException {
10094:                IClass promotedType;
10095:                {
10096:                    IClass c1 = this .isUnboxingConvertible(type1);
10097:                    IClass c2 = this .isUnboxingConvertible(type2);
10098:                    promotedType = this .binaryNumericPromotionType(l,
10099:                            c1 != null ? c1 : type1, c2 != null ? c2 : type2);
10100:                }
10101:
10102:                if (convertInserter1 != null) {
10103:                    this .codeContext.pushInserter(convertInserter1);
10104:                    try {
10105:                        this .numericPromotion(l, this 
10106:                                .convertToPrimitiveNumericType(l, type1),
10107:                                promotedType);
10108:                    } finally {
10109:                        this .codeContext.popInserter();
10110:                    }
10111:                }
10112:
10113:                if (convertInserter2 != null) {
10114:                    this .codeContext.pushInserter(convertInserter2);
10115:                    try {
10116:                        this .numericPromotion(l, this 
10117:                                .convertToPrimitiveNumericType(l, type2),
10118:                                promotedType);
10119:                    } finally {
10120:                        this .codeContext.popInserter();
10121:                    }
10122:                }
10123:
10124:                return promotedType;
10125:            }
10126:
10127:            private IClass binaryNumericPromotionType(Java.Locatable locatable,
10128:                    IClass type1, IClass type2) throws CompileException {
10129:                if (!type1.isPrimitiveNumeric() || !type2.isPrimitiveNumeric())
10130:                    this .compileError(
10131:                            "Binary numeric promotion not possible on types \""
10132:                                    + type1 + "\" and \"" + type2 + "\"",
10133:                            locatable.getLocation());
10134:
10135:                return (type1 == IClass.DOUBLE || type2 == IClass.DOUBLE ? IClass.DOUBLE
10136:                        : type1 == IClass.FLOAT || type2 == IClass.FLOAT ? IClass.FLOAT
10137:                                : type1 == IClass.LONG || type2 == IClass.LONG ? IClass.LONG
10138:                                        : IClass.INT);
10139:            }
10140:
10141:            /**
10142:             * Checks whether "identity conversion" (5.1.1) is possible.
10143:             *
10144:             * @return Whether the conversion is possible
10145:             */
10146:            private boolean isIdentityConvertible(IClass sourceType,
10147:                    IClass targetType) {
10148:                return sourceType == targetType;
10149:            }
10150:
10151:            /**
10152:             * Implements "identity conversion" (5.1.1).
10153:             *
10154:             * @return Whether the conversion was possible
10155:             */
10156:            private boolean tryIdentityConversion(IClass sourceType,
10157:                    IClass targetType) {
10158:                return sourceType == targetType;
10159:            }
10160:
10161:            private boolean isWideningPrimitiveConvertible(IClass sourceType,
10162:                    IClass targetType) {
10163:                return UnitCompiler.PRIMITIVE_WIDENING_CONVERSIONS
10164:                        .get(sourceType.getDescriptor()
10165:                                + targetType.getDescriptor()) != null;
10166:            }
10167:
10168:            /**
10169:             * Implements "widening primitive conversion" (5.1.2).
10170:             *
10171:             * @return Whether the conversion succeeded
10172:             */
10173:            private boolean tryWideningPrimitiveConversion(Locatable l,
10174:                    IClass sourceType, IClass targetType) {
10175:                byte[] opcodes = (byte[]) UnitCompiler.PRIMITIVE_WIDENING_CONVERSIONS
10176:                        .get(sourceType.getDescriptor()
10177:                                + targetType.getDescriptor());
10178:                if (opcodes != null) {
10179:                    this .writeOpcodes(l, opcodes);
10180:                    return true;
10181:                }
10182:                return false;
10183:            }
10184:
10185:            private static final HashMap PRIMITIVE_WIDENING_CONVERSIONS = new HashMap();
10186:            static {
10187:                UnitCompiler.fillConversionMap(new Object[] { new byte[0],
10188:                        Descriptor.BYTE_ + Descriptor.SHORT_,
10189:
10190:                        Descriptor.BYTE_ + Descriptor.INT_,
10191:                        Descriptor.SHORT_ + Descriptor.INT_,
10192:                        Descriptor.CHAR_ + Descriptor.INT_,
10193:
10194:                        new byte[] { Opcode.I2L },
10195:                        Descriptor.BYTE_ + Descriptor.LONG_,
10196:                        Descriptor.SHORT_ + Descriptor.LONG_,
10197:                        Descriptor.CHAR_ + Descriptor.LONG_,
10198:                        Descriptor.INT_ + Descriptor.LONG_,
10199:
10200:                        new byte[] { Opcode.I2F },
10201:                        Descriptor.BYTE_ + Descriptor.FLOAT_,
10202:                        Descriptor.SHORT_ + Descriptor.FLOAT_,
10203:                        Descriptor.CHAR_ + Descriptor.FLOAT_,
10204:                        Descriptor.INT_ + Descriptor.FLOAT_,
10205:
10206:                        new byte[] { Opcode.L2F },
10207:                        Descriptor.LONG_ + Descriptor.FLOAT_,
10208:
10209:                        new byte[] { Opcode.I2D },
10210:                        Descriptor.BYTE_ + Descriptor.DOUBLE_,
10211:                        Descriptor.SHORT_ + Descriptor.DOUBLE_,
10212:                        Descriptor.CHAR_ + Descriptor.DOUBLE_,
10213:                        Descriptor.INT_ + Descriptor.DOUBLE_,
10214:
10215:                        new byte[] { Opcode.L2D },
10216:                        Descriptor.LONG_ + Descriptor.DOUBLE_,
10217:
10218:                        new byte[] { Opcode.F2D },
10219:                        Descriptor.FLOAT_ + Descriptor.DOUBLE_, },
10220:                        UnitCompiler.PRIMITIVE_WIDENING_CONVERSIONS);
10221:            }
10222:
10223:            private static void fillConversionMap(Object[] array, HashMap map) {
10224:                byte[] opcodes = null;
10225:                for (int i = 0; i < array.length; ++i) {
10226:                    Object o = array[i];
10227:                    if (o instanceof  byte[]) {
10228:                        opcodes = (byte[]) o;
10229:                    } else {
10230:                        map.put(o, opcodes);
10231:                    }
10232:                }
10233:            }
10234:
10235:            /**
10236:             * Checks if "widening reference conversion" (5.1.4) is possible.
10237:             *
10238:             * @return Whether the conversion is possible
10239:             */
10240:            private boolean isWideningReferenceConvertible(IClass sourceType,
10241:                    IClass targetType) throws CompileException {
10242:                if (targetType.isPrimitive() || sourceType == targetType)
10243:                    return false;
10244:
10245:                return targetType.isAssignableFrom(sourceType);
10246:            }
10247:
10248:            /**
10249:             * Performs "widening reference conversion" (5.1.4) if possible.
10250:             *
10251:             * @return Whether the conversion was possible
10252:             */
10253:            private boolean tryWideningReferenceConversion(IClass sourceType,
10254:                    IClass targetType) throws CompileException {
10255:                if (targetType.isPrimitive() || sourceType == targetType)
10256:                    return false;
10257:
10258:                return targetType.isAssignableFrom(sourceType);
10259:            }
10260:
10261:            /**
10262:             * Check whether "narrowing primitive conversion" (JLS 5.1.3) is possible.
10263:             */
10264:            private boolean isNarrowingPrimitiveConvertible(IClass sourceType,
10265:                    IClass targetType) {
10266:                return UnitCompiler.PRIMITIVE_NARROWING_CONVERSIONS
10267:                        .containsKey(sourceType.getDescriptor()
10268:                                + targetType.getDescriptor());
10269:            }
10270:
10271:            /**
10272:             * Implements "narrowing primitive conversion" (JLS 5.1.3).
10273:             *
10274:             * @return Whether the conversion succeeded
10275:             */
10276:            private boolean tryNarrowingPrimitiveConversion(Locatable l,
10277:                    IClass sourceType, IClass targetType) {
10278:                byte[] opcodes = (byte[]) UnitCompiler.PRIMITIVE_NARROWING_CONVERSIONS
10279:                        .get(sourceType.getDescriptor()
10280:                                + targetType.getDescriptor());
10281:                if (opcodes != null) {
10282:                    this .writeOpcodes(l, opcodes);
10283:                    return true;
10284:                }
10285:                return false;
10286:            }
10287:
10288:            private static final HashMap PRIMITIVE_NARROWING_CONVERSIONS = new HashMap();
10289:            static {
10290:                UnitCompiler.fillConversionMap(new Object[] { new byte[0],
10291:                        Descriptor.BYTE_ + Descriptor.CHAR_,
10292:                        Descriptor.SHORT_ + Descriptor.CHAR_,
10293:                        Descriptor.CHAR_ + Descriptor.SHORT_,
10294:
10295:                        new byte[] { Opcode.I2B },
10296:                        Descriptor.SHORT_ + Descriptor.BYTE_,
10297:                        Descriptor.CHAR_ + Descriptor.BYTE_,
10298:                        Descriptor.INT_ + Descriptor.BYTE_,
10299:
10300:                        new byte[] { Opcode.I2S },
10301:                        Descriptor.INT_ + Descriptor.SHORT_,
10302:                        Descriptor.INT_ + Descriptor.CHAR_,
10303:
10304:                        new byte[] { Opcode.L2I, Opcode.I2B },
10305:                        Descriptor.LONG_ + Descriptor.BYTE_,
10306:
10307:                        new byte[] { Opcode.L2I, Opcode.I2S },
10308:                        Descriptor.LONG_ + Descriptor.SHORT_,
10309:                        Descriptor.LONG_ + Descriptor.CHAR_,
10310:
10311:                        new byte[] { Opcode.L2I },
10312:                        Descriptor.LONG_ + Descriptor.INT_,
10313:
10314:                        new byte[] { Opcode.F2I, Opcode.I2B },
10315:                        Descriptor.FLOAT_ + Descriptor.BYTE_,
10316:
10317:                        new byte[] { Opcode.F2I, Opcode.I2S },
10318:                        Descriptor.FLOAT_ + Descriptor.SHORT_,
10319:                        Descriptor.FLOAT_ + Descriptor.CHAR_,
10320:
10321:                        new byte[] { Opcode.F2I },
10322:                        Descriptor.FLOAT_ + Descriptor.INT_,
10323:
10324:                        new byte[] { Opcode.F2L },
10325:                        Descriptor.FLOAT_ + Descriptor.LONG_,
10326:
10327:                        new byte[] { Opcode.D2I, Opcode.I2B },
10328:                        Descriptor.DOUBLE_ + Descriptor.BYTE_,
10329:
10330:                        new byte[] { Opcode.D2I, Opcode.I2S },
10331:                        Descriptor.DOUBLE_ + Descriptor.SHORT_,
10332:                        Descriptor.DOUBLE_ + Descriptor.CHAR_,
10333:
10334:                        new byte[] { Opcode.D2I },
10335:                        Descriptor.DOUBLE_ + Descriptor.INT_,
10336:
10337:                        new byte[] { Opcode.D2L },
10338:                        Descriptor.DOUBLE_ + Descriptor.LONG_,
10339:
10340:                        new byte[] { Opcode.D2F },
10341:                        Descriptor.DOUBLE_ + Descriptor.FLOAT_, },
10342:                        UnitCompiler.PRIMITIVE_NARROWING_CONVERSIONS);
10343:            }
10344:
10345:            /**
10346:             * Check if "constant assignment conversion" (JLS 5.2, paragraph 1) is possible.
10347:             * @param constantValue The constant value that is to be converted
10348:             * @param targetType The type to convert to
10349:             */
10350:            private boolean tryConstantAssignmentConversion(Locatable l,
10351:                    Object constantValue, IClass targetType)
10352:                    throws CompileException {
10353:                if (UnitCompiler.DEBUG)
10354:                    System.out
10355:                            .println("isConstantPrimitiveAssignmentConvertible("
10356:                                    + constantValue + ", " + targetType + ")");
10357:
10358:                int cv;
10359:                if (constantValue instanceof  Byte) {
10360:                    cv = ((Byte) constantValue).byteValue();
10361:                } else if (constantValue instanceof  Short) {
10362:                    cv = ((Short) constantValue).shortValue();
10363:                } else if (constantValue instanceof  Integer) {
10364:                    cv = ((Integer) constantValue).intValue();
10365:                } else if (constantValue instanceof  Character) {
10366:                    cv = ((Character) constantValue).charValue();
10367:                } else {
10368:                    return false;
10369:                }
10370:
10371:                if (targetType == IClass.BYTE)
10372:                    return cv >= Byte.MIN_VALUE && cv <= Byte.MAX_VALUE;
10373:                if (targetType == IClass.SHORT)
10374:                    return cv >= Short.MIN_VALUE && cv <= Short.MAX_VALUE;
10375:                if (targetType == IClass.CHAR)
10376:                    return cv >= Character.MIN_VALUE
10377:                            && cv <= Character.MAX_VALUE;
10378:
10379:                IClassLoader icl = this .iClassLoader;
10380:                if (targetType == icl.BYTE && cv >= Byte.MIN_VALUE
10381:                        && cv <= Byte.MAX_VALUE) {
10382:                    this .boxingConversion(l, IClass.BYTE, targetType);
10383:                    return true;
10384:                }
10385:                if (targetType == icl.SHORT && cv >= Short.MIN_VALUE
10386:                        && cv <= Short.MAX_VALUE) {
10387:                    this .boxingConversion(l, IClass.SHORT, targetType);
10388:                    return true;
10389:                }
10390:                if (targetType == icl.CHARACTER && cv >= Character.MIN_VALUE
10391:                        && cv <= Character.MAX_VALUE) {
10392:                    this .boxingConversion(l, IClass.CHAR, targetType);
10393:                    return true;
10394:                }
10395:
10396:                return false;
10397:            }
10398:
10399:            /**
10400:             * Check whether "narrowing reference conversion" (JLS 5.1.5) is possible.
10401:             */
10402:            private boolean isNarrowingReferenceConvertible(IClass sourceType,
10403:                    IClass targetType) throws CompileException {
10404:                if (sourceType.isPrimitive())
10405:                    return false;
10406:                if (sourceType == targetType)
10407:                    return false;
10408:
10409:                // 5.1.5.1
10410:                if (sourceType.isAssignableFrom(targetType))
10411:                    return true;
10412:
10413:                // 5.1.5.2
10414:                if (targetType.isInterface() && !sourceType.isFinal()
10415:                        && !targetType.isAssignableFrom(sourceType))
10416:                    return true;
10417:
10418:                // 5.1.5.3
10419:                if (sourceType == this .iClassLoader.OBJECT
10420:                        && targetType.isArray())
10421:                    return true;
10422:
10423:                // 5.1.5.4
10424:                if (sourceType == this .iClassLoader.OBJECT
10425:                        && targetType.isInterface())
10426:                    return true;
10427:
10428:                // 5.1.5.5
10429:                if (sourceType.isInterface() && !targetType.isFinal())
10430:                    return true;
10431:
10432:                // 5.1.5.6
10433:                if (sourceType.isInterface() && targetType.isFinal()
10434:                        && sourceType.isAssignableFrom(targetType))
10435:                    return true;
10436:
10437:                // 5.1.5.7
10438:                // TODO: Check for redefinition of methods with same signature but different return type.
10439:                if (sourceType.isInterface() && targetType.isInterface()
10440:                        && !targetType.isAssignableFrom(sourceType))
10441:                    return true;
10442:
10443:                // 5.1.5.8
10444:                if (sourceType.isArray() && targetType.isArray()) {
10445:                    IClass st = sourceType.getComponentType();
10446:                    IClass tt = targetType.getComponentType();
10447:                    if (this .isNarrowingPrimitiveConvertible(st, tt)
10448:                            || this .isNarrowingReferenceConvertible(st, tt))
10449:                        return true;
10450:                }
10451:
10452:                return false;
10453:            }
10454:
10455:            /**
10456:             * Implements "narrowing reference conversion" (5.1.5).
10457:             *
10458:             * @return Whether the conversion succeeded
10459:             */
10460:            private boolean tryNarrowingReferenceConversion(Locatable l,
10461:                    IClass sourceType, IClass targetType)
10462:                    throws CompileException {
10463:                if (!this .isNarrowingReferenceConvertible(sourceType,
10464:                        targetType))
10465:                    return false;
10466:
10467:                this .writeOpcode(l, Opcode.CHECKCAST);
10468:                this .writeConstantClassInfo(targetType.getDescriptor());
10469:                return true;
10470:            }
10471:
10472:            /*
10473:             * @return the boxed type or <code>null</code>
10474:             */
10475:            private IClass isBoxingConvertible(IClass sourceType) {
10476:                IClassLoader icl = this .iClassLoader;
10477:                if (sourceType == IClass.BOOLEAN)
10478:                    return icl.BOOLEAN;
10479:                if (sourceType == IClass.BYTE)
10480:                    return icl.BYTE;
10481:                if (sourceType == IClass.CHAR)
10482:                    return icl.CHARACTER;
10483:                if (sourceType == IClass.SHORT)
10484:                    return icl.SHORT;
10485:                if (sourceType == IClass.INT)
10486:                    return icl.INTEGER;
10487:                if (sourceType == IClass.LONG)
10488:                    return icl.LONG;
10489:                if (sourceType == IClass.FLOAT)
10490:                    return icl.FLOAT;
10491:                if (sourceType == IClass.DOUBLE)
10492:                    return icl.DOUBLE;
10493:                return null;
10494:            }
10495:
10496:            private boolean tryBoxingConversion(Locatable l, IClass sourceType,
10497:                    IClass targetType) throws CompileException {
10498:                if (this .isBoxingConvertible(sourceType) == targetType) {
10499:                    this .boxingConversion(l, sourceType, targetType);
10500:                    return true;
10501:                }
10502:                return false;
10503:            }
10504:
10505:            /**
10506:             * @param sourceType a primitive type (except VOID)
10507:             * @param targetType the corresponding wrapper type
10508:             */
10509:            private void boxingConversion(Locatable l, IClass sourceType,
10510:                    IClass targetType) throws CompileException {
10511:
10512:                // In some pre-1.5 JDKs, only some wrapper classes have the static "Target.valueOf(source)" method.
10513:                if (targetType.hasIMethod("valueOf",
10514:                        new IClass[] { sourceType })) {
10515:                    this .writeOpcode(l, Opcode.INVOKESTATIC);
10516:                    this .writeConstantMethodrefInfo(targetType.getDescriptor(),
10517:                            "valueOf", // classFD
10518:                            '(' + sourceType.getDescriptor() + ')'
10519:                                    + targetType.getDescriptor() // methodFD
10520:                    );
10521:                    return;
10522:                }
10523:                // new Target(source)
10524:                this .writeOpcode(l, Opcode.NEW);
10525:                this .writeConstantClassInfo(targetType.getDescriptor());
10526:                if (Descriptor.hasSize2(sourceType.getDescriptor())) {
10527:                    this .writeOpcode(l, Opcode.DUP_X2);
10528:                    this .writeOpcode(l, Opcode.DUP_X2);
10529:                    this .writeOpcode(l, Opcode.POP);
10530:                } else {
10531:                    this .writeOpcode(l, Opcode.DUP_X1);
10532:                    this .writeOpcode(l, Opcode.SWAP);
10533:                }
10534:                this .writeOpcode(l, Opcode.INVOKESPECIAL);
10535:                this .writeConstantMethodrefInfo(targetType.getDescriptor(),
10536:                        "<init>", // classFD
10537:                        '(' + sourceType.getDescriptor() + ')'
10538:                                + Descriptor.VOID_ // methodMD
10539:                );
10540:            }
10541:
10542:            /*
10543:             * @return the unboxed type or <code>null</code>
10544:             */
10545:            private IClass isUnboxingConvertible(IClass sourceType) {
10546:                IClassLoader icl = this .iClassLoader;
10547:                if (sourceType == icl.BOOLEAN)
10548:                    return IClass.BOOLEAN;
10549:                if (sourceType == icl.BYTE)
10550:                    return IClass.BYTE;
10551:                if (sourceType == icl.CHARACTER)
10552:                    return IClass.CHAR;
10553:                if (sourceType == icl.SHORT)
10554:                    return IClass.SHORT;
10555:                if (sourceType == icl.INTEGER)
10556:                    return IClass.INT;
10557:                if (sourceType == icl.LONG)
10558:                    return IClass.LONG;
10559:                if (sourceType == icl.FLOAT)
10560:                    return IClass.FLOAT;
10561:                if (sourceType == icl.DOUBLE)
10562:                    return IClass.DOUBLE;
10563:                return null;
10564:            }
10565:
10566:            private boolean tryUnboxingConversion(Locatable l,
10567:                    IClass sourceType, IClass targetType) {
10568:                if (this .isUnboxingConvertible(sourceType) == targetType) {
10569:                    this .unboxingConversion(l, sourceType, targetType);
10570:                    return true;
10571:                }
10572:                return false;
10573:            }
10574:
10575:            /**
10576:             * @param targetType a primitive type (except VOID)
10577:             * @param sourceType the corresponding wrapper type
10578:             */
10579:            private void unboxingConversion(Locatable l, IClass sourceType,
10580:                    IClass targetType) {
10581:
10582:                // "source.targetValue()"
10583:                this .writeOpcode(l, Opcode.INVOKEVIRTUAL);
10584:                this .writeConstantMethodrefInfo(sourceType.getDescriptor(),
10585:                        targetType.toString() + "Value", // classFD
10586:                        "()" + targetType.getDescriptor() // methodFD
10587:                );
10588:            }
10589:
10590:            /**
10591:             * Attempt to load an {@link IClass} by fully-qualified name
10592:             * @param identifiers
10593:             * @return <code>null</code> if a class with the given name could not be loaded
10594:             */
10595:            private IClass loadFullyQualifiedClass(String[] identifiers)
10596:                    throws CompileException {
10597:
10598:                // Compose the descriptor (like "La/b/c;") and remember the positions of the slashes
10599:                // (2 and 4).
10600:                int[] slashes = new int[identifiers.length - 1];
10601:                StringBuffer sb = new StringBuffer("L");
10602:                for (int i = 0;; ++i) {
10603:                    sb.append(identifiers[i]);
10604:                    if (i == identifiers.length - 1)
10605:                        break;
10606:                    slashes[i] = sb.length();
10607:                    sb.append('/');
10608:                }
10609:                sb.append(';');
10610:
10611:                // Attempt to load the IClass and replace dots with dollar signs, i.e.:
10612:                // La/b/c; La/b$c; La$b$c;
10613:                for (int j = slashes.length - 1;; --j) {
10614:                    IClass result;
10615:                    try {
10616:                        result = this .iClassLoader.loadIClass(sb.toString());
10617:                    } catch (ClassNotFoundException ex) {
10618:                        if (ex.getException() instanceof  CompileException)
10619:                            throw (CompileException) ex.getException();
10620:                        throw new CompileException(sb.toString(), null, ex);
10621:                    }
10622:                    if (result != null)
10623:                        return result;
10624:                    if (j < 0)
10625:                        break;
10626:                    sb.setCharAt(slashes[j], '$');
10627:                }
10628:                return null;
10629:            }
10630:
10631:            // Load the value of a local variable onto the stack and return its type.
10632:            private IClass load(Locatable l, Java.LocalVariable localVariable) {
10633:                this .load(l, localVariable.type,
10634:                        localVariable.localVariableArrayIndex);
10635:                return localVariable.type;
10636:            }
10637:
10638:            private void load(Locatable l, IClass type, int index) {
10639:                if (index <= 3) {
10640:                    this .writeOpcode(l, Opcode.ILOAD_0 + 4 * this .ilfda(type)
10641:                            + index);
10642:                } else if (index <= 255) {
10643:                    this .writeOpcode(l, Opcode.ILOAD + this .ilfda(type));
10644:                    this .writeByte(index);
10645:                } else {
10646:                    this .writeOpcode(l, Opcode.WIDE);
10647:                    this .writeOpcode(l, Opcode.ILOAD + this .ilfda(type));
10648:                    this .writeShort(index);
10649:                }
10650:            }
10651:
10652:            /**
10653:             * Assign stack top value to the given local variable. (Assignment conversion takes effect.)
10654:             * If <copde>optionalConstantValue</code> is not <code>null</code>, then the top stack value
10655:             * is a constant value with that type and value, and a narrowing primitive conversion as
10656:             * described in JLS 5.2 is applied.
10657:             */
10658:            private void store(Locatable l, IClass valueType,
10659:                    Java.LocalVariable localVariable) {
10660:                this .store(l, // l
10661:                        localVariable.type, // lvType
10662:                        localVariable.localVariableArrayIndex // lvIndex
10663:                        );
10664:            }
10665:
10666:            private void store(Locatable l, IClass lvType, short lvIndex) {
10667:                if (lvIndex <= 3) {
10668:                    this .writeOpcode(l, Opcode.ISTORE_0 + 4
10669:                            * this .ilfda(lvType) + lvIndex);
10670:                } else if (lvIndex <= 255) {
10671:                    this .writeOpcode(l, Opcode.ISTORE + this .ilfda(lvType));
10672:                    this .writeByte(lvIndex);
10673:                } else {
10674:                    this .writeOpcode(l, Opcode.WIDE);
10675:                    this .writeOpcode(l, Opcode.ISTORE + this .ilfda(lvType));
10676:                    this .writeShort(lvIndex);
10677:                }
10678:            }
10679:
10680:            private void dup(Locatable l, int n) {
10681:                switch (n) {
10682:
10683:                case 0:
10684:                    ;
10685:                    break;
10686:
10687:                case 1:
10688:                    this .writeOpcode(l, Opcode.DUP);
10689:                    break;
10690:
10691:                case 2:
10692:                    this .writeOpcode(l, Opcode.DUP2);
10693:                    break;
10694:
10695:                default:
10696:                    throw new RuntimeException("dup(" + n + ")");
10697:                }
10698:            }
10699:
10700:            private void dupx(Locatable l, IClass type, int x) {
10701:                if (x < 0 || x > 2)
10702:                    throw new RuntimeException("SNO: x has value " + x);
10703:                int dup = Opcode.DUP + x;
10704:                int dup2 = Opcode.DUP2 + x;
10705:                this .writeOpcode(l, (type == IClass.LONG
10706:                        || type == IClass.DOUBLE ? dup2 : dup));
10707:            }
10708:
10709:            private void pop(Locatable l, IClass type) {
10710:                if (type == IClass.VOID)
10711:                    return;
10712:                this .writeOpcode(l, (type == IClass.LONG
10713:                        || type == IClass.DOUBLE ? Opcode.POP2 : Opcode.POP));
10714:            }
10715:
10716:            static int ilfd(IClass t) {
10717:                if (t == IClass.BYTE || t == IClass.CHAR || t == IClass.INT
10718:                        || t == IClass.SHORT || t == IClass.BOOLEAN)
10719:                    return 0;
10720:                if (t == IClass.LONG)
10721:                    return 1;
10722:                if (t == IClass.FLOAT)
10723:                    return 2;
10724:                if (t == IClass.DOUBLE)
10725:                    return 3;
10726:                throw new RuntimeException("Unexpected type \"" + t + "\"");
10727:            }
10728:
10729:            static int ilfd(IClass t, int opcodeInt, int opcodeLong,
10730:                    int opcodeFloat, int opcodeDouble) {
10731:                if (t == IClass.BYTE || t == IClass.CHAR || t == IClass.INT
10732:                        || t == IClass.SHORT || t == IClass.BOOLEAN)
10733:                    return opcodeInt;
10734:                if (t == IClass.LONG)
10735:                    return opcodeLong;
10736:                if (t == IClass.FLOAT)
10737:                    return opcodeFloat;
10738:                if (t == IClass.DOUBLE)
10739:                    return opcodeDouble;
10740:                throw new RuntimeException("Unexpected type \"" + t + "\"");
10741:            }
10742:
10743:            private int ilfda(IClass t) {
10744:                return !t.isPrimitive() ? 4 : UnitCompiler.ilfd(t);
10745:            }
10746:
10747:            static int ilfdabcs(IClass t) {
10748:                if (t == IClass.INT)
10749:                    return 0;
10750:                if (t == IClass.LONG)
10751:                    return 1;
10752:                if (t == IClass.FLOAT)
10753:                    return 2;
10754:                if (t == IClass.DOUBLE)
10755:                    return 3;
10756:                if (!t.isPrimitive())
10757:                    return 4;
10758:                if (t == IClass.BOOLEAN || t == IClass.BYTE)
10759:                    return 5;
10760:                if (t == IClass.CHAR)
10761:                    return 6;
10762:                if (t == IClass.SHORT)
10763:                    return 7;
10764:                throw new RuntimeException("Unexpected type \"" + t + "\"");
10765:            }
10766:
10767:            /**
10768:             * Find a named field in the given {@link IClass}.
10769:             * Honor superclasses and interfaces. See JLS 8.3.
10770:             * @return <code>null</code> if no field is found
10771:             */
10772:            private IClass.IField findIField(IClass iClass, String name,
10773:                    Location location) throws CompileException {
10774:
10775:                // Search for a field with the given name in the current class.
10776:                IClass.IField[] fields = iClass.getDeclaredIFields();
10777:                for (int i = 0; i < fields.length; ++i) {
10778:                    final IClass.IField f = fields[i];
10779:                    if (name.equals(f.getName()))
10780:                        return f;
10781:                }
10782:
10783:                // Examine superclass.
10784:                IClass.IField f = null;
10785:                {
10786:                    IClass super class = iClass.getSuperclass();
10787:                    if (super class != null)
10788:                        f = this .findIField(super class, name, location);
10789:                }
10790:
10791:                // Examine interfaces.
10792:                IClass[] ifs = iClass.getInterfaces();
10793:                for (int i = 0; i < ifs.length; ++i) {
10794:                    IClass.IField f2 = this .findIField(ifs[i], name, location);
10795:                    if (f2 != null) {
10796:                        if (f != null)
10797:                            throw new CompileException(
10798:                                    "Access to field \"" + name
10799:                                            + "\" is ambiguous - both \""
10800:                                            + f.getDeclaringIClass()
10801:                                            + "\" and \""
10802:                                            + f2.getDeclaringIClass()
10803:                                            + "\" declare it", location);
10804:                        f = f2;
10805:                    }
10806:                }
10807:                return f;
10808:            }
10809:
10810:            /**
10811:             * Find a named type in the given {@link IClass}.
10812:             * Honor superclasses, interfaces and enclosing type declarations.
10813:             * @return <code>null</code> if no type with the given name is found
10814:             */
10815:            private IClass findMemberType(IClass iClass, String name,
10816:                    Location location) throws CompileException {
10817:                IClass[] types = iClass.findMemberType(name);
10818:                if (types.length == 0)
10819:                    return null;
10820:                if (types.length == 1)
10821:                    return types[0];
10822:
10823:                StringBuffer sb = new StringBuffer("Type \"" + name
10824:                        + "\" is ambiguous: " + types[0].toString());
10825:                for (int i = 1; i < types.length; ++i)
10826:                    sb.append(" vs. ").append(types[i].toString());
10827:                this .compileError(sb.toString(), location);
10828:                return types[0];
10829:            }
10830:
10831:            /**
10832:             * Find one class or interface by name.
10833:             * @param className Fully qualified class name, e.g. "pkg1.pkg2.Outer$Inner".
10834:             * @return <code>null</code> if a class with that name is not declared in this compilation unit
10835:             */
10836:            public IClass findClass(String className) {
10837:
10838:                // Examine package name.
10839:                String packageName = (this .compilationUnit.optionalPackageDeclaration == null ? null
10840:                        : this .compilationUnit.optionalPackageDeclaration.packageName);
10841:                if (packageName != null) {
10842:                    if (!className.startsWith(packageName + '.'))
10843:                        return null;
10844:                    className = className.substring(packageName.length() + 1);
10845:                }
10846:
10847:                StringTokenizer st = new StringTokenizer(className, "$");
10848:                Java.TypeDeclaration td = this .compilationUnit
10849:                        .getPackageMemberTypeDeclaration(st.nextToken());
10850:                if (td == null)
10851:                    return null;
10852:                while (st.hasMoreTokens()) {
10853:                    td = td.getMemberTypeDeclaration(st.nextToken());
10854:                    if (td == null)
10855:                        return null;
10856:                }
10857:                return this .resolve((Java.AbstractTypeDeclaration) td);
10858:            }
10859:
10860:            /**
10861:             * Equivalent to {@link #compileError(String, Location)} with a
10862:             * <code>null</code> location argument.
10863:             */
10864:            private void compileError(String message) throws CompileException {
10865:                this .compileError(message, null);
10866:            }
10867:
10868:            /**
10869:             * Issue a compile error with the given message. This is done through the
10870:             * {@link ErrorHandler} that was installed through
10871:             * {@link #setCompileErrorHandler(ErrorHandler)}. Such a handler typically throws
10872:             * a {@link CompileException}, but it may as well decide to return normally. Consequently,
10873:             * the calling code must be prepared that {@link #compileError(String, Location)}
10874:             * returns normally, and must attempt to continue compiling.
10875:             *
10876:             * @param message The message to report
10877:             * @param optionalLocation The location to report
10878:             */
10879:            private void compileError(String message, Location optionalLocation)
10880:                    throws CompileException {
10881:                ++this .compileErrorCount;
10882:                if (this .optionalCompileErrorHandler != null) {
10883:                    this .optionalCompileErrorHandler.handleError(message,
10884:                            optionalLocation);
10885:                } else {
10886:                    throw new CompileException(message, optionalLocation);
10887:                }
10888:            }
10889:
10890:            /**
10891:             * Issues a warning with the given message an location an returns. This is done through
10892:             * a {@link WarningHandler} that was installed through
10893:             * {@link #setWarningHandler(WarningHandler)}.
10894:             * <p>
10895:             * The <code>handle</code> argument qulifies the warning and is typically used by
10896:             * the {@link WarningHandler} to suppress individual warnings.
10897:             *
10898:             * @param handle
10899:             * @param message
10900:             * @param optionalLocation
10901:             */
10902:            private void warning(String handle, String message,
10903:                    Location optionalLocation) {
10904:                if (this .optionalWarningHandler != null)
10905:                    this .optionalWarningHandler.handleWarning(handle, message,
10906:                            optionalLocation);
10907:            }
10908:
10909:            /**
10910:             * Interface type for {@link UnitCompiler#setCompileErrorHandler}.
10911:             */
10912:            public interface ErrorHandler {
10913:                void handleError(String message, Location optionalLocation)
10914:                        throws CompileException;
10915:            }
10916:
10917:            /**
10918:             * By default, {@link CompileException}s are thrown on compile errors, but an application
10919:             * my install its own (thread-local) {@link ErrorHandler}.
10920:             * <p>
10921:             * Be aware that a single problem during compilation often causes a bunch of compile errors,
10922:             * so a good {@link ErrorHandler} counts errors and throws a {@link CompileException} when
10923:             * a limit is reached.
10924:             * <p>
10925:             * If the given {@link ErrorHandler} does not throw {@link CompileException}s, then
10926:             * {@link #compileUnit(EnumeratorSet)} will throw one when the compilation of the unit
10927:             * is finished, and errors had occurred. In other words: The {@link ErrorHandler} may
10928:             * throw a {@link CompileException} or not, but {@link #compileUnit(EnumeratorSet)} will
10929:             * definitely throw a {@link CompileException} if one or more compile errors have
10930:             * occurred.
10931:             *
10932:             * @param optionalCompileErrorHandler <code>null</code> to restore the default behavior (throwing a {@link CompileException}
10933:             */
10934:            public void setCompileErrorHandler(
10935:                    ErrorHandler optionalCompileErrorHandler) {
10936:                this .optionalCompileErrorHandler = optionalCompileErrorHandler;
10937:            }
10938:
10939:            /**
10940:             * By default, warnings are discarded, but an application my install a custom
10941:             * {@link WarningHandler}.
10942:             *
10943:             * @param optionalWarningHandler <code>null</code> to indicate that no warnings be issued
10944:             */
10945:            public void setWarningHandler(WarningHandler optionalWarningHandler) {
10946:                this .optionalWarningHandler = optionalWarningHandler;
10947:            }
10948:
10949:            private CodeContext getCodeContext() {
10950:                CodeContext res = this .codeContext;
10951:                if (res == null)
10952:                    throw new RuntimeException("S.N.O.: Null CodeContext");
10953:                return res;
10954:            }
10955:
10956:            private CodeContext replaceCodeContext(CodeContext newCodeContext) {
10957:                CodeContext oldCodeContext = this .codeContext;
10958:                this .codeContext = newCodeContext;
10959:                return oldCodeContext;
10960:            }
10961:
10962:            private CodeContext createDummyCodeContext() {
10963:                return new CodeContext(this .getCodeContext().getClassFile());
10964:            }
10965:
10966:            private void writeByte(int v) {
10967:                this .codeContext.write((short) -1, new byte[] { (byte) v });
10968:            }
10969:
10970:            private void writeShort(int v) {
10971:                this .codeContext.write((short) -1, new byte[] {
10972:                        (byte) (v >> 8), (byte) v });
10973:            }
10974:
10975:            private void writeInt(int v) {
10976:                this .codeContext.write((short) -1, new byte[] {
10977:                        (byte) (v >> 24), (byte) (v >> 16), (byte) (v >> 8),
10978:                        (byte) v });
10979:            }
10980:
10981:            private void writeOpcode(Java.Locatable l, int opcode) {
10982:                this .codeContext.write(l.getLocation().getLineNumber(),
10983:                        new byte[] { (byte) opcode });
10984:            }
10985:
10986:            private void writeOpcodes(Java.Locatable l, byte[] opcodes) {
10987:                this .codeContext
10988:                        .write(l.getLocation().getLineNumber(), opcodes);
10989:            }
10990:
10991:            private void writeBranch(Java.Locatable l, int opcode,
10992:                    final CodeContext.Offset dst) {
10993:                this .codeContext.writeBranch(l.getLocation().getLineNumber(),
10994:                        opcode, dst);
10995:            }
10996:
10997:            private void writeOffset(CodeContext.Offset src,
10998:                    final CodeContext.Offset dst) {
10999:                this .codeContext.writeOffset((short) -1, src, dst);
11000:            }
11001:
11002:            // Wrappers for "ClassFile.addConstant...Info()". Saves us some coding overhead.
11003:
11004:            private void writeConstantClassInfo(String descriptor) {
11005:                CodeContext ca = this .codeContext;
11006:                ca.writeShort((short) -1, ca.getClassFile()
11007:                        .addConstantClassInfo(descriptor));
11008:            }
11009:
11010:            private void writeConstantFieldrefInfo(String classFD,
11011:                    String fieldName, String fieldFD) {
11012:                CodeContext ca = this .codeContext;
11013:                ca.writeShort((short) -1, ca.getClassFile()
11014:                        .addConstantFieldrefInfo(classFD, fieldName, fieldFD));
11015:            }
11016:
11017:            private void writeConstantMethodrefInfo(String classFD,
11018:                    String methodName, String methodMD) {
11019:                CodeContext ca = this .codeContext;
11020:                ca.writeShort((short) -1,
11021:                        ca.getClassFile().addConstantMethodrefInfo(classFD,
11022:                                methodName, methodMD));
11023:            }
11024:
11025:            private void writeConstantInterfaceMethodrefInfo(String classFD,
11026:                    String methodName, String methodMD) {
11027:                CodeContext ca = this .codeContext;
11028:                ca.writeShort((short) -1, ca.getClassFile()
11029:                        .addConstantInterfaceMethodrefInfo(classFD, methodName,
11030:                                methodMD));
11031:            }
11032:
11033:            /* UNUSED
11034:             private void writeConstantStringInfo(String value) {
11035:             this.codeContext.writeShort((short) -1, this.addConstantStringInfo(value));
11036:             }
11037:             */
11038:            private short addConstantStringInfo(String value) {
11039:                return this .codeContext.getClassFile().addConstantStringInfo(
11040:                        value);
11041:            }
11042:
11043:            /* UNUSED
11044:             private void writeConstantIntegerInfo(int value) {
11045:             this.codeContext.writeShort((short) -1, this.addConstantIntegerInfo(value));
11046:             }
11047:             */
11048:            private short addConstantIntegerInfo(int value) {
11049:                return this .codeContext.getClassFile().addConstantIntegerInfo(
11050:                        value);
11051:            }
11052:
11053:            /* UNUSED
11054:             private void writeConstantFloatInfo(float value) {
11055:             this.codeContext.writeShort((short) -1, this.addConstantFloatInfo(value));
11056:             }
11057:             */
11058:            private short addConstantFloatInfo(float value) {
11059:                return this .codeContext.getClassFile().addConstantFloatInfo(
11060:                        value);
11061:            }
11062:
11063:            private void writeConstantLongInfo(long value) {
11064:                CodeContext ca = this .codeContext;
11065:                ca.writeShort((short) -1, ca.getClassFile()
11066:                        .addConstantLongInfo(value));
11067:            }
11068:
11069:            private void writeConstantDoubleInfo(double value) {
11070:                CodeContext ca = this .codeContext;
11071:                ca.writeShort((short) -1, ca.getClassFile()
11072:                        .addConstantDoubleInfo(value));
11073:            }
11074:
11075:            public CodeContext.Offset getWhereToBreak(Java.BreakableStatement bs) {
11076:                if (bs.whereToBreak == null) {
11077:                    bs.whereToBreak = this .codeContext.new Offset();
11078:                }
11079:                return bs.whereToBreak;
11080:            }
11081:
11082:            private Java.TypeBodyDeclaration getDeclaringTypeBodyDeclaration(
11083:                    Java.QualifiedThisReference qtr) throws CompileException {
11084:                if (qtr.declaringTypeBodyDeclaration == null) {
11085:
11086:                    // Compile error if in static function context.
11087:                    Java.Scope s;
11088:                    for (s = qtr.getEnclosingBlockStatement(); !(s instanceof  Java.TypeBodyDeclaration); s = s
11089:                            .getEnclosingScope())
11090:                        ;
11091:                    qtr.declaringTypeBodyDeclaration = (Java.TypeBodyDeclaration) s;
11092:                    if (qtr.declaringTypeBodyDeclaration.isStatic())
11093:                        this 
11094:                                .compileError(
11095:                                        "No current instance available in static method",
11096:                                        qtr.getLocation());
11097:
11098:                    // Determine declaring type.
11099:                    qtr.declaringClass = (Java.ClassDeclaration) qtr.declaringTypeBodyDeclaration
11100:                            .getDeclaringType();
11101:                }
11102:                return qtr.declaringTypeBodyDeclaration;
11103:            }
11104:
11105:            private Java.ClassDeclaration getDeclaringClass(
11106:                    Java.QualifiedThisReference qtr) throws CompileException {
11107:                if (qtr.declaringClass == null) {
11108:                    this .getDeclaringTypeBodyDeclaration(qtr);
11109:                }
11110:                return qtr.declaringClass;
11111:            }
11112:
11113:            private void referenceThis(Locatable l) {
11114:                this .writeOpcode(l, Opcode.ALOAD_0);
11115:            }
11116:
11117:            /**
11118:             * Expects "dimExprCount" values of type "integer" on the operand stack.
11119:             * Creates an array of "dimExprCount" + "dims" dimensions of
11120:             * "componentType".
11121:             *
11122:             * @return The type of the created array
11123:             */
11124:            private IClass newArray(Locatable l, int dimExprCount, int dims,
11125:                    IClass componentType) {
11126:                if (dimExprCount == 1 && dims == 0
11127:                        && componentType.isPrimitive()) {
11128:
11129:                    // "new <primitive>[<n>]"
11130:                    this .writeOpcode(l, Opcode.NEWARRAY);
11131:                    this 
11132:                            .writeByte((componentType == IClass.BOOLEAN ? 4
11133:                                    : componentType == IClass.CHAR ? 5
11134:                                            : componentType == IClass.FLOAT ? 6
11135:                                                    : componentType == IClass.DOUBLE ? 7
11136:                                                            : componentType == IClass.BYTE ? 8
11137:                                                                    : componentType == IClass.SHORT ? 9
11138:                                                                            : componentType == IClass.INT ? 10
11139:                                                                                    : componentType == IClass.LONG ? 11
11140:                                                                                            : -1));
11141:                    return componentType
11142:                            .getArrayIClass(this .iClassLoader.OBJECT);
11143:                }
11144:
11145:                if (dimExprCount == 1) {
11146:                    IClass at = componentType.getArrayIClass(dims,
11147:                            this .iClassLoader.OBJECT);
11148:
11149:                    // "new <class-or-interface>[<n>]"
11150:                    // "new <anything>[<n>][]..."
11151:                    this .writeOpcode(l, Opcode.ANEWARRAY);
11152:                    this .writeConstantClassInfo(at.getDescriptor());
11153:                    return at.getArrayIClass(this .iClassLoader.OBJECT);
11154:                } else {
11155:                    IClass at = componentType.getArrayIClass(dimExprCount
11156:                            + dims, this .iClassLoader.OBJECT);
11157:
11158:                    // "new <anything>[]..."
11159:                    // "new <anything>[<n>][<m>]..."
11160:                    // "new <anything>[<n>][<m>]...[]..."
11161:                    this .writeOpcode(l, Opcode.MULTIANEWARRAY);
11162:                    this .writeConstantClassInfo(at.getDescriptor());
11163:                    this .writeByte(dimExprCount);
11164:                    return at;
11165:                }
11166:            }
11167:
11168:            /**
11169:             * Short-hand implementation of {@link IClass.IField} that implements a
11170:             * non-constant, non-static, package-accessible field.
11171:             */
11172:            public static class SimpleIField extends IClass.IField {
11173:                private final String name;
11174:                private final IClass type;
11175:
11176:                public SimpleIField(IClass declaringIClass, String name,
11177:                        IClass type) {
11178:                    declaringIClass.super ();
11179:                    this .name = name;
11180:                    this .type = type;
11181:                }
11182:
11183:                public Object getConstantValue() {
11184:                    return null;
11185:                }
11186:
11187:                public String getName() {
11188:                    return this .name;
11189:                }
11190:
11191:                public IClass getType() {
11192:                    return this .type;
11193:                }
11194:
11195:                public boolean isStatic() {
11196:                    return false;
11197:                }
11198:
11199:                public Access getAccess() {
11200:                    return Access.DEFAULT;
11201:                }
11202:            };
11203:
11204:            private static Access modifiers2Access(short modifiers) {
11205:                return ((modifiers & Mod.PUBLIC) != 0 ? Access.PUBLIC
11206:                        : (modifiers & Mod.PROTECTED) != 0 ? Access.PROTECTED
11207:                                : (modifiers & Mod.PRIVATE) != 0 ? Access.PRIVATE
11208:                                        : Access.DEFAULT);
11209:            }
11210:
11211:            private static String last(String[] sa) {
11212:                if (sa.length == 0)
11213:                    throw new IllegalArgumentException(
11214:                            "SNO: Empty string array");
11215:                return sa[sa.length - 1];
11216:            }
11217:
11218:            private static String[] allButLast(String[] sa) {
11219:                if (sa.length == 0)
11220:                    throw new IllegalArgumentException(
11221:                            "SNO: Empty string array");
11222:                String[] tmp = new String[sa.length - 1];
11223:                System.arraycopy(sa, 0, tmp, 0, tmp.length);
11224:                return tmp;
11225:            }
11226:
11227:            private static String[] concat(String[] sa, String s) {
11228:                String[] tmp = new String[sa.length + 1];
11229:                System.arraycopy(sa, 0, tmp, 0, sa.length);
11230:                tmp[sa.length] = s;
11231:                return tmp;
11232:            }
11233:
11234:            // Used to write byte code while compiling one constructor/method.
11235:            private CodeContext codeContext = null;
11236:
11237:            // Used for elaborate compile error handling.
11238:            private ErrorHandler optionalCompileErrorHandler = null;
11239:            private int compileErrorCount = 0;
11240:
11241:            // Used for elaborate warning handling.
11242:            private WarningHandler optionalWarningHandler = null;
11243:
11244:            public final Java.CompilationUnit compilationUnit;
11245:
11246:            private final IClassLoader iClassLoader;
11247:            private final boolean isStringBuilderAvailable;
11248:            private List generatedClassFiles;
11249:            private EnumeratorSet debuggingInformation;
11250:
11251:            private final Map singleTypeImports = new HashMap(); // String simpleTypeName => String[] fullyQualifiedTypeName
11252:            private final Collection typeImportsOnDemand; // String[] package
11253:            private final Map singleStaticImports = new HashMap(); // String staticMemberName => IField, List of IMethod, or IClass
11254:            private final Collection staticImportsOnDemand = new ArrayList(); // IClass
11255:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.