Package anvil.script.compiler

Source Code of anvil.script.compiler.ByteCompiler

/*
* $Id: ByteCompiler.java,v 1.14 2002/09/16 08:05:03 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 anvil.core.Any;
import anvil.core.AnyPattern;
import anvil.core.AnyRange;
import anvil.core.Array;
import anvil.core.Register;
import anvil.core.reflect.Reflection;
import anvil.Location;
import anvil.Log;
import anvil.doc.Doc;
import anvil.server.Address;
import anvil.server.ZoneClassLoader;
import anvil.server.Zone;
import anvil.server.CompilerPreferences;
import anvil.script.CompilableFunction;
import anvil.script.ClassType;
import anvil.script.Type;
import anvil.script.expression.Node;
import anvil.script.Smith;
import anvil.script.Module;
import anvil.script.ModuleEnvelope;
import anvil.script.expression.Node;
import anvil.script.statements.FunctionStatement;
import anvil.script.statements.SwitchStatement;
import anvil.java.util.BindingEnumeration;
import anvil.util.Conversions;
import anvil.java.util.Hashlist;
import anvil.java.util.HashlistIterator;
import java.io.File;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Stack;

import anvil.codec.Code;
import anvil.codec.ClassRoom;
import anvil.codec.Method;
import anvil.codec.Field;
import anvil.codec.CodecConstants;
import anvil.codec.ConstantPool;
import anvil.codec.Source;

/**
* class ByteCompiler
*
* @author: Jani Lehtim´┐Żki
*/
public class ByteCompiler implements CodecConstants
{

  public static final int L_THIS    = 0;
  public static final int L_CONTEXT = 0;
  public static final int L_FRAME   = 0;

  public String TYPE_MODULE;
  public static final String TYPE_OBJECT = "java/lang/Object";
  public static final String TYPE_ANY = "anvil/core/Any";
  public static final String TYPE_ANY_OP = "anvil/core/Any$Op";
  public static final String TYPE_ANY_ARRAY = "[Lanvil/core/Any;";
  public static final String TYPE_CONTEXT = "anvil/script/Context";
  public static final String TYPE_SYMBOLS = "anvil/core/Symbols";
  public static final String TYPE_FUNCTION = "anvil/script/Function";
  public static final String TYPE_COMPILED_SCRIPT = "anvil/script/compiler/CompiledModule";
  public static final String TYPE_STACKFRAME = "anvil/script/StackFrame";


  public static final int GET         = 0;
  public static final int GET_BOOLEAN = 1;
  public static final int SET         = 2;
  public static final int CHECK       = 3;
  public static final int DELETE      = 4;

  private Smith _smith;
  private ModuleEnvelope _envelope;
  private CompilerPreferences _prefs;
  private boolean _debug;
  private Writer _writer;
  private Hashlist _constants = new Hashlist();
  private Hashlist _symbols = new Hashlist();
  private Hashlist _texts = new Hashlist();
  private Hashlist _reflections = new Hashlist();
  private Vector _switches = new Vector();
  private StringBuffer _text = new StringBuffer();

  private ClassRoom _scriptclass;
  private ClassRoom _class;
  private ConstantPool _pool;
  private Code _code;
  private Stack _classes = new Stack();
  private Stack _codes = new Stack();

  public Field _f_const;
  public Field _f_text;
  public Field _f_switch;


  public ByteCompiler(Smith smith, ModuleEnvelope envelope)
  {
    _smith = smith;
    _envelope = envelope;
    Zone zone = envelope.getAddress().getZone();
    _prefs = zone.getCompilerPreferences();
    _debug = zone.getDebug();
  }


  public String getClassname()
  {
    return _envelope.getClassname();
  }
 

  public Module getModule()
  {
    return _envelope.getModule();
  }
 

  public ClassRoom getModuleClass()
  {
    return _scriptclass;
  }


  public ClassRoom getClassRoom()
  {
    return _class;
  }


  public ConstantPool getPool()
  {
    return _pool;
  }


