From 890bbf9b1fba98ac9791eaacaf594492e7ead662 Mon Sep 17 00:00:00 2001 From: William Carroll Date: Tue, 6 Sep 2022 14:55:13 -0700 Subject: feat(tvix/eval): Support builtins.lessThan Extend and export the `cmp_op`, and this becomes trivial. Change-Id: I9c93fa4db0f5a1fc8b56928ea144676f79247de1 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6557 Autosubmit: wpcarro Tested-by: BuildkiteCI Reviewed-by: sterni --- tvix/eval/src/builtins/mod.rs | 7 ++++- .../tvix_tests/eval-okay-builtins-lessThan.exp | 1 + .../tvix_tests/eval-okay-builtins-lessThan.nix | 15 ++++++++++ tvix/eval/src/vm.rs | 33 +++++++++++++--------- 4 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.exp create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-builtins-lessThan.nix 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 { .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> { -- cgit 1.4.1