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