Package railo.transformer.bytecode.statement.udf

Source Code of railo.transformer.bytecode.statement.udf.Function

package railo.transformer.bytecode.statement.udf;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

import railo.commons.lang.CFTypes;
import railo.commons.lang.StringUtil;
import railo.runtime.Component;
import railo.runtime.exp.TemplateException;
import railo.runtime.listener.AppListenerUtil;
import railo.runtime.type.FunctionArgument;
import railo.runtime.type.FunctionArgumentImpl;
import railo.runtime.type.FunctionArgumentLight;
import railo.runtime.type.util.ComponentUtil;
import railo.transformer.bytecode.Body;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Literal;
import railo.transformer.bytecode.Page;
import railo.transformer.bytecode.Position;
import railo.transformer.bytecode.cast.CastBoolean;
import railo.transformer.bytecode.cast.CastInt;
import railo.transformer.bytecode.cast.CastString;
import railo.transformer.bytecode.expression.ExprBoolean;
import railo.transformer.bytecode.expression.ExprInt;
import railo.transformer.bytecode.expression.ExprString;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.expression.var.Variable;
import railo.transformer.bytecode.literal.LitBoolean;
import railo.transformer.bytecode.literal.LitInteger;
import railo.transformer.bytecode.literal.LitString;
import railo.transformer.bytecode.statement.Argument;
import railo.transformer.bytecode.statement.HasBody;
import railo.transformer.bytecode.statement.IFunction;
import railo.transformer.bytecode.statement.StatementBaseNoFinal;
import railo.transformer.bytecode.statement.tag.Attribute;
import railo.transformer.bytecode.util.ASMConstants;
import railo.transformer.bytecode.util.ASMUtil;
import railo.transformer.bytecode.util.ExpressionUtil;
import railo.transformer.bytecode.util.Types;
import railo.transformer.cfml.evaluator.EvaluatorException;

public abstract class Function extends StatementBaseNoFinal implements Opcodes, IFunction,HasBody {

 

  // Scope variablesScope()
  static final Method VARIABLE_SCOPE = new Method(
      "variablesScope",
      Types.VARIABLES,
      new Type[]{}
        );
  // Scope variablesScope()
  static final Method GET_PAGESOURCE = new Method(
      "getPageSource",
      Types.PAGE_SOURCE,
      new Type[]{}
        );


  // Object set(String,Object)
  static final Method SET_STR = new Method(
      "set",
      Types.OBJECT,
      new Type[]{Types.STRING,Types.OBJECT}
        );
 
  static final Method SET_KEY = new Method(
      "set",
      Types.OBJECT,
      new Type[]{Types.COLLECTION_KEY,Types.OBJECT}
        );
 
  static final Method REG_UDF_STR = new Method(
      "registerUDF",
      Types.VOID,
      new Type[]{Types.STRING,Types.UDF_PROPERTIES}
        );

 
  static final Method REG_UDF_KEY = new Method(
      "registerUDF",
      Types.VOID,
      new Type[]{Types.COLLECTION_KEY,Types.UDF_PROPERTIES}
        );

 
 
  private static final ExprString ANY = LitString.toExprString("any");
 
  // <init>(Page,FunctionArgument[],int String,String,boolean);
  private static final Type FUNCTION_ARGUMENT = Type.getType(FunctionArgument.class);
  private static final Type FUNCTION_ARGUMENT_IMPL = Type.getType(FunctionArgumentImpl.class);
  private static final Type FUNCTION_ARGUMENT_LIGHT = Type.getType(FunctionArgumentLight.class);
  private static final Type FUNCTION_ARGUMENT_ARRAY = Type.getType(FunctionArgument[].class);
 
