From c7c7ab9bd4e105251ad56eb6c97157ee17354a9a Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 11 Aug 2022 14:38:38 +0300 Subject: feat(tvix/compiler): implement `||` operator Same dance as `&&` but logically inverted. Change-Id: I213e200e3836527e9abe510f354ee7cd1f70d041 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6151 Tested-by: BuildkiteCI Reviewed-by: grfn Reviewed-by: sterni --- tvix/eval/src/compiler.rs | 28 ++++++++++++++++++++++------ tvix/eval/src/opcode.rs | 1 + tvix/eval/src/vm.rs | 6 ++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs index f03ebee530b8..b8ade621743c 100644 --- a/tvix/eval/src/compiler.rs +++ b/tvix/eval/src/compiler.rs @@ -148,8 +148,8 @@ impl Compiler { // standard binary operators). match op.operator().unwrap() { BinOpKind::And => return self.compile_and(op), + BinOpKind::Or => return self.compile_or(op), BinOpKind::Implication => todo!(), - BinOpKind::Or => todo!(), _ => {} }; @@ -354,15 +354,31 @@ impl Compiler { Ok(()) } + fn compile_or(&mut self, node: rnix::types::BinOp) -> EvalResult<()> { + debug_assert!( + matches!(node.operator(), Some(BinOpKind::Or)), + "compile_or called with wrong operator kind: {:?}", + node.operator(), + ); + + // Leave left-hand side value on the stack + self.compile(node.lhs().unwrap())?; + + // Opposite of above: If this value is **true**, we can + // short-circuit the right-hand side. + let end_idx = self.chunk.add_op(OpCode::OpJumpIfTrue(0)); + self.chunk.add_op(OpCode::OpPop); + self.compile(node.rhs().unwrap())?; + self.patch_jump(end_idx); + + Ok(()) + } + fn patch_jump(&mut self, idx: CodeIdx) { let offset = self.chunk.code.len() - 1 - idx.0; match &mut self.chunk.code[idx.0] { - OpCode::OpJump(n) => { - *n = offset; - } - - OpCode::OpJumpIfFalse(n) => { + OpCode::OpJump(n) | OpCode::OpJumpIfFalse(n) | OpCode::OpJumpIfTrue(n) => { *n = offset; } diff --git a/tvix/eval/src/opcode.rs b/tvix/eval/src/opcode.rs index 8bb8fe9a1f31..f577bc985d3a 100644 --- a/tvix/eval/src/opcode.rs +++ b/tvix/eval/src/opcode.rs @@ -39,6 +39,7 @@ pub enum OpCode { // Logical operators & generic jumps OpJump(usize), + OpJumpIfTrue(usize), OpJumpIfFalse(usize), // Attribute sets diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs index 4ea1b3b65cf5..ed040cf91743 100644 --- a/tvix/eval/src/vm.rs +++ b/tvix/eval/src/vm.rs @@ -176,6 +176,12 @@ impl VM { self.ip += offset; } + OpCode::OpJumpIfTrue(offset) => { + if self.peek(0).as_bool()? { + self.ip += offset; + } + } + OpCode::OpJumpIfFalse(offset) => { if !self.peek(0).as_bool()? { self.ip += offset; -- cgit 1.4.1