about summary refs log tree commit diff
path: root/tvix/eval/src/vm/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval/src/vm/macros.rs')
-rw-r--r--tvix/eval/src/vm/macros.rs70
1 files changed, 70 insertions, 0 deletions
diff --git a/tvix/eval/src/vm/macros.rs b/tvix/eval/src/vm/macros.rs
new file mode 100644
index 0000000000..4c027b0f64
--- /dev/null
+++ b/tvix/eval/src/vm/macros.rs
@@ -0,0 +1,70 @@
+/// This module provides macros which are used in the implementation
+/// of the VM for the implementation of repetitive operations.
+
+/// This macro simplifies the implementation of arithmetic operations,
+/// correctly handling the behaviour on different pairings of number
+/// types.
+#[macro_export]
+macro_rules! arithmetic_op {
+    ( $self:ident, $op:tt ) => {{ // TODO: remove
+        let b = $self.pop();
+        let a = $self.pop();
+        let result = fallible!($self, arithmetic_op!(&a, &b, $op));
+        $self.push(result);
+    }};
+
+    ( $a:expr, $b:expr, $op:tt ) => {{
+        match ($a, $b) {
+            (Value::Integer(i1), Value::Integer(i2)) => Ok(Value::Integer(i1 $op i2)),
+            (Value::Float(f1), Value::Float(f2)) => Ok(Value::Float(f1 $op f2)),
+            (Value::Integer(i1), Value::Float(f2)) => Ok(Value::Float(*i1 as f64 $op f2)),
+            (Value::Float(f1), Value::Integer(i2)) => Ok(Value::Float(f1 $op *i2 as f64)),
+
+            (v1, v2) => Err(ErrorKind::TypeError {
+                expected: "number (either int or float)",
+                actual: if v1.is_number() {
+                    v2.type_of()
+                } else {
+                    v1.type_of()
+                },
+            }),
+        }
+    }};
+}
+
+/// This macro simplifies the implementation of comparison operations.
+#[macro_export]
+macro_rules! cmp_op {
+    ( $vm:ident, $frame:ident, $span:ident, $op:tt ) => {{
+        let b = $vm.stack_pop();
+        let a = $vm.stack_pop();
+
+        async fn compare(a: Value, b: Value, co: GenCo) -> Result<Value, ErrorKind> {
+            let a = generators::request_force(&co, a).await;
+            let b = generators::request_force(&co, b).await;
+            let ordering = a.nix_cmp_ordering(b, co).await?;
+            Ok(Value::Bool(cmp_op!(@order $op ordering)))
+        }
+
+        let gen_span = $frame.current_light_span();
+        $vm.push_call_frame($span, $frame);
+        $vm.enqueue_generator(gen_span, |co| compare(a, b, co));
+        return Ok(false);
+    }};
+
+    (@order < $ordering:expr) => {
+        $ordering == Some(Ordering::Less)
+    };
+
+    (@order > $ordering:expr) => {
+        $ordering == Some(Ordering::Greater)
+    };
+
+    (@order <= $ordering:expr) => {
+        !matches!($ordering, None | Some(Ordering::Greater))
+    };
+
+    (@order >= $ordering:expr) => {
+        !matches!($ordering, None | Some(Ordering::Less))
+    };
+}