  public void pushClass(ClassRoom clazz)
  {
    if (_scriptclass == null) {
      _scriptclass = clazz;
    }
    _classes.push(clazz);
    _class = clazz;
    _pool = clazz.getPool();
  }


  public void popClass()
  {
    _classes.pop();
    if (!_classes.isEmpty()) {
      _class = (ClassRoom)_classes.peek();
      _pool = _class.getPool();
    } else {
      _class = null;
      _pool = null;
    }
  }

  public Method getMethod()
  {
    return getCode().getMethod();
  }



  public Code getCode()
  {
    return _code;
  }


  public void pushCode(Code code)
  {
    _codes.push(code);
    _code = code;
  }


  public void popCode()
  {
    _codes.pop();
    if (!_codes.isEmpty()) {
      _code = (Code)_codes.peek();
    }
  }



  private int addText(String text)
  {
    Integer slot = (Integer)_texts.get(text);
    if (slot != null) {
      return slot.intValue();
    } else {
      int ctr = _texts.size();
      _texts.put(text, new Integer(ctr));
      return ctr;
    }
  }
 

  public ByteCompiler text(Code code, String text, boolean newline)
  {
    if (text.length()>0) {
      code.aload_first();
      code.getstatic(code.getPool().addFieldRef(TYPE_MODULE, "_text", "[[B"));
      code.iconst(addText(text));
      code.aaload();
      code.invokevirtual(code.getPool().addMethodRef("anvil/script/Context",
        newline?"println":"print", "([B)V"));
    }
    return this;
  }



  public ByteCompiler symbol(String name)
  {
    return symbol(Register.register(name));
  }
 

  public ByteCompiler symbol(int index)
  {
    Code code = getCode();
    String name = Register.getNameOf(index);
    code.getstatic(getPool().addFieldRef(TYPE_MODULE, "r_"+name, "I"));
    _symbols.put(new Integer(index), name);
    return this;
  }
 


  private int addConstant(Any value)
  {
    Integer slot = (Integer)_constants.get(value);
    if (slot != null) {
      return slot.intValue();
    } else {
      int ctr = _constants.size();
      _constants.put(value, new Integer(ctr));
      return ctr;
    }
  }


  public ByteCompiler constant(Any value, boolean canchange)
  {
    Code code = getCode();
    int slot = addConstant(value);
    code.getstatic(code.getPool().addFieldRef(TYPE_MODULE, "_const", "[Lanvil/core/Any;"));
    code.iconst(slot);
    code.aaload();
    if (canchange && value.isMutable()) {
      code.invokevirtual(getPool().addMethodRef("anvil/core/Any", "copy", "()Lanvil/core/Any;"));
    }
    return this;
  }
 

  public int addSwitch(Enumeration keys)
  {
    _switches.addElement(keys);
    return _switches.size() - 1;
  }


  public ByteCompiler reflect(String classname)
  {
    Integer slot = (Integer)_reflections.get(classname);
    if (slot == null) {
      slot = new Integer(_reflections.size());
      _reflections.put(classname, slot);
    }
    Code code = getCode();
    ConstantPool pool = getPool();
    int javafield = pool.addFieldRef(TYPE_MODULE, "java$"+slot,
      "Lanvil/core/reflect/Reflection;");
    int contextclass = pool.addClass(TYPE_CONTEXT);
    code.getstatic(javafield);
    Source isnull = code.if_null();
    code.getstatic(javafield);
    Source notnull = code.go_to();
    isnull.bind();
    code.aload_first();
    code.astring(classname);
    code.invokevirtual(pool.addMethodRef(contextclass, "reflect", "(Ljava/lang/String;)Lanvil/core/reflect/Reflection;"));
    code.dup();
    code.putstatic(javafield);
    notnull.bind();
    code.popop();
    return this;
  }
 

