package railo.transformer.bytecode.op;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import railo.runtime.exp.TemplateException;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Literal;
import railo.transformer.bytecode.cast.CastBoolean;
import railo.transformer.bytecode.expression.ExprBoolean;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.expression.ExpressionBase;
import railo.transformer.bytecode.literal.LitBoolean;
import railo.transformer.bytecode.util.Methods;
import railo.transformer.bytecode.util.Methods_Operator;
import railo.transformer.bytecode.util.Types;
public final class OpBool extends ExpressionBase implements ExprBoolean {
public static final int AND=0;
public static final int OR=1;
public static final int XOR=2;
public static final int EQV = 3;
public static final int IMP = 4;
private ExprBoolean left;
private ExprBoolean right;
private int operation;
/**
*
* @see railo.transformer.bytecode.expression.ExpressionBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
*/
public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
GeneratorAdapter adapter = bc.getAdapter();
if(mode==MODE_REF) {
_writeOut(bc,MODE_VALUE);
adapter.invokeStatic(Types.CASTER,Methods.METHOD_TO_BOOLEAN_FROM_BOOLEAN);
return Types.BOOLEAN;
}
Label doFalse = new Label();
Label end = new Label();
if(operation==AND) {
left.writeOut(bc, MODE_VALUE);
adapter.ifZCmp(Opcodes.IFEQ, doFalse);
right.writeOut(bc, MODE_VALUE);
adapter.ifZCmp(Opcodes.IFEQ, doFalse);
adapter.push(true);
adapter.visitJumpInsn(Opcodes.GOTO, end);
adapter.visitLabel(doFalse);
adapter.push(false);
adapter.visitLabel(end);
}
if(operation==OR) {
left.writeOut(bc, MODE_VALUE);
adapter.ifZCmp(Opcodes.IFNE, doFalse);
right.writeOut(bc, MODE_VALUE);
adapter.ifZCmp(Opcodes.IFNE, doFalse);
adapter.push(false);
adapter.visitJumpInsn(Opcodes.GOTO, end);
adapter.visitLabel(doFalse);
adapter.push(true);
adapter.visitLabel(end);
}
else if(operation==XOR) {
left.writeOut(bc, MODE_VALUE);
right.writeOut(bc, MODE_VALUE);
adapter.visitInsn(Opcodes.IXOR);
}
else if(operation==EQV) {
left.writeOut(bc,MODE_VALUE);
right.writeOut(bc,MODE_VALUE);
adapter.invokeStatic(Types.OPERATOR,Methods_Operator.OPERATOR_EQV_BV_BV);
}
else if(operation==IMP) {
left.writeOut(bc,MODE_VALUE);
right.writeOut(bc,MODE_VALUE);
adapter.invokeStatic(Types.OPERATOR,Methods_Operator.OPERATOR_IMP_BV_BV);
}
return Types.BOOLEAN_VALUE;
}
private OpBool(Expression left, Expression right, int operation) {
super(left.getStart(),right.getEnd());
this.left=CastBoolean.toExprBoolean(left);
this.right=CastBoolean.toExprBoolean(right);
this.operation=operation;
}
/**
* Create a String expression from a Expression
* @param left
* @param right
*
* @return String expression
* @throws TemplateException
*/
public static ExprBoolean toExprBoolean(Expression left, Expression right,int operation) {
if(left instanceof Literal && right instanceof Literal) {
Boolean l=((Literal) left).getBoolean(null);
Boolean r=((Literal) right).getBoolean(null);
if(l!=null && r!=null) {
switch(operation) {
case AND: return new LitBoolean(l.booleanValue()&&r.booleanValue(),left.getStart(),right.getEnd());
case OR: return new LitBoolean(l.booleanValue()||r.booleanValue(),left.getStart(),right.getEnd());
case XOR: return new LitBoolean(l.booleanValue()^r.booleanValue(),left.getStart(),right.getEnd());
}
}
}
return new OpBool(left,right,operation);
}
public String toString(){
return left+" "+toStringOperation()+" "+right;
}
private String toStringOperation() {
if(AND==operation) return "and";
if(OR==operation) return "or";
if(XOR==operation) return "xor";
if(EQV==operation) return "eqv";
if(IMP==operation) return "imp";
return operation+"";
}
}