Package jfun.yan.xml

Source Code of jfun.yan.xml.BodyCompiler$TagCompiler

package jfun.yan.xml;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;


import jfun.util.Misc;
import jfun.util.StringUtils;
import jfun.util.dict.Dict;
import jfun.yan.Binder;
import jfun.yan.Component;
import jfun.yan.ComponentBinder;
import jfun.yan.Components;
import jfun.yan.Creator;
import jfun.yan.DelegatingComponent;
import jfun.yan.Dependency;
import jfun.yan.Monad;
import jfun.yan.ParameterBinder;
import jfun.yan.PropertyBinder;
import jfun.yan.Verifiable;
import jfun.yan.lifecycle.DefaultLifecycleManager;
import jfun.yan.util.ReflectionUtil;
import jfun.yan.util.Utils;
import jfun.yan.util.deserializer.Deserializer;
import jfun.yan.util.resource.ResourceLoader;
import jfun.yan.xml.nut.Nut;
import jfun.yan.xml.nut.NutDescriptor;

/**
* This class is responsible for setting up references between
* tags.
* local tag and sequence tag need special treatment.
* <p>
* @author Ben Yu
*
*/
class BodyCompiler extends Constants
implements NutEnvironment, Converter, java.io.Serializable{
 
  private static final Set sys_attributes = MyUtil.getNameSet(
      new String[]{
          ID, VAR, SINGLETON, /*INITIALIZER, DISPOSER, STARTER, STOPPER,*/
          TYPE, AUTOWIRE, SYNCHRONIZED, EAGER_INSTANTIATED, EAGER_INSTANTIATED2
        }
  );
  //attributes allowed on <function>
  private static final Set fun_attributes = MyUtil.getNameSet(
      new String[]{
          ID, PARAMS, SYNCHRONIZED
      }
  );
  private static final Set callcc_attributes = MyUtil.getNameSet(
      new String[]{
          ID, VAR, SINGLETON, /*INITIALIZER, DISPOSER, STARTER, STOPPER,*/
          TYPE, SYNCHRONIZED, EXIT
        }
  );
  private static final Set bare_attributes = MyUtil.getNameSet(new String[]{
     ID, VAR
  });
  private final Map nut_descriptors;
  //private final ClassLoader cloader;
  //private final DefaultLifecycleManager manager;
  //private final File basedir;
  private final WiringMode defaults;
  //private final Map services;
  private final Interpreter interpreter;
  private final Set reserves;
  private final Object module_id;
  private final boolean default_eager_mode;
  //private final AutoWiringMap wirings;
 
  public ParameterBinder getParameterWiringMode(String mode_name, Location loc) {
    return MyUtil.autocast(MyUtil.getParamWiring(mode_name, getCustomWiringModes(),
        loc, defaults.getParameterWiring()),
        loc, this);
  }

  public PropertyBinder getPropertyWiringMode(String mode_name, Location loc) {
    return MyUtil.autocast(
        MyUtil.getPropWiring(mode_name, getCustomWiringModes(),
        loc, defaults.getPropertyWiring()),
        loc, this);
  }

  BodyCompiler(Interpreter interpreter, Object module_id,
      Map nut_descriptors, String list_separator, String map_separator,
      WiringMode defaults, //AutoWiringMap wirings,
      Set reserves, final boolean eager_default) {
    this.interpreter = interpreter;
    this.module_id = module_id;
    //this.cloader = cloader;
//    this.manager = manager;
    //this.basedir = base;
    this.nut_descriptors = nut_descriptors;
    this.list_separator = list_separator;
    this.map_separator = map_separator;
    this.defaults = defaults;
    //this.services = services;
    this.reserves = reserves;
    this.default_eager_mode = eager_default;
    //this.wirings = wirings;
  }
 
  public Statements compileStatements(
      final Tag thistag,
      final Dict initial_ctxt,
      final IdChecker idchecker,
      final String tagname,
      List nodes){
    //top level components use the global default singleton mode.
    final LocalScope scope = compileLocalScope(
        tagname, initial_ctxt, nodes, idchecker,
        defaults.getSingletonMode(), true);
    final Object[] keys = scope.getKeys();
    final Stmt[] stmts = scope.getDefinitions();
    return new Statements(keys, stmts);
  }
  private final String list_separator;
  private final String map_separator;
  private ConfigurationException raiseTypeMismatch(Class type, Object v, Location loc){
    throw new ConfigurationException(Misc.getTypeName(type)+" expected, while "
        +(v==null?"null":Misc.getTypeName(v.getClass()))
        +" encountered.", loc);  
  }
  private Object fromList(Class type, List ll, Location loc)
  throws IllegalAccessException, InstantiationException,
  InvocationTargetException{
    final int sz = ll.size();
    if(isListType(type)){
      final List result = Utils.createList(type, sz);
      result.addAll(ll);
      return result;
    }
    else if(Set.class.isAssignableFrom(type)){
      final Set result = Utils.createSet(type, sz);
      for(int i=0; i<sz; i++){
        final Object elem = ll.get(i);
        if(result.contains(elem)){
          throw new ConfigurationException("duplicate set element: "+elem, loc);
        }
        result.add(elem);
      }
      return result;
    }
    else if(type.isArray()){
      final Class etype = type.getComponentType();
      final Object result = Array.newInstance(etype, sz);
      for(int i=0; i<sz; i++){
        final Object elem = convert(etype, ll.get(i), loc);
        Array.set(result, i, elem);
      }
      return result;
    }
    return null;
  }
  private Object cast(Class type, Object obj, Location loc)
  throws IllegalAccessException, InstantiationException,
  InvocationTargetException{
    if(Component.class.equals(type)){
      return NutsUtils.asComponent(obj);
    }
    else if(obj instanceof ListLiteral){
      final Object result = fromList(type, (ListLiteral)obj, loc);
      if(result != null) return result;
    }
    else if(obj instanceof MapLiteral){
      final MapLiteral ml = (MapLiteral)obj;
      final int sz = ml.size();
      if(Map.class.isAssignableFrom(type)){
        final Map result = Utils.createMap(type, sz);
        final Object[] keys = ml.getKeys();
        for(int i=0; i<keys.length; i++){
          final Object key = keys[i];
          final Object val = ml.get(key);
          result.put(key, val);
        }
        return result;
      }
    }
    else if(type.isArray()){
      final Class elemtype = type.getComponentType();
      return MyUtil.toArray(elemtype, convert(elemtype, obj, loc));
    }
    else if(List.class.isAssignableFrom(type) || Collection.class.equals(type)){
      return MyUtil.toList(type, obj);
    }
    else if(Set.class.isAssignableFrom(type)){
      return MyUtil.toSet(type, obj);
    }
    throw raiseTypeMismatch(type, obj, loc);
  }
  public Component cast(final Class target_type, Component c,
      final Location loc){
    return MyUtil.cast(target_type, c, loc, this);
  }
  public Object convert(Class expected, Object obj, Location loc){
    if(expected==null) return obj;
    if(ReflectionUtil.isInstance(expected, obj)){
      return obj;
    }
    else if(String.class.equals(expected)){
      if(obj instanceof Literal){
        return ((Literal)obj).toText();
      }
      else return obj.toString();
    }
    else if(obj instanceof String){
      try{
        return convertLiteral(expected, (String)obj, loc);
      }
      catch(Throwable e){
        throw raise(e, loc);
      }
    }
    try{
      return cast(expected, obj, loc);
    }
    catch(Throwable e){
      throw raise(e, loc);
    }
  }
  private Object convertLiteral(Class type, String str, Location loc)
  throws Exception{
    if(type.isInstance(str)) return str;
    str = str.trim();
    if(isCompoundType(type)){
      final String[] subs = NutsUtils.split(str, list_separator);
      final List sublist = Utils.asList(subs);
      final Object result = fromList(type, sublist, loc);
      if(result != null) return result;
    }
    else if(Map.class.isAssignableFrom(type)){
      if(!(str.startsWith("{") && str.endsWith("}"))){
        throw new IllegalArgumentException("map literal has to be enclosed with {}");
      }
      str = str.substring(1, str.length()-1);
      final String[] entries = NutsUtils.split(str, map_separator);
      final Map map = jfun.yan.util.Utils.createMap(type, entries.length);
      for(int i=0; i<entries.length; i++){
        final String entry = entries[i];
        final int delimit = entry.indexOf('=');
        if(delimit<0){
          throw new IllegalArgumentException("'=' is required for each map entry.");
        }
        final String key = entry.substring(0, delimit).trim();
        if(map.containsKey(key)){
          throw new IllegalArgumentException("duplicate map key: "+key);
        }
        final String val = entry.substring(delimit+1, entry.length());
        map.put(key, val);
      }
      return map;
    }
    /*
    else if(Class.class.equals(type)){
      return MyUtil.getClass(getComponentClassLoader(), str);
    }
    else if(File.class.equals(type)){
      return NutsUtils.toFile(getBaseDir(), str);
    }
    else if(URL.class.equals(type)){
      return NutsUtils.toUrl(getBaseDir(), str);
    }*/
    try{
      return deserialize(type, str);
    }
    catch(Throwable e){
      throw raise("failed to convert string to "+Misc.getTypeName(type), e, loc);
    }
  }

  private String getIdAttribute(Tag tag){
    return getWord(tag, ID);
  }
  private String getVarAttribute(Tag tag){
    return getWord(tag, VAR);
  }
  private void checkWord(String word, String kind, Location loc){
    if(word!=null && !NutsUtils.isValidId(word)){
      throw new ConfigurationException("invalid "+kind, loc);
    }
    if(reserves.contains(word)){
      throw new ConfigurationException(kind+" "+word+" is a reserved word.",
          loc);
    }
  }
  private String getWord(Tag tag, String kind){
    final String word = tag.getAttribute(kind);
    checkWord(word, kind, tag.getLocation());
    return word;
   
  }
  private String getMandatoryVar(Tag tag){
    final String var = getVarAttribute(tag);
    if(var==null)
      throw new ConfigurationException("missing mandatory "+VAR,
          tag.getLocation());
    return var;
  }
  private static Dict declareName(Dict ctxt, String name, Location loc){
    return ctxt.put(name, new Bound(name, loc));
  }
  static class CurrentLocation extends ThreadLocal{
    public Location getLocation(){
      return (Location)this.get();
    }
    public void setLocation(Location loc){
      this.set(loc);
    }
  }
  static CurrentLocation current_location = new CurrentLocation();
  private final class TagCompiler{
    private final int ind;
    private final Dict ctxt;
    private final Tag tag;
    private final SingletonMode singleton_mode;
    private final boolean var_permitted;
    private final boolean is_global;
    TagCompiler(int ind, Dict ctxt, Tag tag,
        SingletonMode singleton_mode, boolean var_permitted,
        boolean is_global) {
      this.ind = ind;
      this.ctxt = ctxt;
      this.tag = tag;
      this.singleton_mode = singleton_mode;
      this.var_permitted = var_permitted;
      this.is_global = is_global;
    }
    public Location getLocation(){
      return tag.getLocation();
    }
    public String getName(){
      return tag.getName();
    }
    private String getErrorMessage(String tagname, String msg){
      return "<"+tagname+"> - "+msg;
    }
    private ConfigurationException raise(String msg){
      throw new ConfigurationException(getErrorMessage(getName(), msg), tag.getLocation());
    }
   
    private ConfigurationException raise(Throwable e){
      if(e instanceof ConfigurationException){
        throw (ConfigurationException)e;
      }
      else if(e instanceof InvocationTargetException){
        return raise(((InvocationTargetException)e).getTargetException());
      }
      throw new ConfigurationException(getErrorMessage(getName(), e.getMessage()), e, tag.getLocation());
    }
    private ConfigurationException raise(Throwable e, Location loc){
      return BodyCompiler.raise(e, loc);
    }
    public String getAttribute(String name){
      return tag.getAttribute(name);
    }
    private void assertAttributes(Set table){
      MyUtil.assertAttributes(tag, table);
    }
    private Dict declareNames(Dict ctxt, String[] names){
      final Stmt[] stmts = new Stmt[names.length];
      final Set cache = new HashSet(names.length);
      for(int i=0; i<names.length; i++){
        final String name = names[i];
        if(cache.contains(name)){
          throw raise("duplicate parameter name: "+name);
        }
        cache.add(name);
        checkWord(name, "parameter name", getLocation());
        stmts[i] = new Bound(names[i], getLocation());
      }
      return ctxt.puts(names, stmts);
    }
    private Stmt compile(){
      current_location.setLocation(getLocation());
      final List subnodes = tag.getSubNodes();
      Dict ctxt = this.ctxt;
      if(BINDER.equals(tag.getName())){
        final String varname = getMandatoryVar(this.tag);
        ctxt = declareName(ctxt, varname, getLocation());
      }
      else if(FUNCTION.equals(tag.getName())){
        final String paramnames = MyUtil.getMandatory(tag, PARAMS)
          .trim();
        final String[] params = NutsUtils.split(paramnames, list_separator);
        /*if(params.length==0){
          throw raise("at least one parameter needs to be specified.");
        }*/
        ctxt = declareNames(ctxt, params);
      }
      if(subnodes.isEmpty()){
        return compileMe(ctxt, subnodes);
      }
      else{
        final Node node = (Node)subnodes.get(0);
        if(node instanceof Tag){
          final Tag t = (Tag)node;
          if(LOCAL.equals(t.getName())){
            final LocalScope scope = compileLocalScope(ctxt, t);
            return withScope(scope, compileMe(scope.getScope(),
                subnodes.subList(1, subnodes.size())), getLocation());
          }
        }
        return compileMe(ctxt, subnodes);
      }
    }
   
    private Stmt wrapStmt(final Dict local_ctxt, final Stmt stmt){
      //final String typename = getAttribute(attrs, TYPE);
      final Stmt type = getTypeAttribute(local_ctxt);
      final Stmt wiring = getAutowireAttribute(local_ctxt, defaults.getParameterWiring());
      final Stmt singleton_mode = getSingletonAttribute(local_ctxt, this.singleton_mode);
      final Stmt sync_stmt = getSynchronizedAttribute(local_ctxt);
      final Stmt eager = is_global?getEagerInstantiationAttribute(local_ctxt):null;
      final String id = getAttribute(ID);
      final Location loc = stmt.getLocation();
      return new Stmt(){
        public String toString(){
          return stmt.toString();
        }
        public Object run(Dict frame, Runtime runtime){
          Object obj = stmt.run(frame, runtime);
          final Class casttype =
            type==null?null:(Class)type.run(frame, runtime);
          final ParameterBinder autowire =
            wiring==null?null:(ParameterBinder)wiring.run(frame, runtime);
          final SingletonMode singleton =
            singleton_mode==null?null:
              (SingletonMode)singleton_mode.run(frame, runtime);
          final boolean sync = sync_stmt==null?false:
            ((Boolean)sync_stmt.run(frame, runtime)).booleanValue();
          if(obj instanceof Creator){
            final Component result = MyUtil.wrapComponent(
                Components.adapt((Creator)obj), runtime, loc,
                casttype, singleton, autowire, sync, BodyCompiler.this);
            if(eager!=null){
              final boolean eagerly_instantiated =
                ((Boolean)eager.run(frame, runtime)).booleanValue();
              if(eagerly_instantiated){
                registerEagerInstantiation(ind, id, result);
              }
            }
            return result;
          }
          else{
            if(sync && obj instanceof NutsFunction){
              obj = new SynchronizedNutsFunction((NutsFunction)obj);
            }
            if(casttype != null){
              try{
                return convert(casttype, obj, loc);
              }
              catch(Throwable e){
                throw raise(e, loc);
              }
            }
            else return obj;
          }
        }
        public Location getLocation(){
          return loc;
        }
        public Class getType(){
          return stmt.getType();
        }
      };
    }

    private Stmt compileMe(Dict local_ctxt, List nodes){
      return wrapStmt(local_ctxt, compileTagBody(local_ctxt, nodes));
    }
    private Stmt compileTagBody(Dict local_ctxt, List nodes){
      final String name = tag.getName();
      //final Location loc = tag.getLocation();
      if(SEQUENCE.equals(name)){
        return compileSequence(local_ctxt, nodes);
      }
      else if(BINDER.equals(name)){
        return compileBinder(local_ctxt, nodes);
      }
      else if(FUNCTION.equals(name)){
        return compileFunction(local_ctxt, nodes);
      }
      else if(CALLCC.equals(name)){
        return compileCallcc(local_ctxt, nodes);
      }
      else{
        final NutDescriptor desc = (NutDescriptor)nut_descriptors.get(name);
        if(desc == null){
          throw raise("unknown nut");
        }
        return compileNut(name, desc, local_ctxt, nodes, false);
      }
    }
    private Stmt compileFunction(Dict ctxt, List nodes){
      assertAttributes(fun_attributes);
      final int sz = nodes.size();
      if(sz==0){
        throw raise("empty function not allowed.");
      }
      else if(sz>1){
        throw raise("only one sub-element is allowed.");
      }
      final String[] params = StringUtils.split(
          MyUtil.getMandatory(tag, PARAMS),
          list_separator);
      final String fname = getIdAttribute(tag);
      final String funname = fname==null?"\\":fname;
      //we do not call compileSequential because <function> is not a Component only tag.
      //like <value>, it returns anything.
      final Stmt body = //compileSequential(ctxt, nodes);
        compileNode(0, ctxt, (Node)nodes.get(0), false);
      final Location loc = getLocation();
      return new Stmt(){
        public Class getType() {
          return NutsFunction.class;
        }
        public Object run(final Dict frame, final Runtime runtime) {
          return new NutsFunction(){
            public Class getReturnType(){
              return body.getType();
            }
            public Object call(Object[] args) {
              return body.run(frame.puts(params, args), runtime);
            }
            public String getName() {
              return funname+StringUtils.listArray("(",",",")",params);
            }
            public int getParameterCount() {
              return params.length;
            }
            public String[] getParameterNames(){
              return (String[])params.clone();
            }
            public Location getLocation() {
              return loc;
            }
            public String toString() {
              return funname;
            }
          };
        }
        public Location getLocation() {
          return loc;
        }
        public String toString(){
          return funname+StringUtils.listArray("(",",",")",params);
        }
      };
    }
    private SideEffect property_setter(final PropertyDescriptor prop,
        final Stmt stmt){
      return dyn_method_invoker(prop.getWriteMethod(), prop.getPropertyType(), stmt);
    }
    private SideEffect literal_property_setter(final PropertyDescriptor prop,
        final String val){
      try{
        return method_invoker(prop.getWriteMethod(),
            prop.getPropertyType(), val, getLocation());
      }
      catch(Throwable e){
        throw raise(e);
      }
    }
    private SideEffect method_invoker(final Method mtd,
        final Class param_type, final String val, final Location loc){
      return new SideEffect(){
        public void apply(Object obj, Dict ctxt, Runtime runtime){
          try{
            mtd.invoke(obj, new Object[]{convertLiteral(param_type, val, loc)});
          }
          catch(Throwable e){
            throw raise(e);
          }
        }
        public String toString(){
          return mtd.getName()+"("+val+")";
        }
      };
    }
    private Stmt compileNut(final String nutname,final NutDescriptor desc,
        boolean is_subnut){
      final List subnodes = tag.getSubNodes();
      if(subnodes.isEmpty()){
        return compileNut(nutname, desc, ctxt, subnodes, is_subnut);
      }
      else{
        final Node node = (Node)subnodes.get(0);
        if(node instanceof Tag){
          final Tag t = (Tag)node;
          if(LOCAL.equals(t.getName())){
            final LocalScope scope = compileLocalScope(ctxt, t);
            final Dict nctxt = scope.getScope();
            return withScope(scope, compileNut(nutname, desc, nctxt,
                subnodes.subList(1, subnodes.size()), is_subnut), getLocation());
          }
        }
        return compileNut(nutname, desc, ctxt, subnodes, is_subnut);
      }
    }
    /**
     * To convert a literal directly to a target type.
     * @param expected_type the expected type.
     * @param local_ctxt the current context.
     * @param literal the literal.
     * @return the target object.
     */
    private Stmt compileLiteralValue(Class expected_type,
    Dict local_ctxt, String literal){
      if(literal==null) return null;
      if(MyUtil.isRefName(literal)){
        final Stmt stmt = compileRefSymbol(literal, local_ctxt);
        return cast(expected_type, stmt);
      }
      else{
        final Location loc = getLocation();
        final Object literal_val = StringInterpolator.interpolate(literal, local_ctxt, loc);
        if(literal_val instanceof Stmt){
          return cast(expected_type, (Stmt)literal_val);
        }
        else return MyUtil.typedValue(expected_type, literal_val, loc, BodyCompiler.this);
      }
    }
   
    /**
     * To convert a literal to a string (when it is a ref) and convert it using a
     * FromLiteral object.
     * @param type the final target type.
     * @param literal the literal.
     * @param fl the FromLiteral object.
     * @param local_ctxt the current context.
     * @param loc the location
     * @return the Stmt object.
     */
    private Stmt compileLiteralString(final Class type, String literal,
        final FromLiteral fl,
        Dict local_ctxt, final Location loc){
      if(MyUtil.isRefName(literal)){
        final Stmt stmt = compileRefSymbol(literal, local_ctxt);
        return transformLiteralString(fl, type, stmt, loc);
      }
      else{
        final Object literal_val = StringInterpolator.interpolate(literal, local_ctxt, loc);
        if(literal_val instanceof Stmt){
          return transformLiteralString(fl, type, (Stmt)literal_val, loc);
        }
        else{
          return MyUtil.value(fl.fromLiteral(literal_val.toString()), loc);
        }
      }
    }
    private Stmt transformLiteralString(final FromLiteral fl,
        final Class type,
        final Stmt stmt, final Location loc){
      return new Stmt(){
        public Class getType() {
          return type;
        }
        public Object run(Dict frame, Runtime runtime) {
          final String val = (String)convert(String.class,
              stmt.run(frame, runtime), loc);
          return fl.fromLiteral(val);
        }
        public Location getLocation() {
          return loc;
        }
        public String toString() {
          return stmt.toString();
        }
      };
    }
    private Stmt compileAttributeValue(Class expected_type,
        Dict local_ctxt, String name){
      final String literal = getAttribute(name);
      return compileLiteralValue(expected_type, local_ctxt, literal);
    }
    private Stmt getBooleanAttribute(Dict local_ctxt, String name, boolean def){
      final Stmt result = compileAttributeValue(boolean.class,
          local_ctxt, name);
      if(result==null){
        return MyUtil.value(Boolean.valueOf(def), getLocation());
      }
      else return result;
    }
    private Stmt getSynchronizedAttribute(Dict local_ctxt){
      return getBooleanAttribute(local_ctxt, SYNCHRONIZED, false);
    }
    private Stmt getEagerInstantiationAttribute(Dict local_ctxt){
      Stmt result = compileLiteralValue(boolean.class, local_ctxt,
          MyUtil.getEagerMode(tag));
      if(result==null){
        return MyUtil.value(Boolean.valueOf(default_eager_mode), getLocation());
      }
      else return result;   
    }
    private Stmt getTypeAttribute(Dict local_ctxt){
      final String literal = getAttribute(TYPE);
      if(literal==null) return null;
      final Location loc = getLocation();
      final FromLiteral fl = new FromLiteral(){
        public Object fromLiteral(String text){
          try{
            return MyUtil.getClass(getComponentClassLoader(), text);
          }
          catch(ClassNotFoundException e){
            throw new ConfigurationException(
                getErrorMessage(tag.getName(),
                "class "+text+" not found."), e,
                loc);
          }
        }
      };
      return compileLiteralString(Class.class, literal, fl, local_ctxt, loc);
      /*
      if(MyUtil.isRefName(literal)){
        final Stmt stmt = compileRefSymbol(literal, local_ctxt);
        return cast(Class.class, stmt);
      }
      else{
        try{
          return MyUtil.value(MyUtil.getClass(getComponentClassLoader(), literal),
              getLocation());
        }
        catch(ClassNotFoundException e){
          throw new ConfigurationException(
              getErrorMessage(tag.getName(),
              "class "+literal+" not found."), e,
              getLocation());
        }
      }*/
    }
    private Stmt getAutowireAttribute(Dict local_ctxt, final ParameterBinder def){
      final String literal = getAttribute(AUTOWIRE);
      final Location loc = getLocation();
      if(literal==null) return MyUtil.value(def, loc);
      final FromLiteral fl = new FromLiteral(){
        public Object fromLiteral(String autowire){
          return MyUtil.getParamWiring(autowire,
              getCustomWiringModes(), loc, def);
        }
      };
      return compileLiteralString(ParameterBinder.class, literal, fl, local_ctxt, loc);
      /*
      if(MyUtil.isRefName(literal)){
        final Stmt stmt = compileRefSymbol(literal, local_ctxt);
        return new Stmt(){
          public Class getType() {
            return ParameterBinder.class;
          }
          public Object run(Dict frame, Runtime runtime) {
            final String autowire = (String)convert(String.class,
                stmt.run(frame, runtime), loc);
            return MyUtil.getParamWiring(autowire,
                getCustomWiringModes(), loc, def);
          }
          public Location getLocation() {
            return loc;
          }
          public String toString() {
            return stmt.toString();
          }
        };
      }
      else{
        return MyUtil.value(MyUtil.getParamWiring(literal,
            getCustomWiringModes(), loc, def), loc);
      }*/
    }
    private Stmt getSingletonAttribute(Dict local_ctxt, final SingletonMode def){
      final String literal = getAttribute(SINGLETON);
      final Location loc = getLocation();
      if(literal==null)
        return MyUtil.value(def, loc);
      final FromLiteral fl = new FromLiteral(){
        public Object fromLiteral(String singleton){
          return MyUtil.getSingletonStrategy(singleton, loc, def);
        }
      };
      return compileLiteralString(ComponentDecorator.class, literal, fl, local_ctxt, loc);
      /*
      if(literal==null) return MyUtil.value(def, loc);
      if(MyUtil.isRefName(literal)){
        final Stmt stmt = compileRefSymbol(literal, local_ctxt);
        return new Stmt(){
          public Class getType() {
            return ComponentDecorator.class;
          }
          public Object run(Dict frame, Runtime runtime) {
            final String singleton = (String)convert(String.class,
                stmt.run(frame, runtime), loc);
            return MyUtil.getSingletonStrategy(singleton, loc, def);
          }
          public Location getLocation() {
            return loc;
          }
          public String toString() {
            return stmt.toString();
          }
        };
      }
      else{
        return MyUtil.value(MyUtil.getSingletonStrategy(literal, loc, def), loc);
      }*/
    }
   
   

   
    private Stmt compileRefSymbol(String refname, Dict local_ctxt){
      return compileRef(refname.substring(1), local_ctxt);
    }
    private Stmt compileRef(String refname, Dict local_ctxt){
      if(!NutsUtils.isValidId(refname)){
        throw raise("invalid identifier: "+refname);
      }
      if(!local_ctxt.containsKey(refname)){
        throw raise("reference not recognized: "+refname);
      }
      return new Bound(refname, getLocation());
    }
   
    private Stmt compileLiteral(String val, Dict local_ctxt){
      if(MyUtil.isRefName(val)){
        //a reference.`
        return compileRefSymbol(val, local_ctxt);
      }
      else{
        final Location loc = getLocation();
        return asStmt(StringInterpolator.interpolate(val, local_ctxt, loc), loc);
        //MyUtil.value(val, getLocation());
      }
    }
    private Object compileRefLiteral(final Class type, String val, Dict local_ctxt){
      if(MyUtil.isRefName(val)){
        //a reference.`
        return compileRefSymbol(val, local_ctxt);
      }
      else if(isRefType(type)){
        //we expect Component, but a string is passed in,
        //this is very probably that the string is a ref name.
        return compileRef(val, local_ctxt);
      }
      else return StringInterpolator.interpolate(val, local_ctxt, getLocation());
        //return null;
    }
    private Stmt compileLiteral(final Class type, String val, Dict local_ctxt){
      return asStmt(compileRefLiteral(type, val, local_ctxt), getLocation());
      /*
      final Stmt ret = compileRefLiteral(type, val, local_ctxt);
      if(ret==null)
        return MyUtil.value(val, getLocation());
      else return ret;*/
    }
    public Entry[] compileMapEntries(String str, Dict local_ctxt){
      str = str.trim();
      final String[] entry_strs = NutsUtils.split(str, map_separator);
      final ArrayList entries = new ArrayList(entry_strs.length);
      for(int i=0; i<entry_strs.length; i++){
        entries.add(compileMapEntry(entry_strs[i], local_ctxt));
      }
      final Entry[] result = new Entry[entries.size()];
      entries.toArray(result);
      return result;
    }
    private Entry compileMapEntry(String str, Dict local_ctxt){
      final int delimit = str.indexOf('=');
      if(delimit<0){
        throw raise("'=' is missing in a map entry.");
      }
      final String key_str = str.substring(0, delimit).trim();
      final String val_str = str.substring(delimit+1, str.length()).trim();
      final Stmt key = compileLiteral(key_str, local_ctxt);
      final Stmt val = compileLiteral(val_str, local_ctxt);
      return new Entry(key, val);
    }
    private Stmt[] compileParts(String[] parts, Class type, Dict local_ctxt){
      final Stmt[] result = new Stmt[parts.length];
      for(int i=0; i<result.length; i++){
        result[i] = compileLiteral(type, parts[i], local_ctxt);
      }
      return result;
    }
    private Stmt[] compileParts(String[] parts, Dict local_ctxt){
      final Stmt[] result = new Stmt[parts.length];
      for(int i=0; i<result.length; i++){
        result[i] = compileLiteral(parts[i], local_ctxt);
      }
      return result;
    }
    private Stmt compileListLiteral(final String val, Dict local_ctxt){
      final String[] parts = NutsUtils.split(val, list_separator);
      final Location loc = getLocation();
      final Stmt[] stmts = compileParts(parts, local_ctxt);
      return new LiteralStmt(ArrayList.class, val, loc){
       public Object run(Dict frame, Runtime runtime) {
         final ListLiteral ll = new ListLiteral(stmts.length);
         for(int i=0; i<stmts.length; i++){
           final Stmt stmt = stmts[i];
           ll.add(stmt.run(frame, runtime));
         }
         return ll;
       }
      };
    }
    private Stmt compileMapLiteral(final String val, Dict local_ctxt){
      final Entry[] entries = compileMapEntries(val, local_ctxt);
      final Location loc = getLocation();
      return new LiteralStmt(ArrayList.class, val, loc){
        public Object run(Dict frame, Runtime runtime) {
          final MapLiteral ml = new MapLiteral(entries.length);
          for(int i=0; i<entries.length; i++){
            final Entry entry = entries[i];
            final Object key = ((Stmt)entry.getKey()).run(frame, runtime);
            final Object val = ((Stmt)entry.getVal()).run(frame, runtime);
            ml.build(key, val);
          }
          return ml;
        }
       };
    }
    private Stmt compileCompound(final String val, final Class type,
        Dict local_ctxt){
     final String[] parts = NutsUtils.split(val, list_separator);
     final Location loc = getLocation();
     if(type.isArray()){
       final Class etype = type.getComponentType();
       final Stmt[] stmts = compileParts(parts, type,
           local_ctxt);
       return new LiteralStmt(type, val, loc){
        public Object run(Dict frame, Runtime runtime) {
          final Object arr = Array.newInstance(etype, stmts.length);
          for(int i=0; i<stmts.length; i++){
            final Stmt stmt = stmts[i];
            Array.set(arr, i, convert(etype, stmt.run(frame, runtime), stmt.getLocation()));
          }
          return arr;
        }
       };
     }
     else if(isListType(type)){
       final Stmt[] stmts = compileParts(parts, local_ctxt);
       return new LiteralStmt(type, val, loc){
         public Object run(Dict frame, Runtime runtime) {
           try{
             final List list = jfun.yan.util.Utils
             .createList(type, stmts.length);
             for(int i=0; i<stmts.length; i++){
               list.add(stmts[i].run(frame, runtime));
             }
             return list;
           }
           catch(Throwable e){
             throw raise(e);
           }
         }
       };
     }
     else if(Set.class.isAssignableFrom(type)){
       final Stmt[] stmts = compileParts(parts, local_ctxt);
       return new LiteralStmt(type, val, loc){
         public Object run(Dict frame, Runtime runtime) {
           try{
             final Set set = jfun.yan.util.Utils
             .createSet(type, stmts.length);
             for(int i=0; i<stmts.length; i++){
               final Object obj = stmts[i].run(frame, runtime);
               if(set.contains(obj)){
                 throw raise("duplicate set element:"+obj);
               }
               set.add(obj);
             }
             return set;
           }
           catch(Throwable e){
             throw raise(e);
           }
         }
       };
     }
     else{
       throw raise("either list or array is expected, "+Misc.getTypeName(type)
           +" encountered");
     }
    }
    private Stmt compileMapLiteral(String val, Class type, Dict local_ctxt){
      final Entry[] entries = compileMapEntries(val, local_ctxt);
      return new LiteralStmt(type, val, getLocation()){
        public Object run(Dict frame, Runtime runtime) {
          try{
            final Map map = jfun.yan.util.Utils
            .createMap(type, entries.length);
            for(int i=0; i<entries.length; i++){
              final Entry entry = entries[i];
              final Object key = ((Stmt)entry.getKey())
                .run(frame, runtime);
              if(map.containsKey(key)){
                throw raise("duplicate map key:"+key);
              }
              final Object val = ((Stmt)entry.getVal())
                .run(frame, runtime);
              map.put(key, val);
            }
            return map;
          }
          catch(Throwable e){
            throw raise(e);
          }
        }
      };
    }
    private boolean isMapLiteral(String val){
      if(val.startsWith("{")){
        //map literal.
        if(!val.endsWith("}")){
          throw raise("map literal has to be ended by a '}'");
        }
        return true;
      }
      else
        return false;
    }
    private boolean isListLiteral(String val){
      return (val.indexOf(',')>=0 && val.indexOf('$')>=0);
    }
    private Stmt attemptMapLiteral(String val, Dict local_ctxt){
      val = val.trim();
      if(isMapLiteral(val)){
        //map literal.
        return compileMapLiteral(val.substring(1, val.length()-1), local_ctxt);
      }
      else return null;
    }
    private Stmt attemptListLiteral(String val, Dict local_ctxt){
      if(isListLiteral(val)){
        return compileListLiteral(val, local_ctxt);
      }
      else return null;
    }
    private Stmt attemptMap(Class type, String val, Dict local_ctxt){
      val = val.trim();
      if(isMapLiteral(val)){
        return compileMapLiteral(val.substring(1, val.length()-1), type, local_ctxt);
      }
      else return null;
    }
    private Stmt attemptCompound(Class type, String val, Dict local_ctxt){
      if(isListLiteral(val)){
        //we only care about list/array of length 2 or more.
        //for a ref string with no ',', we don't treat it as array/list.
        return compileCompound(val, type, local_ctxt);
      }
      else return null;
    }
    private SideEffect compileNutAttribute(String val,
        final PropertyDescriptor prop, Dict local_ctxt){
      final Class type = prop.getPropertyType();
      if(Map.class.isAssignableFrom(type)){
        final Stmt stmt = attemptMap(type, val, local_ctxt);
        if(stmt!=null)
          return property_setter(prop, stmt);

      }
      else if(isCompoundType(type)){
        final Stmt stmt = attemptCompound(type, val, local_ctxt);
        if(stmt!=null)
          return property_setter(prop, stmt);
      }
      else if(Object.class.equals(type)){
        //wild guess, populate a Literal.
        Stmt stmt = attemptMapLiteral(val, local_ctxt);
        if(stmt==null)
          stmt = attemptListLiteral(val, local_ctxt);
        if(stmt!=null)
          return property_setter(prop, stmt);
      }
      return compileTerm(type, val, prop, local_ctxt);
    }
    private SideEffect compileTerm(final Class type, String val, final PropertyDescriptor prop, Dict local_ctxt) {
      final Object result = compileRefLiteral(type, val, local_ctxt);
      if(result instanceof Stmt){
        return property_setter(prop, (Stmt)result);
      }
      else{
        return literal_property_setter(prop, (String)result);
      }
      /*
      final Object result = compileRefLiteral(type, val, local_ctxt);
      if(ref==null)
        return literal_property_setter(prop, val);
      else return property_setter(prop, ref);*/
    }
    Object returnSubNut(NutDescriptor desc, Object nut, Object result){
      if(result==null || !ReflectionUtil.isInstance(desc.getType(), result)){
        return nut;
      }
      else return result;
    }
    private Stmt getCollectionNut(final String nutname,
        final NutDescriptor desc, final ArrayList mutations,
        final Stmt[] args, final boolean is_subnut){
      final Class elem_type = desc.getSetterElementType();
      final Location loc = getLocation();
      return new Stmt(){
        public String toString(){
          return nutname;
        }
        public Object run(Dict frame, Runtime runtime){
          final Object nut = createNut(nutname,
              desc, mutations, frame, runtime);
          try{
            if(args.length!=0){
              final Object arr = Array.newInstance(elem_type, args.length);
              for(int i=0; i<args.length; i++){
                final Object elem = args[i].run(frame, runtime);
                final Object converted = convert(elem_type, elem, loc);
                try{
                  Array.set(arr, i, converted);
                }
                catch(IllegalArgumentException e){
                  raise("array element type mismatch: ["+i+"]");
                }
              }
              desc.getSetter().invoke(nut, new Object[]{arr});
            }
            final Object result = desc.getEvaluator().eval(nut);
            //for subnut, we always return the nut instance because that's what the enclosing tag is expecting.
            return is_subnut?returnSubNut(desc, nut, result):result;
          }
          catch(Throwable e){
            throw raise(e);
          }
        }
        public Class getType(){
          return is_subnut?desc.getType():desc.getEvaluator().getType();
        }
        public Location getLocation(){
          return loc;
        }
      };
    }
   
    private void populateAdders(final String nutname, final NutDescriptor desc,
      final List nodes, final List mutations, final Dict ctxt){
      final int sz = nodes.size();
      for(int i=0; i<sz; i++){
        final Node node = (Node)nodes.get(i);
        if(node instanceof CharacterData){
          final CharacterData literal = (CharacterData)node;
          populateLiteralAdder(nutname, desc, literal, mutations);
        }
        else{
          final Tag subtag = (Tag)node;
          populateSubnutAdder(i, desc, subtag, mutations, ctxt);
        }
      }
    }
    private void populateLiteralAdder(final String nutname, final NutDescriptor desc,
        CharacterData literal, List mutations){
      final Location subloc = literal.getLocation();
      /*
      final Method adder = desc.getAdder("");
      if(adder==null){
        if(literal.getText().trim().length()==0){
          //ignore whitespaces.
          return;
        }
        throw new ConfigurationException("literal disallowed within "+nutname, subloc);
      }*/
      if(literal.getText().trim().length()==0){
        //ignore whitespaces.
        return;
      }
      try{
        /*
        mutations.add(method_invoker(adder,
          convertLiteral(desc.getAdderType(""), literal.getText(),
              getLocation())));
        */
        mutations.add(anonymous_adder_invoker(desc,
            MyUtil.value(literal.getText(), literal.getLocation())));
      }
      catch(Throwable e){
        raise(e, subloc);
      }
    }
    private void populateSubnutAdder(int seq, final NutDescriptor desc,
        Tag subtag, List mutations, Dict ctxt){
      final String subname = subtag.getName();
      NutDescriptor subdesc = desc.getSubDescriptor(subname);
      if(subdesc!=null){
        final NutDescriptor customized_desc =
          (NutDescriptor)nut_descriptors.get(subname);
        if(customized_desc!=null){
          if(subdesc.getType().isAssignableFrom(customized_desc.getType())){
            //we have a customized nut tag that's subtype.
            subdesc = customized_desc;
          }
        }
        final Stmt sub = new TagCompiler(seq, ctxt, subtag, null, false, false)
        .compileNut(subname, subdesc, true);
        final Method adder = desc.getAdder(subname);
        mutations.add(dyn_method_invoker(adder, desc.getAdderType(subname), sub));
      }
      else{
        //try anonymous adder if the name is a top-level nut
        /*subdesc = (NutDescriptor)nut_descriptors.get(subname);
        if(subdesc == null){
          throw new ConfigurationException("unknown subnut: "+subname,
              subtag.getLocation());
        }*/
        final Stmt sub = compileLocalTag(seq, ctxt, subtag, false);
        mutations.add(anonymous_adder_invoker(desc, sub));
      }
    }
    private Stmt getRegularNut(final String nutname, final NutDescriptor desc,
        final ArrayList mutations, final boolean is_subnut){
      final Location loc = getLocation();
      return new Stmt(){
        public String toString(){
          return nutname;
        }
        public Object run(Dict frame, Runtime runtime){
          final Object nut = createNut(nutname, desc, mutations,
              frame, runtime);
          try{
            final Object result = desc.getEvaluator().eval(nut);
            return is_subnut?returnSubNut(desc, nut, result):result;
          }
          catch(Throwable e){
            throw raise(e);
          }
        }
        public Class getType(){
          return is_subnut?desc.getType():desc.getEvaluator().getType();
        }
        public Location getLocation(){
          return loc;
        }
      };
    }
    private Object createNut(final String nutname,
        NutDescriptor desc, ArrayList mutations,
        Dict ctxt, Runtime runtime){
      try{
        final Object nut = desc.createNut();
        if(nut instanceof Nut){
          final Nut r = (Nut)nut;
          r.initGloballyDefined(is_global);
          r.initSequenceNumber(ind);
          r.initTagLocation(getLocation());
          r.initNutEnvironment(BodyCompiler.this);
          r.initTagName(nutname);

        }
        final int sz = mutations.size();
        for(int i=0; i<sz; i++){
          ((SideEffect)mutations.get(i)).apply(nut, ctxt, runtime);
        }
        return nut;
      }
      catch(Throwable e){
        throw raise(e);
      }
    }
    private boolean isSkippable(String name){
      if(sys_attributes.contains(name)){
        return true;
      }
      if(is_global && (EAGER_INSTANTIATED.equals(name)||EAGER_INSTANTIATED2.equals(name))){
        return true;
      }
      else return false;
    }
    private Stmt compileNut(final String nutname,
        final NutDescriptor desc, final Dict local_ctxt, final List nodes,
        boolean is_subnut){
      final Attributes attrs = tag.getAttributes();
      final Map props = desc.getPropertyDescriptors();
      final Location loc = getLocation();
      //final HashMap propvals = new HashMap();
      final ArrayList mutations = new ArrayList();
      for(int i=0; i<attrs.size(); i++){
        final String name = NutsUtils.canonicalizeAttributeName(attrs.getKey(i));
        final String val = attrs.getVal(i);
        final PropertyDescriptor prop = (PropertyDescriptor)props.get(name);
        if(prop == null){
          if(!var_permitted && VAR.equals(name)){
            throw raise(VAR + " not permitted in this context.");
          }
          if(isSkippable(name)){
            //sys attribute, we skip.
            continue;
          }
          else{
            throw new ConfigurationException(name + " attribute not supported", loc);
          }
        }
        //compileNutAttribute(val, prop, ctxt, mutations);
        mutations.add(compileNutAttribute(val, prop, local_ctxt));
      }
      if(desc.isCollectionNut()){
        //sub-elements are an array.
        final Stmt[] stmts = new Stmt[nodes.size()];
        final Class elem_type = desc.getSetterElementType();
        for(int i=0; i<stmts.length; i++){
          final Stmt stmt = compileNode(i, local_ctxt,
              (Node)nodes.get(i), false);
          checkElementType(elem_type, stmt);
          stmts[i] = stmt;
        }
        return getCollectionNut(nutname, desc,  mutations, stmts, is_subnut);
      }
      else{
        populateAdders(nutname, desc, nodes, mutations, local_ctxt);
        return getRegularNut(nutname, desc, mutations, is_subnut);
      }
    }
    private void assertNoCustomAttributes(){
      if(!var_permitted){
        if(tag.getAttribute(VAR)!=null){
          raise(VAR + " not permitted in this context.");
        }
      }
      assertAttributes(sys_attributes);
    }

    private Definition[] compileDefinitions(Dict ctxt, List subnodes,
        HashMap local_names){
      final Definition[] stmts = new Definition[subnodes.size()];
      for(int i=0; i<subnodes.size(); i++){
        final Node node = (Node)(subnodes).get(i);
        final Location loc = node.getLocation();
        if(node instanceof Tag){
          Tag sub = (Tag)node;
          final String id = getIdAttribute(sub);
          final String var = getVarAttribute(sub);
          if(id!=null&&var!=null&&id.equals(var)){
            throw new ConfigurationException("id and var cannot share the same value",
                loc);
          }
          checkDup(local_names, id, ID, loc);
          checkDup(local_names, var, VAR, loc);
          final Stmt stmt = compileLocalTag(i, ctxt, sub, true);
          //let's allow non-component sub-elements.
          /*
          if(!maybeType(Component.class, stmt.getType())){
            throw new ConfigurationException(getName() + " only allow sub-elements that evaluates to Component",
                loc);
          }*/
          stmts[i] = new Definition(sub.getName(), id, var, stmt);
          if(id != null){
            ctxt = declareName(ctxt, id, loc);
          }
          if(var != null)
            ctxt = declareName(ctxt, var, loc);
        }
        else{
          throw new ConfigurationException(getName() + " only allow sub-elements that evaluates to Component",
              loc);
        }
      }
      return stmts;
    }
    private Stmt compileCallcc(Dict local_ctxt, List subnodes){
      assertAttributes(callcc_attributes);
      final String exit = MyUtil.getMandatory(tag, EXIT);
      final Location loc = getLocation();
      final Stmt body = compileSequential(declareName(local_ctxt, exit, loc),
          subnodes);
      return new Stmt(){
        public Location getLocation() {
          return loc;
        }
        public Class getType() {
          return Component.class;
        }
        public Object run(Dict frame, Runtime runtime) {
          final Object id = new ReferentialId(exit);
          final NutsContinuation cont = new NutsContinuation(exit, loc, id);
          frame = frame.put(exit, cont);
          final Object r = body.run(frame, runtime);
          if(r instanceof Component){
            final Component c = (Component)r;
            return new DelegatingComponent(c){
              public Object create(Dependency dep){
                try{
                  return super.create(dep);
                }
                catch(RuntimeException e){
                  final ContinuationEscapeException escape =
                    MyUtil.getEscapeException(e);
                  if(escape!=null && escape.getId()==id){
                    return escape.getResult();
                  }
                  throw e;
                }
              }
            };
            /*
            return c.recover(new Recovery(){
              public Creator recover(RuntimeException e){
                final ContinuationEscapeException escape =
                  MyUtil.getEscapeException(e);
                if(escape!=null && escape.getId()==id){
                  return NutsUtils.asComponent(escape.getResult());
                }
                throw e;
              }
              public String toString(){
                return c.toString();
              }
            });*/
          }
          else return r;
        }
      };
    }
    private Stmt compileSequence(Dict local_ctxt, List subnodes){
      //id, var and local are already handled.
      assertNoCustomAttributes();
      return compileSequential(local_ctxt, subnodes);
    }
    private Stmt compileSequential(Dict local_ctxt, List subnodes){
      final HashMap local_names = new HashMap();
      final Definition[] stmt = compileDefinitions(local_ctxt, subnodes, local_names);
      return bindStatements(stmt, 0, stmt.length);
    }
    private Stmt compileBinder(Dict ctxt, List subnodes){
      assertAttributes(bare_attributes);
      final String varname = getMandatoryVar(tag);
      final String id = getIdAttribute(tag);
      if(id!=null && id.equals(varname)){
        throw raise(ID+" and "+VAR+" cannot share the same value");
      }
      final HashMap local_names = new HashMap();
      local_names.put(varname, varname);
      final Dict nctxt = ctxt;//declareName(ctxt, varname, getLocation());
      final Definition[] stmt = compileDefinitions(nctxt, subnodes, local_names);
      return compileBinder(varname, stmt, 0, stmt.length);
    }
    private Component seq(Component c1, Component c2){
      if(c1==null) return c2;
      else return c1.seq(c2);
    }
    private Component evalDefinitions(final Definition[] defs,
        final int begin, final int end, Dict frame, Runtime runtime) {
      if(begin==end)
        return Components.value(null);
      Component cc = null;
      final int last = end - 1;
      for(int i=begin;i<end;i++){
        final Definition def = defs[i];
        final Object retval = evalStmt(def.stmt, runtime, frame);
        final boolean isComponent = retval instanceof Component;
        if(isComponent){
          cc = seq(cc,(Component)retval);
          if(i==last) return cc;
        }
        else if(i==last){
          return seq(cc, NutsUtils.asComponent(retval));
        }
        /*
        if(isComponent){
          final Component cur = (Component)retval;
          cc = cc==null?cur:cc.seq(cur);
        }
        else{
          //relax this restriction because sometimes we may have a tag
          //that may or may not result in a component.
          if(i==last){
            cc = NutsUtils.asComponent(retval);
          }
        }*/
        frame = nextFrame(def, frame, retval);
        final String vi = def.var;
        if(vi != null){
          if(isComponent){
            final Stmt binder = bindStatements(defs, i+1, end);
            return cc.bind(evalBinder(vi,
                binder, runtime, frame));
          }
          else{
            frame = frame.put(vi, retval);
          }
        }
      }
      return cc;
    }

    private Stmt bindStatements(final Definition[] defs,
        final int begin, final int end){
      final Location loc = this.tag.getLocation();
      return new Stmt(){
        public Location getLocation(){
          return loc;
        }
        public Class getType(){
          return Component.class;
        }
        public Object run(final Dict frame, Runtime runtime){
          return evalDefinitions(defs, begin, end, frame, runtime);
        }
        public String toString(){
          return StringUtils.listArray("[", ", ", "]", defs);
        }
      };
    }
    private Stmt compileBinder(final String varname,
        final Definition[] stmt,
        final int begin, final int end){
      final Location loc = this.tag.getLocation();
      final Stmt body = bindStatements(stmt, begin, end);
      return new Stmt(){
        public Location getLocation(){
          return loc;
        }
        public Class getType(){
          return Binder.class;
        }
        public Object run(final Dict frame, Runtime runtime){
          return evalBinder(varname, body, runtime, frame);
        }
        public String toString(){
          return body.toString();
        }
      };
    }
  }//TagCompiler
 
  private static final class LocalScope{
    private final Dict ctxt;
    private final Object[] keys;
    private final Stmt[] stmts;
    public String toString(){
      return StringUtils.listArray("{",";","}",keys);
    }
    public Dict getScope() {
      return ctxt;
    }
    public Stmt[] getDefinitions() {
      return stmts;
    }
    public Object[] getKeys() {
      return keys;
    }
    public LocalScope(Object[] keys, Stmt[] stmts, Dict ctxt) {
      this.ctxt = ctxt;
      this.stmts = stmts;
      this.keys = keys;
    }
   
  }
  static Stmt withScope(LocalScope scope, final Stmt stmt, final Location loc){
    final Object[] keys = scope.getKeys();
    final Stmt[] stmts = scope.getDefinitions();
    return new Stmt(){
      public String toString(){
        return stmt.toString();
      }
      public Object run(Dict frame, Runtime runtime){
        return stmt.run(newFrame(keys, stmts, frame, runtime), runtime);
      }
      public Class getType(){
        return stmt.getType();
      }
      public Location getLocation(){
        return loc;
      }
    };
  }
  private static Dict newFrame(Object[] keys, Stmt[] stmts,
      Dict frame, final Runtime runtime){
    final Thunk[] thunks = new Thunk[keys.length];
    final Dict[] nframe = new Dict[1];
    for(int i=0; i<keys.length; i++){
      final Stmt stmt = stmts[i];
      thunks[i] = new Thunk(keys[i], stmt.getLocation()){
        Object evaluate(){
          return stmt.run(nframe[0], runtime);
        }
        public Class getType(){
          return stmt.getType();
        }
      };
    }
    nframe[0] = frame.puts(keys, thunks);
    return nframe[0];
  }
  static Body evaluate(Object[] keys, Stmt[] stmts,
      Runtime runtime,
      Dict initial_frame){
    final Dict frame = newFrame(keys,
        stmts, initial_frame, runtime);
    final Closure[] closures = new Closure[keys.length];
    final Location[] locations = new Location[keys.length];
    for(int i=0; i<keys.length; i++){
      final Object key = keys[i];
      //final Location iloc = stmts[i].getLocation();
      closures[i] = (Closure)frame.get(key);
      locations[i] = stmts[i].getLocation();
    }
    return new Body(keys, closures, locations);
  }


  private LocalScope compileLocalScope(final String tagname, Dict ctxt, List decs,
      IdChecker global, SingletonMode singleton_mode, boolean is_global){
    final Object[] keys = new Object[decs.size()];
    final Bound[] bounds = new Bound[keys.length];
    final HashMap locals = new HashMap(keys.length);
    for(int i=0; i<keys.length; i++){
      final Node node = (Node)decs.get(i);
      final Location loc = node.getLocation();
      if(node instanceof Tag){
        final Tag tag = (Tag)node;
        final String id = getIdAttribute(tag);
        if(id==null){
          if(!is_global){
            throw new ConfigurationException(ID+" is required.",
              loc);
          }
          else{
            final Object aid = new AnonymousId(i);
            keys[i] = aid;
            bounds[i] = new Bound(aid, loc);
          }
        }
        else{
          if(locals.containsKey(id)){
            throw new ConfigurationException("duplicate id: "+id, loc);
          }
          if(reserves.contains(id)){
            throw new ConfigurationException("id "+id+" is reserved.", loc);
          }
          if(global!=null)
            global.checkId(id, loc);
          keys[i] = id;
          bounds[i] = new Bound(id, loc);
          locals.put(id, id);
        }
      }
      else{
        throw new ConfigurationException("only elements are allowed within "+tagname,
            loc);
      }
    }
    final Dict nctxt = ctxt.puts(keys, bounds);
    final Stmt[] stmts = new Stmt[keys.length];
    for(int i=0; i<keys.length; i++){
      final Tag tag = (Tag)decs.get(i);
      stmts[i] = compileTag(i, nctxt, tag, false, is_global, singleton_mode);
    }
    return new LocalScope(keys, stmts, nctxt);

  }
  private LocalScope compileLocalScope(Dict ctxt, Tag localtag){
    if(localtag.getAttributes().size()>0){
      throw new ConfigurationException("attributes not allowed on local tag",
          localtag.getLocation());
    }
    final List decs = localtag.getSubNodes();
    return compileLocalScope(localtag.getName(), ctxt, decs, null, null, false);
  }

  private static void checkDup(Map map, String key, String kind, Location loc){
    if(key!=null && map.containsKey(key)){
      throw new ConfigurationException("duplicate "+kind+": "+key, loc);
    }
    map.put(key, loc);
  }
  static final class Definition{
    final Stmt stmt;
    final String var;
    final String id;
    final String tagname;
    Definition(String tagname, String id, String var, Stmt stmt) {
      this.tagname = tagname;
      this.stmt = stmt;
      this.var = var;
      this.id = id;
    }
    public String toString(){
      return tagname;
    }
  }
  private static boolean maybeType(Class expected, Class actual){
    if(actual == null)
      return true;
    return ReflectionUtil.isCompatible(expected, actual);
  }
  private Stmt compileNode(
      int ind, Dict ctxt, Node node, boolean var_permitted){
    if(node instanceof CharacterData){
      final CharacterData literal = (CharacterData)node;
      return MyUtil.value(literal.getText(), node.getLocation());
    }
    else{
      return compileLocalTag(ind, ctxt, (Tag)node, var_permitted);
    }
  }
  private Stmt compileTag(int ind, Dict ctxt, Tag tag, boolean var_permitted, boolean is_global,
      SingletonMode singleton_mode){
    return new TagCompiler(ind, ctxt, tag, singleton_mode, var_permitted, is_global)
        .compile();
  }
  private Stmt compileLocalTag(int ind, Dict local_ctxt, Tag tag, boolean var_permitted){
    return compileTag(ind, local_ctxt, tag, var_permitted, false, null);
  }
  private void checkElementType(final Class expected,
      final Stmt stmt){
    final Class type = stmt.getType();
    final Location loc = stmt.getLocation();
    if(maybeType(expected, type)){
      return;
    }
    else if(String.class.equals(type)){
      if(!isDeserializable(expected)){
        throw new ConfigurationException("cannot convert string to "
            + Misc.getTypeName(expected), loc);
      }
      return;
    }
    else{
      throw new ConfigurationException("cannot convert " + Misc.getTypeName(type)
          +" to " + Misc.getTypeName(expected), loc);
    }
  }
  static ConfigurationException raise(String msg, Throwable e, Location loc){
    if(e instanceof ConfigurationException){
      throw (ConfigurationException)e;
    }
    else if(e instanceof InvocationTargetException){
      throw raise(msg, ((InvocationTargetException)e).getTargetException(), loc);
    }
    throw new ConfigurationException(msg, e, loc);
   
  }
  static ConfigurationException raise(Throwable e, Location loc){
    if(e instanceof ConfigurationException){
      throw (ConfigurationException)e;
    }
    else if(e instanceof InvocationTargetException){
      throw raise(((InvocationTargetException)e).getTargetException(), loc);
    }
    throw new ConfigurationException(e.getMessage(), e, loc);
  }

  private SideEffect anonymous_adder_invoker(
      final NutDescriptor desc,
      final Stmt stmt){
    return new SideEffect(){
      public String toString(){
        return "add";
      }
      public void apply(Object obj, Dict frame, Runtime runtime){
        try{
          final Object v = stmt.run(frame, runtime);
          final Method mtd = desc.getAnonymousAdder(v);
          try{
            mtd.invoke(obj, new Object[]{v});
          }
          catch(InvocationTargetException e){
            throw new ConfigurationException(e.getTargetException(), stmt.getLocation());
          }
        }
        catch(Throwable e){
          throw raise(e, stmt.getLocation());
        }
      }
    }
  }
  private SideEffect dyn_method_invoker(final Method mtd,
      final Class param_type,
      final Stmt stmt){
    return new SideEffect(){
      //final boolean to_component = Component.class.equals(param_type);
      public String toString(){
        return mtd.toString();
      }
      public void apply(Object obj, Dict frame, Runtime runtime){
        try{
          Object v = stmt.run(frame, runtime);
          /*if(v instanceof Var){
            v = ((Var)v).val;
            if(to_component){
              v = NutsUtils.asComponent(v);
            }
          }*/
          try{
            mtd.invoke(obj, new Object[]{
                convert(param_type, v, stmt.getLocation())});
          }
          catch(RuntimeException e){
            throw new ConfigurationException("failed to invoke " + mtd.getName()+
                "("+Misc.getTypeName(param_type)+") with argument of type "
                +(v==null?null:Misc.getTypeName(v.getClass()))
                , e, stmt.getLocation());
          }
        }
        catch(Throwable e){
          throw raise(e, stmt.getLocation());
        }
      }
    }
  }
  private static Object evalStmt(Stmt stmt,
      Runtime runtime, Dict frame){
    final Object r = stmt.run(frame, runtime);
    return r;
  }
  private static Dict nextFrame(Definition c, Dict frame, Object cur){
    final String id = c.id;
    if(id!=null){
      frame = frame.put(id, cur);
    }
    return frame;
  }
  /*
  private static final class Var{
    final Object val;
    Var(Object val) {
      this.val = val;
    }
   
  }*/
  private static boolean isCompoundType(Class type){
    return type.isArray() || List.class.isAssignableFrom(type)
    || Set.class.isAssignableFrom(type) || Collection.class.equals(type);
  }
  private static boolean isListType(Class type){
    return Collection.class.equals(type) || List.class.isAssignableFrom(type);
  }
  private static boolean isRefType(Class type){
    return Component.class.equals(type) || Binder.class.isAssignableFrom(type)
    || NutsFunction.class.isAssignableFrom(type);
  }
  private Stmt cast(final Class target_type, final Stmt stmt){
    return new Stmt(){
      public Class getType() {
        return target_type;
      }
      public Object run(Dict frame, Runtime runtime) {
        return convert(target_type, stmt.run(frame, runtime), getLocation());
      }
      public Location getLocation() {
        return stmt.getLocation();
      }
      public String toString(){
        return stmt.toString();
      }
    };
  }
  private static ComponentBinder evalBinder(final String varname,
      final Stmt stmt, final Runtime runtime, final Dict frame){
    return new ComponentBinder(){
      public String toString(){
        return "\\"+varname+"->"+stmt;
      }
      public Creator bind(Object v){
        //final Var var = new Var(v);
        Dict nframe = frame.put(varname, v);
        final Object retval = evalStmt(stmt, runtime, nframe);
        return NutsUtils.asComponent(retval);
      }

      public Class bindType(Class type) {
        return stmt.getType();
      }
      public Verifiable verify(Class type) {
        return Monad.verifyAs(stmt.getType());
      }
    };
  }
  AutoWiringMap getCustomWiringModes(){
    return interpreter.getCustomWiringModes();
  }
  public File getBaseDir() {
    return interpreter.getBaseDir();
  }
  public ResourceLoader getResourceLoader(){
    return interpreter.getResourceLoader();
  }
  public ClassLoader getComponentClassLoader() {
    return interpreter.getClassloader();
  }
  public ClassLoader getNutClassLoader(){
    return interpreter.getClass().getClassLoader();
  }
  public Object findService(Object key) {
    return interpreter.getServices().get(key);
  }
  public DefaultLifecycleManager getLifecycleManager(){
    return interpreter.getLifecycleManager();
  }
  public boolean isDeserializable(Class type){
    return interpreter.isDeserializable(type);
  }
  public Object deserialize(Class type, String text)
  throws Throwable{
    return interpreter.deserialize(type, text);
  }
  public void registerDeserializer(Class type, Deserializer deserializer,
      boolean overriding, boolean mandatory){
    interpreter.registerDeserializer(type, deserializer,
        overriding, mandatory);
  }
  private int seq_no = 0;
  public synchronized void registerEagerInstantiation(int ind, Object key, Component c){
    interpreter.registerEagerInstantiation(new UID(module_id, ind, seq_no++, key), c);
  }
  public boolean isEagerlyInstantiating(){
    return this.default_eager_mode;
  }
  public synchronized void registerDynamic(Object key, Object val,
      boolean overridable, boolean overriding, Location loc){
    interpreter.registerDynamic(key, val, overridable, overriding, loc);
  }
  private interface FromLiteral{
    Object fromLiteral(String literal);
  }
  private static Stmt asStmt(Object v, Location loc){
    if(v instanceof Stmt){
      return (Stmt)v;
    }
    else return MyUtil.value(v, loc);
  }

}
TOP

Related Classes of jfun.yan.xml.BodyCompiler$TagCompiler

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.
ew');