about summary refs log tree commit diff
path: root/tvix/eval/src/vm.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-10T17·23+0300
committertazjin <tazjin@tvl.su>2022-08-25T11·07+0000
commit322ce36cea732619c50220fc93f0eba51cf2eb8d (patch)
treed66080da9183cb0b375976f86dd8b269a884fb2d /tvix/eval/src/vm.rs
parent8150803e77fb749bb331cf4072ebc9e87d3d0e96 (diff)
refactor(tvix/vm): use a macro to handle binary arithmetic operators r/4471
Instead of constructing another runtime value representing the pair on
which to perform arithmetic, implement the same logic in the shape of
a macro.

This is designed to be compatible with operators like `+` that work
both as an arithmetic operator AND as an operator on another pair of
types.

Change-Id: I1c83649ead6117f811f1fb45482d0cadf811125e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6136
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r--tvix/eval/src/vm.rs81
1 files changed, 32 insertions, 49 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index a529c5a799f7..3afda7a966eb 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -16,6 +16,34 @@ pub struct VM {
     stack: Vec<Value>,
 }
 
+macro_rules! arithmetic_op {
+    ( $self:ident, $op:tt ) => {{
+        let result = arithmetic_op!($self.pop(), $self.pop(), $op);
+        $self.push(result);
+    }};
+
+    ( $b:expr, $a:expr, $op:tt ) => {{
+        let b = $b;
+        let a = $a;
+
+        match (a, b) {
+            (Value::Integer(i1), Value::Integer(i2)) => Value::Integer(i1 $op i2),
+            (Value::Float(f1), Value::Float(f2)) => Value::Float(f1 $op f2),
+            (Value::Integer(i1), Value::Float(f2)) => Value::Float(i1 as f64 $op f2),
+            (Value::Float(f1), Value::Integer(i2)) => Value::Float(f1 $op i2 as f64),
+
+            (v1, v2) => return Err(Error::TypeError {
+                expected: "number (either int or float)",
+                actual: if v1.is_number() {
+                    v2.type_of()
+                } else {
+                    v1.type_of()
+                },
+            }),
+        }
+    }};
+}
+
 impl VM {
     fn inc_ip(&mut self) -> OpCode {
         let op = self.chunk.code[self.ip];
@@ -27,30 +55,6 @@ impl VM {
         self.stack.pop().expect("TODO")
     }
 
-    fn pop_number_pair(&mut self) -> EvalResult<NumberPair> {
-        let v2 = self.pop();
-        let v1 = self.pop();
-
-        match (v1, v2) {
-            (Value::Integer(i1), Value::Integer(i2)) => Ok(NumberPair::Integer(i1, i2)),
-
-            (Value::Float(f1), Value::Float(f2)) => Ok(NumberPair::Floats(f1, f2)),
-
-            (Value::Integer(i1), Value::Float(f2)) => Ok(NumberPair::Floats(i1 as f64, f2)),
-
-            (Value::Float(f1), Value::Integer(i2)) => Ok(NumberPair::Floats(f1, i2 as f64)),
-
-            (v1, v2) => Err(Error::TypeError {
-                expected: "number (either int or float)",
-                actual: if v1.is_number() {
-                    v2.type_of()
-                } else {
-                    v1.type_of()
-                },
-            }),
-        }
-    }
-
     fn push(&mut self, value: Value) {
         self.stack.push(value)
     }
@@ -63,25 +67,10 @@ impl VM {
                     self.push(c);
                 }
 
-                OpCode::OpAdd => match self.pop_number_pair()? {
-                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 + f2)),
-                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 + i2)),
-                },
-
-                OpCode::OpSub => match self.pop_number_pair()? {
-                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 - f2)),
-                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 - i2)),
-                },
-
-                OpCode::OpMul => match self.pop_number_pair()? {
-                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 * f2)),
-                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 * i2)),
-                },
-
-                OpCode::OpDiv => match self.pop_number_pair()? {
-                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 / f2)),
-                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 / i2)),
-                },
+                OpCode::OpAdd => arithmetic_op!(self, +),
+                OpCode::OpSub => arithmetic_op!(self, -),
+                OpCode::OpMul => arithmetic_op!(self, *),
+                OpCode::OpDiv => arithmetic_op!(self, /),
 
                 OpCode::OpInvert => {
                     let v = self.pop().as_bool()?;
@@ -182,12 +171,6 @@ impl VM {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum NumberPair {
-    Floats(f64, f64),
-    Integer(i64, i64),
-}
-
 pub fn run_chunk(chunk: Chunk) -> EvalResult<Value> {
     let mut vm = VM {
         chunk,