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}