package railo.transformer.bytecode.op;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import railo.runtime.op.Elvis;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Literal;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.expression.ExpressionBase;
import railo.transformer.bytecode.expression.var.DataMember;
import railo.transformer.bytecode.expression.var.Member;
import railo.transformer.bytecode.expression.var.Variable;
import railo.transformer.bytecode.util.ASMUtil;
import railo.transformer.bytecode.util.ExpressionUtil;
import railo.transformer.bytecode.util.Types;
import railo.transformer.bytecode.visitor.ArrayVisitor;
public final class OpElvis extends ExpressionBase {
private static final Type ELVIS=Type.getType(Elvis.class);
public static final Method INVOKE_STR = new Method(
"operate",
Types.BOOLEAN_VALUE,
new Type[]{Types.PAGE_CONTEXT,Types.DOUBLE_VALUE,Types.STRING_ARRAY});
public static final Method INVOKE_KEY = new Method(
"operate",
Types.BOOLEAN_VALUE,
new Type[]{Types.PAGE_CONTEXT,Types.DOUBLE_VALUE,Types.COLLECTION_KEY_ARRAY});
private Variable left;
private Expression right;
/**
*
* @see railo.transformer.bytecode.expression.ExpressionBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
*/
public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
if(ASMUtil.hasOnlyDataMembers(left))return _writeOutPureDataMember(bc, mode);
Label notNull = new Label();
Label end = new Label();
GeneratorAdapter ga = bc.getAdapter();
int l = ga.newLocal(Types.OBJECT);
ExpressionUtil.visitLine(bc, left.getStart());
left.writeOut(bc, MODE_REF);
ExpressionUtil.visitLine(bc, left.getEnd());
ga.dup();
ga.storeLocal(l);
ga.visitJumpInsn(Opcodes.IFNONNULL, notNull);
ExpressionUtil.visitLine(bc, right.getStart());
right.writeOut(bc, MODE_REF);
ExpressionUtil.visitLine(bc, right.getEnd());
ga.visitJumpInsn(Opcodes.GOTO, end);
ga.visitLabel(notNull);
ga.loadLocal(l);
ga.visitLabel(end);
return Types.OBJECT;
}
public Type _writeOutPureDataMember(BytecodeContext bc, int mode) throws BytecodeException {
// TODO use function isNull for this
GeneratorAdapter adapter = bc.getAdapter();
Label yes = new Label();
Label end = new Label();
List<Member> members = left.getMembers();
// to array
Iterator<Member> it = members.iterator();
List<DataMember> list=new ArrayList<DataMember>();
while(it.hasNext()){
list.add((DataMember) it.next());
}
DataMember[] arr = list.toArray(new DataMember[members.size()]);
ExpressionUtil.visitLine(bc, left.getStart());
// public static boolean call(PageContext pc , double scope,String[] varNames)
// pc
adapter.loadArg(0);
// scope
adapter.push((double)left.getScope());
//varNames
// all literal string?
boolean allLiteral=true;
for(int i=0;i<arr.length;i++){
if(!(arr[i].getName() instanceof Literal)) allLiteral=false;
}
ArrayVisitor av=new ArrayVisitor();
if(!allLiteral) {
// String Array
av.visitBegin(adapter,Types.STRING,arr.length);
for(int i=0;i<arr.length;i++){
av.visitBeginItem(adapter, i);
arr[i].getName().writeOut(bc, MODE_REF);
av.visitEndItem(adapter);
}
}
else {
// Collection.Key Array
av.visitBegin(adapter,Types.COLLECTION_KEY,arr.length);
for(int i=0;i<arr.length;i++){
av.visitBeginItem(adapter, i);
Variable.registerKey(bc, arr[i].getName());
av.visitEndItem(adapter);
}
}
av.visitEnd();
// allowNull
//adapter.push(false);
//ASMConstants.NULL(adapter);
// call IsDefined.invoke
adapter.invokeStatic(ELVIS, allLiteral?INVOKE_KEY:INVOKE_STR);
ExpressionUtil.visitLine(bc, left.getEnd());
adapter.visitJumpInsn(Opcodes.IFEQ, yes);
// left
ExpressionUtil.visitLine(bc, left.getStart());
left.writeOut(bc, MODE_REF);
ExpressionUtil.visitLine(bc, left.getEnd());
adapter.visitJumpInsn(Opcodes.GOTO, end);
// right
ExpressionUtil.visitLine(bc, right.getStart());
adapter.visitLabel(yes);
right.writeOut(bc, MODE_REF);
ExpressionUtil.visitLine(bc, right.getEnd());
adapter.visitLabel(end);
return Types.OBJECT;
}
private OpElvis(Variable left, Expression right) {
super(left.getStart(),right.getEnd());
this.left=left;
this.right=right;
}
public static Expression toExpr(Variable left, Expression right) {
return new OpElvis(left,right);
}
}