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.op; 020 021import java.util.Iterator; 022import java.util.List; 023 024import lucee.runtime.interpreter.VariableInterpreter; 025import lucee.transformer.bytecode.BytecodeContext; 026import lucee.transformer.bytecode.BytecodeException; 027import lucee.transformer.bytecode.Position; 028import lucee.transformer.bytecode.cast.CastDouble; 029import lucee.transformer.bytecode.cast.CastString; 030import lucee.transformer.bytecode.expression.ExprDouble; 031import lucee.transformer.bytecode.expression.Expression; 032import lucee.transformer.bytecode.expression.ExpressionBase; 033import lucee.transformer.bytecode.expression.var.DataMember; 034import lucee.transformer.bytecode.expression.var.Member; 035import lucee.transformer.bytecode.expression.var.Variable; 036import lucee.transformer.bytecode.literal.LitString; 037import lucee.transformer.bytecode.util.Methods; 038import lucee.transformer.bytecode.util.Types; 039import lucee.transformer.bytecode.visitor.ArrayVisitor; 040 041import org.objectweb.asm.Type; 042import org.objectweb.asm.commons.GeneratorAdapter; 043import org.objectweb.asm.commons.Method; 044 045public class OPUnary extends ExpressionBase implements ExprDouble { 046 047 public static final short POST = 1; 048 public static final short PRE = 2; 049 050 public static final int CONCAT = 1001314342; 051 public static final int PLUS = OpDouble.PLUS; 052 public static final int MINUS = OpDouble.MINUS; 053 public static final int DIVIDE = OpDouble.DIVIDE; 054 public static final int MULTIPLY = OpDouble.MULTIPLY; 055 056 057 058 final static Method UNARY_POST_PLUS_1= new Method("unaryPoPl", 059 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 060 final static Method UNARY_POST_PLUS_N= new Method("unaryPoPl", 061 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY_ARRAY,Types.DOUBLE_VALUE}); 062 063 final static Method UNARY_POST_MINUS_N= new Method("unaryPoMi", 064 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY_ARRAY,Types.DOUBLE_VALUE}); 065 final static Method UNARY_POST_MINUS_1= new Method("unaryPoMi", 066 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 067 068 069 final static Method UNARY_PRE_PLUS_N= new Method("unaryPrPl", 070 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY_ARRAY,Types.DOUBLE_VALUE}); 071 final static Method UNARY_PRE_PLUS_1= new Method("unaryPrPl", 072 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 073 074 075 final static Method UNARY_PRE_MINUS_N= new Method("unaryPrMi", 076 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY_ARRAY,Types.DOUBLE_VALUE}); 077 final static Method UNARY_PRE_MINUS_1= new Method("unaryPrMi", 078 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 079 080 final static Method UNARY_PRE_MULTIPLY_N= new Method("unaryPrMu", 081 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY_ARRAY,Types.DOUBLE_VALUE}); 082 final static Method UNARY_PRE_MULTIPLY_1= new Method("unaryPrMu", 083 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 084 085 final static Method UNARY_PRE_DIVIDE_N= new Method("unaryPrDi", 086 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY_ARRAY,Types.DOUBLE_VALUE}); 087 final static Method UNARY_PRE_DIVIDE_1= new Method("unaryPrDi", 088 Types.DOUBLE_VALUE, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 089 090 final static Method UNARY_PRE_CONCAT_N= new Method("unaryPreConcat", 091 Types.STRING, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY_ARRAY,Types.STRING}); 092 final static Method UNARY_PRE_CONCAT_1= new Method("unaryPreConcat", 093 Types.STRING, new Type[]{Types.PAGE_CONTEXT,Types.COLLECTION_KEY,Types.STRING}); 094 095 096 097 098 099 final static Method UNARY_POST_PLUS2= new Method("unaryPoPl", 100 Types.DOUBLE_VALUE, new Type[]{Types.COLLECTION,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 101 102 final static Method UNARY_POST_MINUS2= new Method("unaryPoMi", 103 Types.DOUBLE_VALUE, new Type[]{Types.COLLECTION,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 104 105 106 final static Method UNARY_PRE_PLUS2= new Method("unaryPrPl", 107 Types.DOUBLE_VALUE, new Type[]{Types.COLLECTION,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 108 109 110 final static Method UNARY_PRE_MINUS2= new Method("unaryPrMi", 111 Types.DOUBLE_VALUE, new Type[]{Types.COLLECTION,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 112 113 final static Method UNARY_PRE_MULTIPLY2= new Method("unaryPrMu", 114 Types.DOUBLE_VALUE, new Type[]{Types.COLLECTION,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 115 116 final static Method UNARY_PRE_DIVIDE2= new Method("unaryPrDi", 117 Types.DOUBLE_VALUE, new Type[]{Types.COLLECTION,Types.COLLECTION_KEY,Types.DOUBLE_VALUE}); 118 119 final static Method UNARY_PRE_CONCAT2= new Method("unaryPreConcat", 120 Types.STRING, new Type[]{Types.COLLECTION,Types.COLLECTION_KEY,Types.STRING}); 121 122 123 124 125 private final Variable var; 126 private Expression value; 127 private final short type; 128 private final int operation; 129 130 public OPUnary(Variable var, Expression value, short type, int operation, Position start, Position end) { 131 super(start, end); 132 this.var=var; 133 this.value=value; 134 this.type=type; 135 this.operation=operation; 136 } 137 138 @Override 139 public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException { 140 GeneratorAdapter adapter = bc.getAdapter(); 141 // convert value 142 if(operation==CONCAT) value=CastString.toExprString(value); 143 else value=CastDouble.toExprDouble(value); 144 145 List<Member> members = var.getMembers(); 146 int size=members.size(); 147 148 149 String scope=VariableInterpreter.scopeInt2String(var.getScope()); 150 151 /* 152 * (susi.sorglos++ or variables.susi++) 153 */ 154 if((scope==null && size>1) || (scope!=null && size>0)) { 155 Member last = var.removeMember(members.size()-1); 156 if(!(last instanceof DataMember)) 157 throw new BytecodeException("you cannot use a unary operator with a function "+last.getClass().getName(), getStart()); 158 159 160 // write the variable 161 var.setAsCollection(Boolean.TRUE); 162 var._writeOut(bc, mode); 163 164 165 // write out last Key 166 Variable.registerKey(bc,((DataMember) last).getName()); 167 168 // write out value 169 value.writeOut(bc, MODE_VALUE); 170 171 172 if(type==POST) { 173 if(operation!=OpDouble.PLUS && operation!=OpDouble.MINUS ) 174 throw new BytecodeException("Post only possible with plus or minus "+operation, value.getStart()); 175 176 if(operation==PLUS) adapter.invokeStatic(Types.OPERATOR, UNARY_POST_PLUS2); 177 else if(operation==MINUS) adapter.invokeStatic(Types.OPERATOR, UNARY_POST_MINUS2); 178 } 179 else if(type==PRE) { 180 181 if(operation==PLUS) adapter.invokeStatic(Types.OPERATOR, UNARY_PRE_PLUS2); 182 else if(operation==MINUS) adapter.invokeStatic(Types.OPERATOR, UNARY_PRE_MINUS2); 183 else if(operation==DIVIDE) adapter.invokeStatic(Types.OPERATOR, UNARY_PRE_DIVIDE2); 184 else if(operation==MULTIPLY) adapter.invokeStatic(Types.OPERATOR, UNARY_PRE_MULTIPLY2); 185 else if(operation==CONCAT) adapter.invokeStatic(Types.OPERATOR, UNARY_PRE_CONCAT2); 186 } 187 188 if(operation==CONCAT) return Types.STRING; 189 190 // convert from Double to double (if necessary) 191 if(mode==MODE_REF) { 192 adapter.invokeStatic(Types.CASTER,Methods.METHOD_TO_DOUBLE_FROM_DOUBLE); 193 return Types.DOUBLE; 194 } 195 return Types.DOUBLE_VALUE; 196 } 197 198 199 200 /* 201 * undefined scope only with one key (susi++;) 202 */ 203 204 // PageContext instance 205 adapter.loadArg(0); 206 207 208 // Collection key Array 209 int arrSize=scope!=null?members.size()+1:members.size(); 210 boolean useArray = arrSize>1 || scope!=null; 211 if(useArray) { 212 ArrayVisitor av=new ArrayVisitor(); 213 int index=0; 214 av.visitBegin(adapter, Types.COLLECTION_KEY, arrSize); 215 Iterator<Member> it = members.iterator(); 216 Member m;DataMember dm; 217 218 if(scope!=null) { 219 av.visitBeginItem(adapter, index++); 220 Variable.registerKey(bc,LitString.toExprString(scope)); 221 av.visitEndItem(adapter); 222 } 223 224 while(it.hasNext()){ 225 av.visitBeginItem(adapter, index++); 226 m = it.next(); 227 if(!(m instanceof DataMember)) throw new BytecodeException("you cannot use a unary operator with a function "+m.getClass().getName(), getStart()); 228 Variable.registerKey(bc,((DataMember) m).getName()); 229 av.visitEndItem(adapter); 230 } 231 av.visitEnd(); 232 } 233 else { 234 Member m = members.iterator().next(); 235 if(!(m instanceof DataMember)) throw new BytecodeException("you cannot use a unary operator with a function "+m.getClass().getName(), getStart()); 236 Variable.registerKey(bc,((DataMember) m).getName()); 237 } 238 239 if(type==POST) { 240 if(operation!=OpDouble.PLUS && operation!=OpDouble.MINUS ) throw new BytecodeException("Post only possible with plus or minus "+operation, value.getStart()); 241 242 value.writeOut(bc, MODE_VALUE); 243 if(operation==PLUS) adapter.invokeStatic(Types.OPERATOR, useArray?UNARY_POST_PLUS_N:UNARY_POST_PLUS_1); 244 else if(operation==MINUS) adapter.invokeStatic(Types.OPERATOR, useArray?UNARY_POST_MINUS_N:UNARY_POST_MINUS_1); 245 } 246 else if(type==PRE) { 247 value.writeOut(bc, MODE_VALUE); 248 249 if(operation==PLUS) adapter.invokeStatic(Types.OPERATOR, useArray?UNARY_PRE_PLUS_N:UNARY_PRE_PLUS_1); 250 else if(operation==MINUS) adapter.invokeStatic(Types.OPERATOR, useArray?UNARY_PRE_MINUS_N:UNARY_PRE_MINUS_1); 251 else if(operation==DIVIDE) adapter.invokeStatic(Types.OPERATOR, useArray?UNARY_PRE_DIVIDE_N:UNARY_PRE_DIVIDE_1); 252 else if(operation==MULTIPLY) adapter.invokeStatic(Types.OPERATOR, useArray?UNARY_PRE_MULTIPLY_N:UNARY_PRE_MULTIPLY_1); 253 else if(operation==CONCAT) adapter.invokeStatic(Types.OPERATOR, useArray?UNARY_PRE_CONCAT_N:UNARY_PRE_CONCAT_1); 254 } 255 256 if(operation==CONCAT) return Types.STRING; 257 258 // convert from double to Double (if necessary) 259 if(mode==MODE_REF) { 260 adapter.invokeStatic(Types.CASTER,Methods.METHOD_TO_DOUBLE_FROM_DOUBLE); 261 return Types.DOUBLE; 262 } 263 return Types.DOUBLE_VALUE; 264 } 265}