001    package railo.transformer.bytecode.expression.var;
002    
003    import org.objectweb.asm.Type;
004    import org.objectweb.asm.commons.GeneratorAdapter;
005    import org.objectweb.asm.commons.Method;
006    
007    import railo.runtime.type.Scope;
008    import railo.runtime.type.scope.ScopeFactory;
009    import railo.runtime.type.scope.ScopeSupport;
010    import railo.transformer.bytecode.BytecodeContext;
011    import railo.transformer.bytecode.BytecodeException;
012    import railo.transformer.bytecode.expression.Expression;
013    import railo.transformer.bytecode.expression.ExpressionBase;
014    import railo.transformer.bytecode.literal.LitString;
015    import railo.transformer.bytecode.util.ExpressionUtil;
016    import railo.transformer.bytecode.util.TypeScope;
017    import railo.transformer.bytecode.util.Types;
018    
019    public class Assign extends ExpressionBase {
020    
021            //final static Method[] METHODS_SCOPE_SET = new Method[6];
022            
023    
024    
025    //  java.lang.Object set(String,Object)
026        private final static Method METHOD_SCOPE_SET = new Method("set",
027                            Types.OBJECT,
028                            new Type[]{Types.STRING,Types.OBJECT});
029        
030    //  java.lang.Object set(String,Object)
031        private final static Method METHOD_SCOPE_SET_KEY = new Method("set",
032                            Types.OBJECT,
033                            new Type[]{Types.COLLECTION_KEY,Types.OBJECT});
034            
035    // .setArgument(obj)
036        private final static Method SET_ARGUMENT = new Method("setArgument",
037                            Types.OBJECT,
038                            new Type[]{Types.OBJECT});
039        
040        
041        // Object touch (Object,String)
042        private final static Method TOUCH = new Method("touch",
043                            Types.OBJECT,
044                            new Type[]{Types.OBJECT,Types.STRING});
045    
046        // Object touch (Object,String)
047        private final static Method TOUCH_KEY = new Method("touch",
048                            Types.OBJECT,
049                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY});
050        
051    
052        //Object set (Object,String,Object)
053        private final static Method SET_KEY = new Method("set",
054                            Types.OBJECT,
055                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT});
056        
057        //Object set (Object,String,Object)
058        private final static Method SET = new Method("set",
059                            Types.OBJECT,
060                            new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT});
061    
062        // Object getFunction (Object,String,Object[])
063        private final static Method GET_FUNCTION = new Method("getFunction",
064                            Types.OBJECT,
065                            new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY});
066        
067        // Object getFunctionWithNamedValues (Object,String,Object[])
068        private final static Method GET_FUNCTION_WITH_NAMED_ARGS = new Method("getFunctionWithNamedValues",
069                            Types.OBJECT,
070                            new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY});
071            
072    
073        // Object getFunction (Object,String,Object[])
074        private final static Method GET_FUNCTION_KEY = new Method("getFunction",
075                            Types.OBJECT,
076                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY});
077        
078        // Object getFunctionWithNamedValues (Object,String,Object[])
079        private final static Method GET_FUNCTION_WITH_NAMED_ARGS_KEY = new Method("getFunctionWithNamedValues",
080                            Types.OBJECT,
081                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY});
082            
083            
084            private Variable variable;
085            private Expression value;
086    
087    
088            /**
089             * Constructor of the class
090             * @param variable
091             * @param value
092             */
093            public Assign(Variable variable, Expression value) {
094                    super(variable.getLine());
095                    this.variable=variable;
096                    this.value=value;
097                    //this.returnOldValue=returnOldValue;
098            }
099            
100    
101            public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
102            GeneratorAdapter adapter = bc.getAdapter();
103                    int count=variable.countFM+variable.countDM;
104            // count 0
105            if(count==0){
106                    if(variable.ignoredFirstMember() && variable.scope==ScopeSupport.SCOPE_VAR){
107                            //print.dumpStack();
108                            return Types.VOID;
109                    }
110                    return _writeOutEmpty(bc);
111            }
112            
113            boolean doOnlyScope=variable.scope==Scope.SCOPE_LOCAL;
114            
115            Type rtn=Types.OBJECT;
116            //boolean last;
117            for(int i=doOnlyScope?0:1;i<count;i++) {
118                            adapter.loadArg(0);
119            }
120                    rtn=_writeOutFirst(bc, ((Member)variable.members.get(0)),mode,count==1,doOnlyScope);
121            
122                    // pc.get(
123                    for(int i=doOnlyScope?0:1;i<count;i++) {
124                            Member member=((Member)variable.members.get(i));
125                            boolean last=(i+1)==count;
126                            
127                            
128                            // Data Member
129                            if(member instanceof DataMember)        {
130                                    //((DataMember)member).getName().writeOut(bc, MODE_REF);
131                            boolean isKey=Variable.registerKey(bc, ((DataMember)member).getName());
132                                    
133                            if(last)value.writeOut(bc, MODE_REF);
134                            if(isKey)adapter.invokeVirtual(Types.PAGE_CONTEXT,last?SET_KEY:TOUCH_KEY);
135                            else adapter.invokeVirtual(Types.PAGE_CONTEXT,last?SET:TOUCH);
136                            rtn=Types.OBJECT;
137                            }
138                            
139                            // UDF
140                            else if(member instanceof UDF) {
141                                    if(last)throw new BytecodeException("can't asign value to a user defined function",getLine());
142                                    UDF udf=(UDF) member;
143                                    boolean isKey=Variable.registerKey(bc, udf.getName());
144                                    //udf.getName().writeOut(bc, MODE_REF);
145                                    ExpressionUtil.writeOutExpressionArray(bc, Types.OBJECT, udf.getArguments());
146                                    
147                                    if(isKey)adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS_KEY:GET_FUNCTION_KEY);
148                                    else adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS:GET_FUNCTION);
149                                    rtn=Types.OBJECT;
150                            }
151            }
152            return rtn;
153            }
154    
155            private Type _writeOutFirst(BytecodeContext bc, Member member, int mode, boolean last, boolean doOnlyScope) throws BytecodeException {
156                    
157                    if(member instanceof DataMember) {
158                            return _writeOutOneDataMember(bc,(DataMember)member,last,doOnlyScope);
159                            //return Variable._writeOutFirstDataMember(adapter,(DataMember)member,variable.scope, last);
160                    }
161            else if(member instanceof UDF) {
162                    if(last)throw new BytecodeException("can't assign value to a user defined function",getLine());
163                    return Variable._writeOutFirstUDF(bc,(UDF)member,variable.scope,doOnlyScope);
164            }
165            else {
166                    if(last)throw new BytecodeException("can't assign value to a built in function",getLine());
167                    return Variable._writeOutFirstBIF(bc,(BIF)member,mode,last,getLine());
168            }
169            }
170    
171    
172    
173            private Type _writeOutOneDataMember(BytecodeContext bc, DataMember member,boolean last, boolean doOnlyScope) throws BytecodeException {
174            GeneratorAdapter adapter = bc.getAdapter();
175                    
176            if(doOnlyScope){
177                    adapter.loadArg(0);
178                    if(variable.scope==Scope.SCOPE_LOCAL){
179                            adapter.checkCast(Types.PAGE_CONTEXT_IMPL);
180                            return TypeScope.invokeScope(adapter, TypeScope.METHOD_LOCAL_TOUCH,Types.PAGE_CONTEXT_IMPL);
181                    }
182                    return TypeScope.invokeScope(adapter, variable.scope);
183            }
184            
185            // pc.get
186                    adapter.loadArg(0);
187                    if(last) {
188                            TypeScope.invokeScope(adapter, variable.scope);
189                            //adapter.invokeVirtual(Types.PAGE_CONTEXT,TypeScope.METHODS[variable.scope]);
190                            
191                            boolean isKey=Variable.registerKey(bc, member.getName());
192                            value.writeOut(bc, MODE_REF);
193                            
194                            if(isKey)adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET_KEY);
195                            else adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET);
196                            
197                    }
198                    else {
199                            adapter.loadArg(0);
200                            TypeScope.invokeScope(adapter, variable.scope);
201                            if(Variable.registerKey(bc, member.getName()))
202                            adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH_KEY);
203                    else
204                            adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH);
205                    }
206                    return Types.OBJECT;
207                    
208                    
209            }
210    
211            private Type _writeOutEmpty(BytecodeContext bc) throws BytecodeException {
212                    GeneratorAdapter adapter = bc.getAdapter();
213    
214                    if(variable.scope==Scope.SCOPE_ARGUMENTS) {
215                            adapter.loadArg(0);
216                            TypeScope.invokeScope(adapter, Scope.SCOPE_ARGUMENTS);
217                            adapter.checkCast(TypeScope.SCOPE_ARGUMENT_IMPL);
218                            value.writeOut(bc, MODE_REF);
219                            adapter.invokeVirtual(TypeScope.SCOPE_ARGUMENT_IMPL,SET_ARGUMENT);
220                    }
221                    else {
222                            adapter.loadArg(0);
223                            TypeScope.invokeScope(adapter, Scope.SCOPE_UNDEFINED);
224                            Variable.registerKey(bc,LitString.toExprString(ScopeFactory.toStringScope(variable.scope,"undefined"),-1));
225                            value.writeOut(bc, MODE_REF);
226                            adapter.invokeInterface(TypeScope.SCOPES[Scope.SCOPE_UNDEFINED],METHOD_SCOPE_SET_KEY);
227                    }
228                    
229                    
230                    return Types.OBJECT;
231            }
232    
233            /**
234             * @return the value
235             */
236            public Expression getValue() {
237                    return value;
238            }
239    
240    
241            /**
242             * @return the variable
243             */
244            public Variable getVariable() {
245                    return variable;
246            }
247    }