  public ByteCompiler location(Location location)
  {
    if (_debug && location != null) {
      Code code = getCode();
      Method method = code.getMethod();
      if (method.getClassRoom().getStatic() != method) {
        code.aload_first();
        code.iconst(location.getLine());
        code.invokevirtual(getPool().addMethodRef("anvil/script/StackFrameStack",
          "setLine", "(I)V"));
      }
    }
    return this;
  }

 
  public boolean compile()
  {
    Code code;
   
    String classname = _envelope.getClassname();
    Address address = _envelope.getAddress();
    String pathinfo = address.getPathinfo();
    String classsig = _envelope.getDescriptor();
    TYPE_MODULE = classsig;
   
    ClassRoom clazz = new ClassRoom();
    pushClass(clazz);
    clazz.setClassname(classsig, null);
    clazz.setSuperClassname("anvil/script/compiler/CompiledModule");
    clazz.setAccessFlags(ACC_SUPER|ACC_PUBLIC);
    ConstantPool pool = clazz.getPool();

    _f_const = clazz.createField("_const", "[Lanvil/core/Any;", ACC_PUBLIC|ACC_STATIC|ACC_FINAL);
    _f_text = clazz.createField("_text", "[[B", ACC_PUBLIC|ACC_STATIC|ACC_FINAL);
    _f_switch = clazz.createField("_switch", "[Lanvil/java/util/Hashlist;", ACC_PUBLIC|ACC_STATIC|ACC_FINAL);

    Method _m_const = clazz.createMethod("_const", "()V", ACC_PUBLIC|ACC_STATIC);
    Method _m_text = clazz.createMethod("_text", "()V", ACC_PUBLIC|ACC_STATIC);
    Method _m_switch = clazz.createMethod("_switch", "()V", ACC_PUBLIC|ACC_STATIC);
    Method _m_symbols = clazz.createMethod("_symbols", "()V", ACC_PUBLIC|ACC_STATIC);
    //Method _m_imports = clazz.createMethod("_imports", "()V", ACC_PUBLIC|ACC_STATIC);
   
    code = clazz.getStatic().getCode();
    //code.println("MODULE-START:"+classsig);
    code.invokestatic(_m_const.getIndex());
    code.invokestatic(_m_text.getIndex());
    code.invokestatic(_m_switch.getIndex());
    code.invokestatic(_m_symbols.getIndex());
    ((anvil.script.statements.ModuleStatement)getModule()).compile(this);
    //code.println("MODULE-END:"+classsig);
    code.vreturn();
   
    /* constants */
    code = _m_const.getCode();
    if (_constants.size() > 0) {
      code.iconst(_constants.size());
      code.anewarray(TYPE_ANY);
      Enumeration e = _constants.keys();
      for(int i=0; e.hasMoreElements(); i++) {
        code.dup();
        code.iconst(i);
        ((Any)e.nextElement()).toCode(code);
        code.aastore();
      }
      code.putstatic(_f_const);
    }
    code.vreturn();
   
    /* texts */
    code = _m_text.getCode();
    int getBytes = pool.addMethodRef("anvil/util/Conversions", "getBytes", "(Ljava/lang/String;)[B");
    if (_texts.size() > 0) {
      int size = _texts.size();
      code.iconst(size);
      code.anewarray("[[B", 1);
      Enumeration e = _texts.keys();
      for(int i=0; e.hasMoreElements(); i++) {
        code.dup();
        code.iconst(i);
        code.astring((String)e.nextElement());
        code.invokestatic(getBytes);
        code.aastore();
      }
      code.putstatic(_f_text);
    }
    code.vreturn();
   
    /* switchtables */
    code = _m_switch.getCode();
    int n = _switches.size();
    if (_switches.size() > 0 ) {
      int hashlistclazz = pool.addClass("anvil/java/util/Hashlist");
      int hashlistctor = pool.addMethodRef(hashlistclazz, "<init>", "()V");
      int hashlistadd = pool.addMethodRef(hashlistclazz, "add",
        "(Ljava/lang/Object;Ljava/lang/Object;)Lanvil/java/util/Hashlist;");
      int intclazz = pool.addClass("java/lang/Integer");
      int intclazzctor = pool.addMethodRef(intclazz, "<init>", "(I)V");
      code.iconst(n);
      code.anewarray(hashlistclazz);
      for(int i=0; i<n; i++) {
        code.dup();
        code.iconst(i);
        code.anew(hashlistclazz);
        code.dup();
        code.invokespecial(hashlistctor);
        int c = 0;
        Enumeration keys = (Enumeration)_switches.elementAt(i);
        while(keys.hasMoreElements()) {
          Any key = (Any)keys.nextElement();
          if (key != SwitchStatement.DEFAULT_MARKER) {
            key.toCode(code);
            code.anew(intclazz);
            code.dup();
            code.iconst(c++);
            code.invokespecial(intclazzctor);
            code.invokevirtual(hashlistadd);
          }
        }
        code.aastore();
      }
      code.putstatic(_f_switch);
    }
    code.vreturn();

    /* methodindices */
    code = _m_symbols.getCode();
    if (_symbols.size() > 0) {
      int register = pool.addMethodRef(pool.addClass("anvil/core/Register"),
        "register", "(Ljava/lang/String;)I");
      BindingEnumeration e = _symbols.keysAndElements();
      while(e.hasMoreElements()) {
        int index = ((Integer)e.nextKey()).intValue();
        String name = (String)e.nextElement();
        Field field = clazz.createField("r_"+name, "I", ACC_PUBLIC|ACC_STATIC|ACC_FINAL);
        code.astring(name);
        code.invokestatic(register);
        code.putstatic(field);
      }
    }
    code.vreturn();
   
    /* reflectionfields */
    if (_reflections.size() > 0) {
      BindingEnumeration e = _reflections.keysAndElements();
      while(e.hasMoreElements()) {
        int index = ((Integer)e.nextElement()).intValue();
        clazz.createField("java$"+index, "Lanvil/core/reflect/Reflection;", ACC_PUBLIC|ACC_STATIC);
      }
    }   
   
   
    popClass();

    try {
      clazz.write(_smith);
      return true;
    } catch (IOException e) {
      e.printStackTrace();
      return false;
    }
  }
 

