throw new UnsupportedOperationException(format("not yet implemented: %s(%s, %s)", node.getType(), leftType, rightType));
}
private ByteCodeNode visitAnd(CompilerContext context, ByteCodeNode left, Type leftType, ByteCodeNode right, Type rightType, String comment)
{
Block block = new Block(context)
.comment(comment)
.setDescription("AND");
block.append(left);
IfStatementBuilder ifLeftIsNull = ifStatementBuilder(context)
.comment("if left wasNull...")
.condition(new Block(context).getVariable("wasNull"));
LabelNode end = new LabelNode("end");
ifLeftIsNull.ifTrue(new Block(context)
.comment("clear the null flag, pop left value off stack, and push left null flag on the stack (true)")
.putVariable("wasNull", false)
.pop(leftType.getJavaType()) // discard left value
.push(true));
LabelNode leftIsTrue = new LabelNode("leftIsTrue");
ifLeftIsNull.ifFalse(new Block(context)
.comment("if left is false, push false, and goto end")
.ifTrueGoto(leftIsTrue)
.push(false)
.gotoLabel(end)
.comment("left was true; push left null flag on the stack (false)")
.visitLabel(leftIsTrue)
.push(false));
block.append(ifLeftIsNull.build());
// At this point we know the left expression was either NULL or TRUE. The stack contains a single boolean
// value for this expression which indicates if the left value was NULL.
// eval right!
block.append(right);
IfStatementBuilder ifRightIsNull = ifStatementBuilder(context)
.comment("if right wasNull...")
.condition(new Block(context).getVariable("wasNull"));
// this leaves a single boolean on the stack which is ignored since the value in NULL
ifRightIsNull.ifTrue(new Block(context)
.comment("right was null, pop the right value off the stack; wasNull flag remains set to TRUE")
.pop(rightType.getJavaType()));
LabelNode rightIsTrue = new LabelNode("rightIsTrue");
ifRightIsNull.ifFalse(new Block(context)
.comment("if right is false, pop left null flag off stack, push false and goto end")
.ifTrueGoto(rightIsTrue)
.pop(boolean.class)
.push(false)
.gotoLabel(end)
.comment("right was true; store left null flag (on stack) in wasNull variable, and push true")
.visitLabel(rightIsTrue)
.putVariable("wasNull")
.push(true));
block.append(ifRightIsNull.build())
.visitLabel(end);
return block;
}