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


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