implement shortcircuiting and/or
This commit is contained in:
parent
abbab2ef90
commit
de3137f72b
|
@ -1,5 +1,5 @@
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Assignment, CellPath, Expr, Expression, Math, Operator, PathMember},
|
ast::{Assignment, Boolean, CellPath, Expr, Expression, Math, Operator, PathMember},
|
||||||
engine::StateWorkingSet,
|
engine::StateWorkingSet,
|
||||||
ir::{Instruction, Literal},
|
ir::{Instruction, Literal},
|
||||||
IntoSpanned, RegId, Span, Spanned, ENV_VARIABLE_ID,
|
IntoSpanned, RegId, Span, Spanned, ENV_VARIABLE_ID,
|
||||||
|
@ -56,6 +56,54 @@ pub(crate) fn compile_binary_op(
|
||||||
lhs_reg,
|
lhs_reg,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
match op.item {
|
||||||
|
// `and` / `or` are short-circuiting, and we can get by with one register and a branch
|
||||||
|
Operator::Boolean(Boolean::And) => {
|
||||||
|
builder.branch_if(lhs_reg, builder.next_instruction_index() + 2, op.span)?;
|
||||||
|
|
||||||
|
// If the branch was not taken it's false, so short circuit to load false
|
||||||
|
let jump_false = builder.jump_placeholder(op.span)?;
|
||||||
|
|
||||||
|
compile_expression(
|
||||||
|
working_set,
|
||||||
|
builder,
|
||||||
|
rhs,
|
||||||
|
RedirectModes::capture_out(rhs.span),
|
||||||
|
None,
|
||||||
|
lhs_reg,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let jump_end = builder.jump_placeholder(op.span)?;
|
||||||
|
|
||||||
|
// Consumed by `branch-if`, so we have to set it false again
|
||||||
|
builder.set_branch_target(jump_false, builder.next_instruction_index())?;
|
||||||
|
builder.load_literal(lhs_reg, Literal::Bool(false).into_spanned(lhs.span))?;
|
||||||
|
|
||||||
|
builder.set_branch_target(jump_end, builder.next_instruction_index())?;
|
||||||
|
}
|
||||||
|
Operator::Boolean(Boolean::Or) => {
|
||||||
|
let branch_true = builder.branch_if_placeholder(lhs_reg, op.span)?;
|
||||||
|
|
||||||
|
// If the branch was not taken it's false, so do the right-side expression
|
||||||
|
compile_expression(
|
||||||
|
working_set,
|
||||||
|
builder,
|
||||||
|
rhs,
|
||||||
|
RedirectModes::capture_out(rhs.span),
|
||||||
|
None,
|
||||||
|
lhs_reg,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let jump_end = builder.jump_placeholder(op.span)?;
|
||||||
|
|
||||||
|
// Consumed by `branch-if`, so we have to set it true again
|
||||||
|
builder.set_branch_target(branch_true, builder.next_instruction_index())?;
|
||||||
|
builder.load_literal(lhs_reg, Literal::Bool(true).into_spanned(lhs.span))?;
|
||||||
|
|
||||||
|
builder.set_branch_target(jump_end, builder.next_instruction_index())?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Any other operator, via `binary-op`
|
||||||
let rhs_reg = builder.next_register()?;
|
let rhs_reg = builder.next_register()?;
|
||||||
|
|
||||||
compile_expression(
|
compile_expression(
|
||||||
|
@ -75,6 +123,8 @@ pub(crate) fn compile_binary_op(
|
||||||
}
|
}
|
||||||
.into_spanned(op.span),
|
.into_spanned(op.span),
|
||||||
)?;
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if lhs_reg != out_reg {
|
if lhs_reg != out_reg {
|
||||||
builder.push(
|
builder.push(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user