package railo.transformer.bytecode.expression.var; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import railo.runtime.type.scope.Scope; import railo.runtime.type.scope.ScopeFactory; import railo.runtime.type.scope.ScopeSupport; import railo.transformer.bytecode.BytecodeContext; import railo.transformer.bytecode.BytecodeException; import railo.transformer.bytecode.expression.Expression; import railo.transformer.bytecode.expression.ExpressionBase; import railo.transformer.bytecode.literal.LitString; import railo.transformer.bytecode.util.ExpressionUtil; import railo.transformer.bytecode.util.TypeScope; import railo.transformer.bytecode.util.Types; public class Assign extends ExpressionBase { //final static Method[] METHODS_SCOPE_SET = new Method[6]; // java.lang.Object set(String,Object) private final static Method METHOD_SCOPE_SET = new Method("set", Types.OBJECT, new Type[]{Types.STRING,Types.OBJECT}); // java.lang.Object set(String,Object) private final static Method METHOD_SCOPE_SET_KEY = new Method("set", Types.OBJECT, new Type[]{Types.COLLECTION_KEY,Types.OBJECT}); // .setArgument(obj) private final static Method SET_ARGUMENT = new Method("setArgument", Types.OBJECT, new Type[]{Types.OBJECT}); // Object touch (Object,String) private final static Method TOUCH = new Method("touch", Types.OBJECT, new Type[]{Types.OBJECT,Types.STRING}); // Object touch (Object,String) private final static Method TOUCH_KEY = new Method("touch", Types.OBJECT, new Type[]{Types.OBJECT,Types.COLLECTION_KEY}); //Object set (Object,String,Object) private final static Method SET_KEY = new Method("set", Types.OBJECT, new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT}); //Object set (Object,String,Object) private final static Method SET = new Method("set", Types.OBJECT, new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT}); // Object getFunction (Object,String,Object[]) private final static Method GET_FUNCTION = new Method("getFunction", Types.OBJECT, new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY}); // Object getFunctionWithNamedValues (Object,String,Object[]) private final static Method GET_FUNCTION_WITH_NAMED_ARGS = new Method("getFunctionWithNamedValues", Types.OBJECT, new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY}); // Object getFunction (Object,String,Object[]) private final static Method GET_FUNCTION_KEY = new Method("getFunction", Types.OBJECT, new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY}); // Object getFunctionWithNamedValues (Object,String,Object[]) private final static Method GET_FUNCTION_WITH_NAMED_ARGS_KEY = new Method("getFunctionWithNamedValues", Types.OBJECT, new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY}); private Variable variable; private Expression value; /** * Constructor of the class * @param variable * @param value */ public Assign(Variable variable, Expression value) { super(variable.getStart(),variable.getEnd()); this.variable=variable; this.value=value; //this.returnOldValue=returnOldValue; } public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); int count=variable.countFM+variable.countDM; // count 0 if(count==0){ if(variable.ignoredFirstMember() && variable.scope==ScopeSupport.SCOPE_VAR){ //print.dumpStack(); return Types.VOID; } return _writeOutEmpty(bc); } boolean doOnlyScope=variable.scope==Scope.SCOPE_LOCAL; Type rtn=Types.OBJECT; //boolean last; for(int i=doOnlyScope?0:1;i<count;i++) { adapter.loadArg(0); } rtn=_writeOutFirst(bc, (variable.members.get(0)),mode,count==1,doOnlyScope); // pc.get( for(int i=doOnlyScope?0:1;i<count;i++) { Member member=(variable.members.get(i)); boolean last=(i+1)==count; // Data Member if(member instanceof DataMember) { //((DataMember)member).getName().writeOut(bc, MODE_REF); boolean isKey=Variable.registerKey(bc, ((DataMember)member).getName()); if(last)value.writeOut(bc, MODE_REF); if(isKey)adapter.invokeVirtual(Types.PAGE_CONTEXT,last?SET_KEY:TOUCH_KEY); else adapter.invokeVirtual(Types.PAGE_CONTEXT,last?SET:TOUCH); rtn=Types.OBJECT; } // UDF else if(member instanceof UDF) { if(last)throw new BytecodeException("can't asign value to a user defined function",getStart()); UDF udf=(UDF) member; boolean isKey=Variable.registerKey(bc, udf.getName()); //udf.getName().writeOut(bc, MODE_REF); ExpressionUtil.writeOutExpressionArray(bc, Types.OBJECT, udf.getArguments()); if(isKey)adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS_KEY:GET_FUNCTION_KEY); else adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS:GET_FUNCTION); rtn=Types.OBJECT; } } return rtn; } private Type _writeOutFirst(BytecodeContext bc, Member member, int mode, boolean last, boolean doOnlyScope) throws BytecodeException { if(member instanceof DataMember) { return _writeOutOneDataMember(bc,(DataMember)member,last,doOnlyScope); //return Variable._writeOutFirstDataMember(adapter,(DataMember)member,variable.scope, last); } else if(member instanceof UDF) { if(last)throw new BytecodeException("can't assign value to a user defined function",getStart()); return Variable._writeOutFirstUDF(bc,(UDF)member,variable.scope,doOnlyScope); } else { if(last)throw new BytecodeException("can't assign value to a built in function",getStart()); return Variable._writeOutFirstBIF(bc,(BIF)member,mode,last,getStart()); } } private Type _writeOutOneDataMember(BytecodeContext bc, DataMember member,boolean last, boolean doOnlyScope) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); if(doOnlyScope){ adapter.loadArg(0); if(variable.scope==Scope.SCOPE_LOCAL){ return TypeScope.invokeScope(adapter, TypeScope.METHOD_LOCAL_TOUCH,Types.PAGE_CONTEXT); } return TypeScope.invokeScope(adapter, variable.scope); } // pc.get adapter.loadArg(0); if(last) { TypeScope.invokeScope(adapter, variable.scope); //adapter.invokeVirtual(Types.PAGE_CONTEXT,TypeScope.METHODS[variable.scope]); boolean isKey=Variable.registerKey(bc, member.getName()); value.writeOut(bc, MODE_REF); if(isKey)adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET_KEY); else adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET); } else { adapter.loadArg(0); TypeScope.invokeScope(adapter, variable.scope); if(Variable.registerKey(bc, member.getName())) adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH_KEY); else adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH); } return Types.OBJECT; } private Type _writeOutEmpty(BytecodeContext bc) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); if(variable.scope==Scope.SCOPE_ARGUMENTS) { adapter.loadArg(0); TypeScope.invokeScope(adapter, Scope.SCOPE_ARGUMENTS); value.writeOut(bc, MODE_REF); adapter.invokeInterface(TypeScope.SCOPE_ARGUMENT,SET_ARGUMENT); } else { adapter.loadArg(0); TypeScope.invokeScope(adapter, Scope.SCOPE_UNDEFINED); Variable.registerKey(bc,LitString.toExprString(ScopeFactory.toStringScope(variable.scope,"undefined"))); value.writeOut(bc, MODE_REF); adapter.invokeInterface(TypeScope.SCOPES[Scope.SCOPE_UNDEFINED],METHOD_SCOPE_SET_KEY); } return Types.OBJECT; } /** * @return the value */ public Expression getValue() { return value; } /** * @return the variable */ public Variable getVariable() { return variable; } }