package railo.transformer.bytecode.cast;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import railo.commons.lang.ClassException;
import railo.commons.lang.ClassUtil;
import railo.commons.lang.StringUtil;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.expression.ExpressionBase;
import railo.transformer.bytecode.expression.var.Variable;
import railo.transformer.bytecode.expression.var.VariableString;
import railo.transformer.bytecode.util.Methods_Caster;
import railo.transformer.bytecode.util.Types;
/**
* cast a Expression to a Double
*/
public final class CastOther extends ExpressionBase implements Cast {
// TODO support short type
private Expression expr;
private String type;
private String lcType;
private CastOther(Expression expr, String type, String lcType) {
super(expr.getStart(),expr.getEnd());
this.expr=expr;
this.type=type;
this.lcType=lcType;
}
public static Expression toExpression(Expression expr, String type) {
if(type==null) return expr;
String lcType=StringUtil.toLowerCase(type);
switch(lcType.charAt(0)) {
case 'a':
if("any".equals(lcType)) {
return expr;
}
break;
case 'b':
if("boolean".equals(type) || "bool".equals(lcType)) return CastBoolean.toExprBoolean(expr);
break;
case 'd':
if("double".equals(type)) return CastDouble.toExprDouble(expr);
break;
case 'i':
if("int".equals(lcType)) return CastInt.toExprInt(expr);
case 'n':
if("number".equals(lcType) || "numeric".equals(lcType))return CastDouble.toExprDouble(expr);
break;
case 'o':
if("object".equals(lcType)) {
return expr;
}
break;
case 's':
if("string".equals(lcType)) return CastString.toExprString(expr);
//if("string_array".equals(lcType)) return StringArray.toExpr(expr);
break;
case 'u':
if("uuid".equals(lcType)) return CastString.toExprString(expr);
break;
case 'v':
if("variablename".equals(lcType)) return VariableString.toExprString(expr);
if("variable_name".equals(lcType)) return VariableString.toExprString(expr);
if("variablestring".equals(lcType)) return VariableString.toExprString(expr);
if("variable_string".equals(lcType)) return VariableString.toExprString(expr);
if("void".equals(lcType)) return expr;
break;
}
return new CastOther(expr,type,lcType);
}
// Array toArray(Object)
final public static Method TO_ARRAY = new Method("toArray",
Types.ARRAY,
new Type[]{Types.OBJECT});
// String toBase64 (Object);
final public static Method TO_BASE64 = new Method("toBase64",
Types.STRING,
new Type[]{Types.OBJECT});
// byte[] toBinary (Object)
final public static Method TO_BINARY = new Method("toBinary",
Types.BYTE_VALUE_ARRAY,
new Type[]{Types.OBJECT});
// byte[] toCollection (Object)
final public static Method TO_COLLECTION = new Method("toCollection",
Types.BYTE_VALUE_ARRAY,
new Type[]{Types.OBJECT});
// railo.runtime.Component toComponent (Object)
final public static Method TO_COMPONENT = new Method("toComponent",
Types.COMPONENT,
new Type[]{Types.OBJECT});
// String toDecimal (Object)
final public static Method TO_DECIMAL = new Method("toDecimal",
Types.STRING,
new Type[]{Types.OBJECT});
// railo.runtime.config.Config getConfig ()
final public static Method GET_CONFIG = new Method("getConfig",
Types.CONFIG_WEB,
new Type[]{});
//java.util.TimeZone getTimeZone ()
final public static Method GET_TIMEZONE = new Method("getTimeZone",
Types.TIMEZONE,
new Type[]{});
// Excel toExcel (Object)
final public static Method TO_EXCEL = new Method("toExcel",
Types.EXCEL,
new Type[]{Types.OBJECT});
/**
* @see railo.transformer.bytecode.expression.Expression#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
*/
public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
//Caster.toDecimal(null);
GeneratorAdapter adapter = bc.getAdapter();
char first=lcType.charAt(0);
Type rtn;
switch(first) {
case 'a':
if("array".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.ARRAY))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_ARRAY);
return Types.ARRAY;
}
break;
case 'b':
if("base64".equals(lcType)) {
expr.writeOut(bc,MODE_REF);
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BASE64);
return Types.STRING;
}
if("binary".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.BYTE_VALUE_ARRAY))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BINARY);
return Types.BYTE_VALUE_ARRAY;
}
if("byte".equals(type)) {
rtn=expr.writeOut(bc,MODE_VALUE);
if(!rtn.equals(Types.BYTE_VALUE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE_VALUE[Types.getType(rtn)]);
return Types.BYTE_VALUE;
}
if("byte".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.BYTE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE[Types.getType(rtn)]);
return Types.BYTE;
}
if("boolean".equals(lcType)) {
return CastBoolean.toExprBoolean(expr).writeOut(bc, MODE_REF);
}
break;
case 'c':
if("char".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_VALUE);
if(!rtn.equals(Types.CHAR))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHAR_VALUE[Types.getType(rtn)]);
return Types.CHAR;
}
if("character".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.CHARACTER))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHARACTER[Types.getType(rtn)]);
return Types.CHARACTER;
}
if("collection".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.COLLECTION))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_COLLECTION);
return Types.COLLECTION;
}
if("component".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.COMPONENT))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_COMPONENT);
return Types.COMPONENT;
}
break;
case 'd':
if("double".equals(lcType)) {
return CastDouble.toExprDouble(expr).writeOut(bc, MODE_REF);
}
if("date".equals(lcType) || "datetime".equals(lcType)) {
// First Arg
rtn=expr.writeOut(bc,MODE_REF);
if(rtn.equals(Types.DATE_TIME)) return Types.DATE_TIME;
int type=Types.getType(rtn);
// Second Arg
adapter.loadArg(0);
adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_CONFIG);
adapter.invokeInterface(Types.CONFIG_WEB,GET_TIMEZONE);
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DATE[type]);
return Types.DATE_TIME;
}
if("decimal".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DECIMAL[Types.getType(rtn)]);
return Types.STRING;
}
break;
case 'e':
if("excel".equals(type)) {
expr.writeOut(bc,MODE_REF);
adapter.invokeStatic(Types.EXCEL_UTIL,TO_EXCEL);
return Types.EXCEL;
}
break;
case 'f':
if("file".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.FILE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FILE);
return Types.FILE;
}
if("float".equals(type)) {
rtn=expr.writeOut(bc,MODE_VALUE);
if(!rtn.equals(Types.FLOAT_VALUE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT_VALUE[Types.getType(rtn)]);
return Types.FLOAT_VALUE;
}
if("float".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.FLOAT))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT[Types.getType(rtn)]);
return Types.FLOAT;
}
break;
case 'i':
if("int".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_VALUE);
if(!rtn.equals(Types.INT_VALUE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INT_VALUE[Types.getType(rtn)]);
return Types.INT_VALUE;
}
if("integer".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.INTEGER))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INTEGER[Types.getType(rtn)]);
return Types.INTEGER;
}
break;
case 'j':
if("java.lang.boolean".equals(lcType)) {
return CastBoolean.toExprBoolean(expr).writeOut(bc, MODE_REF);
}
if("java.lang.double".equals(lcType)) {
return CastDouble.toExprDouble(expr).writeOut(bc, MODE_REF);
}
if("java.lang.string".equals(lcType)) {
return CastString.toExprString(expr).writeOut(bc, MODE_REF);
}
if("java.lang.stringbuffer".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.STRING_BUFFER))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRING_BUFFER);
return Types.STRING_BUFFER;
}
if("java.lang.byte".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.BYTE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE[Types.getType(rtn)]);
return Types.BYTE;
}
if("java.lang.character".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.CHARACTER))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHARACTER[Types.getType(rtn)]);
return Types.CHARACTER;
}
if("java.lang.short".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.SHORT))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT[Types.getType(rtn)]);
return Types.SHORT;
}
if("java.lang.integer".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.INTEGER))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INTEGER[Types.getType(rtn)]);
return Types.INTEGER;
}
if("java.lang.long".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.LONG))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG[Types.getType(rtn)]);
return Types.LONG;
}
if("java.lang.float".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.FLOAT))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT[Types.getType(rtn)]);
return Types.FLOAT;
}
if("java.io.file".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.FILE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FILE);
return Types.FILE;
}
if("java.lang.object".equals(lcType)) {
return expr.writeOut(bc,MODE_REF);
}
else if("java.util.date".equals(lcType)) {
// First Arg
rtn=expr.writeOut(bc,MODE_REF);
if(rtn.equals(Types.DATE)) return Types.DATE;
if(rtn.equals(Types.DATE_TIME)) return Types.DATE_TIME;
// Second Arg
adapter.loadArg(0);
adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_CONFIG);
adapter.invokeVirtual(Types.CONFIG_WEB,GET_TIMEZONE);
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DATE[Types.getType(rtn)]);
return Types.DATE_TIME;
}
break;
case 'l':
if("long".equals(type)) {
rtn=expr.writeOut(bc,MODE_VALUE);
if(!rtn.equals(Types.LONG_VALUE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG_VALUE[Types.getType(rtn)]);
return Types.LONG_VALUE;
}
else if("long".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.LONG))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG[Types.getType(rtn)]);
return Types.LONG;
}
break;
case 'n':
if("node".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.NODE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NODE);
return Types.NODE;
}
else if("null".equals(lcType)) {
expr.writeOut(bc,MODE_REF);
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NULL);
// TODO gibt es einen null typ?
return Types.OBJECT;
}
break;
case 'o':
if("object".equals(lcType) || "other".equals(lcType)) {
expr.writeOut(bc,MODE_REF);
return Types.OBJECT;
}
break;
case 's':
if("struct".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.STRUCT))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRUCT);
return Types.STRUCT;
}
if("short".equals(type)) {
rtn=expr.writeOut(bc,MODE_VALUE);
if(!rtn.equals(Types.SHORT_VALUE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT_VALUE[Types.getType(rtn)]);
return Types.SHORT_VALUE;
}
if("short".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.SHORT))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT[Types.getType(rtn)]);
return Types.SHORT;
}
if("stringbuffer".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.STRING_BUFFER))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRING_BUFFER);
return Types.STRING_BUFFER;
}
break;
case 'x':
if("xml".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.NODE))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NODE);
return Types.NODE;
}
break;
default:
if("query".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.QUERY))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_QUERY);
return Types.QUERY;
}
if("querycolumn".equals(lcType)) {
rtn=(expr instanceof Variable)?((Variable)expr).writeOutCollection(bc, mode):expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.QUERY_COLUMN)) {
adapter.loadArg(0);
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_QUERY_COLUMN);
}
return Types.QUERY_COLUMN;
}
else if("timespan".equals(lcType)) {
rtn=expr.writeOut(bc,MODE_REF);
if(!rtn.equals(Types.TIMESPAN))
adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_TIMESPAN);
return Types.TIMESPAN;
}
}
Type t=getType(type);
expr.writeOut(bc,MODE_REF);
adapter.checkCast(t);
return t;
}
/*
private int writeExprx(BytecodeContext bc) throws TemplateException {
return Types.getType(expr.writeOut(bc,MODE_VALUE));
}*/
public static Type getType(String type) throws BytecodeException {
if(StringUtil.isEmpty(type)) return Types.OBJECT;
String lcType=StringUtil.toLowerCase(type);
switch(lcType.charAt(0)) {
case 'a':
if("any".equals(lcType)) return Types.OBJECT;
if("array".equals(lcType)) return Types.ARRAY;
break;
case 'b':
if("bool".equals(lcType) || "boolean".equals(type)) return Types.BOOLEAN_VALUE;
if("boolean".equals(lcType)) return Types.BOOLEAN;
if("base64".equals(lcType)) return Types.STRING;
if("binary".equals(lcType)) return Types.BYTE_VALUE_ARRAY;
if("byte".equals(type)) return Types.BYTE_VALUE;
if("byte".equals(lcType)) return Types.BYTE;
break;
case 'c':
if("char".equals(lcType)) return Types.CHAR;
if("character".equals(lcType)) return Types.CHARACTER;
if("collection".equals(lcType)) return Types.COLLECTION;
if("component".equals(lcType)) return Types.COMPONENT;
break;
case 'd':
if("double".equals(type)) return Types.DOUBLE_VALUE;
if("double".equals(lcType)) return Types.DOUBLE;
if("date".equals(lcType) || "datetime".equals(lcType))return Types.DATE_TIME;
if("decimal".equals(lcType)) return Types.STRING;
break;
case 'e':
if("excel".equals(lcType)) return Types.EXCEL;
break;
case 'f':
if("file".equals(lcType)) return Types.FILE;
if("float".equals(type)) return Types.FLOAT_VALUE;
if("float".equals(lcType)) return Types.FLOAT;
if("function".equals(lcType)) return Types.UDF;
break;
case 'i':
if("int".equals(lcType)) return Types.INT_VALUE;
if("integer".equals(lcType)) return Types.INTEGER;
break;
case 'l':
if("long".equals(type)) return Types.LONG_VALUE;
if("long".equals(lcType)) return Types.LONG;
break;
case 'n':
if("node".equals(lcType)) return Types.NODE;
if("null".equals(lcType)) return Types.OBJECT;
if("number".equals(lcType)) return Types.DOUBLE_VALUE;
if("numeric".equals(lcType)) return Types.DOUBLE_VALUE;
break;
case 's':
if("string".equals(lcType)) return Types.STRING;
if("struct".equals(lcType)) return Types.STRUCT;
if("short".equals(type)) return Types.SHORT_VALUE;
if("short".equals(lcType)) return Types.SHORT;
break;
case 'o':
if("other".equals(lcType)) return Types.OBJECT;
if("object".equals(lcType)) return Types.OBJECT;
break;
case 'u':
if("uuid".equals(lcType)) return Types.STRING;
if("udf".equals(lcType)) return Types.UDF;
break;
case 'q':
if("query".equals(lcType)) return Types.QUERY;
if("querycolumn".equals(lcType)) return Types.QUERY_COLUMN;
break;
case 't':
if("timespan".equals(lcType)) return Types.TIMESPAN;
break;
case 'v':
if("variablename".equals(lcType)) return Types.STRING;
if("variable_name".equals(lcType)) return Types.STRING;
if("variablestring".equals(lcType)) return Types.STRING;
if("variable_string".equals(lcType)) return Types.STRING;
if("void".equals(lcType)) return Types.VOID;
break;
case 'x':
if("xml".equals(lcType)) return Types.NODE;
break;
}
try {
return Type.getType(ClassUtil.loadClass(type));
}
catch (ClassException e) {
throw new BytecodeException(e.getMessage(),null);
}
}
@Override
public Expression getExpr() {
return expr;
}
/**
* @return the type
*/
public String getType() {
return type;
}
}