  protected static final Method INIT_UDF_IMPL_PROP = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.UDF_PROPERTIES
        }
        );
 
 
  private static final Method INIT_UDF_PROPERTIES_STRTYPE = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.PAGE_SOURCE,
          FUNCTION_ARGUMENT_ARRAY,
          Types.INT_VALUE,
          Types.STRING,
          Types.STRING,
          Types.STRING,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE,
          Types.BOOLEAN,
          Types.STRING,
          Types.STRING,
          Types.STRING,
          Types.BOOLEAN,
          Types.BOOLEAN,
          Types.LONG_VALUE,
          Types.INTEGER,
          Page.STRUCT_IMPL
        }
        );
  private static final Method INIT_UDF_PROPERTIES_SHORTTYPE = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.PAGE_SOURCE,
          FUNCTION_ARGUMENT_ARRAY,
          Types.INT_VALUE,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.STRING,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE,
          Types.BOOLEAN,
          Types.STRING,
          Types.STRING,
          Types.STRING,
          Types.BOOLEAN,
          Types.BOOLEAN,
          Types.LONG_VALUE,
          Types.INTEGER,
          Page.STRUCT_IMPL
        }
        );
  private static final Method INIT_UDF_PROPERTIES_SHORTTYPE_LIGHT = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.PAGE_SOURCE,
          FUNCTION_ARGUMENT_ARRAY,
          Types.INT_VALUE,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.STRING,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE
        }
        );


  // FunctionArgumentImpl(String name,String type,boolean required,int defaultType,String dspName,String hint,StructImpl meta)
  private static final Method INIT_FAI_KEY1 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY}
        )
  private static final Method INIT_FAI_KEY3 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY,
          Types.STRING,
          Types.SHORT_VALUE}
        );
  private static final Method INIT_FAI_KEY4 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.BOOLEAN_VALUE}
        )
  private static final Method INIT_FAI_KEY5 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE}
        );
  private static final Method INIT_FAI_KEY6 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE,
          Types.BOOLEAN_VALUE}
        );
  private static final Method INIT_FAI_KEY7 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.STRING}
        );
  private static final Method INIT_FAI_KEY8 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.STRING,
          Types.STRING}
        );
  private static final Method INIT_FAI_KEY9 = new Method(
      "<init>",
      Types.VOID,
      new Type[]{
          Types.COLLECTION_KEY,
          Types.STRING,
          Types.SHORT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.INT_VALUE,
          Types.BOOLEAN_VALUE,
          Types.STRING,
          Types.STRING,
          Page.STRUCT_IMPL}
        )
  private static final Method[] INIT_FAI_KEY=new Method[]{
    INIT_FAI_KEY1,INIT_FAI_KEY3,INIT_FAI_KEY4,INIT_FAI_KEY5,INIT_FAI_KEY6,INIT_FAI_KEY7,INIT_FAI_KEY8,INIT_FAI_KEY9
  };
  private static final Method[] INIT_FAI_KEY_LIGHT=new Method[]{
    INIT_FAI_KEY1,INIT_FAI_KEY3
  };
 
 
  ExprString name;
  ExprString returnType=ANY;
  ExprBoolean output=LitBoolean.TRUE;
  ExprBoolean bufferOutput;
  //ExprBoolean abstry=LitBoolean.FALSE;
  int access=Component.ACCESS_PUBLIC;
  ExprString displayName=LitString.EMPTY;
  ExprString hint=LitString.EMPTY;
  Body body;
  List<Argument> arguments=new ArrayList<Argument>();
  Map<String,Attribute> metadata;
  ExprString returnFormat;
  ExprString description;
  ExprBoolean secureJson;
  ExprBoolean verifyClient;
  ExprInt localMode;
  protected int valueIndex;
  protected int arrayIndex;
  private long cachedWithin;
  private boolean _abstract;
  private boolean _final;
 

  public Function(Page page,String name,int access,String returnType,Body body,Position start, Position end) {
    super(start,end);
    this.name=LitString.toExprString(name);
    this.access=access;
    if(!StringUtil.isEmpty(returnType))this.returnType=LitString.toExprString(returnType);
    this.body=body;
    body.setParent(this);
    int[] indexes = page.addFunction(this);
    valueIndex=indexes[VALUE_INDEX];
    arrayIndex=indexes[ARRAY_INDEX];
  }
 
  public Function(Page page,Expression name,Expression returnType,Expression returnFormat,Expression output,Expression bufferOutput,
      int access,Expression displayName,Expression description,Expression hint,Expression secureJson,
      Expression verifyClient,Expression localMode,long cachedWithin, boolean _abstract, boolean _final,Body body,Position start, Position end) {
    super(start,end);
   
    this.name=CastString.toExprString(name);
    this.returnType=CastString.toExprString(returnType);
    this.returnFormat=returnFormat!=null?CastString.toExprString(returnFormat):null;
    this.output=CastBoolean.toExprBoolean(output);
    this.bufferOutput=bufferOutput==null?null:CastBoolean.toExprBoolean(bufferOutput);
    this.access=access;
    this.description=description!=null?CastString.toExprString(description):null;
    this.displayName=CastString.toExprString(displayName);
    this.hint=CastString.toExprString(hint);
    this.secureJson=secureJson!=null?CastBoolean.toExprBoolean(secureJson):null;
    this.verifyClient=verifyClient!=null?CastBoolean.toExprBoolean(verifyClient):null;
    this.cachedWithin=cachedWithin;
    this._abstract=_abstract;
    this._final=_final;
    this.localMode=toLocalMode(localMode, null);
   
    this.body=body;
    body.setParent(this);
    int[] indexes=page.addFunction(this);
    valueIndex=indexes[VALUE_INDEX];
    arrayIndex=indexes[ARRAY_INDEX];
   
  }


  public static ExprInt toLocalMode(Expression expr, ExprInt defaultValue) {
    int mode=-1;
    if(expr instanceof Literal) {
      String str = ((Literal)expr).getString();
      str=str.trim().toLowerCase();
      mode = AppListenerUtil.toLocalMode(str,-1);
    }
    if(mode==-1) return defaultValue;
    return LitInteger.toExpr(mode);
  }
 


  /*private static void checkNameConflict(ExprString expr) {
    if(expr instanceof LitString){
      String name=((LitString)expr).getString();
      if()
    }
  }*/

  /**
   * @see railo.transformer.bytecode.statement.IFunction#writeOut(railo.transformer.bytecode.BytecodeContext, int)
   */
  public final void writeOut(BytecodeContext bc, int type) throws BytecodeException {
      ExpressionUtil.visitLine(bc, getStart());
        _writeOut(bc,type);
      ExpressionUtil.visitLine(bc, getEnd());
  }
 
  /**
   * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(railo.transformer.bytecode.BytecodeContext)
   */
  public final void _writeOut(BytecodeContext bc) throws BytecodeException {
    _writeOut(bc,PAGE_TYPE_REGULAR);
  }
 
  public abstract void _writeOut(BytecodeContext bc, int pageType) throws BytecodeException;
 

  public final void loadUDFProperties(BytecodeContext bc, int valueIndex,int arrayIndex, boolean closure) throws BytecodeException {
    BytecodeContext constr = bc.getConstructor();
    GeneratorAdapter cga = constr.getAdapter();
    GeneratorAdapter ga = bc.getAdapter();
   
    // store
    cga.visitVarInsn(ALOAD, 0);
    cga.visitFieldInsn(GETFIELD, bc.getClassName(), "udfs", Types.UDF_PROPERTIES_ARRAY.toString());
    cga.push(arrayIndex);
    createUDFProperties(constr,valueIndex,closure);
    //cga.visitInsn(DUP_X2);
    cga.visitInsn(AASTORE);
   
    // get
    ga.visitVarInsn(ALOAD, 0);
    ga.visitFieldInsn(GETFIELD, bc.getClassName(), "udfs", Types.UDF_PROPERTIES_ARRAY.toString());
    ga.push(arrayIndex);
    ga.visitInsn(AALOAD);
  }
 
 
 
  public final void createUDFProperties(BytecodeContext bc, int index, boolean closure) throws BytecodeException {
    GeneratorAdapter adapter=bc.getAdapter();
    adapter.newInstance(Types.UDF_PROPERTIES_IMPL);
    adapter.dup();
    if(closure){
      adapter.loadThis();
      adapter.invokeVirtual(Types.PAGE, GET_PAGESOURCE);
    }
    else adapter.visitVarInsn(ALOAD, 1);
    // page
    //adapter.loadLocal(0);
    //adapter.loadThis();
   
    // arguments
    createArguments(bc);
    // index
    adapter.push(index);
    // name
    ExpressionUtil.writeOutSilent(name,bc, Expression.MODE_REF);
    // return type
    short type=ExpressionUtil.toShortType(returnType,false,CFTypes.TYPE_UNKNOW);
    if(type==CFTypes.TYPE_UNKNOW) ExpressionUtil.writeOutSilent(returnType,bc, Expression.MODE_REF);
    else adapter.push(type);
   
    // return format
    if(returnFormat!=null)ExpressionUtil.writeOutSilent(returnFormat,bc, Expression.MODE_REF);
    else ASMConstants.NULL(adapter);
   
    // output
    ExpressionUtil.writeOutSilent(output,bc, Expression.MODE_VALUE);
   
   
    // access
    writeOutAccess(bc, access);
   
    boolean light=type!=-1;
    if(light && !LitString.EMPTY.equals(displayName))light=false;
    if(light && description!=null && !LitString.EMPTY.equals(description))light=false;
    if(light && !LitString.EMPTY.equals(hint))light=false;
    if(light && secureJson!=null)light=false;
    if(light && verifyClient!=null)light=false;
    if(light && cachedWithin>0)light=false;
    if(light && bufferOutput!=null)light=false;
    if(light && localMode!=null)light=false;
    if(light && Page.hasMetaDataStruct(metadata, null))light=false;
   
    if(light){
      adapter.invokeConstructor(Types.UDF_PROPERTIES_IMPL, INIT_UDF_PROPERTIES_SHORTTYPE_LIGHT);
      return;
    }
   

    // buffer output
    if(bufferOutput!=null)ExpressionUtil.writeOutSilent(bufferOutput,bc, Expression.MODE_REF);
    else ASMConstants.NULL(adapter);
   
    // displayName
    ExpressionUtil.writeOutSilent(displayName,bc, Expression.MODE_REF);// displayName;
   
    // description
    if(description!=null)ExpressionUtil.writeOutSilent(description,bc, Expression.MODE_REF);// displayName;
    else adapter.push("");
   
    // hint
    ExpressionUtil.writeOutSilent(hint,bc, Expression.MODE_REF);// hint;
   
    // secureJson
    if(secureJson!=null)ExpressionUtil.writeOutSilent(secureJson,bc, Expression.MODE_REF);
    else ASMConstants.NULL(adapter);
   
    // verify client
    if(verifyClient!=null)ExpressionUtil.writeOutSilent(verifyClient,bc, Expression.MODE_REF);
    else ASMConstants.NULL(adapter);
   
    // cachedwithin
    adapter.push(cachedWithin<0?0:cachedWithin);
   
    // localMode
    if(localMode!=null)ExpressionUtil.writeOutSilent(localMode,bc, Expression.MODE_REF);
    else ASMConstants.NULL(adapter);
   
    // meta
    Page.createMetaDataStruct(bc,metadata,null);
   
    adapter.invokeConstructor(Types.UDF_PROPERTIES_IMPL, type==-1?INIT_UDF_PROPERTIES_STRTYPE:INIT_UDF_PROPERTIES_SHORTTYPE);
   
  }
 
  /*public final void loadUDF(BytecodeContext bc, int index) throws BytecodeException {
    // new UDF(...)
    GeneratorAdapter adapter=bc.getAdapter();
    adapter.newInstance(Types.UDF_IMPL);
    adapter.dup();
   
    loadUDFProperties(bc, index,false);
   
    adapter.invokeConstructor(Types.UDF_IMPL, INIT_UDF_IMPL_PROP);
  }*/
 
  public final void createUDF(BytecodeContext bc, int index, boolean closure) throws BytecodeException {
    // new UDF(...)
    GeneratorAdapter adapter=bc.getAdapter();
    adapter.newInstance(closure?Types.CLOSURE:Types.UDF_IMPL);
    adapter.dup();
   
    createUDFProperties(bc, index,closure);
    //loadUDFProperties(bc, index,closure);
   
    adapter.invokeConstructor(closure?Types.CLOSURE:Types.UDF_IMPL, INIT_UDF_IMPL_PROP);
  }
 

 
  private final void createArguments(BytecodeContext bc) throws BytecodeException {
    GeneratorAdapter ga = bc.getAdapter();
    ga.push(arguments.size());
    ga.newArray(FUNCTION_ARGUMENT);
    Argument arg;
        for (int i = 0; i < arguments.size(); i++) {
          arg= arguments.get(i);
           
          boolean canHaveKey = Variable.canRegisterKey(arg.getName());
       
      // CHECK if default values
        // type
        ExprString _strType = arg.getType();
        short _type=CFTypes.TYPE_UNKNOW;
        if(_strType instanceof LitString){
          _type=CFTypes.toShortStrict(((LitString)_strType).getString(),CFTypes.TYPE_UNKNOW);
        }
        boolean useType=!canHaveKey || _type!=CFTypes.TYPE_ANY;
        //boolean useStrType=useType && (_type==CFTypes.TYPE_UNDEFINED || _type==CFTypes.TYPE_UNKNOW || CFTypes.toString(_type, null)==null);
       
        // required
        ExprBoolean _req = arg.getRequired();
        boolean useReq=!canHaveKey || toBoolean(_req,null)!=Boolean.FALSE;
       
        // default-type
        Expression _def = arg.getDefaultValueType();
        boolean useDef=!canHaveKey || toInt(_def,-1)!=FunctionArgument.DEFAULT_TYPE_NULL;
       
        // pass by reference
        ExprBoolean _pass = arg.isPassByReference();
        boolean usePass=!canHaveKey || toBoolean(_pass,null)!=Boolean.TRUE;
       
        // display-hint
        ExprString _dsp = arg.getDisplayName();
        boolean useDsp=!canHaveKey || !isLiteralEmptyString(_dsp);
       
        // hint
        ExprString _hint = arg.getHint();
        boolean useHint=!canHaveKey || !isLiteralEmptyString(_hint);
       
        // meta
        Map _meta = arg.getMetaData();
        boolean useMeta=!canHaveKey || (_meta!=null && !_meta.isEmpty());
        int functionIndex=7;
        if(!useMeta) {
          functionIndex--;
          if(!useHint) {
            functionIndex--;
            if(!useDsp){
                functionIndex--;
                if(!usePass) {
                  functionIndex--;
                  if(!useDef) {
                    functionIndex--;
                    if(!useReq) {
                      functionIndex--;
                      if(!useType){
                        functionIndex--;
                      }
                    }
                  }
                }
            }
          }
        }
      // write out arguments 
        ga.dup();
            ga.push(i);
             
            // new FunctionArgument(...)
            ga.newInstance(canHaveKey && functionIndex<INIT_FAI_KEY_LIGHT.length?FUNCTION_ARGUMENT_LIGHT:FUNCTION_ARGUMENT_IMPL);
        ga.dup();
        Variable.registerKey(bc,arg.getName(),false);
       
        // type
        if(functionIndex>=INIT_FAI_KEY.length-7) {
          _strType.writeOut(bc, Expression.MODE_REF);
          bc.getAdapter().push(_type);
        }
        // required
        if(functionIndex>=INIT_FAI_KEY.length-6)_req.writeOut(bc, Expression.MODE_VALUE);
        // default value
        if(functionIndex>=INIT_FAI_KEY.length-5)_def.writeOut(bc, Expression.MODE_VALUE);
        // pass by reference
        if(functionIndex>=INIT_FAI_KEY.length-4)_pass.writeOut(bc, Expression.MODE_VALUE);
        // display-name
        if(functionIndex>=INIT_FAI_KEY.length-3)_dsp.writeOut(bc, Expression.MODE_REF);
        // hint
        if(functionIndex>=INIT_FAI_KEY.length-2)_hint.writeOut(bc, Expression.MODE_REF);
        //meta
        if(functionIndex==INIT_FAI_KEY.length-1)Page.createMetaDataStruct(bc,_meta,null);
       
        if(functionIndex<INIT_FAI_KEY_LIGHT.length)
            ga.invokeConstructor(FUNCTION_ARGUMENT_LIGHT, INIT_FAI_KEY[functionIndex]);
        else
          ga.invokeConstructor(FUNCTION_ARGUMENT_IMPL, INIT_FAI_KEY[functionIndex]);

            ga.visitInsn(Opcodes.AASTORE);
        }
  }

  private final int toInt(Expression expr, int defaultValue) {
    if(expr instanceof LitInteger) {
      return ((LitInteger)expr).getInteger().intValue();
    }
    return defaultValue;
  }

  private final Boolean toBoolean(ExprBoolean expr, Boolean defaultValue) {
    if(expr instanceof LitBoolean) {
      return ((LitBoolean)expr).getBooleanValue()?Boolean.TRUE:Boolean.FALSE;
    }
    return defaultValue;
  }

  private final boolean isLiteralEmptyString(ExprString expr) {
    if(expr instanceof LitString) {
      return StringUtil.isEmpty(((LitString)expr).getString());
    }
    return false;
  }

  private final void writeOutAccess(BytecodeContext bc,ExprString expr) {
   
    // write short type
    if(expr instanceof LitString){
      int access=ComponentUtil.toIntAccess(((LitString)expr).getString(),Component.ACCESS_PUBLIC);
      bc.getAdapter().push(access);
    }
    else bc.getAdapter().push(Component.ACCESS_PUBLIC);
  }
  private final void writeOutAccess(BytecodeContext bc,int access) {
    bc.getAdapter().push(access);
  }

  public final void addArgument(String name, String type, boolean required, Expression defaultValue) {
    addArgument(
        LitString.toExprString(name),
        LitString.toExprString(type),
        LitBoolean.toExprBoolean(required),
        defaultValue,
        LitBoolean.TRUE,
        LitString.EMPTY,
        LitString.EMPTY,null);
  }

  public final void addArgument(Expression name, Expression type, Expression required, Expression defaultValue,ExprBoolean passByReference,
      Expression displayName, Expression hint,Map meta) {
    arguments.add(new Argument(name,type,required,defaultValue,passByReference,displayName,hint,meta));
  }

  /**
   * @return the arguments
   */
  public final List<Argument> getArguments() {
    return arguments;
  }

  /**
   * @return the body
   */
  public final Body getBody() {
    return body;
  }

  public final void setMetaData(Map<String,Attribute> metadata) {
    this.metadata=metadata;
  }
 
  public final void setHint(String hint){
    this.hint=LitString.toExprString(hint);
  }

  public final void addAttribute(Attribute attr) throws TemplateException {
    String name=attr.getName().toLowerCase();
    // name
    if("name".equals(name))  {
      throw new BytecodeException("name cannot be defined twice",getStart());
      //this.name=CastString.toExprString(attr.getValue());
    }
    else if("returntype".equals(name))  {
      this.returnType=toLitString(name,attr.getValue());
    }
    else if("access".equals(name))  {
     
      LitString ls = toLitString(name,attr.getValue());
      String strAccess = ls.getString();
      int acc = ComponentUtil.toIntAccess(strAccess,-1);
      if(acc==-1)
        throw new BytecodeException("invalid access type ["+strAccess+"], access types are remote, public, package, private",getStart());
      access=acc;
     
    }
   
    else if("output".equals(name))    this.output=toLitBoolean(name,attr.getValue());
    else if("bufferoutput".equals(name))this.bufferOutput=toLitBoolean(name,attr.getValue());
    else if("displayname".equals(name))  this.displayName=toLitString(name,attr.getValue());
    else if("hint".equals(name))    this.hint=toLitString(name,attr.getValue());
    else if("description".equals(name))  this.description=toLitString(name,attr.getValue());
    else if("returnformat".equals(name))this.returnFormat=toLitString(name,attr.getValue());
    else if("securejson".equals(name))  this.secureJson=toLitBoolean(name,attr.getValue());
    else if("verifyclient".equals(name))  this.verifyClient=toLitBoolean(name,attr.getValue());
    else if("localmode".equals(name))  {
      Expression v = attr.getValue();
      if(v!=null) {
        String str = ASMUtil.toString(v,null);
        if(!StringUtil.isEmpty(str)){
          int mode = AppListenerUtil.toLocalMode(str, -1);
          if(mode!=-1) this.localMode=LitInteger.toExpr(mode);
          else throw new BytecodeException("Attribute localMode of the Tag Function, must be a literal value (modern, classic, true or false)",getStart());
        }
      }
    }
    else if("cachedwithin".equals(name))  {
      try {
        this.cachedWithin=ASMUtil.timeSpanToLong(attr.getValue());
      } catch (EvaluatorException e) {
        throw new TemplateException(e.getMessage());
      }
    }
    else if("modifier".equals(name))  {
      Expression val = attr.getValue();
      if(val instanceof Literal) {
        Literal l=(Literal) val;
        String str = StringUtil.emptyIfNull(l.getString()).trim();
        if("abstract".equalsIgnoreCase(str))_abstract=true;
        else if("final".equalsIgnoreCase(str))_final=true;
      }
    }
   
   
   
    else {
      toLitString(name,attr.getValue());// needed for testing
      if(metadata==null)metadata=new HashMap<String,Attribute>();
      metadata.put(attr.getName(), attr);
    }
  }

  private final LitString toLitString(String name, Expression value) throws BytecodeException {
    ExprString es = CastString.toExprString(value);
    if(!(es instanceof LitString))
      throw new BytecodeException("value of attribute ["+name+"] must have a literal/constant value",getStart());
    return (LitString) es;
  }
 
  private final LitBoolean toLitBoolean(String name, Expression value) throws BytecodeException {
     ExprBoolean eb = CastBoolean.toExprBoolean(value);
    if(!(eb instanceof LitBoolean))
      throw new BytecodeException("value of attribute ["+name+"] must have a literal/constant value",getStart());
    return (LitBoolean) eb;
  }
 
  private final ExprInt toLitInt(String name, Expression value) throws BytecodeException {
    ExprInt eb = CastInt.toExprInt(value);
    if(!(eb instanceof Literal))
      throw new BytecodeException("value of attribute ["+name+"] must have a literal/constant value",getStart());
    return eb;
  }

}
TOP

Related Classes of railo.transformer.bytecode.statement.udf.Function

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.