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; } }