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.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.getStart(),variable.getEnd());
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, (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=(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",getStart());
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",getStart());
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",getStart());
167                    return Variable._writeOutFirstBIF(bc,(BIF)member,mode,last,getStart());
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                            return TypeScope.invokeScope(adapter, TypeScope.METHOD_LOCAL_TOUCH,Types.PAGE_CONTEXT);
180                    }
181                    return TypeScope.invokeScope(adapter, variable.scope);
182            }
183            
184            // pc.get
185                    adapter.loadArg(0);
186                    if(last) {
187                            TypeScope.invokeScope(adapter, variable.scope);
188                            //adapter.invokeVirtual(Types.PAGE_CONTEXT,TypeScope.METHODS[variable.scope]);
189                            
190                            boolean isKey=Variable.registerKey(bc, member.getName());
191                            value.writeOut(bc, MODE_REF);
192                            
193                            if(isKey)adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET_KEY);
194                            else adapter.invokeInterface(TypeScope.SCOPES[variable.scope],METHOD_SCOPE_SET);
195                            
196                    }
197                    else {
198                            adapter.loadArg(0);
199                            TypeScope.invokeScope(adapter, variable.scope);
200                            if(Variable.registerKey(bc, member.getName()))
201                            adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH_KEY);
202                    else
203                            adapter.invokeVirtual(Types.PAGE_CONTEXT,TOUCH);
204                    }
205                    return Types.OBJECT;
206                    
207                    
208            }
209    
210            private Type _writeOutEmpty(BytecodeContext bc) throws BytecodeException {
211                    GeneratorAdapter adapter = bc.getAdapter();
212    
213                    if(variable.scope==Scope.SCOPE_ARGUMENTS) {
214                            adapter.loadArg(0);
215                            TypeScope.invokeScope(adapter, Scope.SCOPE_ARGUMENTS);
216                            value.writeOut(bc, MODE_REF);
217                            adapter.invokeInterface(TypeScope.SCOPE_ARGUMENT,SET_ARGUMENT);
218                    }
219                    else {
220                            adapter.loadArg(0);
221                            TypeScope.invokeScope(adapter, Scope.SCOPE_UNDEFINED);
222                            Variable.registerKey(bc,LitString.toExprString(ScopeFactory.toStringScope(variable.scope,"undefined")));
223                            value.writeOut(bc, MODE_REF);
224                            adapter.invokeInterface(TypeScope.SCOPES[Scope.SCOPE_UNDEFINED],METHOD_SCOPE_SET_KEY);
225                    }
226                    
227                    
228                    return Types.OBJECT;
229            }
230    
231            /**
232             * @return the value
233             */
234            public Expression getValue() {
235                    return value;
236            }
237    
238    
239            /**
240             * @return the variable
241             */
242            public Variable getVariable() {
243                    return variable;
244            }
245    }