001 package railo.transformer.bytecode.cast; 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.commons.lang.ClassException; 008 import railo.commons.lang.ClassUtil; 009 import railo.commons.lang.StringUtil; 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.expression.var.VariableString; 015 import railo.transformer.bytecode.util.Methods_Caster; 016 import railo.transformer.bytecode.util.Types; 017 018 /** 019 * cast a Expression to a Double 020 */ 021 public final class Cast extends ExpressionBase { 022 // TODO support short type 023 private Expression expr; 024 private String type; 025 private String lcType; 026 027 private Cast(Expression expr, String type, String lcType) { 028 super(expr.getLine()); 029 this.expr=expr; 030 this.type=type; 031 this.lcType=lcType; 032 033 } 034 035 public static Expression toExpression(Expression expr, String type) { 036 if(type==null) return expr; 037 038 String lcType=StringUtil.toLowerCase(type); 039 switch(lcType.charAt(0)) { 040 case 'a': 041 if("any".equals(lcType)) { 042 return expr; 043 } 044 break; 045 case 'b': 046 if("boolean".equals(type) || "bool".equals(lcType)) return CastBoolean.toExprBoolean(expr); 047 break; 048 case 'd': 049 if("double".equals(type)) return CastDouble.toExprDouble(expr); 050 break; 051 case 'n': 052 if("number".equals(lcType) || "numeric".equals(lcType))return CastDouble.toExprDouble(expr); 053 break; 054 case 'o': 055 if("object".equals(lcType)) { 056 return expr; 057 } 058 break; 059 case 's': 060 if("string".equals(lcType)) return CastString.toExprString(expr); 061 //if("string_array".equals(lcType)) return StringArray.toExpr(expr); 062 break; 063 case 'u': 064 if("uuid".equals(lcType)) return CastString.toExprString(expr); 065 break; 066 case 'v': 067 if("variablename".equals(lcType)) return VariableString.toExprString(expr); 068 if("variable_name".equals(lcType)) return VariableString.toExprString(expr); 069 if("variablestring".equals(lcType)) return VariableString.toExprString(expr); 070 if("variable_string".equals(lcType)) return VariableString.toExprString(expr); 071 if("void".equals(lcType)) return expr; 072 break; 073 074 075 076 077 } 078 return new Cast(expr,type,lcType); 079 } 080 081 // Array toArray(Object) 082 final public static Method TO_ARRAY = new Method("toArray", 083 Types.ARRAY, 084 new Type[]{Types.OBJECT}); 085 086 // String toBase64 (Object); 087 final public static Method TO_BASE64 = new Method("toBase64", 088 Types.STRING, 089 new Type[]{Types.OBJECT}); 090 091 // byte[] toBinary (Object) 092 final public static Method TO_BINARY = new Method("toBinary", 093 Types.BYTE_VALUE_ARRAY, 094 new Type[]{Types.OBJECT}); 095 096 // byte[] toCollection (Object) 097 final public static Method TO_COLLECTION = new Method("toCollection", 098 Types.BYTE_VALUE_ARRAY, 099 new Type[]{Types.OBJECT}); 100 101 // railo.runtime.Component toComponent (Object) 102 final public static Method TO_COMPONENT = new Method("toComponent", 103 Types.COMPONENT, 104 new Type[]{Types.OBJECT}); 105 106 107 // String toDecimal (Object) 108 final public static Method TO_DECIMAL = new Method("toDecimal", 109 Types.STRING, 110 new Type[]{Types.OBJECT}); 111 112 // railo.runtime.config.Config getConfig () 113 final public static Method GET_CONFIG = new Method("getConfig", 114 Types.CONFIG_WEB, 115 new Type[]{}); 116 117 //java.util.TimeZone getTimeZone () 118 final public static Method GET_TIMEZONE = new Method("getTimeZone", 119 Types.TIMEZONE, 120 new Type[]{}); 121 122 123 /** 124 * @see railo.transformer.bytecode.expression.Expression#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int) 125 */ 126 public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException { 127 //Caster.toDecimal(null); 128 GeneratorAdapter adapter = bc.getAdapter(); 129 char first=lcType.charAt(0); 130 Type rtn; 131 132 switch(first) { 133 case 'a': 134 if("array".equals(lcType)) { 135 rtn=expr.writeOut(bc,MODE_REF); 136 if(!rtn.equals(Types.ARRAY)) 137 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_ARRAY); 138 return Types.ARRAY; 139 } 140 break; 141 case 'b': 142 if("base64".equals(lcType)) { 143 expr.writeOut(bc,MODE_REF); 144 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BASE64); 145 return Types.STRING; 146 } 147 if("binary".equals(lcType)) { 148 rtn=expr.writeOut(bc,MODE_REF); 149 if(!rtn.equals(Types.BYTE_VALUE_ARRAY)) 150 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BINARY); 151 return Types.BYTE_VALUE_ARRAY; 152 } 153 if("byte".equals(type)) { 154 rtn=expr.writeOut(bc,MODE_VALUE); 155 if(!rtn.equals(Types.BYTE_VALUE)) 156 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE_VALUE[Types.getType(rtn)]); 157 return Types.BYTE_VALUE; 158 } 159 if("byte".equals(lcType)) { 160 rtn=expr.writeOut(bc,MODE_REF); 161 if(!rtn.equals(Types.BYTE)) 162 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE[Types.getType(rtn)]); 163 return Types.BYTE; 164 } 165 if("boolean".equals(lcType)) { 166 return CastBoolean.toExprBoolean(expr).writeOut(bc, MODE_REF); 167 } 168 break; 169 case 'c': 170 if("char".equals(lcType)) { 171 rtn=expr.writeOut(bc,MODE_VALUE); 172 if(!rtn.equals(Types.CHAR)) 173 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHAR_VALUE[Types.getType(rtn)]); 174 return Types.CHAR; 175 } 176 if("character".equals(lcType)) { 177 rtn=expr.writeOut(bc,MODE_REF); 178 if(!rtn.equals(Types.CHARACTER)) 179 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHARACTER[Types.getType(rtn)]); 180 return Types.CHARACTER; 181 } 182 if("collection".equals(lcType)) { 183 rtn=expr.writeOut(bc,MODE_REF); 184 if(!rtn.equals(Types.COLLECTION)) 185 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_COLLECTION); 186 return Types.COLLECTION; 187 } 188 if("component".equals(lcType)) { 189 rtn=expr.writeOut(bc,MODE_REF); 190 if(!rtn.equals(Types.COMPONENT)) 191 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_COMPONENT); 192 return Types.COMPONENT; 193 } 194 break; 195 case 'd': 196 if("double".equals(lcType)) { 197 return CastDouble.toExprDouble(expr).writeOut(bc, MODE_REF); 198 } 199 if("date".equals(lcType) || "datetime".equals(lcType)) { 200 // First Arg 201 rtn=expr.writeOut(bc,MODE_REF); 202 if(rtn.equals(Types.DATE_TIME)) return Types.DATE_TIME; 203 204 int type=Types.getType(rtn); 205 206 // Second Arg 207 adapter.loadArg(0); 208 adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_CONFIG); 209 adapter.invokeInterface(Types.CONFIG_WEB,GET_TIMEZONE); 210 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DATE[type]); 211 return Types.DATE_TIME; 212 } 213 if("decimal".equals(lcType)) { 214 rtn=expr.writeOut(bc,MODE_REF); 215 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DECIMAL[Types.getType(rtn)]); 216 return Types.STRING; 217 } 218 break; 219 case 'f': 220 if("file".equals(lcType)) { 221 rtn=expr.writeOut(bc,MODE_REF); 222 if(!rtn.equals(Types.FILE)) 223 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FILE); 224 return Types.FILE; 225 } 226 if("float".equals(type)) { 227 rtn=expr.writeOut(bc,MODE_VALUE); 228 if(!rtn.equals(Types.FLOAT_VALUE)) 229 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT_VALUE[Types.getType(rtn)]); 230 return Types.FLOAT_VALUE; 231 } 232 if("float".equals(lcType)) { 233 rtn=expr.writeOut(bc,MODE_REF); 234 if(!rtn.equals(Types.FLOAT)) 235 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT[Types.getType(rtn)]); 236 return Types.FLOAT; 237 } 238 break; 239 case 'i': 240 if("int".equals(lcType)) { 241 rtn=expr.writeOut(bc,MODE_VALUE); 242 if(!rtn.equals(Types.INT_VALUE)) 243 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INT_VALUE[Types.getType(rtn)]); 244 return Types.INT_VALUE; 245 } 246 if("integer".equals(lcType)) { 247 rtn=expr.writeOut(bc,MODE_REF); 248 if(!rtn.equals(Types.INTEGER)) 249 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INTEGER[Types.getType(rtn)]); 250 return Types.INTEGER; 251 } 252 break; 253 case 'j': 254 255 if("java.lang.boolean".equals(lcType)) { 256 return CastBoolean.toExprBoolean(expr).writeOut(bc, MODE_REF); 257 } 258 if("java.lang.double".equals(lcType)) { 259 return CastDouble.toExprDouble(expr).writeOut(bc, MODE_REF); 260 } 261 if("java.lang.string".equals(lcType)) { 262 return CastString.toExprString(expr).writeOut(bc, MODE_REF); 263 } 264 if("java.lang.stringbuffer".equals(lcType)) { 265 rtn=expr.writeOut(bc,MODE_REF); 266 if(!rtn.equals(Types.STRING_BUFFER)) 267 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRING_BUFFER); 268 return Types.STRING_BUFFER; 269 } 270 if("java.lang.byte".equals(lcType)) { 271 rtn=expr.writeOut(bc,MODE_REF); 272 if(!rtn.equals(Types.BYTE)) 273 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE[Types.getType(rtn)]); 274 return Types.BYTE; 275 } 276 if("java.lang.character".equals(lcType)) { 277 rtn=expr.writeOut(bc,MODE_REF); 278 if(!rtn.equals(Types.CHARACTER)) 279 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHARACTER[Types.getType(rtn)]); 280 return Types.CHARACTER; 281 } 282 if("java.lang.short".equals(lcType)) { 283 rtn=expr.writeOut(bc,MODE_REF); 284 if(!rtn.equals(Types.SHORT)) 285 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT[Types.getType(rtn)]); 286 return Types.SHORT; 287 } 288 if("java.lang.integer".equals(lcType)) { 289 rtn=expr.writeOut(bc,MODE_REF); 290 if(!rtn.equals(Types.INTEGER)) 291 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INTEGER[Types.getType(rtn)]); 292 return Types.INTEGER; 293 } 294 if("java.lang.long".equals(lcType)) { 295 rtn=expr.writeOut(bc,MODE_REF); 296 if(!rtn.equals(Types.LONG)) 297 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG[Types.getType(rtn)]); 298 return Types.LONG; 299 } 300 if("java.lang.float".equals(lcType)) { 301 rtn=expr.writeOut(bc,MODE_REF); 302 if(!rtn.equals(Types.FLOAT)) 303 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT[Types.getType(rtn)]); 304 return Types.FLOAT; 305 } 306 if("java.io.file".equals(lcType)) { 307 rtn=expr.writeOut(bc,MODE_REF); 308 if(!rtn.equals(Types.FILE)) 309 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FILE); 310 return Types.FILE; 311 } 312 if("java.lang.object".equals(lcType)) { 313 return expr.writeOut(bc,MODE_REF); 314 } 315 else if("java.util.date".equals(lcType)) { 316 // First Arg 317 rtn=expr.writeOut(bc,MODE_REF); 318 if(rtn.equals(Types.DATE)) return Types.DATE; 319 if(rtn.equals(Types.DATE_TIME)) return Types.DATE_TIME; 320 321 // Second Arg 322 adapter.loadArg(0); 323 adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_CONFIG); 324 adapter.invokeVirtual(Types.CONFIG_WEB,GET_TIMEZONE); 325 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DATE[Types.getType(rtn)]); 326 return Types.DATE_TIME; 327 } 328 break; 329 case 'l': 330 if("long".equals(type)) { 331 rtn=expr.writeOut(bc,MODE_VALUE); 332 if(!rtn.equals(Types.LONG_VALUE)) 333 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG_VALUE[Types.getType(rtn)]); 334 return Types.LONG_VALUE; 335 } 336 else if("long".equals(lcType)) { 337 rtn=expr.writeOut(bc,MODE_REF); 338 if(!rtn.equals(Types.LONG)) 339 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG[Types.getType(rtn)]); 340 return Types.LONG; 341 } 342 break; 343 case 'n': 344 if("node".equals(lcType)) { 345 rtn=expr.writeOut(bc,MODE_REF); 346 if(!rtn.equals(Types.NODE)) 347 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NODE); 348 return Types.NODE; 349 } 350 else if("null".equals(lcType)) { 351 expr.writeOut(bc,MODE_REF); 352 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NULL); 353 // TODO gibt es einen null typ? 354 return Types.OBJECT; 355 } 356 break; 357 case 'o': 358 if("object".equals(lcType) || "other".equals(lcType)) { 359 expr.writeOut(bc,MODE_REF); 360 return Types.OBJECT; 361 } 362 break; 363 case 's': 364 if("struct".equals(lcType)) { 365 rtn=expr.writeOut(bc,MODE_REF); 366 if(!rtn.equals(Types.STRUCT)) 367 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRUCT); 368 return Types.STRUCT; 369 } 370 if("short".equals(type)) { 371 rtn=expr.writeOut(bc,MODE_VALUE); 372 if(!rtn.equals(Types.SHORT_VALUE)) 373 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT_VALUE[Types.getType(rtn)]); 374 return Types.SHORT_VALUE; 375 } 376 if("short".equals(lcType)) { 377 rtn=expr.writeOut(bc,MODE_REF); 378 if(!rtn.equals(Types.SHORT)) 379 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT[Types.getType(rtn)]); 380 return Types.SHORT; 381 } 382 if("stringbuffer".equals(lcType)) { 383 rtn=expr.writeOut(bc,MODE_REF); 384 if(!rtn.equals(Types.STRING_BUFFER)) 385 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRING_BUFFER); 386 return Types.STRING_BUFFER; 387 } 388 break; 389 390 case 'x': 391 if("xml".equals(lcType)) { 392 rtn=expr.writeOut(bc,MODE_REF); 393 if(!rtn.equals(Types.NODE)) 394 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NODE); 395 return Types.NODE; 396 } 397 break; 398 default: 399 if("query".equals(lcType)) { 400 rtn=expr.writeOut(bc,MODE_REF); 401 if(!rtn.equals(Types.QUERY)) 402 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_QUERY); 403 return Types.QUERY; 404 } 405 else if("timespan".equals(lcType)) { 406 rtn=expr.writeOut(bc,MODE_REF); 407 if(!rtn.equals(Types.TIMESPAN)) 408 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_TIMESPAN); 409 return Types.TIMESPAN; 410 } 411 } 412 Type t=getType(type); 413 414 expr.writeOut(bc,MODE_REF); 415 adapter.checkCast(t); 416 return t; 417 } 418 419 /* 420 private int writeExprx(BytecodeContext bc) throws TemplateException { 421 return Types.getType(expr.writeOut(bc,MODE_VALUE)); 422 }*/ 423 424 425 426 public static Type getType(String type) throws BytecodeException { 427 if(StringUtil.isEmpty(type)) return Types.OBJECT; 428 429 430 String lcType=StringUtil.toLowerCase(type); 431 switch(lcType.charAt(0)) { 432 case 'a': 433 if("any".equals(lcType)) return Types.OBJECT; 434 if("array".equals(lcType)) return Types.ARRAY; 435 break; 436 case 'b': 437 if("bool".equals(lcType) || "boolean".equals(type)) return Types.BOOLEAN_VALUE; 438 if("boolean".equals(lcType)) return Types.BOOLEAN; 439 if("base64".equals(lcType)) return Types.STRING; 440 441 if("binary".equals(lcType)) return Types.BYTE_VALUE_ARRAY; 442 if("byte".equals(type)) return Types.BYTE_VALUE; 443 if("byte".equals(lcType)) return Types.BYTE; 444 445 break; 446 447 case 'c': 448 if("char".equals(lcType)) return Types.CHAR; 449 if("character".equals(lcType)) return Types.CHARACTER; 450 if("collection".equals(lcType)) return Types.COLLECTION; 451 if("component".equals(lcType)) return Types.COMPONENT; 452 break; 453 454 case 'd': 455 if("double".equals(type)) return Types.DOUBLE_VALUE; 456 if("double".equals(lcType)) return Types.DOUBLE; 457 458 if("date".equals(lcType) || "datetime".equals(lcType))return Types.DATE_TIME; 459 if("decimal".equals(lcType)) return Types.STRING; 460 461 break; 462 463 case 'f': 464 if("file".equals(lcType)) return Types.FILE; 465 if("float".equals(type)) return Types.FLOAT_VALUE; 466 if("float".equals(lcType)) return Types.FLOAT; 467 break; 468 469 case 'i': 470 if("int".equals(lcType)) return Types.INT_VALUE; 471 if("integer".equals(lcType)) return Types.INTEGER; 472 break; 473 474 case 'l': 475 if("long".equals(type)) return Types.LONG_VALUE; 476 if("long".equals(lcType)) return Types.LONG; 477 break; 478 case 'n': 479 if("node".equals(lcType)) return Types.NODE; 480 if("null".equals(lcType)) return Types.OBJECT; 481 if("number".equals(lcType)) return Types.DOUBLE_VALUE; 482 if("numeric".equals(lcType)) return Types.DOUBLE_VALUE; 483 break; 484 case 's': 485 if("string".equals(lcType)) return Types.STRING; 486 if("struct".equals(lcType)) return Types.STRUCT; 487 if("short".equals(type)) return Types.SHORT_VALUE; 488 if("short".equals(lcType)) return Types.SHORT; 489 break; 490 case 'o': 491 if("other".equals(lcType)) return Types.OBJECT; 492 if("object".equals(lcType)) return Types.OBJECT; 493 break; 494 case 'u': 495 if("uuid".equals(lcType)) return Types.STRING; 496 break; 497 case 'q': 498 if("query".equals(lcType)) return Types.QUERY; 499 break; 500 case 't': 501 if("timespan".equals(lcType)) return Types.TIMESPAN; 502 break; 503 case 'v': 504 if("variablename".equals(lcType)) return Types.STRING; 505 if("variable_name".equals(lcType)) return Types.STRING; 506 if("variablestring".equals(lcType)) return Types.STRING; 507 if("variable_string".equals(lcType)) return Types.STRING; 508 if("void".equals(lcType)) return Types.VOID; 509 break; 510 case 'x': 511 if("xml".equals(lcType)) return Types.NODE; 512 break; 513 } 514 try { 515 return Type.getType(ClassUtil.loadClass(type)); 516 } 517 catch (ClassException e) { 518 throw new BytecodeException(e.getMessage(),-1); 519 } 520 521 } 522 523 /** 524 * @return the expr 525 */ 526 public Expression getExpr() { 527 return expr; 528 } 529 530 /** 531 * @return the type 532 */ 533 public String getType() { 534 return type; 535 } 536 537 } 538 539 540 541