0001: // Copyright (c) 1999, 2000-2005, 2006 Per M.A. Bothner.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.expr;
0005:
0006: import gnu.bytecode.*;
0007: import gnu.mapping.*;
0008: import java.util.*;
0009: import java.io.*;
0010: import kawa.Shell;
0011: import gnu.text.*;
0012: import java.util.zip.*;
0013: import java.util.Stack;
0014:
0015: /** State for a single expression or module.
0016: * For each top-level thing (expression or file) we compile or evaluate
0017: * we create a new Compilation.
0018: */
0019:
0020: public class Compilation implements SourceLocator {
0021: /** True if the form is too complex to evaluate,and we must compile it.
0022: * This is because it contains a construct we know how to compile, but not
0023: * evaluate, and it it outside a function (which we always compile).
0024: * This can be a let scope, or primitive procedure. */
0025: public boolean mustCompile;
0026:
0027: /** Used by LambdaExp.getSelectorValue if need to allocate new selector. */
0028: int maxSelectorValue;
0029:
0030: public ClassType curClass;
0031: public ClassType mainClass;
0032: /** Generated class that extends ModuleBody. Normally same as mainClass. */
0033: public ClassType moduleClass;
0034:
0035: public LambdaExp curLambda;
0036: public ModuleExp mainLambda;
0037: public Variable this Decl;
0038:
0039: /** Contains "$instance" if the module is static; otherwise null. */
0040: Variable moduleInstanceVar;
0041:
0042: /** A code, one of the following constants, indicating how far along
0043: * we are in the parsing/compilation process.
0044: * These codes are even integers for completed stages and odd integers
0045: * for begun but not completed stages. */
0046: private int state;
0047:
0048: /** Returns a code indicating how far along
0049: * we are in the parsing/compilation process. */
0050: public int getState() {
0051: return state;
0052: }
0053:
0054: public void setState(int state) {
0055: this .state = state;
0056: }
0057:
0058: /** State code for initial pre-parse looking for module name. */
0059: public static final int PROLOG_PARSING = 1;
0060: /** We have determined the module name and class, but not finished parsing. */
0061: public static final int PROLOG_PARSED = 2;
0062: /** State code indicating the entire module has been parsed. */
0063: public static final int BODY_PARSED = 4;
0064: /** State code for lexical bindings having been resolved. */
0065: public static final int RESOLVED = 6;
0066: /** State code when various inlining and optimization passes are done. */
0067: public static final int WALKED = 8;
0068: /** State code that various compile-only data has been determined. */
0069: public static final int COMPILE_SETUP = 10;
0070: /** State code indicating the bytecode has been generated. */
0071: public static final int COMPILED = 12;
0072: /** State code indicating that bytecode has been written to its target. */
0073: public static final int CLASS_WRITTEN = 14;
0074: public static final int ERROR_SEEN = 100;
0075:
0076: public ModuleInfo minfo;
0077: public Lexer lexer;
0078:
0079: boolean pedantic;
0080:
0081: public boolean isPedantic() {
0082: return pedantic;
0083: }
0084:
0085: /** Used to access the "main" instance.
0086: * This is used for two different purposes, which may be confusing:
0087: * <ul>
0088: * <li>
0089: * If we're compiling a static module, then {@code moduleInstanceMainField}
0090: * is a field in {@code mainClass} named {@code "$instance"} that
0091: * points to the single instance of the module.</li>
0092: * <li>
0093: * If {@code moduleClass!=mainClass} (typically because we've specified
0094: * {@code module-extends}) <em>and</em> the module is non-static then
0095: * {@code moduleInstanceMainField} is a field in {@code moduleClass}
0096: * named {@code "$main"} that points back to {@code mainClass}.</li></ul>
0097: */
0098: Field moduleInstanceMainField;
0099:
0100: public java.util.Stack pendingImports;
0101:
0102: public void pushPendingImport(ModuleInfo info, ScopeExp defs) {
0103: if (pendingImports == null)
0104: pendingImports = new java.util.Stack();
0105: pendingImports.push(info);
0106: pendingImports.push(defs);
0107: Expression posExp = new ReferenceExp((Object) null);
0108: posExp.setLine(this );
0109: pendingImports.push(posExp);
0110: }
0111:
0112: /** If true, minimize the number of classes generated.
0113: * Do this even if it makes things a little slower. */
0114: public static boolean fewerClasses;
0115:
0116: /** If true, print out expressions after parsing and before optimizations. */
0117: public static boolean debugPrintExpr = false;
0118:
0119: /** If true, print out final expressions after optimizations etc. */
0120: public static boolean debugPrintFinalExpr;
0121:
0122: public static Options options = new Options();
0123: public Options currentOptions = new Options(options);
0124: static {
0125: options.add("warn-undefined-variable", Options.BOOLEAN_OPTION,
0126: "warn if no compiler-visible binding for a variable");
0127: options.add("warn-invoke-unknown-method",
0128: Options.BOOLEAN_OPTION,
0129: "warn if invoke calls an unknown method");
0130: options.add("warn-as-error", Options.BOOLEAN_OPTION,
0131: "Make all warnings into errors");
0132: }
0133:
0134: /** Get a named boolean option. */
0135: public final boolean getBooleanOption(String key,
0136: boolean defaultValue) {
0137: return currentOptions.getBoolean(key, defaultValue);
0138: }
0139:
0140: /** Get a named boolean option. */
0141: public final boolean getBooleanOption(String key) {
0142: return currentOptions.getBoolean(key);
0143: }
0144:
0145: /** The default calling convention.
0146: * One of the following CALL_WITHG_xxx values. */
0147: public static int defaultCallConvention;
0148: public static final int CALL_WITH_UNSPECIFIED = 0;
0149: /** Plain calling convention, using regular Java parameters and returns. */
0150: public static final int CALL_WITH_RETURN = 1;
0151: /** Function results are written to the current CallContext's Consumer. */
0152: public static final int CALL_WITH_CONSUMER = 2;
0153: /** Like CALL_WITH_CONSUMER, but handle full on-stack-growing tail-calls. */
0154: public static final int CALL_WITH_TAILCALLS = 3;
0155: /** Support for full continuations. Not implemented. */
0156: public static final int CALL_WITH_CONTINUATIONS = 4;
0157:
0158: public boolean usingCPStyle() {
0159: return defaultCallConvention == CALL_WITH_CONTINUATIONS;
0160: }
0161:
0162: public boolean usingTailCalls() {
0163: return defaultCallConvention >= CALL_WITH_TAILCALLS;
0164: }
0165:
0166: /** If moduleStatic > 0, (module-static #t) is implied by default.
0167: * If moduleStatic == 2, <clinit> calls run.
0168: * If moduleStatic < 0, (module-static #f) is implied by default. */
0169: public static int moduleStatic = 0;
0170:
0171: ClassType[] classes;
0172: int numClasses;
0173:
0174: /** When immediate, the ClassLoader we will load the compiled
0175: * classes from. */
0176: ArrayClassLoader loader;
0177:
0178: /** True if the compiled result will be immediately loaded. */
0179: public boolean immediate;
0180:
0181: /** The current method. */
0182: public Method method;
0183:
0184: Method clinitMethod;
0185:
0186: public final CodeAttr getCode() {
0187: return method.getCode();
0188: }
0189:
0190: int method_counter;
0191:
0192: /* When multiple procedures are compiled into a single method,
0193: we use a switch to jump to the correct part of the method. */
0194: SwitchState fswitch;
0195:
0196: Field fswitchIndex;
0197:
0198: // Various standard classes
0199: static public ClassType typeObject = Type.pointer_type;
0200: static public ClassType scmBooleanType = ClassType
0201: .make("java.lang.Boolean");
0202: static public ClassType typeString = ClassType
0203: .make("java.lang.String");
0204: static public ClassType javaStringType = typeString;
0205: static public ClassType scmKeywordType = ClassType
0206: .make("gnu.expr.Keyword");
0207: static public ClassType scmSequenceType = ClassType
0208: .make("gnu.lists.Sequence");
0209: static public ClassType javaIntegerType = ClassType
0210: .make("java.lang.Integer");
0211: static public ClassType scmListType = ClassType
0212: .make("gnu.lists.LList");
0213: static public ClassType typePair = ClassType.make("gnu.lists.Pair");
0214: static public ClassType scmPairType = typePair;
0215: public static final ArrayType objArrayType = ArrayType
0216: .make(typeObject);
0217: static public ClassType scmNamedType = ClassType
0218: .make("gnu.mapping.Named");
0219: static public ClassType typeRunnable = ClassType
0220: .make("java.lang.Runnable");
0221: public static ClassType typeType = ClassType
0222: .make("gnu.bytecode.Type");
0223: public static ClassType typeObjectType = ClassType.make(
0224: "gnu.bytecode.ObjectType", typeType);
0225: public static ClassType typeClass = Type.java_lang_Class_type;
0226: static public ClassType typeClassType = ClassType.make(
0227: "gnu.bytecode.ClassType", typeObjectType);
0228: static public ClassType typeProcedure = ClassType
0229: .make("gnu.mapping.Procedure");
0230: static public ClassType typeLanguage = ClassType
0231: .make("gnu.expr.Language");
0232: static public ClassType typeEnvironment = ClassType
0233: .make("gnu.mapping.Environment");
0234: static public ClassType typeLocation = ClassType
0235: .make("gnu.mapping.Location");
0236: static public ClassType typeSymbol = ClassType
0237: .make("gnu.mapping.Symbol");
0238: static public final Method getSymbolValueMethod = typeLanguage
0239: .getDeclaredMethod("getSymbolValue", 1);
0240: static public final Method getSymbolProcedureMethod = typeLanguage
0241: .getDeclaredMethod("getSymbolProcedure", 1);
0242: static public final Method getLocationMethod = typeLocation
0243: .addMethod("get", Type.typeArray0, Type.pointer_type,
0244: Access.PUBLIC);
0245: static public final Method getProcedureBindingMethod = typeSymbol
0246: .addMethod("getProcedure", Type.typeArray0, typeProcedure,
0247: Access.PUBLIC);
0248: static public final Field trueConstant = scmBooleanType
0249: .getDeclaredField("TRUE");
0250: static public final Field falseConstant = scmBooleanType
0251: .getDeclaredField("FALSE");
0252:
0253: static final Method setNameMethod = typeProcedure
0254: .getDeclaredMethod("setName", 1);
0255: static Method makeListMethod;
0256:
0257: public static final Type[] int1Args = { Type.int_type };
0258: public static final Type[] string1Arg = { javaStringType };
0259: public static final Type[] sym1Arg = string1Arg;
0260:
0261: static public final Method getLocation1EnvironmentMethod = typeEnvironment
0262: .getDeclaredMethod("getLocation", 1);
0263: static public final Method getLocation2EnvironmentMethod;
0264: static {
0265: Type[] args = { typeSymbol, Type.pointer_type };
0266: getLocation2EnvironmentMethod = typeEnvironment.addMethod(
0267: "getLocation", args, typeLocation, Access.PUBLIC
0268: | Access.FINAL);
0269: }
0270:
0271: static {
0272: Type[] makeListArgs = { objArrayType, Type.int_type };
0273: makeListMethod = scmListType.addMethod("makeList",
0274: makeListArgs, scmListType, Access.PUBLIC
0275: | Access.STATIC);
0276: }
0277:
0278: public static Method getCurrentEnvironmentMethod = typeEnvironment
0279: .addMethod("getCurrent", Type.typeArray0, typeEnvironment,
0280: Access.PUBLIC | Access.STATIC);
0281:
0282: public static Type[] apply0args = Type.typeArray0;
0283: public static Type[] apply1args = { typeObject };
0284: public static Type[] apply2args = { typeObject, typeObject };
0285: public static Type[] applyNargs = { objArrayType };
0286:
0287: static Method checkArgCountMethod;
0288:
0289: public static Method apply0method = typeProcedure.addMethod(
0290: "apply0", apply0args, typeObject, Access.PUBLIC
0291: | Access.FINAL);
0292:
0293: public static Method apply1method;
0294: public static Method apply2method;
0295: public static Method apply3method;
0296: public static Method apply4method;
0297: public static Method applyNmethod;
0298:
0299: static {
0300: apply1method = typeProcedure.addMethod("apply1", apply1args,
0301: typeObject, Access.PUBLIC);
0302: apply2method = typeProcedure.addMethod("apply2", apply2args,
0303: typeObject, Access.PUBLIC);
0304: Type[] apply3args = { typeObject, typeObject, typeObject };
0305: apply3method = typeProcedure.addMethod("apply3", apply3args,
0306: typeObject, Access.PUBLIC);
0307: Type[] apply4args = { typeObject, typeObject, typeObject,
0308: typeObject };
0309: apply4method = typeProcedure.addMethod("apply4", apply4args,
0310: typeObject, Access.PUBLIC);
0311: applyNmethod = typeProcedure.addMethod("applyN", applyNargs,
0312: typeObject, Access.PUBLIC);
0313: Type[] args = new Type[2];
0314: args[0] = typeProcedure;
0315: args[1] = Type.int_type;
0316: checkArgCountMethod = typeProcedure.addMethod("checkArgCount",
0317: args, Type.void_type, Access.PUBLIC | Access.STATIC);
0318: }
0319:
0320: public static Method[] applymethods = { apply0method, apply1method,
0321: apply2method, apply3method, apply4method, applyNmethod };
0322:
0323: public static ClassType typeProcedure0 = ClassType.make(
0324: "gnu.mapping.Procedure0", typeProcedure);
0325: public static ClassType typeProcedure1 = ClassType.make(
0326: "gnu.mapping.Procedure1", typeProcedure);
0327: public static ClassType typeProcedure2 = ClassType.make(
0328: "gnu.mapping.Procedure2", typeProcedure);
0329: public static ClassType typeProcedure3 = ClassType.make(
0330: "gnu.mapping.Procedure3", typeProcedure);
0331: public static ClassType typeProcedure4 = ClassType.make(
0332: "gnu.mapping.Procedure4", typeProcedure);
0333: public static ClassType typeProcedureN = ClassType.make(
0334: "gnu.mapping.ProcedureN", typeProcedure);
0335: public static ClassType typeModuleBody = ClassType.make(
0336: "gnu.expr.ModuleBody", typeProcedure0);
0337: public static ClassType typeModuleWithContext = ClassType.make(
0338: "gnu.expr.ModuleWithContext", typeModuleBody);
0339: public static ClassType typeApplet = ClassType
0340: .make("java.applet.Applet");
0341: public static ClassType typeServlet = ClassType
0342: .make("gnu.kawa.servlet.KawaServlet");
0343:
0344: /* Classes, fields, and methods used wgen usingCPStyle". */
0345: public static ClassType typeCallContext = ClassType
0346: .make("gnu.mapping.CallContext");
0347: public static final ClassType typeConsumer = ClassType
0348: .make("gnu.lists.Consumer");
0349: public static Method getCallContextInstanceMethod = typeCallContext
0350: .getDeclaredMethod("getInstance", 0);
0351: public static ClassType typeValues = ClassType
0352: .make("gnu.mapping.Values");
0353: public static Field noArgsField = typeValues
0354: .getDeclaredField("noArgs");
0355: public static Field pcCallContextField = typeCallContext
0356: .getDeclaredField("pc");
0357: public static ClassType typeMethodProc = ClassType.make(
0358: "gnu.mapping.MethodProc", typeProcedureN);
0359: public static ClassType typeModuleMethod = ClassType.make(
0360: "gnu.expr.ModuleMethod", typeMethodProc);
0361: // public static Field numArgsCallFrameField = typeCallFrame.getDeclaredField("numArgs");
0362: public static Field argsCallContextField = typeCallContext
0363: .getDeclaredField("values");
0364: public static Field procCallContextField = typeCallContext
0365: .getDeclaredField("proc");
0366: private static Type[] applyCpsArgs = { typeCallContext };
0367: public static Method applyCpsMethod = typeProcedure.addMethod(
0368: "apply", applyCpsArgs, Type.void_type, Access.PUBLIC);
0369:
0370: public static ClassType[] typeProcedureArray = { typeProcedure0,
0371: typeProcedure1, typeProcedure2, typeProcedure3,
0372: typeProcedure4 };
0373:
0374: /** Rembembers stuff to do in <clinit> of main class. */
0375: Initializer clinitChain;
0376:
0377: public static boolean generateMainDefault = false;
0378: /** True if we should generate a main(String[]) method. */
0379: public boolean generateMain = generateMainDefault;
0380:
0381: LitTable litTable;
0382:
0383: public static boolean generateAppletDefault = false;
0384: /** True if we should generate an Applet. */
0385: public boolean generateApplet = generateAppletDefault;
0386:
0387: public static boolean generateServletDefault = false;
0388: /** True if we should generate an Servlet. */
0389: public boolean generateServlet = generateServletDefault;
0390:
0391: public final ClassType getModuleType() {
0392: return (defaultCallConvention >= Compilation.CALL_WITH_CONSUMER ? typeModuleWithContext
0393: : typeModuleBody);
0394: }
0395:
0396: /** Emit code to "evaluate" a compile-time constant.
0397: * This is the normal external interface.
0398: * @param value the value to be compiled
0399: */
0400: public void compileConstant(Object value) {
0401: gnu.bytecode.CodeAttr code = getCode();
0402: if (value == null)
0403: code.emitPushNull();
0404: else if (value instanceof String && !immediate)
0405: code.emitPushString((String) value);
0406: else
0407: code.emitGetStatic(compileConstantToField(value));
0408: }
0409:
0410: public Field compileConstantToField(Object value) {
0411: Literal literal = litTable.findLiteral(value);
0412: if (literal.field == null)
0413: literal.assign(litTable);
0414: return literal.field;
0415: }
0416:
0417: public static boolean inlineOk = true;
0418:
0419: public boolean inlineOk(Expression proc) {
0420: if (proc instanceof LambdaExp) {
0421: // The compiler gets confused if we turn off inlining for nested
0422: // procedures - and they can't be rebound anyway.
0423: if (!(((LambdaExp) proc).currentLambda() instanceof ModuleExp))
0424: return true;
0425: }
0426: return inlineOk;
0427: }
0428:
0429: public boolean inlineOk(Procedure proc) {
0430: return inlineOk;
0431: }
0432:
0433: public void compileConstant(Object value, Target target) {
0434: if (target instanceof IgnoreTarget)
0435: return;
0436: if (value instanceof Values) {
0437: Object[] values = ((Values) value).getValues();
0438: int len = values.length;
0439: if (target instanceof ConsumerTarget) {
0440: for (int i = 0; i < len; i++) {
0441: compileConstant(values[i], target);
0442: }
0443: return;
0444: } else if (target instanceof SeriesTarget) {
0445: SeriesTarget starget = (SeriesTarget) target;
0446: Label saveDone = starget.done;
0447: if (len > 0) {
0448: starget.done = null;
0449: for (int i = 0; i < len; i++) {
0450: if (i + 1 == len)
0451: starget.done = saveDone;
0452: compileConstant(values[i], target);
0453: }
0454: } else if (saveDone != null
0455: && getCode().reachableHere())
0456: getCode().emitGoto(saveDone);
0457: return;
0458: }
0459: }
0460: if (target instanceof ConditionalTarget) {
0461: ConditionalTarget ctarg = (ConditionalTarget) target;
0462: getCode().emitGoto(
0463: getLanguage().isTrue(value) ? ctarg.ifTrue
0464: : ctarg.ifFalse);
0465: return;
0466: }
0467: if (target instanceof StackTarget) {
0468: Type type = ((StackTarget) target).getType();
0469: if (type instanceof PrimType) {
0470: try {
0471: String signature = type.getSignature();
0472: CodeAttr code = getCode();
0473: char sig1 = (signature == null || signature
0474: .length() != 1) ? ' ' : signature.charAt(0);
0475: if (value instanceof Number) {
0476: Number num = (Number) value;
0477: switch (sig1) {
0478: case 'I':
0479: code.emitPushInt(num.intValue());
0480: return;
0481: case 'S':
0482: code.emitPushInt(num.shortValue());
0483: return;
0484: case 'B':
0485: code.emitPushInt(num.byteValue());
0486: return;
0487: case 'J':
0488: code.emitPushLong(num.longValue());
0489: return;
0490: case 'F':
0491: code.emitPushFloat(num.floatValue());
0492: return;
0493: case 'D':
0494: code.emitPushDouble(num.doubleValue());
0495: return;
0496: }
0497: }
0498: if (sig1 == 'C') {
0499: code.emitPushInt((int) ((PrimType) type)
0500: .charValue(value));
0501: return;
0502: }
0503: if (sig1 == 'Z') {
0504: boolean val = PrimType.booleanValue(value);
0505: code.emitPushInt(val ? 1 : 0);
0506: return;
0507: }
0508: } catch (ClassCastException ex) {
0509: // should print an ERROR.
0510: }
0511: }
0512: try {
0513: value = type.coerceFromObject(value);
0514: } catch (Exception ex) {
0515: StringBuffer sbuf = new StringBuffer();
0516: if (value == Values.empty)
0517: sbuf.append("cannot convert void to ");
0518: else {
0519: sbuf.append("cannot convert literal (of type ");
0520: sbuf.append(value.getClass().getName());
0521: sbuf.append(") to ");
0522: }
0523: sbuf.append(type.getName());
0524: error('w', sbuf.toString());
0525: }
0526: }
0527: compileConstant(value);
0528: target.compileFromStack(this , value == null ? target.getType()
0529: : Type.make(value.getClass()));
0530: }
0531:
0532: private void dumpInitializers(Initializer inits) {
0533: for (Initializer init = Initializer.reverse(inits); init != null; init = init.next)
0534: init.emit(this );
0535: }
0536:
0537: /** Search this Compilation for a ClassType with a given name.
0538: * @param name the name of the class desired
0539: * @return the matching ClassType, or null if none is found */
0540: public ClassType findNamedClass(String name) {
0541: for (int i = 0; i < numClasses; i++) {
0542: if (name.equals(classes[i].getName()))
0543: return classes[i];
0544: }
0545: return null;
0546: }
0547:
0548: public static String classPrefixDefault = "";
0549: /** If non-null: a prefix for generateClassName to prepend to names. */
0550: public String classPrefix = classPrefixDefault;
0551:
0552: /** Recusive helper function to reverse order of words in hostname. */
0553: private static void putURLWords(String name, StringBuffer sbuf) {
0554: int dot = name.indexOf('.');
0555: if (dot > 0) {
0556: putURLWords(name.substring(dot + 1), sbuf);
0557: sbuf.append('.');
0558: name = name.substring(0, dot);
0559: }
0560: sbuf.append(name);
0561: }
0562:
0563: /** Map a URI to a package/class name.
0564: * Similar to the JAXB mangling, and that in the Java language spec.
0565: */
0566: public static String mangleURI(String name) {
0567: boolean hasSlash = name.indexOf('/') >= 0;
0568: int len = name.length();
0569: if (len > 6 && name.startsWith("class:"))
0570: return name.substring(6);
0571: // Remove "http:" or "urn:".
0572: if (len > 5 && name.charAt(4) == ':'
0573: && name.substring(0, 4).equalsIgnoreCase("http")) {
0574: name = name.substring(5);
0575: len -= 5;
0576: hasSlash = true;
0577: } else if (len > 4 && name.charAt(3) == ':'
0578: && name.substring(0, 3).equalsIgnoreCase("uri")) {
0579: name = name.substring(4);
0580: len -= 4;
0581: }
0582: int start = 0;
0583: StringBuffer sbuf = new StringBuffer();
0584: for (;;) {
0585: int slash = name.indexOf('/', start);
0586: int end = slash < 0 ? len : slash;
0587: boolean first = sbuf.length() == 0;
0588: if (first && hasSlash) {
0589: // Remove initial "www.".
0590: String host = name.substring(start, end);
0591: if (end - start > 4 && host.startsWith("www."))
0592: host = host.substring(4);
0593: // Reverse order of words in "host" part.
0594: putURLWords(host, sbuf);
0595: } else if (start != end) {
0596: if (!first)
0597: sbuf.append('.');
0598: if (end == len) {
0599: int dot = name.lastIndexOf('.', len);
0600: if (dot > start + 1 && !first) {
0601: // Remove file extension:
0602: int extLen = len - dot;
0603: if (extLen <= 4
0604: || (extLen == 5 && name
0605: .endsWith("html"))) {
0606: len -= extLen;
0607: end = len;
0608: name = name.substring(0, len);
0609: }
0610: }
0611: }
0612: sbuf.append(name.substring(start, end));
0613: }
0614: if (slash < 0)
0615: break;
0616: start = slash + 1;
0617: }
0618: return sbuf.toString();
0619: }
0620:
0621: public static String mangleName(String name) {
0622: return mangleName(name, -1);
0623: }
0624:
0625: public static String mangleNameIfNeeded(String name) {
0626: if (isValidJavaName(name))
0627: return name;
0628: else
0629: return mangleName(name, 0);
0630: }
0631:
0632: public static boolean isValidJavaName(String name) {
0633: int len = name.length();
0634: if (len == 0
0635: || !Character.isJavaIdentifierStart(name.charAt(0)))
0636: return false;
0637: for (int i = len; --i > 0;)
0638: if (!Character.isJavaIdentifierPart(name.charAt(i)))
0639: return false;
0640: return true;
0641: }
0642:
0643: /** Convert a string to a safe Java identifier.
0644: * @param reversible if we should use an invertible mapping.
0645: */
0646: public static String mangleName(String name, boolean reversible) {
0647: return mangleName(name, reversible ? 1 : -1);
0648: }
0649:
0650: /** Convert a string to a safe Java identifier.
0651: * @param kind -1 - non-reversible;
0652: * 0: reversible, except that '$' is not mapped;
0653: * 1: reversible
0654: */
0655: public static String mangleName(String name, int kind) {
0656: boolean reversible = kind >= 0;
0657: int len = name.length();
0658: if (len == 6 && name.equals("*init*")) // Constructor methods.
0659: return "<init>";
0660: StringBuffer mangled = new StringBuffer(len);
0661: boolean upcaseNext = false;
0662: for (int i = 0; i < len; i++) {
0663: char ch = name.charAt(i);
0664: if (upcaseNext) {
0665: ch = Character.toTitleCase(ch);
0666: upcaseNext = false;
0667: }
0668: if (Character.isDigit(ch)) {
0669: if (i == 0)
0670: mangled.append("$N");
0671: mangled.append(ch);
0672: } else if (Character.isLetter(ch) || ch == '_')
0673: mangled.append(ch);
0674: else if (ch == '$')
0675: mangled.append(kind > 1 ? "$$" : "$");
0676: else {
0677: switch (ch) {
0678: case '+':
0679: mangled.append("$Pl");
0680: break;
0681: case '-':
0682: if (reversible)
0683: mangled.append("$Mn");
0684: else {
0685: char next = i + 1 < len ? name.charAt(i + 1)
0686: : '\0';
0687: if (next == '>') {
0688: mangled.append("$To$");
0689: i++;
0690: } else if (!Character.isLowerCase(next))
0691: mangled.append("$Mn");
0692: }
0693: break;
0694: case '*':
0695: mangled.append("$St");
0696: break;
0697: case '/':
0698: mangled.append("$Sl");
0699: break;
0700: case '=':
0701: mangled.append("$Eq");
0702: break;
0703: case '<':
0704: mangled.append("$Ls");
0705: break;
0706: case '>':
0707: mangled.append("$Gr");
0708: break;
0709: case '@':
0710: mangled.append("$At");
0711: break;
0712: case '~':
0713: mangled.append("$Tl");
0714: break;
0715: case '%':
0716: mangled.append("$Pc");
0717: break;
0718: case '.':
0719: mangled.append("$Dt");
0720: break;
0721: case ',':
0722: mangled.append("$Cm");
0723: break;
0724: case '(':
0725: mangled.append("$LP");
0726: break;
0727: case ')':
0728: mangled.append("$RP");
0729: break;
0730: case '[':
0731: mangled.append("$LB");
0732: break;
0733: case ']':
0734: mangled.append("$RB");
0735: break;
0736: case '{':
0737: mangled.append("$LC");
0738: break;
0739: case '}':
0740: mangled.append("$RC");
0741: break;
0742: case '\'':
0743: mangled.append("$Sq");
0744: break;
0745: case '"':
0746: mangled.append("$Dq");
0747: break;
0748: case '&':
0749: mangled.append("$Am");
0750: break;
0751: case '#':
0752: mangled.append("$Nm");
0753: break;
0754: case '?':
0755: char first = mangled.length() > 0 ? mangled
0756: .charAt(0) : '\0';
0757: if (!reversible && i + 1 == len
0758: && Character.isLowerCase(first)) {
0759: mangled.setCharAt(0, Character
0760: .toTitleCase(first));
0761: mangled.insert(0, "is");
0762: } else
0763: mangled.append("$Qu");
0764: break;
0765: case '!':
0766: mangled.append("$Ex");
0767: break;
0768: case ':':
0769: mangled.append("$Cl");
0770: break;
0771: case ';':
0772: mangled.append("$SC");
0773: break;
0774: case '^':
0775: mangled.append("$Up");
0776: break;
0777: case '|':
0778: mangled.append("$VB");
0779: break;
0780: default:
0781: mangled.append('$');
0782: mangled.append(Character.forDigit((ch >> 12) & 15,
0783: 16));
0784: mangled.append(Character.forDigit((ch >> 8) & 15,
0785: 16));
0786: mangled.append(Character.forDigit((ch >> 4) & 15,
0787: 16));
0788: mangled.append(Character.forDigit((ch) & 15, 16));
0789: }
0790: if (!reversible)
0791: upcaseNext = true;
0792: }
0793: }
0794: String mname = mangled.toString();
0795: return mname.equals(name) ? name : mname;
0796: }
0797:
0798: /** Demangle a three-character mangling starting with '$'.
0799: * UNFINISHED!
0800: */
0801: public static char demangle2(char char1, char char2) {
0802: switch (char1 << 16 | char2) {
0803: case 'A' << 16 | 'm':
0804: return '&';
0805: case 'A' << 16 | 't':
0806: return '@';
0807: case 'C' << 16 | 'l':
0808: return ':';
0809: case 'C' << 16 | 'm':
0810: return ',';
0811: case 'D' << 16 | 'q':
0812: return '\"';
0813: case 'D' << 16 | 't':
0814: return '.';
0815: case 'E' << 16 | 'q':
0816: return '=';
0817: case 'E' << 16 | 'x':
0818: return '!';
0819: case 'G' << 16 | 'r':
0820: return '>';
0821: case 'L' << 16 | 'B':
0822: return '[';
0823: case 'L' << 16 | 'C':
0824: return '{';
0825: case 'L' << 16 | 'P':
0826: return '(';
0827: case 'L' << 16 | 's':
0828: return '<';
0829: case 'M' << 16 | 'c':
0830: return '%';
0831: case 'M' << 16 | 'n':
0832: return '-';
0833: case 'N' << 16 | 'm':
0834: return '#';
0835: case 'P' << 16 | 'c':
0836: return '%';
0837: case 'P' << 16 | 'l':
0838: return '+';
0839: case 'Q' << 16 | 'u':
0840: return '?';
0841: case 'R' << 16 | 'B':
0842: return ']';
0843: case 'R' << 16 | 'C':
0844: return '}';
0845: case 'R' << 16 | 'P':
0846: return ')';
0847: case 'S' << 16 | 'C':
0848: return ';';
0849: case 'S' << 16 | 'l':
0850: return '/';
0851: case 'S' << 16 | 'q':
0852: return '\\';
0853: case 'S' << 16 | 't':
0854: return '*';
0855: case 'T' << 16 | 'l':
0856: return '~';
0857: case 'U' << 16 | 'p':
0858: return '^';
0859: case 'V' << 16 | 'B':
0860: return '|';
0861: }
0862: return (char) (-1);
0863: }
0864:
0865: public static String demangleName(String name) {
0866: return demangleName(name, false);
0867: }
0868:
0869: public static String demangleName(String name, boolean reversible) {
0870: StringBuffer sbuf = new StringBuffer();
0871: int len = name.length();
0872: boolean mangled = false;
0873: boolean predicate = false;
0874: boolean downCaseNext = false;
0875: for (int i = 0; i < len; i++) {
0876: char ch = name.charAt(i);
0877: if (downCaseNext && !reversible) {
0878: ch = Character.toLowerCase(ch);
0879: downCaseNext = false;
0880: }
0881: char d;
0882: if (!reversible && ch == 'i' && i == 0 && len > 2
0883: && name.charAt(i + 1) == 's'
0884: && !Character.isLowerCase(d = name.charAt(i + 2))) {
0885: mangled = true;
0886: predicate = true;
0887: i++;
0888: if (Character.isUpperCase(d)
0889: || Character.isTitleCase(d)) {
0890: sbuf.append(Character.toLowerCase(d));
0891: i++;
0892: continue;
0893: }
0894: continue;
0895: } else if (ch == '$' && i + 2 < len) {
0896: char c1 = name.charAt(i + 1);
0897: char c2 = name.charAt(i + 2);
0898: d = Compilation.demangle2(c1, c2);
0899: if (d != (char) (-1)) {
0900: sbuf.append(d);
0901: i += 2;
0902: mangled = true;
0903: downCaseNext = true;
0904: continue;
0905: } else if (c1 == 'T' && c2 == 'o' && i + 3 < len
0906: && name.charAt(i + 3) == '$') {
0907: sbuf.append("->");
0908: i += 3;
0909: mangled = true;
0910: downCaseNext = true;
0911: continue;
0912: }
0913: } else if (!reversible
0914: && i > 1
0915: && (Character.isUpperCase(ch) || Character
0916: .isTitleCase(ch))
0917: && (Character.isLowerCase(name.charAt(i - 1)))) {
0918: sbuf.append('-');
0919: mangled = true;
0920: ch = Character.toLowerCase(ch);
0921: }
0922: sbuf.append(ch);
0923: }
0924: if (predicate)
0925: sbuf.append('?');
0926: return mangled ? sbuf.toString() : name;
0927: }
0928:
0929: /** Generate an unused class name.
0930: * @param hint the requested name (or prefix)
0931: * @return a unique class name.
0932: */
0933: public String generateClassName(String hint) {
0934: hint = mangleName(hint, true);
0935: if (mainClass != null)
0936: hint = mainClass.getName() + '$' + hint;
0937: else if (classPrefix != null)
0938: hint = classPrefix + hint;
0939: if (findNamedClass(hint) == null)
0940: return hint;
0941: for (int i = 0;; i++) {
0942: String new_hint = hint + i;
0943: if (findNamedClass(new_hint) == null)
0944: return new_hint;
0945: }
0946: }
0947:
0948: public Compilation(boolean immediate, SourceMessages messages) {
0949: this (messages);
0950: this .immediate = immediate;
0951: }
0952:
0953: public Compilation(SourceMessages messages) {
0954: this .messages = messages;
0955: lexical = new NameLookup(getLanguage());
0956: }
0957:
0958: public Compilation(Language language, SourceMessages messages) {
0959: this (language, messages, new NameLookup(language));
0960: }
0961:
0962: public Compilation(Language language, SourceMessages messages,
0963: NameLookup lexical) {
0964: this .language = language;
0965: this .messages = messages;
0966: this .lexical = lexical;
0967: }
0968:
0969: /** Shared processing for both compiling/eval. */
0970: public void walkModule(ModuleExp mexp) {
0971: if (debugPrintExpr) {
0972: OutPort dout = OutPort.errDefault();
0973: dout.println("[Module:" + mexp.getName());
0974: mexp.print(dout);
0975: dout.println(']');
0976: dout.flush();
0977: }
0978:
0979: InlineCalls.inlineCalls(mexp, this );
0980: PushApply.pushApply(mexp);
0981: ChainLambdas.chainLambdas(mexp, this );
0982: FindTailCalls.findTailCalls(mexp, this );
0983: }
0984:
0985: public void outputClass(String directory) throws IOException {
0986: char dirSep = File.separatorChar;
0987: for (int iClass = 0; iClass < numClasses; iClass++) {
0988: ClassType clas = classes[iClass];
0989: String out_name = (directory
0990: + clas.getName().replace('.', dirSep) + ".class");
0991: String parent = new File(out_name).getParent();
0992: if (parent != null)
0993: new File(parent).mkdirs();
0994: clas.writeToFile(out_name);
0995:
0996: clas.cleanupAfterCompilation();
0997: }
0998:
0999: minfo.comp = null;
1000: mainLambda.body = null;
1001: mainLambda = null;
1002: litTable = null;
1003: }
1004:
1005: public void compileToArchive(ModuleExp mexp, String fname)
1006: throws java.io.IOException {
1007: boolean makeJar = false;
1008: if (fname.endsWith(".zip"))
1009: makeJar = false;
1010: else if (fname.endsWith(".jar"))
1011: makeJar = true;
1012: else {
1013: fname = fname + ".zip";
1014: makeJar = false;
1015: }
1016:
1017: process(COMPILED);
1018:
1019: File zar_file = new File(fname);
1020: if (zar_file.exists())
1021: zar_file.delete();
1022: ZipOutputStream zout;
1023: /* #ifdef JAVA2 */
1024: if (makeJar)
1025: zout = new java.util.jar.JarOutputStream(
1026: new FileOutputStream(zar_file));
1027: else
1028: /* #endif */
1029: {
1030: zout = new ZipOutputStream(new FileOutputStream(zar_file));
1031: zout.setMethod(ZipOutputStream.STORED); // no compression
1032: }
1033:
1034: byte[][] classBytes = new byte[numClasses][];
1035: CRC32 zcrc = new CRC32();
1036: for (int iClass = 0; iClass < numClasses; iClass++) {
1037: ClassType clas = classes[iClass];
1038: classBytes[iClass] = clas.writeToArray();
1039: ZipEntry zent = new ZipEntry(clas.getName().replace('.',
1040: '/')
1041: + ".class");
1042:
1043: zent.setSize(classBytes[iClass].length);
1044: zcrc.reset();
1045: zcrc.update(classBytes[iClass], 0,
1046: classBytes[iClass].length);
1047: zent.setCrc(zcrc.getValue());
1048:
1049: zout.putNextEntry(zent);
1050: zout.write(classBytes[iClass]);
1051: }
1052: zout.close();
1053: }
1054:
1055: // FIXME - make this settable, as it does make .class files bigger.
1056: public static boolean emitSourceDebugExtAttr = true;
1057:
1058: private void registerClass(ClassType new_class) {
1059: if (classes == null)
1060: classes = new ClassType[20];
1061: else if (numClasses >= classes.length) {
1062: ClassType[] new_classes = new ClassType[2 * classes.length];
1063: System.arraycopy(classes, 0, new_classes, 0, numClasses);
1064: classes = new_classes;
1065: }
1066: new_class.access_flags |= new_class.isInterface() ? Access.PUBLIC
1067: : Access.PUBLIC | Access.SUPER;
1068: if (new_class == mainClass && numClasses > 0) {
1069: // Ensure mainClass is written first when writing an archive.
1070: new_class = classes[0];
1071: classes[0] = mainClass;
1072: }
1073: classes[numClasses++] = new_class;
1074: }
1075:
1076: public void addClass(ClassType new_class) {
1077: if (mainLambda.filename != null) {
1078: if (emitSourceDebugExtAttr)
1079: new_class.setStratum(getLanguage().getName());
1080: new_class.setSourceFile(mainLambda.filename);
1081: }
1082: registerClass(new_class);
1083: /* #ifdef JAVA5 */
1084: // new_class.setClassfileVersionJava5();
1085: /* #endif */
1086: }
1087:
1088: public void addMainClass(ModuleExp module) {
1089: mustCompile = true;
1090:
1091: mainClass = module.classFor(this );
1092:
1093: ClassType type = mainClass;
1094: ClassType[] interfaces = module.getInterfaces();
1095: if (interfaces != null)
1096: type.setInterfaces(interfaces);
1097: ClassType sup = module.getSuperType();
1098: if (sup == null) {
1099: if (generateApplet)
1100: sup = typeApplet;
1101: else if (generateServlet)
1102: sup = typeServlet;
1103: else
1104: sup = getModuleType();
1105: }
1106: if (!generateServlet)
1107: type.addInterface(typeRunnable);
1108: type.setSuper(sup);
1109:
1110: module.type = type;
1111: addClass(type);
1112: getConstructor(mainClass, module);
1113: }
1114:
1115: public final Method getConstructor(LambdaExp lexp) {
1116: return getConstructor(lexp.getHeapFrameType(), lexp);
1117: }
1118:
1119: public static final Method getConstructor(ClassType clas,
1120: LambdaExp lexp) {
1121: Method meth = clas.getDeclaredMethod("<init>", 0);
1122: if (meth != null)
1123: return meth;
1124: Type[] args;
1125: if (lexp instanceof ClassExp && lexp.staticLinkField != null) {
1126: args = new Type[1];
1127: args[0] = lexp.staticLinkField.getType();
1128: } else
1129: args = apply0args;
1130: return clas.addMethod("<init>", Access.PUBLIC, args,
1131: Type.void_type);
1132: }
1133:
1134: public final void generateConstructor(LambdaExp lexp) {
1135: generateConstructor(lexp.getHeapFrameType(), lexp);
1136: }
1137:
1138: public final void generateConstructor(ClassType clas, LambdaExp lexp) {
1139: Method save_method = method;
1140: Variable callContextSave = callContextVar;
1141: callContextVar = null;
1142: ClassType save_class = curClass;
1143: curClass = clas;
1144: Method constructor_method = getConstructor(clas, lexp);
1145: clas.constructor = constructor_method;
1146: method = constructor_method;
1147: CodeAttr code = constructor_method.startCode();
1148:
1149: if (lexp instanceof ClassExp && lexp.staticLinkField != null) {
1150: code.emitPushThis();
1151: code.emitLoad(code.getCurrentScope().getVariable(1));
1152: code.emitPutField(lexp.staticLinkField);
1153: }
1154: Method super Constructor = clas.getSuperclass().addMethod(
1155: "<init>", Access.PUBLIC, apply0args, Type.void_type);
1156: code.emitPushThis();
1157: code.emitInvokeSpecial(super Constructor);
1158:
1159: if (curClass == mainClass
1160: // Optimization: No pointing in calling register if we aren't
1161: // compiling a named module.
1162: && minfo != null && minfo.sourcePath != null) {
1163: code.emitPushThis();
1164: code.emitInvokeStatic(ClassType.make("gnu.expr.ModuleInfo")
1165: .getDeclaredMethod("register", 1));
1166: }
1167:
1168: if (lexp.initChain != null) {
1169: // Create dummy lambda, for its closureEnv. This may be needed
1170: // if init.value contains a reference that uses our heap frame.
1171: LambdaExp save = curLambda;
1172: curLambda = new LambdaExp();
1173: curLambda.closureEnv = code.getArg(0);
1174: curLambda.outer = save;
1175: Initializer init;
1176: while ((init = lexp.initChain) != null) {
1177: lexp.initChain = null;
1178: dumpInitializers(init);
1179: }
1180: curLambda = save;
1181: }
1182:
1183: if (lexp instanceof ClassExp) {
1184: ClassExp cexp = (ClassExp) lexp;
1185: callInitMethods(cexp.getCompiledClassType(this ),
1186: new Vector(10));
1187: }
1188:
1189: code.emitReturn();
1190: method = save_method;
1191: curClass = save_class;
1192: callContextVar = callContextSave;
1193: }
1194:
1195: /** In an <init> for a generated ClassExp, emit $finit$ calls.
1196: * This recursively traverses superclasses, and also calls their $finit$.
1197: * @param clas Class to search for $finit$, and to search supertypes.
1198: * @param seen array of seen classes, to avoid duplicate $finit$ calls.
1199: */
1200: void callInitMethods(ClassType clas, Vector seen) {
1201: if (clas == null)
1202: return;
1203:
1204: String name = clas.getName();
1205: if ("java.lang.Object".equals(name))
1206: return;
1207: // Check for duplicates.
1208: for (int i = seen.size(); --i >= 0;)
1209: if (((ClassType) seen.elementAt(i)).getName() == name)
1210: return;
1211: seen.addElement(clas);
1212:
1213: // Recusive call to emit $finit$ of super-types. However, don't do that
1214: // for clas.getSuperclass(), because our <init> will automatically call
1215: // the super-class's <init>, which will call its $finit$.
1216: ClassType[] interfaces = clas.getInterfaces();
1217: if (interfaces != null) {
1218: int n = interfaces.length;
1219: for (int i = 0; i < n; i++)
1220: callInitMethods(interfaces[i], seen);
1221: }
1222:
1223: int clEnvArgs = 1;
1224: if (clas instanceof PairClassType)
1225: clas = ((PairClassType) clas).instanceType;
1226: else if (clas.isInterface()) {
1227: try {
1228: clas = ((ClassType) Type.make(Class.forName(clas
1229: .getName()
1230: + "$class")));
1231: } catch (Throwable ex) {
1232: return;
1233: }
1234: } else
1235: clEnvArgs = 0;
1236: Method meth = clas.getDeclaredMethod("$finit$", clEnvArgs);
1237: if (meth != null) {
1238: CodeAttr code = getCode();
1239: code.emitPushThis();
1240: code.emitInvoke(meth);
1241: }
1242: }
1243:
1244: public void generateMatchMethods(LambdaExp lexp) {
1245: int numApplyMethods = lexp.applyMethods == null ? 0
1246: : lexp.applyMethods.size();
1247: if (numApplyMethods == 0)
1248: return;
1249: Method save_method = method;
1250: ClassType save_class = curClass;
1251: ClassType procType = typeModuleMethod;
1252: curClass = lexp.getHeapFrameType();
1253: if (!(curClass.getSuperclass().isSubtype(typeModuleBody)))
1254: curClass = moduleClass;
1255: CodeAttr code = null;
1256: for (int i = 0; i <= 5; i++) {
1257: boolean needThisMatch = false;
1258: SwitchState aswitch = null;
1259: String mname = null;
1260: Type[] matchArgs = null;
1261: for (int j = numApplyMethods; --j >= 0;) {
1262: LambdaExp source = (LambdaExp) lexp.applyMethods
1263: .elementAt(j);
1264: // Select the subset of source.primMethods[*] that are suitable
1265: // for the current apply method.
1266: Method[] primMethods = source.primMethods;
1267: int numMethods = primMethods.length;
1268: boolean varArgs = source.max_args < 0
1269: || source.max_args >= source.min_args
1270: + numMethods;
1271: int methodIndex;
1272: if (i < 5) // Handling match0 .. match4
1273: {
1274: methodIndex = i - source.min_args;
1275: if (methodIndex < 0
1276: || methodIndex >= numMethods
1277: || (methodIndex == numMethods - 1 && varArgs))
1278: continue;
1279: numMethods = 1;
1280: varArgs = false;
1281: } else // Handling matchN
1282: {
1283: methodIndex = 5 - source.min_args;
1284: if (methodIndex > 0 && numMethods <= methodIndex
1285: && !varArgs)
1286: continue;
1287: methodIndex = numMethods - 1;
1288: }
1289: if (!needThisMatch) {
1290: // First LambdaExp we seen suitable for this i.
1291: if (i < 5) {
1292: mname = "match" + i;
1293: matchArgs = new Type[i + 2];
1294: for (int k = i; k >= 0; k--)
1295: matchArgs[k + 1] = typeObject;
1296: matchArgs[i + 1] = typeCallContext;
1297: } else {
1298: mname = "matchN";
1299: matchArgs = new Type[3];
1300: matchArgs[1] = objArrayType;
1301: matchArgs[2] = typeCallContext;
1302: }
1303: matchArgs[0] = procType;
1304: method = curClass.addMethod(mname, matchArgs,
1305: Type.int_type, Access.PUBLIC);
1306: code = method.startCode();
1307:
1308: code.emitLoad(code.getArg(1)); // method
1309: code.emitGetField(procType.getField("selector"));
1310: aswitch = new SwitchState(code);
1311:
1312: needThisMatch = true;
1313: }
1314:
1315: aswitch.addCase(source.getSelectorValue(this ), code);
1316:
1317: int line = source.getLineNumber();
1318: if (line > 0)
1319: code.putLineNumber(source.getFileName(), line);
1320:
1321: Variable ctxVar = code.getArg(i == 5 ? 3 : i + 2);
1322:
1323: if (i < 5) {
1324: Declaration var = source.firstDecl();
1325: for (int k = 1; k <= i; k++) {
1326: code.emitLoad(ctxVar);
1327: code.emitLoad(code.getArg(k + 1));
1328: Type ptype = var.getType();
1329: if (ptype != Type.pointer_type) {
1330: if (ptype instanceof TypeValue) {
1331: Label trueLabel = new Label(code), falseLabel = new Label(
1332: code);
1333: ConditionalTarget ctarget = new ConditionalTarget(
1334: trueLabel, falseLabel,
1335: getLanguage());
1336: code.emitDup();
1337: ((TypeValue) ptype).emitIsInstance(
1338: null, this , ctarget);
1339: falseLabel.define(code);
1340: code
1341: .emitPushInt(MethodProc.NO_MATCH_BAD_TYPE
1342: | k);
1343: code.emitReturn();
1344: trueLabel.define(code);
1345: } else if (ptype instanceof ClassType
1346: && ptype != Type.pointer_type
1347: && ptype != Type.tostring_type) // FIXME
1348: {
1349: code.emitDup();
1350: ptype.emitIsInstance(code);
1351: code.emitIfIntEqZero();
1352: code
1353: .emitPushInt(MethodProc.NO_MATCH_BAD_TYPE
1354: | k);
1355: code.emitReturn();
1356: code.emitFi();
1357: }
1358: }
1359: code.emitPutField(typeCallContext
1360: .getField("value" + k));
1361: var = var.nextDecl();
1362: }
1363: } else {
1364: // FIXME - need to check
1365: code.emitLoad(ctxVar);
1366: code.emitLoad(code.getArg(2));
1367: code.emitPutField(typeCallContext
1368: .getField("values"));
1369: }
1370: code.emitLoad(ctxVar);
1371: if (defaultCallConvention < Compilation.CALL_WITH_CONSUMER)
1372: code.emitLoad(code.getArg(1)); // proc
1373: else
1374: code.emitLoad(code.getArg(0)); // this (module)
1375: code.emitPutField(procCallContextField);
1376: code.emitLoad(ctxVar);
1377: if (defaultCallConvention >= CALL_WITH_CONSUMER)
1378: code.emitPushInt(source.getSelectorValue(this )
1379: + methodIndex);
1380: else
1381: code.emitPushInt(i);
1382: code.emitPutField(pcCallContextField);
1383: code.emitPushInt(0);
1384: code.emitReturn();
1385: }
1386: if (needThisMatch) {
1387: aswitch.addDefault(code);
1388: int nargs = i > 4 ? 2 : i + 1;
1389: nargs++;
1390: for (int k = 0; k <= nargs; k++)
1391: code.emitLoad(code.getArg(k));
1392: Method defMethod = (typeModuleBody.getDeclaredMethod(
1393: mname, matchArgs.length));
1394: code.emitInvokeSpecial(defMethod);
1395: code.emitReturn();
1396: aswitch.finish(code);
1397: }
1398: }
1399: method = save_method;
1400: curClass = save_class;
1401: }
1402:
1403: /** Generate ModuleBody's <tt>apply(CallContext)</tt> method
1404: * Use the <tt>applyMethods</tt> vector, which contains methods that
1405: * implement the (public, readable) methods of the current module. */
1406: public void generateApplyMethodsWithContext(LambdaExp lexp) {
1407: int numApplyMethods = lexp.applyMethods == null ? 0
1408: : lexp.applyMethods.size();
1409: if (numApplyMethods == 0)
1410: return;
1411: ClassType save_class = curClass;
1412: curClass = lexp.getHeapFrameType();
1413: if (!(curClass.getSuperclass().isSubtype(typeModuleWithContext)))
1414: curClass = moduleClass;
1415: ClassType procType = typeModuleMethod;
1416: Method save_method = method;
1417: CodeAttr code = null;
1418: Type[] applyArgs = { typeCallContext };
1419:
1420: // First LambdaExp we seen suitable for this i.
1421: method = curClass.addMethod("apply", applyArgs,
1422: (Type) Type.void_type, Access.PUBLIC);
1423: code = method.startCode();
1424: Variable ctxVar = code.getArg(1);
1425:
1426: code.emitLoad(ctxVar);
1427: code.emitGetField(pcCallContextField);
1428: SwitchState aswitch = new SwitchState(code);
1429:
1430: for (int j = 0; j < numApplyMethods; ++j) {
1431: LambdaExp source = (LambdaExp) lexp.applyMethods
1432: .elementAt(j);
1433: Method[] primMethods = source.primMethods;
1434: int numMethods = primMethods.length;
1435:
1436: for (int i = 0; i < numMethods; i++) {
1437: // Select the subset of source.primMethods[*] that are suitable
1438: // for the current apply method.
1439: boolean varArgs = (i == numMethods - 1 && (source.max_args < 0 || source.max_args >= source.min_args
1440: + numMethods));
1441: int methodIndex = i;
1442:
1443: aswitch
1444: .addCase(source.getSelectorValue(this ) + i,
1445: code);
1446:
1447: int line = source.getLineNumber();
1448: if (line > 0)
1449: code.putLineNumber(source.getFileName(), line);
1450:
1451: Method primMethod = primMethods[methodIndex];
1452: Type[] primArgTypes = primMethod.getParameterTypes();
1453: int singleArgs = source.min_args + methodIndex;
1454: Variable counter = null;
1455: int pendingIfEnds = 0;
1456:
1457: if (i > 4 && numMethods > 1) // FIXME
1458: {
1459: counter = code.addLocal(Type.int_type);
1460: code.emitLoad(ctxVar);
1461: code.emitGetField(typeCallContext
1462: .getDeclaredField("count"));
1463: if (source.min_args != 0) {
1464: code.emitPushInt(source.min_args);
1465: code.emitSub(Type.int_type);
1466: }
1467: code.emitStore(counter);
1468: }
1469:
1470: int needsThis = primMethod.getStaticFlag() ? 0 : 1;
1471: int explicitFrameArg = singleArgs + (varArgs ? 2 : 1) < primArgTypes.length ? 1
1472: : 0;
1473: if (needsThis + explicitFrameArg > 0) {
1474: code.emitPushThis();
1475: if (curClass == moduleClass
1476: && mainClass != moduleClass)
1477: code.emitGetField(moduleInstanceMainField);
1478: }
1479:
1480: Declaration var = source.firstDecl();
1481: for (int k = 0; k < singleArgs; k++) {
1482: if (counter != null && k >= source.min_args) {
1483: code.emitLoad(counter);
1484: code.emitIfIntLEqZero();
1485: code.emitLoad(ctxVar);
1486: code
1487: .emitInvoke(primMethods[k
1488: - source.min_args]);
1489: code.emitElse();
1490: pendingIfEnds++;
1491: code.emitInc(counter, (short) (-1));
1492: }
1493:
1494: code.emitLoad(ctxVar);
1495: if (k <= 4 && !varArgs && source.max_args <= 4)
1496: code.emitGetField(typeCallContext
1497: .getDeclaredField("value" + (k + 1)));
1498: else {
1499: code.emitGetField(typeCallContext
1500: .getDeclaredField("values"));
1501: code.emitPushInt(k);
1502: code.emitArrayLoad(Type.pointer_type);
1503: }
1504: Type ptype = var.getType();
1505: if (ptype != Type.pointer_type)
1506: CheckedTarget.emitCheckedCoerce(this , source,
1507: k + 1, ptype);
1508: var = var.nextDecl();
1509: }
1510:
1511: if (varArgs) {
1512: Type lastArgType = primArgTypes[explicitFrameArg
1513: + singleArgs];
1514: if (lastArgType instanceof ArrayType) {
1515: Type elType = ((ArrayType) lastArgType)
1516: .getComponentType();
1517: boolean mustConvert = !"java.lang.Object"
1518: .equals(elType.getName());
1519: if (mustConvert)
1520: new Error(
1521: "not implemented mustConvert restarg");
1522: code.emitLoad(ctxVar);
1523: code.emitPushInt(singleArgs);
1524: code.emitInvokeVirtual(typeCallContext
1525: .getDeclaredMethod("getRestArgsArray",
1526: 1));
1527: } else if ("gnu.lists.LList".equals(lastArgType
1528: .getName())) {
1529: code.emitLoad(ctxVar);
1530: code.emitPushInt(singleArgs);
1531: code
1532: .emitInvokeVirtual(typeCallContext
1533: .getDeclaredMethod(
1534: "getRestArgsList", 1));
1535: } else if (lastArgType == typeCallContext)
1536: code.emitLoad(ctxVar);
1537: else
1538: throw new RuntimeException(
1539: "unsupported #!rest type:"
1540: + lastArgType);
1541: }
1542: code.emitLoad(ctxVar); // get $ctx
1543: code.emitInvoke(primMethod);
1544: while (--pendingIfEnds >= 0)
1545: code.emitFi();
1546: if (defaultCallConvention < Compilation.CALL_WITH_CONSUMER)
1547: Target.pushObject.compileFromStack(this , source
1548: .getReturnType());
1549: code.emitReturn();
1550: }
1551: }
1552: aswitch.addDefault(code);
1553: Method errMethod = typeModuleMethod.getDeclaredMethod(
1554: "applyError", 0);
1555: code.emitInvokeStatic(errMethod);
1556: code.emitReturn();
1557: aswitch.finish(code);
1558: method = save_method;
1559: curClass = save_class;
1560: }
1561:
1562: /** Generate ModuleBody's <tt>apply0</tt>...<tt>applyN</tt> methods.
1563: * Use the <tt>applyMethods</tt> vector, which contains methods that
1564: * implement the (public, readable) methods of the current module.
1565: */
1566: public void generateApplyMethodsWithoutContext(LambdaExp lexp) {
1567: int numApplyMethods = lexp.applyMethods == null ? 0
1568: : lexp.applyMethods.size();
1569: if (numApplyMethods == 0)
1570: return;
1571: ClassType save_class = curClass;
1572: curClass = lexp.getHeapFrameType();
1573: ClassType procType = typeModuleMethod;
1574: if (!(curClass.getSuperclass().isSubtype(typeModuleBody)))
1575: curClass = moduleClass;
1576: Method save_method = method;
1577: CodeAttr code = null;
1578: for (int i = defaultCallConvention >= Compilation.CALL_WITH_CONSUMER ? 5
1579: : 0; i < 6; i++) {
1580: // If i < 5, generate the method named ("apply"+i);
1581: // else generate "applyN".
1582: boolean needThisApply = false;
1583: SwitchState aswitch = null;
1584: String mname = null;
1585: Type[] applyArgs = null;
1586:
1587: for (int j = numApplyMethods; --j >= 0;) {
1588: LambdaExp source = (LambdaExp) lexp.applyMethods
1589: .elementAt(j);
1590: // Select the subset of source.primMethods[*] that are suitable
1591: // for the current apply method.
1592: Method[] primMethods = source.primMethods;
1593: int numMethods = primMethods.length;
1594: boolean varArgs = source.max_args < 0
1595: || source.max_args >= source.min_args
1596: + numMethods;
1597: int methodIndex;
1598: boolean skipThisProc = false;
1599: if (i < 5) // Handling apply0 .. apply4
1600: {
1601: methodIndex = i - source.min_args;
1602: if (methodIndex < 0
1603: || methodIndex >= numMethods
1604: || (methodIndex == numMethods - 1 && varArgs))
1605: skipThisProc = true;
1606: numMethods = 1;
1607: varArgs = false;
1608: } else // Handling applyN
1609: {
1610: methodIndex = 5 - source.min_args;
1611: if (methodIndex > 0 && numMethods <= methodIndex
1612: && !varArgs)
1613: skipThisProc = true;
1614: methodIndex = numMethods - 1;
1615: }
1616: if (skipThisProc)
1617: continue;
1618: if (!needThisApply) {
1619: // First LambdaExp we seen suitable for this i.
1620: if (i < 5) {
1621: mname = "apply" + i;
1622: applyArgs = new Type[i + 1];
1623: for (int k = i; k > 0; k--)
1624: applyArgs[k] = typeObject;
1625: } else {
1626: mname = "applyN";
1627: applyArgs = new Type[2];
1628: applyArgs[1] = objArrayType;
1629: }
1630: applyArgs[0] = procType;
1631: method = curClass
1632: .addMethod(
1633: mname,
1634: applyArgs,
1635: defaultCallConvention >= Compilation.CALL_WITH_CONSUMER ? (Type) Type.void_type
1636: : (Type) Type.pointer_type,
1637: Access.PUBLIC);
1638: code = method.startCode();
1639:
1640: code.emitLoad(code.getArg(1)); // method
1641: code.emitGetField(procType.getField("selector"));
1642: aswitch = new SwitchState(code);
1643:
1644: needThisApply = true;
1645: }
1646:
1647: aswitch.addCase(source.getSelectorValue(this ), code);
1648:
1649: int line = source.getLineNumber();
1650: if (line > 0)
1651: code.putLineNumber(source.getFileName(), line);
1652:
1653: Method primMethod = primMethods[methodIndex];
1654: Type[] primArgTypes = primMethod.getParameterTypes();
1655: int singleArgs = source.min_args + methodIndex;
1656: Variable counter = null;
1657: int pendingIfEnds = 0;
1658:
1659: if (i > 4 && numMethods > 1) {
1660: counter = code.addLocal(Type.int_type);
1661: code.emitLoad(code.getArg(2));
1662: code.emitArrayLength();
1663: if (source.min_args != 0) {
1664: code.emitPushInt(source.min_args);
1665: code.emitSub(Type.int_type);
1666: }
1667: code.emitStore(counter);
1668: }
1669:
1670: int needsThis = primMethod.getStaticFlag() ? 0 : 1;
1671: int explicitFrameArg = singleArgs + (varArgs ? 1 : 0) < primArgTypes.length ? 1
1672: : 0;
1673: if (needsThis + explicitFrameArg > 0) {
1674: code.emitPushThis();
1675: if (curClass == moduleClass
1676: && mainClass != moduleClass)
1677: code.emitGetField(moduleInstanceMainField);
1678: }
1679:
1680: Declaration var = source.firstDecl();
1681: for (int k = 0; k < singleArgs; k++) {
1682: if (counter != null && k >= source.min_args) {
1683: code.emitLoad(counter);
1684: code.emitIfIntLEqZero();
1685: code
1686: .emitInvoke(primMethods[k
1687: - source.min_args]);
1688: code.emitElse();
1689: pendingIfEnds++;
1690: code.emitInc(counter, (short) (-1));
1691: }
1692:
1693: Variable pvar = null;
1694: if (i <= 4) // apply'i method
1695: {
1696: pvar = code.getArg(k + 2);
1697: code.emitLoad(pvar);
1698: } else // applyN method
1699: {
1700: // Load Object[]args value:
1701: code.emitLoad(code.getArg(2));
1702: code.emitPushInt(k);
1703: code.emitArrayLoad(Type.pointer_type);
1704: }
1705: Type ptype = var.getType();
1706: if (ptype != Type.pointer_type)
1707: CheckedTarget.emitCheckedCoerce(this , source,
1708: k + 1, ptype, pvar);
1709: var = var.nextDecl();
1710: }
1711:
1712: if (varArgs) {
1713: Type lastArgType = primArgTypes[explicitFrameArg
1714: + singleArgs];
1715: if (lastArgType instanceof ArrayType) {
1716: Type elType = ((ArrayType) lastArgType)
1717: .getComponentType();
1718: boolean mustConvert = !"java.lang.Object"
1719: .equals(elType.getName());
1720: if (singleArgs == 0 && !mustConvert)
1721: code.emitLoad(code.getArg(2)); // load args array.
1722: else {
1723: code.pushScope();
1724: if (counter == null) {
1725: counter = code.addLocal(Type.int_type);
1726: code.emitLoad(code.getArg(2));
1727: code.emitArrayLength();
1728: if (singleArgs != 0) {
1729: code.emitPushInt(singleArgs);
1730: code.emitSub(Type.int_type);
1731: }
1732: code.emitStore(counter);
1733: }
1734: code.emitLoad(counter);
1735: code.emitNewArray(elType);
1736: Label testLabel = new Label(code);
1737: code.emitGoto(testLabel);
1738: Label loopTopLabel = new Label(code);
1739: loopTopLabel.define(code);
1740:
1741: code.emitDup(1); // new array
1742: code.emitLoad(counter);
1743: code.emitLoad(code.getArg(2));
1744: code.emitLoad(counter);
1745: if (singleArgs != 0) {
1746: code.emitPushInt(singleArgs);
1747: code.emitAdd(Type.int_type);
1748: }
1749: code.emitArrayLoad(Type.pointer_type);
1750: if (mustConvert) {
1751: CheckedTarget.emitCheckedCoerce(this ,
1752: source, source.getName(), 0,
1753: elType, null);
1754: }
1755: code.emitArrayStore(elType);
1756: testLabel.define(code);
1757: code.emitInc(counter, (short) (-1));
1758: code.emitLoad(counter);
1759: code.emitGotoIfIntGeZero(loopTopLabel);
1760: code.popScope();
1761: }
1762: } else if ("gnu.lists.LList".equals(lastArgType
1763: .getName())) {
1764: code.emitLoad(code.getArg(2)); // load args array.
1765: code.emitPushInt(singleArgs);
1766: code
1767: .emitInvokeStatic(Compilation.makeListMethod);
1768: } else if (lastArgType == typeCallContext)
1769: code.emitLoad(code.getArg(2));
1770: else
1771: throw new RuntimeException(
1772: "unsupported #!rest type:"
1773: + lastArgType);
1774: }
1775: code.emitInvoke(primMethod);
1776: while (--pendingIfEnds >= 0)
1777: code.emitFi();
1778: if (defaultCallConvention < Compilation.CALL_WITH_CONSUMER)
1779: Target.pushObject.compileFromStack(this , source
1780: .getReturnType());
1781: code.emitReturn();
1782: }
1783: if (needThisApply) {
1784: aswitch.addDefault(code);
1785: if (defaultCallConvention >= Compilation.CALL_WITH_CONSUMER) {
1786: Method errMethod = typeModuleMethod
1787: .getDeclaredMethod("applyError", 0);
1788: code.emitInvokeStatic(errMethod);
1789: } else {
1790: int nargs = i > 4 ? 2 : i + 1;
1791: nargs++;
1792: for (int k = 0; k < nargs; k++)
1793: code.emitLoad(code.getArg(k));
1794: code.emitInvokeSpecial(typeModuleBody
1795: .getDeclaredMethod(mname, applyArgs));
1796: }
1797: code.emitReturn();
1798: aswitch.finish(code);
1799: }
1800: }
1801: method = save_method;
1802: curClass = save_class;
1803: }
1804:
1805: private Method startClassInit() {
1806: method = curClass.addMethod("<clinit>", apply0args,
1807: Type.void_type, Access.PUBLIC | Access.STATIC);
1808:
1809: CodeAttr code = method.startCode();
1810:
1811: if (generateMain || generateApplet || generateServlet) {
1812: ClassType languageType = (ClassType) Type
1813: .make(getLanguage().getClass());
1814: Method registerMethod = languageType.getDeclaredMethod(
1815: "registerEnvironment", 0);
1816: if (registerMethod != null)
1817: code.emitInvokeStatic(registerMethod);
1818: }
1819: return method;
1820: }
1821:
1822: /** Parse/walk/compile this module as needed and requested.
1823: * This method does not process any dependent modules (expect indirectly,
1824: * such as may be done by a require form).
1825: * @param wantedState the desired value of getState().
1826: */
1827: public void process(int wantedState) {
1828: Compilation saveCompilation = Compilation.getCurrent();
1829: try {
1830: Compilation.setCurrent(this );
1831: ModuleExp mexp = getModule();
1832: if (wantedState >= BODY_PARSED
1833: && getState() < BODY_PARSED - 1) {
1834: setState(BODY_PARSED - 1);
1835: language.parse(this , 0);
1836: lexer.close();
1837: lexer = null;
1838: setState(messages.seenErrors() ? ERROR_SEEN
1839: : BODY_PARSED);
1840: if (pendingImports != null)
1841: return;
1842: }
1843: if (wantedState >= RESOLVED && getState() < RESOLVED) {
1844: addMainClass(mexp);
1845: language.resolve(this );
1846: setState(messages.seenErrors() ? ERROR_SEEN : RESOLVED);
1847: }
1848: if (wantedState >= WALKED && getState() < WALKED) {
1849: walkModule(mexp);
1850: setState(messages.seenErrors() ? ERROR_SEEN : WALKED);
1851: }
1852: if (wantedState >= COMPILE_SETUP
1853: && getState() < COMPILE_SETUP) {
1854: litTable = new LitTable(this );
1855: mexp.setCanRead(true);
1856: FindCapturedVars.findCapturedVars(mexp, this );
1857: mexp.allocFields(this );
1858: mexp.allocChildMethods(this );
1859: setState(messages.seenErrors() ? ERROR_SEEN
1860: : COMPILE_SETUP);
1861: }
1862: if (wantedState >= COMPILED && getState() < COMPILED) {
1863: generateBytecode();
1864: setState(messages.seenErrors() ? ERROR_SEEN : COMPILED);
1865: }
1866: if (wantedState >= CLASS_WRITTEN
1867: && getState() < CLASS_WRITTEN) {
1868: ModuleManager manager = ModuleManager.getInstance();
1869: outputClass(manager.getCompilationDirectory());
1870: setState(CLASS_WRITTEN);
1871: }
1872: } catch (gnu.text.SyntaxException ex) {
1873: setState(ERROR_SEEN);
1874: if (ex.getMessages() != getMessages())
1875: throw new RuntimeException("confussing syntax error: "
1876: + ex);
1877: // otherwise ignore it - it's already been recorded in messages.
1878: } catch (java.io.IOException ex) {
1879: ex.printStackTrace();
1880: error('f', "caught " + ex);
1881: setState(ERROR_SEEN);
1882: } finally {
1883: Compilation.setCurrent(saveCompilation);
1884: }
1885: }
1886:
1887: /** The guts of compiling a module to one or more classes.
1888: * Assumes walkModule has been done.
1889: */
1890: void generateBytecode() {
1891: ModuleExp module = getModule();
1892: if (debugPrintFinalExpr) {
1893: OutPort dout = OutPort.errDefault();
1894: dout.println("[Compiling final " + module.getName()
1895: + " to " + mainClass.getName() + ":");
1896: module.print(dout);
1897: dout.println(']');
1898: dout.flush();
1899: }
1900:
1901: ClassType neededSuper = getModuleType();
1902: if (mainClass.getSuperclass().isSubtype(neededSuper))
1903: moduleClass = mainClass;
1904: else {
1905: moduleClass = new ClassType(generateClassName("frame"));
1906: moduleClass.setSuper(neededSuper);
1907: addClass(moduleClass);
1908: generateConstructor(moduleClass, module);
1909: }
1910:
1911: curClass = module.type;
1912: int arg_count;
1913: LambdaExp saveLambda = curLambda;
1914: curLambda = module;
1915: Type[] arg_types;
1916: if (module.isHandlingTailCalls()) {
1917: arg_count = 1;
1918: arg_types = new Type[1];
1919: arg_types[0] = typeCallContext;
1920: } else if (module.min_args != module.max_args
1921: || module.min_args > 4
1922: || (fewerClasses && curClass == mainClass)) {
1923: arg_count = 1;
1924: arg_types = new Type[1];
1925: arg_types[0] = new ArrayType(typeObject);
1926: } else {
1927: arg_count = module.min_args;
1928: arg_types = new Type[arg_count];
1929: for (int i = arg_count; --i >= 0;)
1930: arg_types[i] = typeObject;
1931: }
1932:
1933: CodeAttr code;
1934: Variable heapFrame = module.heapFrame;
1935: boolean staticModule = module.isStatic();
1936: Method apply_method;
1937:
1938: apply_method = curClass.addMethod("run", arg_types,
1939: Type.void_type, Access.PUBLIC + Access.FINAL);
1940: method = apply_method;
1941: // For each parameter, assign it to its proper slot.
1942: // If a parameter !isSimple(), we cannot assign it to a local slot,
1943: // so instead create an artificial Variable for the incoming argument.
1944: // Below, we assign the value to the slot.
1945: method.initCode();
1946: code = getCode();
1947: // if (usingCPStyle()) code.addParamLocals();
1948:
1949: this Decl = method.getStaticFlag() ? null : module
1950: .declareThis(module.type);
1951: module.closureEnv = module.this Variable;
1952: module.heapFrame = module.isStatic() ? null
1953: : module.this Variable;
1954: module.allocChildClasses(this );
1955:
1956: if (module.isHandlingTailCalls() || usingCPStyle()) {
1957: callContextVar = new Variable("$ctx", typeCallContext);
1958: module.getVarScope().addVariableAfter(this Decl,
1959: callContextVar);
1960: callContextVar.setParameter(true);
1961: }
1962:
1963: int line = module.getLineNumber();
1964: if (line > 0)
1965: code.putLineNumber(module.getFileName(), line);
1966:
1967: module.allocParameters(this );
1968: module.enterFunction(this );
1969: if (usingCPStyle()) {
1970: loadCallContext();
1971: code.emitGetField(pcCallContextField);
1972: fswitch = new SwitchState(code);
1973: Label l = new Label(code);
1974: l.define(code);
1975: fswitch.addCase(0, l, code);
1976: }
1977:
1978: module.compileBody(this );
1979: module.compileChildMethods(this );
1980:
1981: Label startLiterals = null;
1982: Label afterLiterals = null;
1983: Method initMethod = null;
1984:
1985: if (curClass == mainClass) {
1986: Method save_method = method;
1987: Variable callContextSave = callContextVar;
1988: callContextVar = null;
1989:
1990: initMethod = startClassInit();
1991: clinitMethod = initMethod;
1992: code = getCode();
1993:
1994: startLiterals = new Label(code);
1995: afterLiterals = new Label(code);
1996: code.fixupChain(afterLiterals, startLiterals);
1997:
1998: if (staticModule) {
1999: generateConstructor(module);
2000:
2001: code.emitNew(moduleClass);
2002: code.emitDup(moduleClass);
2003: code.emitInvokeSpecial(moduleClass.constructor);
2004: moduleInstanceMainField = moduleClass.addField(
2005: "$instance", mainClass, Access.STATIC
2006: | Access.PUBLIC | Access.FINAL);
2007: code.emitPutStatic(moduleInstanceMainField);
2008: }
2009: Initializer init;
2010: while ((init = clinitChain) != null) {
2011: clinitChain = null;
2012: dumpInitializers(init);
2013: }
2014:
2015: if (!immediate && module.staticInitRun()) {
2016: code.emitGetStatic(moduleInstanceMainField);
2017: code.emitInvokeInterface(typeRunnable
2018: .getDeclaredMethod("run", 0));
2019: }
2020: code.emitReturn();
2021:
2022: if (moduleClass != mainClass && !staticModule
2023: && !generateMain && !immediate) {
2024: // Compare the run methods in ModuleBody.
2025: method = curClass.addMethod("run", Access.PUBLIC,
2026: Type.typeArray0, Type.void_type);
2027: code = method.startCode();
2028: Variable ctxVar = code.addLocal(typeCallContext);
2029: Variable saveVar = code.addLocal(typeConsumer);
2030: Variable exceptionVar = code
2031: .addLocal(Type.throwable_type);
2032: // ctx = CallContext.getInstance();
2033: code.emitInvokeStatic(getCallContextInstanceMethod);
2034: code.emitStore(ctxVar);
2035: Field consumerFld = typeCallContext
2036: .getDeclaredField("consumer");
2037: // save = ctx.consumer;
2038: code.emitLoad(ctxVar);
2039: code.emitGetField(consumerFld);
2040: code.emitStore(saveVar);
2041: // ctx.consumer = VoidConsumer.instance:
2042: code.emitLoad(ctxVar);
2043: code.emitGetStatic(ClassType.make(
2044: "gnu.lists.VoidConsumer").getDeclaredField(
2045: "instance"));
2046: code.emitPutField(consumerFld);
2047: // try {
2048: code.emitTryStart(false, Type.void_type);
2049: // this.apply(ctx):
2050: code.emitPushThis();
2051: code.emitLoad(ctxVar);
2052: code.emitInvokeVirtual(save_method);
2053: // exception = null
2054: code.emitPushNull();
2055: code.emitStore(exceptionVar);
2056: // } catch (Throwable th) { exception = th; }
2057: code.emitTryEnd();
2058: code.emitCatchStart(exceptionVar);
2059: code.emitCatchEnd();
2060: code.emitTryCatchEnd();
2061: // MooduleBody.runCleanup(ctx, ex, save);
2062: code.emitLoad(ctxVar);
2063: code.emitLoad(exceptionVar);
2064: code.emitLoad(saveVar);
2065: code.emitInvokeStatic(typeModuleBody.getDeclaredMethod(
2066: "runCleanup", 3));
2067: code.emitReturn();
2068: }
2069:
2070: method = save_method;
2071: callContextVar = callContextSave;
2072: }
2073:
2074: module.compileEnd(this );
2075:
2076: curLambda = saveLambda;
2077:
2078: if (Compilation.fewerClasses) // FIXME
2079: method.popScope(); // Undoes pushScope in method.initCode.
2080:
2081: module.heapFrame = heapFrame; // Restore heapFrame.
2082: if (usingCPStyle() || (fewerClasses && curClass == mainClass)) {
2083: code = getCode();
2084: fswitch.finish(code);
2085: }
2086:
2087: if (startLiterals != null || callContextVar != null) {
2088: method = initMethod;
2089: code = getCode();
2090:
2091: Label endLiterals = new Label(code);
2092: code.fixupChain(startLiterals, endLiterals);
2093:
2094: if (callContextVarForInit != null) {
2095: code.emitInvokeStatic(getCallContextInstanceMethod);
2096: code.emitStore(callContextVarForInit);
2097: }
2098:
2099: try {
2100: if (immediate) {
2101: code
2102: .emitPushInt(registerForImmediateLiterals(this ));
2103: code.emitInvokeStatic(ClassType.make(
2104: "gnu.expr.Compilation").getDeclaredMethod(
2105: "setupLiterals", 1));
2106: } else
2107: litTable.emit();
2108: } catch (Throwable ex) {
2109: error('e', "Literals: Internal error:" + ex);
2110: }
2111: code.fixupChain(endLiterals, afterLiterals);
2112: }
2113:
2114: if (generateMain && curClass == mainClass) {
2115: Type[] args = { new ArrayType(javaStringType) };
2116: method = curClass.addMethod("main", Access.PUBLIC
2117: | Access.STATIC, args, Type.void_type);
2118:
2119: code = method.startCode();
2120:
2121: if (Shell.defaultFormatName != null) {
2122: code.emitPushString(Shell.defaultFormatName);
2123: code.emitInvokeStatic(ClassType.make("kawa.Shell")
2124: .getDeclaredMethod("setDefaultFormat", 1));
2125: }
2126: code.emitLoad(code.getArg(0));
2127: code.emitInvokeStatic(typeModuleBody.getDeclaredMethod(
2128: "processArgs", 1));
2129: if (moduleInstanceMainField != null)
2130: code.emitGetStatic(moduleInstanceMainField);
2131: else {
2132: code.emitNew(curClass);
2133: code.emitDup(curClass);
2134: code.emitInvokeSpecial(curClass.constructor);
2135: }
2136: code.emitInvokeVirtual(typeModuleBody.getDeclaredMethod(
2137: "runAsMain", 0));
2138: code.emitReturn();
2139: }
2140:
2141: String uri;
2142: if (minfo != null && (uri = minfo.getNamespaceUri()) != null) {
2143: // Need to generate a ModuleSet for this class, so XQuery can find
2144: // this module and other modules in the same namespace.
2145: ModuleManager manager = ModuleManager.getInstance();
2146: String mainPrefix = mainClass.getName();
2147: int dot = mainPrefix.lastIndexOf('.');
2148: if (dot < 0) {
2149: mainPrefix = "";
2150: } else {
2151: String mainPackage = mainPrefix.substring(0, dot);
2152: try {
2153: manager.loadPackageInfo(mainPackage);
2154: } catch (ClassNotFoundException ex) {
2155: // Do nothing.
2156: } catch (Throwable ex) {
2157: error('e', "error loading map for " + mainPackage
2158: + " - " + ex);
2159: }
2160: mainPrefix = mainPrefix.substring(0, dot + 1);
2161: }
2162: ClassType mapClass = new ClassType(mainPrefix
2163: + ModuleSet.MODULES_MAP);
2164: ClassType typeModuleSet = ClassType
2165: .make("gnu.expr.ModuleSet");
2166: mapClass.setSuper(typeModuleSet);
2167: registerClass(mapClass);
2168:
2169: method = mapClass.addMethod("<init>", Access.PUBLIC,
2170: apply0args, Type.void_type);
2171: Method super Constructor = typeModuleSet.addMethod("<init>",
2172: Access.PUBLIC, apply0args, Type.void_type);
2173: code = method.startCode();
2174: code.emitPushThis();
2175: code.emitInvokeSpecial(super Constructor);
2176: code.emitReturn();
2177:
2178: ClassType typeModuleManager = ClassType
2179: .make("gnu.expr.ModuleManager");
2180: Type[] margs = { typeModuleManager };
2181: method = mapClass.addMethod("register", margs,
2182: Type.void_type, Access.PUBLIC);
2183: code = method.startCode();
2184: Method reg = typeModuleManager.getDeclaredMethod(
2185: "register", 3);
2186:
2187: for (ModuleInfo mi = manager.firstModule(); mi != null; mi = mi
2188: .nextModule()) {
2189: String miClassName = mi.className;
2190: if (miClassName == null
2191: || !miClassName.startsWith(mainPrefix))
2192: continue;
2193: String moduleSource = mi.sourcePath;
2194: String moduleUri = mi.getNamespaceUri();
2195: code.emitLoad(code.getArg(1));
2196: compileConstant(miClassName);
2197: if (!Path.valueOf(moduleSource).isAbsolute())
2198: try {
2199: // If the source path was relative, emit it as relative.
2200: // But make it relative to the compilation directory,
2201: // to allows sources to be moved along with binaries.
2202: char sep = File.separatorChar;
2203: String path = manager.getCompilationDirectory();
2204: path = path + mainPrefix.replace('.', sep);
2205: path = Path.toURL(path).toString();
2206: int plen = path.length();
2207: if (plen > 0 && path.charAt(plen - 1) != sep)
2208: path = path + sep;
2209: moduleSource = Path.relativize(mi
2210: .getSourceAbsPathname(), path);
2211: } catch (Throwable ex) {
2212: throw new WrappedException(
2213: "exception while fixing up '"
2214: + moduleSource + '\'', ex);
2215: }
2216: compileConstant(moduleSource);
2217: compileConstant(moduleUri);
2218: code.emitInvokeVirtual(reg);
2219: }
2220: code.emitReturn();
2221: }
2222: }
2223:
2224: int localFieldIndex;
2225:
2226: public Field allocLocalField(Type type, String name) {
2227: if (name == null)
2228: name = "tmp_" + (++localFieldIndex);
2229: Field field = curClass.addField(name, type, 0);
2230: return field;
2231: }
2232:
2233: /** If non-null, contains the value of the current CallContext. */
2234: Variable callContextVar;
2235: Variable callContextVarForInit;
2236:
2237: /** Generate code to push the current CallContext on the JVM stack. */
2238: public final void loadCallContext() {
2239: CodeAttr code = getCode();
2240: if (callContextVar != null && !callContextVar.dead())
2241: code.emitLoad(callContextVar);
2242: // We're cautious about re-using a previously extracted CallContext,
2243: // because it's tricky to manage the variables safely.
2244: // A possible solution is to inject a Variable into the current scope,
2245: // and making sure each separate straight-line block has its own scope.
2246: // (If the current scope is in the same "basic block" as an outer scope,
2247: // we can use that instead.) FIXME
2248: else if (method == clinitMethod) {
2249: // The variable is initialized just after literals.
2250: callContextVar = new Variable("$ctx", typeCallContext);
2251: // To make sure it doesn't clash with variables that have already
2252: // allocated and freed for previous initialzier.
2253: callContextVar.reserveLocal(code.getMaxLocals(), code);
2254: code.emitLoad(callContextVar);
2255: callContextVarForInit = callContextVar;
2256: } else {
2257: code.emitInvokeStatic(getCallContextInstanceMethod);
2258: code.emitDup();
2259: callContextVar = new Variable("$ctx", typeCallContext);
2260: code.getCurrentScope().addVariable(code, callContextVar);
2261: code.emitStore(callContextVar);
2262: }
2263: }
2264:
2265: public void freeLocalField(Field field) {
2266: // FIXME
2267: }
2268:
2269: /** This may not make sense, except for Lisp-like languages.
2270: * For those, 'input' an s-expression from the reader. */
2271: public Expression parse(Object input) {
2272: throw new Error("unimeplemented parse");
2273: }
2274:
2275: protected Language language;
2276:
2277: public Language getLanguage() {
2278: return language;
2279: }
2280:
2281: public LambdaExp currentLambda() {
2282: return current_scope.currentLambda();
2283: }
2284:
2285: public final ModuleExp getModule() {
2286: return mainLambda;
2287: }
2288:
2289: public void setModule(ModuleExp mexp) {
2290: mainLambda = mexp;
2291: }
2292:
2293: public boolean isStatic() {
2294: return mainLambda.isStatic();
2295: }
2296:
2297: /** The same as getModule, until we allow nested modules. */
2298: public ModuleExp currentModule() {
2299: return current_scope.currentModule();
2300: }
2301:
2302: /** Note that we have seen a construct that must be compiled, not evaluated.
2303: * If we are not inside a lambda (which is always compiled), but
2304: * only inside the outer-most ModuleExp, note that it must be compiled.
2305: */
2306: public void mustCompileHere() {
2307: mustCompile = true;
2308: }
2309:
2310: public ScopeExp currentScope() {
2311: return current_scope;
2312: }
2313:
2314: /** Set <code>currentScope()</code>.
2315: * Also update the <code>nesting</code> object.
2316: */
2317: public void setCurrentScope(ScopeExp scope) {
2318: int scope_nesting = ScopeExp.nesting(scope);
2319: int current_nesting = ScopeExp.nesting(current_scope);
2320: while (current_nesting > scope_nesting) {
2321: pop(current_scope);
2322: current_nesting--;
2323: }
2324: ScopeExp sc = scope;
2325: while (scope_nesting > current_nesting) {
2326: sc = sc.outer;
2327: scope_nesting--;
2328: }
2329: while (sc != current_scope) {
2330: pop(current_scope);
2331: sc = sc.outer;
2332: }
2333: pushChain(scope, sc);
2334: }
2335:
2336: void pushChain(ScopeExp scope, ScopeExp limit) {
2337: if (scope != limit) {
2338: pushChain(scope.outer, limit);
2339: pushScope(scope);
2340: lexical.push(scope);
2341: }
2342: }
2343:
2344: public ModuleExp pushNewModule(Lexer lexer) {
2345: this .lexer = lexer;
2346: return pushNewModule(lexer.getName());
2347: }
2348:
2349: public ModuleExp pushNewModule(String filename) {
2350: ModuleExp module = new ModuleExp();
2351: if (filename != null)
2352: module.setFile(filename);
2353: if (Compilation.generateAppletDefault)
2354: module.setFlag(ModuleExp.SUPERTYPE_SPECIFIED);
2355: if (immediate) {
2356: module.setFlag(ModuleExp.IMMEDIATE);
2357: new ModuleInfo().setCompilation(this );
2358: }
2359: mainLambda = module;
2360: push(module);
2361: return module;
2362: }
2363:
2364: public void push(ScopeExp scope) {
2365: pushScope(scope);
2366: lexical.push(scope);
2367: }
2368:
2369: public final void pushScope(ScopeExp scope) {
2370: if (!mustCompile
2371: // We set mustCompile if we see a LambdaExp - not because we must
2372: // but because it is usually desirable.
2373: && (scope.mustCompile() || (scope instanceof LambdaExp && !(scope instanceof ModuleExp))))
2374: mustCompileHere();
2375: scope.outer = current_scope;
2376: current_scope = scope;
2377: }
2378:
2379: public void pop(ScopeExp scope) {
2380: lexical.pop(scope);
2381: current_scope = scope.outer;
2382: }
2383:
2384: public final void pop() {
2385: pop(current_scope);
2386: }
2387:
2388: public void push(Declaration decl) {
2389: lexical.push(decl);
2390: }
2391:
2392: public Declaration lookup(Object name, int namespace) {
2393: return lexical.lookup(name, namespace);
2394: }
2395:
2396: /** Called for classes referenced in bytecode.
2397: * Since this only does something when immediate, we only care about
2398: * classes referenced in the bytecode when immediate.
2399: * It is used to ensure that we can inherit from classes defines when in
2400: * immediate mode (in Scheme using define-class or similar).
2401: */
2402: public void usedClass(Type type) {
2403: while (type instanceof ArrayType)
2404: type = ((ArrayType) type).getComponentType();
2405: if (!immediate || !(type instanceof ClassType))
2406: return;
2407: ClassType clas = (ClassType) type;
2408: if (loader != null && clas.isExisting()) {
2409: loader.addClass(clas.getReflectClass());
2410: }
2411: }
2412:
2413: public SourceMessages getMessages() {
2414: return messages;
2415: }
2416:
2417: public void setMessages(SourceMessages messages) {
2418: this .messages = messages;
2419: }
2420:
2421: public void error(char severity, String message,
2422: SourceLocator location) {
2423: String file = location.getFileName();
2424: int line = location.getLineNumber();
2425: int column = location.getColumnNumber();
2426: if (file == null || line <= 0) {
2427: file = getFileName();
2428: line = getLineNumber();
2429: column = getColumnNumber();
2430: }
2431:
2432: if (severity == 'w' && getBooleanOption("warn-as-error", false))
2433: severity = 'e';
2434: messages.error(severity, file, line, column, message);
2435: }
2436:
2437: public void error(char severity, String message) {
2438: if (severity == 'w' && getBooleanOption("warn-as-error", false))
2439: severity = 'e';
2440:
2441: messages.error(severity, this , message);
2442: }
2443:
2444: public void error(char severity, Declaration decl, String msg1,
2445: String msg2) {
2446: error(severity, msg1 + decl.getName() + msg2, null, decl);
2447: }
2448:
2449: public void error(char severity, String message, String code,
2450: Declaration decl) {
2451: if (severity == 'w' && getBooleanOption("warn-as-error", false))
2452: severity = 'e';
2453:
2454: String filename = getFileName();
2455: int line = getLineNumber();
2456: int column = getColumnNumber();
2457: int decl_line = decl.getLineNumber();
2458: if (decl_line > 0) {
2459: filename = decl.getFileName();
2460: line = decl_line;
2461: column = decl.getColumnNumber();
2462: }
2463: messages.error(severity, filename, line, column, message, code);
2464: }
2465:
2466: /**
2467: * Handle syntax errors (at rewrite time).
2468: * @param message an error message to print out
2469: * @return an ErrorExp
2470: */
2471: public Expression syntaxError(String message) {
2472: error('e', message);
2473: return new ErrorExp(message);
2474: }
2475:
2476: public final int getLineNumber() {
2477: return messages.getLineNumber();
2478: }
2479:
2480: public final int getColumnNumber() {
2481: return messages.getColumnNumber();
2482: }
2483:
2484: public final String getFileName() {
2485: return messages.getFileName();
2486: }
2487:
2488: public String getPublicId() {
2489: return messages.getPublicId();
2490: }
2491:
2492: public String getSystemId() {
2493: return messages.getSystemId();
2494: }
2495:
2496: public boolean isStableSourceLocation() {
2497: return false;
2498: }
2499:
2500: public void setFile(String filename) {
2501: messages.setFile(filename);
2502: }
2503:
2504: public void setLine(int line) {
2505: messages.setLine(line);
2506: }
2507:
2508: public void setColumn(int column) {
2509: messages.setColumn(column);
2510: }
2511:
2512: public final void setLine(Expression position) {
2513: messages.setLocation(position);
2514: }
2515:
2516: public void setLine(Object location) {
2517: if (location instanceof SourceLocator)
2518: messages.setLocation((SourceLocator) location);
2519: }
2520:
2521: public final void setLocation(SourceLocator position) {
2522: messages.setLocation(position);
2523: }
2524:
2525: public void setLine(String filename, int line, int column) {
2526: messages.setLine(filename, line, column);
2527: }
2528:
2529: /** A help vector for building expressions. */
2530: public Stack exprStack;
2531:
2532: public void letStart() {
2533: pushScope(new LetExp(null));
2534: }
2535:
2536: public Declaration letVariable(Object name, Type type,
2537: Expression init) {
2538: LetExp let = (LetExp) current_scope;
2539: Declaration decl = let.addDeclaration(name, type);
2540: decl.noteValue(init);
2541: return decl;
2542: }
2543:
2544: public void letEnter() {
2545: LetExp let = (LetExp) current_scope;
2546: int ndecls = let.countDecls();
2547: Expression[] inits = new Expression[ndecls];
2548: int i = 0;
2549: for (Declaration decl = let.firstDecl(); decl != null; decl = decl
2550: .nextDecl())
2551: inits[i++] = decl.getValue();
2552: let.inits = inits;
2553: lexical.push(let);
2554: }
2555:
2556: public LetExp letDone(Expression body) {
2557: LetExp let = (LetExp) current_scope;
2558: let.body = body;
2559: pop(let);
2560: return let;
2561: }
2562:
2563: private void checkLoop() {
2564: if (((LambdaExp) current_scope).getName() != "%do%loop")
2565: throw new Error("internal error - bad loop state");
2566: }
2567:
2568: /** Start a new loop.
2569: * (We could make this implied by the first loopVaribale call ???) */
2570: public void loopStart() {
2571: LambdaExp loopLambda = new LambdaExp();
2572: Expression[] inits = { loopLambda };
2573: LetExp let = new LetExp(inits);
2574: String fname = "%do%loop";
2575: Declaration fdecl = let.addDeclaration(fname);
2576: fdecl.noteValue(loopLambda);
2577: loopLambda.setName(fname);
2578: let.outer = current_scope;
2579: loopLambda.outer = let;
2580: current_scope = loopLambda;
2581: }
2582:
2583: public Declaration loopVariable(Object name, Type type,
2584: Expression init) {
2585: checkLoop();
2586: LambdaExp loopLambda = (LambdaExp) current_scope;
2587: Declaration decl = loopLambda.addDeclaration(name, type);
2588: if (exprStack == null)
2589: exprStack = new Stack();
2590: exprStack.push(init);
2591: loopLambda.min_args++;
2592: return decl;
2593: }
2594:
2595: /** Done handling loop variables, and pushes them into the lexical scope.
2596: * Ready to parse the loop condition. */
2597: public void loopEnter() {
2598: checkLoop();
2599: LambdaExp loopLambda = (LambdaExp) current_scope;
2600: int ninits = loopLambda.min_args;
2601: loopLambda.max_args = ninits;
2602: Expression[] inits = new Expression[ninits];
2603: for (int i = ninits; --i >= 0;)
2604: inits[i] = (Expression) exprStack.pop();
2605: LetExp let = (LetExp) loopLambda.outer;
2606: Declaration fdecl = let.firstDecl(); // The decls for loopLambda.
2607: let.setBody(new ApplyExp(new ReferenceExp(fdecl), inits));
2608: lexical.push(loopLambda);
2609: }
2610:
2611: public void loopCond(Expression cond) {
2612: checkLoop();
2613: exprStack.push(cond);
2614: }
2615:
2616: public void loopBody(Expression body) {
2617: LambdaExp loopLambda = (LambdaExp) current_scope;
2618: loopLambda.body = body;
2619: }
2620:
2621: public Expression loopRepeat(Expression[] exps) {
2622: LambdaExp loopLambda = (LambdaExp) current_scope;
2623: ScopeExp let = loopLambda.outer;
2624: Declaration fdecl = let.firstDecl(); // The decls for loopLambda.
2625: Expression cond = (Expression) exprStack.pop();
2626: Expression recurse = new ApplyExp(new ReferenceExp(fdecl), exps);
2627: loopLambda.body = new IfExp(cond, new BeginExp(loopLambda.body,
2628: recurse), QuoteExp.voidExp);
2629: lexical.pop(loopLambda);
2630: current_scope = let.outer;
2631: return let;
2632: }
2633:
2634: public Expression loopRepeat() {
2635: return loopRepeat(Expression.noExpressions);
2636: }
2637:
2638: public Expression loopRepeat(Expression exp) {
2639: Expression[] args = { exp };
2640: return loopRepeat(args);
2641: }
2642:
2643: /** If non-null, a helper method generated by getForNameHelper. */
2644: Method forNameHelper;
2645:
2646: public void loadClassRef(ClassType clas) {
2647: // Try an optimization
2648: if (clas == mainClass && mainLambda.isStatic()
2649: // moduleInstanceMainField may not have been set yet.
2650: && moduleInstanceMainField != null) {
2651: CodeAttr code = getCode();
2652: code.emitGetStatic(moduleInstanceMainField);
2653: code.emitInvokeVirtual(Type.pointer_type.getDeclaredMethod(
2654: "getClass", 0));
2655: } else
2656: loadClassRef(clas.getName());
2657: }
2658:
2659: /** Generate code to load a named Class without initializing it.
2660: */
2661: public void loadClassRef(String className) {
2662: CodeAttr code = getCode();
2663: if (curClass.getClassfileMajorVersion() >= 49) // Java5 feature
2664: code.emitPushClass(className);
2665: else {
2666: code.emitPushString(className);
2667: code.emitInvokeStatic(getForNameHelper());
2668: }
2669: }
2670:
2671: /** Generate a method to find a named Class without initializing it.
2672: * Generate a static helper method "class$" like javac generates for
2673: * 'CLASS.class', but does not initialize CLASS. Also, we don't bother
2674: * catching exceptions, since the JVM doesn't require us to. I.e. generates:
2675: * public static class $(String name)
2676: * { return Class.forName(name, false,
2677: * Class.forName(THISCLASSNAME).getClassLoader()); }
2678: * Note that we want the result to use the same ClassLoader as the caller,
2679: * which is why we generate a static helper method.
2680: */
2681: public Method getForNameHelper() {
2682: if (forNameHelper == null) {
2683: /* #ifdef JAVA2 */
2684: Method save_method = method;
2685: method = curClass.addMethod("class$", Access.PUBLIC
2686: | Access.STATIC, string1Arg, typeClass);
2687: forNameHelper = method;
2688: CodeAttr code = method.startCode();
2689: code.emitLoad(code.getArg(0));
2690: code.emitPushInt(0);
2691: code.emitPushString(mainClass.getName());
2692: code.emitInvokeStatic(typeClass.getDeclaredMethod(
2693: "forName", 1));
2694: code.emitInvokeVirtual(typeClass.getDeclaredMethod(
2695: "getClassLoader", 0));
2696: code.emitInvokeStatic(typeClass.getDeclaredMethod(
2697: "forName", 3));
2698: code.emitReturn();
2699: method = save_method;
2700: /* #else */
2701: // forNameHelper = typeClass.getDeclaredMethod("forName", 1);
2702: /* #endif */
2703: }
2704: return forNameHelper;
2705: }
2706:
2707: public Object resolve(Object name, boolean function) {
2708: Environment env = Environment.getCurrent();
2709: Symbol symbol;
2710: if (name instanceof String)
2711: symbol = env.defaultNamespace().lookup((String) name);
2712: else
2713: symbol = (Symbol) name;
2714: if (symbol == null)
2715: return null;
2716: if (function && getLanguage().hasSeparateFunctionNamespace())
2717: return env.getFunction(symbol, null);
2718: return env.get(symbol, null);
2719: }
2720:
2721: /** A key we can pass from the compiler to identity a Compilation. */
2722: private int keyUninitialized;
2723: /** Chain of immediate Compilation whose setupLiterals hasn't been called. */
2724: private static Compilation chainUninitialized;
2725: /** Next in chain headed by chainUninitialized. */
2726: private Compilation nextUninitialized;
2727:
2728: /** Call-back from compiled code to initialize literals in immediate mode.
2729: * In non-immediate mode (i.e. generating class files) the compiler emits
2730: * code to "re-construct" literal values. However, in immediate mode
2731: * that would be wasteful, plus we would get values that are similar (equals)
2732: * to but not necessarily identical (eq) to the compile-time literal.
2733: * So we need to pass the literal values to the compiled code, by using
2734: * reflection to initialize various static fields. This method does that.
2735: * It is called at the start of the generated static initializer, which
2736: * helps makes things more consistent between immediate and non-immediate
2737: * mode.
2738: */
2739: public static void setupLiterals(int key) {
2740: Compilation comp = Compilation.findForImmediateLiterals(key);
2741: try {
2742: Class clas = comp.loader
2743: .loadClass(comp.mainClass.getName());
2744:
2745: /* Pass literal values to the compiled code. */
2746: for (Literal init = comp.litTable.literalsChain; init != null; init = init.next) {
2747: /* DEBUGGING:
2748: OutPort out = OutPort.errDefault();
2749: out.print("init["+init.index+"]=");
2750: out.print(init.value);
2751: out.println();
2752: */
2753: clas.getDeclaredField(init.field.getName()).set(null,
2754: init.value);
2755: }
2756: } catch (Throwable ex) {
2757: throw new WrappedException("internal error", ex);
2758: }
2759: }
2760:
2761: public static synchronized int registerForImmediateLiterals(
2762: Compilation comp) {
2763: int i = 0;
2764: for (Compilation c = chainUninitialized; c != null; c = c.nextUninitialized) {
2765: if (i <= c.keyUninitialized)
2766: i = c.keyUninitialized + 1;
2767: }
2768: comp.keyUninitialized = i;
2769: comp.nextUninitialized = chainUninitialized;
2770: chainUninitialized = comp;
2771: return i;
2772: }
2773:
2774: public static synchronized Compilation findForImmediateLiterals(
2775: int key) {
2776: Compilation prev = null;
2777: for (Compilation comp = chainUninitialized;;) {
2778: Compilation next = comp.nextUninitialized;
2779: if (comp.keyUninitialized == key) {
2780: if (prev == null)
2781: chainUninitialized = next;
2782: else
2783: prev.nextUninitialized = next;
2784: return comp;
2785: }
2786: prev = comp;
2787: comp = next;
2788: }
2789: }
2790:
2791: /** Current lexical scope - map name to Declaration. */
2792: public NameLookup lexical;
2793:
2794: protected ScopeExp current_scope;
2795:
2796: protected SourceMessages messages;
2797:
2798: private static final ThreadLocation current = new ThreadLocation(
2799: "current-compilation");
2800:
2801: public static Compilation getCurrent() {
2802: return (Compilation) current.get();
2803: }
2804:
2805: public static void setCurrent(Compilation comp) {
2806: current.set(comp);
2807: }
2808:
2809: public String toString() {
2810: return "<compilation " + mainLambda + ">";
2811: }
2812: }
|