0001: /*
0002: * $Id: ClassStatement.java,v 1.20 2002/09/16 08:05:06 jkl Exp $
0003: *
0004: * Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
0005: *
0006: * Use is subject to license terms, as defined in
0007: * Anvil Sofware License, Version 1.1. See LICENSE
0008: * file, or http://njet.org/license-1.1.txt
0009: */
0010: package anvil.script.statements;
0011:
0012: import anvil.core.Any;
0013: import anvil.core.AnyClass;
0014: import anvil.core.AnyString;
0015: import anvil.core.Array;
0016: import anvil.core.Register;
0017: import anvil.core.ObjectPool;
0018: import anvil.codec.Code;
0019: import anvil.codec.ClassRoom;
0020: import anvil.codec.ConstantPool;
0021: import anvil.codec.Field;
0022: import anvil.codec.Method;
0023: import anvil.codec.Target;
0024: import anvil.codec.Source;
0025: import anvil.codec.Switch;
0026: import anvil.Location;
0027: import anvil.doc.Doc;
0028: import anvil.doc.DocParser;
0029: import anvil.parser.Tag;
0030: import anvil.ErrorListener;
0031: import anvil.script.ClassType;
0032: import anvil.script.ClassRef;
0033: import anvil.script.ClassDispatcher;
0034: import anvil.script.CompilableFunction;
0035: import anvil.script.compiler.ByteCompiler;
0036: import anvil.script.Context;
0037: import anvil.script.Grammar;
0038: import anvil.script.Type;
0039: import anvil.script.InterfaceType;
0040: import anvil.script.InterfaceRef;
0041: import anvil.script.Name;
0042: import anvil.script.ParameterListDeclaration;
0043: import anvil.script.parser.TemplateParser;
0044: import anvil.script.expression.Node;
0045: import anvil.script.expression.ConstantNode;
0046: import anvil.script.expression.ConstructorInvokeNode;
0047: import anvil.script.expression.Expression;
0048: import anvil.script.expression.AssignmentNode;
0049: import anvil.script.expression.MemberVariableNode;
0050: import anvil.script.expression.ExpressionList;
0051: import anvil.script.expression.LinkNode;
0052: import anvil.script.Scope;
0053: import anvil.script.Module;
0054: import anvil.java.util.Hashlist;
0055: import anvil.java.util.BindingEnumeration;
0056: import java.io.IOException;
0057: import java.util.Enumeration;
0058: import java.util.Iterator;
0059: import java.util.HashSet;
0060: import java.util.HashMap;
0061: import java.util.ArrayList;
0062:
0063: /**
0064: * class ClassStatement
0065: *
0066: * @author: Jani Lehtimäki
0067: */
0068: public class ClassStatement extends DefinitionStatement implements
0069: ClassType {
0070:
0071: protected ClassType[] _parents;
0072: protected String _constructor_signature = null;
0073: protected ClassRef _base;
0074: protected InterfaceRef[] _interfaces;
0075: protected ConstructorStatement _constructor;
0076: protected int _inlinecount;
0077:
0078: public ClassStatement(DefinitionStatement parent, Location location) {
0079: super (parent, location);
0080: }
0081:
0082: public void parse(TemplateParser parser, Tag tag) {
0083: super .parse(parser, tag);
0084: Location location = getLocation();
0085: boolean init = true;
0086: String s = tag.get("name");
0087: if (s == null) {
0088: parser.error(location,
0089: "Required class attribute 'name' is missing");
0090: init = false;
0091: }
0092: _name = s;
0093: _document = DocParser.parseClass(_name, parser.getDocument());
0094: s = tag.get("extends");
0095: if (s != null) {
0096: Name name = Grammar.parseDottedName(parser, location, s);
0097: if (name != null) {
0098: _base = new ClassRef(new LinkNode(this , location, name));
0099: } else {
0100: init = false;
0101: }
0102: }
0103: s = tag.get("implements");
0104: if (s != null) {
0105: Name[] names = Grammar
0106: .parseDottedNames(parser, location, s);
0107: if (names != null) {
0108: int n = names.length;
0109: _interfaces = new InterfaceRef[n];
0110: for (int i = 0; i < n; i++) {
0111: _interfaces[i] = new InterfaceRef(new LinkNode(
0112: this , location, names[i]));
0113: }
0114: } else {
0115: init = false;
0116: }
0117: }
0118: if (init) {
0119: init();
0120: }
0121: }
0122:
0123: public ClassStatement(Location location,
0124: DefinitionStatement parent, String name, String document,
0125: ClassRef base, InterfaceRef[] interfaces) {
0126: super (parent, location, name, DocParser.parseClass(name,
0127: document));
0128: _base = base;
0129: _interfaces = interfaces;
0130: init();
0131: }
0132:
0133: protected void init() {
0134: if (_base == null) {
0135: _base = new anvil.script.compiler.ResolvedClassRef(
0136: Any.__class__);
0137: }
0138:
0139: if (_interfaces == null) {
0140: _interfaces = new InterfaceRef[0];
0141: }
0142:
0143: ArrayList list = new ArrayList();
0144: Type type = _parent;
0145: while (type != null) {
0146: if (type.getType() != CLASS) {
0147: break;
0148: }
0149: list.add(0, type);
0150: type = type.getParent();
0151: }
0152: _parents = (ClassType[]) list
0153: .toArray(new ClassType[list.size()]);
0154:
0155: _descriptor = (_parent.getDescriptor() + "$z_" + _name);
0156:
0157: StringBuffer signature = new StringBuffer();
0158: signature.append('(');
0159: int n = _parents.length;
0160: for (int i = 0; i < n; i++) {
0161: signature.append('L');
0162: signature.append(_parents[i].getDescriptor());
0163: signature.append(';');
0164: }
0165: signature.append(")V");
0166: _constructor_signature = signature.toString();
0167: }
0168:
0169: public ClassType[] getEnclosingClasses() {
0170: return _parents;
0171: }
0172:
0173: public int typeOf() {
0174: return Statement.ST_CLASS;
0175: }
0176:
0177: public String name() {
0178: return "class";
0179: }
0180:
0181: public int getConstructorReference(ConstantPool pool) {
0182: return pool.addMethodRef(getTypeRef(pool), "<init>",
0183: _constructor_signature);
0184: }
0185:
0186: public int getType() {
0187: return CLASS;
0188: }
0189:
0190: public String getPathinfo() {
0191: return getModuleStatement().getPathinfo();
0192: }
0193:
0194: public boolean isInstanceOf(Type ofType) {
0195: return false;
0196: }
0197:
0198: public boolean isInnerClass() {
0199: return (_parent != null);
0200: }
0201:
0202: public ClassRef getBase() {
0203: return _base;
0204: }
0205:
0206: public ClassType getBaseClass() {
0207: return _base.getClassType();
0208: }
0209:
0210: public InterfaceRef[] getInterfaces() {
0211: return _interfaces;
0212: }
0213:
0214: public CompilableFunction getConstructor() {
0215: return _constructor;
0216: }
0217:
0218: public BindingEnumeration getMembers(AnyClass instance) {
0219: return BindingEnumeration.EMPTY;
0220: }
0221:
0222: public AnyClass newInstance() {
0223: return null;
0224: }
0225:
0226: public boolean isStaticRegion() {
0227: return false;
0228: }
0229:
0230: public int getNextInlined() {
0231: return _inlinecount++;
0232: }
0233:
0234: public void declare(Type type) {
0235: if (type.getType() == CONSTRUCTOR) {
0236: _constructor = (ConstructorStatement) type;
0237: } else {
0238: super .declare(type);
0239: }
0240: }
0241:
0242: public VariableStatement declare(Location location, String name,
0243: Expression expr, String document, boolean statik) {
0244: VariableStatement var;
0245: if (statik) {
0246: declare(var = new StaticVariableStatement(location, this ,
0247: name, expr, document));
0248: } else {
0249: declare(var = new MemberVariableStatement(location, this ,
0250: name, expr, document));
0251: }
0252: return var;
0253: }
0254:
0255: public boolean isEntityReserved(String name) {
0256: return _name.equals(name);
0257: }
0258:
0259: public Type lookupDeclaration(String name) {
0260: Type type = (Type) _types.get(name);
0261: if (type != null) {
0262: return type;
0263: }
0264: type = lookupInheritedDeclaration(name);
0265: if (type != null) {
0266: return type;
0267: }
0268: return super .lookupDeclaration(name);
0269: }
0270:
0271: public Type lookupInheritedDeclaration(String name) {
0272: Type type;
0273: if (_base != null) {
0274: ClassType classtype = _base.getClassType();
0275: if (classtype != null) {
0276: if ((type = classtype.lookupDeclaration(name)) != null) {
0277: return type;
0278: }
0279: }
0280: }
0281: if (_interfaces != null) {
0282: InterfaceRef[] bases = _interfaces;
0283: InterfaceType base;
0284: for (int i = 0; i < bases.length; i++) {
0285: if ((base = bases[i].getInterfaceType()) != null) {
0286: if ((type = base.lookupDeclaration(name)) != null) {
0287: return type;
0288: }
0289: }
0290: }
0291: }
0292: return null;
0293: }
0294:
0295: public CompilableFunction getBaseClassConstructor() {
0296: ClassRef ref = getBase();
0297: if (ref != null) {
0298: ClassType base = ref.getClassType();
0299: if (base != Any.__class__) {
0300: return base.getConstructor();
0301: }
0302: }
0303: return null;
0304: }
0305:
0306: public void onCharacters(TemplateParser parser, String cdata) {
0307: }
0308:
0309: public boolean onTag(TemplateParser parser, int type, Tag tag) {
0310: switch (type) {
0311: case ST_TAG:
0312: break;
0313:
0314: case ST_IMPORT:
0315: onImport(parser, tag);
0316: break;
0317:
0318: case ST_VAR:
0319: onVar(parser, tag);
0320: break;
0321:
0322: case ST_CONST:
0323: onConst(parser, tag);
0324: break;
0325:
0326: case ST_FUNCTION: {
0327: Location location = parser.getLocation();
0328: String name = tag.get("name");
0329: if (name == null) {
0330: parser
0331: .error(location,
0332: "Required attribute 'name' missing from function definition");
0333: } else {
0334: name = name.trim();
0335: FunctionStatement function = null;
0336: if (name.equals(_name)) {
0337: function = new ConstructorStatement(this , location);
0338: } else {
0339: if (tag.contains("static")) {
0340: function = new FunctionStatement(this , location);
0341: } else {
0342: function = new MethodStatement(this , location);
0343: }
0344: }
0345: parser.push(function);
0346: function.parse(parser, tag);
0347: if (lookupLocalDeclaration(name) == null) {
0348: declare(function);
0349: } else {
0350: parser.error(location, "Entity '" + name
0351: + "' is already declared");
0352: }
0353: }
0354: }
0355: break;
0356:
0357: case ST_ENDCLASS:
0358: parser.pop();
0359: finish();
0360: break;
0361:
0362: default:
0363: return false;
0364: }
0365:
0366: return true;
0367: }
0368:
0369: protected void addConstructorCall(ErrorListener context) {
0370: CompilableFunction ctor = getBaseClassConstructor();
0371: if (ctor != null) {
0372: if (ctor.getMinimumParameterCount() > 0) {
0373: context
0374: .error(
0375: getLocation(),
0376: "Cannot create implicit constructor call in class '"
0377: + getName()
0378: + "' since superclass '"
0379: + getBase().getReference()
0380: + "' does not have constructor with empty parameter list");
0381: } else {
0382: BlockStatement block = _constructor.getBlockStatement();
0383: block
0384: .insert(new EvalStatement(block, getLocation(),
0385: new Expression(
0386: new ConstructorInvokeNode(this ,
0387: new ExpressionList(0)),
0388: getLocation())));
0389: }
0390: }
0391: }
0392:
0393: public void finish() {
0394: if (_constructor == null) {
0395: _constructor = new ConstructorStatement(getLocation(),
0396: this , false, _name, null,
0397: new ParameterListDeclaration().open().close());
0398: }
0399: }
0400:
0401: public void check(ErrorListener context)
0402: {
0403: Grammar.checkInstanceAccess(context, getLocation(), _parent, getBaseClass());
0404:
0405: _constructor.check(context);
0406:
0407: super .check(context);
0408:
0409: BlockStatement block = _constructor.getBlockStatement();
0410: Statement stmt = block.getHead();
0411: if (stmt instanceof EvalStatement) {
0412: if (((EvalStatement)stmt).getExpression().getChild() instanceof ConstructorInvokeNode) {
0413: //skip
0414: } else {
0415: addConstructorCall(context);
0416: }
0417: } else {
0418: addConstructorCall(context);
0419: }
0420:
0421: BlockStatement init = new ImplicitBlockStatement(this , getLocation());
0422: Enumeration enum = getDeclarations();
0423: while(enum.hasMoreElements()) {
0424: Type type = (Type)enum.nextElement();
0425: if (type.getType() == Type.MEMBER_VARIABLE) {
0426: MemberVariableStatement member = (MemberVariableStatement)type;
0427: if (!member.hasConstantInitializer()) {
0428: init.add(new EvalStatement(init, _constructor.getLocation(), member.createInitializer()));
0429: }
0430: }
0431: }
0432: if (!init.isEmpty()) {
0433: ClassType base = getBaseClass();
0434: if (base != Any.__class__) {
0435: block.insert(block.getHead(), init);
0436: } else {
0437: block.insert(init);
0438: }
0439: }
0440: checkMethod(context, "copy", 0);
0441: checkMethod(context, "toBoolean", 0);
0442: checkMethod(context, "toString", 0);
0443: checkMethod(context, "sizeOf", 0);
0444: checkMethod(context, "equals", 1);
0445: checkMethod(context, "compareTo", 1);
0446: checkMethod(context, "_get", 1);
0447: checkMethod(context, "_check", 1);
0448: checkMethod(context, "_delete", 1);
0449: checkMethod(context, "_append", 1);
0450: checkMethod(context, "_set", 2);
0451: checkMethod(context, "_fetch", 1);
0452: checkMethod(context, "_defined", 1);
0453: checkMethod(context, "_dispose", 1);
0454: checkMethod(context, "_store", 2);
0455: checkMethod(context, "_enumeration", 0);
0456: checkMethod(context, "_in", 1);
0457: checkMethod(context, "_has", 1);
0458: checkMethod(context, "_invoke", 1);
0459: checkMethod(context, "_execute", 0);
0460: checkMethod(context, "_sleep", 0);
0461: checkMethod(context, "_wakeup", 0);
0462: checkMethod(context, "_getRef", 0);
0463: checkMethod(context, "_setRef", 1);
0464:
0465: checkPrefixedMethods(context, "_fetch_", 0);
0466: checkPrefixedMethods(context, "_defined_", 0);
0467: checkPrefixedMethods(context, "_dispose_", 0);
0468: checkPrefixedMethods(context, "_store_", 1);
0469: }
0470:
0471: protected MethodStatement getMethod(String name) {
0472: Type type = (Type) _types.get(name);
0473: if (type != null && type.getType() == METHOD) {
0474: return (MethodStatement) type;
0475: }
0476: return null;
0477: }
0478:
0479: protected void checkMethod(ErrorListener listener, String name,
0480: int params) {
0481: checkMethod(listener, getMethod(name), params);
0482: }
0483:
0484: protected void checkPrefixedMethods(ErrorListener listener,
0485: String prefix, int params) {
0486: MethodStatement[] methods = getMethodsStartingWith(prefix);
0487: if (methods != null) {
0488: int n = methods.length;
0489: for (int i = 0; i < n; i++) {
0490: checkMethod(listener, methods[i], params);
0491: }
0492: }
0493: }
0494:
0495: protected void checkMethod(ErrorListener listener,
0496: MethodStatement method, int params) {
0497: if (method != null) {
0498: if (method.getMinimumParameterCount() > params) {
0499: listener.error(method.getLocation(), "Special method '"
0500: + method + "' should have no more than "
0501: + params + " required parameter(s)");
0502: }
0503: }
0504: }
0505:
0506: protected MethodStatement[] getMethodsStartingWith(String prefix)
0507: {
0508: ArrayList list = null;
0509: Enumeration enum = _types.elements();
0510: while(enum.hasMoreElements()) {
0511: Type type = (Type)enum.nextElement();
0512: if (type.getType() == METHOD) {
0513: String name = type.getName();
0514: if (name.startsWith(prefix) && name.length() > prefix.length()) {
0515: if (list == null) {
0516: list = new ArrayList();
0517: }
0518: list.add(type);
0519: }
0520: }
0521: }
0522: if (list == null) {
0523: return null;
0524: } else {
0525: return (MethodStatement[])list.toArray(new MethodStatement[list.size()]);
0526: }
0527: }
0528:
0529: public void compile(ByteCompiler context) {
0530: _types.put(_constructor.getName(), _constructor);
0531:
0532: ClassRoom clazz = context.getClassRoom().createClass(
0533: _descriptor, "z_" + _name);
0534: clazz.setAccessFlags(Code.ACC_PUBLIC);
0535: ConstantPool pool = clazz.getPool();
0536: context.pushClass(clazz);
0537: Field typefield1 = clazz.createField("_class",
0538: "Lanvil/script/compiler/CompiledClassType;",
0539: Code.ACC_PUBLIC | Code.ACC_STATIC);
0540: Field typefield2 = clazz.createField("_type",
0541: "Lanvil/core/Any;", Code.ACC_PUBLIC | Code.ACC_STATIC);
0542: ClassType base = getBaseClass();
0543: if (base != Any.__class__) {
0544: clazz.setSuperClassname(base.getDescriptor());
0545: } else {
0546: clazz.setSuperClassname("anvil/core/AnyClass");
0547: }
0548: clazz.setAccessFlags(Code.ACC_SUPER | Code.ACC_PUBLIC);
0549:
0550: Field bases = clazz.createField("_bases",
0551: "[Ljava/lang/String;", Code.ACC_PUBLIC
0552: | Code.ACC_STATIC);
0553: Code code = clazz.getStatic().getCode();
0554: context.pushCode(code);
0555:
0556: code.getstatic(pool.addFieldRef(_parent.getDescriptor(),
0557: "_members", "[Ljava/lang/Object;"));
0558: code.pop();
0559:
0560: compileConstructors(context, typefield1);
0561:
0562: compileMembers(context, _types.size(), _types.elements());
0563:
0564: int n = _interfaces.length;
0565: code.iconst(n);
0566: code.anewarray("java/lang/String");
0567: for (int i = 0; i < n; i++) {
0568: InterfaceType interfacetype = _interfaces[i]
0569: .getInterfaceType();
0570: code.dup();
0571: code.iconst(i);
0572: code.astring(interfacetype.getDescriptor()
0573: .replace('/', '.'));
0574: code.aastore();
0575: }
0576: code.putstatic(bases);
0577:
0578: Enumeration e = _types.elements();
0579: while (e.hasMoreElements()) {
0580: Type type = (Type) e.nextElement();
0581: if (type.getType() == CLASS) {
0582: code.getstatic(pool.addFieldRef(type.getTypeRef(pool),
0583: "_members", "[Ljava/lang/Object;"));
0584: code.pop();
0585: }
0586: }
0587:
0588: code.vreturn();
0589:
0590: context.popCode();
0591:
0592: super .compile(context);
0593:
0594: compileMemberCallback(context);
0595:
0596: MethodStatement method = getMethod("clone");
0597: if (method != null) {
0598: compileCallback(context, method, clazz.createMethod(
0599: "clone", "()Ljava/lang/Object;", Code.ACC_PUBLIC),
0600: true, 0, EMPTY, 0, 2);
0601: } else {
0602: compileCopyMethod(context, method, false, typefield1);
0603: }
0604:
0605: method = getMethod("copy");
0606: if (method != null) {
0607: compileCallback(context, method, clazz.createMethod("copy",
0608: "()Lanvil/core/Any;", Code.ACC_PUBLIC), true, 0,
0609: EMPTY, 0, 2);
0610: } else {
0611: compileCopyMethod(context, method, true, typefield1);
0612: }
0613:
0614: method = getMethod("toBoolean");
0615: if (method != null) {
0616: compileCallback(context, method, clazz.createMethod(
0617: "toBoolean", "()Z", Code.ACC_PUBLIC), true, 0,
0618: EMPTY, pool.addMethodRef(context.TYPE_ANY,
0619: "toBoolean", "()Z"), 1);
0620: }
0621:
0622: method = getMethod("toString");
0623: if (method != null) {
0624: compileCallback(context, method, clazz
0625: .createMethod("toString", "()Ljava/lang/String;",
0626: Code.ACC_PUBLIC), true, 0, EMPTY, pool
0627: .addMethodRef(context.TYPE_ANY, "toString",
0628: "()Ljava/lang/String;"), 2);
0629: }
0630:
0631: method = getMethod("sizeOf");
0632: if (method != null) {
0633: compileCallback(
0634: context,
0635: method,
0636: clazz
0637: .createMethod("sizeOf", "()I",
0638: Code.ACC_PUBLIC),
0639: true,
0640: 0,
0641: EMPTY,
0642: pool.addMethodRef(context.TYPE_ANY, "toInt", "()I"),
0643: 1);
0644: }
0645:
0646: method = getMethod("hashCode");
0647: if (method != null) {
0648: compileCallback(context, method, clazz.createMethod(
0649: "hashCode", "()I", Code.ACC_PUBLIC), true, 0,
0650: EMPTY, pool.addMethodRef(context.TYPE_ANY, "toInt",
0651: "()I"), 1);
0652: }
0653:
0654: method = getMethod("equals");
0655: if (method != null) {
0656: compileEqualsMethod(context, method);
0657: }
0658:
0659: method = getMethod("compareTo");
0660: if (method != null) {
0661: compileCallback(context, method, clazz.createMethod(
0662: "compare", "(Lanvil/core/Any;)I", Code.ACC_PUBLIC),
0663: true, 1, CAST_P1_NODE, pool.addMethodRef(
0664: context.TYPE_ANY, "toInt", "()I"), 1);
0665: }
0666:
0667: method = getMethod("_get");
0668: if (method != null) {
0669: compileCallback(
0670: context,
0671: method,
0672: clazz
0673: .createMethod(
0674: "getReference",
0675: "(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;",
0676: Code.ACC_PUBLIC), false, 2,
0677: P2_NODE, 0, 2);
0678: }
0679:
0680: method = getMethod("_check");
0681: if (method != null) {
0682: compileCallback(
0683: context,
0684: method,
0685: clazz
0686: .createMethod(
0687: "checkReference",
0688: "(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;",
0689: Code.ACC_PUBLIC), false, 2,
0690: P2_NODE, 0, 2);
0691: }
0692:
0693: method = getMethod("_delete");
0694: if (method != null) {
0695: compileCallback(context, method, clazz.createMethod(
0696: "deleteReference",
0697: "(Lanvil/script/Context;Lanvil/core/Any;)Z",
0698: Code.ACC_PUBLIC), false, 2, P2_NODE,
0699: pool.addMethodRef(context.TYPE_ANY, "toBoolean",
0700: "()Z"), 1);
0701: }
0702:
0703: method = getMethod("_append");
0704: if (method != null) {
0705: compileCallback(
0706: context,
0707: method,
0708: clazz
0709: .createMethod(
0710: "setReference",
0711: "(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;",
0712: Code.ACC_PUBLIC), false, 2,
0713: P2_NODE, 0, 2);
0714: }
0715:
0716: method = getMethod("_set");
0717: if (method != null) {
0718: compileCallback(
0719: context,
0720: method,
0721: clazz
0722: .createMethod(
0723: "setReference",
0724: "(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
0725: Code.ACC_PUBLIC), false, 3,
0726: P_Q_NODE, 0, 2);
0727: }
0728:
0729: method = getMethod("_fetch");
0730: MethodStatement[] methods = getMethodsStartingWith("_fetch_");
0731: if (method != null || methods != null) {
0732: Method target = clazz
0733: .createMethod(
0734: "getAttribute",
0735: "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;",
0736: Code.ACC_PUBLIC);
0737: compileAttributeCallback(context, target, 7, false,
0738: methods, EMPTY, method, P_S2A_NODE, false);
0739: }
0740:
0741: method = getMethod("_defined");
0742: methods = getMethodsStartingWith("_defined_");
0743: if (method != null || methods != null) {
0744: Method target = clazz
0745: .createMethod(
0746: "checkAttribute",
0747: "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;",
0748: Code.ACC_PUBLIC);
0749: compileAttributeCallback(context, target, 9, false,
0750: methods, EMPTY, method, P_S2A_NODE, false);
0751: }
0752:
0753: method = getMethod("_dispose");
0754: methods = getMethodsStartingWith("_dispose_");
0755: if (method != null || methods != null) {
0756: Method target = clazz.createMethod("deleteAttribute",
0757: "(Lanvil/script/Context;Ljava/lang/String;)Z",
0758: Code.ACC_PUBLIC);
0759: compileAttributeCallback(context, target, 9, false,
0760: methods, EMPTY, method, P_S2A_NODE, true);
0761: }
0762:
0763: method = getMethod("_store");
0764: methods = getMethodsStartingWith("_store_");
0765: if (method != null || methods != null) {
0766: Method target = clazz
0767: .createMethod(
0768: "setAttribute",
0769: "(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;",
0770: Code.ACC_PUBLIC);
0771: compileAttributeCallback(context, target, 7, true, methods,
0772: P3_NODE, method, P_S2A_Q_NODE, false);
0773: }
0774:
0775: method = getMethod("_enumeration");
0776: if (method != null) {
0777: compileCallback(
0778: context,
0779: method,
0780: clazz.createMethod("enumeration",
0781: "()Lanvil/java/util/BindingEnumeration;",
0782: Code.ACC_PUBLIC),
0783: true,
0784: 0,
0785: EMPTY,
0786: -pool
0787: .addMethodRef(context.TYPE_COMPILED_SCRIPT,
0788: "enumerate",
0789: "(Lanvil/core/Any;)Lanvil/java/util/BindingEnumeration;"),
0790: 2);
0791: }
0792:
0793: method = getMethod("_in");
0794: if (method != null) {
0795: compileCallback(context, method,
0796: clazz.createMethod("contains",
0797: "(Lanvil/core/Any;)Z", Code.ACC_PUBLIC),
0798: true, 1, P1_NODE, pool.addMethodRef(
0799: context.TYPE_ANY, "toBoolean", "()Z"), 1);
0800: }
0801:
0802: method = getMethod("_has");
0803: if (method != null) {
0804: compileCallback(context, method, clazz.createMethod("has",
0805: "(Ljava/lang/String;)Z", Code.ACC_PUBLIC), true, 1,
0806: P1_S2A_NODE, pool.addMethodRef(context.TYPE_ANY,
0807: "toBoolean", "()Z"), 1);
0808: }
0809:
0810: method = getMethod("_invoke");
0811: if (method != null) {
0812: compileInvokeMethod(context, clazz, method);
0813: }
0814:
0815: method = getMethod("_execute");
0816: if (method != null) {
0817: compileExecuteMethod(context, clazz, method);
0818: }
0819:
0820: method = getMethod("_getRef");
0821: if (method != null) {
0822: compileCallback(context, method, clazz.createMethod(
0823: "getRef", "()Lanvil/core/Any;", Code.ACC_PUBLIC),
0824: true, 0, EMPTY, 0, 2);
0825: }
0826:
0827: method = getMethod("_setRef");
0828: if (method != null) {
0829: compileCallback(context, method, clazz.createMethod(
0830: "setRef", "(Lanvil/core/Any;)V", Code.ACC_PUBLIC),
0831: true, 1, P1_NODE, 0, 0);
0832: }
0833:
0834: compileAux(context);
0835:
0836: //compileInvoker(context);
0837:
0838: context.popClass();
0839: }
0840:
0841: protected void compileAux(ByteCompiler context) {
0842: ClassRoom clazz = context.getClassRoom();
0843: ConstantPool pool = clazz.getPool();
0844:
0845: Method method = clazz.createMethod("getAllMembers",
0846: "()Lanvil/java/util/BindingEnumeration;",
0847: Code.ACC_PUBLIC);
0848: Code code = method.getCode();
0849: int cge = pool.addClass("anvil/script/ClassGraphEnumeration");
0850: code.anew(cge);
0851: code.dup();
0852: code.getstatic(pool.addFieldRef(clazz.getIndex(), "_class",
0853: "Lanvil/script/compiler/CompiledClassType;"));
0854: code.self();
0855: code.invokespecial(pool.addMethodRef(cge, "<init>",
0856: "(Lanvil/script/ClassType;Lanvil/core/AnyClass;)V"));
0857: code.areturn();
0858:
0859: method = clazz.createMethod("classOf",
0860: "()Lanvil/script/ClassType;", Code.ACC_PUBLIC);
0861: code = method.getCode();
0862: code.getstatic(pool.addFieldRef(clazz.getIndex(), "_class",
0863: "Lanvil/script/compiler/CompiledClassType;"));
0864: code.areturn();
0865: }
0866:
0867: protected void addTypeEntry(Hashlist names, Type type) {
0868: String name = type.getName();
0869: Integer hash = new Integer(name.hashCode());
0870: Type[] types = (Type[]) names.get(hash);
0871: if (types == null) {
0872: names.put(hash, new Type[] { type });
0873: } else {
0874: int n = types.length;
0875: Type[] types2 = new Type[n + 1];
0876: System.arraycopy(types, 0, types2, 0, n);
0877: types2[n] = type;
0878: names.put(hash, types2);
0879: }
0880: }
0881:
0882: protected void compileMemberCallback(ByteCompiler context)
0883: {
0884: ClassRoom clazz = context.getClassRoom();
0885: ConstantPool pool = clazz.getPool();
0886:
0887: int sig_equals = pool.addMethodRef("java/lang/String", "equals", "(Ljava/lang/Object;)Z");
0888:
0889: int total_get = 0;
0890: int total_set = 0;
0891: Hashlist names_get = new Hashlist();
0892: Hashlist names_set = new Hashlist();
0893: BindingEnumeration enum = _types.keysAndElements();
0894: while(enum.hasMoreElements()) {
0895: Type type = (Type)enum.nextElement();
0896: switch(type.getType()) {
0897: case Type.MEMBER_VARIABLE:
0898: case Type.STATIC_VARIABLE:
0899: {
0900: total_set++;
0901: addTypeEntry(names_set, type);
0902: }
0903: // fall through
0904: case Type.METHOD:
0905: case Type.FUNCTION:
0906: case Type.CONSTANT_VARIABLE:
0907: {
0908: total_get++;
0909: addTypeEntry(names_get, type);
0910: }
0911: break;
0912: }
0913: }
0914:
0915: Method method = clazz.createMethod("getMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;", Code.ACC_PUBLIC);
0916: Code code = method.getCode();
0917: context.pushCode(code);
0918: compileMemberAccess(method, code, pool, names_get, false, total_get, sig_equals);
0919: code.self();
0920: code.aload(1);
0921: code.aload(2);
0922: code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "getMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;"));
0923: code.areturn();
0924: context.popCode();
0925:
0926: method = clazz.createMethod("checkMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;", Code.ACC_PUBLIC);
0927: code = method.getCode();
0928: context.pushCode(code);
0929: compileMemberAccess(method, code, pool, names_get, false, total_get, sig_equals);
0930: code.self();
0931: code.aload(1);
0932: code.aload(2);
0933: code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "checkMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;"));
0934: code.areturn();
0935: context.popCode();
0936:
0937: method = clazz.createMethod("setMember", "(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC);
0938: code = method.getCode();
0939: context.pushCode(code);
0940: compileMemberAccess(method, code, pool, names_set, true, total_set, sig_equals);
0941: code.self();
0942: code.aload(1);
0943: code.aload(2);
0944: code.aload(3);
0945: code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "setMember", "(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;"));
0946: code.areturn();
0947: context.popCode();
0948: }
0949:
0950: protected void compileMemberAccess(Method method, Code code, ConstantPool pool, Hashlist names, boolean assign, int total, int sig_equals)
0951: {
0952: int l_context = code.addLocal();
0953: int l_attr = code.addLocal();
0954: int l_value = 0;
0955: if (assign) {
0956: l_value = code.addLocal();
0957: }
0958: if (total <= 3) {
0959: BindingEnumeration enum = names.keysAndElements();
0960: while(enum.hasMoreElements()) {
0961: Type[] types = (Type[])enum.nextElement();
0962: for(int i=0; i<types.length; i++) {
0963: Type type = types[i];
0964: code.aload(l_attr);
0965: code.astring(type.getName());
0966: code.invokevirtual(sig_equals);
0967: Source isfalse = code.if_eq();
0968: if (assign) {
0969: compileMemberSet(code, pool, type, l_value);
0970: } else {
0971: compileMemberGet(code, pool, type);
0972: }
0973: isfalse.bind();
0974: }
0975: }
0976:
0977:
0978: } else {
0979: code.aload(l_attr);
0980: code.invokevirtual(pool.addMethodRef("java/lang/String", "hashCode", "()I"));
0981: Source notfound = code.getSource();
0982: Switch select = code.select();
0983: BindingEnumeration enum = names.keysAndElements();
0984: while(enum.hasMoreElements()) {
0985: Integer hash = (Integer)enum.nextKey();
0986: select.addCase(hash.intValue());
0987: enum.nextElement();
0988: }
0989: select.end();
0990:
0991: enum = names.keysAndElements();
0992: while(enum.hasMoreElements()) {
0993: Integer hash = (Integer)enum.nextKey();
0994: select.bindCase(hash.intValue());
0995: Type[] types = (Type[])enum.nextElement();
0996: for(int i=0; i<types.length; i++) {
0997: Type type = types[i];
0998: code.aload(l_attr);
0999: code.astring(type.getName());
1000: code.invokevirtual(sig_equals);
1001: Source isfalse = code.if_eq();
1002: if (assign) {
1003: compileMemberSet(code, pool, type, l_value);
1004: } else {
1005: compileMemberGet(code, pool, type);
1006: }
1007: isfalse.bind();
1008: }
1009: code.go_to(notfound);
1010: }
1011: select.bindDefault();
1012: notfound.bind();
1013: }
1014: }
1015:
1016: protected void compileMemberGet(Code code, ConstantPool pool,
1017: Type type) {
1018: switch (type.getType()) {
1019: case Type.MEMBER_VARIABLE: {
1020: code.self();
1021: code.getfield(type.getTypeRef(pool));
1022: code.areturn();
1023: }
1024: break;
1025:
1026: case Type.METHOD: {
1027: int sig = pool.addClass("anvil/core/runtime/AnyFunction");
1028: code.anew(sig);
1029: code.dup();
1030: code.self();
1031: code.getstatic(pool.addFieldRef(type.getParent()
1032: .getTypeRef(pool), "m_" + type.getName(),
1033: "Lanvil/script/Function;"));
1034: code.invokespecial(pool.addMethodRef(sig, "<init>",
1035: "(Lanvil/core/Any;Lanvil/script/Function;)V"));
1036: code.areturn();
1037: }
1038: break;
1039:
1040: case Type.FUNCTION: {
1041: code.getstatic(pool.addFieldRef(type.getParent()
1042: .getTypeRef(pool), "F_" + type.getName(),
1043: "Lanvil/core/Any;"));
1044: code.areturn();
1045: }
1046: break;
1047:
1048: case Type.CONSTANT_VARIABLE:
1049: case Type.STATIC_VARIABLE: {
1050: code.getstatic(type.getTypeRef(pool));
1051: code.areturn();
1052: }
1053: break;
1054: }
1055: }
1056:
1057: protected void compileMemberSet(Code code, ConstantPool pool,
1058: Type type, int l_value) {
1059: switch (type.getType()) {
1060: case Type.MEMBER_VARIABLE: {
1061: code.self();
1062: code.aload(l_value);
1063: code.dup_x1();
1064: code.putfield(type.getTypeRef(pool));
1065: code.areturn();
1066: }
1067: break;
1068:
1069: case Type.STATIC_VARIABLE: {
1070: code.aload(l_value);
1071: code.dup();
1072: code.putstatic(type.getTypeRef(pool));
1073: code.areturn();
1074: }
1075: break;
1076: }
1077: }
1078:
1079: protected void compileAttributeCallback(ByteCompiler context,
1080: Method method, int prefixLength, boolean hasValue,
1081: MethodStatement[] methods, Node[] nodes1,
1082: MethodStatement callback, Node[] nodes2,
1083: boolean castToBoolean) {
1084: ClassRoom clazz = context.getClassRoom();
1085: Code code = method.getCode();
1086: ConstantPool pool = code.getPool();
1087: int sig_equals = pool.addMethodRef("java/lang/String",
1088: "equals", "(Ljava/lang/Object;)Z");
1089: int sig_toBoolean = pool.addMethodRef("anvil/core/Any",
1090: "toBoolean", "()Z");
1091: context.pushCode(code);
1092:
1093: int l_context = code.addLocal();
1094: int l_attr = code.addLocal();
1095: int l_value = 0;
1096: if (hasValue) {
1097: l_value = code.addLocal();
1098: }
1099:
1100: if (methods != null) {
1101: int n = methods.length;
1102: if (n > 3) {
1103: code.aload(l_attr);
1104: code.invokevirtual(pool.addMethodRef(
1105: "java/lang/String", "hashCode", "()I"));
1106: Source notfound = code.getSource();
1107: Switch select = code.select();
1108: for (int i = 0; i < n; i++) {
1109: select.addCase(methods[i].getName().substring(
1110: prefixLength).hashCode());
1111: }
1112: select.end();
1113: Iterator iter = select.getCases();
1114: while (iter.hasNext()) {
1115: Switch.Case kase = (Switch.Case) iter.next();
1116: kase.bind();
1117: for (int i = 0; i < n; i++) {
1118: MethodStatement target = methods[i];
1119: String name = target.getName().substring(
1120: prefixLength);
1121: if (name.hashCode() == kase.getKey()) {
1122: code.aload(l_attr);
1123: code.astring(name);
1124: code.invokevirtual(sig_equals);
1125: Source isfalse = code.if_eq();
1126: code.self();
1127: context.compileArgumentList(target, nodes1,
1128: l_context);
1129: code.invokevirtual(target.getTypeRef(pool));
1130: if (castToBoolean) {
1131: code.invokevirtual(sig_toBoolean);
1132: code.ireturn();
1133: } else {
1134: code.areturn();
1135: }
1136: isfalse.bind();
1137: }
1138: }
1139: code.go_to(notfound);
1140: }
1141: select.bindDefault();
1142: notfound.bind();
1143:
1144: } else {
1145: for (int i = 0; i < n; i++) {
1146: MethodStatement target = methods[i];
1147: code.aload(l_attr);
1148: code.astring(target.getName().substring(
1149: prefixLength));
1150: code.invokevirtual(sig_equals);
1151: Source isfalse = code.if_eq();
1152: code.self();
1153: context.compileArgumentList(target, nodes1,
1154: l_context);
1155: code.invokevirtual(target.getTypeRef(pool));
1156: if (castToBoolean) {
1157: code.invokevirtual(sig_toBoolean);
1158: code.ireturn();
1159: } else {
1160: code.areturn();
1161: }
1162: isfalse.bind();
1163: }
1164: }
1165: }
1166:
1167: if (callback != null) {
1168: code.self();
1169: context.compileArgumentList(callback, nodes2, l_context);
1170: code.invokevirtual(callback.getTypeRef(pool));
1171: if (castToBoolean) {
1172: code.invokevirtual(sig_toBoolean);
1173: code.ireturn();
1174: } else {
1175: code.areturn();
1176: }
1177:
1178: } else {
1179: code.self();
1180: code.aload(l_context);
1181: code.aload(l_attr);
1182: if (hasValue) {
1183: code.aload(l_value);
1184: }
1185: code.invokespecial(pool.addMethodRef(clazz
1186: .getSuperClassIndex(), method.getName(), method
1187: .getDescriptor()));
1188: if (castToBoolean) {
1189: code.ireturn();
1190: } else {
1191: code.areturn();
1192: }
1193: }
1194:
1195: context.popCode();
1196: }
1197:
1198: protected void compileConstructors(ByteCompiler context, Field typefield)
1199: {
1200: ClassRoom clazz = context.getClassRoom();
1201: ConstantPool pool = clazz.getPool();
1202:
1203: ClassType[] parents = getEnclosingClasses();
1204: int n = parents.length;
1205: Field[] fields = new Field[n];
1206: for(int i=0; i<n; i++) {
1207: fields[i] = clazz.createField("this $"+i, 'L'+parents[i].getDescriptor()+';', Code.ACC_PUBLIC);
1208: }
1209: Method constructor = clazz.createMethod("<init>", _constructor_signature, Code.ACC_PUBLIC);
1210: Code code = constructor.getCode();
1211: context.pushCode(code);
1212: code.self();
1213: code.addLocals(n);
1214:
1215: ClassType[] base_parents = getBaseClass().getEnclosingClasses();
1216: int m = base_parents.length;
1217: next: for(int j=0; j<m; j++) {
1218: ClassType parent = base_parents[j];
1219: for(int i=0; i<n; i++) {
1220: if (parent == parents[i]) {
1221: code.aload(1+i);
1222: continue next;
1223: }
1224: }
1225: code.aconst_null();
1226: }
1227:
1228: ClassType baseclazz = getBaseClass();
1229: if (baseclazz != Any.__class__) {
1230: code.invokespecial(baseclazz.getConstructorReference(pool));
1231: } else {
1232: code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "<init>", "()V"));
1233: }
1234:
1235: for(int i=0; i<n; i++) {
1236: code.self();
1237: code.aload(1+i);
1238: code.putfield(fields[i]);
1239: }
1240:
1241: Enumeration enum = _types.elements();
1242: for(int i=0; enum.hasMoreElements();) {
1243: Type type = (Type)enum.nextElement();
1244: if (type.getType() == MEMBER_VARIABLE) {
1245: MemberVariableStatement member = (MemberVariableStatement)type;
1246: if (member.hasConstantInitializer()) {
1247: Expression initializer = member.createInitializer();
1248: initializer.compile(context, Expression.GET);
1249: code.pop();
1250: }
1251: }
1252: }
1253: code.vreturn();
1254: context.popCode();
1255:
1256:
1257: if (n > 0) {
1258: constructor = clazz.createMethod("<init>", "()V", Code.ACC_PUBLIC);
1259: code = constructor.getCode();
1260: code.self();
1261: code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "<init>", "()V"));
1262: code.vreturn();
1263: }
1264:
1265:
1266: Method method = clazz.createMethod("_serialize", "(Lanvil/core/Serializer;)V", Code.ACC_PUBLIC);
1267: method.addCheckedException(pool.addClass("java/io/IOException"));
1268: code = method.getCode();
1269: context.pushCode(code);
1270:
1271: int lserializer = code.addLocal();
1272: int serializerclazz = pool.addClass("anvil/core/Serializer");
1273: int unserializerclazz = pool.addClass("anvil/core/Unserializer");
1274: int writestring = pool.addMethodRef(serializerclazz, "write", "(Ljava/lang/String;)V");
1275: int writechar = pool.addMethodRef(serializerclazz, "write", "(C)V");
1276: int serializemethod = pool.addMethodRef(context.TYPE_ANY, "serialize", "(Lanvil/core/Serializer;)V");
1277:
1278: MethodStatement sleepmethod = getMethod("_sleep");
1279: int lcontext = 0;
1280: int lenum = 0;
1281: if (sleepmethod != null) {
1282: lenum = code.addLocal();
1283: lcontext = code.addLocal();
1284: code.aload(lserializer);
1285: code.invokevirtual(pool.addMethodRef(serializerclazz, "getContext", "()Lanvil/script/Context;"));
1286: code.astore(lcontext);
1287: code.self();
1288: context.compileArgumentList(sleepmethod, EMPTY, lcontext);
1289: code.invokespecial(sleepmethod.getTypeRef(pool));
1290: code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "enumeration",
1291: "()Lanvil/java/util/BindingEnumeration;"));
1292: code.astore(lenum);
1293: }
1294:
1295: if (baseclazz != Any.__class__) {
1296: code.self();
1297: code.aload(lserializer);
1298: code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "_serialize", "(Lanvil/core/Serializer;)V"));
1299: }
1300:
1301: for(int i=0; i<n; i++) {
1302: code.self();
1303: code.getfield(fields[i]);
1304: code.aload(lserializer);
1305: code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "serialize", "(Lanvil/core/Serializer;)V"));
1306: }
1307:
1308: if (sleepmethod != null) {
1309: Target loop = code.getTarget();
1310: code.aload(lenum);
1311: code.invokeinterface(pool.addInterfaceMethodRef("java/util/Enumeration",
1312: "hasMoreElements", "()Z"));
1313: Source nomoreelements = code.if_eq();
1314: int lfield = code.addLocal();
1315: code.aload(lenum);
1316: code.invokeinterface(pool.addInterfaceMethodRef("java/util/Enumeration",
1317: "nextElement", "()Ljava/lang/Object;"));
1318: code.invokevirtual(pool.addMethodRef(context.TYPE_OBJECT, "toString", "()Ljava/lang/String;"));
1319: code.astore(lfield);
1320: code.aload(lserializer);
1321: code.aload(lfield);
1322: code.invokevirtual(writestring);
1323: code.self();
1324: code.aload(lcontext);
1325: code.aload(lfield);
1326: code.invokevirtual(pool.addMethodRef("anvil/core/AnyClass", "getMember",
1327: "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;"));
1328: code.aload(lserializer);
1329: code.invokevirtual(serializemethod);
1330: code.go_to(loop);
1331: nomoreelements.bind();
1332: } else {
1333: enum = _types.elements();
1334: for(int i=0; enum.hasMoreElements();) {
1335: Type type = (Type)enum.nextElement();
1336: if (type.getType() == MEMBER_VARIABLE) {
1337: code.aload(lserializer);
1338: code.astring(type.getName());
1339: code.invokevirtual(writestring);
1340: code.self();
1341: code.getfield(type.getTypeRef(pool));
1342: code.aload(lserializer);
1343: code.invokevirtual(serializemethod);
1344: }
1345: }
1346: }
1347: code.aload(lserializer);
1348: code.iconst((int)';');
1349: code.invokevirtual(writechar);
1350: code.vreturn();
1351: context.popCode();
1352:
1353:
1354: method = clazz.createMethod("_unserialize", "(Lanvil/core/Unserializer;)V", Code.ACC_PUBLIC);
1355: method.addCheckedException(pool.addClass("anvil/core/UnserializationException"));
1356: code = method.getCode();
1357: context.pushCode(code);
1358: int unserializemethod = pool.addMethodRef(unserializerclazz, "unserialize", "()Lanvil/core/Any;");
1359: int lunserializer = code.addLocal();
1360: lcontext = code.addLocal();
1361: code.aload(lunserializer);
1362: code.invokevirtual(pool.addMethodRef(unserializerclazz, "getContext", "()Lanvil/script/Context;"));
1363: code.astore(lcontext);
1364: //if (sleepmethod != null) {
1365: int undefined = pool.addFieldRef(context.TYPE_ANY, "UNDEFINED", "Lanvil/core/Any;");
1366: enum = _types.elements();
1367: while(enum.hasMoreElements()) {
1368: Type type = (Type)enum.nextElement();
1369: if (type.getType() == MEMBER_VARIABLE) {
1370: MemberVariableStatement member = (MemberVariableStatement)type;
1371: if (member.hasConstantInitializer()) {
1372: Expression initializer = member.createInitializer();
1373: initializer.compile(context, Expression.GET);
1374: code.pop();
1375: } else {
1376: code.self();
1377: code.getstatic(undefined);
1378: code.putfield(type.getTypeRef(pool));
1379: }
1380: }
1381: }
1382: //}
1383: if (baseclazz != Any.__class__) {
1384: code.self();
1385: code.aload(lunserializer);
1386: code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "_unserialize", "(Lanvil/core/Unserializer;)V"));
1387: }
1388: for(int i=0; i<n; i++) {
1389: code.self();
1390: code.aload(lunserializer);
1391: code.invokevirtual(unserializemethod);
1392: code.checkcast(parents[i].getDescriptor());
1393: code.putfield(fields[i]);
1394: }
1395: Target loop = code.getTarget();
1396: code.aload(lunserializer);
1397: code.invokevirtual(pool.addMethodRef(unserializerclazz, "get", "()I"));
1398: code.iconst((int)';');
1399: Source endoffields = code.if_icmpeq();
1400: code.self();
1401: code.aload(lcontext);
1402: code.aload(lunserializer);
1403: code.invokevirtual(pool.addMethodRef(unserializerclazz, "getUTF16String", "()Ljava/lang/String;"));
1404: code.aload(lunserializer);
1405: code.invokevirtual(unserializemethod);
1406: code.invokevirtual(pool.addMethodRef("anvil/core/AnyClass", "setMember",
1407: "(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;"));
1408: code.pop();
1409: code.go_to(loop);
1410: endoffields.bind();
1411: MethodStatement wakeupmethod = getMethod("_wakeup");
1412: if (wakeupmethod != null) {
1413: code.self();
1414: context.compileArgumentList(wakeupmethod, EMPTY, lcontext);
1415: code.invokespecial(wakeupmethod.getTypeRef(pool));
1416: code.pop();
1417: }
1418: code.vreturn();
1419: context.popCode();
1420:
1421: }
1422:
1423: protected static final Node[] EMPTY = new Node[0];
1424: protected static final Node[] P1_NODE = new Node[] { new ParameterNode(
1425: 1) };
1426: protected static final Node[] P2_NODE = new Node[] { new ParameterNode(
1427: 2) };
1428: protected static final Node[] P3_NODE = new Node[] { new ParameterNode(
1429: 3) };
1430: protected static final Node[] P_Q_NODE = new Node[] {
1431: new ParameterNode(2), new ParameterNode(3) };
1432: protected static final Node[] CAST_P1_NODE = new Node[] { new AnyCastNode(
1433: 1) };
1434: protected static final Node[] P1_S2A_NODE = new Node[] { new StringToAnyNode(
1435: 1) };
1436: protected static final Node[] P_S2A_NODE = new Node[] { new StringToAnyNode(
1437: 2) };
1438: protected static final Node[] P_S2A_Q_NODE = new Node[] {
1439: new StringToAnyNode(2), new ParameterNode(3) };
1440:
1441: protected static class ParameterNode extends Node {
1442:
1443: private int _local;
1444:
1445: public ParameterNode(int local) {
1446: _local = local;
1447: }
1448:
1449: public boolean isConstant() {
1450: return false;
1451: }
1452:
1453: public void compile(ByteCompiler context, int operation) {
1454: context.getCode().aload(_local);
1455: }
1456:
1457: }
1458:
1459: protected static class AnyCastNode extends Node {
1460:
1461: private int _local;
1462:
1463: public AnyCastNode(int local) {
1464: _local = local;
1465: }
1466:
1467: public boolean isConstant() {
1468: return false;
1469: }
1470:
1471: public void compile(ByteCompiler context, int operation) {
1472: Code code = context.getCode();
1473: code.aload(_local);
1474: code.checkcast(context.TYPE_ANY);
1475: }
1476:
1477: }
1478:
1479: protected static class IndexToSymbol extends Node {
1480:
1481: private int _local;
1482:
1483: public IndexToSymbol(int local) {
1484: _local = local;
1485: }
1486:
1487: public boolean isConstant() {
1488: return false;
1489: }
1490:
1491: public void compile(ByteCompiler context, int operation) {
1492: Code code = context.getCode();
1493: ConstantPool pool = code.getPool();
1494: code.iload(_local);
1495: code.invokestatic(pool.addMethodRef("anvil/core/Register",
1496: "getAnyNameOf", "(I)Lanvil/core/Any;"));
1497: }
1498:
1499: }
1500:
1501: protected static class StringToAnyNode extends Node {
1502:
1503: private int _local;
1504:
1505: public StringToAnyNode(int local) {
1506: _local = local;
1507: }
1508:
1509: public boolean isConstant() {
1510: return false;
1511: }
1512:
1513: public void compile(ByteCompiler context, int operation) {
1514: Code code = context.getCode();
1515: code.aload(_local);
1516: code.invokestatic(code.getPool().addMethodRef(
1517: context.TYPE_ANY, "create",
1518: "(Ljava/lang/String;)Lanvil/core/Any;"));
1519: }
1520:
1521: }
1522:
1523: private static final String[] EXECUTE_SIGNATURES = new String[] {
1524: "(Lanvil/script/Context;)Lanvil/core/Any;",
1525: "(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;",
1526: "(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
1527: "(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
1528: "(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;", };
1529:
1530: protected void compileExecuteMethod(ByteCompiler context,
1531: ClassRoom clazz, CompilableFunction function) {
1532: /* execute(Context, Any[]) */
1533: {
1534: Method method = clazz
1535: .createMethod(
1536: "execute",
1537: "(Lanvil/script/Context;[Lanvil/core/Any;)Lanvil/core/Any;",
1538: Code.ACC_PUBLIC);
1539: Code code = method.getCode();
1540: ConstantPool pool = code.getPool();
1541: int l_context = code.addLocal();
1542: int l_parameters = code.addLocal();
1543: context.pushCode(code);
1544: code.getstatic(pool.addFieldRef(clazz.getIndex(), "m_"
1545: + function.getName(), "Lanvil/script/Function;"));
1546: code.aload(l_context);
1547: code.self();
1548: code.aload(l_parameters);
1549: code
1550: .invokeinterface(pool
1551: .addInterfaceMethodRef(
1552: "anvil/script/Function", "execute",
1553: "(Lanvil/script/Context;Lanvil/core/Any;[Lanvil/core/Any;)Lanvil/core/Any;"));
1554: code.areturn();
1555: context.popCode();
1556: }
1557:
1558: for (int i = 0; i < 5; i++) {
1559: Method method = clazz.createMethod("execute",
1560: EXECUTE_SIGNATURES[i], Code.ACC_PUBLIC);
1561: Node[] params = new Node[i];
1562: for (int j = 0; j < i; j++) {
1563: params[j] = new ParameterNode(2 + j);
1564: }
1565: compileCallback(context, function, method, false, 1 + i,
1566: params, 0, 2);
1567: }
1568: }
1569:
1570: private static final String[] INVOKE_SIGNATURES = new String[] {
1571: "(Lanvil/script/Context;I)Lanvil/core/Any;",
1572: "(Lanvil/script/Context;ILanvil/core/Any;)Lanvil/core/Any;",
1573: "(Lanvil/script/Context;ILanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
1574: "(Lanvil/script/Context;ILanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
1575: "(Lanvil/script/Context;ILanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;", };
1576:
1577: private static final Node P2_TO_SYMBOL = new IndexToSymbol(2);
1578:
1579: protected void compileInvokeMethod(ByteCompiler context,
1580: ClassRoom clazz, CompilableFunction function) {
1581: /* invoke(Context, int, Any[]) */
1582: {
1583: Method method = clazz
1584: .createMethod(
1585: "invoke",
1586: "(Lanvil/script/Context;I[Lanvil/core/Any;)Lanvil/core/Any;",
1587: Code.ACC_PUBLIC);
1588: Code code = method.getCode();
1589: ConstantPool pool = code.getPool();
1590: context.pushCode(code);
1591: int l_context = code.addLocal();
1592: int l_index = code.addLocal();
1593: int l_parameters = code.addLocal();
1594: int l_length = code.addLocal();
1595: int l_newparameters = code.addLocal();
1596: code.aload(l_parameters);
1597: code.arraylength();
1598: code.istore(l_length);
1599: code.iload(l_length);
1600: code.iconst(1);
1601: code.iadd();
1602: code.anewarray(context.TYPE_ANY);
1603: code.astore(l_newparameters);
1604: code.aload(l_parameters);
1605: code.iconst(0);
1606: code.aload(l_newparameters);
1607: code.iconst(1);
1608: code.iload(l_length);
1609: code.invokestatic(pool.addMethodRef("java/lang/System",
1610: "arraycopy",
1611: "(Ljava/lang/Object;ILjava/lang/Object;II)V"));
1612: code.aload(l_newparameters);
1613: code.iconst(0);
1614: code.iload(l_index);
1615: code.invokestatic(pool.addMethodRef("anvil/core/Register",
1616: "getAnyNameOf", "(I)Lanvil/core/Any;"));
1617: code.aastore();
1618: code.getstatic(pool.addFieldRef(clazz.getIndex(), "m_"
1619: + function.getName(), "Lanvil/script/Function;"));
1620: code.aload(l_context);
1621: code.self();
1622: code.aload(l_newparameters);
1623: code
1624: .invokeinterface(pool
1625: .addInterfaceMethodRef(
1626: "anvil/script/Function", "execute",
1627: "(Lanvil/script/Context;Lanvil/core/Any;[Lanvil/core/Any;)Lanvil/core/Any;"));
1628: code.areturn();
1629: context.popCode();
1630: }
1631:
1632: for (int i = 0; i < 4; i++) {
1633: Method method = clazz.createMethod("invoke",
1634: INVOKE_SIGNATURES[i], Code.ACC_PUBLIC);
1635: Node[] params = new Node[1 + i];
1636: params[0] = P2_TO_SYMBOL;
1637: for (int j = 0; j < i; j++) {
1638: params[j + 1] = new ParameterNode(3 + j);
1639: }
1640: compileCallback(context, function, method, false, 3 + i,
1641: params, 0, 2);
1642: }
1643:
1644: /* invoke(Context, int, Any, Any, Any, Any) */
1645: {
1646: Method method = clazz.createMethod("invoke",
1647: INVOKE_SIGNATURES[4], Code.ACC_PUBLIC);
1648: Code code = method.getCode();
1649: ConstantPool pool = code.getPool();
1650: context.pushCode(code);
1651: int l_context = code.addLocal();
1652: int l_index = code.addLocal();
1653: int l_base = code.addLocal();
1654: code.addLocals(3);
1655:
1656: code.getstatic(pool.addFieldRef(clazz.getIndex(), "m_"
1657: + function.getName(), "Lanvil/script/Function;"));
1658:
1659: code.aload(l_context);
1660:
1661: code.self();
1662:
1663: code.iconst(5);
1664: code.anewarray(context.TYPE_ANY);
1665:
1666: code.dup();
1667: code.iconst(0);
1668: code.iload(l_index);
1669: code.invokestatic(pool.addMethodRef("anvil/core/Register",
1670: "getNameOf", "(I)Ljava/lang/String;"));
1671: code.invokestatic(pool.addMethodRef(context.TYPE_ANY,
1672: "create", "(Ljava/lang/String;)Lanvil/core/Any;"));
1673: code.aastore();
1674:
1675: for (int i = 0; i < 4; i++) {
1676: code.dup();
1677: code.iconst(i + 1);
1678: code.aload(l_base + i);
1679: code.aastore();
1680: }
1681:
1682: code
1683: .invokeinterface(pool
1684: .addInterfaceMethodRef(
1685: "anvil/script/Function", "execute",
1686: "(Lanvil/script/Context;Lanvil/core/Any;[Lanvil/core/Any;)Lanvil/core/Any;"));
1687: code.areturn();
1688:
1689: context.popCode();
1690: }
1691: }
1692:
1693: protected void compileCallback(ByteCompiler context,
1694: CompilableFunction function, Method method,
1695: boolean getContext, int parameters, Node[] nodes,
1696: int toType, int treturn) {
1697: Code code = method.getCode();
1698: ConstantPool pool = code.getPool();
1699: context.pushCode(code);
1700: int contextindex = 1;
1701: if (parameters > 0) {
1702: code.addLocals(parameters);
1703: }
1704: if (getContext) {
1705: contextindex = code.addLocal();
1706: code.invokestatic(pool.addMethodRef(context.TYPE_CONTEXT,
1707: "getInstance", "()Lanvil/script/Context;"));
1708: code.astore(contextindex);
1709: }
1710: code.self();
1711: context.compileArgumentList(function, nodes, contextindex);
1712: code.invokevirtual(function.getTypeRef(pool));
1713: if (toType > 0) {
1714: code.invokevirtual(toType);
1715: } else if (toType < 0) {
1716: code.invokestatic(-toType);
1717: }
1718: switch (treturn) {
1719: case 0:
1720: code.pop();
1721: code.vreturn();
1722: break;
1723: case 1:
1724: code.ireturn();
1725: break;
1726: case 2:
1727: code.areturn();
1728: break;
1729: }
1730: context.popCode();
1731: }
1732:
1733: protected void compileEqualsMethod(ByteCompiler context,
1734: CompilableFunction function) {
1735: ClassRoom clazz = context.getClassRoom();
1736: Method method = clazz.createMethod("equals",
1737: "(Ljava/lang/Object;)Z", Code.ACC_PUBLIC);
1738: Code code = method.getCode();
1739: ConstantPool pool = code.getPool();
1740: context.pushCode(code);
1741: code.addLocal();
1742: code.aload(1);
1743: code.instance_of(context.TYPE_ANY);
1744: Source isfalse = code.if_eq();
1745: code.invokestatic(pool.addMethodRef(context.TYPE_CONTEXT,
1746: "getInstance", "()Lanvil/script/Context;"));
1747: code.astore(code.addLocal());
1748: code.self();
1749: context.compileArgumentList(function, CAST_P1_NODE, 2);
1750: code.invokevirtual(function.getTypeRef(pool));
1751: code.invokevirtual(pool.addMethodRef(context.TYPE_ANY,
1752: "toBoolean", "()Z"));
1753: code.ireturn();
1754: isfalse.bind();
1755: code.iconst(false);
1756: code.ireturn();
1757: context.popCode();
1758: }
1759:
1760: protected void compileCopyMethod(ByteCompiler context, MethodStatement callback, boolean iscopy, Field typefield)
1761: {
1762: ClassRoom clazz = context.getClassRoom();
1763: ConstantPool pool = clazz.getPool();
1764: Method method;
1765: if (iscopy) {
1766: method = clazz.createMethod("copy", "()Lanvil/core/Any;", Code.ACC_PUBLIC);
1767: } else {
1768: method = clazz.createMethod("clone", "()Ljava/lang/Object;", Code.ACC_PUBLIC);
1769: }
1770: Code code = method.getCode();
1771: context.pushCode(code);
1772: int copymethod;
1773: if (iscopy) {
1774: copymethod = pool.addMethodRef(context.TYPE_ANY, "copy", "()Lanvil/core/Any;");
1775: } else {
1776: copymethod = pool.addMethodRef(context.TYPE_ANY, "clone", "()Ljava/lang/Object;");
1777: }
1778: int classindex = clazz.getIndex();
1779: int l_self = code.addLocal();
1780: code.anew(classindex);
1781: code.dup();
1782: ClassType[] parents = _parents;
1783: int n = parents.length;
1784: for(int i=0; i<n; i++) {
1785: code.self();
1786: code.getfield(pool.addFieldRef(clazz.getIndex(), "this $"+i, 'L'+parents[i].getDescriptor()+';'));
1787: }
1788: code.invokespecial(pool.addMethodRef(classindex, "<init>", _constructor_signature));
1789: code.astore(l_self);
1790: ClassType classtype = this ;
1791: while(classtype != null) {
1792: classindex = classtype.getTypeRef(pool);
1793: Enumeration enum = classtype.getDeclarations();
1794: while (enum.hasMoreElements()) {
1795: Type type = (Type)enum.nextElement();
1796: if (type.getType() == Type.MEMBER_VARIABLE) {
1797: int fieldref = pool.addFieldRef(classindex, "f_"+type.getName(), "Lanvil/core/Any;");
1798: code.aload(l_self);
1799: code.self();
1800: code.getfield(fieldref);
1801: code.invokevirtual(copymethod);
1802: if (!iscopy) {
1803: code.checkcast(context.TYPE_ANY);
1804: }
1805: code.putfield(fieldref);
1806: }
1807: }
1808: classtype = classtype.getBaseClass();
1809: }
1810: code.aload(l_self);
1811: code.areturn();
1812: context.popCode();
1813: }
1814:
1815: public ClassDispatcher getDispatcher(Context context) {
1816: return null;
1817: }
1818:
1819: }
|