  public void compileArgumentList(CompilableFunction function, Node[] parameters)
  {
    compileArgumentList(function, parameters, -1);
  }
 

  public void compileArgumentList(CompilableFunction function, Node[] parameters, int contextindex)
  {
    Code code = getCode();
    ConstantPool pool = getPool();
    int max = (parameters != null) ? parameters.length : 0;
    int c = 0;
    int n = function.getParameterCount();
    for(int i=0; i<n; i++) {
      Any defaultValue = function.getParameterDefault(i);
      switch(function.getParameterType(i)) {
      case CompilableFunction.PARAMETER_ANY:
        if (c<max) {
          parameters[c++].compile(this, Node.GET);
        } else {
          if (defaultValue != null) {
            constant(defaultValue, true);
          } else {
            code.aconst_null();
          }
        }
        break;

      case CompilableFunction.PARAMETER_OBJECT:
        if (c<max) {
          parameters[c++].compile(this, Node.GET);
          code.invokevirtual(pool.addMethodRef(TYPE_ANY,
            "toObject", "()Ljava/lang/Object;"));
        } else {
          if (defaultValue != null) {
            constant(defaultValue, true);
            code.invokevirtual(pool.addMethodRef(TYPE_ANY,
              "toObject", "()Ljava/lang/Object;"));
          } else {
            code.aconst_null();
          }
        }
        break;

      case CompilableFunction.PARAMETER_BOOLEAN:
        if (c<max) {
          Node node = parameters[c++];
          if (node.isConstant()) {
            code.iconst(node.eval().toBoolean());
          } else {
            node.compile(this, Node.GET_BOOLEAN);
          }
        } else {
          if (defaultValue != null) {
            code.iconst(defaultValue.toBoolean());
          } else {
            code.iconst(false);
          }
        }
        break;

      case CompilableFunction.PARAMETER_INT:
        if (c<max) {
          Node node = parameters[c++];
          if (node.isConstant()) {
            code.iconst(node.eval().toInt());
          } else {
            node.compile(this, Node.GET);
            code.invokevirtual(pool.addMethodRef(TYPE_ANY,
              "toInt", "()I"));           
          }
        } else {
          if (defaultValue != null) {
            code.iconst(defaultValue.toInt());
          } else {
            code.iconst(0);
          }
        }
        break;

      case CompilableFunction.PARAMETER_LONG:
        if (c<max) {
          Node node = parameters[c++];
          if (node.isConstant()) {
            code.lconst(node.eval().toLong());
          } else {
            node.compile(this, Node.GET);
            code.invokevirtual(pool.addMethodRef(TYPE_ANY,
              "toLong", "()J"))
          }
        } else {
          if (defaultValue != null) {
            code.lconst(defaultValue.toLong());
          } else {
            code.lconst(0);
          }
        }
        break;

      case CompilableFunction.PARAMETER_DOUBLE:
        if (c<max) {
          Node node = parameters[c++];
          if (node.isConstant()) {
            code.dconst(node.eval().toDouble());
          } else {
            node.compile(this, Node.GET);
            code.invokevirtual(pool.addMethodRef(TYPE_ANY,
              "toDouble", "()D"));
          }
        } else {
          if (defaultValue != null) {
            code.dconst(defaultValue.toDouble());
          } else {
            code.dconst(0.0);
          }
        }
        break;

      case CompilableFunction.PARAMETER_STRING:
        if (c<max) {
          Node node = parameters[c++];
          if (node.isConstant()) {
            code.astring(node.eval().toString());
          } else {
            node.compile(this, Node.GET);
            code.invokevirtual(pool.addMethodRef(TYPE_OBJECT,
              "toString", "()Ljava/lang/String;"));
          }
        } else {
          if (defaultValue != null) {
            code.astring(defaultValue.toString());
          } else {
            code.aconst_null();
          }
        }
        break;

      case CompilableFunction.PARAMETER_ARRAY:
        {
          int arrayclazz = pool.addClass("anvil/core/Array");
          int appendmethod = pool.addMethodRef(arrayclazz, "append",
            "(Lanvil/core/Any;)Lanvil/core/Array;");
          code.anew(arrayclazz);
          code.dup();
          code.invokespecial(pool.addMethodRef(arrayclazz, "<init>", "()V"));
          for(; c < max; c++) {
            code.dup();
            parameters[c].compile(this, Node.GET);
            code.invokevirtual(appendmethod);
          }
        }
        break;

      case CompilableFunction.PARAMETER_ANYLIST:
      case CompilableFunction.PARAMETER_REST:
        if (c >= max) {
          code.getstatic(pool.addFieldRef(TYPE_ANY, "EMPTY_TUPLE",
            "Lanvil/core/AnyTuple;"));
        } else {
          int tupleclazz = pool.addClass("anvil/core/AnyTuple");
          int appendmethod = pool.addMethodRef(tupleclazz, "append",
            "(Lanvil/core/Any;)Lanvil/core/Array;");
          code.anew(tupleclazz);
          code.dup();
          code.iconst(max - c);
          code.anewarray(TYPE_ANY);
          int index = 0;
          for(; c < max; c++) {
            code.dup();
            code.iconst(index++);
            parameters[c].compile(this, Node.GET);
            code.aastore();
          }
          code.invokespecial(pool.addMethodRef(tupleclazz, "<init>",
            "([Lanvil/core/Any;)V"));
        }
        break;

      case CompilableFunction.PARAMETER_LIST:
        int len = max - c;
        if (len <= 0) {
          code.getstatic(pool.addFieldRef(TYPE_ANY, "ARRAY0",
            "[Lanvil/core/Any;"));
        } else {
          code.iconst(len);
          code.anewarray(TYPE_ANY);
          int index = 0;
          for(; c < max; c++) {
            code.dup();
            code.iconst(index++);
            parameters[c].compile(this, Node.GET);
            code.aastore();
          }
        }
        break;

      case CompilableFunction.PARAMETER_CONTEXT:
        if (contextindex == -1) {
          code.aload_first();
        } else {
          code.aload(contextindex);
        }
        break;
      }
    }
  }

 
  public void compileArgumentList(Node[] parameters)
  {
    Code code = getCode();
    ConstantPool pool = getPool();
   
    int n = (parameters != null) ? parameters.length : 0;
    if (n == 0) {
      code.getstatic(pool.addFieldRef(TYPE_ANY, "ARRAY0",
        "[Lanvil/core/Any;"));
      return;
    }

    boolean hasSplices = false;
    for(int i=0; i<n; i++) {
      if (parameters[i].typeOf() == Node.EXPR_SPLICE) {
        hasSplices = true;
        break;
      }
    }

    if (hasSplices) {
      int clazz = pool.addClass("anvil/script/ParameterList");
      int splicemethod = pool.addMethodRef(clazz, "splice",
        "(Lanvil/core/Any;)Lanvil/script/ParameterList;");
      int addmethod = pool.addMethodRef(clazz, "add",
        "(Lanvil/core/Any;)Lanvil/script/ParameterList;");
      code.anew(clazz);
      code.dup();
      code.iconst(n);
      code.invokespecial(pool.addMethodRef(clazz, "<init>", "(I)V"));
      for(int i=0; i<n; i++) {
        parameters[i].compile(this, Node.GET);
        if (parameters[i].typeOf() == Node.EXPR_SPLICE) {
          code.invokevirtual(splicemethod);
        } else {
          code.invokevirtual(addmethod);
        }
      }
      code.invokevirtual(pool.addMethodRef(clazz, "toArray",
        "()[Lanvil/core/Any;"));
    } else {
      code.iconst(n);
      code.anewarray(TYPE_ANY);
      for(int i=0; i<n; i++) {
        code.dup();
        code.iconst(i);
        parameters[i].compile(this, Node.GET);
        code.aastore();
      }
    }
  } 


