about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-11T11·38+0300
committertazjin <tazjin@tvl.su>2022-08-25T16·00+0000
commitc7c7ab9bd4e105251ad56eb6c97157ee17354a9a (patch)
tree341d7952e41072574e95c619d462d9eeea1dafa8
parent4b920912b8ea5ad963b76359c27902f6ece2ceec (diff)
feat(tvix/compiler): implement `||` operator r/4486
Same dance as `&&` but logically inverted.

Change-Id: I213e200e3836527e9abe510f354ee7cd1f70d041
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6151
Tested-by: BuildkiteCI
Reviewed-by: grfn <grfn@gws.fyi>
Reviewed-by: sterni <sternenseemann@systemli.org>
-rw-r--r--tvix/eval/src/compiler.rs28
-rw-r--r--tvix/eval/src/opcode.rs1
-rw-r--r--tvix/eval/src/vm.rs6
3 files changed, 29 insertions, 6 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs
index f03ebee530..b8ade62174 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 8bb8fe9a1f..f577bc985d 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 4ea1b3b65c..ed040cf917 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;