Package anvil.script.compiler

Source Code of anvil.script.compiler.DispatcherFactory

/*
* $Id: DispatcherFactory.java,v 1.9 2002/09/16 08:05:04 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.compiler;

import java.io.File;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.ByteArrayOutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import anvil.java.util.BindingEnumeration;
import anvil.java.util.Hashlist;

import anvil.script.CompilableFunction;
import anvil.script.Function;
import anvil.script.ClassType;
import anvil.script.Type;
import anvil.script.Scope;
import anvil.script.ClassDispatcher;
import anvil.script.FunctionDispatcher;
import anvil.script.GeneratorDispatcher;
import anvil.script.NativeJava;
import anvil.core.Any;
import anvil.core.Register;
import anvil.codec.ClassRoom;
import anvil.codec.Code;
import anvil.codec.ConstantPool;
import anvil.codec.ExceptionHandler;
import anvil.codec.Method;
import anvil.codec.Field;
import anvil.codec.CodecConstants;
import anvil.codec.Switch;
import anvil.codec.Source;
import anvil.server.ZoneClassLoader;

public class DispatcherFactory implements CodecConstants
{

  private static int _index;
 

  private static synchronized String getNextName()
  {
    return "anvil/script/compiler/GeneratedDispatcher_"+(_index++);
  }


  private static String[] EXECUTE_SIGNATURES =
  {
    "(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;",
    "(Lanvil/script/Context;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;"
  };
 
  private static String[] GATHER1 =
  {
    "()Lanvil/core/Array;",
    "(Lanvil/core/Any;)Lanvil/core/Array;",
    "(Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Array;",
    "(Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Array;",
    "(Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Array;"
  };

  private static String[] GATHER2 =
  {
    "()[Lanvil/core/Any;",
    "(Lanvil/core/Any;)[Lanvil/core/Any;",
    "(Lanvil/core/Any;Lanvil/core/Any;)[Lanvil/core/Any;",
    "(Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)[Lanvil/core/Any;",
    "(Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)[Lanvil/core/Any;",
  };

  private static String[] GATHER3 =
  {
    "()Lanvil/core/AnyTuple;",
    "(Lanvil/core/Any;)Lanvil/core/AnyTuple;",
    "(Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/AnyTuple;",
    "(Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/AnyTuple;",
    "(Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/AnyTuple;",
  };

  public static FunctionDispatcher create(CompilableFunction function, boolean isstatic, ZoneClassLoader loader)
    throws Throwable
  {
    ClassRoom clazz = new ClassRoom();
    ConstantPool pool = clazz.getPool();
    String classname = getNextName();
    clazz.setClassname(classname, null);
    clazz.setSuperClassname("java/lang/Object");
    clazz.addInterface("anvil/script/FunctionDispatcher");
    clazz.setAccessFlags(ACC_PUBLIC|ACC_FINAL);

    Hashlist constants = new Hashlist();

    //generic
    {
      Method method = clazz.createMethod("execute",
       "(Lanvil/script/Context;Lanvil/core/Any;[Lanvil/core/Any;)Lanvil/core/Any;",
       ACC_PUBLIC|ACC_FINAL);
      Code code = method.getCode();
      int l_context = code.addLocal();
      int l_self = code.addLocal();
      int l_parameters = code.addLocal();
      compileDispatch(function, isstatic, clazz, code, pool, l_context, l_self, l_parameters, constants);
    }

    for(int params=0; params<=4; params++) {
   
      Method method = clazz.createMethod("execute", EXECUTE_SIGNATURES[params], ACC_PUBLIC|ACC_FINAL);
      Code code = method.getCode();
      int l_context = code.addLocal();
      int l_self = code.addLocal();
      int l_base = code.addLocal();
      code.addLocals(params);
      compileDispatch(function, isstatic, clazz, code, pool, l_context, l_self, l_base, params, constants);
    }

    createConstructor(clazz, constants);

    ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
    clazz.write(new DataOutputStream(bytestream));
    bytestream.close();

    //FileOutputStream fout = new FileOutputStream("/data/projects/anvil/src/"+classname+".class");
    //bytestream.writeTo(fout);
    //fout.close();

    Class cls = loader.define(classname, bytestream.toByteArray());
    return (FunctionDispatcher)cls.newInstance();

  }


  private static void createConstructor(ClassRoom clazz, Hashlist constants)
  {
    Method method = clazz.createMethod("<init>", "()V", ACC_PUBLIC);
    ConstantPool pool = clazz.getPool();
    Code code = method.getCode();
    code.self();
    code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "<init>", "()V"));
    Enumeration enum = constants.keys();
    for(int i=0; enum.hasMoreElements(); i++) {
      Any defaultvalue = (Any)enum.nextElement();
      Field field = clazz.createField("const_"+i, "Lanvil/core/Any;", ACC_PUBLIC);
      code.self();
      defaultvalue.toCode(code);
      code.putfield(field);
    }
    code.vreturn();
  }


  private static void compileDispatch(
      CompilableFunction function,
      boolean isstatic,
      ClassRoom clazz,
      Code code,
      ConstantPool pool,
      int l_context,
      int l_self,
      int l_parameters,
      Hashlist constants)
  {
    int minparams = function.getMinimumParameterCount();
    int maxparams = function.getParameterCount();
   
    int helperclass = pool.addClass("anvil/script/compiler/DispatcherHelper");

    boolean collector = false;
    int realparams = 0;
    for(int i=0; i<maxparams; i++) {
      int type = function.getParameterType(i);
      if (type == CompilableFunction.PARAMETER_CONTEXT) {
        continue;
      }
      if (type>=CompilableFunction.PARAMETER_ARRAY) {
        collector = true;
        continue;
      }
      realparams++;
    }

    if (!isstatic) {
      code.aload(l_self);
      Source nonnull = code.if_nonnull();
      code.aload(l_context);
      code.astring(function.toString());
      code.invokevirtual(pool.addMethodRef("anvil/script/Context", "NoInstance",
        "(Ljava/lang/String;)Lanvil/script/ScriptException;"));
      code.athrow();
      nonnull.bind();
    }

    code.aload(l_parameters);
    code.arraylength();
    Switch select = code.select();
    for(int params=0; params<=realparams; params++) {
      select.addCase(params);
    }
    select.end();

    for(int params=0; params<=realparams; params++) {
      select.bindCase(params);
      if (params < minparams-1) {
        // fall through
      } else if (params == minparams-1) {
        code.aload(l_context);
        code.astring(function.toString());
        code.invokevirtual(pool.addMethodRef("anvil/script/Context", "NotEnoughParameters",
          "(Ljava/lang/String;)Lanvil/script/ScriptException;"));
        code.athrow();
      } else {
        if (params == realparams) {
          select.bindDefault();
        }

        /*int l_index = 0;
        ExceptionHandler handler = null;
        if (function instanceof NativeJava) {
          code.addLocal();
          code.aload(l_context);
          code.invokevirtual(pool.addMethodRef("anvil/script/StackFrameStack", "size", "()I"));
          code.istore(l_index);
          handler = code.startExceptionHandler(false);
        }*/

        if (!isstatic) {
          code.aload(l_self);
          code.checkcast(function.getParent().getTypeRef(pool));
        }
        int c = 0;
        for(int i=0; i<maxparams; i++) {
          int type = function.getParameterType(i);
          switch(type) {
          case CompilableFunction.PARAMETER_CONTEXT:
            code.aload(l_context);
            break;

          case CompilableFunction.PARAMETER_ARRAY:
            code.aload(l_parameters);
            code.iconst(params);
            code.invokestatic(pool.addMethodRef(helperclass, "rest1", "([Lanvil/core/Any;I)Lanvil/core/Array;"));
            break;

          case CompilableFunction.PARAMETER_LIST:
            if (params == 0) {
              code.aload(l_parameters);
            } else {
              code.aload(l_parameters);
              code.iconst(params);
              code.invokestatic(pool.addMethodRef(helperclass, "rest2", "([Lanvil/core/Any;I)[Lanvil/core/Any;"));
            }
            break;           

          case CompilableFunction.PARAMETER_ANYLIST:
          case CompilableFunction.PARAMETER_REST:
            code.aload(l_parameters);
            code.iconst(params);
            code.invokestatic(pool.addMethodRef(helperclass, "rest3", "([Lanvil/core/Any;I)Lanvil/core/AnyTuple;"));
            break;

          default:
            if (c>=params) {
              anvil.core.Any defaultvalue = function.getParameterDefault(i);
              switch(type) {
              case CompilableFunction.PARAMETER_ANY:
                if (defaultvalue != null) {
                  code.self();
                  int index = addConstant(constants, defaultvalue);
                  code.getfield(pool.addFieldRef(clazz.getClassnameIndex(), "const_"+index, "Lanvil/core/Any;"));
                  if (defaultvalue.isMutable()) {
                    code.invokevirtual(pool.addMethodRef("anvil/core/Any", "copy", "()Lanvil/core/Any;"));
                  }
                } else {
                  code.aconst_null();
                }
                break;

              case CompilableFunction.PARAMETER_OBJECT:
                if (defaultvalue != null) {
                  code.self();
                  int index = addConstant(constants, defaultvalue);
                  code.getfield(pool.addFieldRef(clazz.getClassnameIndex(), "const_"+index, "Lanvil/core/Any;"));
                  if (defaultvalue.isMutable()) {
                    code.invokevirtual(pool.addMethodRef("anvil/core/Any", "copy", "()Lanvil/core/Any;"));
                  }
                  code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toObject",
                    "()Ljava/lang/Object;"));
                } else {
                  code.aconst_null();
                }
                break;

              case CompilableFunction.PARAMETER_STRING:
                if (defaultvalue != null) {
                  code.astring(defaultvalue.toString());
                } else {
                  code.aconst_null();
                }
                break;

              case CompilableFunction.PARAMETER_DOUBLE:
                if (defaultvalue != null) {
                  code.dconst(defaultvalue.toDouble());
                } else {
                  code.dconst(0.0);
                }
                break;

              case CompilableFunction.PARAMETER_INT:
                if (defaultvalue != null) {
                  code.iconst(defaultvalue.toInt());
                } else {
                  code.iconst(0);
                }
                break;

              case CompilableFunction.PARAMETER_LONG:
                if (defaultvalue != null) {
                  code.lconst(defaultvalue.toLong());
                } else {
                  code.lconst(0);
                }
                break;           

              case CompilableFunction.PARAMETER_BOOLEAN:
                if (defaultvalue != null) {
                  code.iconst(defaultvalue.toBoolean());
                } else {
                  code.iconst(false);
                }
                break;
              }

            } else {
              code.aload(l_parameters);
              code.iconst(c++);
              code.aaload();
              switch(type) {
              case CompilableFunction.PARAMETER_ANY:
                break;

              case CompilableFunction.PARAMETER_STRING:
                code.invokevirtual(pool.addMethodRef("java/lang/Object", "toString",
                  "()Ljava/lang/String;"));
                break;

              case CompilableFunction.PARAMETER_OBJECT:
                code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toObject",
                  "()Ljava/lang/Object;"));
                break;

              case CompilableFunction.PARAMETER_DOUBLE:
                code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toDouble",
                  "()D"));
                break;

              case CompilableFunction.PARAMETER_INT:
                code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toInt",
                  "()I"));
                break;

              case CompilableFunction.PARAMETER_LONG:
                code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toLong",
                  "()J"));
                break;           

              case CompilableFunction.PARAMETER_BOOLEAN:
                code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toBoolean",
                  "()Z"));
                break;
              }
            }
          }
        }
        if (isstatic) {
          code.invokestatic(function.getTypeRef(pool));
        } else {
          code.invokevirtual(function.getTypeRef(pool));
        }
        code.areturn();
       
        /*if (handler != null) {
          handler.endTry();
          handler.startCatch(pool.addClass("anvil/script/ScriptException"));
          int l_throwable = code.addLocal();
          code.astore(l_throwable);

          code.aload(l_throwable);
          code.aload(l_self);
          code.iload(l_index);
          code.iconst(Register.register(function.getName()));
          code.invokevirtual(pool.addMethodRef("anvil/script/ScriptException", "fill",
            "(Ljava/lang/Object;II)Lanvil/script/ScriptException;"));
          code.athrow();
          code.endLocal(l_throwable);
          handler.endProtectedRegion();
          handler.endCatches();
          handler.end();

          code.endLocal(l_index);
        }*/

      }
    }

  }
 

  private static int addConstant(Hashlist constants, Any value)
  {
    Integer index = (Integer)constants.get(value);
    if (index == null) {
      int next = constants.size();
      constants.put(value, anvil.core.ObjectPool.createInteger(next));
      return next;
    }
    return index.intValue();
  }
 

  private static void compileDispatch(
      CompilableFunction function,
      boolean isstatic,
      ClassRoom clazz,
      Code code,
      ConstantPool pool,
      int l_context,
      int l_self,
      int l_base,
      int parameters,
      Hashlist constants)
  {
    int minparams = function.getMinimumParameterCount();
    int maxparams = function.getParameterCount();
   
    int helperclass = pool.addClass("anvil/script/compiler/DispatcherHelper");

    boolean collector = false;
    int realparameters = 0;
    for(int i=0; i<maxparams; i++) {
      int type = function.getParameterType(i);
      if (type == CompilableFunction.PARAMETER_CONTEXT) {
        continue;
      }
      if (type>=CompilableFunction.PARAMETER_ARRAY) {
        collector = true;
        continue;
      }
      realparameters++;
    }
   
    if (parameters < minparams) {
      code.aload(l_context);
      code.astring(function.toString());
      code.invokevirtual(pool.addMethodRef("anvil/script/Context", "NotEnoughParameters",
        "(Ljava/lang/String;)Lanvil/script/ScriptException;"));
      code.athrow();
      return;
    }

    if (!isstatic) {
      code.aload(l_self);
      Source nonnull = code.if_nonnull();
      code.aload(l_context);
      code.astring(function.toString());
      code.invokevirtual(pool.addMethodRef("anvil/script/Context", "NoInstance",
        "(Ljava/lang/String;)Lanvil/script/ScriptException;"));
      code.athrow();
      nonnull.bind();
    }
   
    /*int l_index = 0;
    ExceptionHandler handler = null;
    if (function instanceof NativeJava) {
      l_index = code.addLocal();
      code.aload(l_context);
      code.invokevirtual(pool.addMethodRef("anvil/script/StackFrameStack", "size", "()I"));
      code.istore(l_index);
      handler = code.startExceptionHandler(false);
    }*/
   
    if (!isstatic) {
      code.aload(l_self);
      code.checkcast(function.getParent().getTypeRef(pool));
    }
   
    int c = 0;
    for(int i=0; i<maxparams; i++) {
      int type = function.getParameterType(i);
      switch(type) {
      case CompilableFunction.PARAMETER_CONTEXT:
        code.aload(l_context);
        break;

      case CompilableFunction.PARAMETER_ARRAY:
        {
          int left = (parameters - c);
          while(c < parameters) {
            code.aload(l_base + c++);
          }
          code.invokestatic(pool.addMethodRef(helperclass, "gather1", GATHER1[left]));
        }
        break;

      case CompilableFunction.PARAMETER_LIST:
        {
          int left = (parameters - c);
          while(c < parameters) {
            code.aload(l_base + c++);
          }
          code.invokestatic(pool.addMethodRef(helperclass, "gather2", GATHER2[left]));
        }
        break;

      case CompilableFunction.PARAMETER_ANYLIST:
      case CompilableFunction.PARAMETER_REST:
        {
          int left = (parameters - c);
          while(c < parameters) {
            code.aload(l_base + c++);
          }
          code.invokestatic(pool.addMethodRef(helperclass, "gather3", GATHER3[left]));
        }
        break;

      default:
        if (c>=parameters) {
          anvil.core.Any defaultvalue = function.getParameterDefault(i);
          switch(type) {
          case CompilableFunction.PARAMETER_ANY:
            if (defaultvalue != null) {
              code.self();
              int index = addConstant(constants, defaultvalue);
              code.getfield(pool.addFieldRef(clazz.getClassnameIndex(), "const_"+index, "Lanvil/core/Any;"));
              if (defaultvalue.isMutable()) {
                code.invokevirtual(pool.addMethodRef("anvil/core/Any", "copy", "()Lanvil/core/Any;"));
              }
            } else {
              code.aconst_null();
            }
            break;

          case CompilableFunction.PARAMETER_OBJECT:
            if (defaultvalue != null) {
              code.self();
              int index = addConstant(constants, defaultvalue);
              code.getfield(pool.addFieldRef(clazz.getClassnameIndex(), "const_"+index, "Lanvil/core/Any;"));
              if (defaultvalue.isMutable()) {
                code.invokevirtual(pool.addMethodRef("anvil/core/Any", "copy", "()Lanvil/core/Any;"));
              }
              code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toObject",
                "()Ljava/lang/Object;"));
            } else {
              code.aconst_null();
            }
            break;

          case CompilableFunction.PARAMETER_STRING:
            if (defaultvalue != null) {
              code.astring(defaultvalue.toString());
            } else {
              code.aconst_null();
            }
            break;

          case CompilableFunction.PARAMETER_DOUBLE:
            if (defaultvalue != null) {
              code.dconst(defaultvalue.toDouble());
            } else {
              code.dconst(0.0);
            }
            break;

          case CompilableFunction.PARAMETER_INT:
            if (defaultvalue != null) {
              code.iconst(defaultvalue.toInt());
            } else {
              code.iconst(0);
            }
            break;

          case CompilableFunction.PARAMETER_LONG:
            if (defaultvalue != null) {
              code.lconst(defaultvalue.toLong());
            } else {
              code.lconst(0);
            }
            break;           

          case CompilableFunction.PARAMETER_BOOLEAN:
            if (defaultvalue != null) {
              code.iconst(defaultvalue.toBoolean());
            } else {
              code.iconst(false);
            }
            break;
          }

        } else {
          code.aload(l_base + c++);
          switch(type) {
          case CompilableFunction.PARAMETER_ANY:
            break;

          case CompilableFunction.PARAMETER_STRING:
            code.invokevirtual(pool.addMethodRef("java/lang/Object", "toString",
              "()Ljava/lang/String;"));
            break;

          case CompilableFunction.PARAMETER_OBJECT:
            code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toObject",
              "()Ljava/lang/Object;"));
            break;

          case CompilableFunction.PARAMETER_DOUBLE:
            code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toDouble",
              "()D"));
            break;

          case CompilableFunction.PARAMETER_INT:
            code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toInt",
              "()I"));
            break;

          case CompilableFunction.PARAMETER_LONG:
            code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toLong",
              "()J"));
            break;           

          case CompilableFunction.PARAMETER_BOOLEAN:
            code.invokevirtual(pool.addMethodRef("anvil/core/Any", "toBoolean",
              "()Z"));
            break;
          }
        }
      }
    }
   
    if (isstatic) {
      code.invokestatic(function.getTypeRef(pool));
    } else {
      code.invokevirtual(function.getTypeRef(pool));
    }
    code.areturn();
   
    /*if (handler != null) {
      handler.endTry();
      handler.startCatch(pool.addClass("anvil/script/ScriptException"));
      int l_throwable = code.addLocal();
      code.astore(l_throwable);

      code.aload(l_throwable);
      code.aload(l_self);
      code.iload(l_index);
      code.iconst(Register.register(function.getName()));
      code.invokevirtual(pool.addMethodRef("anvil/script/ScriptException", "fill",
        "(Ljava/lang/Object;II)Lanvil/script/ScriptException;"));
      code.athrow();
      code.endLocal(l_throwable);
      handler.endProtectedRegion();
      handler.endCatches();
      handler.end();

      code.endLocal(l_index);
    }*/

  }




  private static String[] INVOKE_SIGNATURES =
  {
    "(Lanvil/script/Context;Ljava/lang/Object;I)Lanvil/core/Any;",
    "(Lanvil/script/Context;Ljava/lang/Object;ILanvil/core/Any;)Lanvil/core/Any;",
    "(Lanvil/script/Context;Ljava/lang/Object;ILanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
    "(Lanvil/script/Context;Ljava/lang/Object;ILanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;",
    "(Lanvil/script/Context;Ljava/lang/Object;ILanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;"
  };
 

  public static ClassDispatcher create(ClassType cls, ZoneClassLoader loader)
    throws Throwable
  {
    HashMap set = new HashMap();
    ClassType c = cls;
    while(c != null) {
      Enumeration enum = c.getDeclarations();
      while(enum.hasMoreElements()) {
        Type type = (Type)enum.nextElement();
        int typeOf = type.getType();
        if (typeOf == Type.METHOD || typeOf == Type.FUNCTION) {
          Integer index = new Integer(Register.register(type.getName()));
          if (!set.containsKey(index)) {
            set.put(index, type);
          }
        }
      }
      c = c.getBaseClass();
    }

    ClassRoom clazz = new ClassRoom();
    ConstantPool pool = clazz.getPool();
    String classname = getNextName();
    clazz.setClassname(classname, null);
    clazz.setSuperClassname("java/lang/Object");
    clazz.addInterface("anvil/script/ClassDispatcher");
    clazz.setAccessFlags(ACC_PUBLIC|ACC_FINAL);

    Method method1 = clazz.createMethod("invoke",
      "(Lanvil/script/Context;Ljava/lang/Object;I[Lanvil/core/Any;)Lanvil/core/Any;",
      ACC_PUBLIC|ACC_FINAL);
    Code code1 = method1.getCode();
    code1.addLocals(4);
   
    Method[] methods = new Method[5];
    for(int i=0; i<5; i++) {
      Method method = clazz.createMethod("invoke", INVOKE_SIGNATURES[i], ACC_PUBLIC|ACC_FINAL);;
      methods[i] = method;
      Code code = method.getCode();
      code.addLocals(3 + i);
    }

    Method method2 = clazz.createMethod("hasMethod", "(I)Z", ACC_PUBLIC|ACC_FINAL);
    Code code2 = method2.getCode();
    code2.addLocal();

    code1.iload(3);
    for(int i=0; i<5; i++) {
      methods[i].getCode().iload(3);
    }
    code2.iload(1);
   
    Switch select1 = code1.select();
    Switch[] select = new Switch[] {
      methods[0].getCode().select(),
      methods[1].getCode().select(),
      methods[2].getCode().select(),
      methods[3].getCode().select(),
      methods[4].getCode().select()
    };
    Switch select2 = code2.select();
    Iterator iter = set.keySet().iterator();
    while(iter.hasNext()) {
      int index = ((Integer)iter.next()).intValue();
      select1.addCase(index);
      for(int i=0; i<5; i++) {
        select[i].addCase(index);
      }
      select2.addCase(index);
    }
    select1.end();
    for(int i=0; i<5; i++) {
      select[i].end();
    }
    select2.end();

    Hashlist constants = new Hashlist();

    iter = set.keySet().iterator();
    while(iter.hasNext()) {
      Integer index = (Integer)iter.next();
      int value = index.intValue();
      select1.bindCase(value);
      for(int i=0; i<5; i++) {
        select[i].bindCase(value);
      }
      select2.bindCase(value);
      CompilableFunction function = (CompilableFunction)set.get(index);
      boolean isStatic = (function.getType() == Type.FUNCTION);
      compileDispatch(function, isStatic, clazz, code1, pool, 1, 2, 4, constants);
      for(int i=0; i<5; i++) {
        compileDispatch(function, isStatic, clazz, methods[i].getCode(), pool, 1, 2, 4, i, constants);
      }
    }
    code2.iconst(true);
    code2.ireturn();

    select1.bindDefault();
    for(int i=0; i<5; i++) {
      select[i].bindDefault();
    }
    select2.bindDefault();

    code1.aload(1);
    code1.astring(cls.getQualifiedName());
    code1.iload(3);
    code1.invokevirtual(pool.addMethodRef("anvil/script/Context", "NoSuchMethod",
      "(Ljava/lang/String;I)Lanvil/script/ScriptException;"));
    code1.athrow();

    for(int i=0; i<5; i++) {
      Code code = methods[i].getCode();
      code.aload(1);
      code.astring(cls.getQualifiedName());
      code.iload(3);
      code.invokevirtual(pool.addMethodRef("anvil/script/Context", "NoSuchMethod",
        "(Ljava/lang/String;I)Lanvil/script/ScriptException;"));
      code.athrow();
    }

    code2.iconst(false);
    code2.ireturn();

    createConstructor(clazz, constants);

    ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
    clazz.write(new DataOutputStream(bytestream));
    bytestream.close();

    /*FileOutputStream fout = new FileOutputStream("/data/projects/anvil/src/"+classname+".class");
    bytestream.writeTo(fout);
    fout.close();*/

    Class javaclass = loader.define(classname, bytestream.toByteArray());
    return (ClassDispatcher)javaclass.newInstance();
  }

 
  public static GeneratorDispatcher createGenerator(CompilableFunction function, ZoneClassLoader loader)
    throws Throwable
  {
    ClassRoom clazz = new ClassRoom();
    ConstantPool pool = clazz.getPool();
    String classname = getNextName();
    clazz.setClassname(classname, null);
    clazz.setSuperClassname("java/lang/Object");
    clazz.addInterface("anvil/script/GeneratorDispatcher");
    clazz.setAccessFlags(ACC_PUBLIC|ACC_FINAL);

    Method method = clazz.createMethod("<init>", "()V", ACC_PUBLIC);
    Code code = method.getCode();
    code.self();
    code.invokespecial(pool.addMethodRef(clazz.getSuperClassIndex(), "<init>", "()V"));
    code.vreturn();

    method = clazz.createMethod("execute",
      "(Lanvil/script/Context;Lanvil/core/AnyClass;Lanvil/script/Generator;)Lanvil/core/Any;",
      ACC_PUBLIC|ACC_FINAL);
    code = method.getCode();
    code.addLocals(4);
   
    boolean ismethod = (function.getType() == Type.METHOD);
    Scope parent = function.getParent();
    int parent_ref = parent.getTypeRef(pool);
    if (ismethod) {
      code.aload(2);
      code.checkcast(parent_ref);
    }
    code.aload(1);
    code.aload(3);
    int method_ref = pool.addMethodRef(
        parent_ref, "h_"+function.getName(), "(Lanvil/script/Context;Lanvil/script/Generator;)Lanvil/core/Any;");
    if (ismethod) {
      code.invokevirtual(method_ref);
    } else {
      code.invokestatic(method_ref);
    }
    code.areturn();

    ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
    clazz.write(new DataOutputStream(bytestream));
    bytestream.close();

    Class cls = loader.define(classname, bytestream.toByteArray());
    return (GeneratorDispatcher)cls.newInstance()
  }


}
TOP

Related Classes of anvil.script.compiler.DispatcherFactory

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.