/*
* $Id: ClassStatement.java,v 1.20 2002/09/16 08:05:06 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.script.statements;
import anvil.core.Any;
import anvil.core.AnyClass;
import anvil.core.AnyString;
import anvil.core.Array;
import anvil.core.Register;
import anvil.core.ObjectPool;
import anvil.codec.Code;
import anvil.codec.ClassRoom;
import anvil.codec.ConstantPool;
import anvil.codec.Field;
import anvil.codec.Method;
import anvil.codec.Target;
import anvil.codec.Source;
import anvil.codec.Switch;
import anvil.Location;
import anvil.doc.Doc;
import anvil.doc.DocParser;
import anvil.parser.Tag;
import anvil.ErrorListener;
import anvil.script.ClassType;
import anvil.script.ClassRef;
import anvil.script.ClassDispatcher;
import anvil.script.CompilableFunction;
import anvil.script.compiler.ByteCompiler;
import anvil.script.Context;
import anvil.script.Grammar;
import anvil.script.Type;
import anvil.script.InterfaceType;
import anvil.script.InterfaceRef;
import anvil.script.Name;
import anvil.script.ParameterListDeclaration;
import anvil.script.parser.TemplateParser;
import anvil.script.expression.Node;
import anvil.script.expression.ConstantNode;
import anvil.script.expression.ConstructorInvokeNode;
import anvil.script.expression.Expression;
import anvil.script.expression.AssignmentNode;
import anvil.script.expression.MemberVariableNode;
import anvil.script.expression.ExpressionList;
import anvil.script.expression.LinkNode;
import anvil.script.Scope;
import anvil.script.Module;
import anvil.java.util.Hashlist;
import anvil.java.util.BindingEnumeration;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.HashSet;
import java.util.HashMap;
import java.util.ArrayList;
/**
* class ClassStatement
*
* @author: Jani Lehtim�ki
*/
public class ClassStatement extends DefinitionStatement implements ClassType
{
protected ClassType[] _parents;
protected String _constructor_signature = null;
protected ClassRef _base;
protected InterfaceRef[] _interfaces;
protected ConstructorStatement _constructor;
protected int _inlinecount;
public ClassStatement(DefinitionStatement parent, Location location)
{
super(parent, location);
}
public void parse(TemplateParser parser, Tag tag)
{
super.parse(parser, tag);
Location location = getLocation();
boolean init = true;
String s = tag.get("name");
if (s == null) {
parser.error(location, "Required class attribute 'name' is missing");
init = false;
}
_name = s;
_document = DocParser.parseClass(_name, parser.getDocument());
s = tag.get("extends");
if (s != null) {
Name name = Grammar.parseDottedName(parser, location, s);
if (name != null) {
_base = new ClassRef(new LinkNode(this, location, name));
} else {
init = false;
}
}
s = tag.get("implements");
if (s != null) {
Name[] names = Grammar.parseDottedNames(parser, location, s);
if (names != null) {
int n = names.length;
_interfaces = new InterfaceRef[n];
for(int i=0; i<n; i++) {
_interfaces[i] = new InterfaceRef(new LinkNode(this, location, names[i]));
}
} else {
init = false;
}
}
if (init) {
init();
}
}
public ClassStatement(
Location location,
DefinitionStatement parent,
String name,
String document,
ClassRef base,
InterfaceRef[] interfaces)
{
super(parent, location, name, DocParser.parseClass(name, document));
_base = base;
_interfaces = interfaces;
init();
}
protected void init()
{
if (_base == null) {
_base = new anvil.script.compiler.ResolvedClassRef(Any.__class__);
}
if (_interfaces == null) {
_interfaces = new InterfaceRef[0];
}
ArrayList list = new ArrayList();
Type type = _parent;
while(type != null) {
if (type.getType() != CLASS) {
break;
}
list.add(0, type);
type = type.getParent();
}
_parents = (ClassType[])list.toArray(new ClassType[list.size()]);
_descriptor = (_parent.getDescriptor() + "$z_" + _name);
StringBuffer signature = new StringBuffer();
signature.append('(');
int n = _parents.length;
for(int i=0; i<n; i++) {
signature.append('L');
signature.append(_parents[i].getDescriptor());
signature.append(';');
}
signature.append(")V");
_constructor_signature = signature.toString();
}
public ClassType[] getEnclosingClasses()
{
return _parents;
}
public int typeOf()
{
return Statement.ST_CLASS;
}
public String name()
{
return "class";
}
public int getConstructorReference(ConstantPool pool)
{
return pool.addMethodRef(getTypeRef(pool), "<init>", _constructor_signature);
}
public int getType()
{
return CLASS;
}
public String getPathinfo()
{
return getModuleStatement().getPathinfo();
}
public boolean isInstanceOf(Type ofType)
{
return false;
}
public boolean isInnerClass()
{
return (_parent != null);
}
public ClassRef getBase()
{
return _base;
}
public ClassType getBaseClass()
{
return _base.getClassType();
}
public InterfaceRef[] getInterfaces()
{
return _interfaces;
}
public CompilableFunction getConstructor()
{
return _constructor;
}
public BindingEnumeration getMembers(AnyClass instance)
{
return BindingEnumeration.EMPTY;
}
public AnyClass newInstance()
{
return null;
}
public boolean isStaticRegion()
{
return false;
}
public int getNextInlined()
{
return _inlinecount++;
}
public void declare(Type type)
{
if (type.getType() == CONSTRUCTOR) {
_constructor = (ConstructorStatement)type;
} else {
super.declare(type);
}
}
public VariableStatement declare(Location location, String name, Expression expr, String document, boolean statik)
{
VariableStatement var;
if (statik) {
declare(var = new StaticVariableStatement(location, this, name, expr, document));
} else {
declare(var = new MemberVariableStatement(location, this, name, expr, document));
}
return var;
}
public boolean isEntityReserved(String name)
{
return _name.equals(name);
}
public Type lookupDeclaration(String name)
{
Type type = (Type)_types.get(name);
if (type != null) {
return type;
}
type = lookupInheritedDeclaration(name);
if (type != null) {
return type;
}
return super.lookupDeclaration(name);
}
public Type lookupInheritedDeclaration(String name)
{
Type type;
if (_base != null) {
ClassType classtype = _base.getClassType();
if (classtype != null) {
if ((type = classtype.lookupDeclaration(name)) != null) {
return type;
}
}
}
if (_interfaces != null) {
InterfaceRef[] bases = _interfaces;
InterfaceType base;
for(int i=0; i<bases.length; i++) {
if ((base = bases[i].getInterfaceType()) != null) {
if ((type = base.lookupDeclaration(name)) != null) {
return type;
}
}
}
}
return null;
}
public CompilableFunction getBaseClassConstructor()
{
ClassRef ref = getBase();
if (ref != null) {
ClassType base = ref.getClassType();
if (base != Any.__class__) {
return base.getConstructor();
}
}
return null;
}
public void onCharacters(TemplateParser parser, String cdata)
{
}
public boolean onTag(TemplateParser parser, int type, Tag tag)
{
switch(type) {
case ST_TAG:
break;
case ST_IMPORT:
onImport(parser, tag);
break;
case ST_VAR:
onVar(parser, tag);
break;
case ST_CONST:
onConst(parser, tag);
break;
case ST_FUNCTION:
{
Location location = parser.getLocation();
String name = tag.get("name");
if (name == null) {
parser.error(location, "Required attribute 'name' missing from function definition");
} else {
name = name.trim();
FunctionStatement function = null;
if (name.equals(_name)) {
function = new ConstructorStatement(this, location);
} else {
if (tag.contains("static")) {
function = new FunctionStatement(this, location);
} else {
function = new MethodStatement(this, location);
}
}
parser.push(function);
function.parse(parser, tag);
if (lookupLocalDeclaration(name) == null) {
declare(function);
} else {
parser.error(location, "Entity '" + name + "' is already declared");
}
}
}
break;
case ST_ENDCLASS:
parser.pop();
finish();
break;
default:
return false;
}
return true;
}
protected void addConstructorCall(ErrorListener context)
{
CompilableFunction ctor = getBaseClassConstructor();
if (ctor != null) {
if (ctor.getMinimumParameterCount() > 0) {
context.error(getLocation(), "Cannot create implicit constructor call in class '" + getName() +
"' since superclass '" + getBase().getReference() + "' does not have constructor with empty parameter list");
} else {
BlockStatement block = _constructor.getBlockStatement();
block.insert(new EvalStatement(block, getLocation(),
new Expression(new ConstructorInvokeNode(this,
new ExpressionList(0)), getLocation())));
}
}
}
public void finish()
{
if (_constructor == null) {
_constructor = new ConstructorStatement(getLocation(), this, false, _name, null,
new ParameterListDeclaration().open().close());
}
}
public void check(ErrorListener context)
{
Grammar.checkInstanceAccess(context, getLocation(), _parent, getBaseClass());
_constructor.check(context);
super.check(context);
BlockStatement block = _constructor.getBlockStatement();
Statement stmt = block.getHead();
if (stmt instanceof EvalStatement) {
if (((EvalStatement)stmt).getExpression().getChild() instanceof ConstructorInvokeNode) {
//skip
} else {
addConstructorCall(context);
}
} else {
addConstructorCall(context);
}
BlockStatement init = new ImplicitBlockStatement(this, getLocation());
Enumeration enum = getDeclarations();
while(enum.hasMoreElements()) {
Type type = (Type)enum.nextElement();
if (type.getType() == Type.MEMBER_VARIABLE) {
MemberVariableStatement member = (MemberVariableStatement)type;
if (!member.hasConstantInitializer()) {
init.add(new EvalStatement(init, _constructor.getLocation(), member.createInitializer()));
}
}
}
if (!init.isEmpty()) {
ClassType base = getBaseClass();
if (base != Any.__class__) {
block.insert(block.getHead(), init);
} else {
block.insert(init);
}
}
checkMethod(context, "copy", 0);
checkMethod(context, "toBoolean", 0);
checkMethod(context, "toString", 0);
checkMethod(context, "sizeOf", 0);
checkMethod(context, "equals", 1);
checkMethod(context, "compareTo", 1);
checkMethod(context, "_get", 1);
checkMethod(context, "_check", 1);
checkMethod(context, "_delete", 1);
checkMethod(context, "_append", 1);
checkMethod(context, "_set", 2);
checkMethod(context, "_fetch", 1);
checkMethod(context, "_defined", 1);
checkMethod(context, "_dispose", 1);
checkMethod(context, "_store", 2);
checkMethod(context, "_enumeration", 0);
checkMethod(context, "_in", 1);
checkMethod(context, "_has", 1);
checkMethod(context, "_invoke", 1);
checkMethod(context, "_execute", 0);
checkMethod(context, "_sleep", 0);
checkMethod(context, "_wakeup", 0);
checkMethod(context, "_getRef", 0);
checkMethod(context, "_setRef", 1);
checkPrefixedMethods(context, "_fetch_", 0);
checkPrefixedMethods(context, "_defined_", 0);
checkPrefixedMethods(context, "_dispose_", 0);
checkPrefixedMethods(context, "_store_", 1);
}
protected MethodStatement getMethod(String name)
{
Type type = (Type)_types.get(name);
if (type != null && type.getType() == METHOD) {
return (MethodStatement)type;
}
return null;
}
protected void checkMethod(ErrorListener listener, String name, int params)
{
checkMethod(listener, getMethod(name), params);
}
protected void checkPrefixedMethods(ErrorListener listener, String prefix, int params)
{
MethodStatement[] methods = getMethodsStartingWith(prefix);
if (methods != null) {
int n = methods.length;
for(int i=0; i<n; i++) {
checkMethod(listener, methods[i], params);
}
}
}
protected void checkMethod(ErrorListener listener, MethodStatement method, int params)
{
if (method != null) {
if (method.getMinimumParameterCount() > params) {
listener.error(method.getLocation(), "Special method '"+method+"' should have no more than "+params+" required parameter(s)");
}
}
}
protected MethodStatement[] getMethodsStartingWith(String prefix)
{
ArrayList list = null;
Enumeration enum = _types.elements();
while(enum.hasMoreElements()) {
Type type = (Type)enum.nextElement();
if (type.getType() == METHOD) {
String name = type.getName();
if (name.startsWith(prefix) && name.length() > prefix.length()) {
if (list == null) {
list = new ArrayList();
}
list.add(type);
}
}
}
if (list == null) {
return null;
} else {
return (MethodStatement[])list.toArray(new MethodStatement[list.size()]);
}
}
public void compile(ByteCompiler context)
{
_types.put(_constructor.getName(), _constructor);
ClassRoom clazz = context.getClassRoom().createClass(_descriptor, "z_"+_name);
clazz.setAccessFlags(Code.ACC_PUBLIC);
ConstantPool pool = clazz.getPool();
context.pushClass(clazz);
Field typefield1 = clazz.createField("_class", "Lanvil/script/compiler/CompiledClassType;", Code.ACC_PUBLIC|Code.ACC_STATIC);
Field typefield2 = clazz.createField("_type", "Lanvil/core/Any;", Code.ACC_PUBLIC|Code.ACC_STATIC);
ClassType base = getBaseClass();
if (base != Any.__class__) {
clazz.setSuperClassname(base.getDescriptor());
} else {
clazz.setSuperClassname("anvil/core/AnyClass");
}
clazz.setAccessFlags(Code.ACC_SUPER|Code.ACC_PUBLIC);
Field bases = clazz.createField("_bases", "[Ljava/lang/String;", Code.ACC_PUBLIC|Code.ACC_STATIC);
Code code = clazz.getStatic().getCode();
context.pushCode(code);
code.getstatic(pool.addFieldRef(_parent.getDescriptor(), "_members", "[Ljava/lang/Object;"));
code.pop();
compileConstructors(context, typefield1);
compileMembers(context, _types.size(), _types.elements());
int n = _interfaces.length;
code.iconst(n);
code.anewarray("java/lang/String");
for(int i=0; i<n; i++) {
InterfaceType interfacetype = _interfaces[i].getInterfaceType();
code.dup();
code.iconst(i);
code.astring(interfacetype.getDescriptor().replace('/', '.'));
code.aastore();
}
code.putstatic(bases);
Enumeration e = _types.elements();
while(e.hasMoreElements()) {
Type type = (Type)e.nextElement();
if (type.getType() == CLASS) {
code.getstatic(pool.addFieldRef(type.getTypeRef(pool),
"_members", "[Ljava/lang/Object;"));
code.pop();
}
}
code.vreturn();
context.popCode();
super.compile(context);
compileMemberCallback(context);
MethodStatement method = getMethod("clone");
if (method != null) {
compileCallback(context, method, clazz.createMethod(
"clone", "()Ljava/lang/Object;", Code.ACC_PUBLIC), true, 0, EMPTY, 0, 2);
} else {
compileCopyMethod(context, method, false, typefield1);
}
method = getMethod("copy");
if (method != null) {
compileCallback(context, method, clazz.createMethod(
"copy", "()Lanvil/core/Any;", Code.ACC_PUBLIC), true, 0, EMPTY, 0, 2);
} else {
compileCopyMethod(context, method, true, typefield1);
}
method = getMethod("toBoolean");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("toBoolean", "()Z", Code.ACC_PUBLIC), true, 0, EMPTY,
pool.addMethodRef(context.TYPE_ANY, "toBoolean", "()Z"), 1);
}
method = getMethod("toString");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("toString", "()Ljava/lang/String;", Code.ACC_PUBLIC), true, 0, EMPTY,
pool.addMethodRef(context.TYPE_ANY, "toString", "()Ljava/lang/String;"), 2);
}
method = getMethod("sizeOf");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("sizeOf", "()I", Code.ACC_PUBLIC), true, 0, EMPTY,
pool.addMethodRef(context.TYPE_ANY, "toInt", "()I"), 1);
}
method = getMethod("hashCode");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("hashCode", "()I", Code.ACC_PUBLIC), true, 0, EMPTY,
pool.addMethodRef(context.TYPE_ANY, "toInt", "()I"), 1);
}
method = getMethod("equals");
if (method != null) {
compileEqualsMethod(context, method);
}
method = getMethod("compareTo");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("compare", "(Lanvil/core/Any;)I", Code.ACC_PUBLIC), true, 1, CAST_P1_NODE,
pool.addMethodRef(context.TYPE_ANY, "toInt", "()I"), 1);
}
method = getMethod("_get");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("getReference", "(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC),
false, 2, P2_NODE, 0, 2);
}
method = getMethod("_check");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("checkReference", "(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC),
false, 2, P2_NODE, 0, 2);
}
method = getMethod("_delete");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("deleteReference", "(Lanvil/script/Context;Lanvil/core/Any;)Z", Code.ACC_PUBLIC),
false, 2, P2_NODE, pool.addMethodRef(context.TYPE_ANY, "toBoolean", "()Z"), 1);
}
method = getMethod("_append");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("setReference", "(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC),
false, 2, P2_NODE, 0, 2);
}
method = getMethod("_set");
if (method != null) {
compileCallback(context, method, clazz.createMethod("setReference",
"(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC),
false, 3, P_Q_NODE, 0, 2);
}
method = getMethod("_fetch");
MethodStatement[] methods = getMethodsStartingWith("_fetch_");
if (method != null || methods != null) {
Method target = clazz.createMethod("getAttribute", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;", Code.ACC_PUBLIC);
compileAttributeCallback(context, target, 7, false, methods, EMPTY, method, P_S2A_NODE, false);
}
method = getMethod("_defined");
methods = getMethodsStartingWith("_defined_");
if (method != null || methods != null) {
Method target = clazz.createMethod("checkAttribute", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;", Code.ACC_PUBLIC);
compileAttributeCallback(context, target, 9, false, methods, EMPTY, method, P_S2A_NODE, false);
}
method = getMethod("_dispose");
methods = getMethodsStartingWith("_dispose_");
if (method != null || methods != null) {
Method target = clazz.createMethod("deleteAttribute", "(Lanvil/script/Context;Ljava/lang/String;)Z", Code.ACC_PUBLIC);
compileAttributeCallback(context, target, 9, false, methods, EMPTY, method, P_S2A_NODE, true);
}
method = getMethod("_store");
methods = getMethodsStartingWith("_store_");
if (method != null || methods != null) {
Method target = clazz.createMethod("setAttribute", "(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC);
compileAttributeCallback(context, target, 7, true, methods, P3_NODE, method, P_S2A_Q_NODE, false);
}
method = getMethod("_enumeration");
if (method != null) {
compileCallback(context, method, clazz.createMethod("enumeration",
"()Lanvil/java/util/BindingEnumeration;", Code.ACC_PUBLIC),
true, 0, EMPTY, -pool.addMethodRef(context.TYPE_COMPILED_SCRIPT,
"enumerate", "(Lanvil/core/Any;)Lanvil/java/util/BindingEnumeration;"), 2);
}
method = getMethod("_in");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("contains", "(Lanvil/core/Any;)Z", Code.ACC_PUBLIC),
true, 1, P1_NODE, pool.addMethodRef(context.TYPE_ANY, "toBoolean", "()Z"), 1);
}
method = getMethod("_has");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("has", "(Ljava/lang/String;)Z", Code.ACC_PUBLIC),
true, 1, P1_S2A_NODE, pool.addMethodRef(context.TYPE_ANY, "toBoolean", "()Z"), 1);
}
method = getMethod("_invoke");
if (method != null) {
compileInvokeMethod(context, clazz, method);
}
method = getMethod("_execute");
if (method != null) {
compileExecuteMethod(context, clazz, method);
}
method = getMethod("_getRef");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("getRef", "()Lanvil/core/Any;", Code.ACC_PUBLIC), true, 0, EMPTY, 0, 2);
}
method = getMethod("_setRef");
if (method != null) {
compileCallback(context, method,
clazz.createMethod("setRef", "(Lanvil/core/Any;)V", Code.ACC_PUBLIC), true, 1, P1_NODE, 0, 0);
}
compileAux(context);
//compileInvoker(context);
context.popClass();
}
protected void compileAux(ByteCompiler context)
{
ClassRoom clazz = context.getClassRoom();
ConstantPool pool = clazz.getPool();
Method method = clazz.createMethod("getAllMembers", "()Lanvil/java/util/BindingEnumeration;", Code.ACC_PUBLIC);
Code code = method.getCode();
int cge = pool.addClass("anvil/script/ClassGraphEnumeration");
code.anew(cge);
code.dup();
code.getstatic(pool.addFieldRef(clazz.getIndex(), "_class", "Lanvil/script/compiler/CompiledClassType;"));
code.self();
code.invokespecial(pool.addMethodRef(cge, "<init>", "(Lanvil/script/ClassType;Lanvil/core/AnyClass;)V"));
code.areturn();
method = clazz.createMethod("classOf", "()Lanvil/script/ClassType;", Code.ACC_PUBLIC);
code = method.getCode();
code.getstatic(pool.addFieldRef(clazz.getIndex(), "_class", "Lanvil/script/compiler/CompiledClassType;"));
code.areturn();
}
protected void addTypeEntry(Hashlist names, Type type)
{
String name = type.getName();
Integer hash = new Integer(name.hashCode());
Type[] types = (Type[])names.get(hash);
if (types == null) {
names.put(hash, new Type[] { type });
} else {
int n = types.length;
Type[] types2 = new Type[n + 1];
System.arraycopy(types, 0, types2, 0, n);
types2[n] = type;
names.put(hash, types2);
}
}
protected void compileMemberCallback(ByteCompiler context)
{
ClassRoom clazz = context.getClassRoom();
ConstantPool pool = clazz.getPool();
int sig_equals = pool.addMethodRef("java/lang/String", "equals", "(Ljava/lang/Object;)Z");
int total_get = 0;
int total_set = 0;
Hashlist names_get = new Hashlist();
Hashlist names_set = new Hashlist();
BindingEnumeration enum = _types.keysAndElements();
while(enum.hasMoreElements()) {
Type type = (Type)enum.nextElement();
switch(type.getType()) {
case Type.MEMBER_VARIABLE:
case Type.STATIC_VARIABLE:
{
total_set++;
addTypeEntry(names_set, type);
}
// fall through
case Type.METHOD:
case Type.FUNCTION:
case Type.CONSTANT_VARIABLE:
{
total_get++;
addTypeEntry(names_get, type);
}
break;
}
}
Method method = clazz.createMethod("getMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;", Code.ACC_PUBLIC);
Code code = method.getCode();
context.pushCode(code);
compileMemberAccess(method, code, pool, names_get, false, total_get, sig_equals);
code.self();
code.aload(1);
code.aload(2);
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "getMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;"));
code.areturn();
context.popCode();
method = clazz.createMethod("checkMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;", Code.ACC_PUBLIC);
code = method.getCode();
context.pushCode(code);
compileMemberAccess(method, code, pool, names_get, false, total_get, sig_equals);
code.self();
code.aload(1);
code.aload(2);
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "checkMember", "(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;"));
code.areturn();
context.popCode();
method = clazz.createMethod("setMember", "(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC);
code = method.getCode();
context.pushCode(code);
compileMemberAccess(method, code, pool, names_set, true, total_set, sig_equals);
code.self();
code.aload(1);
code.aload(2);
code.aload(3);
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "setMember", "(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;"));
code.areturn();
context.popCode();
}
protected void compileMemberAccess(Method method, Code code, ConstantPool pool, Hashlist names, boolean assign, int total, int sig_equals)
{
int l_context = code.addLocal();
int l_attr = code.addLocal();
int l_value = 0;
if (assign) {
l_value = code.addLocal();
}
if (total <= 3) {
BindingEnumeration enum = names.keysAndElements();
while(enum.hasMoreElements()) {
Type[] types = (Type[])enum.nextElement();
for(int i=0; i<types.length; i++) {
Type type = types[i];
code.aload(l_attr);
code.astring(type.getName());
code.invokevirtual(sig_equals);
Source isfalse = code.if_eq();
if (assign) {
compileMemberSet(code, pool, type, l_value);
} else {
compileMemberGet(code, pool, type);
}
isfalse.bind();
}
}
} else {
code.aload(l_attr);
code.invokevirtual(pool.addMethodRef("java/lang/String", "hashCode", "()I"));
Source notfound = code.getSource();
Switch select = code.select();
BindingEnumeration enum = names.keysAndElements();
while(enum.hasMoreElements()) {
Integer hash = (Integer)enum.nextKey();
select.addCase(hash.intValue());
enum.nextElement();
}
select.end();
enum = names.keysAndElements();
while(enum.hasMoreElements()) {
Integer hash = (Integer)enum.nextKey();
select.bindCase(hash.intValue());
Type[] types = (Type[])enum.nextElement();
for(int i=0; i<types.length; i++) {
Type type = types[i];
code.aload(l_attr);
code.astring(type.getName());
code.invokevirtual(sig_equals);
Source isfalse = code.if_eq();
if (assign) {
compileMemberSet(code, pool, type, l_value);
} else {
compileMemberGet(code, pool, type);
}
isfalse.bind();
}
code.go_to(notfound);
}
select.bindDefault();
notfound.bind();
}
}
protected void compileMemberGet(Code code, ConstantPool pool, Type type)
{
switch(type.getType()) {
case Type.MEMBER_VARIABLE:
{
code.self();
code.getfield(type.getTypeRef(pool));
code.areturn();
}
break;
case Type.METHOD:
{
int sig = pool.addClass("anvil/core/runtime/AnyFunction");
code.anew(sig);
code.dup();
code.self();
code.getstatic(pool.addFieldRef(type.getParent().getTypeRef(pool), "m_" + type.getName(), "Lanvil/script/Function;"));
code.invokespecial(pool.addMethodRef(sig, "<init>", "(Lanvil/core/Any;Lanvil/script/Function;)V"));
code.areturn();
}
break;
case Type.FUNCTION:
{
code.getstatic(pool.addFieldRef(type.getParent().getTypeRef(pool), "F_" + type.getName(), "Lanvil/core/Any;"));
code.areturn();
}
break;
case Type.CONSTANT_VARIABLE:
case Type.STATIC_VARIABLE:
{
code.getstatic(type.getTypeRef(pool));
code.areturn();
}
break;
}
}
protected void compileMemberSet(Code code, ConstantPool pool, Type type, int l_value)
{
switch(type.getType()) {
case Type.MEMBER_VARIABLE:
{
code.self();
code.aload(l_value);
code.dup_x1();
code.putfield(type.getTypeRef(pool));
code.areturn();
}
break;
case Type.STATIC_VARIABLE:
{
code.aload(l_value);
code.dup();
code.putstatic(type.getTypeRef(pool));
code.areturn();
}
break;
}
}
protected void compileAttributeCallback(
ByteCompiler context,
Method method,
int prefixLength,
boolean hasValue,
MethodStatement[] methods,
Node[] nodes1,
MethodStatement callback,
Node[] nodes2,
boolean castToBoolean)
{
ClassRoom clazz = context.getClassRoom();
Code code = method.getCode();
ConstantPool pool = code.getPool();
int sig_equals = pool.addMethodRef("java/lang/String", "equals", "(Ljava/lang/Object;)Z");
int sig_toBoolean = pool.addMethodRef("anvil/core/Any", "toBoolean", "()Z");
context.pushCode(code);
int l_context = code.addLocal();
int l_attr = code.addLocal();
int l_value = 0;
if (hasValue) {
l_value = code.addLocal();
}
if (methods != null) {
int n = methods.length;
if (n>3) {
code.aload(l_attr);
code.invokevirtual(pool.addMethodRef("java/lang/String", "hashCode", "()I"));
Source notfound = code.getSource();
Switch select = code.select();
for(int i=0; i<n; i++) {
select.addCase(methods[i].getName().substring(prefixLength).hashCode());
}
select.end();
Iterator iter = select.getCases();
while(iter.hasNext()) {
Switch.Case kase = (Switch.Case)iter.next();
kase.bind();
for(int i=0; i<n; i++) {
MethodStatement target = methods[i];
String name = target.getName().substring(prefixLength);
if (name.hashCode() == kase.getKey()) {
code.aload(l_attr);
code.astring(name);
code.invokevirtual(sig_equals);
Source isfalse = code.if_eq();
code.self();
context.compileArgumentList(target, nodes1, l_context);
code.invokevirtual(target.getTypeRef(pool));
if (castToBoolean) {
code.invokevirtual(sig_toBoolean);
code.ireturn();
} else {
code.areturn();
}
isfalse.bind();
}
}
code.go_to(notfound);
}
select.bindDefault();
notfound.bind();
} else {
for(int i=0; i<n; i++) {
MethodStatement target = methods[i];
code.aload(l_attr);
code.astring(target.getName().substring(prefixLength));
code.invokevirtual(sig_equals);
Source isfalse = code.if_eq();
code.self();
context.compileArgumentList(target, nodes1, l_context);
code.invokevirtual(target.getTypeRef(pool));
if (castToBoolean) {
code.invokevirtual(sig_toBoolean);
code.ireturn();
} else {
code.areturn();
}
isfalse.bind();
}
}
}
if (callback != null) {
code.self();
context.compileArgumentList(callback, nodes2, l_context);
code.invokevirtual(callback.getTypeRef(pool));
if (castToBoolean) {
code.invokevirtual(sig_toBoolean);
code.ireturn();
} else {
code.areturn();
}
} else {
code.self();
code.aload(l_context);
code.aload(l_attr);
if (hasValue) {
code.aload(l_value);
}
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(),
method.getName(), method.getDescriptor()));
if (castToBoolean) {
code.ireturn();
} else {
code.areturn();
}
}
context.popCode();
}
protected void compileConstructors(ByteCompiler context, Field typefield)
{
ClassRoom clazz = context.getClassRoom();
ConstantPool pool = clazz.getPool();
ClassType[] parents = getEnclosingClasses();
int n = parents.length;
Field[] fields = new Field[n];
for(int i=0; i<n; i++) {
fields[i] = clazz.createField("this$"+i, 'L'+parents[i].getDescriptor()+';', Code.ACC_PUBLIC);
}
Method constructor = clazz.createMethod("<init>", _constructor_signature, Code.ACC_PUBLIC);
Code code = constructor.getCode();
context.pushCode(code);
code.self();
code.addLocals(n);
ClassType[] base_parents = getBaseClass().getEnclosingClasses();
int m = base_parents.length;
next: for(int j=0; j<m; j++) {
ClassType parent = base_parents[j];
for(int i=0; i<n; i++) {
if (parent == parents[i]) {
code.aload(1+i);
continue next;
}
}
code.aconst_null();
}
ClassType baseclazz = getBaseClass();
if (baseclazz != Any.__class__) {
code.invokespecial(baseclazz.getConstructorReference(pool));
} else {
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "<init>", "()V"));
}
for(int i=0; i<n; i++) {
code.self();
code.aload(1+i);
code.putfield(fields[i]);
}
Enumeration enum = _types.elements();
for(int i=0; enum.hasMoreElements();) {
Type type = (Type)enum.nextElement();
if (type.getType() == MEMBER_VARIABLE) {
MemberVariableStatement member = (MemberVariableStatement)type;
if (member.hasConstantInitializer()) {
Expression initializer = member.createInitializer();
initializer.compile(context, Expression.GET);
code.pop();
}
}
}
code.vreturn();
context.popCode();
if (n > 0) {
constructor = clazz.createMethod("<init>", "()V", Code.ACC_PUBLIC);
code = constructor.getCode();
code.self();
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "<init>", "()V"));
code.vreturn();
}
Method method = clazz.createMethod("_serialize", "(Lanvil/core/Serializer;)V", Code.ACC_PUBLIC);
method.addCheckedException(pool.addClass("java/io/IOException"));
code = method.getCode();
context.pushCode(code);
int lserializer = code.addLocal();
int serializerclazz = pool.addClass("anvil/core/Serializer");
int unserializerclazz = pool.addClass("anvil/core/Unserializer");
int writestring = pool.addMethodRef(serializerclazz, "write", "(Ljava/lang/String;)V");
int writechar = pool.addMethodRef(serializerclazz, "write", "(C)V");
int serializemethod = pool.addMethodRef(context.TYPE_ANY, "serialize", "(Lanvil/core/Serializer;)V");
MethodStatement sleepmethod = getMethod("_sleep");
int lcontext = 0;
int lenum = 0;
if (sleepmethod != null) {
lenum = code.addLocal();
lcontext = code.addLocal();
code.aload(lserializer);
code.invokevirtual(pool.addMethodRef(serializerclazz, "getContext", "()Lanvil/script/Context;"));
code.astore(lcontext);
code.self();
context.compileArgumentList(sleepmethod, EMPTY, lcontext);
code.invokespecial(sleepmethod.getTypeRef(pool));
code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "enumeration",
"()Lanvil/java/util/BindingEnumeration;"));
code.astore(lenum);
}
if (baseclazz != Any.__class__) {
code.self();
code.aload(lserializer);
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "_serialize", "(Lanvil/core/Serializer;)V"));
}
for(int i=0; i<n; i++) {
code.self();
code.getfield(fields[i]);
code.aload(lserializer);
code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "serialize", "(Lanvil/core/Serializer;)V"));
}
if (sleepmethod != null) {
Target loop = code.getTarget();
code.aload(lenum);
code.invokeinterface(pool.addInterfaceMethodRef("java/util/Enumeration",
"hasMoreElements", "()Z"));
Source nomoreelements = code.if_eq();
int lfield = code.addLocal();
code.aload(lenum);
code.invokeinterface(pool.addInterfaceMethodRef("java/util/Enumeration",
"nextElement", "()Ljava/lang/Object;"));
code.invokevirtual(pool.addMethodRef(context.TYPE_OBJECT, "toString", "()Ljava/lang/String;"));
code.astore(lfield);
code.aload(lserializer);
code.aload(lfield);
code.invokevirtual(writestring);
code.self();
code.aload(lcontext);
code.aload(lfield);
code.invokevirtual(pool.addMethodRef("anvil/core/AnyClass", "getMember",
"(Lanvil/script/Context;Ljava/lang/String;)Lanvil/core/Any;"));
code.aload(lserializer);
code.invokevirtual(serializemethod);
code.go_to(loop);
nomoreelements.bind();
} else {
enum = _types.elements();
for(int i=0; enum.hasMoreElements();) {
Type type = (Type)enum.nextElement();
if (type.getType() == MEMBER_VARIABLE) {
code.aload(lserializer);
code.astring(type.getName());
code.invokevirtual(writestring);
code.self();
code.getfield(type.getTypeRef(pool));
code.aload(lserializer);
code.invokevirtual(serializemethod);
}
}
}
code.aload(lserializer);
code.iconst((int)';');
code.invokevirtual(writechar);
code.vreturn();
context.popCode();
method = clazz.createMethod("_unserialize", "(Lanvil/core/Unserializer;)V", Code.ACC_PUBLIC);
method.addCheckedException(pool.addClass("anvil/core/UnserializationException"));
code = method.getCode();
context.pushCode(code);
int unserializemethod = pool.addMethodRef(unserializerclazz, "unserialize", "()Lanvil/core/Any;");
int lunserializer = code.addLocal();
lcontext = code.addLocal();
code.aload(lunserializer);
code.invokevirtual(pool.addMethodRef(unserializerclazz, "getContext", "()Lanvil/script/Context;"));
code.astore(lcontext);
//if (sleepmethod != null) {
int undefined = pool.addFieldRef(context.TYPE_ANY, "UNDEFINED", "Lanvil/core/Any;");
enum = _types.elements();
while(enum.hasMoreElements()) {
Type type = (Type)enum.nextElement();
if (type.getType() == MEMBER_VARIABLE) {
MemberVariableStatement member = (MemberVariableStatement)type;
if (member.hasConstantInitializer()) {
Expression initializer = member.createInitializer();
initializer.compile(context, Expression.GET);
code.pop();
} else {
code.self();
code.getstatic(undefined);
code.putfield(type.getTypeRef(pool));
}
}
}
//}
if (baseclazz != Any.__class__) {
code.self();
code.aload(lunserializer);
code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "_unserialize", "(Lanvil/core/Unserializer;)V"));
}
for(int i=0; i<n; i++) {
code.self();
code.aload(lunserializer);
code.invokevirtual(unserializemethod);
code.checkcast(parents[i].getDescriptor());
code.putfield(fields[i]);
}
Target loop = code.getTarget();
code.aload(lunserializer);
code.invokevirtual(pool.addMethodRef(unserializerclazz, "get", "()I"));
code.iconst((int)';');
Source endoffields = code.if_icmpeq();
code.self();
code.aload(lcontext);
code.aload(lunserializer);
code.invokevirtual(pool.addMethodRef(unserializerclazz, "getUTF16String", "()Ljava/lang/String;"));
code.aload(lunserializer);
code.invokevirtual(unserializemethod);
code.invokevirtual(pool.addMethodRef("anvil/core/AnyClass", "setMember",
"(Lanvil/script/Context;Ljava/lang/String;Lanvil/core/Any;)Lanvil/core/Any;"));
code.pop();
code.go_to(loop);
endoffields.bind();
MethodStatement wakeupmethod = getMethod("_wakeup");
if (wakeupmethod != null) {
code.self();
context.compileArgumentList(wakeupmethod, EMPTY, lcontext);
code.invokespecial(wakeupmethod.getTypeRef(pool));
code.pop();
}
code.vreturn();
context.popCode();
}
protected static final Node[] EMPTY = new Node[0];
protected static final Node[] P1_NODE = new Node[] { new ParameterNode(1) };
protected static final Node[] P2_NODE = new Node[] { new ParameterNode(2) };
protected static final Node[] P3_NODE = new Node[] { new ParameterNode(3) };
protected static final Node[] P_Q_NODE = new Node[] { new ParameterNode(2), new ParameterNode(3) };
protected static final Node[] CAST_P1_NODE = new Node[] { new AnyCastNode(1) };
protected static final Node[] P1_S2A_NODE = new Node[] { new StringToAnyNode(1) };
protected static final Node[] P_S2A_NODE = new Node[] { new StringToAnyNode(2) };
protected static final Node[] P_S2A_Q_NODE = new Node[] { new StringToAnyNode(2), new ParameterNode(3) };
protected static class ParameterNode extends Node
{
private int _local;
public ParameterNode(int local)
{
_local = local;
}
public boolean isConstant()
{
return false;
}
public void compile(ByteCompiler context, int operation)
{
context.getCode().aload(_local);
}
}
protected static class AnyCastNode extends Node
{
private int _local;
public AnyCastNode(int local)
{
_local = local;
}
public boolean isConstant()
{
return false;
}
public void compile(ByteCompiler context, int operation)
{
Code code = context.getCode();
code.aload(_local);
code.checkcast(context.TYPE_ANY);
}
}
protected static class IndexToSymbol extends Node
{
private int _local;
public IndexToSymbol(int local)
{
_local = local;
}
public boolean isConstant()
{
return false;
}
public void compile(ByteCompiler context, int operation)
{
Code code = context.getCode();
ConstantPool pool = code.getPool();
code.iload(_local);
code.invokestatic(pool.addMethodRef("anvil/core/Register", "getAnyNameOf", "(I)Lanvil/core/Any;"));
}
}
protected static class StringToAnyNode extends Node
{
private int _local;
public StringToAnyNode(int local)
{
_local = local;
}
public boolean isConstant()
{
return false;
}
public void compile(ByteCompiler context, int operation)
{
Code code = context.getCode();
code.aload(_local);
code.invokestatic(code.getPool().addMethodRef(context.TYPE_ANY, "create",
"(Ljava/lang/String;)Lanvil/core/Any;"));
}
}
private static final String[] EXECUTE_SIGNATURES = new String[] {
"(Lanvil/script/Context;)Lanvil/core/Any;",
"(Lanvil/script/Context;Lanvil/core/Any;)Lanvil/core/Any;",
"(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
"(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
"(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
};
protected void compileExecuteMethod(ByteCompiler context, ClassRoom clazz, CompilableFunction function)
{
/* execute(Context, Any[]) */
{
Method method = clazz.createMethod("execute",
"(Lanvil/script/Context;[Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC);
Code code = method.getCode();
ConstantPool pool = code.getPool();
int l_context = code.addLocal();
int l_parameters = code.addLocal();
context.pushCode(code);
code.getstatic(pool.addFieldRef(clazz.getIndex(), "m_"+function.getName(), "Lanvil/script/Function;"));
code.aload(l_context);
code.self();
code.aload(l_parameters);
code.invokeinterface(pool.addInterfaceMethodRef("anvil/script/Function",
"execute", "(Lanvil/script/Context;Lanvil/core/Any;[Lanvil/core/Any;)Lanvil/core/Any;"));
code.areturn();
context.popCode();
}
for(int i=0; i<5; i++) {
Method method = clazz.createMethod("execute", EXECUTE_SIGNATURES[i], Code.ACC_PUBLIC);
Node[] params = new Node[i];
for(int j=0; j<i; j++) {
params[j] = new ParameterNode(2 + j);
}
compileCallback(context, function, method, false, 1+i, params, 0, 2);
}
}
private static final String[] INVOKE_SIGNATURES = new String[] {
"(Lanvil/script/Context;I)Lanvil/core/Any;",
"(Lanvil/script/Context;ILanvil/core/Any;)Lanvil/core/Any;",
"(Lanvil/script/Context;ILanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
"(Lanvil/script/Context;ILanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
"(Lanvil/script/Context;ILanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
};
private static final Node P2_TO_SYMBOL = new IndexToSymbol(2);
protected void compileInvokeMethod(ByteCompiler context, ClassRoom clazz, CompilableFunction function)
{
/* invoke(Context, int, Any[]) */
{
Method method = clazz.createMethod("invoke",
"(Lanvil/script/Context;I[Lanvil/core/Any;)Lanvil/core/Any;", Code.ACC_PUBLIC);
Code code = method.getCode();
ConstantPool pool = code.getPool();
context.pushCode(code);
int l_context = code.addLocal();
int l_index = code.addLocal();
int l_parameters = code.addLocal();
int l_length = code.addLocal();
int l_newparameters = code.addLocal();
code.aload(l_parameters);
code.arraylength();
code.istore(l_length);
code.iload(l_length);
code.iconst(1);
code.iadd();
code.anewarray(context.TYPE_ANY);
code.astore(l_newparameters);
code.aload(l_parameters);
code.iconst(0);
code.aload(l_newparameters);
code.iconst(1);
code.iload(l_length);
code.invokestatic(pool.addMethodRef("java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V"));
code.aload(l_newparameters);
code.iconst(0);
code.iload(l_index);
code.invokestatic(pool.addMethodRef("anvil/core/Register", "getAnyNameOf", "(I)Lanvil/core/Any;"));
code.aastore();
code.getstatic(pool.addFieldRef(clazz.getIndex(), "m_"+function.getName(), "Lanvil/script/Function;"));
code.aload(l_context);
code.self();
code.aload(l_newparameters);
code.invokeinterface(pool.addInterfaceMethodRef("anvil/script/Function",
"execute", "(Lanvil/script/Context;Lanvil/core/Any;[Lanvil/core/Any;)Lanvil/core/Any;"));
code.areturn();
context.popCode();
}
for(int i=0; i<4; i++) {
Method method = clazz.createMethod("invoke", INVOKE_SIGNATURES[i], Code.ACC_PUBLIC);
Node[] params = new Node[1 + i];
params[0] = P2_TO_SYMBOL;
for(int j=0; j<i; j++) {
params[j+1] = new ParameterNode(3 + j);
}
compileCallback(context, function, method, false, 3+i, params, 0, 2);
}
/* invoke(Context, int, Any, Any, Any, Any) */
{
Method method = clazz.createMethod("invoke", INVOKE_SIGNATURES[4], Code.ACC_PUBLIC);
Code code = method.getCode();
ConstantPool pool = code.getPool();
context.pushCode(code);
int l_context = code.addLocal();
int l_index = code.addLocal();
int l_base = code.addLocal();
code.addLocals(3);
code.getstatic(pool.addFieldRef(clazz.getIndex(), "m_"+function.getName(), "Lanvil/script/Function;"));
code.aload(l_context);
code.self();
code.iconst(5);
code.anewarray(context.TYPE_ANY);
code.dup();
code.iconst(0);
code.iload(l_index);
code.invokestatic(pool.addMethodRef("anvil/core/Register", "getNameOf", "(I)Ljava/lang/String;"));
code.invokestatic(pool.addMethodRef(context.TYPE_ANY, "create", "(Ljava/lang/String;)Lanvil/core/Any;"));
code.aastore();
for(int i=0; i<4; i++) {
code.dup();
code.iconst(i+1);
code.aload(l_base + i);
code.aastore();
}
code.invokeinterface(pool.addInterfaceMethodRef("anvil/script/Function",
"execute", "(Lanvil/script/Context;Lanvil/core/Any;[Lanvil/core/Any;)Lanvil/core/Any;"));
code.areturn();
context.popCode();
}
}
protected void compileCallback(ByteCompiler context, CompilableFunction function,
Method method, boolean getContext, int parameters, Node[] nodes, int toType, int treturn)
{
Code code = method.getCode();
ConstantPool pool = code.getPool();
context.pushCode(code);
int contextindex = 1;
if (parameters > 0) {
code.addLocals(parameters);
}
if (getContext) {
contextindex = code.addLocal();
code.invokestatic(pool.addMethodRef(context.TYPE_CONTEXT, "getInstance", "()Lanvil/script/Context;"));
code.astore(contextindex);
}
code.self();
context.compileArgumentList(function, nodes, contextindex);
code.invokevirtual(function.getTypeRef(pool));
if (toType > 0) {
code.invokevirtual(toType);
} else if (toType < 0) {
code.invokestatic(-toType);
}
switch(treturn) {
case 0:
code.pop();
code.vreturn();
break;
case 1:
code.ireturn();
break;
case 2:
code.areturn();
break;
}
context.popCode();
}
protected void compileEqualsMethod(ByteCompiler context, CompilableFunction function)
{
ClassRoom clazz = context.getClassRoom();
Method method = clazz.createMethod("equals", "(Ljava/lang/Object;)Z", Code.ACC_PUBLIC);
Code code = method.getCode();
ConstantPool pool = code.getPool();
context.pushCode(code);
code.addLocal();
code.aload(1);
code.instance_of(context.TYPE_ANY);
Source isfalse = code.if_eq();
code.invokestatic(pool.addMethodRef(context.TYPE_CONTEXT, "getInstance", "()Lanvil/script/Context;"));
code.astore(code.addLocal());
code.self();
context.compileArgumentList(function, CAST_P1_NODE, 2);
code.invokevirtual(function.getTypeRef(pool));
code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "toBoolean", "()Z"));
code.ireturn();
isfalse.bind();
code.iconst(false);
code.ireturn();
context.popCode();
}
protected void compileCopyMethod(ByteCompiler context, MethodStatement callback, boolean iscopy, Field typefield)
{
ClassRoom clazz = context.getClassRoom();
ConstantPool pool = clazz.getPool();
Method method;
if (iscopy) {
method = clazz.createMethod("copy", "()Lanvil/core/Any;", Code.ACC_PUBLIC);
} else {
method = clazz.createMethod("clone", "()Ljava/lang/Object;", Code.ACC_PUBLIC);
}
Code code = method.getCode();
context.pushCode(code);
int copymethod;
if (iscopy) {
copymethod = pool.addMethodRef(context.TYPE_ANY, "copy", "()Lanvil/core/Any;");
} else {
copymethod = pool.addMethodRef(context.TYPE_ANY, "clone", "()Ljava/lang/Object;");
}
int classindex = clazz.getIndex();
int l_self = code.addLocal();
code.anew(classindex);
code.dup();
ClassType[] parents = _parents;
int n = parents.length;
for(int i=0; i<n; i++) {
code.self();
code.getfield(pool.addFieldRef(clazz.getIndex(), "this$"+i, 'L'+parents[i].getDescriptor()+';'));
}
code.invokespecial(pool.addMethodRef(classindex, "<init>", _constructor_signature));
code.astore(l_self);
ClassType classtype = this;
while(classtype != null) {
classindex = classtype.getTypeRef(pool);
Enumeration enum = classtype.getDeclarations();
while (enum.hasMoreElements()) {
Type type = (Type)enum.nextElement();
if (type.getType() == Type.MEMBER_VARIABLE) {
int fieldref = pool.addFieldRef(classindex, "f_"+type.getName(), "Lanvil/core/Any;");
code.aload(l_self);
code.self();
code.getfield(fieldref);
code.invokevirtual(copymethod);
if (!iscopy) {
code.checkcast(context.TYPE_ANY);
}
code.putfield(fieldref);
}
}
classtype = classtype.getBaseClass();
}
code.aload(l_self);
code.areturn();
context.popCode();
}
public ClassDispatcher getDispatcher(Context context)
{
return null;
}
}