about summary refs log tree commit diff
path: root/tvix/eval
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval')
-rw-r--r--tvix/eval/src/builtins/mod.rs7
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.exp1
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.nix15
-rw-r--r--tvix/eval/src/vm.rs33
4 files changed, 42 insertions, 14 deletions
diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs
index f40c6f9574b1..650cfe674f52 100644
--- a/tvix/eval/src/builtins/mod.rs
+++ b/tvix/eval/src/builtins/mod.rs
@@ -16,7 +16,7 @@ use crate::{
     vm::VM,
 };
 
-use crate::arithmetic_op;
+use crate::{arithmetic_op, cmp_op};
 
 use self::versions::{VersionPart, VersionPartsIter};
 
@@ -160,6 +160,11 @@ fn pure_builtins() -> Vec<Builtin> {
                 .map(|list| Value::List(NixList::from(list)))
                 .map_err(Into::into)
         }),
+        Builtin::new(
+            "lessThan",
+            &[false, false],
+            |args, vm| cmp_op!(&*args[0].force(vm)?, &*args[1].force(vm)?, <),
+        ),
         Builtin::new("hasAttr", &[true, true], |args, _| {
             let k = args[0].to_str()?;
             let xs = args[1].to_attrs()?;
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.exp
new file mode 100644
index 000000000000..31f4598bb504
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.exp
@@ -0,0 +1 @@
+[ true true true true false false false false true true true true false ]
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.nix
new file mode 100644
index 000000000000..cd2d0c209c3a
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.nix
@@ -0,0 +1,15 @@
+[
+  (builtins.lessThan 2 3)
+  (builtins.lessThan 2.0 3)
+  (builtins.lessThan 2 3.0)
+  (builtins.lessThan 2.0 3.0)
+  (builtins.lessThan 3 2)
+  (builtins.lessThan 3.0 2)
+  (builtins.lessThan 3 2.0)
+  (builtins.lessThan 3.0 2.0)
+  (builtins.lessThan 10 (builtins.add 9 2))
+  (builtins.lessThan (builtins.add 9 1) 11)
+  (builtins.lessThan (builtins.add 9 1) (builtins.add 9 2))
+  (builtins.lessThan "a" "b")
+  (builtins.lessThan "b" "a")
+]
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index 87adfe5611a4..52627a1fea14 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -94,29 +94,36 @@ macro_rules! arithmetic_op {
     }};
 }
 
+#[macro_export]
 macro_rules! cmp_op {
     ( $self:ident, $op:tt ) => {{
         let b = $self.pop();
         let a = $self.pop();
+        let result = fallible!($self, cmp_op!(&a, &b, $op));
+        $self.push(result);
+    }};
 
+    ( $a:expr, $b:expr, $op:tt ) => {
         // Comparable (in terms of ordering) values are numbers and
         // strings. Numbers need to be coerced similarly to arithmetic
         // ops if mixed types are encountered.
-        let result = match (a, b) {
-            (Value::Integer(i1), Value::Integer(i2)) => i1 $op i2,
-            (Value::Float(f1), Value::Float(f2)) => f1 $op f2,
-            (Value::Integer(i1), Value::Float(f2)) => (i1 as f64) $op f2,
-            (Value::Float(f1), Value::Integer(i2)) => f1 $op (i2 as f64),
-            (Value::String(s1), Value::String(s2)) => s1 $op s2,
-
-            (lhs, rhs) => return Err($self.error(ErrorKind::Incomparable {
+        match ($a, $b) {
+            // same types
+            (Value::Integer(i1), Value::Integer(i2)) => Ok(Value::Bool(i1 $op i2)),
+            (Value::Float(f1), Value::Float(f2)) => Ok(Value::Bool(f1 $op f2)),
+            (Value::String(s1), Value::String(s2)) => Ok(Value::Bool(s1 $op s2)),
+
+            // different types
+            (Value::Integer(i1), Value::Float(f2)) => Ok(Value::Bool((*i1 as f64) $op *f2)),
+            (Value::Float(f1), Value::Integer(i2)) => Ok(Value::Bool(*f1 $op (*i2 as f64))),
+
+            // unsupported types
+            (lhs, rhs) => Err(ErrorKind::Incomparable {
                 lhs: lhs.type_of(),
                 rhs: rhs.type_of(),
-            })),
-        };
-
-        $self.push(Value::Bool(result));
-    }};
+            }),
+        }
+    }
 }
 
 impl<'o> VM<'o> {