  public void compileCall(CompilableFunction function, Node[] parameters)
  {
    compileArgumentList(function, parameters);
    getCode().invokestatic(function.getTypeRef(getPool()));
  }



  public static String getSignature(CompilableFunction function)
  {
    StringBuffer sig = new StringBuffer();
    int n = function.getParameterCount();
    sig.append('(');
    for(int i=0; i<n; i++) {
      sig.append(CompilableFunction.SIGNATURES[function.getParameterType(i)]);
    }
    sig.append(')');
    sig.append(CompilableFunction.SIGNATURES[CompilableFunction.PARAMETER_ANY]);
    return sig.toString();
  }


  public void any2boolean()
  {
    Code code = getCode();
    code.invokevirtual(code.getPool().addMethodRef("anvil/core/Any", "toBoolean", "()Z"));
  }


  public void boolean2any()
  {
    Code code = getCode();
    code.invokestatic(code.getPool().addMethodRef(
      "anvil/script/compiler/CompiledModule", "b2a", "(Z)Lanvil/core/Any;"));
  }


  public void accessInstance(ClassType context, ClassType target)
  {
    Code code = getCode();
    if (context == null || context == target) {
      code.self();
      return;
    }
    ConstantPool pool = code.getPool();
    ClassType[] parents = context.getEnclosingClasses();
    int n = parents.length;
    for(int i=0; i<n; i++) {
      ClassType parent = parents[i];
      if (parent == target) {
        code.self();
        code.getfield(pool.addFieldRef(context.getTypeRef(pool), "this$"+i,
          'L'+parent.getDescriptor()+';'));
        return;
      }
    }
    code.self();
  }


}
TOP

Related Classes of anvil.script.compiler.ByteCompiler

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.