Package anvil.script.statements

Source Code of anvil.script.statements.ClassStatement$IndexToSymbol

/*
* $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;
  }


}
TOP

Related Classes of anvil.script.statements.ClassStatement$IndexToSymbol

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
div>