diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-24T08·00+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-09-02T12·59+0000 |
commit | e0f1356ae31783664f597b33f8b69b060a9e3033 (patch) | |
tree | 54dc3a82429b2844b2c443ab9eb0911fc78f1615 /tvix/eval/src/value/builtin.rs | |
parent | 64746388e2c81c3dac7f520c40a4c4aacb3dc376 (diff) |
feat(tvix/eval): add initial representation of builtins r/4585
Builtins are represented as a Rust function pointer that accepts a vector of arguments, which represents variable arity builtins. Change-Id: Ibab7e662a646caf1172695d876d2f55e187c03dd Reviewed-on: https://cl.tvl.fyi/c/depot/+/6251 Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi>
Diffstat (limited to 'tvix/eval/src/value/builtin.rs')
-rw-r--r-- | tvix/eval/src/value/builtin.rs | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/tvix/eval/src/value/builtin.rs b/tvix/eval/src/value/builtin.rs new file mode 100644 index 000000000000..8d7e82136125 --- /dev/null +++ b/tvix/eval/src/value/builtin.rs @@ -0,0 +1,66 @@ +//! This module implements the runtime representation of a Nix +//! builtin. +//! +//! Builtins are directly backed by Rust code operating on Nix values. + +use crate::errors::EvalResult; + +use super::Value; + +use std::fmt::{Debug, Display}; + +pub type BuiltinFn = fn(arg: Vec<Value>) -> EvalResult<Value>; + +/// Represents a single built-in function which directly executes Rust +/// code that operates on a Nix value. +/// +/// Builtins are the only functions in Nix that have varying arities +/// (for example, `hasAttr` has an arity of 2, but `isAttrs` an arity +/// of 1). To facilitate this generically, builtins expect to be +/// called with a vector of Nix values corresponding to their +/// arguments in order. +/// +/// Partially applied builtins act similar to closures in that they +/// "capture" the partially applied arguments, and are treated +/// specially when printing their representation etc. +#[derive(Clone)] +pub struct Builtin { + name: &'static str, + arity: usize, + func: BuiltinFn, + + // Partially applied function arguments. + partials: Vec<Value>, +} + +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) -> EvalResult<Value> { + self.partials.push(arg); + + if self.partials.len() == self.arity { + return (self.func)(self.partials); + } + + // Function is not yet ready to be called. + return Ok(Value::Builtin(self)); + } +} + +impl Debug for Builtin { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "builtin[{}]", self.name) + } +} + +impl Display for Builtin { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if !self.partials.is_empty() { + f.write_str("<<primop-app>>") + } else { + f.write_str("<<primop>>") + } + } +} |