0001: /*
0002: * Compiler.java
0003: *
0004: * Copyright (c) 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: *
0006: * See the file "LICENSE.txt" for information on usage and redistribution
0007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
0008: */
0009: package pnuts.compiler;
0010:
0011: import java.io.ByteArrayOutputStream;
0012: import java.io.File;
0013: import java.io.IOException;
0014: import java.io.Reader;
0015: import java.lang.reflect.Constructor;
0016: import java.lang.reflect.Method;
0017: import java.lang.reflect.Modifier;
0018: import java.math.BigDecimal;
0019: import java.math.BigInteger;
0020: import java.net.URL;
0021: import java.security.AccessController;
0022: import java.security.PrivilegedAction;
0023: import java.util.ArrayList;
0024: import java.util.Collection;
0025: import java.util.Enumeration;
0026: import java.util.HashMap;
0027: import java.util.HashSet;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.Map;
0031: import java.util.Set;
0032: import org.pnuts.lang.ConstraintsTransformer;
0033: import org.pnuts.lang.GeneratorHelper;
0034: import org.pnuts.lang.NodeUtil;
0035: import org.pnuts.lang.Signature;
0036: import org.pnuts.lang.DefaultParseEnv;
0037:
0038: import pnuts.lang.PnutsParser;
0039: import pnuts.lang.Context;
0040: import pnuts.lang.Function;
0041: import pnuts.lang.Generator;
0042: import pnuts.lang.ParseException;
0043: import pnuts.lang.Pnuts;
0044: import pnuts.lang.PnutsException;
0045: import pnuts.lang.PnutsFunction;
0046: import pnuts.lang.PnutsInterpreter;
0047: import pnuts.lang.Runtime;
0048: import pnuts.lang.SimpleNode;
0049: import pnuts.lang.Visitor;
0050: import pnuts.lang.PnutsParserTreeConstants;
0051: import pnuts.lang.ParseEnvironment;
0052:
0053: /**
0054: * Pnuts to JVM bytecode compiler
0055: */
0056: public class Compiler extends Runtime implements Visitor {
0057:
0058: private final static boolean DEBUG = false;
0059:
0060: private final static boolean PROFILE = false;
0061:
0062: final static String SUPER = "super".intern();
0063:
0064: final static String THIS = "this".intern();
0065:
0066: final static String YIELD = "yield".intern();
0067:
0068: final static String STAR = "*".intern();
0069:
0070: final static String METHOD_FACTORY_FUNCTION = "$methodFactoryFunction";
0071:
0072: private static PnutsInterpreter interpreter = new PnutsInterpreter(); // fallback
0073:
0074: private static Preprocessor preproc = new Preprocessor();
0075:
0076: private static boolean optimize = getBoolean("pnuts.compiler.optimize");
0077:
0078: static boolean hasBootClassLoader = false;
0079: static {
0080: try {
0081: Class cls = ClassLoader.class;
0082: cls.getDeclaredConstructor(new Class[] { cls });
0083: hasBootClassLoader = true;
0084: } catch (Exception e) {
0085: /* skip */
0086: }
0087: }
0088:
0089: static boolean hasJava2Security = false;
0090: static {
0091: try {
0092: Class.class
0093: .getMethod("getProtectionDomain", new Class[] {});
0094: hasJava2Security = true;
0095: } catch (Exception e) {
0096: /* skip */
0097: }
0098: }
0099:
0100: static boolean hasValueOfPrimitive = false;
0101: static {
0102: try {
0103: Integer.class.getMethod("valueOf",
0104: new Class[] { int.class });
0105: hasValueOfPrimitive = true;
0106: } catch (Exception e) {
0107: /* skip */
0108: }
0109: }
0110:
0111: static CodeLoaderFactory codeLoaderFactory;
0112:
0113: static CodeLoaderFactory privilegedCodeLoaderFactory;
0114: static {
0115: codeLoaderFactory = new CodeLoaderFactory();
0116: if (hasJava2Security) {
0117: privilegedCodeLoaderFactory = new PrivilegedCodeLoaderFactory();
0118: }
0119: }
0120:
0121: private static boolean proxyConf = getBoolean("pnuts.compiler.useDynamicProxy");
0122:
0123: private long s; // for profiling
0124:
0125: boolean _includeLineNo = !optimize;
0126:
0127: boolean _includeColumnNo = false;
0128:
0129: boolean _constantFolding = false;
0130:
0131: boolean traceMode = getBoolean("pnuts.compiler.traceMode");
0132:
0133: boolean includeMainMethod = false;
0134:
0135: private long classCount = 0L;
0136:
0137: boolean automatic;
0138:
0139: String className;
0140:
0141: String runtimeClassName;
0142:
0143: boolean useDynamicProxy = proxyConf;
0144:
0145: String sourceFile;
0146:
0147: public Compiler() {
0148: this (null);
0149: }
0150:
0151: public Compiler(String className) {
0152: this (className, true);
0153: }
0154:
0155: public Compiler(String className, boolean automatic) {
0156: this (className, automatic, proxyConf);
0157: }
0158:
0159: public Compiler(String className, boolean automatic,
0160: boolean useDynamicProxy) {
0161: if (className == null) {
0162: this .className = "_pnuts_";
0163: } else {
0164: this .className = className;
0165: }
0166: this .automatic = automatic;
0167: useDynamicProxy(useDynamicProxy);
0168: }
0169:
0170: public void includeLineNo(boolean flag) {
0171: this ._includeLineNo = flag;
0172: }
0173:
0174: public void includeColumnNo(boolean flag) {
0175: this ._includeColumnNo = flag;
0176: }
0177:
0178: public void setConstantFolding(boolean flag) {
0179: this ._constantFolding = flag;
0180: }
0181:
0182: public void includeMainMethod(boolean flag) {
0183: this .includeMainMethod = flag;
0184: }
0185:
0186: public void setTraceMode(boolean mode) {
0187: this .traceMode = mode;
0188: }
0189:
0190: public void useDynamicProxy(boolean flag) {
0191: this .useDynamicProxy = flag;
0192: if (flag) {
0193: runtimeClassName = "pnuts.compiler.DynamicRuntime";
0194: } else {
0195: runtimeClassName = "pnuts.lang.Runtime";
0196: }
0197: }
0198:
0199: void addLineInfo(CompileContext cc, int ctx, SimpleNode node) {
0200: if (_includeLineNo || traceMode) {
0201: int line = node.beginLine;
0202: int column = node.beginColumn;
0203: ClassFile cf = cc.cf;
0204: if ((_includeColumnNo && (cc.line != line || cc.column != column))
0205: || traceMode) {
0206: cf.loadLocal(ctx);
0207: cf.pushInteger(line);
0208: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
0209: "setLine", "(Lpnuts/lang/Context;I)", "V");
0210: cc.line = line;
0211: cc.column = column;
0212: cf.addLineNumber(line);
0213: } else if (cc.line != line) {
0214: cf.loadLocal(ctx);
0215: cf.pushInteger(line);
0216: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
0217: "setLine", "(Lpnuts/lang/Context;I)", "V");
0218: cc.line = line;
0219: cf.addLineNumber(line);
0220: }
0221: }
0222: }
0223:
0224: protected Object execute(CompileContext cc, Context context,
0225: boolean catchJump) {
0226: if (DEBUG) {
0227: cc.debug();
0228: }
0229: try {
0230: Runtime rt;
0231: if (PROFILE) {
0232: s = System.currentTimeMillis();
0233: CodeLoader loader = createCodeLoader(context
0234: .getClassLoader(), true);
0235: Class cls = cc.loadClasses(loader);
0236: rt = (Runtime) cls.newInstance();
0237: System.out.println("load: "
0238: + (System.currentTimeMillis() - s));
0239: } else {
0240: CodeLoader loader = createCodeLoader(context
0241: .getClassLoader(), true);
0242: Class cls = cc.loadClasses(loader);
0243: rt = (Runtime) cls.newInstance();
0244: }
0245: return rt.run(context);
0246: } catch (IOException io) {
0247: throw new PnutsException(io, context);
0248: } catch (InstantiationException ie) {
0249: throw new PnutsException(ie, context);
0250: } catch (IllegalAccessException iae) {
0251: throw new PnutsException(iae, context);
0252: }
0253: }
0254:
0255: void preprocess(SimpleNode node) {
0256: node.accept(preproc, new TranslateContext());
0257: }
0258:
0259: public Object startSet(SimpleNode node, Context context) {
0260: if (!_includeLineNo && context.isVerbose()) {
0261: _includeLineNo = true;
0262: }
0263:
0264: preprocess(node);
0265:
0266: return start(node, context);
0267: }
0268:
0269: public Object start(SimpleNode node, Context context) {
0270: try {
0271: preprocess(node);
0272: return _start(node, context, true);
0273: } catch (LinkageError e) {
0274: if (context.isVerbose()) {
0275: e.printStackTrace();
0276: } else {
0277: System.out.println(e);
0278: }
0279: if (automatic) {
0280: return node.accept(interpreter, context);
0281: } else {
0282: throw e;
0283: }
0284: }
0285: }
0286:
0287: Object _start(SimpleNode node, Context context, boolean catchJump) {
0288:
0289: if (PROFILE) {
0290: s = System.currentTimeMillis();
0291: }
0292:
0293: CompileContext cc;
0294: Object src = null;
0295: if (automatic) {
0296: cc = new CompileContext(context);
0297: src = getScriptSource(context);
0298:
0299: } else {
0300: cc = (CompileContext) context;
0301:
0302: src = cc.scriptSource;
0303: }
0304: if (src instanceof URL) {
0305: String s = ((URL) src).toString();
0306: int idx = s.lastIndexOf('/');
0307: if (idx > 0) {
0308: this .sourceFile = s.substring(idx + 1);
0309: }
0310: }
0311: cc.constClassName = className;
0312: cc.cf = new ClassFile(className, runtimeClassName, sourceFile,
0313: Constants.ACC_PUBLIC);
0314: ClassFile cf = cc.cf;
0315: cf.addInterface("pnuts.compiler.Compiled");
0316:
0317: /*
0318: * constructor
0319: */
0320: cf.openMethod("<init>", "()V", Constants.ACC_PUBLIC);
0321: cf.add(Opcode.ALOAD_0);
0322: cf.add(Opcode.INVOKESPECIAL, runtimeClassName, "<init>", "()",
0323: "V");
0324: cf.add(Opcode.RETURN);
0325: cf.closeMethod();
0326:
0327: /*
0328: * public static void main(String[])
0329: */
0330: if (includeMainMethod) {
0331: cf
0332: .openMethod(
0333: "main",
0334: "([Ljava/lang/String;)V",
0335: (short) (Constants.ACC_PUBLIC | Constants.ACC_STATIC));
0336: cf.add(Opcode.NEW, className);
0337: cf.add(Opcode.DUP);
0338: cf
0339: .add(Opcode.INVOKESPECIAL, className, "<init>",
0340: "()", "V");
0341:
0342: Label catchStart = cf.getLabel(true);
0343: cf.add(Opcode.NEW, "pnuts.lang.Context");
0344: cf.add(Opcode.DUP);
0345: cf.add(Opcode.INVOKESPECIAL, "pnuts.lang.Context",
0346: "<init>", "()", "V");
0347: cf.add(Opcode.INVOKEINTERFACE, "pnuts.lang.Executable",
0348: "run", "(Lpnuts/lang/Context;)",
0349: "Ljava/lang/Object;");
0350: cf.add(Opcode.POP);
0351: cf.add(Opcode.RETURN);
0352:
0353: Label catchEnd = cf.getLabel(true);
0354: Label catchTarget = cf.getLabel(true);
0355: cf.reserveStack(1);
0356: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Jump", "getValue",
0357: "()", "Ljava/lang/Object;");
0358: cf.add(Opcode.POP);
0359: cf.add(Opcode.RETURN);
0360: cf.addExceptionHandler(catchStart, catchEnd, catchTarget,
0361: "pnuts.lang.Jump");
0362:
0363: cf.closeMethod();
0364: }
0365:
0366: /*
0367: * protected Object exec(Context context);
0368: */
0369: cf.openMethod("exec",
0370: "(Lpnuts/lang/Context;)Ljava/lang/Object;",
0371: Constants.ACC_PROTECTED);
0372:
0373: int ctx = 1;
0374: cc.setContextIndex(ctx);
0375:
0376: int n = node.jjtGetNumChildren();
0377: if (n > 0) {
0378: int m = n - 1;
0379: for (int i = 0; i < m; i++) {
0380: accept(node, i, cc);
0381: cf.add(Opcode.POP);
0382: }
0383: accept(node, m, cc);
0384: } else {
0385: cf.add(Opcode.ACONST_NULL);
0386: }
0387: cf.add(Opcode.ARETURN);
0388: cf.closeMethod();
0389:
0390: /*
0391: * static {} clause
0392: */
0393: staticBlock(cf, null, cc);
0394:
0395: if (PROFILE) {
0396: System.out.println(className + " classFile: "
0397: + (System.currentTimeMillis() - s));
0398: }
0399:
0400: if (automatic) {
0401: return execute(cc, context, catchJump);
0402: } else {
0403: return null;
0404: }
0405: }
0406:
0407: void staticBlock(ClassFile cf, SimpleNode closureNode,
0408: CompileContext cc) {
0409: String className = cf.getClassName();
0410:
0411: cf.openMethod("<clinit>", "()V", Constants.ACC_STATIC);
0412: cf.addField("NO_PARAM", "[Ljava/lang/Object;",
0413: Constants.ACC_STATIC);
0414: cf.add(Opcode.ICONST_0);
0415: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
0416: cf.add(Opcode.PUTSTATIC, className, "NO_PARAM",
0417: "[Ljava/lang/Object;");
0418:
0419: /**/
0420: if (cc.hasAttachMethod) {
0421: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
0422: "getThreadContext", "()", "Lpnuts/lang/Context;");
0423: int tmp = cf.getLocal();
0424: cf.storeLocal(tmp);
0425: cf.loadLocal(tmp);
0426: Label end = cf.getLabel();
0427: cf.add(Opcode.IFNULL, end);
0428: cf.loadLocal(tmp);
0429: cf.add(Opcode.INVOKESTATIC, className, "attach",
0430: "(Lpnuts/lang/Context;)", "V");
0431: end.fix();
0432: }
0433: /**/
0434: cf.addField(METHOD_FACTORY_FUNCTION,
0435: "Lpnuts/lang/PnutsFunction;", Constants.ACC_STATIC);
0436:
0437: if (closureNode != null) {
0438: closureNode.accept(this , cc);
0439: cf.add(Opcode.PUTSTATIC, className,
0440: METHOD_FACTORY_FUNCTION,
0441: "Lpnuts/lang/PnutsFunction;");
0442: }
0443:
0444: for (Iterator it = cc.constants.keySet().iterator(); it
0445: .hasNext();) {
0446: Object obj = it.next();
0447: String k = (String) cc.constants.get(obj);
0448: if (DEBUG) {
0449: System.out.println(k + " : " + obj);
0450: }
0451:
0452: if (obj instanceof Integer) {
0453: int value = ((Integer) obj).intValue();
0454: cf.addField(k, "Ljava/lang/Integer;",
0455: Constants.ACC_STATIC);
0456: cf.add(Opcode.NEW, "java.lang.Integer");
0457: cf.add(Opcode.DUP);
0458: cf.pushInteger(value);
0459: cf.add(Opcode.INVOKESPECIAL, "java.lang.Integer",
0460: "<init>", "(I)", "V");
0461: cf.add(Opcode.PUTSTATIC, className, k,
0462: "Ljava/lang/Integer;");
0463: } else if (obj instanceof Byte) {
0464: byte value = ((Byte) obj).byteValue();
0465: cf
0466: .addField(k, "Ljava/lang/Byte;",
0467: Constants.ACC_STATIC);
0468: cf.add(Opcode.NEW, "java.lang.Byte");
0469: cf.add(Opcode.DUP);
0470: cf.pushInteger((int) value);
0471: cf.add(Opcode.INVOKESPECIAL, "java.lang.Byte",
0472: "<init>", "(B)", "V");
0473: cf.add(Opcode.PUTSTATIC, className, k,
0474: "Ljava/lang/Byte;");
0475: } else if (obj instanceof Character) {
0476: char value = ((Character) obj).charValue();
0477: cf.addField(k, "Ljava/lang/Character;",
0478: Constants.ACC_STATIC);
0479: cf.add(Opcode.NEW, "java.lang.Character");
0480: cf.add(Opcode.DUP);
0481: cf.pushInteger((int) value);
0482: cf.add(Opcode.INVOKESPECIAL, "java.lang.Character",
0483: "<init>", "(C)", "V");
0484: cf.add(Opcode.PUTSTATIC, className, k,
0485: "Ljava/lang/Character;");
0486: } else if (obj instanceof Long) {
0487: long value = ((Long) obj).longValue();
0488: cf
0489: .addField(k, "Ljava/lang/Long;",
0490: Constants.ACC_STATIC);
0491: cf.add(Opcode.NEW, "java.lang.Long");
0492: cf.add(Opcode.DUP);
0493: cf.pushLong(value);
0494: cf.add(Opcode.INVOKESPECIAL, "java.lang.Long",
0495: "<init>", "(J)", "V");
0496: cf.add(Opcode.PUTSTATIC, className, k,
0497: "Ljava/lang/Long;");
0498: } else if (obj instanceof Float) {
0499: float value = ((Float) obj).floatValue();
0500: cf.addField(k, "Ljava/lang/Float;",
0501: Constants.ACC_STATIC);
0502: cf.add(Opcode.NEW, "java.lang.Float");
0503: cf.add(Opcode.DUP);
0504: cf.pushFloat(value);
0505: cf.add(Opcode.INVOKESPECIAL, "java.lang.Float",
0506: "<init>", "(F)", "V");
0507: cf.add(Opcode.PUTSTATIC, className, k,
0508: "Ljava/lang/Float;");
0509: } else if (obj instanceof Double) {
0510: double value = ((Double) obj).doubleValue();
0511: cf.addField(k, "Ljava/lang/Double;",
0512: Constants.ACC_STATIC);
0513: cf.add(Opcode.NEW, "java.lang.Double");
0514: cf.add(Opcode.DUP);
0515: cf.pushDouble(value);
0516: cf.add(Opcode.INVOKESPECIAL, "java.lang.Double",
0517: "<init>", "(D)", "V");
0518: cf.add(Opcode.PUTSTATIC, className, k,
0519: "Ljava/lang/Double;");
0520: } else if (obj instanceof BigDecimal) {
0521: cf.addField(k, "Ljava/math/BigDecimal;",
0522: Constants.ACC_STATIC);
0523: cf.add(Opcode.NEW, "java.math.BigDecimal");
0524: cf.add(Opcode.DUP);
0525: cf.pushString(obj.toString());
0526: cf.add(Opcode.INVOKESPECIAL, "java.math.BigDecimal",
0527: "<init>", "(Ljava/lang/String;)", "V");
0528: cf.add(Opcode.PUTSTATIC, className, k,
0529: "Ljava/math/BigDecimal;");
0530: } else if (obj instanceof BigInteger) {
0531: cf.addField(k, "Ljava/math/BigInteger;",
0532: Constants.ACC_STATIC);
0533: cf.add(Opcode.NEW, "java.math.BigInteger");
0534: cf.add(Opcode.DUP);
0535: cf.pushString(obj.toString());
0536: cf.add(Opcode.INVOKESPECIAL, "java.math.BigInteger",
0537: "<init>", "(Ljava/lang/String;)", "V");
0538: cf.add(Opcode.PUTSTATIC, className, k,
0539: "Ljava/math/BigInteger;");
0540: }
0541: }
0542:
0543: cf.add(Opcode.RETURN);
0544: cf.closeMethod();
0545: }
0546:
0547: public Object expressionList(SimpleNode node, Context context) {
0548: CompileContext cc = (CompileContext) context;
0549: ClassFile cf = cc.cf;
0550:
0551: int n = node.jjtGetNumChildren();
0552: if (n > 0) {
0553: int m = n - 1;
0554: for (int i = 0; i < m; i++) {
0555: accept(node, i, context);
0556: cf.add(Opcode.POP);
0557: }
0558: accept(node, m, context);
0559: } else {
0560: cf.add(Opcode.ACONST_NULL);
0561: }
0562: return null;
0563: }
0564:
0565: public Object integerNode(SimpleNode node, Context context) {
0566: CompileContext cc = (CompileContext) context;
0567: ClassFile cf = cc.cf;
0568: String str = node.str;
0569: Object p[] = (Object[]) node.info;
0570: Number n = (Number) p[0];
0571:
0572: String assoc = (String) cc.constants.get(n);
0573: if (assoc == null) {
0574: assoc = gensym(context);
0575: cc.constants.put(n, assoc);
0576: }
0577:
0578: if (n instanceof Integer) {
0579: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0580: "Ljava/lang/Integer;");
0581: } else if (n instanceof Long) {
0582: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0583: "Ljava/lang/Long;");
0584: } else if (n instanceof Byte) {
0585: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0586: "Ljava/lang/Byte;");
0587: } else if (n instanceof BigInteger) {
0588: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0589: "Ljava/math/BigInteger;");
0590: } else if (n instanceof BigDecimal) {
0591: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0592: "Ljava/math/BigDecimal;");
0593: } else {
0594: throw new InternalError("compiler error");
0595: }
0596:
0597: if (p[1] != null) {
0598: addLineInfo(cc, cc.getContextIndex(), node);
0599:
0600: int offset = ((int[]) p[1])[0];
0601: cf.add(Opcode.CHECKCAST, "java.lang.Number");
0602:
0603: cf.pushString(str.substring(0, offset));
0604: cf.add(Opcode.LDC, cf.addConstant(str.substring(offset)));
0605: cf.loadLocal(cc.getContextIndex());
0606: cf
0607: .add(
0608: Opcode.INVOKESTATIC,
0609: "pnuts.lang.Runtime",
0610: "quantity",
0611: "(Ljava/lang/Number;Ljava/lang/String;Ljava/lang/String;Lpnuts/lang/Context;)",
0612: "Ljava/lang/Object;");
0613: }
0614: return null;
0615: }
0616:
0617: public Object floatingNode(SimpleNode node, Context context) {
0618: CompileContext cc = (CompileContext) context;
0619: ClassFile cf = cc.cf;
0620: String str = node.str;
0621: Object p[] = (Object[]) node.info;
0622: Number n = (Number) p[0];
0623:
0624: String assoc = (String) cc.constants.get(n);
0625: if (assoc == null) {
0626: assoc = gensym(context);
0627: cc.constants.put(n, assoc);
0628: }
0629: if (n instanceof Float) {
0630: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0631: "Ljava/lang/Float;");
0632: } else if (n instanceof Double) {
0633: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0634: "Ljava/lang/Double;");
0635: } else if (n instanceof BigDecimal) {
0636: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0637: "Ljava/math/BigDecimal;");
0638: } else {
0639: throw new InternalError("compiler error");
0640: }
0641: if (p[1] != null) {
0642: addLineInfo(cc, cc.getContextIndex(), node);
0643:
0644: int offset = ((int[]) p[1])[0];
0645: cf.add(Opcode.CHECKCAST, "java.lang.Number");
0646:
0647: cf
0648: .add(Opcode.LDC, cf.addConstant(str.substring(0,
0649: offset)));
0650: cf.add(Opcode.LDC, cf.addConstant(str.substring(offset)));
0651: cf.loadLocal(cc.getContextIndex());
0652: cf
0653: .add(
0654: Opcode.INVOKESTATIC,
0655: "pnuts.lang.Runtime",
0656: "quantity",
0657: "(Ljava/lang/Number;Ljava/lang/String;Ljava/lang/String;Lpnuts/lang/Context;)",
0658: "Ljava/lang/Object;");
0659: }
0660: return null;
0661: }
0662:
0663: public Object stringNode(SimpleNode node, Context context) {
0664: CompileContext cc = (CompileContext) context;
0665: ClassFile cf = cc.cf;
0666: String str = node.str;
0667: if (str != null) {
0668: cf.pushString(node.str);
0669: } else {
0670: cf.add(Opcode.NEW, "java.lang.StringBuffer");
0671: cf.add(Opcode.DUP);
0672: cf.add(Opcode.INVOKESPECIAL, "java.lang.StringBuffer",
0673: "<init>", "()", "V");
0674: int n = node.jjtGetNumChildren();
0675: for (int i = 0; i < n; i++) {
0676: SimpleNode c = node.jjtGetChild(i);
0677: if (c.id == PnutsParserTreeConstants.JJTSTRINGNODE) {
0678: cf.pushString(c.str);
0679: } else {
0680: c.accept(this , context);
0681: cf.add(Opcode.INVOKESTATIC, "java.lang.String",
0682: "valueOf", "(Ljava/lang/Object;)",
0683: "Ljava/lang/String;");
0684: }
0685: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.StringBuffer",
0686: "append", "(Ljava/lang/String;)",
0687: "Ljava/lang/StringBuffer;");
0688: }
0689: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.StringBuffer",
0690: "toString", "()", "Ljava/lang/String;");
0691: }
0692: return null;
0693: }
0694:
0695: public Object characterNode(SimpleNode node, Context context) {
0696: CompileContext cc = (CompileContext) context;
0697: ClassFile cf = cc.cf;
0698: Character ch = (Character) node.info;
0699: String assoc = (String) cc.constants.get(ch);
0700: if (assoc == null) {
0701: assoc = gensym(context);
0702: cc.constants.put(ch, assoc);
0703: }
0704: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
0705: "Ljava/lang/Character;");
0706: return null;
0707: }
0708:
0709: public Object classNode(SimpleNode node, Context context) {
0710: CompileContext cc = (CompileContext) context;
0711: ClassFile cf = cc.cf;
0712: int ctx = cc.getContextIndex();
0713: addLineInfo(cc, ctx, node);
0714:
0715: SimpleNode c = node.jjtGetChild(0);
0716: if (c.id == PnutsParserTreeConstants.JJTCLASSNAME) {
0717: StringBuffer sbuf = new StringBuffer();
0718: sbuf.append(c.jjtGetChild(0).str);
0719: int n = c.jjtGetNumChildren();
0720: for (int i = 1; i < n; i++) {
0721: SimpleNode ch = c.jjtGetChild(i);
0722: sbuf.append('.');
0723: sbuf.append(ch.str);
0724: }
0725: String name = sbuf.toString();
0726: cf.add(Opcode.LDC, cf.addConstant(name));
0727: } else {
0728: c.accept(this , context);
0729: cf.add(Opcode.CHECKCAST, "java.lang.String");
0730: }
0731: cf.loadLocal(ctx);
0732: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Pnuts", "loadClass",
0733: "(Ljava/lang/String;Lpnuts/lang/Context;)",
0734: "Ljava/lang/Class;");
0735:
0736: return null;
0737: }
0738:
0739: static class MethodSignatureInfo {
0740: String methodName;
0741: SimpleNode returnTypeNode;
0742: SimpleNode[] paramTypeNodes;
0743: SimpleNode fnode;
0744: Map/*<String,Collection<SimpleNode>>*/this References;
0745: Map/*<String,SimpleNode>*/paramReferences;
0746: }
0747:
0748: static class ConstructorSignatureInfo extends MethodSignatureInfo {
0749: }
0750:
0751: static class FieldSignatureInfo {
0752: String fieldName;
0753: SimpleNode typeNode;
0754: //SimpleNode lhs;
0755: SimpleNode rhs;
0756: }
0757:
0758: /*
0759: * Transform methodef to function
0760: * Also, set attributes of MethodSignatureInfo
0761: */
0762: static SimpleNode buildMethodFunction(SimpleNode methodDef,
0763: MethodSignatureInfo siginfo, Set /**/super MethodNames) {
0764: SimpleNode n1 = methodDef.jjtGetChild(0);
0765: SimpleNode param;
0766: SimpleNode block;
0767: SimpleNode returnTypeNode = null;
0768: String symbol = methodDef.str;
0769: siginfo.methodName = symbol;
0770:
0771: if (n1.id == PnutsParserTreeConstants.JJTCLASSNAME
0772: || n1.id == PnutsParserTreeConstants.JJTARRAYTYPE) {
0773: returnTypeNode = n1;
0774: param = methodDef.jjtGetChild(1);
0775: block = methodDef.jjtGetChild(2);
0776: } else {
0777: param = methodDef.jjtGetChild(0);
0778: block = methodDef.jjtGetChild(1);
0779: }
0780:
0781: SimpleNode newParam = new SimpleNode(
0782: PnutsParserTreeConstants.JJTPARAMLIST);
0783:
0784: int nargs = param.jjtGetNumChildren();
0785: SimpleNode[] paramTypeNodes = new SimpleNode[nargs];
0786: siginfo.paramReferences = new HashMap();
0787: for (int k = 0; k < nargs; k++) {
0788: SimpleNode c = param.jjtGetChild(k);
0789: SimpleNode cp = param.jjtGetChild(k);
0790: if (c.jjtGetNumChildren() > 1) {
0791: cp = c.jjtGetChild(1);
0792: paramTypeNodes[k] = c.jjtGetChild(0);
0793: } else {
0794: cp = c.jjtGetChild(0);
0795: }
0796: siginfo.paramReferences.put(cp.str, cp);
0797: newParam.jjtAddChild(cp, k);
0798: }
0799: siginfo.paramTypeNodes = paramTypeNodes;
0800: siginfo.returnTypeNode = returnTypeNode;
0801: SimpleNode fnode = new SimpleNode(
0802: PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT);
0803: fnode.setAttribute("isMethod", Boolean.TRUE);
0804: fnode.info = methodDef.info;
0805: fnode.setAttribute("frameInfo", methodDef
0806: .getAttribute("frameInfo"));
0807: fnode.str = symbol;
0808: fnode.jjtAddChild(newParam, 0);
0809: fnode.jjtAddChild(block, 1);
0810: fnode.jjtSetParent(methodDef.jjtGetParent());
0811: Map/*<String,Collection<SimpleNode>>*/refs = collectThisReferences(
0812: block, super MethodNames);
0813: if (DEBUG) {
0814: System.out.println("ref = " + refs);
0815: }
0816: siginfo.this References = refs;
0817: return fnode;
0818: }
0819:
0820: static Map/*<String,SimpleNode>*/collectThisReferences(
0821: SimpleNode node, Set super MethodNames) {
0822: Map refs = new HashMap();
0823: collectThisReferences(node, refs, super MethodNames);
0824: return refs;
0825: }
0826:
0827: static void collectThisReferences(SimpleNode node,
0828: Map/*<String,SimpleNode>*/frefs, Set super MethodNames) {
0829: int n = node.jjtGetNumChildren();
0830: for (int i = 0; i < n; i++) {
0831: SimpleNode c = node.jjtGetChild(i);
0832: if (c.id == PnutsParserTreeConstants.JJTMEMBERNODE) {
0833: SimpleNode lhs = c.jjtGetChild(0);
0834: if ((lhs.id == PnutsParserTreeConstants.JJTIDNODE)
0835: && lhs.str == THIS) {
0836: Collection refset = (Collection) frefs.get(c.str);
0837: if (refset == null) {
0838: frefs.put(c.str, refset = new ArrayList());
0839: }
0840: refset.add(c);
0841: }
0842: } else if (c.id == PnutsParserTreeConstants.JJTMETHODNODE) {
0843: SimpleNode target = c.jjtGetChild(0);
0844: if (target.id == PnutsParserTreeConstants.JJTIDNODE
0845: && target.str == "super") {
0846: SimpleNode args = c.jjtGetChild(1);
0847: super MethodNames.add(c.str);
0848: }
0849: } else if (c.id != PnutsParserTreeConstants.JJTCLASSDEFBODY) {
0850: collectThisReferences(c, frefs, super MethodNames);
0851: }
0852: }
0853: }
0854:
0855: /*
0856: * Examine the methodDef node and returns MethodSignatureInfo
0857: * Also, define a function in the Package object stored at pkg
0858: */
0859: static MethodSignatureInfo handleMethodDef(SimpleNode methodDef,
0860: Set/**/super MethodNames) {
0861: MethodSignatureInfo siginfo = new MethodSignatureInfo();
0862: SimpleNode fnode = buildMethodFunction(methodDef, siginfo,
0863: super MethodNames);
0864: siginfo.fnode = fnode;
0865: if (DEBUG) {
0866: System.out.println(siginfo.this References);
0867: System.out.println(siginfo.paramReferences);
0868: }
0869: return siginfo;
0870: }
0871:
0872: static ConstructorSignatureInfo handleConstructorDef(
0873: SimpleNode defNode, Set super MethodNames) {
0874: ConstructorSignatureInfo siginfo = new ConstructorSignatureInfo();
0875: SimpleNode param = defNode.jjtGetChild(0);
0876: SimpleNode block = defNode.jjtGetChild(1);
0877: SimpleNode first = null;
0878:
0879: SimpleNode newParam = new SimpleNode(
0880: PnutsParserTreeConstants.JJTPARAMLIST);
0881:
0882: int nargs = param.jjtGetNumChildren();
0883: SimpleNode[] paramTypeNodes = new SimpleNode[nargs];
0884: siginfo.paramReferences = new HashMap();
0885: for (int k = 0; k < nargs; k++) {
0886: SimpleNode c = param.jjtGetChild(k);
0887: SimpleNode cp = param.jjtGetChild(k);
0888: if (c.jjtGetNumChildren() > 1) {
0889: cp = c.jjtGetChild(1);
0890: paramTypeNodes[k] = c.jjtGetChild(0);
0891: } else {
0892: cp = c.jjtGetChild(0);
0893: }
0894: siginfo.paramReferences.put(cp.str, cp);
0895: newParam.jjtAddChild(cp, k);
0896: }
0897: siginfo.paramTypeNodes = paramTypeNodes;
0898:
0899: SimpleNode fnode = new SimpleNode(
0900: PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT);
0901: fnode.setAttribute("isMethod", Boolean.TRUE);
0902: fnode.info = defNode.info;
0903: fnode.setAttribute("frameInfo", defNode
0904: .getAttribute("frameInfo"));
0905: siginfo.fnode = fnode;
0906:
0907: fnode.jjtAddChild(newParam, 0);
0908: fnode.jjtAddChild(block, 1);
0909:
0910: Map refs = collectThisReferences(block, super MethodNames);
0911: if (DEBUG) {
0912: System.out.println("ref = " + refs);
0913: }
0914: siginfo.this References = refs;
0915:
0916: return siginfo;
0917: }
0918:
0919: static FieldSignatureInfo handleFieldDef(SimpleNode defNode) {
0920: FieldSignatureInfo finfo = new FieldSignatureInfo();
0921: finfo.fieldName = defNode.str;
0922: boolean hasTypeNode = (defNode.jjtGetChild(0).id == PnutsParserTreeConstants.JJTCLASSNAME);
0923: if (hasTypeNode) {
0924: finfo.typeNode = defNode.jjtGetChild(0);
0925: }
0926: if (defNode.jjtGetNumChildren() > 1) {
0927: finfo.rhs = defNode.jjtGetChild(1);
0928: } else if (!hasTypeNode) {
0929: finfo.rhs = defNode.jjtGetChild(0);
0930: }
0931: //finfo.lhs = defNode.jjtGetChild(0);
0932: return finfo;
0933: }
0934:
0935: static void handleClassDefBody(SimpleNode classDefBody,
0936: List/*<MethodSignatureInfo>*/methodSigs,
0937: List/*<ConstructorSignatureInfo>*/constructorSigs,
0938: List/*<FieldSignatureInfo>*/fieldSigs, Set super MethodNames) {
0939: for (int i = 0; i < classDefBody.jjtGetNumChildren(); i++) {
0940: SimpleNode defNode = classDefBody.jjtGetChild(i);
0941: if (defNode.id == PnutsParserTreeConstants.JJTFIELDDEF) {
0942: fieldSigs.add(handleFieldDef(defNode));
0943: } else {
0944: SimpleNode n0 = defNode.jjtGetChild(0);
0945: if (n0.id != PnutsParserTreeConstants.JJTCLASSNAME
0946: && n0.id != PnutsParserTreeConstants.JJTARRAYNODE) {
0947: SimpleNode parent = classDefBody.jjtGetParent();
0948: if (parent.id == PnutsParserTreeConstants.JJTCLASSSCRIPT
0949: || parent.id == PnutsParserTreeConstants.JJTCLASSDEF) {
0950: if (defNode.str.equals(getClassName(parent
0951: .jjtGetChild(0)))) {
0952: /* constructor */
0953: constructorSigs.add(handleConstructorDef(
0954: defNode, super MethodNames));
0955: continue;
0956: }
0957: }
0958: }
0959: methodSigs.add(handleMethodDef(defNode,
0960: super MethodNames));
0961: }
0962: }
0963: }
0964:
0965: static void buildFieldDeclaration(FieldSignatureInfo fsig,
0966: List assignmentNodes) {
0967: if (fsig.rhs != null) {
0968: /*
0969: * this.fieldName = rhs
0970: */
0971: SimpleNode assign = new SimpleNode(
0972: PnutsParserTreeConstants.JJTASSIGNMENT);
0973: SimpleNode member = new SimpleNode(
0974: PnutsParserTreeConstants.JJTMEMBERNODE);
0975: SimpleNode id = new SimpleNode(
0976: PnutsParserTreeConstants.JJTIDNODE);
0977: id.str = THIS;
0978: member.str = fsig.fieldName;
0979: member.jjtAddChild(id, 0);
0980: assign.jjtAddChild(fsig.rhs, 1);
0981: assign.jjtAddChild(member, 0);
0982: assignmentNodes.add(assign);
0983: }
0984: }
0985:
0986: /**
0987: * Convert 'new type(){...}' to 'class name extends type {...}'
0988: */
0989: SimpleNode getClassDefNode(SimpleNode node, Context cc) {
0990: SimpleNode n0 = node.jjtGetChild(0);
0991: String super className = getClassName(n0);
0992: Class[] interfaces = null;
0993: Class super class = null;
0994:
0995: ClassSpec super typeSpec = ClassSpec.create(super className, cc);
0996: Class super type = super typeSpec.compileTimeClass;
0997: super className = super typeSpec.className;
0998:
0999: String className = super className.replace('.', '_')
1000: + "__adapter" + "$"
1001: + (classCount++ & 0x7fffffffffffffffL);
1002: SimpleNode classDefBody = node.jjtGetChild(2);
1003:
1004: List/*<MethodSignatureInfo>*/methodSigs = new ArrayList();
1005: List/*<ConstructorSignatureInfo>*/constructorSigs = new ArrayList();
1006: List/*<FieldSignatureInfo>*/fieldSigs = new ArrayList();
1007: Set super MethodNames = new HashSet();
1008: handleClassDefBody(classDefBody, methodSigs, constructorSigs,
1009: fieldSigs, super MethodNames);
1010:
1011: return getClassDefNode(className, super type != null
1012: && super type.isInterface(), n0, classDefBody);
1013: }
1014:
1015: static SimpleNode getClassDefNode(String className,
1016: boolean isInterface, SimpleNode typeNode,
1017: SimpleNode classDefBody) {
1018: SimpleNode def = new SimpleNode(
1019: PnutsParserTreeConstants.JJTCLASSDEF);
1020: SimpleNode classNameNode = new SimpleNode(
1021: PnutsParserTreeConstants.JJTCLASSNAME);
1022: SimpleNode _p = new SimpleNode(
1023: PnutsParserTreeConstants.JJTPACKAGE);
1024: _p.str = className;
1025: classNameNode.jjtAddChild(_p, 0);
1026: _p.jjtSetParent(classNameNode);
1027: SimpleNode ext = new SimpleNode(
1028: PnutsParserTreeConstants.JJTEXTENDS);
1029: SimpleNode imp = new SimpleNode(
1030: PnutsParserTreeConstants.JJTIMPLEMENTS);
1031: def.jjtAddChild(classNameNode, 0);
1032: classNameNode.jjtSetParent(def);
1033: if (isInterface) {
1034: imp.jjtAddChild(typeNode, 0);
1035: typeNode.jjtSetParent(imp);
1036: } else {
1037: ext.jjtAddChild(typeNode, 0);
1038: typeNode.jjtSetParent(ext);
1039: }
1040: def.jjtAddChild(ext, 1);
1041: ext.jjtSetParent(def);
1042: def.jjtAddChild(imp, 2);
1043: imp.jjtSetParent(def);
1044: def.jjtAddChild(classDefBody, 3);
1045: classDefBody.jjtSetParent(def);
1046: return def;
1047: }
1048:
1049: public Object newNode(SimpleNode node, Context context) {
1050: CompileContext cc = (CompileContext) context;
1051: ClassFile cf = cc.cf;
1052: int ctx = cc.getContextIndex();
1053: addLineInfo(cc, ctx, node);
1054:
1055: SimpleNode n0 = node.jjtGetChild(0);
1056:
1057: int n = node.jjtGetNumChildren();
1058: if (n == 3
1059: && node.jjtGetChild(2).id == PnutsParserTreeConstants.JJTCLASSDEFBODY) { // subclass
1060: String encodedNode = NodeUtil.saveNode(node);
1061: cf.add(Opcode.LDC, cf.addConstant(encodedNode));
1062: cf.loadLocal(ctx);
1063: cf.add(Opcode.INVOKESTATIC, "pnuts.compiler.Compiler",
1064: "buildSubclassInstance",
1065: "(Ljava/lang/String;Lpnuts/lang/Context;)",
1066: "Ljava/lang/Object;");
1067:
1068: } else if (n0.id == PnutsParserTreeConstants.JJTINDEXNODE) { // instantiation
1069: Object[] idx = parseIndex(n0);
1070: Object[] dim = (Object[]) idx[1];
1071: SimpleNode nameNode = (SimpleNode) idx[0];
1072:
1073: if (node.getAttribute("hasTryStatement") != null) {
1074: int[] vars = new int[dim.length];
1075: for (int i = 0; i < dim.length; i++) {
1076: int var = cf.getLocal();
1077: ((SimpleNode) dim[i]).accept(this , context);
1078: cf.storeLocal(var);
1079: vars[i] = var;
1080: }
1081: resolveClassName(nameNode, cc, ctx);
1082: cf.pushInteger(dim.length);
1083: cf.add(Opcode.NEWARRAY, Opcode.T_INT);
1084: for (int i = 0; i < dim.length; i++) {
1085: cf.add(Opcode.DUP);
1086: cf.pushInteger(i);
1087: cf.loadLocal(vars[i]);
1088: cf.add(Opcode.CHECKCAST, "java.lang.Number");
1089: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Number",
1090: "intValue", "()", "I");
1091: cf.add(Opcode.IASTORE);
1092: }
1093: for (int i = 0; i < dim.length; i++) {
1094: cf.freeLocal(vars[i]);
1095: }
1096: } else {
1097:
1098: resolveClassName(nameNode, cc, ctx);
1099:
1100: cf.pushInteger(dim.length);
1101: cf.add(Opcode.NEWARRAY, Opcode.T_INT);
1102: for (int i = 0; i < dim.length; i++) {
1103: cf.add(Opcode.DUP);
1104: cf.pushInteger(i);
1105: ((SimpleNode) dim[i]).accept(this , context);
1106:
1107: cf.add(Opcode.CHECKCAST, "java.lang.Number");
1108: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Number",
1109: "intValue", "()", "I");
1110: cf.add(Opcode.IASTORE);
1111: }
1112: }
1113: cf.add(Opcode.INVOKESTATIC, "java.lang.reflect.Array",
1114: "newInstance", "(Ljava/lang/Class;[I)",
1115: "Ljava/lang/Object;");
1116:
1117: } else if (n0.id == PnutsParserTreeConstants.JJTARRAYTYPE) {
1118: arrayType(n0, context);
1119:
1120: } else if (n0.id == PnutsParserTreeConstants.JJTARRAYNODE) {
1121: cf.loadLocal(ctx);
1122: accept(n0, 0, context);
1123: cf.add(Opcode.CHECKCAST, "java.lang.Class");
1124: // accept(n0, 1, context);
1125: _listElements(n0.jjtGetChild(1), context);
1126: cf.add(Opcode.ICONST_1);
1127: cf
1128: .add(
1129: Opcode.INVOKESTATIC,
1130: "pnuts.lang.Runtime",
1131: "cast",
1132: "(Lpnuts/lang/Context;Ljava/lang/Class;Ljava/lang/Object;Z)",
1133: "Ljava/lang/Object;");
1134:
1135: } else { // instantiation
1136:
1137: if (node.getAttribute("hasTryStatement") != null) {
1138: int arg = cf.getLocal();
1139: // accept(node, 1, context);
1140: _listElements(node.jjtGetChild(1), context);
1141: cf.storeLocal(arg);
1142: cf.loadLocal(ctx);
1143: SimpleNode nameNode = node.jjtGetChild(0);
1144: resolveClassName(nameNode, cc, ctx);
1145: cf.loadLocal(arg);
1146: cf.freeLocal(arg);
1147: } else {
1148: cf.loadLocal(ctx);
1149: SimpleNode nameNode = node.jjtGetChild(0);
1150: resolveClassName(nameNode, cc, ctx);
1151: // accept(node, 1, context);
1152: _listElements(node.jjtGetChild(1), context);
1153: }
1154: cf.add(Opcode.CHECKCAST, "[Ljava/lang/Object;");
1155: cf.add(Opcode.ACONST_NULL);
1156: cf
1157: .add(
1158: Opcode.INVOKESTATIC,
1159: "pnuts.lang.Runtime",
1160: "callConstructor",
1161: "(Lpnuts/lang/Context;Ljava/lang/Class;[Ljava/lang/Object;[Ljava/lang/Class;)",
1162: "Ljava/lang/Object;");
1163: }
1164:
1165: return null;
1166: }
1167:
1168: public Object classDef(SimpleNode node, Context context) {
1169: CompileContext cc = (CompileContext) context;
1170: ClassFile cf = cc.cf;
1171: int ctx = cc.getContextIndex();
1172: ClassGenerationResult r = generateClass(node, cc);
1173: ByteArrayOutputStream bout = new ByteArrayOutputStream();
1174: try {
1175: r.classFile.write(bout);
1176: } catch (IOException ioe) {
1177: ioe.printStackTrace();
1178: }
1179: byte[] bcode = bout.toByteArray();
1180: String encodedBytecode = NodeUtil.byteArrayToString(bcode,
1181: bcode.length);
1182: if (DEBUG) {
1183: System.out.println(encodedBytecode.length());
1184: }
1185: String className = r.classFile.getClassName();
1186: if (className != null) {
1187: cf.add(Opcode.LDC, cf.addConstant(className));
1188: } else {
1189: cf.add(Opcode.ACONST_NULL);
1190: }
1191: cf.add(Opcode.LDC, cf.addConstant(encodedBytecode));
1192: r.closureNode.accept(this , cc);
1193: cf.loadLocal(ctx);
1194: cf
1195: .add(
1196: Opcode.INVOKESTATIC,
1197: "pnuts.compiler.Compiler",
1198: "loadBytecode",
1199: "(Ljava/lang/String;Ljava/lang/String;Lpnuts/lang/PnutsFunction;Lpnuts/lang/Context;)",
1200: "Ljava/lang/Class;");
1201: return null;
1202: }
1203:
1204: static CodeLoader getCodeLoader(Context context) {
1205: ClassLoader cl = context.getCodeLoader();
1206: if (cl instanceof CodeLoader) {
1207: return (CodeLoader) cl;
1208: }
1209: ClassLoader classLoader = context.getClassLoader();
1210: if (classLoader == null) {
1211: classLoader = Thread.currentThread()
1212: .getContextClassLoader();
1213: }
1214: cl = createCodeLoader(classLoader, true);
1215: context.setCodeLoader(cl);
1216: Thread.currentThread().setContextClassLoader(cl);
1217: return (CodeLoader) cl;
1218: }
1219:
1220: /*
1221: * classDef/buildSubclassInstance
1222: */
1223: public ClassGenerationResult generateClass(SimpleNode node,
1224: Context context) {
1225: String className = getClassName(node.jjtGetChild(0));
1226: SimpleNode extendsNode = node.jjtGetChild(1);
1227: ClassSpec super classSpec;
1228: String super className = null;
1229: if (extendsNode.jjtGetNumChildren() == 1) {
1230: SimpleNode n = extendsNode.jjtGetChild(0);
1231: super classSpec = ClassSpec.create(getClassName(n), context);
1232: super className = super classSpec.className;
1233: } else {
1234: super classSpec = ClassSpec.create(Object.class);
1235: super className = "java.lang.Object";
1236: }
1237:
1238: Class compileTimeClass = super classSpec.compileTimeClass;
1239:
1240: SimpleNode implements Node = node.jjtGetChild(2);
1241: SimpleNode classDefBody = node.jjtGetChild(3);
1242:
1243: List interfaces = null;
1244: int nc = implements Node.jjtGetNumChildren();
1245: if (nc > 0) {
1246: interfaces = new ArrayList();
1247: for (int i = 0; i < nc; i++) {
1248: SimpleNode n = implements Node.jjtGetChild(i);
1249: interfaces.add(getClassName(n));
1250: }
1251: }
1252:
1253: ClassSpec[] compileTimeInterfaces = null;
1254: if (interfaces != null) {
1255: compileTimeInterfaces = new ClassSpec[interfaces.size()];
1256: for (int i = 0, n = interfaces.size(); i < n; i++) {
1257: String name = (String) interfaces.get(i);
1258: ClassSpec s = ClassSpec.create(name, context);
1259: compileTimeInterfaces[i] = s;
1260: }
1261: }
1262:
1263: CompileContext cc = new CompileContext(context);
1264: ClassFile cf = cc.cf;
1265:
1266: if (compileTimeClass != null) {
1267: ClassGenerator.transformClassDefBody(classDefBody,
1268: compileTimeClass);
1269: }
1270:
1271: CompileContext cc2 = (CompileContext) cc.clone(false, true);
1272: cc2.constClassName = className;
1273:
1274: return generateClass(className, null, classDefBody,
1275: super classSpec, compileTimeInterfaces, null, this , cc2);
1276:
1277: }
1278:
1279: public static Class attachClosure(Class cls, PnutsFunction closure,
1280: Context context) {
1281: try {
1282: Method method = cls.getMethod("attach", new Class[] {
1283: Context.class, PnutsFunction.class });
1284: method.invoke(null, new Object[] { context, closure });
1285: } catch (Exception e) {
1286: e.printStackTrace();
1287: }
1288: return cls;
1289: }
1290:
1291: public static Class loadBytecode(String name,
1292: String encodedBytecode, PnutsFunction closure,
1293: Context context) {
1294: CodeLoader loader = getCodeLoader(context);
1295: byte[] bcode = NodeUtil.stringToByteArray(encodedBytecode);
1296: System.out.println(name);
1297: Class cls = loader.define(name, bcode, 0, bcode.length);
1298: return attachClosure(cls, closure, context);
1299: }
1300:
1301: /*
1302: * Helper method for interpreter
1303: */
1304: public static Object buildSubclassInstance(String encodedNode,
1305: Context context) {
1306: CompilerPnutsImpl impl = (CompilerPnutsImpl) context
1307: .getImplementation();
1308: return impl.compiler.buildSubclassInstance(NodeUtil
1309: .loadNode(encodedNode), context);
1310: }
1311:
1312: public Object buildSubclassInstance(SimpleNode node, Context context) {
1313: SimpleNode def = getClassDefNode(node, context);
1314: Class cls = defineClass(def, context);
1315: Object[] arg = interpreter._listElements(node.jjtGetChild(1),
1316: context);
1317: return Runtime.callConstructor(context, cls, arg, null);
1318: }
1319:
1320: public Class defineClass(String encodedNode, Context context) {
1321: return defineClass(NodeUtil.loadNode(encodedNode), context);
1322: }
1323:
1324: public Class defineClass(SimpleNode node, Context context) {
1325:
1326: String className = getClassName(node.jjtGetChild(0));
1327: SimpleNode extendsNode = node.jjtGetChild(1);
1328: String super class = null;
1329: if (extendsNode.jjtGetNumChildren() == 1) {
1330: SimpleNode n = extendsNode.jjtGetChild(0);
1331: super class = getClassName(n);
1332: } else {
1333: super class = "java.lang.Object";
1334: }
1335:
1336: SimpleNode implements Node = node.jjtGetChild(2);
1337: SimpleNode classDefBody = node.jjtGetChild(3);
1338:
1339: List interfaces = null;
1340: int nc = implements Node.jjtGetNumChildren();
1341: if (nc > 0) {
1342: interfaces = new ArrayList();
1343: for (int i = 0; i < nc; i++) {
1344: SimpleNode n = implements Node.jjtGetChild(i);
1345: interfaces.add(getClassName(n));
1346: }
1347: }
1348:
1349: ClassSpec super classSpec = ClassSpec
1350: .create(super class, context);
1351: Class compileTimeClass = super classSpec.compileTimeClass;
1352:
1353: ClassSpec[] compileTimeInterfaces = null;
1354: if (interfaces != null) {
1355: compileTimeInterfaces = new ClassSpec[interfaces.size()];
1356: for (int i = 0, n = interfaces.size(); i < n; i++) {
1357: String name = (String) interfaces.get(i);
1358: ClassSpec s = ClassSpec.create(name, context);
1359: compileTimeInterfaces[i] = s;
1360: }
1361: }
1362:
1363: CompileContext cc = new CompileContext(context);
1364: ClassFile cf = cc.cf;
1365:
1366: ClassGenerator.transformClassDefBody(classDefBody,
1367: compileTimeClass);
1368:
1369: CompileContext cc2 = (CompileContext) cc.clone(false, true);
1370: cc2.constClassName = className;
1371:
1372: ClassGenerationResult cg = generateClass(className, null,
1373: classDefBody, super classSpec, compileTimeInterfaces,
1374: null, this , cc2);
1375:
1376: ClassFile cf2 = cg.classFile;
1377: PnutsFunction closure = (PnutsFunction) cg.closureNode.accept(
1378: interpreter, context);
1379:
1380: try {
1381: CodeLoader loader = getCodeLoader(context);
1382:
1383: Class cls = cc2.loadClasses(loader);
1384: Method m = cls.getMethod("attach", new Class[] {
1385: Context.class, PnutsFunction.class });
1386: m.invoke(null,
1387: new Object[] { new Context(context), closure });
1388: return cls;
1389: } catch (LinkageError e) {
1390: ClassLoader cl = compileTimeClass.getClassLoader();
1391: if (cl instanceof CodeLoader) {
1392: try {
1393: Class cls = cc2.loadClasses((CodeLoader) cl);
1394: Method m = cls.getMethod("attach", new Class[] {
1395: Context.class, PnutsFunction.class });
1396: m.invoke(null, new Object[] { new Context(context),
1397: closure });
1398: return cls;
1399: } catch (Exception e2) {
1400: }
1401: }
1402: throw new PnutsException(e, context);
1403: } catch (Exception ex) {
1404: throw new PnutsException(ex, context);
1405: }
1406: }
1407:
1408: public Object methodDef(SimpleNode node, Context context) {
1409: return null;
1410: }
1411:
1412: public Object classDefBody(SimpleNode node, Context context) {
1413: return null;
1414: }
1415:
1416: static Signature resolveSignature(MethodSignatureInfo methodSig,
1417: Context context) {
1418: Class returnType;
1419: if (methodSig.returnTypeNode != null) {
1420: returnType = interpreter.resolveType(
1421: methodSig.returnTypeNode, context);
1422: } else {
1423: returnType = null;
1424: }
1425: SimpleNode[] parameterTypeNodes = methodSig.paramTypeNodes;
1426: Class[] parameterTypes = null;
1427: if (parameterTypeNodes != null) {
1428: parameterTypes = new Class[parameterTypeNodes.length];
1429: for (int i = 0; i < parameterTypes.length; i++) {
1430: SimpleNode typeNode = parameterTypeNodes[i];
1431: if (typeNode != null) {
1432: parameterTypes[i] = interpreter.resolveType(
1433: typeNode, context);
1434: }
1435: }
1436: }
1437: return new Signature(methodSig.methodName, returnType,
1438: parameterTypes, null, methodSig.fnode);
1439: }
1440:
1441: static Signature resolveSignature(
1442: ConstructorSignatureInfo constructorSig, Context context) {
1443: SimpleNode[] parameterTypeNodes = constructorSig.paramTypeNodes;
1444: Class[] parameterTypes = null;
1445: if (parameterTypeNodes != null) {
1446: parameterTypes = new Class[parameterTypeNodes.length];
1447: for (int i = 0; i < parameterTypes.length; i++) {
1448: SimpleNode typeNode = parameterTypeNodes[i];
1449: if (typeNode != null) {
1450: parameterTypes[i] = interpreter.resolveType(
1451: typeNode, context);
1452: }
1453: }
1454: }
1455: return new Signature(null, null, parameterTypes, null,
1456: constructorSig.fnode);
1457: }
1458:
1459: static String[] split(String s, char delim) {
1460: ArrayList list = new ArrayList();
1461: int offset = 0;
1462: int idx = 0;
1463: while (idx >= 0) {
1464: idx = s.indexOf(delim, offset);
1465: if (idx > 0) {
1466: list.add(s.substring(offset, idx));
1467: offset = idx + 1;
1468: }
1469: }
1470: list.add(s.substring(offset));
1471: return (String[]) list.toArray(new String[list.size()]);
1472: }
1473:
1474: public static class ClassGenerationResult {
1475: public ClassFile classFile;
1476: public SimpleNode closureNode;
1477: }
1478:
1479: static ClassGenerationResult generateClass(String className,
1480: String scriptFile, SimpleNode classDefBody,
1481: ClassSpec super classSpec, ClassSpec[] interfaces,
1482: List importNodes, Compiler compiler, CompileContext cc) {
1483: List/*<MethodSignatureInfo>*/methodSigs = new ArrayList();
1484: List/*<ConstructorSignatureInfo>*/constructorSigs = new ArrayList();
1485: List/*<FieldSignatureInfo>*/fieldSigs = new ArrayList();
1486: Set super MethodNames = new HashSet();
1487: handleClassDefBody(classDefBody, methodSigs, constructorSigs,
1488: fieldSigs, super MethodNames);
1489: return generateClass(className, scriptFile, methodSigs,
1490: constructorSigs, fieldSigs, super MethodNames,
1491: super classSpec, interfaces, importNodes, compiler, cc);
1492: }
1493:
1494: static void updateMethodSignatureInfo(MethodSignatureInfo sig,
1495: String fieldName) {
1496: SimpleNode fnode = sig.fnode;
1497: Map this References = sig.this References;
1498: Collection refs = (Collection) this References.get(fieldName);
1499: if (refs != null) {
1500: Map params = sig.paramReferences;
1501: SimpleNode paramNode = (SimpleNode) params.get(fieldName);
1502: if (paramNode != null) {
1503: paramNode.str = (" " + paramNode.str).intern();
1504: renameIDs(fnode, fieldName);
1505: }
1506: for (Iterator it = refs.iterator(); it.hasNext();) {
1507: SimpleNode node = (SimpleNode) it.next();
1508: node.id = PnutsParserTreeConstants.JJTIDNODE;
1509: node.clearChildren();
1510: }
1511: }
1512: }
1513:
1514: static void renameIDs(SimpleNode node, String name) {
1515: int id = node.id;
1516: if (id == PnutsParserTreeConstants.JJTIDNODE) {
1517: if (node.str == name) {
1518: SimpleNode parent = node.jjtGetParent();
1519: if (parent == null
1520: || parent.id != PnutsParserTreeConstants.JJTMEMBERNODE) {
1521: node.str = (" " + name).intern();
1522: }
1523: }
1524: } else if (id != PnutsParserTreeConstants.JJTCLASSDEF) {
1525: int n = node.jjtGetNumChildren();
1526: for (int i = 0; i < n; i++) {
1527: renameIDs(node.jjtGetChild(i), name);
1528: }
1529: }
1530: }
1531:
1532: static void updateMethodSignatureInfo(
1533: List/*<MethodSignatureInfo>*/sigs, String fieldName) {
1534: for (int i = 0, n = sigs.size(); i < n; i++) {
1535: updateMethodSignatureInfo(
1536: (MethodSignatureInfo) sigs.get(i), fieldName);
1537: }
1538: }
1539:
1540: static SimpleNode buildClosureNode(List/*<SimpleNode>*/nodes,
1541: List/*<FieldSignatureInfo>*/fieldSigs, Map typeMap) {
1542: SimpleNode block = new SimpleNode(
1543: PnutsParserTreeConstants.JJTBLOCK);
1544:
1545: SimpleNode listElements = new SimpleNode(
1546: PnutsParserTreeConstants.JJTLISTELEMENTS);
1547: block.jjtAddChild(listElements, fieldSigs.size() + 1);
1548: listElements.jjtSetParent(block);
1549: for (int i = nodes.size() - 1; i >= 0; i--) {
1550: SimpleNode n = (SimpleNode) nodes.get(i);
1551: listElements.jjtAddChild(n, i);
1552: n.jjtSetParent(listElements);
1553: }
1554: for (int i = 0, n = fieldSigs.size(); i < n; i++) {
1555: FieldSignatureInfo finfo = (FieldSignatureInfo) fieldSigs
1556: .get(i);
1557: String fieldName = finfo.fieldName;
1558: SimpleNode rhs = finfo.rhs;
1559: SimpleNode var = new SimpleNode(
1560: PnutsParserTreeConstants.JJTIDNODE);
1561: var.str = fieldName;
1562: SimpleNode assignment = new SimpleNode(
1563: PnutsParserTreeConstants.JJTASSIGNMENT);
1564: if (rhs == null) {
1565: Class type = (Class) typeMap.get(fieldName);
1566: if (type.isPrimitive()) {
1567: if (type == boolean.class) {
1568: rhs = new SimpleNode(
1569: PnutsParserTreeConstants.JJTFALSENODE);
1570: } else {
1571: rhs = new SimpleNode(
1572: PnutsParserTreeConstants.JJTINTEGERNODE);
1573: rhs.info = new Object[] { new Integer(0), null };
1574: }
1575: } else {
1576: rhs = new SimpleNode(
1577: PnutsParserTreeConstants.JJTNULLNODE);
1578: }
1579: }
1580: assignment.jjtAddChild(rhs, 1);
1581: rhs.jjtSetParent(assignment);
1582: assignment.jjtAddChild(var, 0);
1583: block.jjtAddChild(assignment, i + 1);
1584: }
1585: SimpleNode super Assignment = new SimpleNode(
1586: PnutsParserTreeConstants.JJTASSIGNMENT);
1587: SimpleNode super ID = new SimpleNode(
1588: PnutsParserTreeConstants.JJTIDNODE);
1589: super ID.str = SUPER;
1590: block.jjtAddChild(super Assignment, 0);
1591: super Assignment.jjtSetParent(super Assignment);
1592:
1593: SimpleNode closure = new SimpleNode(
1594: PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT);
1595: SimpleNode paramList = new SimpleNode(
1596: PnutsParserTreeConstants.JJTPARAMLIST);
1597:
1598: SimpleNode this Param = new SimpleNode(
1599: PnutsParserTreeConstants.JJTPARAM);
1600: this Param.str = THIS;
1601: SimpleNode super Creation = new SimpleNode(
1602: PnutsParserTreeConstants.JJTNEW);
1603: super Assignment.jjtAddChild(super Creation, 1);
1604: super Assignment.jjtAddChild(super ID, 0);
1605: SimpleNode typeNode = new SimpleNode(
1606: PnutsParserTreeConstants.JJTCLASSNAME);
1607: SimpleNode pkg0 = new SimpleNode(
1608: PnutsParserTreeConstants.JJTPACKAGE);
1609: pkg0.str = "pnuts";
1610: SimpleNode pkg1 = new SimpleNode(
1611: PnutsParserTreeConstants.JJTPACKAGE);
1612: pkg1.str = "compiler";
1613: SimpleNode pkg2 = new SimpleNode(
1614: PnutsParserTreeConstants.JJTPACKAGE);
1615: pkg2.str = "ClassGenerator$SuperCallProxy";
1616: typeNode.jjtAddChild(pkg2, 2);
1617: typeNode.jjtAddChild(pkg1, 1);
1618: typeNode.jjtAddChild(pkg0, 0);
1619: SimpleNode arg = new SimpleNode(
1620: PnutsParserTreeConstants.JJTLISTELEMENTS);
1621: SimpleNode this Node = new SimpleNode(
1622: PnutsParserTreeConstants.JJTIDNODE);
1623: this Node.str = THIS;
1624: arg.jjtAddChild(this Node, 0);
1625: super Creation.jjtAddChild(arg, 1);
1626: super Creation.jjtAddChild(typeNode, 0);
1627:
1628: paramList.jjtAddChild(this Param, 0);
1629: this Param.jjtSetParent(paramList);
1630:
1631: closure.jjtAddChild(block, 1);
1632: closure.jjtAddChild(paramList, 0);
1633: block.jjtSetParent(closure);
1634: paramList.jjtSetParent(closure);
1635:
1636: if (DEBUG) {
1637: System.out.println(closure.unparse());
1638: }
1639: return closure;
1640:
1641: }
1642:
1643: /*
1644: * intermediate results:
1645: * methodIDs
1646: * signatureList
1647: * closure
1648: */
1649: static ClassGenerationResult generateClass(String className,
1650: String scriptFile,
1651: List/*<MethodSignatureInfo>*/methodSigs,
1652: List/*<ConstructorSignatureInfo>*/constructorSigs,
1653: List/*<FieldSignatureInfo>*/fieldSigs,
1654: Set super MethodNames, ClassSpec super classSpec,
1655: ClassSpec[] interfaces, List importNodes,
1656: Compiler compiler, CompileContext cc) {
1657: Class super class = super classSpec.compileTimeClass;
1658: String super className = super classSpec.className;
1659: /*
1660: * instance fields
1661: */
1662: Map typeMap = new HashMap();
1663: for (int i = 0, n = fieldSigs.size(); i < n; i++) {
1664: FieldSignatureInfo finfo = (FieldSignatureInfo) fieldSigs
1665: .get(i);
1666: String fieldName = finfo.fieldName;
1667:
1668: updateMethodSignatureInfo(methodSigs, fieldName);
1669: updateMethodSignatureInfo(constructorSigs, fieldName);
1670: SimpleNode rhs = finfo.rhs;
1671:
1672: Class type = (finfo.typeNode != null) ? interpreter
1673: .resolveType(finfo.typeNode, cc) : Object.class;
1674: typeMap.put(fieldName, type);
1675:
1676: }
1677:
1678: Set/*<Signature>*/signatureSet = new HashSet();
1679: for (int i = 0, n = methodSigs.size(); i < n; i++) {
1680: MethodSignatureInfo sig = (MethodSignatureInfo) methodSigs
1681: .get(i);
1682: Signature s = resolveSignature(sig, cc);
1683: Class[] parameterTypes;
1684: Class[] exceptionTypes;
1685: Class returnType;
1686: int modifiers;
1687: boolean resolved = s.isResolved();
1688: if (!resolved) {
1689: String methodName = s.getMethodName();
1690: int n_types = s.getParameterTypes().length;
1691: String prop = null;
1692: if (n_types == 0) {
1693: if (methodName.startsWith("get")) {
1694: prop = decapitalize(methodName.substring(3));
1695: Class t = (Class) typeMap.get(prop);
1696: Class t2 = s.getReturnType();
1697: if (t != null && (t2 == null || t2.equals(t))) {
1698: returnType = t;
1699: s.setReturnType(returnType);
1700: s.setModifiers(Modifier.PUBLIC);
1701: }
1702: } else if (methodName.startsWith("is")) {
1703: prop = decapitalize(methodName.substring(2));
1704: Class t = (Class) typeMap.get(prop);
1705: Class t2 = s.getReturnType();
1706: if (t != null && t2 == null) {
1707: returnType = t;
1708: s.setReturnType(returnType);
1709: s.setModifiers(Modifier.PUBLIC);
1710: }
1711: }
1712: } else if (n_types == 1 && methodName.startsWith("set")) {
1713: prop = decapitalize(methodName.substring(3));
1714: Class p = s.getParameterTypes()[0];
1715: Class t = (Class) typeMap.get(prop);
1716: Class t2 = s.getReturnType();
1717: if (t != null && p == null
1718: && (t2 == null || t2.equals(void.class))) {
1719: parameterTypes = new Class[] { t };
1720: returnType = void.class;
1721: s.setReturnType(returnType);
1722: s.setParameterTypes(parameterTypes);
1723: s.setModifiers(Modifier.PUBLIC);
1724: }
1725: }
1726: }
1727:
1728: List/*<Method>*/methods = new ArrayList();
1729: Class[] interfaceTypes = null;
1730: if (interfaces != null) {
1731: interfaceTypes = new Class[interfaces.length];
1732: for (int j = 0; j < interfaces.length; j++) {
1733: interfaceTypes[j] = interfaces[j].compileTimeClass;
1734: }
1735: }
1736: if (super class != null
1737: && s.resolve(super class, interfaceTypes, methods)) {
1738: for (int j = 0, n2 = methods.size(); j < n2; j++) {
1739: Method first = (Method) methods.get(j);
1740: parameterTypes = first.getParameterTypes();
1741: returnType = first.getReturnType();
1742: exceptionTypes = first.getExceptionTypes();
1743: modifiers = Constants.ACC_PUBLIC;
1744:
1745: Signature s2 = (Signature) s.clone();
1746: s2.setParameterTypes(parameterTypes);
1747: s2.setReturnType(returnType);
1748: s2.setExceptionTypes(exceptionTypes);
1749: s2.setModifiers(Constants.ACC_PUBLIC);
1750:
1751: signatureSet.add(s2);
1752: }
1753:
1754: } else {
1755: parameterTypes = s.getParameterTypes();
1756: returnType = s.getReturnType();
1757: if (returnType == null) {
1758: returnType = Object.class;
1759: }
1760: exceptionTypes = new Class[0];
1761: for (int j = 0; j < parameterTypes.length; j++) {
1762: if (parameterTypes[j] == null) {
1763: parameterTypes[j] = Object.class;
1764: }
1765: }
1766: modifiers = Constants.ACC_PUBLIC;
1767:
1768: Signature s2 = (Signature) s.clone();
1769: s2.setParameterTypes(parameterTypes);
1770: s2.setReturnType(returnType);
1771: s2.setExceptionTypes(exceptionTypes);
1772: s2.setModifiers(Constants.ACC_PUBLIC);
1773:
1774: signatureSet.add(s2);
1775: }
1776: }
1777:
1778: List/*<String>*/methodIDs = new ArrayList();
1779: List/*<Signature>*/signatureList = new ArrayList();
1780: List/*<Signature>*/constructorSignatureList = new ArrayList();
1781: List/*<SimpleNode>*/nodes = new ArrayList();
1782:
1783: for (int i = 0, n = constructorSigs.size(); i < n; i++) {
1784: ConstructorSignatureInfo constructorSig = (ConstructorSignatureInfo) constructorSigs
1785: .get(i);
1786: Signature sig = resolveSignature(constructorSig, cc);
1787: constructorSignatureList.add(sig);
1788: List constructors = new ArrayList();
1789: Class[] parameterTypes;
1790: Class[] exceptionTypes;
1791: if (super class != null
1792: && sig.resolveAsConstructor(super class,
1793: constructors)) {
1794: for (int j = 0, n2 = constructors.size(); j < n2; j++) {
1795: Constructor cons = (Constructor) constructors
1796: .get(j);
1797: parameterTypes = cons.getParameterTypes();
1798: exceptionTypes = cons.getExceptionTypes();
1799: String constructorSignature = ClassFile
1800: .signature(parameterTypes);
1801:
1802: Signature s2 = (Signature) sig.clone();
1803: s2.setParameterTypes(parameterTypes);
1804: s2.setReturnType(void.class);
1805: s2.setExceptionTypes(exceptionTypes);
1806: s2.setModifiers(Constants.ACC_PUBLIC);
1807: signatureSet.add(s2);
1808: }
1809: } else {
1810: parameterTypes = sig.getParameterTypes();
1811: exceptionTypes = new Class[0];
1812: for (int j = 0; j < parameterTypes.length; j++) {
1813: if (parameterTypes[j] == null) {
1814: parameterTypes[j] = Object.class;
1815: }
1816: }
1817:
1818: Signature s2 = (Signature) sig.clone();
1819: s2.setParameterTypes(parameterTypes);
1820: s2.setReturnType(void.class);
1821: s2.setExceptionTypes(exceptionTypes);
1822: s2.setModifiers(Constants.ACC_PUBLIC);
1823:
1824: signatureSet.add(s2);
1825: }
1826: }
1827:
1828: HashMap readableAttributes = new HashMap();
1829: HashMap writableAttributes = new HashMap();
1830:
1831: for (Iterator it = typeMap.entrySet().iterator(); it.hasNext();) {
1832: Map.Entry entry = (Map.Entry) it.next();
1833: String name = (String) entry.getKey();
1834: Class type = (Class) entry.getValue();
1835: Signature s = getterSignature(type, name);
1836: if (!signatureSet.contains(s)) {
1837: readableAttributes.put(name, type);
1838: }
1839:
1840: s = setterSignature(type, name);
1841: if (!signatureSet.contains(s)) {
1842: writableAttributes.put(name, type);
1843: }
1844: }
1845: if (DEBUG) {
1846: System.out.println("readableAttributes are "
1847: + readableAttributes);
1848: System.out.println("writableAttributes are "
1849: + writableAttributes);
1850: }
1851: for (Iterator it = signatureSet.iterator(); it.hasNext();) {
1852: Signature sig = (Signature) it.next();
1853: SimpleNode node = (SimpleNode) sig.nodeInfo;
1854: nodes.add(loadNode(saveNode(node)));
1855: String mid = sig.toJavaIdentifier();
1856: signatureList.add(sig);
1857: methodIDs.add(mid);
1858: }
1859: for (Iterator it = readableAttributes.entrySet().iterator(); it
1860: .hasNext();) {
1861: Map.Entry entry = (Map.Entry) it.next();
1862: String name = (String) entry.getKey();
1863: Class type = (Class) entry.getValue();
1864: SimpleNode getterNode = buildGetterNode(type, name);
1865: nodes.add(getterNode);
1866: Signature sig = new Signature(getterNode.str, type,
1867: new Class[0], new Class[0], Constants.ACC_PUBLIC);
1868: String mid = sig.toJavaIdentifier();
1869: signatureList.add(sig);
1870: methodIDs.add(mid);
1871: }
1872: for (Iterator it = writableAttributes.entrySet().iterator(); it
1873: .hasNext();) {
1874: Map.Entry entry = (Map.Entry) it.next();
1875: String name = (String) entry.getKey();
1876: Class type = (Class) entry.getValue();
1877: SimpleNode setterNode = buildSetterNode(type, name);
1878: nodes.add(setterNode);
1879: Signature sig = new Signature(setterNode.str, void.class,
1880: new Class[] { type }, new Class[0],
1881: Constants.ACC_PUBLIC);
1882: String mid = sig.toJavaIdentifier();
1883: signatureList.add(sig);
1884: methodIDs.add(mid);
1885: }
1886: if (DEBUG) {
1887: System.out.println("methodIDs = " + methodIDs);
1888: System.out.println("signatureList = " + signatureList);
1889: }
1890:
1891: SimpleNode closure = buildClosureNode(nodes, fieldSigs, typeMap);
1892:
1893: /*
1894: * className, superclass, interfaces, superMethodNames,signatureList, constructorSignatureList, cc, methodIDs
1895: */
1896: cc.cf = ClassGenerator.createClassFile(className,
1897: super classSpec, interfaces, super MethodNames);
1898: ClassFile cf = cc.cf;
1899:
1900: ClassGenerator.constructor(cf, super classSpec, compiler, cc,
1901: constructorSignatureList);
1902:
1903: for (int i = 0, n = methodIDs.size(); i < n; i++) {
1904: String mid = (String) methodIDs.get(i);
1905: cf.addField(mid, "Lpnuts/lang/PnutsFunction;",
1906: Constants.ACC_PRIVATE);
1907: Signature sig = (Signature) signatureList.get(i);
1908: String methodName = sig.getMethodName();
1909: if (methodName != null) {
1910: ClassGenerator.defineMethod(cf,
1911: sig.getParameterTypes(), sig.getReturnType(),
1912: sig.getExceptionTypes(), sig.getModifiers(),
1913: sig.getMethodName(), sig.getMethodName()
1914: + ClassFile.signature(sig
1915: .getParameterTypes()), mid);
1916: }
1917:
1918: }
1919:
1920: cf.openMethod("__initialize", "()V", Constants.ACC_PRIVATE);
1921: cf.add(Opcode.GETSTATIC, className, METHOD_FACTORY_FUNCTION,
1922: "Lpnuts/lang/PnutsFunction;");
1923: cf.add(Opcode.ICONST_1);
1924: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
1925: cf.add(Opcode.DUP);
1926: cf.add(Opcode.ICONST_0);
1927: cf.add(Opcode.ALOAD_0);
1928: cf.add(Opcode.AASTORE);
1929: cf.add(Opcode.GETSTATIC, className, "_context",
1930: "Lpnuts/lang/Context;");
1931: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
1932: "call", "([Ljava/lang/Object;Lpnuts/lang/Context;)",
1933: "Ljava/lang/Object;");
1934: cf.add(Opcode.CHECKCAST, "[Ljava/lang/Object;");
1935: int array = cf.getLocal();
1936: cf.storeLocal(array);
1937:
1938: for (int i = 0; i < methodIDs.size(); i++) {
1939: cf.add(Opcode.ALOAD_0);
1940: cf.loadLocal(array);
1941: cf.pushInteger(i);
1942: cf.add(Opcode.AALOAD);
1943: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
1944: cf.add(Opcode.PUTFIELD, className, (String) methodIDs
1945: .get(i), "Lpnuts/lang/PnutsFunction;");
1946: }
1947: cf.add(Opcode.RETURN);
1948: cf.closeMethod();
1949:
1950: /*
1951: * public static void attach(Context);
1952: */
1953: cf.openMethod("attach", "(Lpnuts/lang/Context;)V",
1954: (short) (Constants.ACC_PUBLIC | Constants.ACC_STATIC));
1955: cc.setContextIndex(0);
1956: cc.hasAttachMethod = true;
1957: cf.add(Opcode.ALOAD_0);
1958: cf.add(Opcode.PUTSTATIC, className, "_context",
1959: "Lpnuts/lang/Context;");
1960: cf.add(Opcode.RETURN);
1961: cf.closeMethod();
1962:
1963: /*
1964: * public static void attach(Context, PnutsFunction);
1965: */
1966: cf.openMethod("attach",
1967: "(Lpnuts/lang/Context;Lpnuts/lang/PnutsFunction;)V",
1968: (short) (Constants.ACC_PUBLIC | Constants.ACC_STATIC));
1969: cc.setContextIndex(0);
1970: cc.hasAttachMethod = true;
1971: cf.add(Opcode.ALOAD_0);
1972: cf.add(Opcode.PUTSTATIC, className, "_context",
1973: "Lpnuts/lang/Context;");
1974: cf.add(Opcode.ALOAD_1);
1975: cf.add(Opcode.PUTSTATIC, className, METHOD_FACTORY_FUNCTION,
1976: "Lpnuts/lang/PnutsFunction;");
1977: cf.add(Opcode.RETURN);
1978: cf.closeMethod();
1979:
1980: /*
1981: * static {}
1982: */
1983: compiler.staticBlock(cf, (scriptFile != null) ? closure : null,
1984: cc);
1985:
1986: ClassGenerationResult result = new ClassGenerationResult();
1987: result.classFile = cf;
1988: result.closureNode = closure;
1989: return result;
1990: }
1991:
1992: static SimpleNode buildSetterNode(Class type, String name) {
1993: SimpleNode n = new SimpleNode(
1994: PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT);
1995: SimpleNode p = new SimpleNode(
1996: PnutsParserTreeConstants.JJTPARAMLIST);
1997: SimpleNode p0 = new SimpleNode(
1998: PnutsParserTreeConstants.JJTPARAM);
1999: p0.str = ("_" + name).intern();
2000: p.jjtAddChild(p0, 0);
2001: SimpleNode block = new SimpleNode(
2002: PnutsParserTreeConstants.JJTBLOCK);
2003: SimpleNode assign = new SimpleNode(
2004: PnutsParserTreeConstants.JJTASSIGNMENT);
2005: SimpleNode lhs = new SimpleNode(
2006: PnutsParserTreeConstants.JJTIDNODE);
2007: SimpleNode rhs = new SimpleNode(
2008: PnutsParserTreeConstants.JJTIDNODE);
2009: lhs.str = name;
2010: rhs.str = p0.str;
2011: assign.jjtAddChild(rhs, 1);
2012: assign.jjtAddChild(lhs, 0);
2013: block.jjtAddChild(assign, 0);
2014: n.jjtAddChild(block, 1);
2015: n.jjtAddChild(p, 0);
2016: n.str = ("set" + Character.toUpperCase(name.charAt(0)) + name
2017: .substring(1)).intern();
2018: return n;
2019: }
2020:
2021: static SimpleNode buildGetterNode(Class type, String name) {
2022: SimpleNode n = new SimpleNode(
2023: PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT);
2024: SimpleNode p = new SimpleNode(
2025: PnutsParserTreeConstants.JJTPARAMLIST);
2026: SimpleNode block = new SimpleNode(
2027: PnutsParserTreeConstants.JJTBLOCK);
2028: SimpleNode id = new SimpleNode(
2029: PnutsParserTreeConstants.JJTIDNODE);
2030: id.str = name;
2031: block.jjtAddChild(id, 0);
2032: n.jjtAddChild(block, 1);
2033: n.jjtAddChild(p, 0);
2034: String prefix = (type == boolean.class) ? "is" : "get";
2035: n.str = (prefix + Character.toUpperCase(name.charAt(0)) + name
2036: .substring(1)).intern();
2037: return n;
2038: }
2039:
2040: static String capitalize(String name) {
2041: if (name == null || name.length() == 0) {
2042: return name;
2043: }
2044: return name.substring(0, 1).toUpperCase() + name.substring(1);
2045: }
2046:
2047: static String decapitalize(String name) {
2048: if (name == null || name.length() == 0) {
2049: return name;
2050: }
2051: if (name.length() > 1 && Character.isUpperCase(name.charAt(1))
2052: && Character.isUpperCase(name.charAt(0))) {
2053: return name;
2054: }
2055: char chars[] = name.toCharArray();
2056: chars[0] = Character.toLowerCase(chars[0]);
2057: return new String(chars);
2058: }
2059:
2060: static final Class[] NO_PARAM = new Class[0];
2061:
2062: public static Signature getterSignature(Class type, String name) {
2063: String prefix;
2064: if (type == boolean.class) {
2065: prefix = "is";
2066: } else {
2067: prefix = "get";
2068: }
2069: return new Signature(prefix + capitalize(name), type, NO_PARAM,
2070: NO_PARAM, Modifier.PUBLIC);
2071: }
2072:
2073: public static Signature setterSignature(Class type, String name) {
2074: String prefix = "set";
2075: return new Signature(prefix + capitalize(name), void.class,
2076: new Class[] { type }, NO_PARAM, Modifier.PUBLIC);
2077: }
2078:
2079: /*
2080: * classScript->generateClass
2081: */
2082: void generateClass(SimpleNode classDefBody, String className,
2083: ClassSpec super classSpec, List/*<ClassSpec>*/interfaces,
2084: List importNodes, CompileContext cc) {
2085: String scriptFile = null;
2086: if (cc.scriptSource instanceof URL) {
2087: String file = ((URL) cc.scriptSource).getFile();
2088: int idx = file.lastIndexOf('/');
2089: if (idx < 0) {
2090: scriptFile = file;
2091: } else {
2092: scriptFile = file.substring(idx + 1);
2093: }
2094: } else if (cc.scriptSource instanceof File) {
2095: scriptFile = ((File) cc.scriptSource).getName();
2096: }
2097: cc.constClassName = className;
2098:
2099: Class super class = super classSpec.compileTimeClass;
2100: ClassSpec[] interfaceArray;
2101: if (interfaces != null) {
2102: interfaceArray = (ClassSpec[]) interfaces
2103: .toArray(new ClassSpec[interfaces.size()]);
2104: } else {
2105: interfaceArray = new ClassSpec[0];
2106: }
2107:
2108: ClassGenerator.transformClassDefBody(classDefBody, super class);
2109:
2110: generateClass(className, scriptFile, classDefBody,
2111: super classSpec, interfaceArray, importNodes, this , cc);
2112: }
2113:
2114: public Object classScript(SimpleNode node, Context context) {
2115: int num = node.jjtGetNumChildren();
2116: List importNodes = new ArrayList();
2117: SimpleNode packageNode = null;
2118: for (int i = 0; i < num; i++) {
2119: SimpleNode n = node.jjtGetChild(i);
2120: if (n.id == PnutsParserTreeConstants.JJTPACKAGESTATEMENT) {
2121: packageNode = n;
2122: } else if (n.id == PnutsParserTreeConstants.JJTIMPORT) {
2123: importNodes.add(n);
2124: n.accept(interpreter, context);
2125: } else if (n.id == PnutsParserTreeConstants.JJTCLASSDEF) {
2126: String className;
2127: if (packageNode != null) {
2128: className = packageName(packageNode) + "."
2129: + getClassName(n.jjtGetChild(0));
2130: } else {
2131: className = getClassName(n.jjtGetChild(0));
2132: }
2133:
2134: SimpleNode extendsNode = n.jjtGetChild(1);
2135: String super class = null;
2136: ClassSpec super classSpec;
2137: if (extendsNode.jjtGetNumChildren() == 1) {
2138: SimpleNode n0 = extendsNode.jjtGetChild(0);
2139: super classSpec = ClassSpec.create(getClassName(n0),
2140: context);
2141: super class = super classSpec.className;
2142: } else {
2143: super class = "java.lang.Object";
2144: super classSpec = ClassSpec.create(super class,
2145: context);
2146: }
2147:
2148: List interfaces = null;
2149: SimpleNode implements Node = n.jjtGetChild(2);
2150: int nc = implements Node.jjtGetNumChildren();
2151: if (nc > 0) {
2152: interfaces = new ArrayList();
2153: for (int j = 0; j < nc; j++) {
2154: SimpleNode nj = implements Node.jjtGetChild(j);
2155: String typename = getClassName(nj);
2156: ClassSpec spec = ClassSpec.create(typename,
2157: context);
2158: interfaces.add(spec);
2159: }
2160: }
2161: SimpleNode classDefBody = n.jjtGetChild(3);
2162: this .className = className;
2163: CompileContext cc = (CompileContext) context;
2164:
2165: generateClass(classDefBody, className, super classSpec,
2166: interfaces, importNodes, cc);
2167: return null;
2168: } else {
2169: throw new InternalError();
2170: }
2171: }
2172: throw new InternalError();
2173: }
2174:
2175: static String packageName(SimpleNode node) {
2176: StringBuffer sbuf = new StringBuffer();
2177: sbuf.append(node.jjtGetChild(0).str);
2178: for (int i = 1, n = node.jjtGetNumChildren(); i < n; i++) {
2179: sbuf.append('.');
2180: sbuf.append(node.jjtGetChild(i).str);
2181: }
2182: return sbuf.toString();
2183: }
2184:
2185: public Object packageNode(SimpleNode node, Context context) {
2186: CompileContext cc = (CompileContext) context;
2187: ClassFile cf = cc.cf;
2188: int ctx = cc.getContextIndex();
2189: int n = node.jjtGetNumChildren();
2190: cf.add(Opcode.GETSTATIC, "pnuts.lang.PnutsFunction", "PACKAGE",
2191: "Lpnuts/lang/PnutsFunction;");
2192: if (n == 0) {
2193: if ("(".equals(node.str)) {
2194: cf.add(Opcode.GETSTATIC, className, "NO_PARAM",
2195: "[Ljava/lang/Object;");
2196: cf.loadLocal(ctx);
2197: cf.add(Opcode.INVOKEVIRTUAL,
2198: "pnuts.lang.PnutsFunction", "call",
2199: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
2200: "Ljava/lang/Object;");
2201: } else {
2202: return null;
2203: }
2204: } else {
2205: SimpleNode c = node.jjtGetChild(0);
2206: cf.add(Opcode.ICONST_1);
2207: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
2208: cf.add(Opcode.DUP);
2209: cf.add(Opcode.ICONST_0);
2210: if (n == 1 && c.id != PnutsParserTreeConstants.JJTPACKAGE) { // package("...")
2211: c.accept(this , context);
2212: } else {
2213: cf.add(Opcode.LDC, cf.addConstant(packageName(node)));
2214: }
2215: cf.add(Opcode.AASTORE);
2216: cf.loadLocal(ctx);
2217: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
2218: "call",
2219: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
2220: "Ljava/lang/Object;");
2221: }
2222: return null;
2223: }
2224:
2225: public Object importNode(SimpleNode node, Context context) {
2226: CompileContext cc = (CompileContext) context;
2227: ClassFile cf = cc.cf;
2228: int ctx = cc.getContextIndex();
2229:
2230: SimpleNode p = node.jjtGetParent();
2231: if (p != null
2232: && p.id == PnutsParserTreeConstants.JJTEXPRESSIONLIST) {
2233: node.accept(interpreter, context);
2234: }
2235:
2236: String t2 = node.str;
2237: int n = node.jjtGetNumChildren();
2238: if (n == 0) {
2239: if ("*".equals(t2)) {
2240: cf.loadLocal(ctx);
2241: cf.add(Opcode.LDC, cf.addConstant("*"));
2242: cf
2243: .add(
2244: Opcode.INVOKESTATIC,
2245: "pnuts.lang.Runtime",
2246: "addImport",
2247: "(Lpnuts/lang/Context;Ljava/lang/String;)",
2248: "V");
2249: cf.add(Opcode.ACONST_NULL);
2250: } else if ("(".equals(t2)) {
2251: cf.add(Opcode.GETSTATIC, "pnuts.lang.PnutsFunction",
2252: "IMPORT", "Lpnuts/lang/PnutsFunction;");
2253: cf.add(Opcode.GETSTATIC, className, "NO_PARAM",
2254: "[Ljava/lang/Object;");
2255: cf.loadLocal(ctx);
2256: cf.add(Opcode.INVOKEVIRTUAL,
2257: "pnuts.lang.PnutsFunction", "call",
2258: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
2259: "Ljava/lang/Object;");
2260: } else {
2261: cf.add(Opcode.GETSTATIC, "pnuts.lang.PnutsFunction",
2262: "IMPORT", "Lpnuts/lang/PnutsFunction;");
2263: }
2264: return null;
2265: }
2266: if (n == 1
2267: && node.jjtGetChild(0).id != PnutsParserTreeConstants.JJTPACKAGE) { // import(...)
2268: int arg = cf.getLocal();
2269: accept(node, 0, context);
2270: cf.storeLocal(arg);
2271: cf.add(Opcode.GETSTATIC, "pnuts.lang.PnutsFunction",
2272: "IMPORT", "Lpnuts/lang/PnutsFunction;");
2273: cf.add(Opcode.ICONST_1);
2274: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
2275: cf.add(Opcode.DUP);
2276: cf.add(Opcode.ICONST_0);
2277: cf.loadLocal(arg);
2278: cf.freeLocal(arg);
2279: cf.add(Opcode.AASTORE);
2280: cf.loadLocal(ctx);
2281: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
2282: "call",
2283: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
2284: "Ljava/lang/Object;");
2285: return null;
2286: }
2287: StringBuffer sbuf = new StringBuffer();
2288: sbuf.append(node.jjtGetChild(0).str);
2289: for (int i = 1; i < n; i++) {
2290: sbuf.append('.');
2291: sbuf.append(node.jjtGetChild(i).str);
2292: }
2293: cf.loadLocal(ctx);
2294: if (node.info != null) { // static import
2295: cf.add(Opcode.LDC, cf.addConstant(sbuf.toString()));
2296: cf.add(t2 == null ? Opcode.ICONST_0 : Opcode.ICONST_1);
2297: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
2298: "addStaticMembers",
2299: "(Lpnuts/lang/Context;Ljava/lang/String;Z)", "V");
2300: } else {
2301: if (t2 != null) {
2302: sbuf.append(".*");
2303: }
2304: cf.add(Opcode.LDC, cf.addConstant(sbuf.toString()));
2305: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
2306: "addImport",
2307: "(Lpnuts/lang/Context;Ljava/lang/String;)", "V");
2308: }
2309: cf.add(Opcode.ACONST_NULL);
2310: return null;
2311: }
2312:
2313: void booleanCheck(int id, ClassFile cf, Context context) {
2314: if (id != PnutsParserTreeConstants.JJTTRUENODE
2315: && id != PnutsParserTreeConstants.JJTFALSENODE
2316: && id != PnutsParserTreeConstants.JJTLENODE
2317: && id != PnutsParserTreeConstants.JJTLTNODE
2318: && id != PnutsParserTreeConstants.JJTGENODE
2319: && id != PnutsParserTreeConstants.JJTGTNODE
2320: && id != PnutsParserTreeConstants.JJTEQUALNODE
2321: && id != PnutsParserTreeConstants.JJTNOTEQNODE
2322: && id != PnutsParserTreeConstants.JJTINSTANCEOFEXPRESSION
2323: && id != PnutsParserTreeConstants.JJTORNODE
2324: && id != PnutsParserTreeConstants.JJTANDNODE
2325: && id != PnutsParserTreeConstants.JJTNOTNODE) {
2326: int index = cf.getLocal();
2327: cf.add(Opcode.DUP);
2328: cf.storeLocal(index);
2329:
2330: cf.add(Opcode.INSTANCEOF, "java.lang.Boolean");
2331: Label l_next = cf.getLabel();
2332: cf.add(Opcode.IFNE, l_next);
2333: Label l_next_2 = cf.getLabel();
2334:
2335: // disable boolean check
2336: // error(cf, "boolean.expected", new int[] { index }, (CompileContext) context);
2337:
2338: cf.loadLocal(index);
2339: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
2340: "toBoolean", "(Ljava/lang/Object;)",
2341: "Ljava/lang/Boolean;");
2342: cf.add(Opcode.GOTO, l_next_2);
2343: l_next.fix();
2344: cf.loadLocal(index);
2345: l_next_2.fix();
2346: cf.freeLocal(index);
2347: }
2348: }
2349:
2350: public Object logAndNode(SimpleNode node, Context context) {
2351: CompileContext cc = (CompileContext) context;
2352: ClassFile cf = cc.cf;
2353: addLineInfo(cc, cc.getContextIndex(), node);
2354:
2355: accept(node, 0, context);
2356: booleanCheck(node.jjtGetChild(0).id, cf, context);
2357: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
2358: int tgt1 = cf.getLocal();
2359: cf.add(Opcode.DUP);
2360: cf.storeLocal(tgt1);
2361:
2362: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
2363: "booleanValue", "()", "Z");
2364: Label l_else = cf.getLabel();
2365: cf.add(Opcode.IFEQ, l_else);
2366: accept(node, 1, context);
2367: booleanCheck(node.jjtGetChild(1).id, cf, context);
2368: Label next = cf.getLabel();
2369: cf.add(Opcode.GOTO, next);
2370: l_else.fix();
2371: cf.popStack();
2372: cf.loadLocal(tgt1);
2373: next.fix();
2374: cf.freeLocal(tgt1);
2375: return null;
2376: }
2377:
2378: public Object logOrNode(SimpleNode node, Context context) {
2379: CompileContext cc = (CompileContext) context;
2380: ClassFile cf = cc.cf;
2381: addLineInfo(cc, cc.getContextIndex(), node);
2382:
2383: accept(node, 0, context);
2384: booleanCheck(node.jjtGetChild(0).id, cf, context);
2385: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
2386: int tgt1 = cf.getLocal();
2387: cf.add(Opcode.DUP);
2388: cf.storeLocal(tgt1);
2389:
2390: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
2391: "booleanValue", "()", "Z");
2392: Label l_else = cf.getLabel();
2393: cf.add(Opcode.IFNE, l_else);
2394: accept(node, 1, context);
2395: booleanCheck(node.jjtGetChild(1).id, cf, context);
2396: Label next = cf.getLabel();
2397: cf.add(Opcode.GOTO, next);
2398: l_else.fix();
2399: cf.popStack();
2400: cf.loadLocal(tgt1);
2401: next.fix();
2402: cf.freeLocal(tgt1);
2403: return null;
2404: }
2405:
2406: public Object logNotNode(SimpleNode node, Context context) {
2407: CompileContext cc = (CompileContext) context;
2408: ClassFile cf = cc.cf;
2409: addLineInfo(cc, cc.getContextIndex(), node);
2410:
2411: accept(node, 0, context);
2412: booleanCheck(node.jjtGetChild(0).id, cf, context);
2413: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
2414: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
2415: "booleanValue", "()", "Z");
2416: Label t = cf.getLabel();
2417: Label next = cf.getLabel();
2418: cf.add(Opcode.IFEQ, t);
2419: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "FALSE",
2420: "Ljava/lang/Boolean;");
2421: cf.add(Opcode.GOTO, next);
2422: t.fix();
2423: cf.popStack();
2424: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "TRUE",
2425: "Ljava/lang/Boolean;");
2426: next.fix();
2427: return null;
2428: }
2429:
2430: boolean canConstantFold(SimpleNode node) {
2431: return _constantFolding && isConstant(node.jjtGetChild(0))
2432: && isConstant(node.jjtGetChild(1));
2433: }
2434:
2435: static boolean isConstant(SimpleNode node) {
2436: switch (node.id) {
2437: case PnutsParserTreeConstants.JJTINTEGERNODE: {
2438: Object[] p = (Object[]) node.info;
2439: return p[1] == null;
2440: }
2441: case PnutsParserTreeConstants.JJTFLOATINGNODE: {
2442: Object[] p = (Object[]) node.info;
2443: return p[1] == null;
2444: }
2445: case PnutsParserTreeConstants.JJTSTRINGNODE:
2446: case PnutsParserTreeConstants.JJTCHARACTERNODE:
2447: case PnutsParserTreeConstants.JJTTRUENODE:
2448: case PnutsParserTreeConstants.JJTFALSENODE:
2449: case PnutsParserTreeConstants.JJTNULLNODE:
2450: return true;
2451: case PnutsParserTreeConstants.JJTLENODE:
2452: case PnutsParserTreeConstants.JJTLTNODE:
2453: case PnutsParserTreeConstants.JJTGENODE:
2454: case PnutsParserTreeConstants.JJTGTNODE:
2455: case PnutsParserTreeConstants.JJTEQUALNODE:
2456: case PnutsParserTreeConstants.JJTNOTEQNODE:
2457: case PnutsParserTreeConstants.JJTANDNODE:
2458: case PnutsParserTreeConstants.JJTORNODE:
2459: case PnutsParserTreeConstants.JJTXORNODE:
2460: case PnutsParserTreeConstants.JJTLOGORNODE:
2461: case PnutsParserTreeConstants.JJTLOGANDNODE:
2462: case PnutsParserTreeConstants.JJTSHIFTLEFTNODE:
2463: case PnutsParserTreeConstants.JJTSHIFTRIGHTNODE:
2464: case PnutsParserTreeConstants.JJTSHIFTARITHMETICNODE:
2465: case PnutsParserTreeConstants.JJTADDNODE:
2466: case PnutsParserTreeConstants.JJTSUBTRACTNODE:
2467: case PnutsParserTreeConstants.JJTMULTNODE:
2468: case PnutsParserTreeConstants.JJTDIVIDENODE:
2469: case PnutsParserTreeConstants.JJTMODNODE:
2470: return isConstant(node.jjtGetChild(0))
2471: && isConstant(node.jjtGetChild(1));
2472: case PnutsParserTreeConstants.JJTNEGATIVENODE:
2473: case PnutsParserTreeConstants.JJTNOTNODE:
2474: case PnutsParserTreeConstants.JJTLOGNOTNODE:
2475: return isConstant(node.jjtGetChild(0));
2476: default:
2477: return false;
2478: }
2479: }
2480:
2481: Object binary(String operator, SimpleNode node, Context context) {
2482: CompileContext cc = (CompileContext) context;
2483: ClassFile cf = cc.cf;
2484: int ctx = cc.getContextIndex();
2485: addLineInfo(cc, ctx, node);
2486:
2487: SimpleNode n0 = node.jjtGetChild(0);
2488: SimpleNode n1 = node.jjtGetChild(1);
2489: if (node.getAttribute("hasTryStatement") != null) {
2490: int arg0 = cf.getLocal();
2491: int arg1 = cf.getLocal();
2492: n0.accept(this , context);
2493: cf.storeLocal(arg0);
2494: n1.accept(this , context);
2495: cf.storeLocal(arg1);
2496: cf.loadLocal(arg0);
2497: cf.loadLocal(arg1);
2498: cf.freeLocal(arg0);
2499: cf.freeLocal(arg1);
2500: } else {
2501: n0.accept(this , context);
2502: n1.accept(this , context);
2503: }
2504: cf.loadLocal(ctx);
2505: cf
2506: .add(
2507: Opcode.INVOKESTATIC,
2508: "pnuts.lang.Runtime",
2509: operator,
2510: "(Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
2511: "Ljava/lang/Object;");
2512: return null;
2513: }
2514:
2515: public Object shiftLeftNode(SimpleNode node, Context context) {
2516: try {
2517: if (canConstantFold(node)) {
2518: addConstant(interpreter.shiftLeftNode(node, context),
2519: context);
2520: return null;
2521: }
2522: } catch (Exception e) {
2523: }
2524: return binary("shiftLeft", node, context);
2525: }
2526:
2527: public Object shiftRightNode(SimpleNode node, Context context) {
2528: try {
2529: if (canConstantFold(node)) {
2530: addConstant(interpreter.shiftRightNode(node, context),
2531: context);
2532: return null;
2533: }
2534: } catch (Exception e) {
2535: }
2536: return binary("shiftRight", node, context);
2537: }
2538:
2539: public Object shiftArithmeticNode(SimpleNode node, Context context) {
2540: try {
2541: if (canConstantFold(node)) {
2542: addConstant(interpreter.shiftArithmeticNode(node,
2543: context), context);
2544: return null;
2545: }
2546: } catch (Exception e) {
2547: }
2548: return binary("shiftArithmetic", node, context);
2549: }
2550:
2551: static void addConstant(Object n, Context context) {
2552: CompileContext cc = (CompileContext) context;
2553: ClassFile cf = cc.cf;
2554: if (n instanceof String) {
2555: cf.add(Opcode.LDC, cf.addConstant((String) n));
2556: return;
2557: }
2558: String assoc = (String) cc.constants.get(n);
2559: if (assoc == null) {
2560: assoc = gensym(cc);
2561: cc.constants.put(n, assoc);
2562: }
2563: if (n instanceof Integer) {
2564: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
2565: "Ljava/lang/Integer;");
2566: } else if (n instanceof Long) {
2567: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
2568: "Ljava/lang/Long;");
2569: } else if (n instanceof Byte) {
2570: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
2571: "Ljava/lang/Byte;");
2572: } else if (n instanceof BigInteger) {
2573: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
2574: "Ljava/math/BigInteger;");
2575: } else if (n instanceof BigDecimal) {
2576: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
2577: "Ljava/math/BigDecimal;");
2578: } else if (n instanceof Float) {
2579: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
2580: "Ljava/lang/Float;");
2581: } else if (n instanceof Double) {
2582: cf.add(Opcode.GETSTATIC, cc.constClassName, assoc,
2583: "Ljava/lang/Double;");
2584: } else {
2585: throw new InternalError("compiler error");
2586: }
2587:
2588: }
2589:
2590: public Object addNode(SimpleNode node, Context context) {
2591: try {
2592: if (canConstantFold(node)) {
2593: addConstant(interpreter.addNode(node, context), context);
2594: return null;
2595: }
2596: } catch (Exception e) {
2597: }
2598: return binary("add", node, context);
2599: }
2600:
2601: public Object subtractNode(SimpleNode node, Context context) {
2602: try {
2603: if (canConstantFold(node)) {
2604: addConstant(interpreter.subtractNode(node, context),
2605: context);
2606: return null;
2607: }
2608: } catch (Exception e) {
2609: }
2610: return binary("subtract", node, context);
2611: }
2612:
2613: public Object multNode(SimpleNode node, Context context) {
2614: try {
2615: if (canConstantFold(node)) {
2616: addConstant(interpreter.multNode(node, context),
2617: context);
2618: return null;
2619: }
2620: } catch (Exception e) {
2621: }
2622: return binary("multiply", node, context);
2623: }
2624:
2625: public Object divideNode(SimpleNode node, Context context) {
2626: try {
2627: if (canConstantFold(node)) {
2628: addConstant(interpreter.divideNode(node, context),
2629: context);
2630: return null;
2631: }
2632: } catch (Exception e) {
2633: }
2634: return binary("divide", node, context);
2635: }
2636:
2637: public Object modNode(SimpleNode node, Context context) {
2638: try {
2639: if (canConstantFold(node)) {
2640: addConstant(interpreter.modNode(node, context), context);
2641: return null;
2642: }
2643: } catch (Exception e) {
2644: }
2645: return binary("mod", node, context);
2646: }
2647:
2648: public Object xorNode(SimpleNode node, Context context) {
2649: try {
2650: if (canConstantFold(node)) {
2651: Object xor = interpreter.xorNode(node, context);
2652: if (xor instanceof Number) {
2653: addConstant(xor, context);
2654: return null;
2655: } else if (xor instanceof Boolean) {
2656: CompileContext cc = (CompileContext) context;
2657: ClassFile cf = cc.cf;
2658: if (((Boolean) xor).booleanValue()) {
2659: cf.add(Opcode.ICONST_0);
2660: } else {
2661: cf.add(Opcode.ICONST_1);
2662: }
2663: }
2664: }
2665: } catch (Exception e) {
2666: }
2667: return binary("xor", node, context);
2668: }
2669:
2670: public Object orNode(SimpleNode node, Context context) {
2671: try {
2672: if (canConstantFold(node)) {
2673: Object or = interpreter.orNode(node, context);
2674: if (or instanceof Number) {
2675: addConstant(or, context);
2676: return null;
2677: } else if (or instanceof Boolean) {
2678: CompileContext cc = (CompileContext) context;
2679: ClassFile cf = cc.cf;
2680: if (((Boolean) or).booleanValue()) {
2681: cf.add(Opcode.ICONST_0);
2682: } else {
2683: cf.add(Opcode.ICONST_1);
2684: }
2685: }
2686: }
2687: } catch (Exception e) {
2688: }
2689: return binary("or", node, context);
2690: }
2691:
2692: public Object andNode(SimpleNode node, Context context) {
2693: try {
2694: if (canConstantFold(node)) {
2695: Object and = interpreter.andNode(node, context);
2696: if (and instanceof Number) {
2697: addConstant(and, context);
2698: return null;
2699: } else if (and instanceof Boolean) {
2700: if (((Boolean) and).booleanValue()) {
2701: CompileContext cc = (CompileContext) context;
2702: ClassFile cf = cc.cf;
2703: if (((Boolean) and).booleanValue()) {
2704: cf.add(Opcode.ICONST_0);
2705: } else {
2706: cf.add(Opcode.ICONST_1);
2707: }
2708: }
2709: }
2710: }
2711: } catch (Exception e) {
2712: }
2713: return binary("and", node, context);
2714: }
2715:
2716: Object unary(String operator, SimpleNode node, Context context) {
2717: CompileContext cc = (CompileContext) context;
2718: int ctx = cc.getContextIndex();
2719: ClassFile cf = cc.cf;
2720: accept(node, 0, context);
2721: cf.loadLocal(ctx);
2722: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime", operator,
2723: "(Ljava/lang/Object;Lpnuts/lang/Context;)",
2724: "Ljava/lang/Object;");
2725: return null;
2726: }
2727:
2728: public Object negativeNode(SimpleNode node, Context context) {
2729: return unary("negate", node, context);
2730: }
2731:
2732: public Object notNode(SimpleNode node, Context context) {
2733: return unary("not", node, context);
2734: }
2735:
2736: Object bool(String operator, SimpleNode node, Context context) {
2737: CompileContext cc = (CompileContext) context;
2738: ClassFile cf = cc.cf;
2739: int ctx = cc.getContextIndex();
2740: addLineInfo(cc, ctx, node);
2741:
2742: if (node.getAttribute("hasTryStatement") != null) {
2743: int arg0 = cf.getLocal();
2744: int arg1 = cf.getLocal();
2745: accept(node, 0, cc);
2746: cf.storeLocal(arg0);
2747: accept(node, 1, cc);
2748: cf.storeLocal(arg1);
2749: cf.loadLocal(arg0);
2750: cf.loadLocal(arg1);
2751: cf.freeLocal(arg0);
2752: cf.freeLocal(arg1);
2753: } else {
2754: accept(node, 0, cc);
2755: accept(node, 1, cc);
2756: }
2757: cf.loadLocal(ctx);
2758: cf
2759: .add(
2760: Opcode.INVOKESTATIC,
2761: "pnuts.lang.Runtime",
2762: operator,
2763: "(Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
2764: "Z");
2765: if (isConditionalNode(node)) {
2766: node.setAttribute("inlinedBoolean", Boolean.TRUE);
2767: } else {
2768: Label deny = cf.getLabel();
2769: cf.add(Opcode.IFEQ, deny);
2770: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "TRUE",
2771: "Ljava/lang/Boolean;");
2772: Label next = cf.getLabel();
2773: cf.add(Opcode.GOTO, next);
2774: deny.fix();
2775: cf.popStack();
2776: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "FALSE",
2777: "Ljava/lang/Boolean;");
2778: next.fix();
2779: }
2780: return null;
2781: }
2782:
2783: public Object ltNode(SimpleNode node, Context context) {
2784: return bool("lt", node, context);
2785: }
2786:
2787: public Object leNode(SimpleNode node, Context context) {
2788: return bool("le", node, context);
2789: }
2790:
2791: public Object gtNode(SimpleNode node, Context context) {
2792: return bool("gt", node, context);
2793: }
2794:
2795: public Object geNode(SimpleNode node, Context context) {
2796: return bool("ge", node, context);
2797: }
2798:
2799: public Object equalNode(SimpleNode node, Context context) {
2800: return bool("eq", node, context);
2801: }
2802:
2803: public Object notEqNode(SimpleNode node, Context context) {
2804: return bool("ne", node, context);
2805: }
2806:
2807: public Object ifStatement(SimpleNode node, Context context) {
2808: CompileContext cc = (CompileContext) context;
2809: ClassFile cf = cc.cf;
2810: int ctx = cc.getContextIndex();
2811:
2812: addLineInfo(cc, ctx, node);
2813:
2814: SimpleNode condNode = node.jjtGetChild(0);
2815: condNode.accept(this , context);
2816:
2817: Label l_else = cf.getLabel();
2818: Label next = cf.getLabel();
2819:
2820: cc.openBranchEnv();
2821:
2822: if (condNode.getAttribute("inlinedBoolean") != null) {
2823: cf.add(Opcode.IFEQ, l_else);
2824: accept(node, 1, context);
2825: cf.add(Opcode.GOTO, next);
2826: l_else.fix();
2827: cf.popStack();
2828: } else {
2829: booleanCheck(node.jjtGetChild(0).id, cf, context);
2830: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
2831: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
2832: "booleanValue", "()", "Z");
2833: cf.add(Opcode.IFEQ, l_else);
2834: accept(node, 1, context);
2835: cf.add(Opcode.GOTO, next);
2836: l_else.fix();
2837: cf.popStack();
2838: }
2839: int n = node.jjtGetNumChildren();
2840: int j = 0;
2841: /*
2842: * if (n < 3){ cf.add(Opcode.ACONST_NULL); cf.add(Opcode.GOTO, next); }
2843: */
2844: for (int i = 2; i < n; i++) {
2845: SimpleNode _node = node.jjtGetChild(i);
2846: if (_node.id == PnutsParserTreeConstants.JJTELSEIFNODE) {
2847: cc.addBranch();
2848:
2849: SimpleNode _condNode = _node.jjtGetChild(0);
2850: _condNode.accept(this , context);
2851:
2852: Label next_else = cf.getLabel();
2853: if (_condNode.getAttribute("inlinedBoolean") != null) {
2854: cf.add(Opcode.IFEQ, next_else);
2855: accept(_node, 1, context);
2856: cf.add(Opcode.GOTO, next);
2857: next_else.fix();
2858: cf.popStack();
2859: } else {
2860: booleanCheck(_node.jjtGetChild(0).id, cf, context);
2861: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
2862: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
2863: "booleanValue", "()", "Z");
2864: cf.add(Opcode.IFEQ, next_else);
2865: accept(_node, 1, context);
2866: cf.add(Opcode.GOTO, next);
2867: next_else.fix();
2868: cf.popStack();
2869: }
2870: } else if (_node.id == PnutsParserTreeConstants.JJTELSENODE) {
2871: cc.addBranch();
2872:
2873: accept(_node, 0, context);
2874: if (i == n - 1) {
2875: next.fix();
2876: cc.closeBranchEnv();
2877: return null;
2878: } else {
2879: cf.add(Opcode.GOTO, next);
2880: }
2881: }
2882: }
2883: cf.add(Opcode.ACONST_NULL);
2884:
2885: cc.closeBranchEnv();
2886:
2887: next.fix();
2888: return null;
2889: }
2890:
2891: static boolean isLeafFrame(SimpleNode node) {
2892: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
2893: if (!info.leafCheckDone) {
2894: scanLeafFrames(node);
2895: }
2896: return info.isLeaf;
2897: }
2898:
2899: private static boolean isFrame(SimpleNode node) {
2900: int id = node.id;
2901: if (id == PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT
2902: || id == PnutsParserTreeConstants.JJTMETHODDEF
2903: || id == PnutsParserTreeConstants.JJTFOREACHSTATEMENT) {
2904: return true;
2905: }
2906: if (id == PnutsParserTreeConstants.JJTFORSTATEMENT) {
2907: SimpleNode c = node.jjtGetChild(0);
2908: if (c.id == PnutsParserTreeConstants.JJTFORENUM) {
2909: return (c.jjtGetNumChildren() == 1);
2910: }
2911: }
2912: return false;
2913: }
2914:
2915: static boolean scanLeafFrames(SimpleNode node) {
2916: boolean c = true;
2917: int n = node.jjtGetNumChildren();
2918: for (int i = 0; i < n; i++) {
2919: SimpleNode child = node.jjtGetChild(i);
2920: if (!scanLeafFrames(child)) {
2921: if (isFrame(node)) {
2922: FrameInfo info = (FrameInfo) node
2923: .getAttribute("frameInfo");
2924: if (info == null) {
2925: node.setAttribute("frameInfo",
2926: info = new FrameInfo());
2927: }
2928: info.isLeaf = false;
2929: info.leafCheckDone = true;
2930: }
2931: c = false;
2932: }
2933: }
2934: boolean c1 = !isFrame(node);
2935: boolean c2 = (c && c1);
2936: if (node.id == PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT
2937: || node.id == PnutsParserTreeConstants.JJTMETHODDEF) {
2938: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
2939: if (info == null) {
2940: node.setAttribute("frameInfo", info = new FrameInfo());
2941: }
2942: info.isLeaf = c;
2943: info.leafCheckDone = true;
2944: }
2945: return c2;
2946: }
2947:
2948: public Object functionStatement(SimpleNode node, Context context) {
2949: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
2950: if (info == null) {
2951: node.setAttribute("frameInfo", info = new FrameInfo());
2952: }
2953: if (!info.preprocessed) {
2954: preprocess(node);
2955: }
2956:
2957: CompileContext cc = (CompileContext) context;
2958: int ctx = cc.getContextIndex();
2959: ClassFile cf = cc.cf;
2960:
2961: addLineInfo(cc, ctx, node);
2962:
2963: SimpleNode block = node.jjtGetChild(1);
2964: SimpleNode param = node.jjtGetChild(0);
2965: int nargs = param.jjtGetNumChildren();
2966: boolean varargs = "[".equals(param.str);
2967: String[] locals = new String[nargs];
2968:
2969: SimpleNode n0 = null;
2970: if (nargs == 1
2971: && (n0 = param.jjtGetChild(0)).id == PnutsParserTreeConstants.JJTINDEXNODE) {
2972: nargs = -1;
2973: locals[0] = n0.jjtGetChild(0).str;
2974: } else {
2975: for (int j = 0; j < nargs; j++) {
2976: locals[j] = param.jjtGetChild(j).str;
2977: }
2978: }
2979:
2980: boolean isGenerator = Runtime.isGenerator(block);
2981:
2982: String cls = className + "$"
2983: + (classCount++ & 0x7fffffffffffffffL);
2984: node.setAttribute("classname", cls);
2985:
2986: cf = new ClassFile(cls, "pnuts.lang.Function", sourceFile,
2987: Constants.ACC_PUBLIC);
2988: cf.addInterface("pnuts.compiler.Compiled");
2989: cc.classFiles.add(cf);
2990: cf.parent = cc.cf;
2991:
2992: /*
2993: * public PnutsFunction register(PnutsFunction pf, boolean);
2994: */
2995: cf
2996: .openMethod(
2997: "register",
2998: "(Lpnuts/lang/PnutsFunction;Z)Lpnuts/lang/PnutsFunction;",
2999: Constants.ACC_PUBLIC);
3000:
3001: cf.add(Opcode.ALOAD_0);
3002: cf.add(Opcode.ALOAD_1);
3003: cf.add(Opcode.ILOAD_2);
3004: cf.add(Opcode.INVOKESPECIAL, "pnuts.lang.Function", "register",
3005: "(Lpnuts/lang/PnutsFunction;Z)",
3006: "Lpnuts/lang/PnutsFunction;");
3007: cf.add(Opcode.ARETURN);
3008: cf.closeMethod();
3009:
3010: if (optimize) {
3011: /*
3012: * protected String unparse(Context context);
3013: */
3014: cf.openMethod("unparse",
3015: "(Lpnuts/lang/Context;)Ljava/lang/String;",
3016: Constants.ACC_PROTECTED);
3017: cf.pushString(Runtime.unparse(node, context));
3018: cf.add(Opcode.ARETURN);
3019: cf.closeMethod();
3020: } else {
3021: /*
3022: * protected SimpleNode getNode();
3023: */
3024: cf.openMethod("getNode", "()Lpnuts/lang/SimpleNode;",
3025: Constants.ACC_PROTECTED);
3026: cf.pushString(Runtime.saveNode(node));
3027: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
3028: "loadNode", "(Ljava/lang/String;)",
3029: "Lpnuts/lang/SimpleNode;");
3030: cf.add(Opcode.ARETURN);
3031: cf.closeMethod();
3032: }
3033:
3034: String fname = node.str;
3035:
3036: /*
3037: * protected Object exec(Object[] args, Context conext);
3038: */
3039: cc._openFrame(fname, locals, isLeafFrame(node));
3040: cf
3041: .openMethod(
3042: "exec",
3043: "([Ljava/lang/Object;Lpnuts/lang/Context;)Ljava/lang/Object;",
3044: Constants.ACC_PROTECTED);
3045: CompileContext cc2 = (CompileContext) cc.clone(false, true);
3046: cc2.line = 0xffffffff;
3047: cc2.cf = cf;
3048: cc2.setContextIndex(2);
3049: cc2.returnLabel = cf.getLabel();
3050:
3051: ByteBuffer code = cf.getCodeBuffer();
3052: ByteBuffer blockCode = new ByteBuffer();
3053: cf.setCodeBuffer(blockCode);
3054:
3055: if (fname != null) {
3056: int f = cf.getLocal();
3057: //cc2._declare(fname, f, -1);
3058: cc2._declare_frame(fname, f);
3059: cf.add(Opcode.ALOAD_0);
3060: cf.add(Opcode.GETFIELD, "pnuts.lang.Function", "function",
3061: "Lpnuts/lang/PnutsFunction;");
3062: cf.storeLocal(f);
3063: }
3064:
3065: int expt = cf.getLocal();
3066: cc2._declare(EXCEPTOIN_FIELD_SYMBOL, expt, -1);
3067:
3068: CompileContext cc3 = null;
3069: ClassFile cf2 = null;
3070:
3071: if (isGenerator) {
3072:
3073: String cls2 = className + "$"
3074: + (classCount++ & 0x7fffffffffffffffL);
3075: cf2 = new ClassFile(cls2, "pnuts.lang.PnutsFunction",
3076: sourceFile, Constants.ACC_PUBLIC);
3077:
3078: cc.classFiles.add(cf2);
3079: cf2.parent = cf;
3080:
3081: String closureSymbol = YIELD;
3082:
3083: SimpleNode gnode = Generator.convertYield(block,
3084: closureSymbol);
3085:
3086: cc3 = (CompileContext) cc2.clone();
3087: cc3.cf = cf2;
3088:
3089: /*
3090: * protected Object exec(Object[], Context)
3091: */
3092: cc3._openFrame(fname, locals, false);
3093: cf2
3094: .openMethod(
3095: "exec",
3096: "([Ljava/lang/Object;Lpnuts/lang/Context;)Ljava/lang/Object;",
3097: Constants.ACC_PROTECTED);
3098:
3099: cf2.loadLocal(0);
3100: cf2.add(Opcode.GETFIELD, cls2, "$context$",
3101: "Lpnuts/lang/Context;");
3102: cf2.storeLocal(2);
3103:
3104: cc3.setContextIndex(2);
3105: cc3.returnLabel = cf2.getLabel();
3106:
3107: ByteBuffer code2 = cf2.getCodeBuffer();
3108: ByteBuffer blockCode2 = new ByteBuffer();
3109: cf2.setCodeBuffer(blockCode2);
3110:
3111: cc3.openScope(new String[] {});
3112: int args = cf2.getLocal();
3113: cf2.loadLocal(0);
3114: cf2.add(Opcode.GETFIELD, cls2, "args",
3115: "[Ljava/lang/Object;");
3116: cf2.storeLocal(args);
3117: for (int i = 0; i < locals.length; i++) {
3118: cc3._declare(locals[i], args, i);
3119: }
3120: int closure = cf2.getLocal();
3121:
3122: cc3._declare(closureSymbol, closure, -1);
3123:
3124: cf2.add(Opcode.ALOAD_1);
3125: cf2.add(Opcode.ICONST_0);
3126: cf2.add(Opcode.AALOAD);
3127: cf2.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
3128: cf2.storeLocal(closure);
3129:
3130: gnode.accept(this , cc3);
3131:
3132: cc3.returnLabel.fix();
3133:
3134: cf2.setCodeBuffer(code2);
3135:
3136: LocalInfo[] infos = cc3.env.bottom.info;
3137: int count = cc3.env.bottom.count;
3138:
3139: for (int i = 0; i < infos.length; i++) {
3140: if (infos[i] != null) {
3141: int idx = infos[i].index;
3142: String sym = infos[i].symbol;
3143: int map = infos[i].map;
3144: if (idx < 0) {
3145: cf2.add(Opcode.ACONST_NULL);
3146: cf2.storeLocal(map);
3147: } else if (idx == 0) {
3148: cf2.add(Opcode.ICONST_1);
3149: cf2.add(Opcode.ANEWARRAY, "java.lang.Object");
3150: cf2.add(Opcode.DUP);
3151: cf2.add(Opcode.ICONST_0);
3152: cf2.add(Opcode.ACONST_NULL);
3153:
3154: cf2.add(Opcode.AASTORE);
3155: cf2.storeLocal(map);
3156: }
3157: }
3158: }
3159:
3160: cf2.shift(code2.size());
3161:
3162: blockCode2.prepend(code2);
3163: cf2.setCodeBuffer(blockCode2);
3164:
3165: cf2.add(Opcode.ARETURN);
3166:
3167: cc3.closeScope();
3168:
3169: cf2.closeMethod();
3170:
3171: ArrayList exports = (ArrayList) cc3.env.parent.exports
3172: .get(cc3.env);
3173:
3174: cc3._closeFrame();
3175:
3176: StringBuffer arg = new StringBuffer("([Ljava/lang/Object;");
3177: int n_names = 0;
3178:
3179: if (exports != null) {
3180: n_names = exports.size();
3181: }
3182: String names[] = new String[n_names];
3183:
3184: int j = 0;
3185: if (n_names > 0) {
3186: for (int i = 0, n = exports.size(); i < n; i++) {
3187: names[j++] = ((Reference) exports.get(i)).symbol;
3188: arg.append("[Ljava/lang/Object;");
3189: }
3190: }
3191:
3192: arg.append("Lpnuts/lang/Context;");
3193: arg.append(')');
3194:
3195: cf2.openMethod("<init>", arg + "V", Constants.ACC_PUBLIC);
3196: cf2.add(Opcode.ALOAD_0);
3197: cf2.add(Opcode.INVOKESPECIAL, "pnuts.lang.PnutsFunction",
3198: "<init>", "()", "V");
3199:
3200: cf2.addField("args", "[Ljava/lang/Object;",
3201: Constants.ACC_PRIVATE);
3202: cf2.add(Opcode.ALOAD_0);
3203: cf2.add(Opcode.ALOAD_1);
3204: cf2.add(Opcode.PUTFIELD, cls2, "args",
3205: "[Ljava/lang/Object;");
3206:
3207: for (int i = 0; i < n_names; i++) {
3208: cf2
3209: .addField(names[i], "[Ljava/lang/Object;",
3210: (short) 0);
3211: cf2.add(Opcode.ALOAD_0);
3212: cf2.loadLocal(2 + i);
3213: cf2.add(Opcode.PUTFIELD, cf2.getClassName(), names[i],
3214: "[Ljava/lang/Object;");
3215: }
3216:
3217: cf2
3218: .addField("$context$", "Lpnuts/lang/Context;",
3219: (short) 0);
3220: cf2.add(Opcode.ALOAD_0);
3221: cf2.loadLocal(2 + n_names);
3222: cf2.add(Opcode.ICONST_0);
3223: cf2.add(Opcode.ICONST_0);
3224: cf2.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
3225: "clone", "(ZZ)", "Ljava/lang/Object;");
3226: cf2.add(Opcode.CHECKCAST, "pnuts.lang.Context");
3227: cf2.add(Opcode.PUTFIELD, cf2.getClassName(), "$context$",
3228: "Lpnuts/lang/Context;");
3229:
3230: cf2.add(Opcode.RETURN);
3231: cf2.closeMethod();
3232:
3233: // cc.debug(cf2);
3234:
3235: cf.add(Opcode.NEW, "pnuts.lang.Generator");
3236: cf.add(Opcode.DUP);
3237:
3238: cf.add(Opcode.NEW, cls2);
3239: cf.add(Opcode.DUP);
3240: cf.loadLocal(1);
3241:
3242: if (exports != null) {
3243: int size = exports.size();
3244: for (int i = 0; i < size; i++) {
3245: Reference ref = (Reference) exports.get(i);
3246: if (ref.index < 0) {
3247: cf.add(Opcode.ALOAD_0);
3248: cf.add(Opcode.GETFIELD, cf.getClassName(),
3249: ref.symbol, "[Ljava/lang/Object;");
3250: } else if (ref.offset < 0) {
3251: cf.add(Opcode.ICONST_1);
3252: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
3253: cf.add(Opcode.DUP);
3254: cf.add(Opcode.ICONST_0);
3255: cf.loadLocal(ref.index);
3256: cf.add(Opcode.AASTORE);
3257: } else {
3258: cf.loadLocal(ref.index);
3259: cf.add(Opcode.CHECKCAST, "[Ljava/lang/Object;");
3260: }
3261: }
3262: }
3263:
3264: cf.loadLocal(2);
3265:
3266: cf.add(Opcode.INVOKESPECIAL, cls2, "<init>",
3267: arg.toString(), "V");
3268:
3269: cf.add(Opcode.INVOKESPECIAL, "pnuts.lang.Generator",
3270: "<init>", "(Lpnuts/lang/PnutsFunction;)", "V");
3271:
3272: } else {
3273: if (info.freeVars != null) {
3274: int loc = cf.getLocal();
3275: for (Iterator it = info.freeVars.iterator(); it
3276: .hasNext();) {
3277: String var = (String) it.next();
3278: if (var == fname) {
3279: continue;
3280: }
3281: cc2.declare(var);
3282: Reference ref = cc2.getReference(var);
3283: cf.loadLocal(cc2.getContextIndex());
3284: cf.add(Opcode.LDC, cf.addConstant(var));
3285: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
3286: "getId", "(Ljava/lang/String;)",
3287: "Ljava/lang/Object;");
3288: cf.storeLocal(loc);
3289: ref.set(cf, loc);
3290: }
3291: cf.freeLocal(loc);
3292: }
3293: block.accept(this , cc2);
3294: }
3295:
3296: cc2.returnLabel.fix();
3297:
3298: cf.setCodeBuffer(code);
3299:
3300: LocalInfo[] infos = cc.env.bottom.info;
3301: int count = cc.env.bottom.count;
3302:
3303: for (int i = 0; i < cc.env.bottom.count; i++) {
3304: int idx = infos[i].index;
3305: String sym = infos[i].symbol;
3306: int map = infos[i].map;
3307: if (idx < 0) {
3308: cf.add(Opcode.ACONST_NULL);
3309: cf.storeLocal(map);
3310: } else if (idx == 0) {
3311: cf.add(Opcode.ICONST_1);
3312: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
3313: cf.add(Opcode.DUP);
3314: cf.add(Opcode.ICONST_0);
3315: cf.add(Opcode.ACONST_NULL);
3316:
3317: cf.add(Opcode.AASTORE);
3318: cf.storeLocal(map);
3319: }
3320: }
3321:
3322: Reference eref = cc2.getReference(EXCEPTOIN_FIELD_SYMBOL);
3323: cf.add(Opcode.ACONST_NULL);
3324: cf.storeLocal(eref.index);
3325:
3326: cf.shift(code.size());
3327:
3328: Label catchStart = cf.getLabel(true);
3329:
3330: blockCode.prepend(code);
3331: cf.setCodeBuffer(blockCode);
3332:
3333: boolean finallyIsSet = cc2.env.finallySet;
3334: Label jsrTag = cf.getLabel();
3335: Label finallyEnd = cf.getLabel();
3336:
3337: if (finallyIsSet) {
3338: int value = cf.getLocal();
3339: cf.storeLocal(value);
3340: cf.add(Opcode.JSR, jsrTag);
3341: cf.loadLocal(value);
3342: cf.freeLocal(value);
3343: }
3344:
3345: cf.add(Opcode.ARETURN);
3346:
3347: Label catchEnd = cf.getLabel(true);
3348: Label catchTarget = cf.getLabel(true);
3349: Label finallyTarget = cf.getLabel();
3350: cf.reserveStack(1);
3351:
3352: int caught = cf.getLocal();
3353: cf.storeLocal(caught);
3354: cf.loadLocal(cc2.getContextIndex());
3355: cf.loadLocal(caught);
3356: cf.freeLocal(caught);
3357:
3358: if (!isGenerator) {
3359: cf.loadLocal(eref.index);
3360: cf.add(Opcode.CHECKCAST, "pnuts.lang.Runtime$TypeMap");
3361: cf
3362: .add(
3363: Opcode.INVOKESTATIC,
3364: "pnuts.lang.Runtime",
3365: "checkException",
3366: "(Lpnuts/lang/Context;Ljava/lang/Throwable;Lpnuts/lang/Runtime$TypeMap;)",
3367: "V");
3368: }
3369: if (finallyIsSet) {
3370: finallyEnd.fix();
3371: cf.add(Opcode.JSR, jsrTag);
3372: }
3373:
3374: cf.add(Opcode.ACONST_NULL);
3375: cf.add(Opcode.ARETURN);
3376:
3377: if (finallyIsSet) {
3378: int throwable = cf.getLocal();
3379: int returnAddr = cf.getLocal();
3380:
3381: finallyTarget.fix();
3382:
3383: cf.reserveStack(1);
3384: cf.storeLocal(throwable);
3385: cf.add(Opcode.JSR, jsrTag);
3386: cf.loadLocal(throwable);
3387: cf.freeLocal(throwable);
3388: cf.add(Opcode.ATHROW);
3389:
3390: jsrTag.fix();
3391:
3392: cf.reserveStack(1);
3393: cf.storeLocal(returnAddr);
3394: Reference ref = cc.getReference("!finally");
3395: cf.loadLocal(ref.index);
3396: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
3397: cf.add(Opcode.GETSTATIC, className, "NO_PARAM",
3398: "[Ljava/lang/Object;");
3399:
3400: cf.loadLocal(cc2.getContextIndex());
3401: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
3402: "call",
3403: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
3404: "Ljava/lang/Object;");
3405: cf.add(Opcode.POP);
3406: cf.add(Opcode.RET, returnAddr);
3407: cf.freeLocal(returnAddr);
3408: }
3409:
3410: cf.addExceptionHandler(catchStart, catchEnd, catchTarget,
3411: "java.lang.Throwable");
3412:
3413: if (finallyIsSet) {
3414: cf.addExceptionHandler(catchStart, finallyEnd,
3415: finallyTarget, null);
3416: }
3417:
3418: StringBuffer arg = new StringBuffer(
3419: "(Ljava/lang/String;[Ljava/lang/String;IZLpnuts/lang/SimpleNode;Lpnuts/lang/Package;Lpnuts/lang/Context;");
3420: int n_names = 0;
3421: if (cc.env.imports != null) {
3422: n_names = cc.env.imports.size();
3423: }
3424:
3425: String names[] = new String[n_names];
3426:
3427: int j = 0;
3428: if (n_names > 0) {
3429: List imports = cc.env.imports;
3430: for (int i = 0, n = imports.size(); i < n; i++) {
3431: String sym = (String) imports.get(i);
3432: if (DEBUG) {
3433: System.out.println(fname + ": " + sym);
3434: }
3435: names[j++] = sym;
3436: arg.append("[Ljava/lang/Object;");
3437: }
3438: }
3439:
3440: if (DEBUG) {
3441: System.out.println(cf.getClassName() + ": " + arg);
3442: }
3443:
3444: cf.closeMethod();
3445: cc._closeFrame();
3446:
3447: arg.append(")");
3448: /*
3449: * constructor
3450: */
3451: cf.openMethod("<init>", arg + "V", (short) 0);
3452: cf.add(Opcode.ALOAD_0);
3453: cf.add(Opcode.ALOAD_1); // String name
3454: cf.add(Opcode.ALOAD_2); // String[] locals
3455: cf.add(Opcode.ILOAD_3); // int nargs
3456: cf.add(Opcode.ILOAD, 4); // int nargs
3457: cf.add(Opcode.ALOAD, 5); // SimpleNode
3458: cf.add(Opcode.ALOAD, 6); // Package
3459: cf.add(Opcode.ALOAD, 7); // Context
3460: cf
3461: .add(
3462: Opcode.INVOKESPECIAL,
3463: "pnuts.lang.Function",
3464: "<init>",
3465: "(Ljava/lang/String;[Ljava/lang/String;IZLpnuts/lang/SimpleNode;Lpnuts/lang/Package;Lpnuts/lang/Context;)",
3466: "V");
3467:
3468: for (int i = 0; i < n_names; i++) {
3469: cf.addField(names[i], "[Ljava/lang/Object;", (short) 0);
3470: cf.add(Opcode.ALOAD_0);
3471: cf.add(Opcode.ALOAD, 8 + i);
3472: cf.add(Opcode.PUTFIELD, cf.getClassName(), names[i],
3473: "[Ljava/lang/Object;");
3474: }
3475:
3476: cf.add(Opcode.RETURN);
3477: cf.closeMethod();
3478:
3479: cf = cc.cf;
3480: cf.loadLocal(ctx);
3481: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
3482: "getCurrentPackage", "()", "Lpnuts/lang/Package;");
3483: int pkg = cf.getLocal();
3484: cf.storeLocal(pkg);
3485:
3486: cf.add(Opcode.NEW, cls);
3487: cf.add(Opcode.DUP);
3488: int fnameIndex = 0;
3489: if (fname != null) {
3490: fnameIndex = cf.addConstant(fname);
3491: cf.add(Opcode.LDC, fnameIndex);
3492: } else {
3493: cf.add(Opcode.ACONST_NULL);
3494: }
3495: cf.pushInteger(locals.length);
3496: cf.add(Opcode.ANEWARRAY, "java.lang.String");
3497: for (int i = 0; i < locals.length; i++) {
3498: cf.add(Opcode.DUP);
3499: cf.pushInteger(i);
3500: cf.add(Opcode.LDC, cf.addConstant(locals[i]));
3501: cf.add(Opcode.AASTORE);
3502: }
3503: cf.pushInteger(nargs);
3504: cf.add(varargs ? Opcode.ICONST_1 : Opcode.ICONST_0);
3505: cf.add(Opcode.ACONST_NULL);
3506: cf.loadLocal(pkg);
3507: cf.loadLocal(ctx);
3508:
3509: ArrayList exports;
3510:
3511: if (isGenerator) {
3512: exports = (ArrayList) cc.env.exports.get(cc3.env);
3513: } else {
3514: exports = (ArrayList) cc.env.exports.get(cc2.env);
3515: }
3516:
3517: if (exports != null) {
3518: int size = exports.size();
3519: for (int i = 0; i < size; i++) {
3520: Reference ref = (Reference) exports.get(i);
3521: if (ref.index < 0) {
3522: cf.add(Opcode.ALOAD_0);
3523: cf.add(Opcode.GETFIELD, cf.getClassName(),
3524: ref.symbol, "[Ljava/lang/Object;");
3525: } else if (ref.offset < 0) {
3526: cf.add(Opcode.ICONST_1);
3527: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
3528: cf.add(Opcode.DUP);
3529: cf.add(Opcode.ICONST_0);
3530: cf.loadLocal(ref.index);
3531: cf.add(Opcode.AASTORE);
3532: } else {
3533: cf.loadLocal(ref.index);
3534: cf.add(Opcode.CHECKCAST, "[Ljava/lang/Object;");
3535: }
3536: }
3537: }
3538:
3539: cf
3540: .add(Opcode.INVOKESPECIAL, cls, "<init>", arg
3541: .toString(), "V");
3542:
3543: int func = cf.getLocal();
3544: cf.storeLocal(func);
3545:
3546: int pfunc = cf.getLocal();
3547: cf.add(Opcode.ACONST_NULL);
3548: cf.storeLocal(pfunc);
3549:
3550: Reference ref = null;
3551: Reference ref2 = null;
3552: if (fname != null && node.getAttribute("isMethod") == null) {
3553: ref = cc.env.findReference(fname); // without lexical scope
3554: ref2 = cc.findReference(fname); // with lexical scope
3555: if (ref != null && ref.frame != cc.env) {
3556: getRef(ref, cc);
3557: cf.storeLocal(pfunc);
3558:
3559: cf.loadLocal(pfunc);
3560: cf.add(Opcode.INSTANCEOF, "pnuts.lang.PnutsFunction");
3561: Label instance = cf.getLabel();
3562: cf.add(Opcode.IFNE, instance);
3563: cf.add(Opcode.ACONST_NULL);
3564: cf.storeLocal(pfunc);
3565: instance.fix();
3566:
3567: cf.loadLocal(func);
3568: cf.loadLocal(pfunc);
3569: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
3570: cf.add(Opcode.ICONST_0);
3571: cf.add(Opcode.INVOKEVIRTUAL, cls, "register",
3572: "(Lpnuts/lang/PnutsFunction;Z)",
3573: "Lpnuts/lang/PnutsFunction;");
3574: cf.storeLocal(pfunc);
3575:
3576: } else if (ref2 != null) { // ref == null && ref2 != null
3577: getRef(ref2, cc);
3578: cf.storeLocal(pfunc);
3579:
3580: cf.loadLocal(pfunc);
3581: cf.add(Opcode.INSTANCEOF, "pnuts.lang.PnutsFunction");
3582: Label instance = cf.getLabel();
3583: cf.add(Opcode.IFNE, instance);
3584: cf.add(Opcode.ACONST_NULL);
3585: cf.storeLocal(pfunc);
3586: instance.fix();
3587:
3588: cf.loadLocal(func);
3589: cf.loadLocal(pfunc);
3590: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
3591: cf.add(Opcode.ICONST_1);
3592: cf.add(Opcode.INVOKEVIRTUAL, cls, "register",
3593: "(Lpnuts/lang/PnutsFunction;Z)",
3594: "Lpnuts/lang/PnutsFunction;");
3595: cf.storeLocal(pfunc);
3596:
3597: } else if (cc.env.parent != null) {
3598: cf.loadLocal(func);
3599: cf.add(Opcode.LDC, fnameIndex);
3600: cf.loadLocal(pkg);
3601: cf
3602: .add(
3603: Opcode.INVOKESTATIC,
3604: "pnuts.lang.Runtime",
3605: "defineUnboundFunction",
3606: "(Lpnuts/lang/Function;Ljava/lang/String;Lpnuts/lang/Package;)",
3607: "Lpnuts/lang/PnutsFunction;");
3608: cf.storeLocal(pfunc);
3609:
3610: cc.declare(fname);
3611: ref = cc.getReference(fname);
3612: ref.set(cf, pfunc);
3613: cf.loadLocal(pfunc);
3614: return null;
3615: } else {
3616: cf.loadLocal(func);
3617: cf.add(Opcode.LDC, fnameIndex);
3618: cf.loadLocal(pkg);
3619: cf.loadLocal(ctx);
3620: cf
3621: .add(
3622: Opcode.INVOKESTATIC,
3623: "pnuts.lang.Runtime",
3624: "defineTopLevelFunction",
3625: "(Lpnuts/lang/Function;Ljava/lang/String;Lpnuts/lang/Package;Lpnuts/lang/Context;)",
3626: "Lpnuts/lang/PnutsFunction;");
3627: return null;
3628: }
3629: } else { // fname == null
3630: cf.loadLocal(func);
3631: cf.add(Opcode.ACONST_NULL);
3632: cf.add(Opcode.ICONST_0);
3633: cf.add(Opcode.INVOKEVIRTUAL, cls, "register",
3634: "(Lpnuts/lang/PnutsFunction;Z)",
3635: "Lpnuts/lang/PnutsFunction;");
3636: return null;
3637: }
3638:
3639: if (cc.env.parent != null) {
3640: if (ref == null) {
3641: cc.declare(fname);
3642: ref = cc.getReference(fname);
3643: } else {
3644: cc.redefine(fname);
3645: }
3646: ref.set(cf, pfunc);
3647: cf.loadLocal(pfunc);
3648: } else {
3649: cf.loadLocal(pkg);
3650: cf.add(Opcode.LDC, fnameIndex);
3651: cf.loadLocal(pfunc);
3652: cf.loadLocal(ctx);
3653: cf
3654: .add(
3655: Opcode.INVOKEVIRTUAL,
3656: "pnuts.lang.Package",
3657: "set",
3658: "(Ljava/lang/String;Ljava/lang/Object;Lpnuts/lang/Context;)",
3659: "V");
3660: cf.loadLocal(pfunc);
3661: }
3662: cf.freeLocal(func);
3663: cf.freeLocal(pfunc);
3664: cf.freeLocal(pkg);
3665: return null;
3666: }
3667:
3668: public Object applicationNode(SimpleNode node, Context context) {
3669: CompileContext cc = (CompileContext) context;
3670: ClassFile cf = cc.cf;
3671: int ctx = cc.getContextIndex();
3672:
3673: addLineInfo(cc, ctx, node);
3674:
3675: SimpleNode n0 = node.jjtGetChild(0);
3676: if (n0.id == PnutsParserTreeConstants.JJTIDNODE) {
3677: String sym = n0.str;
3678: Reference ref = cc.getReference(sym);
3679: if (ref != null) {
3680: Frame frame = ref.frame;
3681: if (frame != null) {
3682: SimpleNode n1 = node.jjtGetChild(1);
3683: int nargs = n1.jjtGetNumChildren();
3684: if (frame.fname == sym
3685: && frame.locals.length == nargs) {
3686: if (DEBUG) {
3687: System.out.println("recursive " + sym);
3688: }
3689: //System.out.println("ref.frame = " + frame + ", env=" + cc.env);
3690: cf.add(Opcode.ALOAD_0);
3691: _listElements(node.jjtGetChild(1), context);
3692: cf.loadLocal(ctx);
3693: cf
3694: .add(
3695: Opcode.INVOKEVIRTUAL,
3696: "pnuts.lang.Function",
3697: "exec",
3698: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
3699: "Ljava/lang/Object;");
3700: return null;
3701: }
3702: }
3703: }
3704: }
3705:
3706: if (node.getAttribute("hasTryStatement") != null) {
3707: int tgt = cf.getLocal();
3708: int arg = cf.getLocal();
3709: accept(node, 0, context);
3710: cf.storeLocal(tgt);
3711: // accept(node, 1, context);
3712: _listElements(node.jjtGetChild(1), context);
3713: cf.storeLocal(arg);
3714:
3715: cf.loadLocal(ctx);
3716: cf.loadLocal(tgt);
3717: cf.loadLocal(arg);
3718:
3719: cf.freeLocal(tgt);
3720: cf.freeLocal(arg);
3721: } else {
3722: cf.loadLocal(ctx);
3723: accept(node, 0, context);
3724: // accept(node, 1, context);
3725: _listElements(node.jjtGetChild(1), context);
3726: }
3727:
3728: SimpleNode argNode = node.jjtGetChild(1);
3729: int nargs = argNode.jjtGetNumChildren();
3730:
3731: boolean types_created = false;
3732: for (int i = 0; i < nargs; i++) {
3733: SimpleNode n = argNode.jjtGetChild(i);
3734: if (n.id == PnutsParserTreeConstants.JJTCASTEXPRESSION) {
3735: if (!types_created) {
3736: cf.pushInteger(nargs);
3737: cf.add(Opcode.ANEWARRAY, "java.lang.Class");
3738: types_created = true;
3739: }
3740: cf.add(Opcode.DUP);
3741: cf.pushInteger(i);
3742:
3743: resolveType(n.jjtGetChild(0), cc, ctx);
3744:
3745: cf.add(Opcode.AASTORE);
3746: }
3747: }
3748: if (!types_created) {
3749: cf.add(Opcode.ACONST_NULL);
3750: }
3751:
3752: if (_includeLineNo) {
3753: cf.pushInteger(node.beginLine);
3754: if (_includeColumnNo) {
3755: cf.pushInteger(node.beginColumn);
3756: } else {
3757: cf.pushInteger(-1);
3758: }
3759: cf
3760: .add(
3761: Opcode.INVOKESTATIC,
3762: "pnuts.lang.Runtime",
3763: "call",
3764: "(Lpnuts/lang/Context;Ljava/lang/Object;[Ljava/lang/Object;[Ljava/lang/Class;II)",
3765: "Ljava/lang/Object;");
3766: } else {
3767: cf
3768: .add(
3769: Opcode.INVOKESTATIC,
3770: "pnuts.lang.Runtime",
3771: "call",
3772: "(Lpnuts/lang/Context;Ljava/lang/Object;[Ljava/lang/Object;[Ljava/lang/Class;)",
3773: "Ljava/lang/Object;");
3774: }
3775:
3776: return null;
3777: }
3778:
3779: public Object tryStatement(SimpleNode node, Context context) {
3780: CompileContext cc = (CompileContext) context;
3781: ClassFile cf = cc.cf;
3782: /*
3783: * if (node.jjtGetParent().id ==
3784: * PnutsParserTreeConstants.JJTLISTELEMENTS){ throw new
3785: * PnutsException("try/catch is not allowed in parameters", context); }
3786: * if (cf.stackTop > 0){ throw new PnutsException("try/catch is not
3787: * allowed in parameters", context); }
3788: */
3789: int throwable = cf.getLocal();
3790: cf.add(Opcode.ACONST_NULL);
3791: cf.storeLocal(throwable);
3792:
3793: int value = cf.getLocal();
3794: cf.add(Opcode.ACONST_NULL);
3795: cf.storeLocal(value);
3796:
3797: Label next = cf.getLabel();
3798: Label finalTag = cf.getLabel();
3799: Label jsrTag = cf.getLabel();
3800:
3801: int n = node.jjtGetNumChildren();
3802: SimpleNode lastNode = node.jjtGetChild(n - 1);
3803: SimpleNode finallyBlock = null;
3804: if (lastNode.id == PnutsParserTreeConstants.JJTFINALLYBLOCK) {
3805: finallyBlock = lastNode;
3806: cc.pushFinallyBlock(jsrTag);
3807: }
3808: boolean hasCatchBlock = false;
3809: if (n > 1
3810: && node.jjtGetChild(1).id == PnutsParserTreeConstants.JJTCATCHBLOCK) {
3811: hasCatchBlock = true;
3812: }
3813:
3814: Label catchStart = cf.getLabel(true);
3815:
3816: accept(node, 0, context);
3817: cf.storeLocal(value);
3818:
3819: Label catchEnd = cf.getLabel(true);
3820:
3821: if (finallyBlock != null) {
3822: cf.add(Opcode.JSR, jsrTag);
3823: }
3824: cf.add(Opcode.GOTO, next);
3825:
3826: Label escape = cf.getLabel(true);
3827: cf.reserveStack(1);
3828:
3829: cf.storeLocal(throwable);
3830: cf.loadLocal(throwable);
3831: cf.add(Opcode.ATHROW);
3832:
3833: Label catchTarget = null;
3834: if (hasCatchBlock) {
3835: catchTarget = cf.getLabel(true);
3836: cf.reserveStack(1);
3837: cf.storeLocal(throwable);
3838:
3839: cf.loadLocal(throwable);
3840: cf.add(Opcode.INSTANCEOF, "pnuts.lang.PnutsException");
3841: Label l1 = cf.getLabel();
3842: cf.add(Opcode.IFEQ, l1);
3843: cf.loadLocal(throwable);
3844: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsException");
3845: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsException",
3846: "getThrowable", "()", "Ljava/lang/Throwable;");
3847: cf.storeLocal(throwable);
3848: l1.fix();
3849:
3850: int cls = cf.getLocal();
3851:
3852: for (int i = 1; i < n; i++) {
3853: SimpleNode c = node.jjtGetChild(i);
3854: if (c.id == PnutsParserTreeConstants.JJTCATCHBLOCK) {
3855: String var = c.str;
3856: StringBuffer sbuf = new StringBuffer();
3857: SimpleNode classNode = c.jjtGetChild(0);
3858: sbuf.append(classNode.jjtGetChild(0).str);
3859: for (int j = 1; j < classNode.jjtGetNumChildren(); j++) {
3860: sbuf.append('.');
3861: sbuf.append(classNode.jjtGetChild(j).str);
3862: }
3863: cf.loadLocal(cc.getContextIndex());
3864: cf.add(Opcode.LDC, cf.addConstant(sbuf.toString()));
3865: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
3866: "resolveClass", "(Ljava/lang/String;)",
3867: "Ljava/lang/Class;");
3868: cf.storeLocal(cls);
3869: cf.loadLocal(cls);
3870: Label nextCatch = cf.getLabel();
3871: cf.add(Opcode.IFNULL, nextCatch);
3872: cf.loadLocal(cls);
3873: cf.loadLocal(throwable);
3874: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Class",
3875: "isInstance", "(Ljava/lang/Object;)", "Z");
3876: cf.add(Opcode.IFEQ, nextCatch);
3877: cc.openScope(new String[] {});
3878: cc._declare(var, throwable, -1);
3879: accept(c, 1, context);
3880: cc.closeScope();
3881: cf.storeLocal(value);
3882: if (finallyBlock != null) {
3883: cf.add(Opcode.JSR, jsrTag);
3884: }
3885: cf.add(Opcode.GOTO, next);
3886: nextCatch.fix();
3887: }
3888: }
3889: cf.loadLocal(throwable);
3890: cf.add(Opcode.ATHROW);
3891: }
3892:
3893: if (finallyBlock != null) {
3894: finalTag = cf.getLabel(true);
3895: cf.reserveStack(1);
3896: cf.storeLocal(throwable);
3897: cf.add(Opcode.JSR, jsrTag);
3898: cf.loadLocal(throwable);
3899: cf.add(Opcode.ATHROW);
3900:
3901: jsrTag.fix();
3902:
3903: int retAddr = cf.getLocal();
3904: cf.reserveStack(1);
3905: cf.storeLocal(retAddr);
3906:
3907: cc.popFinallyBlock();
3908: accept(finallyBlock, 0, context);
3909: cf.add(Opcode.POP);
3910: cf.add(Opcode.RET, retAddr);
3911: }
3912:
3913: cf.addExceptionHandler(catchStart, catchEnd, escape,
3914: "pnuts.lang.Escape");
3915: if (hasCatchBlock) {
3916: cf.addExceptionHandler(catchStart, catchEnd, catchTarget,
3917: "java.lang.Throwable");
3918: }
3919: if (finallyBlock != null) {
3920: cf
3921: .addExceptionHandler(catchStart, finalTag,
3922: finalTag, null);
3923: }
3924:
3925: next.fix();
3926:
3927: cf.loadLocal(value);
3928:
3929: // cf.freeLocal(throwable);
3930: // cf.freeLocal(value);
3931:
3932: return null;
3933: }
3934:
3935: public Object catchBlock(SimpleNode node, Context context) {
3936: return null;
3937: }
3938:
3939: public Object blockNode(SimpleNode node, Context context) {
3940: CompileContext cc = (CompileContext) context;
3941: ClassFile cf = cc.cf;
3942: int n = node.jjtGetNumChildren();
3943:
3944: if (n > 0) {
3945: int m = n - 1;
3946: for (int i = 0; i < m; i++) {
3947: accept(node, i, context);
3948: cf.add(Opcode.POP);
3949: }
3950: accept(node, m, context);
3951: } else {
3952: cf.add(Opcode.ACONST_NULL);
3953: }
3954: return null;
3955: }
3956:
3957: public Object trueNode(SimpleNode node, Context context) {
3958: CompileContext cc = (CompileContext) context;
3959: ClassFile cf = cc.cf;
3960: if (isConditionalNode(node)) {
3961: node.setAttribute("inlinedBoolean", Boolean.TRUE);
3962: cf.add(Opcode.ICONST_1);
3963: } else {
3964: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "TRUE",
3965: "Ljava/lang/Boolean;");
3966: }
3967: return null;
3968: }
3969:
3970: public Object falseNode(SimpleNode node, Context context) {
3971: CompileContext cc = (CompileContext) context;
3972: ClassFile cf = cc.cf;
3973: if (isConditionalNode(node)) {
3974: node.setAttribute("inlinedBoolean", Boolean.TRUE);
3975: cf.add(Opcode.ICONST_0);
3976: } else {
3977: cc.cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "FALSE",
3978: "Ljava/lang/Boolean;");
3979: }
3980: return null;
3981: }
3982:
3983: public Object nullNode(SimpleNode node, Context context) {
3984: CompileContext cc = (CompileContext) context;
3985: cc.cf.add(Opcode.ACONST_NULL);
3986: return null;
3987: }
3988:
3989: public Object idNode(SimpleNode node, Context context) {
3990: CompileContext cc = (CompileContext) context;
3991: ClassFile cf = cc.cf;
3992:
3993: String symbol = node.str;
3994: int ctx = cc.getContextIndex();
3995:
3996: addLineInfo(cc, ctx, node);
3997:
3998: Reference ref = cc.getReference(symbol);
3999:
4000: if (ref != null) {
4001: getRef(ref, cc);
4002: } else {
4003: cf.loadLocal(ctx);
4004: cf.add(Opcode.LDC, cf.addConstant(symbol));
4005: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context", "getId",
4006: "(Ljava/lang/String;)", "Ljava/lang/Object;");
4007: }
4008: return null;
4009: }
4010:
4011: public Object global(SimpleNode node, Context context) {
4012: CompileContext cc = (CompileContext) context;
4013: ClassFile cf = cc.cf;
4014: int ctx = cc.getContextIndex();
4015:
4016: cf.add(Opcode.LDC, cf.addConstant(""));
4017: cf.loadLocal(ctx);
4018: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Package", "find",
4019: "(Ljava/lang/String;Lpnuts/lang/Context;)",
4020: "Lpnuts/lang/Package;");
4021:
4022: int gbl = cf.getLocal();
4023: cf.add(Opcode.DUP);
4024: cf.storeLocal(gbl);
4025:
4026: Label else_ = cf.getLabel();
4027: cf.add(Opcode.IFNULL, else_);
4028:
4029: cf.loadLocal(gbl);
4030: int symbol = cf.addConstant(node.str);
4031: cf.add(Opcode.LDC, symbol);
4032: cf.loadLocal(ctx);
4033:
4034: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Package", "lookup",
4035: "(Ljava/lang/String;Lpnuts/lang/Context;)",
4036: "Lpnuts/lang/NamedValue;");
4037:
4038: int val = cf.getLocal();
4039: cf.add(Opcode.DUP);
4040: cf.storeLocal(val);
4041:
4042: cf.add(Opcode.IFNULL, else_);
4043:
4044: cf.loadLocal(val);
4045: cf.add(Opcode.INVOKEINTERFACE, "pnuts.lang.Value", "get", "()",
4046: "Ljava/lang/Object;");
4047:
4048: Label next = cf.getLabel();
4049: cf.add(Opcode.GOTO, next);
4050: else_.fix();
4051: errorSymbol(cf, "not.defined", symbol, cc);
4052: next.fix();
4053:
4054: cf.freeLocal(gbl);
4055: return null;
4056: }
4057:
4058: public Object listElements(SimpleNode node, Context context) {
4059: if ("{".equals(node.str)) {
4060: buildList(node, context);
4061: } else {
4062: buildArray(node, context);
4063: }
4064: return null;
4065: }
4066:
4067: void buildList(SimpleNode node, Context context) {
4068: int n = node.jjtGetNumChildren();
4069: CompileContext cc = (CompileContext) context;
4070: ClassFile cf = cc.cf;
4071: int ctx = cc.getContextIndex();
4072: boolean hasTryStatement = (node.getAttribute("hasTryStatement") != null);
4073: if (hasTryStatement) {
4074: int[] vars = new int[n];
4075: for (int i = 0; i < n; i++) {
4076: int var = cf.getLocal();
4077: accept(node, i, context);
4078: cf.storeLocal(var);
4079: vars[i] = var;
4080: }
4081: cf.loadLocal(ctx);
4082: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
4083: "createList", "(Lpnuts/lang/Context;)",
4084: "Ljava/util/List;");
4085: int ret = cf.getLocal();
4086: cf.storeLocal(ret);
4087: for (int i = 0; i < n; i++) {
4088: cf.loadLocal(ret);
4089: accept(node, i, context);
4090: cf.add(Opcode.INVOKEINTERFACE, "java.util.List", "add",
4091: "(Ljava/lang/Object;)", "Z");
4092: cf.add(Opcode.POP);
4093: }
4094: for (int i = 0; i < n; i++) {
4095: cf.freeLocal(vars[i]);
4096: }
4097: cf.loadLocal(ret);
4098: } else {
4099: cf.loadLocal(ctx);
4100: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
4101: "createList", "(Lpnuts/lang/Context;)",
4102: "Ljava/util/List;");
4103: int ret = cf.getLocal();
4104: cf.storeLocal(ret);
4105: for (int i = 0; i < n; i++) {
4106: cf.loadLocal(ret);
4107: accept(node, i, context);
4108: cf.add(Opcode.INVOKEINTERFACE, "java.util.List", "add",
4109: "(Ljava/lang/Object;)", "Z");
4110: cf.add(Opcode.POP);
4111: }
4112: cf.loadLocal(ret);
4113: }
4114: }
4115:
4116: void buildArray(SimpleNode node, Context context) {
4117: CompileContext cc = (CompileContext) context;
4118: ClassFile cf = cc.cf;
4119: int ctx = cc.getContextIndex();
4120: _listElements(node, context);
4121: cf.loadLocal(ctx);
4122: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime", "makeArray",
4123: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
4124: "Ljava/lang/Object;");
4125: }
4126:
4127: public Object _listElements(SimpleNode node, Context context) {
4128: CompileContext cc = (CompileContext) context;
4129: ClassFile cf = cc.cf;
4130:
4131: int n = node.jjtGetNumChildren();
4132: if (n == 0) {
4133: cf.add(Opcode.GETSTATIC, cc.constClassName, "NO_PARAM",
4134: "[Ljava/lang/Object;");
4135: } else {
4136: boolean hasTryStatement = (node
4137: .getAttribute("hasTryStatement") != null);
4138: if (hasTryStatement) {
4139: int[] vars = new int[n];
4140: for (int i = 0; i < n; i++) {
4141: int var = cf.getLocal();
4142: accept(node, i, context);
4143: cf.storeLocal(var);
4144: vars[i] = var;
4145: }
4146: cf.pushInteger(n);
4147: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
4148: for (int i = 0; i < n; i++) {
4149: cf.add(Opcode.DUP);
4150: cf.pushInteger(i);
4151: cf.loadLocal(vars[i]);
4152: cf.add(Opcode.AASTORE);
4153: }
4154: for (int i = 0; i < n; i++) {
4155: cf.freeLocal(vars[i]);
4156: }
4157: } else {
4158: cf.pushInteger(n);
4159: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
4160: for (int i = 0; i < n; i++) {
4161: cf.add(Opcode.DUP);
4162: cf.pushInteger(i);
4163: accept(node, i, context);
4164: cf.add(Opcode.AASTORE);
4165: }
4166: }
4167: }
4168: return null;
4169: }
4170:
4171: public Object mapNode(SimpleNode node, Context context) {
4172: CompileContext cc = (CompileContext) context;
4173: ClassFile cf = cc.cf;
4174: int n = node.jjtGetNumChildren();
4175: cf.pushInteger(n);
4176: cf.loadLocal(cc.getContextIndex());
4177: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime", "createMap",
4178: "(ILpnuts/lang/Context;)", "Ljava/util/Map;");
4179: int map = cf.getLocal();
4180: cf.storeLocal(map);
4181: for (int i = 0; i < n; i++) {
4182: SimpleNode c = node.jjtGetChild(i);
4183: cf.loadLocal(map);
4184: accept(c, 0, context);
4185: accept(c, 1, context);
4186: cf.add(Opcode.INVOKEINTERFACE, "java.util.Map", "put",
4187: "(Ljava/lang/Object;Ljava/lang/Object;)",
4188: "Ljava/lang/Object;");
4189: cf.add(Opcode.POP);
4190: }
4191: cf.loadLocal(map);
4192: return null;
4193: }
4194:
4195: public Object castExpression(SimpleNode node, Context context) {
4196: CompileContext cc = (CompileContext) context;
4197: ClassFile cf = cc.cf;
4198: int ctx = cc.getContextIndex();
4199:
4200: int tgt = cf.getLocal();
4201: accept(node, 1, context);
4202: cf.storeLocal(tgt);
4203:
4204: cf.loadLocal(ctx);
4205: resolveType(node.jjtGetChild(0), cc, ctx);
4206: cf.loadLocal(tgt);
4207: cf.freeLocal(tgt);
4208: cf.add(Opcode.ICONST_1);
4209: cf
4210: .add(
4211: Opcode.INVOKESTATIC,
4212: "pnuts.lang.Runtime",
4213: "cast",
4214: "(Lpnuts/lang/Context;Ljava/lang/Class;Ljava/lang/Object;Z)",
4215: "Ljava/lang/Object;");
4216: return null;
4217: }
4218:
4219: public Object memberNode(SimpleNode node, Context context) {
4220: CompileContext cc = (CompileContext) context;
4221: ClassFile cf = cc.cf;
4222: int ctx = cc.getContextIndex();
4223:
4224: accept(node, 0, context);
4225: int tgt = cf.getLocal();
4226: cf.storeLocal(tgt);
4227:
4228: Label else_end = cf.getLabel();
4229:
4230: if ("length".equals(node.str)) {
4231: cf.loadLocal(tgt);
4232: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
4233: "isArray", "(Ljava/lang/Object;)", "Z");
4234: Label else_ = cf.getLabel();
4235: cf.add(Opcode.IFEQ, else_);
4236:
4237: if (hasValueOfPrimitive) {
4238: cf.loadLocal(tgt);
4239: cf.add(Opcode.INVOKESTATIC, "java.lang.reflect.Array",
4240: "getLength", "(Ljava/lang/Object;)", "I");
4241: cf.add(Opcode.INVOKESTATIC, "java.lang.Integer",
4242: "valueOf", "(I)", "Ljava/lang/Integer;");
4243: } else {
4244: cf.add(Opcode.NEW, "java.lang.Integer");
4245: cf.add(Opcode.DUP);
4246: cf.loadLocal(tgt);
4247: cf.add(Opcode.INVOKESTATIC, "java.lang.reflect.Array",
4248: "getLength", "(Ljava/lang/Object;)", "I");
4249: cf.add(Opcode.INVOKESPECIAL, "java.lang.Integer",
4250: "<init>", "(I)", "V");
4251: }
4252:
4253: cf.add(Opcode.GOTO, else_end);
4254: else_.fix();
4255: cf.popStack();
4256: }
4257:
4258: if (node.info != null) { /* experimental BIND feature */
4259: Object[] info = (Object[]) node.info;
4260: int targetIndex = ((int[]) info[0])[0];
4261: int tableIndex = ((int[]) info[0])[1];
4262: final SimpleNode c = (SimpleNode) info[1];
4263: SimpleNode c0 = c.jjtGetChild(0);
4264:
4265: cf.loadLocal(tableIndex);
4266: cf.loadLocal(targetIndex);
4267: cf.add(Opcode.LDC, cf.addConstant(c.str));
4268: cf.loadLocal(tgt);
4269: cf.add(Opcode.LDC, cf.addConstant(node.str));
4270: toFunctionNode(c0).accept(this , context);
4271: cf
4272: .add(
4273: Opcode.INVOKESTATIC,
4274: "pnuts.lang.Runtime",
4275: "watchProperty",
4276: "(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Lpnuts/lang/Callable;)",
4277: "V");
4278:
4279: if (c0 == node) {
4280: cf.loadLocal(tableIndex);
4281: cf.loadLocal(tgt);
4282: cf.add(Opcode.LDC, cf.addConstant(node.str));
4283: cf.loadLocal(targetIndex);
4284: cf.add(Opcode.LDC, cf.addConstant(c.str));
4285: cf.add(Opcode.ACONST_NULL);
4286: cf
4287: .add(
4288: Opcode.INVOKESTATIC,
4289: "pnuts.lang.Runtime",
4290: "watchProperty",
4291: "(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Lpnuts/lang/Callable;)",
4292: "V");
4293: }
4294: node.info = null;
4295: }
4296:
4297: cf.loadLocal(ctx);
4298: cf.loadLocal(tgt);
4299: cf.add(Opcode.LDC, cf.addConstant(node.str));
4300: cf
4301: .add(
4302: Opcode.INVOKESTATIC,
4303: "pnuts.lang.Runtime",
4304: "getField",
4305: "(Lpnuts/lang/Context;Ljava/lang/Object;Ljava/lang/String;)",
4306: "Ljava/lang/Object;");
4307: else_end.fix();
4308: cf.freeLocal(tgt);
4309: return null;
4310: }
4311:
4312: public Object methodNode(SimpleNode node, Context context) {
4313: CompileContext cc = (CompileContext) context;
4314: ClassFile cf = cc.cf;
4315: int ctx = cc.getContextIndex();
4316:
4317: addLineInfo(cc, ctx, node);
4318:
4319: accept(node, 0, context);
4320: int tgt = cf.getLocal();
4321: cf.storeLocal(tgt);
4322:
4323: SimpleNode argNode = node.jjtGetChild(1);
4324: int nargs = argNode.jjtGetNumChildren();
4325: int arg = cf.getLocal();
4326: // accept(node, 1, context);
4327: _listElements(argNode, context);
4328: cf.storeLocal(arg);
4329:
4330: boolean types_created = false;
4331: for (int i = 0; i < nargs; i++) {
4332: SimpleNode n = argNode.jjtGetChild(i);
4333: if (n.id == PnutsParserTreeConstants.JJTCASTEXPRESSION) {
4334: if (!types_created) {
4335: cf.pushInteger(nargs);
4336: cf.add(Opcode.ANEWARRAY, "java.lang.Class");
4337: types_created = true;
4338: }
4339: cf.add(Opcode.DUP);
4340: cf.pushInteger(i);
4341: resolveType(n.jjtGetChild(0), cc, ctx);
4342: cf.add(Opcode.AASTORE);
4343: }
4344: }
4345: int types = 0;
4346: if (types_created) {
4347: types = cf.getLocal();
4348: cf.storeLocal(types);
4349: }
4350:
4351: cf.loadLocal(ctx);
4352: cf.loadLocal(tgt);
4353: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Object", "getClass",
4354: "()", "Ljava/lang/Class;");
4355: cf.add(Opcode.LDC, cf.addConstant(node.str));
4356: cf.loadLocal(arg);
4357: cf.freeLocal(arg);
4358:
4359: if (types_created) {
4360: cf.loadLocal(types);
4361: } else {
4362: cf.add(Opcode.ACONST_NULL);
4363: }
4364: cf.loadLocal(tgt);
4365: cf.freeLocal(tgt);
4366:
4367: cf
4368: .add(
4369: Opcode.INVOKESTATIC,
4370: "pnuts.lang.Runtime",
4371: "callMethod",
4372: "(Lpnuts/lang/Context;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;Ljava/lang/Object;)",
4373: "Ljava/lang/Object;");
4374: return null;
4375: }
4376:
4377: public Object className(SimpleNode node, Context context) {
4378: CompileContext cc = (CompileContext) context;
4379: int ctx = cc.getContextIndex();
4380: resolveClassName(node, cc, ctx);
4381: return null;
4382: }
4383:
4384: /*
4385: * ArrayType .. ArrayType IndexNode IdNode IntegerNode
4386: */
4387: public Object arrayType(SimpleNode node, Context context) {
4388: CompileContext cc = (CompileContext) context;
4389: ClassFile cf = cc.cf;
4390:
4391: SimpleNode n = node;
4392: int count = 0;
4393: while (n != null
4394: && n.id == PnutsParserTreeConstants.JJTARRAYTYPE) {
4395: count++;
4396: n = n.jjtGetChild(0);
4397: }
4398: if (n != null && n.id == PnutsParserTreeConstants.JJTINDEXNODE) {
4399: Label clserr = cf.getLabel();
4400: Label numerr = cf.getLabel();
4401:
4402: Object[] idx = parseIndex(n);
4403: SimpleNode idx0 = (SimpleNode) idx[0];
4404: idx0.accept(this , context);
4405: cf.add(Opcode.DUP);
4406: cf.add(Opcode.INSTANCEOF, "java.lang.Class");
4407:
4408: cf.add(Opcode.IFEQ, clserr);
4409: cf.add(Opcode.CHECKCAST, "java.lang.Class");
4410:
4411: cf.pushInteger(count);
4412: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
4413: "arrayType", "(Ljava/lang/Class;I)",
4414: "Ljava/lang/Class;");
4415:
4416: Object[] dim = (Object[]) idx[1];
4417:
4418: cf.pushInteger(dim.length);
4419: cf.add(Opcode.NEWARRAY, Opcode.T_INT);
4420: int dlen = dim.length;
4421: for (int i = 0; i < dlen; i++) {
4422: cf.add(Opcode.DUP);
4423: cf.pushInteger(i);
4424: ((SimpleNode) dim[i]).accept(this , context);
4425: /*
4426: * cf.add(Opcode.DUP); cf.add(Opcode.INSTANCEOF,
4427: * "java.lang.Number"); cf.add(Opcode.IFEQ, numerr);
4428: */
4429: cf.add(Opcode.CHECKCAST, "java.lang.Number");
4430: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Number",
4431: "intValue", "()", "I");
4432: cf.add(Opcode.IASTORE);
4433: }
4434:
4435: cf.add(Opcode.INVOKESTATIC, "java.lang.reflect.Array",
4436: "newInstance", "(Ljava/lang/Class;[I)",
4437: "Ljava/lang/Object;");
4438: Label next = cf.getLabel();
4439: cf.add(Opcode.GOTO, next);
4440: numerr.fix();
4441: error(cf, "number.expected", cc);
4442: cf.add(Opcode.GOTO, next);
4443: clserr.fix();
4444: error(cf, "classOrArray.expected", cc);
4445: next.fix();
4446: return null;
4447: } else if (node.jjtGetParent().id != PnutsParserTreeConstants.JJTNEW) {
4448: n.accept(this , context);
4449: int type = cf.getLocal();
4450: cf.add(Opcode.DUP);
4451: cf.storeLocal(type);
4452:
4453: cf.add(Opcode.INSTANCEOF, "java.lang.Class");
4454: Label err = cf.getLabel();
4455: cf.add(Opcode.IFEQ, err);
4456: cf.loadLocal(type);
4457: cf.freeLocal(type);
4458: cf.add(Opcode.CHECKCAST, "java.lang.Class");
4459: cf.pushInteger(count);
4460: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
4461: "arrayType", "(Ljava/lang/Class;I)",
4462: "Ljava/lang/Class;");
4463: Label next = cf.getLabel();
4464: cf.add(Opcode.GOTO, next);
4465: err.fix();
4466: error(cf, "classOrArray.expected", new int[] { type }, cc);
4467: next.fix();
4468: } else {
4469: cf.add(Opcode.NEW, "java.lang.IllegalArgumentException");
4470: cf.add(Opcode.DUP);
4471: cf.add(Opcode.INVOKESPECIAL,
4472: "java.lang.IllegalArgumentException", "<init>",
4473: "()", "V");
4474: cf.add(Opcode.ATHROW);
4475: }
4476: return null;
4477: }
4478:
4479: /**
4480: * @return [base_component_node, [idx_node_0, idx_node_1, ...]]
4481: */
4482: static Object[] parseIndex(SimpleNode node) {
4483: SimpleNode c0 = node.jjtGetChild(0);
4484: SimpleNode c1 = node.jjtGetChild(1);
4485: if (c0.id != PnutsParserTreeConstants.JJTINDEXNODE) {
4486: return new Object[] { c0, new Object[] { c1 } };
4487: } else {
4488: Object[] r = parseIndex(c0);
4489: Object[] d = (Object[]) r[1];
4490: Object[] a = new Object[d.length + 1];
4491: System.arraycopy(d, 0, a, 0, d.length);
4492: a[d.length] = c1;
4493: return new Object[] { r[0], a };
4494: }
4495: }
4496:
4497: static void convertIndexNode(SimpleNode node) {
4498: SimpleNode n0 = node.jjtGetChild(0);
4499: SimpleNode n1 = node.jjtGetChild(1);
4500: if (ConstraintsTransformer.isPredicate(n1)) {
4501: SimpleNode n = ConstraintsTransformer.buildFunc(n1);
4502: node.jjtAddChild(n, 1);
4503: n.jjtSetParent(node);
4504: }
4505: if (n0.id == PnutsParserTreeConstants.JJTINDEXNODE) {
4506: convertIndexNode(n0);
4507: }
4508: }
4509:
4510: public Object indexNode(SimpleNode node, Context context) {
4511: FrameInfo info = (FrameInfo) node.getAttribute("frameInfo");
4512: if (info == null) {
4513: node.setAttribute("frameInfo", info = new FrameInfo());
4514: }
4515:
4516: if (!info.preprocessed) {
4517: info.preprocessed = true;
4518: convertIndexNode(node);
4519: }
4520:
4521: CompileContext cc = (CompileContext) context;
4522: ClassFile cf = cc.cf;
4523: Object[] idx = parseIndex(node);
4524: SimpleNode c = (SimpleNode) idx[0];
4525: c.accept(this , context);
4526: int tgt = cf.getLocal();
4527: cf.storeLocal(tgt);
4528:
4529: Object[] dim = (Object[]) idx[1];
4530:
4531: Label else_end = cf.getLabel();
4532: int ctx = cc.getContextIndex();
4533:
4534: if (c.id == PnutsParserTreeConstants.JJTCLASS
4535: || c.id == PnutsParserTreeConstants.JJTIDNODE) {
4536: cf.loadLocal(tgt);
4537: cf.add(Opcode.INSTANCEOF, "java.lang.Class");
4538: Label else_ = cf.getLabel();
4539: cf.add(Opcode.IFEQ, else_);
4540:
4541: if (node.getAttribute("hasTryStatement") != null) {
4542: int[] vars = new int[dim.length];
4543: for (int i = 0; i < dim.length; i++) {
4544: int var = cf.getLocal();
4545: ((SimpleNode) dim[i]).accept(this , context);
4546: cf.storeLocal(var);
4547: vars[i] = var;
4548: }
4549: cf.loadLocal(tgt);
4550: cf.add(Opcode.CHECKCAST, "java.lang.Class");
4551: cf.pushInteger(dim.length);
4552: cf.add(Opcode.NEWARRAY, Opcode.T_INT);
4553: for (int i = 0; i < dim.length; i++) {
4554: cf.add(Opcode.DUP);
4555: cf.pushInteger(i);
4556: cf.loadLocal(vars[i]);
4557: cf.add(Opcode.CHECKCAST, "java.lang.Number");
4558: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Number",
4559: "intValue", "()", "I");
4560: cf.add(Opcode.IASTORE);
4561: }
4562: for (int i = 0; i < dim.length; i++) {
4563: cf.freeLocal(vars[i]);
4564: }
4565:
4566: } else {
4567: cf.loadLocal(tgt);
4568: cf.add(Opcode.CHECKCAST, "java.lang.Class");
4569: cf.pushInteger(dim.length);
4570: cf.add(Opcode.NEWARRAY, Opcode.T_INT);
4571: for (int i = 0; i < dim.length; i++) {
4572: cf.add(Opcode.DUP);
4573: cf.pushInteger(i);
4574: ((SimpleNode) dim[i]).accept(this , context);
4575:
4576: cf.add(Opcode.CHECKCAST, "java.lang.Number");
4577: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Number",
4578: "intValue", "()", "I");
4579: cf.add(Opcode.IASTORE);
4580: }
4581: }
4582: cf.add(Opcode.INVOKESTATIC, "java.lang.reflect.Array",
4583: "newInstance", "(Ljava/lang/Class;[I)",
4584: "Ljava/lang/Object;");
4585: cf.add(Opcode.GOTO, else_end);
4586: else_.fix();
4587: cf.popStack();
4588: }
4589:
4590: for (int i = 0; i < dim.length; i++) {
4591: ((SimpleNode) dim[i]).accept(this , context);
4592: int _idx = cf.getLocal();
4593: cf.storeLocal(_idx);
4594:
4595: cf.loadLocal(tgt);
4596: cf.loadLocal(_idx);
4597: cf.loadLocal(ctx);
4598: cf
4599: .add(
4600: Opcode.INVOKESTATIC,
4601: "pnuts.lang.Runtime",
4602: "getElement",
4603: "(Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
4604: "Ljava/lang/Object;");
4605: cf.storeLocal(tgt);
4606: }
4607: cf.loadLocal(tgt);
4608:
4609: else_end.fix();
4610: cf.freeLocal(tgt);
4611: return null;
4612: }
4613:
4614: public Object instanceof Expression(SimpleNode node, Context context) {
4615: CompileContext cc = (CompileContext) context;
4616: ClassFile cf = cc.cf;
4617: int ctx = cc.getContextIndex();
4618:
4619: Label next = cf.getLabel();
4620: Label l_false = cf.getLabel();
4621:
4622: resolveType(node.jjtGetChild(1), cc, ctx);
4623: accept(node, 0, context);
4624:
4625: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Class", "isInstance",
4626: "(Ljava/lang/Object;)", "Z");
4627: cf.add(Opcode.IFEQ, l_false);
4628: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "TRUE",
4629: "Ljava/lang/Boolean;");
4630: cf.add(Opcode.GOTO, next);
4631: l_false.fix();
4632: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "FALSE",
4633: "Ljava/lang/Boolean;");
4634: next.fix();
4635: return null;
4636: }
4637:
4638: public Object assignment(SimpleNode node, Context context) {
4639: SimpleNode lhs = node.jjtGetChild(0);
4640: if (lhs.id == PnutsParserTreeConstants.JJTMULTIASSIGNLHS) {
4641: SimpleNode rhs = node.jjtGetChild(1);
4642: if (rhs.id == PnutsParserTreeConstants.JJTLISTELEMENTS) {
4643: return multiAssignFast(lhs, rhs, context);
4644: } else {
4645: return multiAssign(lhs, rhs, context);
4646: }
4647: } else {
4648: return assign(node, context,
4649: PnutsParserTreeConstants.JJTASSIGNMENT);
4650: }
4651: }
4652:
4653: Object multiAssignFast(SimpleNode lhs, SimpleNode rhs,
4654: Context context) {
4655: CompileContext cc = (CompileContext) context;
4656: int ctx = cc.getContextIndex();
4657: ClassFile cf = cc.cf;
4658: int n = lhs.jjtGetNumChildren();
4659: int[] r_array = new int[n];
4660: for (int i = 0; i < n; i++) {
4661: SimpleNode _rhs = rhs.jjtGetChild(i);
4662: int r = r_array[i] = cf.getLocal();
4663: _rhs.accept(this , context);
4664: cf.storeLocal(r);
4665: }
4666: for (int i = 0; i < n; i++) {
4667: SimpleNode _lhs = lhs.jjtGetChild(i);
4668: assignId(cf, PnutsParserTreeConstants.JJTASSIGNMENT, ctx,
4669: r_array[i], _lhs, cc, false, false);
4670: }
4671: cf.add(Opcode.ACONST_NULL);
4672: for (int i = 0; i < n; i++) {
4673: cf.freeLocal(r_array[i]);
4674: }
4675: return null;
4676: }
4677:
4678: Object multiAssign(SimpleNode lhs, SimpleNode rhs, Context context) {
4679: CompileContext cc = (CompileContext) context;
4680: int ctx = cc.getContextIndex();
4681: ClassFile cf = cc.cf;
4682: int n = lhs.jjtGetNumChildren();
4683: int expr = cf.getLocal();
4684: int _rhs = cf.getLocal();
4685: rhs.accept(this , context);
4686: cf.storeLocal(expr);
4687: for (int i = 0; i < n; i++) {
4688: cf.loadLocal(expr);
4689: cf.pushInteger(i);
4690: cf.loadLocal(ctx);
4691: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
4692: "getElementAt",
4693: "(Ljava/lang/Object;ILpnuts/lang/Context;)",
4694: "Ljava/lang/Object;");
4695: cf.storeLocal(_rhs);
4696: SimpleNode _lhs = lhs.jjtGetChild(i);
4697: assignId(cf, PnutsParserTreeConstants.JJTASSIGNMENT, ctx,
4698: _rhs, _lhs, cc, false, true);
4699: cf.add(Opcode.POP);
4700: }
4701: cf.loadLocal(expr);
4702: return null;
4703: }
4704:
4705: public Object assignmentTA(SimpleNode node, Context context) {
4706: return assign(node, context,
4707: PnutsParserTreeConstants.JJTASSIGNMENTTA);
4708: }
4709:
4710: public Object assignmentMA(SimpleNode node, Context context) {
4711: return assign(node, context,
4712: PnutsParserTreeConstants.JJTASSIGNMENTMA);
4713: }
4714:
4715: public Object assignmentDA(SimpleNode node, Context context) {
4716: return assign(node, context,
4717: PnutsParserTreeConstants.JJTASSIGNMENTDA);
4718: }
4719:
4720: public Object assignmentPA(SimpleNode node, Context context) {
4721: return assign(node, context,
4722: PnutsParserTreeConstants.JJTASSIGNMENTPA);
4723: }
4724:
4725: public Object assignmentSA(SimpleNode node, Context context) {
4726: return assign(node, context,
4727: PnutsParserTreeConstants.JJTASSIGNMENTSA);
4728: }
4729:
4730: public Object assignmentLA(SimpleNode node, Context context) {
4731: return assign(node, context,
4732: PnutsParserTreeConstants.JJTASSIGNMENTLA);
4733: }
4734:
4735: public Object assignmentRA(SimpleNode node, Context context) {
4736: return assign(node, context,
4737: PnutsParserTreeConstants.JJTASSIGNMENTRA);
4738: }
4739:
4740: public Object assignmentRAA(SimpleNode node, Context context) {
4741: return assign(node, context,
4742: PnutsParserTreeConstants.JJTASSIGNMENTRAA);
4743: }
4744:
4745: public Object assignmentAA(SimpleNode node, Context context) {
4746: return assign(node, context,
4747: PnutsParserTreeConstants.JJTASSIGNMENTAA);
4748: }
4749:
4750: public Object assignmentEA(SimpleNode node, Context context) {
4751: return assign(node, context,
4752: PnutsParserTreeConstants.JJTASSIGNMENTEA);
4753: }
4754:
4755: public Object assignmentOA(SimpleNode node, Context context) {
4756: return assign(node, context,
4757: PnutsParserTreeConstants.JJTASSIGNMENTOA);
4758: }
4759:
4760: public Object preIncrNode(SimpleNode node, Context context) {
4761: SimpleNode node0 = node.jjtGetChild(0);
4762: node0.accept(this , context);
4763: _assign(node0, context,
4764: PnutsParserTreeConstants.JJTASSIGNMENTPA | 0x8000,
4765: false, true);
4766: return null;
4767: }
4768:
4769: public Object preDecrNode(SimpleNode node, Context context) {
4770: SimpleNode node0 = node.jjtGetChild(0);
4771: node0.accept(this , context);
4772: _assign(node0, context,
4773: PnutsParserTreeConstants.JJTASSIGNMENTSA | 0x8000,
4774: false, true);
4775: return null;
4776: }
4777:
4778: public Object postIncrNode(SimpleNode node, Context context) {
4779: CompileContext cc = (CompileContext) context;
4780: ClassFile cf = cc.cf;
4781: accept(node, 0, context);
4782: int ret = cf.getLocal();
4783: cf.storeLocal(ret);
4784: cf.loadLocal(ret);
4785:
4786: _assign(node.jjtGetChild(0), cc,
4787: PnutsParserTreeConstants.JJTASSIGNMENTPA | 0x8000,
4788: false, false);
4789: cf.loadLocal(ret);
4790: cf.freeLocal(ret);
4791: return null;
4792: }
4793:
4794: public Object postDecrNode(SimpleNode node, Context context) {
4795: CompileContext cc = (CompileContext) context;
4796: ClassFile cf = cc.cf;
4797:
4798: accept(node, 0, context);
4799: int ret = cf.getLocal();
4800: cf.storeLocal(ret);
4801: cf.loadLocal(ret);
4802:
4803: _assign(node.jjtGetChild(0), context,
4804: PnutsParserTreeConstants.JJTASSIGNMENTSA | 0x8000,
4805: false, false);
4806:
4807: cf.loadLocal(ret);
4808: cf.freeLocal(ret);
4809: return null;
4810: }
4811:
4812: public Object staticMethodNode(SimpleNode node, Context context) {
4813: CompileContext cc = (CompileContext) context;
4814: ClassFile cf = cc.cf;
4815: int ctx = cc.getContextIndex();
4816:
4817: addLineInfo(cc, ctx, node);
4818:
4819: SimpleNode argNode = node.jjtGetChild(1);
4820: int nargs = argNode.jjtGetNumChildren();
4821:
4822: // accept(node, 1, context);
4823: _listElements(argNode, context);
4824: int args = cf.getLocal();
4825: cf.storeLocal(args);
4826:
4827: SimpleNode c1 = node.jjtGetChild(0);
4828: String pkgName = getPackageName(c1);
4829:
4830: cf.add(Opcode.LDC, cf.addConstant(pkgName));
4831: cf.loadLocal(ctx);
4832:
4833: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Package", "find",
4834: "(Ljava/lang/String;Lpnuts/lang/Context;)",
4835: "Lpnuts/lang/Package;");
4836: int pkg = cf.getLocal();
4837: cf.add(Opcode.DUP);
4838: cf.storeLocal(pkg);
4839:
4840: Label l_null = cf.getLabel();
4841: cf.add(Opcode.IFNULL, l_null);
4842: cf.loadLocal(pkg);
4843: cf.add(Opcode.LDC, cf.addConstant(node.str));
4844: cf.loadLocal(ctx);
4845: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Package", "get",
4846: "(Ljava/lang/String;Lpnuts/lang/Context;)",
4847: "Ljava/lang/Object;");
4848: int got = cf.getLocal();
4849: cf.add(Opcode.DUP);
4850: cf.storeLocal(got);
4851:
4852: cf.add(Opcode.INSTANCEOF, "pnuts.lang.PnutsFunction");
4853: Label l_else = cf.getLabel();
4854: cf.add(Opcode.IFEQ, l_else);
4855: cf.loadLocal(ctx);
4856: cf.loadLocal(got);
4857: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
4858: cf.loadLocal(args);
4859: cf
4860: .add(
4861: Opcode.INVOKESTATIC,
4862: "pnuts.lang.Runtime",
4863: "callFunction",
4864: "(Lpnuts/lang/Context;Lpnuts/lang/PnutsFunction;[Ljava/lang/Object;)",
4865: "Ljava/lang/Object;");
4866: Label next = cf.getLabel();
4867: cf.add(Opcode.GOTO, next);
4868: l_else.fix();
4869: cf.popStack();
4870: cf.loadLocal(got);
4871: cf.add(Opcode.INSTANCEOF, "java.lang.Class");
4872: cf.add(Opcode.IFEQ, l_null);
4873:
4874: boolean types_created = false;
4875: for (int i = 0; i < nargs; i++) {
4876: SimpleNode n = argNode.jjtGetChild(i);
4877: if (n.id == PnutsParserTreeConstants.JJTCASTEXPRESSION) {
4878: if (!types_created) {
4879: cf.pushInteger(nargs);
4880: cf.add(Opcode.ANEWARRAY, "java.lang.Class");
4881: types_created = true;
4882: }
4883: cf.add(Opcode.DUP);
4884: cf.pushInteger(i);
4885: resolveType(n.jjtGetChild(0), cc, ctx);
4886: cf.add(Opcode.AASTORE);
4887: }
4888: }
4889: int types = 0;
4890: if (types_created) {
4891: types = cf.getLocal();
4892: cf.storeLocal(types);
4893: }
4894:
4895: cf.loadLocal(ctx);
4896: cf.loadLocal(got);
4897: cf.add(Opcode.CHECKCAST, "java.lang.Class");
4898: cf.loadLocal(args);
4899: if (types_created) {
4900: cf.loadLocal(types);
4901: } else {
4902: cf.add(Opcode.ACONST_NULL);
4903: }
4904: cf
4905: .add(
4906: Opcode.INVOKESTATIC,
4907: "pnuts.lang.Runtime",
4908: "newInstance",
4909: "(Lpnuts/lang/Context;Ljava/lang/Class;[Ljava/lang/Object;[Ljava/lang/Class;)",
4910: "Ljava/lang/Object;");
4911:
4912: cf.add(Opcode.GOTO, next);
4913:
4914: l_null.fix();
4915: cf.popStack();
4916: accept(node, 0, context);
4917: int tgt = cf.getLocal();
4918: cf.add(Opcode.DUP);
4919: cf.storeLocal(tgt);
4920:
4921: cf.add(Opcode.INSTANCEOF, "java.lang.Class");
4922: Label ok = cf.getLabel();
4923: cf.add(Opcode.IFNE, ok);
4924: cf.add(Opcode.NEW, "pnuts.lang.PnutsException");
4925: cf.add(Opcode.DUP);
4926: cf.add(Opcode.LDC, cf.addConstant("illegal.staticCall"));
4927: cf.add(Opcode.ICONST_3);
4928: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
4929: cf.add(Opcode.DUP);
4930: cf.add(Opcode.ICONST_0);
4931: cf.add(Opcode.LDC, cf.addConstant(pkgName));
4932: cf.add(Opcode.AASTORE);
4933: cf.add(Opcode.DUP);
4934: cf.add(Opcode.ICONST_1);
4935: cf.add(Opcode.LDC, cf.addConstant(node.str));
4936: cf.add(Opcode.AASTORE);
4937: cf.add(Opcode.DUP);
4938: cf.add(Opcode.ICONST_2);
4939:
4940: if (hasValueOfPrimitive) {
4941: cf.pushInteger(nargs);
4942: cf.add(Opcode.INVOKESTATIC, "java.lang.Integer", "valueOf",
4943: "(I)", "Ljava/lang/Integer;");
4944: } else {
4945: cf.add(Opcode.NEW, "java.lang.Integer");
4946: cf.add(Opcode.DUP);
4947: cf.pushInteger(nargs);
4948: cf.add(Opcode.INVOKESPECIAL, "java.lang.Integer", "<init>",
4949: "(I)", "V");
4950: }
4951:
4952: cf.add(Opcode.AASTORE);
4953: cf.loadLocal(ctx);
4954: cf
4955: .add(
4956: Opcode.INVOKESPECIAL,
4957: "pnuts.lang.PnutsException",
4958: "<init>",
4959: "(Ljava/lang/String;[Ljava/lang/Object;Lpnuts/lang/Context;)",
4960: "V");
4961: cf.add(Opcode.ATHROW);
4962: ok.fix();
4963:
4964: types_created = false;
4965: for (int i = 0; i < nargs; i++) {
4966: SimpleNode n = argNode.jjtGetChild(i);
4967: if (n.id == PnutsParserTreeConstants.JJTCASTEXPRESSION) {
4968: if (!types_created) {
4969: cf.pushInteger(nargs);
4970: cf.add(Opcode.ANEWARRAY, "java.lang.Class");
4971: types_created = true;
4972: }
4973: cf.add(Opcode.DUP);
4974: cf.pushInteger(i);
4975: resolveType(n.jjtGetChild(0), cc, ctx);
4976: cf.add(Opcode.AASTORE);
4977: }
4978: }
4979: types = 0;
4980: if (types_created) {
4981: types = cf.getLocal();
4982: cf.storeLocal(types);
4983: }
4984: cf.loadLocal(ctx);
4985: cf.loadLocal(tgt);
4986: cf.add(Opcode.CHECKCAST, "java.lang.Class");
4987: cf.add(Opcode.LDC, cf.addConstant(node.str));
4988: cf.loadLocal(args);
4989: if (types_created) {
4990: cf.loadLocal(types);
4991: cf.freeLocal(types);
4992: } else {
4993: cf.add(Opcode.ACONST_NULL);
4994: }
4995: cf.add(Opcode.ACONST_NULL);
4996:
4997: cf
4998: .add(
4999: Opcode.INVOKESTATIC,
5000: "pnuts.lang.Runtime",
5001: "callMethod",
5002: "(Lpnuts/lang/Context;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;Ljava/lang/Object;)",
5003: "Ljava/lang/Object;");
5004: next.fix();
5005: return null;
5006: }
5007:
5008: public Object staticMemberNode(SimpleNode node, Context context) {
5009: CompileContext cc = (CompileContext) context;
5010: ClassFile cf = cc.cf;
5011: int ctx = cc.getContextIndex();
5012:
5013: addLineInfo(cc, ctx, node);
5014:
5015: SimpleNode c1 = node.jjtGetChild(0);
5016: Label next = cf.getLabel();
5017:
5018: String pkgName = getPackageName(c1);
5019:
5020: cf.add(Opcode.LDC, cf.addConstant(pkgName));
5021: cf.loadLocal(ctx);
5022: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Package", "find",
5023: "(Ljava/lang/String;Lpnuts/lang/Context;)",
5024: "Lpnuts/lang/Package;");
5025: int pkg = cf.getLocal();
5026: cf.add(Opcode.DUP);
5027: cf.storeLocal(pkg);
5028:
5029: Label l_null = cf.getLabel();
5030: cf.add(Opcode.IFNULL, l_null);
5031:
5032: cf.loadLocal(pkg);
5033: cf.freeLocal(pkg);
5034: cf.add(Opcode.LDC, cf.addConstant(node.str));
5035: cf.loadLocal(ctx);
5036: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Package", "lookup",
5037: "(Ljava/lang/String;Lpnuts/lang/Context;)",
5038: "Lpnuts/lang/NamedValue;");
5039:
5040: int val = cf.getLocal();
5041: cf.add(Opcode.DUP);
5042: cf.storeLocal(val);
5043:
5044: Label undef = cf.getLabel();
5045: cf.add(Opcode.IFNULL, undef);
5046:
5047: cf.loadLocal(val);
5048: cf.freeLocal(val);
5049:
5050: cf.add(Opcode.INVOKEINTERFACE, "pnuts.lang.Value", "get", "()",
5051: "Ljava/lang/Object;");
5052: cf.add(Opcode.GOTO, next);
5053:
5054: undef.fix();
5055: errorSymbol(cf, "not.defined", cf.addConstant(node.str), cc);
5056: l_null.fix();
5057:
5058: c1.accept(this , context);
5059: int tgt = cf.getLocal();
5060: cf.add(Opcode.DUP);
5061: cf.storeLocal(tgt);
5062:
5063: cf.add(Opcode.INSTANCEOF, "java.lang.Class");
5064: Label err = cf.getLabel();
5065: cf.add(Opcode.IFEQ, err);
5066:
5067: cf.loadLocal(ctx);
5068: cf.loadLocal(tgt);
5069: cf.freeLocal(tgt);
5070: cf.add(Opcode.CHECKCAST, "java.lang.Class");
5071: cf.add(Opcode.LDC, cf.addConstant(node.str));
5072: cf
5073: .add(
5074: Opcode.INVOKESTATIC,
5075: "pnuts.lang.Runtime",
5076: "getStaticField",
5077: "(Lpnuts/lang/Context;Ljava/lang/Class;Ljava/lang/String;)",
5078: "Ljava/lang/Object;");
5079: cf.add(Opcode.GOTO, next);
5080:
5081: err.fix();
5082: error(cf, "packageOrClass.expected", new int[] { tgt }, cc);
5083: next.fix();
5084: return null;
5085: }
5086:
5087: public Object rangeNode(SimpleNode node, Context context) {
5088: CompileContext cc = (CompileContext) context;
5089: ClassFile cf = cc.cf;
5090: int ctx = cc.getContextIndex();
5091:
5092: accept(node, 0, context);
5093: int tgt = cf.getLocal();
5094: cf.storeLocal(tgt);
5095:
5096: accept(node, 1, context);
5097: int idx1 = cf.getLocal();
5098: cf.storeLocal(idx1);
5099:
5100: int idx2 = cf.getLocal();
5101: if (node.jjtGetNumChildren() >= 3) {
5102: accept(node, 2, context);
5103: } else {
5104: cf.add(Opcode.ACONST_NULL);
5105: }
5106: cf.storeLocal(idx2);
5107:
5108: cf.loadLocal(tgt);
5109: cf.freeLocal(tgt);
5110: cf.loadLocal(idx1);
5111: cf.freeLocal(idx1);
5112: cf.loadLocal(idx2);
5113: cf.freeLocal(idx2);
5114: cf.loadLocal(ctx);
5115: cf
5116: .add(
5117: Opcode.INVOKESTATIC,
5118: "pnuts.lang.Runtime",
5119: "getRange",
5120: "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
5121: "Ljava/lang/Object;");
5122: return null;
5123: }
5124:
5125: public Object forStatement(SimpleNode node, Context context) {
5126: CompileContext cc = (CompileContext) context;
5127: ClassFile cf = cc.cf;
5128: int ctx = cc.getContextIndex();
5129:
5130: addLineInfo(cc, ctx, node);
5131:
5132: SimpleNode initNode = null;
5133: SimpleNode condNode = null;
5134: SimpleNode updateNode = null;
5135: SimpleNode blockNode = null;
5136:
5137: int j = 0;
5138: SimpleNode n = node.jjtGetChild(j);
5139:
5140: if (n.id == PnutsParserTreeConstants.JJTFORENUM) {
5141: SimpleNode n0 = n.jjtGetChild(0);
5142: if (n0.id == PnutsParserTreeConstants.JJTMULTIASSIGNLHS) {
5143: int num = n0.jjtGetNumChildren();
5144: String[] vars = new String[num];
5145: for (int i = 0; i < num; i++) {
5146: vars[i] = n0.jjtGetChild(i).str;
5147: }
5148: blockNode = node.jjtGetChild(1);
5149: doForeach(vars, n.jjtGetChild(1), blockNode, cc, cf);
5150: return null;
5151: }
5152: int nc = n.jjtGetNumChildren();
5153: blockNode = node.jjtGetChild(1);
5154: if (nc == 1) { // for (i : value)
5155: doForeach(new String[] { n.str }, n.jjtGetChild(0),
5156: blockNode, cc, cf);
5157: } else if (nc == 2) { // for (i : start .. end)
5158: doForeachRange(n.str, n.jjtGetChild(0), n
5159: .jjtGetChild(1), blockNode, cc, cf);
5160: } else {
5161: }
5162: return null;
5163: }
5164: /*
5165: * for(A;B;C) ...
5166: */
5167: if (n.id == PnutsParserTreeConstants.JJTFORINIT) {
5168: initNode = n;
5169: j++;
5170: }
5171: n = node.jjtGetChild(j);
5172: if (n.id != PnutsParserTreeConstants.JJTFORUPDATE
5173: && n.id != PnutsParserTreeConstants.JJTBLOCK) {
5174: condNode = n;
5175: j++;
5176: }
5177: n = node.jjtGetChild(j);
5178: if (n.id == PnutsParserTreeConstants.JJTFORUPDATE) {
5179: updateNode = n;
5180: j++;
5181: }
5182:
5183: blockNode = node.jjtGetChild(j);
5184:
5185: int last = cf.getLocal();
5186: cf.add(Opcode.ACONST_NULL);
5187: cf.storeLocal(last);
5188:
5189: if (initNode != null) {
5190: int num = initNode.jjtGetNumChildren();
5191: String[] env = new String[num];
5192: for (int i = 0; i < env.length; i++) {
5193: SimpleNode sn = initNode.jjtGetChild(i);
5194: env[i] = sn.str;
5195: }
5196: cc.openScope(env);
5197: for (int i = 0; i < env.length; i++) {
5198: /**/
5199: Reference ref = cc.getReference(env[i]);
5200: if (DEBUG) {
5201: System.out.println("ref = " + ref);
5202: }
5203: SimpleNode sn = initNode.jjtGetChild(i);
5204: accept(sn, 0, context);
5205: if (ref.offset < 0) {
5206: cf.storeLocal(ref.index);
5207: } else {
5208: int tgt = cf.getLocal();
5209: cf.storeLocal(tgt);
5210: cf.add(Opcode.ACONST_NULL);
5211: cf.storeLocal(ref.index);
5212: ref.set(cf, tgt);
5213: }
5214: /**/
5215:
5216: }
5217: } else {
5218: cc.openScope(new String[] {});
5219: }
5220:
5221: Label start = cf.getLabel(true);
5222: Label cont = cf.getLabel();
5223: Label next = cf.getLabel();
5224: Label brk = cf.getLabel();
5225:
5226: ControlEnv ctrl = cc.openControlEnv(node.id);
5227: ctrl.continueLabel = cont;
5228: ctrl.breakLabel = brk;
5229:
5230: if (condNode != null) {
5231: condNode.accept(this , context);
5232: if (condNode.getAttribute("inlinedBoolean") != null) {
5233: cf.add(Opcode.IFEQ, next);
5234: } else {
5235: booleanCheck(condNode.id, cf, context);
5236: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
5237: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
5238: "booleanValue", "()", "Z");
5239: cf.add(Opcode.IFEQ, next);
5240: }
5241: }
5242:
5243: blockNode.accept(this , context);
5244: cont.fix();
5245: cf.storeLocal(last);
5246:
5247: if (updateNode != null) {
5248: int num = updateNode.jjtGetNumChildren();
5249: for (int i = 0; i < num; i++) {
5250: accept(updateNode, i, context);
5251: cf.add(Opcode.POP);
5252: }
5253: }
5254:
5255: cf.add(Opcode.GOTO, start);
5256: next.fix();
5257: cf.loadLocal(last);
5258: cf.freeLocal(last);
5259: cc.closeScope();
5260: brk.fix();
5261:
5262: cc.closeControlEnv();
5263:
5264: return null;
5265: }
5266:
5267: public Object breakNode(SimpleNode node, Context context) {
5268: CompileContext cc = (CompileContext) context;
5269: ClassFile cf = cc.cf;
5270:
5271: cc.leaveControlEnv();
5272:
5273: if (node.jjtGetNumChildren() > 0) {
5274: accept(node, 0, context);
5275: } else {
5276: cf.add(Opcode.ACONST_NULL);
5277: }
5278:
5279: Label brk = cc.getBreakLabel();
5280: if (brk != null) {
5281: cf.add(Opcode.GOTO, brk);
5282: } else {
5283: if (cc.inGeneratorBlock) {
5284: int value = cf.getLocal();
5285: cf.storeLocal(value);
5286: cf.add(Opcode.NEW, "pnuts.lang.Generator$Break");
5287: cf.add(Opcode.DUP);
5288: cf.loadLocal(value);
5289: cf.freeLocal(value);
5290: cf.add(Opcode.INVOKESPECIAL,
5291: "pnuts.lang.Generator$Break", "<init>",
5292: "(Ljava/lang/Object;)", "V");
5293: cf.add(Opcode.ATHROW);
5294: }
5295: }
5296: return null;
5297: }
5298:
5299: public Object continueNode(SimpleNode node, Context context) {
5300: CompileContext cc = (CompileContext) context;
5301: ClassFile cf = cc.cf;
5302:
5303: cc.leaveControlEnv();
5304:
5305: Label cnt = cc.getContinueLabel();
5306: cf.add(Opcode.ACONST_NULL);
5307: if (cnt != null) {
5308: cf.add(Opcode.GOTO, cnt);
5309: } else {
5310: if (cc.inGeneratorBlock) {
5311: cf.add(Opcode.ARETURN);
5312: }
5313: }
5314: return null;
5315: }
5316:
5317: public Object returnNode(SimpleNode node, Context context) {
5318: CompileContext cc = (CompileContext) context;
5319: ClassFile cf = cc.cf;
5320:
5321: cc.leaveFrame();
5322:
5323: if (node.jjtGetNumChildren() > 0) {
5324: accept(node, 0, context);
5325: } else {
5326: cf.add(Opcode.ACONST_NULL);
5327: }
5328:
5329: if (cc.env.parent != null) {
5330: if (cc.inGeneratorBlock) {
5331: int value = cf.getLocal();
5332: cf.storeLocal(value);
5333: cf.add(Opcode.NEW, "pnuts.lang.Jump");
5334: cf.add(Opcode.DUP);
5335: cf.loadLocal(value);
5336: cf.add(Opcode.INVOKESPECIAL, "pnuts.lang.Jump",
5337: "<init>", "(Ljava/lang/Object;)", "V");
5338: cf.add(Opcode.ATHROW);
5339: } else {
5340: cf.add(Opcode.GOTO, cc.returnLabel);
5341: }
5342: } else {
5343: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime", "jump",
5344: "(Ljava/lang/Object;)", "V");
5345: cf.add(Opcode.ACONST_NULL);
5346: }
5347: return null;
5348: }
5349:
5350: public Object yieldNode(SimpleNode node, Context context) {
5351: throw new PnutsException(
5352: "yield must be used in a generator function", context);
5353: }
5354:
5355: public Object catchNode(SimpleNode node, Context context) {
5356: CompileContext cc = (CompileContext) context;
5357: ClassFile cf = cc.cf;
5358: int ctx = cc.getContextIndex();
5359:
5360: if (node.jjtGetNumChildren() == 0) {
5361: cf.add(Opcode.GETSTATIC, "pnuts.lang.PnutsFunction",
5362: "CATCH", "Lpnuts/lang/PnutsFunction;");
5363: return null;
5364: }
5365:
5366: int cls = cf.getLocal();
5367: int func = cf.getLocal();
5368:
5369: accept(node, 0, context);
5370: cf.add(Opcode.CHECKCAST, "java.lang.Class");
5371: cf.storeLocal(cls);
5372:
5373: accept(node, 1, context);
5374: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
5375: cf.storeLocal(func);
5376:
5377: Reference eref = cc.getReference(EXCEPTOIN_FIELD_SYMBOL);
5378: if (cc.env.parent != null && eref != null) {
5379: int tmap = cf.getLocal();
5380: cf.add(Opcode.NEW, "pnuts.lang.Runtime$TypeMap");
5381: cf.add(Opcode.DUP);
5382: cf.loadLocal(cls);
5383: cf.loadLocal(func);
5384:
5385: getRef(eref, cc);
5386:
5387: cf.add(Opcode.CHECKCAST, "pnuts.lang.Runtime$TypeMap");
5388:
5389: cf
5390: .add(
5391: Opcode.INVOKESPECIAL,
5392: "pnuts.lang.Runtime$TypeMap",
5393: "<init>",
5394: "(Ljava/lang/Class;Ljava/lang/Object;Lpnuts/lang/Runtime$TypeMap;)",
5395: "V");
5396: cf.storeLocal(tmap);
5397: eref.set(cf, tmap);
5398: cf.add(Opcode.ACONST_NULL);
5399:
5400: } else {
5401: cf.loadLocal(cls);
5402: cf.loadLocal(func);
5403: cf.loadLocal(ctx);
5404: cf
5405: .add(
5406: Opcode.INVOKESTATIC,
5407: "pnuts.lang.Runtime",
5408: "catchException",
5409: "(Ljava/lang/Class;Lpnuts/lang/PnutsFunction;Lpnuts/lang/Context;)",
5410: "V");
5411: cf.add(Opcode.ACONST_NULL);
5412: }
5413: cf.freeLocal(cls);
5414: cf.freeLocal(func);
5415: return null;
5416: }
5417:
5418: public Object throwNode(SimpleNode node, Context context) {
5419: CompileContext cc = (CompileContext) context;
5420: ClassFile cf = cc.cf;
5421: int ctx = cc.getContextIndex();
5422:
5423: addLineInfo(cc, ctx, node);
5424:
5425: int n = node.jjtGetNumChildren();
5426: if (n == 0) {
5427: cf.add(Opcode.GETSTATIC, "pnuts.lang.PnutsFunction",
5428: "THROW", "Lpnuts/lang/PnutsFunction;");
5429: } else {
5430: accept(node, 0, context);
5431: int arg = cf.getLocal();
5432: cf.storeLocal(arg);
5433: cf.loadLocal(arg);
5434: cf.add(Opcode.INSTANCEOF, "java.lang.Throwable");
5435: Label throwable = cf.getLabel();
5436: cf.add(Opcode.IFNE, throwable);
5437:
5438: Label next = cf.getLabel();
5439: cf.add(Opcode.NEW, "pnuts.lang.PnutsException");
5440: cf.add(Opcode.DUP);
5441: cf.loadLocal(arg);
5442: cf.add(Opcode.INVOKESTATIC, "java.lang.String", "valueOf",
5443: "(Ljava/lang/Object;)", "Ljava/lang/String;");
5444: cf.loadLocal(cc.getContextIndex());
5445: cf.add(Opcode.INVOKESPECIAL, "pnuts.lang.PnutsException",
5446: "<init>",
5447: "(Ljava/lang/String;Lpnuts/lang/Context;)", "V");
5448: cf.add(Opcode.GOTO, next);
5449: throwable.fix();
5450: cf.loadLocal(arg);
5451: cf.add(Opcode.CHECKCAST, "java.lang.Throwable");
5452:
5453: cf.freeLocal(arg);
5454: next.fix();
5455: cf.add(Opcode.ATHROW);
5456: }
5457: return null;
5458: }
5459:
5460: public Object finallyNode(SimpleNode node, Context context) {
5461: CompileContext cc = (CompileContext) context;
5462: ClassFile cf = cc.cf;
5463: int ctx = cc.getContextIndex();
5464: int n = node.jjtGetNumChildren();
5465: if (n == 0) {
5466: cf.add(Opcode.ACONST_NULL);
5467: } else if (n == 1) {
5468: Frame env = cc.env;
5469: if (env.parent != null) {
5470: env.finallySet = true;
5471: int fin = cf.getLocal();
5472: cc.declare("!finally", fin, -1);
5473: accept(node, 0, context);
5474: cf.storeLocal(fin);
5475: cf.loadLocal(fin);
5476: } else {
5477: cf.loadLocal(ctx);
5478: int val = cf.getLocal();
5479: accept(node, 0, context);
5480: cf.storeLocal(val);
5481: cf.loadLocal(val);
5482: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
5483: cf
5484: .add(
5485: Opcode.INVOKESTATIC,
5486: "pnuts.lang.Runtime",
5487: "setExitHook",
5488: "(Lpnuts/lang/Context;Lpnuts/lang/PnutsFunction;)",
5489: "V");
5490: cf.loadLocal(val);
5491: }
5492: } else if (n == 2) {
5493: int value = cf.getLocal();
5494: int retAddr = cf.getLocal();
5495: Label catchStart = cf.getLabel(true);
5496: Label jsrTag = cf.getLabel();
5497:
5498: accept(node, 0, context);
5499: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
5500: cf.add(Opcode.GETSTATIC, cc.constClassName, "NO_PARAM",
5501: "[Ljava/lang/Object;");
5502: cf.loadLocal(ctx);
5503: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
5504: "call",
5505: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
5506: "Ljava/lang/Object;");
5507: cf.storeLocal(value);
5508:
5509: Label catchEnd = cf.getLabel(true);
5510:
5511: cf.add(Opcode.JSR, jsrTag);
5512:
5513: cf.loadLocal(value);
5514: cf.add(Opcode.ARETURN);
5515:
5516: Label finallyTag = cf.getLabel(true);
5517:
5518: cf.reserveStack(1);
5519: cf.add(Opcode.ATHROW);
5520:
5521: jsrTag.fix();
5522:
5523: cf.reserveStack(1);
5524: cf.storeLocal(retAddr);
5525: accept(node, 1, context);
5526: cf.add(Opcode.CHECKCAST, "pnuts.lang.PnutsFunction");
5527: cf.add(Opcode.GETSTATIC, cc.constClassName, "NO_PARAM",
5528: "[Ljava/lang/Object;");
5529: cf.loadLocal(ctx);
5530: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.PnutsFunction",
5531: "call",
5532: "([Ljava/lang/Object;Lpnuts/lang/Context;)",
5533: "Ljava/lang/Object;");
5534: cf.add(Opcode.POP);
5535: cf.add(Opcode.RET, retAddr);
5536:
5537: cf.addExceptionHandler(catchStart, catchEnd, finallyTag,
5538: null);
5539: }
5540: return null;
5541: }
5542:
5543: /*
5544: * while or do..while
5545: */
5546: private Object conditionLoop(SimpleNode node, Context context,
5547: boolean isDoWhile) {
5548: CompileContext cc = (CompileContext) context;
5549: ClassFile cf = cc.cf;
5550: int ctx = cc.getContextIndex();
5551:
5552: addLineInfo(cc, ctx, node);
5553:
5554: cf.add(Opcode.ACONST_NULL);
5555: int last = cf.getLocal();
5556: cf.storeLocal(last);
5557:
5558: Label start = cf.getLabel(true);
5559: Label next = cf.getLabel();
5560: Label brk = cf.getLabel();
5561: Label cont = cf.getLabel();
5562:
5563: ControlEnv env;
5564: if (isDoWhile) {
5565: env = cc
5566: .openControlEnv(PnutsParserTreeConstants.JJTDOSTATEMENT);
5567: } else {
5568: env = cc
5569: .openControlEnv(PnutsParserTreeConstants.JJTWHILESTATEMENT);
5570: }
5571: env.breakLabel = brk;
5572: env.continueLabel = cont;
5573:
5574: if (isDoWhile) {
5575: if (traceMode) {
5576: addLineInfo(cc, ctx, node);
5577: }
5578: accept(node, 0, context);
5579: cont.fix();
5580: cf.storeLocal(last);
5581: }
5582:
5583: SimpleNode condNode = node.jjtGetChild(isDoWhile ? 1 : 0);
5584: condNode.accept(this , context);
5585:
5586: if (condNode.getAttribute("inlinedBoolean") != null) {
5587: cf.add(Opcode.IFEQ, next);
5588: } else {
5589: booleanCheck(node.jjtGetChild(0).id, cf, context);
5590: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
5591: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
5592: "booleanValue", "()", "Z");
5593: cf.add(Opcode.IFEQ, next);
5594: }
5595:
5596: if (!isDoWhile) {
5597: if (traceMode) {
5598: addLineInfo(cc, ctx, node);
5599: }
5600: accept(node, 1, context);
5601: cont.fix();
5602: cf.storeLocal(last);
5603: }
5604: cf.add(Opcode.GOTO, start);
5605:
5606: next.fix();
5607:
5608: cc.closeControlEnv();
5609:
5610: cf.loadLocal(last);
5611: cf.freeLocal(last);
5612: brk.fix();
5613: return null;
5614: }
5615:
5616: public Object doStatement(SimpleNode node, Context context) {
5617: return conditionLoop(node, context, true);
5618: }
5619:
5620: public Object whileStatement(SimpleNode node, Context context) {
5621: return conditionLoop(node, context, false);
5622: }
5623:
5624: private void doGenerator(String[] vars, int tgt,
5625: SimpleNode blockNode, CompileContext cc, ClassFile cf) {
5626: String cls = className + "$"
5627: + (classCount++ & 0x7fffffffffffffffL);
5628:
5629: String tmpVar;
5630: if (vars.length > 1) {
5631: tmpVar = "_tmp";
5632: blockNode = GeneratorHelper.expandMultiAssign(vars, tmpVar,
5633: blockNode);
5634: } else {
5635: tmpVar = vars[0];
5636: }
5637:
5638: ClassFile cf2 = new ClassFile(cls, "pnuts.lang.PnutsFunction",
5639: sourceFile, Constants.ACC_PUBLIC);
5640: cf2.addInterface("pnuts.compiler.Compiled");
5641: cc.classFiles.add(cf2);
5642: CompileContext cc2 = (CompileContext) cc.clone();
5643: cc2.returnLabel = cf2.getLabel();
5644: cc2.cf = cf2;
5645:
5646: cc2._openFrame(null, new String[] { tmpVar }, false);
5647: cf2
5648: .openMethod(
5649: "exec",
5650: "([Ljava/lang/Object;Lpnuts/lang/Context;)Ljava/lang/Object;",
5651: Constants.ACC_PROTECTED);
5652: cc2.setContextIndex(2);
5653: cc2.inGeneratorBlock = true;
5654:
5655: cf2.loadLocal(0);
5656: cf2.add(Opcode.GETFIELD, cls, "$context$",
5657: "Lpnuts/lang/Context;");
5658: cf2.storeLocal(2);
5659:
5660: cc2._declare(tmpVar, 1, 0);
5661:
5662: blockNode.accept(this , cc2);
5663:
5664: cc2.returnLabel.fix();
5665: cf2.add(Opcode.ARETURN);
5666:
5667: cc2.inGeneratorBlock = false;
5668: cf2.closeMethod();
5669:
5670: StringBuffer arg = new StringBuffer("(");
5671: int n_names = 0;
5672: if (cc2.env.imports != null) {
5673: n_names = cc2.env.imports.size();
5674: }
5675: String names[] = new String[n_names];
5676: int j = 0;
5677: if (n_names > 0) {
5678: List imports = cc2.env.imports;
5679: for (int i = 0, n = imports.size(); i < n; i++) {
5680: String sym = (String) imports.get(i);
5681: names[j++] = sym;
5682: arg.append("[Ljava/lang/Object;");
5683: }
5684: }
5685:
5686: arg.append("Lpnuts/lang/Context;");
5687: arg.append(")");
5688:
5689: cf2.openMethod("<init>", arg + "V", Constants.ACC_PUBLIC);
5690: cf2.add(Opcode.ALOAD_0);
5691: cf2.add(Opcode.INVOKESPECIAL, "pnuts.lang.PnutsFunction",
5692: "<init>", "()", "V");
5693:
5694: for (int i = 0; i < n_names; i++) {
5695: cf2.addField(names[i], "[Ljava/lang/Object;", (short) 0);
5696: cf2.add(Opcode.ALOAD_0);
5697: cf2.add(Opcode.ALOAD, 1 + i);
5698: cf2.add(Opcode.PUTFIELD, cf2.getClassName(), names[i],
5699: "[Ljava/lang/Object;");
5700: }
5701:
5702: cf2.addField("$context$", "Lpnuts/lang/Context;", (short) 0);
5703: cf2.add(Opcode.ALOAD_0);
5704: cf2.add(Opcode.ALOAD, 1 + n_names);
5705: cf2.add(Opcode.PUTFIELD, cf2.getClassName(), "$context$",
5706: "Lpnuts/lang/Context;");
5707:
5708: cf2.add(Opcode.RETURN);
5709: cf2.closeMethod();
5710:
5711: cf.loadLocal(tgt);
5712: cf.add(Opcode.CHECKCAST, "pnuts.lang.Generator");
5713: cf.add(Opcode.NEW, cls);
5714: cf.add(Opcode.DUP);
5715:
5716: ArrayList exports = (ArrayList) cc.env.exports.get(cc2.env);
5717:
5718: cc2._closeFrame();
5719:
5720: if (exports != null) {
5721:
5722: int size = exports.size();
5723: for (int i = 0; i < size; i++) {
5724: Reference ref = (Reference) exports.get(i);
5725: if (ref.index < 0) {
5726: cf.add(Opcode.ALOAD_0);
5727: cf.add(Opcode.GETFIELD, cf.getClassName(),
5728: ref.symbol, "[Ljava/lang/Object;");
5729: } else if (ref.offset < 0) {
5730: cf.add(Opcode.ICONST_1);
5731: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
5732: cf.add(Opcode.DUP);
5733: cf.add(Opcode.ICONST_0);
5734: cf.loadLocal(ref.index);
5735: cf.add(Opcode.AASTORE);
5736: } else {
5737: cf.loadLocal(ref.index);
5738: Label l1 = cf.getLabel();
5739: cf.add(Opcode.IFNONNULL, l1);
5740: cf.add(Opcode.ICONST_1);
5741: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
5742: cf.storeLocal(ref.index);
5743: l1.fix();
5744: cf.loadLocal(ref.index);
5745: cf.add(Opcode.CHECKCAST, "[Ljava/lang/Object;");
5746: }
5747: }
5748: }
5749:
5750: cf.loadLocal(cc.getContextIndex());
5751: cf
5752: .add(Opcode.INVOKESPECIAL, cls, "<init>", arg
5753: .toString(), "V");
5754:
5755: cf.loadLocal(cc.getContextIndex());
5756: cf
5757: .add(
5758: Opcode.INVOKESTATIC,
5759: "pnuts.lang.Runtime",
5760: "applyGenerator",
5761: "(Lpnuts/lang/Generator;Lpnuts/lang/PnutsFunction;Lpnuts/lang/Context;)",
5762: "Ljava/lang/Object;");
5763: }
5764:
5765: private void doForeach(String[] vars, SimpleNode collectionNode,
5766: SimpleNode blockNode, CompileContext cc, ClassFile cf) {
5767: int ctx = cc.getContextIndex();
5768: cc.openScope(vars);
5769: /*
5770: Reference count = cc.getReference(vars[0]);
5771: cf.add(Opcode.ICONST_1);
5772: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
5773: cf.storeLocal(count.index);
5774: */
5775: Reference[] count = new Reference[vars.length];
5776: for (int i = 0; i < vars.length; i++) {
5777: count[i] = cc.getReference(vars[i]);
5778: cf.add(Opcode.ICONST_1);
5779: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
5780: cf.storeLocal(count[i].index);
5781: }
5782:
5783: Label next = cf.getLabel();
5784: Label brk = cf.getLabel();
5785:
5786: ControlEnv env = cc
5787: .openControlEnv(PnutsParserTreeConstants.JJTFORSTATEMENT);
5788: env.breakLabel = brk;
5789:
5790: int last = cf.getLocal();
5791: cf.add(Opcode.ACONST_NULL);
5792: cf.storeLocal(last);
5793:
5794: collectionNode.accept(this , cc);
5795: int tgt = cf.getLocal();
5796: cf.add(Opcode.DUP);
5797: cf.storeLocal(tgt);
5798:
5799: Label nonnull = cf.getLabel();
5800:
5801: cf.add(Opcode.IFNONNULL, nonnull);
5802: cf.add(Opcode.GOTO, next);
5803: nonnull.fix();
5804:
5805: cf.loadLocal(tgt);
5806: cf.add(Opcode.INSTANCEOF, "pnuts.lang.Generator");
5807: Label fn = cf.getLabel();
5808: cf.add(Opcode.IFNE, fn);
5809:
5810: cf.loadLocal(tgt);
5811: cf.loadLocal(cc.getContextIndex());
5812: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
5813: "toEnumeration",
5814: "(Ljava/lang/Object;Lpnuts/lang/Context;)",
5815: "Ljava/util/Enumeration;");
5816: int tmp1 = cf.getLocal();
5817: cf.storeLocal(tmp1);
5818: cf.loadLocal(tmp1);
5819:
5820: Label err = cf.getLabel();
5821: cf.add(Opcode.IFNULL, err);
5822:
5823: Label loop2 = cf.getLabel();
5824: cf.add(Opcode.GOTO, loop2);
5825: Label body = cf.getLabel(true);
5826:
5827: cf.loadLocal(tmp1);
5828: cf.add(Opcode.CHECKCAST, "java.util.Enumeration");
5829: cf.add(Opcode.INVOKEINTERFACE, "java.util.Enumeration",
5830: "nextElement", "()", "Ljava/lang/Object;");
5831:
5832: int tmp2 = cf.getLocal();
5833: cf.storeLocal(tmp2);
5834:
5835: if (vars.length > 1) { // multi-assignment
5836: int tmp3 = cf.getLocal();
5837: for (int i = 0; i < vars.length; i++) {
5838: cf.loadLocal(tmp2);
5839: cf.pushInteger(i);
5840: cf.loadLocal(ctx);
5841: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
5842: "getElementAt",
5843: "(Ljava/lang/Object;ILpnuts/lang/Context;)",
5844: "Ljava/lang/Object;");
5845: cf.storeLocal(tmp3);
5846: count[i].set(cf, tmp3);
5847: }
5848: } else {
5849: count[0].set(cf, tmp2);
5850: }
5851:
5852: Label cont = cf.getLabel();
5853: env.continueLabel = cont;
5854:
5855: blockNode.accept(this , cc);
5856: cont.fix();
5857: cf.storeLocal(last);
5858:
5859: loop2.fix();
5860: cf.loadLocal(tmp1);
5861: cf.add(Opcode.CHECKCAST, "java.util.Enumeration");
5862: cf.add(Opcode.INVOKEINTERFACE, "java.util.Enumeration",
5863: "hasMoreElements", "()", "Z");
5864: cf.add(Opcode.IFEQ, next);
5865: cf.add(Opcode.GOTO, body);
5866:
5867: fn.fix();
5868: doGenerator(vars, tgt, blockNode, cc, cf);
5869: cf.storeLocal(last);
5870: cf.add(Opcode.GOTO, next);
5871:
5872: err.fix();
5873: error(cf, "illegal.type.foreach", new int[] { tgt }, cc);
5874:
5875: next.fix();
5876: cf.loadLocal(last);
5877: cf.freeLocal(last);
5878: cf.freeLocal(tmp1);
5879: cf.freeLocal(tmp2);
5880: cf.freeLocal(tgt);
5881:
5882: cc.closeControlEnv();
5883:
5884: cc.closeScope();
5885: brk.fix();
5886: }
5887:
5888: private void doForeachRange(String var, SimpleNode startNode,
5889: SimpleNode endNode, SimpleNode blockNode,
5890: CompileContext cc, ClassFile cf) {
5891: cc.openScope(new String[] { var });
5892: Reference count = cc.getReference(var);
5893: cf.add(Opcode.ICONST_1);
5894: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
5895: cf.storeLocal(count.index);
5896:
5897: Label next = cf.getLabel();
5898: Label brk = cf.getLabel();
5899:
5900: ControlEnv env = cc
5901: .openControlEnv(PnutsParserTreeConstants.JJTFORSTATEMENT);
5902: env.breakLabel = brk;
5903:
5904: int last = cf.getLocal();
5905: int tmp = cf.getLocal();
5906: cf.add(Opcode.ACONST_NULL);
5907: cf.storeLocal(last);
5908:
5909: int start = cf.getLocal();
5910: startNode.accept(this , cc);
5911: cf.add(Opcode.CHECKCAST, "java.lang.Number");
5912: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Number", "intValue",
5913: "()", "I");
5914: cf.istoreLocal(start);
5915:
5916: int end = cf.getLocal();
5917: endNode.accept(this , cc);
5918: cf.add(Opcode.CHECKCAST, "java.lang.Number");
5919: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Number", "intValue",
5920: "()", "I");
5921: cf.istoreLocal(end);
5922:
5923: cf.iloadLocal(start);
5924: cf.iloadLocal(end);
5925: Label loop2 = cf.getLabel();
5926: cf.add(Opcode.IF_ICMPGT, loop2);
5927:
5928: Label loop1 = cf.getLabel(true);
5929:
5930: cf.iloadLocal(start);
5931: cf.iloadLocal(end);
5932: cf.add(Opcode.IF_ICMPGT, next);
5933:
5934: if (hasValueOfPrimitive) {
5935: cf.iloadLocal(start);
5936: cf.add(Opcode.INVOKESTATIC, "java.lang.Integer", "valueOf",
5937: "(I)", "Ljava/lang/Integer;");
5938: } else {
5939: cf.add(Opcode.NEW, "java.lang.Integer");
5940: cf.add(Opcode.DUP);
5941: cf.iloadLocal(start);
5942: cf.add(Opcode.INVOKESPECIAL, "java.lang.Integer", "<init>",
5943: "(I)", "V");
5944: }
5945:
5946: cf.storeLocal(tmp);
5947: count.set(cf, tmp);
5948:
5949: Label cont = cf.getLabel();
5950: env.continueLabel = cont;
5951:
5952: blockNode.accept(this , cc);
5953: cont.fix();
5954: cf.storeLocal(last);
5955:
5956: cf.add(Opcode.IINC, start, 1);
5957: cf.add(Opcode.GOTO, loop1);
5958:
5959: loop2.fix();
5960:
5961: cf.iloadLocal(start);
5962: cf.iloadLocal(end);
5963: cf.add(Opcode.IF_ICMPLT, next);
5964:
5965: if (hasValueOfPrimitive) {
5966: cf.iloadLocal(start);
5967: cf.add(Opcode.INVOKESTATIC, "java.lang.Integer", "valueOf",
5968: "(I)", "Ljava/lang/Integer;");
5969: } else {
5970: cf.add(Opcode.NEW, "java.lang.Integer");
5971: cf.add(Opcode.DUP);
5972: cf.iloadLocal(start);
5973: cf.add(Opcode.INVOKESPECIAL, "java.lang.Integer", "<init>",
5974: "(I)", "V");
5975: }
5976:
5977: cf.storeLocal(tmp);
5978: count.set(cf, tmp);
5979:
5980: Label cont2 = cf.getLabel();
5981: env.continueLabel = cont2;
5982:
5983: blockNode.accept(this , cc);
5984: cont2.fix();
5985: cf.storeLocal(last);
5986:
5987: cf.add(Opcode.IINC, start, -1);
5988: cf.add(Opcode.GOTO, loop2);
5989:
5990: next.fix();
5991: cf.loadLocal(last);
5992: cf.freeLocal(last);
5993: cf.freeLocal(tmp);
5994: cf.freeLocal(start);
5995: cf.freeLocal(end);
5996:
5997: cc.closeControlEnv();
5998:
5999: cc.closeScope();
6000: brk.fix();
6001: }
6002:
6003: public Object foreachStatement(SimpleNode node, Context context) {
6004: CompileContext cc = (CompileContext) context;
6005: ClassFile cf = cc.cf;
6006: int ctx = cc.getContextIndex();
6007:
6008: addLineInfo(cc, ctx, node);
6009:
6010: doForeach(new String[] { node.str }, node.jjtGetChild(0), node
6011: .jjtGetChild(1), cc, cf);
6012: return null;
6013: }
6014:
6015: public Object switchStatement(SimpleNode node, Context context) {
6016: CompileContext cc = (CompileContext) context;
6017: ClassFile cf = cc.cf;
6018: int ctx = cc.getContextIndex();
6019:
6020: addLineInfo(cc, ctx, node);
6021:
6022: int n = node.jjtGetNumChildren();
6023: accept(node, 0, context);
6024: int tgt = cf.getLocal();
6025: cf.storeLocal(tgt);
6026:
6027: cc.openScope(new String[] {});
6028:
6029: int match = cf.getLocal();
6030: cf.add(Opcode.ICONST_0);
6031: cf.istoreLocal(match);
6032: int last = cf.getLocal();
6033: cf.add(Opcode.ACONST_NULL);
6034: cf.storeLocal(last);
6035:
6036: Label next = cf.getLabel();
6037:
6038: ControlEnv env = cc
6039: .openControlEnv(PnutsParserTreeConstants.JJTSWITCHSTATEMENT);
6040: env.breakLabel = next;
6041:
6042: for (int i = 1; i < n; i++) {
6043: SimpleNode _node = node.jjtGetChild(i);
6044: if (_node.jjtGetNumChildren() == 1) { // case
6045: cf.iloadLocal(match);
6046: Label hit = cf.getLabel();
6047: cf.add(Opcode.IFNE, hit);
6048: i++;
6049: accept(_node, 0, context);
6050: cf.loadLocal(tgt);
6051: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime", "eq",
6052: "(Ljava/lang/Object;Ljava/lang/Object;)", "Z");
6053: Label cont = cf.getLabel();
6054: cf.add(Opcode.IFEQ, cont);
6055: cf.add(Opcode.ICONST_1); // match = 1
6056: cf.istoreLocal(match);
6057: hit.fix();
6058: accept(node, i, context);
6059: cf.storeLocal(last);
6060: cont.fix();
6061: } else { // default
6062: cf.add(Opcode.ICONST_1);
6063: cf.istoreLocal(match);
6064: accept(node, ++i, context);
6065: cf.storeLocal(last);
6066: }
6067: }
6068: cf.freeLocal(tgt);
6069: cf.freeLocal(match);
6070: cf.loadLocal(last);
6071: next.fix();
6072:
6073: cc.closeControlEnv();
6074: cc.closeScope();
6075:
6076: return null;
6077: }
6078:
6079: public Object switchBlock(SimpleNode node, Context context) {
6080: CompileContext cc = (CompileContext) context;
6081: ClassFile cf = cc.cf;
6082:
6083: int n = node.jjtGetNumChildren();
6084: if (n > 0) {
6085: int m = n - 1;
6086: for (int i = 0; i < m; i++) {
6087: accept(node, i, context);
6088: cf.add(Opcode.POP);
6089: }
6090: accept(node, m, context);
6091: } else {
6092: cf.add(Opcode.ACONST_NULL);
6093: }
6094: return null;
6095: }
6096:
6097: public Object ternary(SimpleNode node, Context context) {
6098: CompileContext cc = (CompileContext) context;
6099: ClassFile cf = cc.cf;
6100: SimpleNode condNode = node.jjtGetChild(0);
6101: condNode.accept(this , context);
6102:
6103: Label l_else = cf.getLabel();
6104: Label next = cf.getLabel();
6105:
6106: if (condNode.getAttribute("inlinedBoolean") != null) {
6107: cf.add(Opcode.IFEQ, l_else);
6108: accept(node, 1, context);
6109: cf.add(Opcode.GOTO, next);
6110: l_else.fix();
6111: cf.popStack();
6112: } else {
6113: booleanCheck(node.jjtGetChild(0).id, cf, context);
6114: cf.add(Opcode.CHECKCAST, "java.lang.Boolean");
6115: cf.add(Opcode.INVOKEVIRTUAL, "java.lang.Boolean",
6116: "booleanValue", "()", "Z");
6117: cf.add(Opcode.IFEQ, l_else);
6118: accept(node, 1, context);
6119: cf.add(Opcode.GOTO, next);
6120: l_else.fix();
6121: cf.popStack();
6122: }
6123: accept(node, 2, context);
6124: next.fix();
6125: return null;
6126: }
6127:
6128: static String getPackageName(SimpleNode node) {
6129: if (node.jjtGetNumChildren() > 0) {
6130: SimpleNode c1 = node.jjtGetChild(0);
6131: return getPackageName(c1) + "::" + node.str;
6132: } else {
6133: return node.str;
6134: }
6135: }
6136:
6137: static String gensym(Context context) {
6138: return ((CompileContext) context).sym.gen();
6139: }
6140:
6141: protected Object accept(SimpleNode node, int idx, Context context) {
6142: return node.jjtGetChild(idx).accept(this , context);
6143: }
6144:
6145: private Object assign(SimpleNode node, Context context, int id) {
6146: accept(node, 1, context);
6147: _assign(node.jjtGetChild(0), context, id, false, true);
6148: return null;
6149: }
6150:
6151: private Object _assign(SimpleNode lhs, Context context, int id,
6152: boolean mutable, boolean nopop) {
6153: CompileContext cc = (CompileContext) context;
6154: ClassFile cf = cc.cf;
6155: int ctx = cc.getContextIndex();
6156: int rhs = cf.getLocal();
6157: if ((id & 0x8000) == 0) {
6158: cf.storeLocal(rhs);
6159: }
6160:
6161: if (lhs.id == PnutsParserTreeConstants.JJTIDNODE) {
6162: assignId(cf, id, ctx, rhs, lhs, cc, mutable, nopop);
6163: } else if (lhs.id == PnutsParserTreeConstants.JJTGLOBAL) {
6164: assignGlobal(cf, id, ctx, rhs, lhs, cc, nopop);
6165: } else if (lhs.id == PnutsParserTreeConstants.JJTINDEXNODE) {
6166: assignIndex(cf, id, ctx, rhs, lhs, cc, nopop);
6167: } else if (lhs.id == PnutsParserTreeConstants.JJTSTATICMEMBERNODE) {
6168: assignStaticMember(cf, id, ctx, rhs, lhs, cc, nopop);
6169: } else if (lhs.id == PnutsParserTreeConstants.JJTMEMBERNODE) {
6170: assignMember(cf, id, ctx, rhs, lhs, cc, nopop);
6171: } else if (lhs.id == PnutsParserTreeConstants.JJTRANGENODE
6172: && id == PnutsParserTreeConstants.JJTASSIGNMENT) {
6173: assignRange(cf, id, ctx, rhs, lhs, cc);
6174: } else {
6175: throw new PnutsException("illegal.assign", new Object[] {},
6176: context);
6177: }
6178: cf.freeLocal(rhs);
6179: return null;
6180: }
6181:
6182: boolean inControl(SimpleNode node, CompileContext cc) {
6183: while (node != null) {
6184: if (node.id == PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT
6185: || node.id == PnutsParserTreeConstants.JJTMETHODDEF) {
6186: return false;
6187: } else if (cc.inGeneratorBlock
6188: && (node.id == PnutsParserTreeConstants.JJTFOREACHSTATEMENT || node.id == PnutsParserTreeConstants.JJTFORSTATEMENT
6189: && node.jjtGetChild(0).id == PnutsParserTreeConstants.JJTFORENUM)) {
6190: return false;
6191: } else if (node.id == PnutsParserTreeConstants.JJTSWITCHSTATEMENT
6192: || node.id == PnutsParserTreeConstants.JJTFOREACHSTATEMENT
6193: || node.id == PnutsParserTreeConstants.JJTFORSTATEMENT
6194: || node.id == PnutsParserTreeConstants.JJTWHILESTATEMENT
6195: || node.id == PnutsParserTreeConstants.JJTDOSTATEMENT
6196: || node.id == PnutsParserTreeConstants.JJTIFSTATEMENT) {
6197: return true;
6198: }
6199: node = node.jjtGetParent();
6200: }
6201: return false;
6202: }
6203:
6204: static boolean isConditionalNode(SimpleNode node) {
6205: int id = node.jjtGetParent().id;
6206: return id == PnutsParserTreeConstants.JJTIFSTATEMENT
6207: || id == PnutsParserTreeConstants.JJTELSEIFNODE
6208: || id == PnutsParserTreeConstants.JJTFORSTATEMENT
6209: || id == PnutsParserTreeConstants.JJTWHILESTATEMENT
6210: || id == PnutsParserTreeConstants.JJTDOSTATEMENT;
6211:
6212: }
6213:
6214: void assignId(ClassFile cf, int id, int ctx, int rhs,
6215: SimpleNode lhs, CompileContext cc, boolean mutable,
6216: boolean nopop) {
6217: Reference ref = cc.findReference(lhs.str);
6218: Frame env = cc.env;
6219:
6220: if (cc.inGeneratorBlock) {
6221: if (ref == null) {
6222: if (cc.env != null && cc.env.parent != null) {
6223: int ret = -1;
6224: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6225: if ((id & 0x8000) == 0) {
6226: cf.loadLocal(ctx);
6227: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6228: cf.add(Opcode.INVOKEVIRTUAL,
6229: "pnuts.lang.Context", "getId",
6230: "(Ljava/lang/String;)",
6231: "Ljava/lang/Object;");
6232: ret = cf.getLocal();
6233: cf.storeLocal(ret);
6234: cf.loadLocal(ret);
6235: cf.loadLocal(rhs);
6236: }
6237: compute(cf, id, ctx);
6238: cf.storeLocal(rhs);
6239: }
6240: cf.loadLocal(ctx);
6241: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
6242: "getCurrentPackage", "()",
6243: "Lpnuts/lang/Package;");
6244: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6245: cf.loadLocal(rhs);
6246: cf.loadLocal(ctx);
6247: cf
6248: .add(
6249: Opcode.INVOKEVIRTUAL,
6250: "pnuts.lang.Package",
6251: "set",
6252: "(Ljava/lang/String;Ljava/lang/Object;Lpnuts/lang/Context;)",
6253: "V");
6254: if (nopop) {
6255: cf.loadLocal(rhs);
6256: }
6257:
6258: return;
6259: }
6260: }
6261: }
6262:
6263: if (cc.env.parent != null && !mutable) {
6264: int idx = 0;
6265:
6266: if (ref == null) {
6267: cc.declare(lhs.str);
6268: ref = cc.getReference(lhs.str);
6269: } else if (id == PnutsParserTreeConstants.JJTASSIGNMENT) {
6270: cc.redefine(lhs.str);
6271: }
6272: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6273: if ((id & 0x8000) == 0) {
6274: getRef(ref, cc);
6275: cf.loadLocal(rhs);
6276: }
6277: compute(cf, id, ctx);
6278: cf.storeLocal(rhs);
6279: }
6280: ref.set(cf, rhs);
6281:
6282: if (!inControl(lhs, cc)) {
6283: cc.setReference(lhs.str);
6284: }
6285:
6286: if (nopop) {
6287: cf.loadLocal(rhs);
6288: }
6289: } else {
6290: if (ref != null) {
6291: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6292: if ((id & 0x8000) == 0) {
6293: getRef(ref, cc);
6294: cf.loadLocal(rhs);
6295: }
6296: compute(cf, id, ctx);
6297: cf.storeLocal(rhs);
6298: }
6299: ref.set(cf, rhs);
6300: if (nopop) {
6301: cf.loadLocal(rhs);
6302: }
6303: } else {
6304: int ret = -1;
6305: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6306: if ((id & 0x8000) == 0) {
6307: cf.loadLocal(ctx);
6308: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6309: cf.add(Opcode.INVOKEVIRTUAL,
6310: "pnuts.lang.Context", "getId",
6311: "(Ljava/lang/String;)",
6312: "Ljava/lang/Object;");
6313: ret = cf.getLocal();
6314: cf.storeLocal(ret);
6315: cf.loadLocal(ret);
6316: cf.loadLocal(rhs);
6317: }
6318: compute(cf, id, ctx);
6319: cf.storeLocal(rhs);
6320: }
6321: cf.loadLocal(ctx);
6322: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
6323: "getCurrentPackage", "()",
6324: "Lpnuts/lang/Package;");
6325: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6326: cf.loadLocal(rhs);
6327: cf.loadLocal(ctx);
6328: cf
6329: .add(
6330: Opcode.INVOKEVIRTUAL,
6331: "pnuts.lang.Package",
6332: "set",
6333: "(Ljava/lang/String;Ljava/lang/Object;Lpnuts/lang/Context;)",
6334: "V");
6335: if (nopop) {
6336: cf.loadLocal(rhs);
6337: }
6338: }
6339: }
6340: }
6341:
6342: void assignMember(ClassFile cf, int id, int ctx, int rhs,
6343: SimpleNode lhs, CompileContext cc, boolean nopop) {
6344: accept(lhs, 0, cc);
6345: int tgt = cf.getLocal();
6346: cf.storeLocal(tgt);
6347: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6348: if ((id & 0x8000) == 0) {
6349: cf.loadLocal(ctx);
6350: cf.loadLocal(tgt);
6351: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6352: cf
6353: .add(
6354: Opcode.INVOKESTATIC,
6355: "pnuts.lang.Runtime",
6356: "getField",
6357: "(Lpnuts/lang/Context;Ljava/lang/Object;Ljava/lang/String;)",
6358: "Ljava/lang/Object;");
6359: cf.loadLocal(rhs);
6360: }
6361: compute(cf, id, ctx);
6362: cf.storeLocal(rhs);
6363: }
6364:
6365: cf.loadLocal(ctx);
6366: cf.loadLocal(tgt);
6367: cf.freeLocal(tgt);
6368: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6369: cf.loadLocal(rhs);
6370: cf
6371: .add(
6372: Opcode.INVOKESTATIC,
6373: "pnuts.lang.Runtime",
6374: "putField",
6375: "(Lpnuts/lang/Context;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)",
6376: "V");
6377: if (nopop) {
6378: cf.loadLocal(rhs);
6379: }
6380: }
6381:
6382: void assignIndex(ClassFile cf, int id, int ctx, int rhs,
6383: SimpleNode lhs, CompileContext cc, boolean nopop) {
6384: SimpleNode idxNode = lhs.jjtGetChild(1);
6385: if (ConstraintsTransformer.isPredicate(idxNode)) {
6386: SimpleNode n = ConstraintsTransformer.buildFunc(idxNode);
6387: lhs.jjtAddChild(n, 1);
6388: n.jjtSetParent(lhs);
6389: }
6390: accept(lhs, 0, cc);
6391: int tgt = cf.getLocal();
6392: cf.storeLocal(tgt);
6393:
6394: accept(lhs, 1, cc);
6395: int idx = cf.getLocal();
6396: cf.storeLocal(idx);
6397:
6398: Label next = cf.getLabel();
6399:
6400: cf.loadLocal(tgt);
6401: cf.add(Opcode.INSTANCEOF, "java.lang.String");
6402: Label l2 = cf.getLabel();
6403: cf.add(Opcode.IFEQ, l2);
6404: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6405: error(cf, "illegal.assign", cc);
6406: } else {
6407: cf.loadLocal(tgt);
6408: cf.add(Opcode.CHECKCAST, "java.lang.String");
6409: cf.loadLocal(idx);
6410: cf.add(Opcode.CHECKCAST, "java.lang.Number");
6411: cf.loadLocal(rhs);
6412:
6413: cf.add(Opcode.INSTANCEOF, "java.lang.Character");
6414: Label ok = cf.getLabel();
6415: cf.add(Opcode.IFNE, ok);
6416: error(cf, "illegal.assign", cc);
6417: ok.fix();
6418: cf.loadLocal(rhs);
6419:
6420: cf
6421: .add(
6422: Opcode.INVOKESTATIC,
6423: "pnuts.lang.Runtime",
6424: "replaceChar",
6425: "(Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Object;)",
6426: "Ljava/lang/String;");
6427:
6428: SimpleNode ch = lhs.jjtGetChild(0);
6429: if (ch.id == PnutsParserTreeConstants.JJTIDNODE
6430: || ch.id == PnutsParserTreeConstants.JJTGLOBAL
6431: || ch.id == PnutsParserTreeConstants.JJTINDEXNODE
6432: || ch.id == PnutsParserTreeConstants.JJTMEMBERNODE
6433: || ch.id == PnutsParserTreeConstants.JJTSTATICMEMBERNODE) {
6434: if (ch.str != null) {
6435: if (cc.env.parent == null
6436: || cc.getReference(ch.str) != null) {
6437: _assign(ch, cc, id, true, true);
6438: }
6439: }
6440: }
6441: cf.add(Opcode.GOTO, next);
6442: }
6443:
6444: l2.fix();
6445:
6446: if (id == PnutsParserTreeConstants.JJTASSIGNMENT) {
6447: cf.loadLocal(tgt);
6448: cf.loadLocal(idx);
6449: cf.loadLocal(rhs);
6450: cf.loadLocal(ctx);
6451: cf
6452: .add(
6453: Opcode.INVOKESTATIC,
6454: "pnuts.lang.Runtime",
6455: "setElement",
6456: "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
6457: "V");
6458: if (nopop) {
6459: cf.loadLocal(rhs);
6460: }
6461: } else {
6462: if ((id & 0x8000) == 0) {
6463: cf.loadLocal(tgt);
6464: cf.loadLocal(idx);
6465: cf.loadLocal(ctx);
6466: cf
6467: .add(
6468: Opcode.INVOKESTATIC,
6469: "pnuts.lang.Runtime",
6470: "getElement",
6471: "(Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
6472: "Ljava/lang/Object;");
6473: cf.loadLocal(rhs);
6474: }
6475: compute(cf, id, ctx);
6476: cf.storeLocal(rhs);
6477: cf.loadLocal(tgt);
6478: cf.loadLocal(idx);
6479: cf.loadLocal(rhs);
6480: cf.loadLocal(ctx);
6481: cf
6482: .add(
6483: Opcode.INVOKESTATIC,
6484: "pnuts.lang.Runtime",
6485: "setElement",
6486: "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
6487: "V");
6488: if (nopop) {
6489: cf.loadLocal(rhs);
6490: }
6491: }
6492: cf.freeLocal(tgt);
6493: cf.freeLocal(idx);
6494: next.fix();
6495: }
6496:
6497: void assignRange(ClassFile cf, int id, int ctx, int rhs,
6498: SimpleNode lhs, CompileContext cc) {
6499: accept(lhs, 0, cc);
6500: int tgt = cf.getLocal();
6501: cf.storeLocal(tgt);
6502:
6503: accept(lhs, 1, cc);
6504: int idx1 = cf.getLocal();
6505: cf.storeLocal(idx1);
6506:
6507: int idx2 = cf.getLocal();
6508: if (lhs.jjtGetNumChildren() >= 3) {
6509: accept(lhs, 2, cc);
6510: } else {
6511: cf.add(Opcode.ACONST_NULL);
6512: }
6513: cf.storeLocal(idx2);
6514:
6515: cf.loadLocal(tgt);
6516: cf.loadLocal(idx1);
6517: cf.freeLocal(idx1);
6518: cf.loadLocal(idx2);
6519: cf.freeLocal(idx2);
6520: cf.loadLocal(rhs);
6521:
6522: cf.loadLocal(cc.getContextIndex());
6523: cf
6524: .add(
6525: Opcode.INVOKESTATIC,
6526: "pnuts.lang.Runtime",
6527: "setRange",
6528: "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
6529: "Ljava/lang/Object;");
6530:
6531: SimpleNode ch = lhs.jjtGetChild(0);
6532: if (ch.id == PnutsParserTreeConstants.JJTIDNODE
6533: || ch.id == PnutsParserTreeConstants.JJTGLOBAL
6534: || ch.id == PnutsParserTreeConstants.JJTINDEXNODE
6535: || ch.id == PnutsParserTreeConstants.JJTMEMBERNODE
6536: || ch.id == PnutsParserTreeConstants.JJTSTATICMEMBERNODE) {
6537: int assigned = cf.getLocal();
6538: cf.storeLocal(assigned);
6539: cf.loadLocal(tgt);
6540: cf.freeLocal(tgt);
6541: cf.add(Opcode.INSTANCEOF, "java.lang.String");
6542: Label no = cf.getLabel();
6543: cf.add(Opcode.IFEQ, no);
6544: cf.loadLocal(assigned);
6545: _assign(ch, cc, id, true, true);
6546: cf.add(Opcode.POP);
6547: no.fix();
6548: cf.loadLocal(assigned);
6549: cf.freeLocal(assigned);
6550: }
6551: }
6552:
6553: void assignStaticMember(ClassFile cf, int id, int ctx, int rhs,
6554: SimpleNode lhs, CompileContext cc, boolean nopop) {
6555: SimpleNode c1 = lhs.jjtGetChild(0);
6556: String pkgName = getPackageName(c1);
6557: cf.add(Opcode.LDC, cf.addConstant(pkgName));
6558: cf.loadLocal(ctx);
6559: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Package", "find",
6560: "(Ljava/lang/String;Lpnuts/lang/Context;)",
6561: "Lpnuts/lang/Package;");
6562: int tgt = cf.getLocal();
6563: cf.storeLocal(tgt);
6564: cf.loadLocal(tgt);
6565:
6566: Label l_null = cf.getLabel();
6567: cf.add(Opcode.IFNULL, l_null);
6568:
6569: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6570: if ((id & 0x8000) == 0) {
6571: cf.loadLocal(tgt);
6572: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6573: cf.loadLocal(ctx);
6574: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Package",
6575: "get",
6576: "(Ljava/lang/String;Lpnuts/lang/Context;)",
6577: "Ljava/lang/Object;");
6578: cf.loadLocal(rhs);
6579: }
6580: compute(cf, id, ctx);
6581: cf.storeLocal(rhs);
6582: }
6583: cf.loadLocal(tgt);
6584: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6585: cf.loadLocal(rhs);
6586: cf.loadLocal(ctx);
6587: cf
6588: .add(
6589: Opcode.INVOKEVIRTUAL,
6590: "pnuts.lang.Package",
6591: "set",
6592: "(Ljava/lang/String;Ljava/lang/Object;Lpnuts/lang/Context;)",
6593: "V");
6594: if (nopop) {
6595: cf.loadLocal(rhs);
6596: }
6597:
6598: Label next = cf.getLabel();
6599: cf.add(Opcode.GOTO, next);
6600: l_null.fix();
6601: if (nopop) {
6602: cf.popStack();
6603: }
6604: c1.accept(this , cc);
6605: cf.add(Opcode.DUP);
6606: cf.storeLocal(tgt);
6607:
6608: cf.add(Opcode.INSTANCEOF, "java.lang.Class");
6609: Label err = cf.getLabel();
6610: cf.add(Opcode.IFEQ, err);
6611: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6612: if ((id & 0x8000) == 0) {
6613: cf.loadLocal(ctx);
6614: cf.loadLocal(tgt);
6615: cf.add(Opcode.CHECKCAST, "java.lang.Class");
6616: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6617: cf
6618: .add(
6619: Opcode.INVOKESTATIC,
6620: "pnuts.lang.Runtime",
6621: "getStaticField",
6622: "(Lpnuts/lang/Context;Ljava/lang/Class;Ljava/lang/String;)",
6623: "Ljava/lang/Object;");
6624: cf.loadLocal(rhs);
6625: }
6626: compute(cf, id, ctx);
6627: cf.storeLocal(rhs);
6628: }
6629: cf.loadLocal(ctx);
6630: cf.loadLocal(tgt);
6631: cf.freeLocal(tgt);
6632: cf.add(Opcode.CHECKCAST, "java.lang.Class");
6633: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6634: cf.loadLocal(rhs);
6635: cf
6636: .add(
6637: Opcode.INVOKESTATIC,
6638: "pnuts.lang.Runtime",
6639: "putStaticField",
6640: "(Lpnuts/lang/Context;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)",
6641: "V");
6642: if (nopop) {
6643: cf.loadLocal(rhs);
6644: }
6645: cf.add(Opcode.GOTO, next);
6646: err.fix();
6647: error(cf, "package.notFound", cc);
6648: next.fix();
6649: }
6650:
6651: void assignGlobal(ClassFile cf, int id, int ctx, int rhs,
6652: SimpleNode lhs, CompileContext cc, boolean nopop) {
6653: cf.add(Opcode.LDC, cf.addConstant(""));
6654: cf.loadLocal(ctx);
6655: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Package", "find",
6656: "(Ljava/lang/String;Lpnuts/lang/Context;)",
6657: "Lpnuts/lang/Package;");
6658: int gbl = cf.getLocal();
6659: cf.storeLocal(gbl);
6660:
6661: if (id != PnutsParserTreeConstants.JJTASSIGNMENT) {
6662: if ((id & 0x8000) == 0) {
6663: cf.loadLocal(gbl);
6664:
6665: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6666: cf.loadLocal(ctx);
6667: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Package",
6668: "get",
6669: "(Ljava/lang/String;Lpnuts/lang/Context;)",
6670: "Ljava/lang/Object;");
6671: cf.loadLocal(rhs);
6672: cf.freeLocal(gbl);
6673: }
6674: compute(cf, id, ctx);
6675: cf.storeLocal(rhs);
6676: }
6677: cf.loadLocal(gbl);
6678: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
6679: cf.loadLocal(rhs);
6680: cf.loadLocal(ctx);
6681: cf
6682: .add(
6683: Opcode.INVOKEVIRTUAL,
6684: "pnuts.lang.Package",
6685: "set",
6686: "(Ljava/lang/String;Ljava/lang/Object;Lpnuts/lang/Context;)",
6687: "V");
6688: if (nopop) {
6689: cf.loadLocal(rhs);
6690: }
6691: }
6692:
6693: void error(ClassFile cf, String keyword, CompileContext cc) {
6694: error(cf, keyword, (int[]) null, cc);
6695: }
6696:
6697: void errorSymbol(ClassFile cf, String keyword, int stringConstant,
6698: CompileContext cc) {
6699: cf.add(Opcode.NEW, "pnuts.lang.PnutsException");
6700: cf.add(Opcode.DUP);
6701: cf.add(Opcode.LDC, cf.addConstant(keyword));
6702: cf.pushInteger(1);
6703: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
6704: cf.add(Opcode.DUP);
6705: cf.pushInteger(0);
6706: cf.add(Opcode.LDC, stringConstant);
6707: cf.add(Opcode.AASTORE);
6708: int ctx = cc.getContextIndex();
6709: cf.loadLocal(ctx);
6710: cf
6711: .add(
6712: Opcode.INVOKESPECIAL,
6713: "pnuts.lang.PnutsException",
6714: "<init>",
6715: "(Ljava/lang/String;[Ljava/lang/Object;Lpnuts/lang/Context;)",
6716: "V");
6717: cf.add(Opcode.ATHROW);
6718: }
6719:
6720: void error(ClassFile cf, String keyword, int[] locals,
6721: CompileContext cc) {
6722: cf.add(Opcode.NEW, "pnuts.lang.PnutsException");
6723: cf.add(Opcode.DUP);
6724: cf.add(Opcode.LDC, cf.addConstant(keyword));
6725: if (locals == null) {
6726: cf.add(Opcode.GETSTATIC, cc.constClassName, "NO_PARAM",
6727: "[Ljava/lang/Object;");
6728: } else {
6729: cf.pushInteger(locals.length);
6730: cf.add(Opcode.ANEWARRAY, "java.lang.Object");
6731: for (int i = 0; i < locals.length; i++) {
6732: cf.add(Opcode.DUP);
6733: cf.pushInteger(i);
6734: cf.loadLocal(locals[i]);
6735: cf.add(Opcode.AASTORE);
6736: }
6737: }
6738:
6739: int ctx = cc.getContextIndex();
6740: cf.loadLocal(ctx);
6741: cf
6742: .add(
6743: Opcode.INVOKESPECIAL,
6744: "pnuts.lang.PnutsException",
6745: "<init>",
6746: "(Ljava/lang/String;[Ljava/lang/Object;Lpnuts/lang/Context;)",
6747: "V");
6748: cf.add(Opcode.ATHROW);
6749: }
6750:
6751: void compute(ClassFile cf, int id, int ctx) {
6752: cf.loadLocal(ctx);
6753: String method;
6754: switch (id) {
6755: case PnutsParserTreeConstants.JJTASSIGNMENTTA:
6756: method = "multiply";
6757: break;
6758: case PnutsParserTreeConstants.JJTASSIGNMENTMA:
6759: method = "mod";
6760: break;
6761: case PnutsParserTreeConstants.JJTASSIGNMENTDA:
6762: method = "divide";
6763: break;
6764: case PnutsParserTreeConstants.JJTASSIGNMENTPA:
6765: method = "add";
6766: break;
6767: case PnutsParserTreeConstants.JJTASSIGNMENTPA | 0x8000:
6768: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime", "add1",
6769: "(Ljava/lang/Object;Lpnuts/lang/Context;)",
6770: "Ljava/lang/Object;");
6771: return;
6772: case PnutsParserTreeConstants.JJTASSIGNMENTSA:
6773: method = "subtract";
6774: break;
6775: case PnutsParserTreeConstants.JJTASSIGNMENTSA | 0x8000:
6776: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
6777: "subtract1",
6778: "(Ljava/lang/Object;Lpnuts/lang/Context;)",
6779: "Ljava/lang/Object;");
6780: return;
6781: case PnutsParserTreeConstants.JJTASSIGNMENTLA:
6782: method = "shiftLeft";
6783: break;
6784: case PnutsParserTreeConstants.JJTASSIGNMENTRA:
6785: method = "shiftRight";
6786: break;
6787: case PnutsParserTreeConstants.JJTASSIGNMENTRAA:
6788: method = "shiftArithmetic";
6789: break;
6790: case PnutsParserTreeConstants.JJTASSIGNMENTAA:
6791: method = "and";
6792: break;
6793: case PnutsParserTreeConstants.JJTASSIGNMENTEA:
6794: method = "xor";
6795: break;
6796: case PnutsParserTreeConstants.JJTASSIGNMENTOA:
6797: method = "or";
6798: break;
6799: default:
6800: throw new RuntimeException("never happen");
6801: }
6802: cf
6803: .add(
6804: Opcode.INVOKESTATIC,
6805: "pnuts.lang.Runtime",
6806: method,
6807: "(Ljava/lang/Object;Ljava/lang/Object;Lpnuts/lang/Context;)",
6808: "Ljava/lang/Object;");
6809: }
6810:
6811: /**
6812: * Create a class loader to load compiled code.
6813: */
6814: static CodeLoader createCodeLoader(ClassLoader loader,
6815: boolean privileged) {
6816: if (hasJava2Security && privileged) {
6817: return privilegedCodeLoaderFactory.create(loader);
6818: } else {
6819: return codeLoaderFactory.create(loader);
6820: }
6821: }
6822:
6823: public static CodeLoader createCodeLoader(ClassLoader loader) {
6824: return createCodeLoader(loader, false);
6825: }
6826:
6827: static class CodeLoaderFactory {
6828: public CodeLoader create(final ClassLoader parent) {
6829: ClassLoader cl = Pnuts.class.getClassLoader();
6830: if (cl != null) {
6831: if (parent != null && cl != parent) {
6832: return new CodeLoader(new MultiClassLoader(parent,
6833: cl));
6834: } else {
6835: return new CodeLoader(cl);
6836: }
6837: } else {
6838: return new CodeLoader(parent);
6839: }
6840: }
6841: }
6842:
6843: static class PrivilegedCodeLoaderFactory extends CodeLoaderFactory {
6844: public CodeLoader create(final ClassLoader parent) {
6845: return (CodeLoader) AccessController
6846: .doPrivileged(new PrivilegedAction() {
6847: public Object run() {
6848: ClassLoader cl = Pnuts.class
6849: .getClassLoader();
6850: if (cl != null) {
6851: if (parent != null && cl != parent) {
6852: return new CodeLoader(
6853: new MultiClassLoader(
6854: parent, cl));
6855: } else {
6856: return new CodeLoader(cl);
6857: }
6858: } else {
6859: return new CodeLoader(parent);
6860: }
6861: }
6862: });
6863: }
6864: }
6865:
6866: /**
6867: * Compile a parsed expression. The resulting bytecode is handled by a
6868: * ClassFileHandler.
6869: */
6870: public Object compile(Pnuts pnuts, ClassFileHandler handler) {
6871: CompileContext cc = new CompileContext();
6872: return compile(pnuts, handler, cc);
6873: }
6874:
6875: Object compile(Pnuts pnuts, ClassFileHandler handler,
6876: CompileContext cc) {
6877: automatic = false;
6878: cc.scriptSource = pnuts.getScriptSource();
6879:
6880: pnuts.accept(this , cc);
6881: Object compileResult = handler.handle(cc.getClassFile());
6882: List classFiles = cc.getClassFiles();
6883: for (int i = 0, n = classFiles.size(); i < n; i++) {
6884: ClassFile cf = (ClassFile) classFiles.get(i);
6885: handler.handle(cf);
6886: }
6887: return compileResult;
6888: }
6889:
6890: /**
6891: * Compile a parsed expression.
6892: *
6893: * @param pnuts
6894: * a parsed expression to be compiled
6895: * @param context
6896: * a context in which the expression is compiled.
6897: * @return a Pnuts object
6898: */
6899: public Pnuts compile(Pnuts pnuts, final Context context) {
6900: Throwable caught = null;
6901: try {
6902: final CodeLoader loader = createCodeLoader(context
6903: .getClassLoader(), true);
6904: final CompileContext cc = new CompileContext(context);
6905: ClassFileHandler loadHandler = new ClassFileHandler() {
6906: public Object handle(ClassFile cf) {
6907: try {
6908: return cc.load(cf, loader);
6909: } catch (IOException e) {
6910: throw new PnutsException(e, context);
6911: }
6912: }
6913: };
6914: Class cls = (Class) compile(pnuts, loadHandler, cc);
6915: cc.resolve(loader);
6916: Runtime rt = (Runtime) cls.newInstance();
6917:
6918: return new CompiledScript(rt, pnuts);
6919: } catch (Throwable t) {
6920: caught = t;
6921: }
6922: Runtime.checkException(context, caught);
6923: throw new PnutsException(caught, context);
6924: }
6925:
6926: /**
6927: * Compile an expression.
6928: *
6929: * @param expression
6930: * an expression to be compiled.
6931: * @return a Pnuts object.
6932: */
6933: public Pnuts compile(String expression) {
6934: Context context = new Context();
6935: try {
6936: return compile(Pnuts.parse(expression), context);
6937: } catch (ParseException e) {
6938: Runtime.checkException(context, e);
6939: throw new PnutsException(e, context);
6940: }
6941: }
6942:
6943: /**
6944: * Compile an expression.
6945: *
6946: * @param expression
6947: * an expression to be compiled
6948: * @param context
6949: * a context in which the expression is compiled.
6950: * @return a Pnuts object.
6951: */
6952: public Pnuts compile(String expression, Context context) {
6953: try {
6954: return compile(Pnuts.parse(expression), context);
6955: } catch (ParseException e) {
6956: Runtime.checkException(context, e);
6957: throw new PnutsException(e, context);
6958: }
6959: }
6960:
6961: /**
6962: * Compile a function group. The resulting bytecode is handled by a
6963: * ClassFileHandler.
6964: *
6965: * @param pf
6966: * a function group.
6967: * @param handler
6968: * the resulting bytecode is handle by this object.
6969: * @return the result of handler.getResult() method.
6970: */
6971: public Object compile(PnutsFunction pf, ClassFileHandler handler) {
6972: CompileContext cc = new CompileContext();
6973: PnutsFunction ret = null;
6974: StringBuffer buf = new StringBuffer();
6975: for (Enumeration e = getFunctions(pf); e.hasMoreElements();) {
6976: Function f = (Function) e.nextElement();
6977: if (f == null) {
6978: continue;
6979: }
6980: int nargs = f.getNumberOfParameter();
6981: String im[] = f.getImportEnv();
6982: buf.append("import(null);");
6983: for (int i = 0; i < im.length; i++) {
6984: buf.append("import " + im[i] + ";");
6985: }
6986: buf.append(pf.unparse(nargs));
6987: buf.append('\n');
6988: }
6989: try {
6990: String expr = buf.toString();
6991: if (DEBUG) {
6992: System.out.println(expr);
6993: }
6994: return compile(Pnuts.parse(expr), handler, cc);
6995: } catch (ParseException pe) {
6996: throw new PnutsException(pe, cc);
6997: }
6998: }
6999:
7000: /**
7001: * Compile a function group
7002: *
7003: * @param pf
7004: * a function group to be compiled.
7005: * @return a compiled version of the function group
7006: */
7007: public PnutsFunction compile(PnutsFunction pf) {
7008: return compile(pf, new Context());
7009: }
7010:
7011: /**
7012: * Compile a function group
7013: *
7014: * @param pf
7015: * a function group to be compiled.
7016: * @param context
7017: * a context in which the function is compiled.
7018: * @return a compiled version of the function group
7019: */
7020: public PnutsFunction compile(PnutsFunction pf, Context context) {
7021: StringBuffer buf = new StringBuffer();
7022: for (Enumeration e = getFunctions(pf); e.hasMoreElements();) {
7023: Function f = (Function) e.nextElement();
7024: if (f == null) { // function written in Java
7025: continue;
7026: }
7027: int nargs = f.getNumberOfParameter();
7028: String im[] = f.getImportEnv();
7029: buf.append("import(null);");
7030: for (int i = 0; i < im.length; i++) {
7031: buf.append("import " + im[i] + ";");
7032: }
7033: buf.append(pf.unparse(nargs));
7034: buf.append('\n');
7035: }
7036: Context c = (Context) context.clone();
7037: return (PnutsFunction) compile(buf.toString(), context).run(c);
7038: }
7039:
7040: /**
7041: * Check if an object is compiled
7042: *
7043: * @param obj
7044: * an object to be checked
7045: * @return true if the object is compiled
7046: */
7047: public static boolean isCompiled(Object obj) {
7048: if (obj instanceof Compiled) {
7049: return true;
7050: }
7051: if (obj instanceof PnutsFunction) {
7052: for (Enumeration e = getFunctions((PnutsFunction) obj); e
7053: .hasMoreElements();) {
7054: Function f = (Function) e.nextElement();
7055: if (!(f instanceof Compiled)) {
7056: return false;
7057: }
7058: }
7059: return true;
7060: }
7061: return false;
7062: }
7063:
7064: static String getClassName(SimpleNode node) {
7065: int n = node.jjtGetNumChildren();
7066: if (n > 1) {
7067: StringBuffer sbuf = new StringBuffer();
7068: sbuf.append(node.jjtGetChild(0).str);
7069: for (int i = 1; i < n; i++) {
7070: sbuf.append('.');
7071: sbuf.append(node.jjtGetChild(i).str);
7072: }
7073: return sbuf.toString();
7074: } else {
7075: return node.jjtGetChild(0).str;
7076: }
7077: }
7078:
7079: void resolveClassName(SimpleNode nameNode, CompileContext cc,
7080: int ctx) {
7081: ClassFile cf = cc.cf;
7082: int n = nameNode.jjtGetNumChildren();
7083: if (n == 1) {
7084: String sym = nameNode.jjtGetChild(0).str;
7085: if (sym == INT_SYMBOL) {
7086: cf.add(Opcode.GETSTATIC, "java.lang.Integer", "TYPE",
7087: "Ljava/lang/Class;");
7088: return;
7089: } else if (sym == SHORT_SYMBOL) {
7090: cf.add(Opcode.GETSTATIC, "java.lang.Short", "TYPE",
7091: "Ljava/lang/Class;");
7092: return;
7093: } else if (sym == CHAR_SYMBOL) {
7094: cf.add(Opcode.GETSTATIC, "java.lang.Character", "TYPE",
7095: "Ljava/lang/Class;");
7096: return;
7097: } else if (sym == BYTE_SYMBOL) {
7098: cf.add(Opcode.GETSTATIC, "java.lang.Byte", "TYPE",
7099: "Ljava/lang/Class;");
7100: return;
7101: } else if (sym == LONG_SYMBOL) {
7102: cf.add(Opcode.GETSTATIC, "java.lang.Long", "TYPE",
7103: "Ljava/lang/Class;");
7104: return;
7105: } else if (sym == FLOAT_SYMBOL) {
7106: cf.add(Opcode.GETSTATIC, "java.lang.Float", "TYPE",
7107: "Ljava/lang/Class;");
7108: return;
7109: } else if (sym == DOUBLE_SYMBOL) {
7110: cf.add(Opcode.GETSTATIC, "java.lang.Double", "TYPE",
7111: "Ljava/lang/Class;");
7112: return;
7113: } else if (sym == BOOLEAN_SYMBOL) {
7114: cf.add(Opcode.GETSTATIC, "java.lang.Boolean", "TYPE",
7115: "Ljava/lang/Class;");
7116: return;
7117: } else if (sym == VOID_SYMBOL) {
7118: cf.add(Opcode.GETSTATIC, "java.lang.Void", "TYPE",
7119: "Ljava/lang/Class;");
7120: return;
7121: }
7122: }
7123:
7124: StringBuffer sbuf = new StringBuffer();
7125: sbuf.append(nameNode.jjtGetChild(0).str);
7126: for (int i = 1; i < n; i++) {
7127: sbuf.append('.');
7128: sbuf.append(nameNode.jjtGetChild(i).str);
7129: }
7130: String className = sbuf.toString();
7131: Label nonnull = cf.getLabel();
7132: int value = cf.getLocal();
7133:
7134: cf.loadLocal(ctx);
7135: int index = cf.getLocal();
7136: cf.add(Opcode.LDC, cf.addConstant(className));
7137: cf.storeLocal(index);
7138: cf.loadLocal(index);
7139: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
7140: "resolveClass", "(Ljava/lang/String;)",
7141: "Ljava/lang/Class;");
7142:
7143: cf.storeLocal(value);
7144: cf.loadLocal(value);
7145: cf.add(Opcode.IFNONNULL, nonnull);
7146: error(cf, "class.notFound", new int[] { index }, cc);
7147: nonnull.fix();
7148: cf.loadLocal(value);
7149: cf.freeLocal(value);
7150: cf.freeLocal(index);
7151: }
7152:
7153: void resolveType(SimpleNode typeNode, CompileContext cc, int ctx) {
7154: ClassFile cf = cc.cf;
7155: Class type = null;
7156: if (typeNode.id == PnutsParserTreeConstants.JJTARRAYTYPE) {
7157: SimpleNode n = typeNode;
7158: int count = 0;
7159: while (n != null
7160: && n.id == PnutsParserTreeConstants.JJTARRAYTYPE) {
7161: count++;
7162: n = n.jjtGetChild(0);
7163: }
7164: if (n != null
7165: && n.id != PnutsParserTreeConstants.JJTCLASSNAME) {
7166: throw new RuntimeException();
7167: }
7168: resolveClassName(n, cc, ctx);
7169: cf.pushInteger(count);
7170: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
7171: "arrayType", "(Ljava/lang/Class;I)",
7172: "Ljava/lang/Class;");
7173:
7174: } else if (typeNode.id == PnutsParserTreeConstants.JJTCLASSNAME) {
7175: resolveClassName(typeNode, cc, ctx);
7176: } else {
7177: error(cf, "class.expected", cc);
7178: }
7179: }
7180:
7181: static void getRef(Reference ref, CompileContext cc) {
7182: ref.get(cc.cf, cc.env.parent != null, cc.getContextIndex());
7183: }
7184:
7185: public ClassFile compileClassScript(SimpleNode classScriptNode,
7186: Object scriptSource, List helperClassFiles) {
7187: CompileContext cc = new CompileContext();
7188: cc.scriptSource = scriptSource;
7189: classScript(classScriptNode, cc);
7190: helperClassFiles.addAll(cc.getClassFiles());
7191: return cc.cf;
7192: }
7193:
7194: public Object compileClassScript(Reader reader,
7195: Object scriptSource, ClassFileHandler handler)
7196: throws ParseException, IOException {
7197: ParseEnvironment env = DefaultParseEnv
7198: .getInstance(scriptSource);
7199: SimpleNode node = new PnutsParser(reader).ClassScript(env);
7200: CompileContext cc = new CompileContext();
7201: cc.scriptSource = scriptSource;
7202: automatic = false;
7203: node.accept(this , cc);
7204: Object compileResult = handler.handle(cc.getClassFile());
7205: List classFiles = cc.getClassFiles();
7206: for (int i = 0, n = classFiles.size(); i < n; i++) {
7207: ClassFile cf = (ClassFile) classFiles.get(i);
7208: handler.handle(cf);
7209: }
7210: return compileResult;
7211: }
7212:
7213: public Object beanDef(SimpleNode node, Context context) {
7214: CompileContext cc = (CompileContext) context;
7215: ClassFile cf = cc.cf;
7216: cc.beanEnv = new BeanEnv(cc.beanEnv);
7217: int tableIndex = cf.getLocal();
7218: //cc.beanEnv.tableIndex = tableIndex;
7219: cf.add(Opcode.NEW, "java.util.HashMap");
7220: cf.add(Opcode.DUP);
7221: cf.add(Opcode.INVOKESPECIAL, "java.util.HashMap", "<init>",
7222: "()", "V");
7223: cf.storeLocal(tableIndex);
7224:
7225: int ctx = cc.getContextIndex();
7226: int conf = cf.getLocal();
7227: cf.loadLocal(ctx);
7228: cf.add(Opcode.INVOKEVIRTUAL, "pnuts.lang.Context",
7229: "getConfiguration", "()", "Lpnuts/lang/Configuration;");
7230: cf.storeLocal(conf);
7231: cf.loadLocal(conf);
7232: cf.loadLocal(ctx);
7233: SimpleNode nameNode = node.jjtGetChild(0);
7234: resolveClassName(nameNode, cc, ctx);
7235: cf.add(Opcode.GETSTATIC, className, "NO_PARAM",
7236: "[Ljava/lang/Object;");
7237: cf.add(Opcode.ACONST_NULL);
7238: cf
7239: .add(
7240: Opcode.INVOKEVIRTUAL,
7241: "pnuts.lang.Configuration",
7242: "callConstructor",
7243: "(Lpnuts/lang/Context;Ljava/lang/Class;[Ljava/lang/Object;[Ljava/lang/Class;)",
7244: "Ljava/lang/Object;");
7245: int target = cf.getLocal();
7246: cf.storeLocal(target);
7247: for (int i = 1; i < node.jjtGetNumChildren(); i++) {
7248: SimpleNode cn = node.jjtGetChild(i);
7249: String propertyName = cn.str;
7250: SimpleNode valueNode = cn.jjtGetChild(0);
7251: boolean bound = "::".equals(cn.info);
7252: if (bound) { /* experimental BIND feature */
7253: List memberNodes = new ArrayList();
7254: cn.info = memberNodes;
7255: markMemberNodeInBeanDef(cn, target, tableIndex,
7256: valueNode);
7257: }
7258: cf.loadLocal(conf);
7259: cf.loadLocal(ctx);
7260: cf.loadLocal(target);
7261: cf.add(Opcode.LDC, cf.addConstant(propertyName));
7262: valueNode.accept(this , context);
7263: cf
7264: .add(
7265: Opcode.INVOKEVIRTUAL,
7266: "pnuts.lang.Configuration",
7267: "putField",
7268: "(Lpnuts/lang/Context;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)",
7269: "V");
7270: }
7271: cf.loadLocal(tableIndex);
7272: cf.loadLocal(ctx);
7273: cf.add(Opcode.INVOKESTATIC, "pnuts.lang.Runtime",
7274: "setupPropertyChangeListeners",
7275: "(Ljava/util/Map;Lpnuts/lang/Context;)", "V");
7276:
7277: cf.loadLocal(target);
7278: cf.freeLocal(conf);
7279: cf.freeLocal(target);
7280: cc.beanEnv = cc.beanEnv.parent;
7281: return null;
7282: }
7283:
7284: static void markMemberNodeInBeanDef(SimpleNode beanPropertyDef,
7285: int targetIndex, int tableIndex, SimpleNode node) {
7286: if (node.id == PnutsParserTreeConstants.JJTMEMBERNODE) {
7287: node.info = new Object[] {
7288: new int[] { targetIndex, tableIndex },
7289: beanPropertyDef };
7290: } else if (node.id != PnutsParserTreeConstants.JJTFUNCTIONSTATEMENT) {
7291: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
7292: markMemberNodeInBeanDef(beanPropertyDef, targetIndex,
7293: tableIndex, node.jjtGetChild(i));
7294: }
7295: }
7296: }
7297:
7298: }
|