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