refactor(tvix/eval): pass a VM reference to builtins
This makes it possible for builtins to force values on their own, without the VM having to apply a strictness mask to the arguments first. Change-Id: Ib49a94e56ca2a8d515c39647381ab55a727766e3 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6411 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
This commit is contained in:
parent
5ee89bcf5c
commit
0d7ad5e6d1
3 changed files with 34 additions and 24 deletions
|
@ -17,17 +17,17 @@ use crate::arithmetic_op;
|
|||
|
||||
fn pure_builtins() -> Vec<Builtin> {
|
||||
vec![
|
||||
Builtin::new("add", 2, |mut args| {
|
||||
Builtin::new("add", 2, |mut args, _| {
|
||||
let b = args.pop().unwrap();
|
||||
let a = args.pop().unwrap();
|
||||
arithmetic_op!(a, b, +)
|
||||
}),
|
||||
Builtin::new("abort", 1, |mut args| {
|
||||
Builtin::new("abort", 1, |mut args, _| {
|
||||
return Err(ErrorKind::Abort(
|
||||
args.pop().unwrap().to_string()?.as_str().to_owned(),
|
||||
));
|
||||
}),
|
||||
Builtin::new("catAttrs", 2, |mut args| {
|
||||
Builtin::new("catAttrs", 2, |mut args, _| {
|
||||
let list = args.pop().unwrap().to_list()?;
|
||||
let key = args.pop().unwrap().to_string()?;
|
||||
let mut output = vec![];
|
||||
|
@ -40,64 +40,64 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
|
||||
Ok(Value::List(NixList::construct(output.len(), output)))
|
||||
}),
|
||||
Builtin::new("div", 2, |mut args| {
|
||||
Builtin::new("div", 2, |mut args, _| {
|
||||
let b = args.pop().unwrap();
|
||||
let a = args.pop().unwrap();
|
||||
arithmetic_op!(a, b, /)
|
||||
}),
|
||||
Builtin::new("length", 1, |args| {
|
||||
Builtin::new("length", 1, |args, _| {
|
||||
Ok(Value::Integer(args[0].as_list()?.len() as i64))
|
||||
}),
|
||||
Builtin::new("isAttrs", 1, |args| {
|
||||
Builtin::new("isAttrs", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::Attrs(_))))
|
||||
}),
|
||||
Builtin::new("isBool", 1, |args| {
|
||||
Builtin::new("isBool", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::Bool(_))))
|
||||
}),
|
||||
Builtin::new("isFloat", 1, |args| {
|
||||
Builtin::new("isFloat", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::Float(_))))
|
||||
}),
|
||||
Builtin::new("isFunction", 1, |args| {
|
||||
Builtin::new("isFunction", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(
|
||||
args[0],
|
||||
Value::Closure(_) | Value::Builtin(_)
|
||||
)))
|
||||
}),
|
||||
Builtin::new("isInt", 1, |args| {
|
||||
Builtin::new("isInt", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::Integer(_))))
|
||||
}),
|
||||
Builtin::new("isList", 1, |args| {
|
||||
Builtin::new("isList", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::List(_))))
|
||||
}),
|
||||
Builtin::new("isNull", 1, |args| {
|
||||
Builtin::new("isNull", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::Null)))
|
||||
}),
|
||||
Builtin::new("isPath", 1, |args| {
|
||||
Builtin::new("isPath", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::Path(_))))
|
||||
}),
|
||||
Builtin::new("isString", 1, |args| {
|
||||
Builtin::new("isString", 1, |args, _| {
|
||||
Ok(Value::Bool(matches!(args[0], Value::String(_))))
|
||||
}),
|
||||
Builtin::new("mul", 2, |mut args| {
|
||||
Builtin::new("mul", 2, |mut args, _| {
|
||||
let b = args.pop().unwrap();
|
||||
let a = args.pop().unwrap();
|
||||
arithmetic_op!(a, b, *)
|
||||
}),
|
||||
Builtin::new("sub", 2, |mut args| {
|
||||
Builtin::new("sub", 2, |mut args, _| {
|
||||
let b = args.pop().unwrap();
|
||||
let a = args.pop().unwrap();
|
||||
arithmetic_op!(a, b, -)
|
||||
}),
|
||||
Builtin::new("throw", 1, |mut args| {
|
||||
Builtin::new("throw", 1, |mut args, _| {
|
||||
return Err(ErrorKind::Throw(
|
||||
args.pop().unwrap().to_string()?.as_str().to_owned(),
|
||||
));
|
||||
}),
|
||||
Builtin::new("toString", 1, |args| {
|
||||
Builtin::new("toString", 1, |args, _| {
|
||||
// TODO: toString is actually not the same as Display
|
||||
Ok(Value::String(format!("{}", args[0]).into()))
|
||||
}),
|
||||
Builtin::new("typeOf", 1, |args| {
|
||||
Builtin::new("typeOf", 1, |args, _| {
|
||||
Ok(Value::String(args[0].type_of().into()))
|
||||
}),
|
||||
]
|
||||
|
|
|
@ -3,13 +3,23 @@
|
|||
//!
|
||||
//! Builtins are directly backed by Rust code operating on Nix values.
|
||||
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::{errors::ErrorKind, vm::VM};
|
||||
|
||||
use super::Value;
|
||||
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
pub type BuiltinFn = fn(arg: Vec<Value>) -> Result<Value, ErrorKind>;
|
||||
/// Function pointer type for builtins implemented directly by backing
|
||||
/// Rust code.
|
||||
///
|
||||
/// Builtins declare their arity and are passed a vector with the
|
||||
/// right number of arguments. Additionally, as they might have to
|
||||
/// force the evaluation of thunks, they are passed a reference to the
|
||||
/// current VM which they can use for forcing a value.
|
||||
///
|
||||
/// Errors returned from a builtin will be annotated with the location
|
||||
/// of the call to the builtin.
|
||||
pub type BuiltinFn = fn(arg: Vec<Value>, vm: &mut VM) -> Result<Value, ErrorKind>;
|
||||
|
||||
/// Represents a single built-in function which directly executes Rust
|
||||
/// code that operates on a Nix value.
|
||||
|
@ -50,11 +60,11 @@ impl Builtin {
|
|||
/// Apply an additional argument to the builtin, which will either
|
||||
/// lead to execution of the function or to returning a partial
|
||||
/// builtin.
|
||||
pub fn apply(mut self, arg: Value) -> Result<Value, ErrorKind> {
|
||||
pub fn apply(mut self, vm: &mut VM, arg: Value) -> Result<Value, ErrorKind> {
|
||||
self.partials.push(arg);
|
||||
|
||||
if self.partials.len() == self.arity {
|
||||
return (self.func)(self.partials);
|
||||
return (self.func)(self.partials, vm);
|
||||
}
|
||||
|
||||
// Function is not yet ready to be called.
|
||||
|
|
|
@ -418,7 +418,7 @@ impl VM {
|
|||
|
||||
Value::Builtin(builtin) => {
|
||||
let arg = self.pop();
|
||||
let result = fallible!(self, builtin.apply(arg));
|
||||
let result = fallible!(self, builtin.apply(self, arg));
|
||||
self.push(result);
|
||||
}
|
||||
_ => return Err(self.error(ErrorKind::NotCallable)),
|
||||
|
|
Loading…
Reference in a new issue