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 <wpcarro@gmail.com>
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
William Carroll 2022-09-06 14:55:13 -07:00 committed by clbot
parent 9e16d70809
commit 890bbf9b1f
4 changed files with 41 additions and 13 deletions

View file

@ -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()?;

View file

@ -0,0 +1 @@
[ true true true true false false false false true true true true false ]

View file

@ -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")
]

View file

@ -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,
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)),
(lhs, rhs) => return Err($self.error(ErrorKind::Incomparable {
// 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> {