refactor(tvix/eval): Define *all* pure builtins at the top-level
Break out all pure builtin functions to top-level functions defined within the `pure_builtins` module in `builtins/mod.rs`. Change-Id: I9a10660446d557b1a86da4c45a463e9a1a9b4f2d Reviewed-on: https://cl.tvl.fyi/c/depot/+/7201 Reviewed-by: tazjin <tazjin@tvl.su> Reviewed-by: Adam Joseph <adam@westernsemico.com> Tested-by: BuildkiteCI
This commit is contained in:
parent
43eb4900e0
commit
2d26925dd9
1 changed files with 791 additions and 727 deletions
|
@ -59,21 +59,16 @@ mod pure_builtins {
|
|||
fn builtin_abort(_vm: &mut VM, message: Value) -> Result<Value, ErrorKind> {
|
||||
Err(ErrorKind::Abort(message.to_str()?.to_string()))
|
||||
}
|
||||
|
||||
#[builtin("add")]
|
||||
fn builtin_add(vm: &mut VM, #[lazy] x: Value, #[lazy] y: Value) -> Result<Value, ErrorKind> {
|
||||
arithmetic_op!(&*x.force(vm)?, &*y.force(vm)?, +)
|
||||
}
|
||||
|
||||
/// Return all pure builtins, that is all builtins that do not rely on
|
||||
/// I/O outside of the VM and which can be used in any contexts (e.g.
|
||||
/// WASM).
|
||||
fn pure_builtins() -> Vec<Builtin> {
|
||||
let mut bs = vec![
|
||||
Builtin::new(
|
||||
"add",
|
||||
&[false, false],
|
||||
|args: Vec<Value>, vm: &mut VM| arithmetic_op!(&*args[0].force(vm)?, &*args[1].force(vm)?, +),
|
||||
),
|
||||
Builtin::new("all", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
for value in args[1].to_list()?.into_iter() {
|
||||
let pred_result = vm.call_with(&args[0], [value])?;
|
||||
#[builtin("all")]
|
||||
fn builtin_all(vm: &mut VM, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
for value in list.to_list()?.into_iter() {
|
||||
let pred_result = vm.call_with(&pred, [value])?;
|
||||
|
||||
if !pred_result.force(vm)?.as_bool()? {
|
||||
return Ok(Value::Bool(false));
|
||||
|
@ -81,10 +76,12 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
}
|
||||
|
||||
Ok(Value::Bool(true))
|
||||
}),
|
||||
Builtin::new("any", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
for value in args[1].to_list()?.into_iter() {
|
||||
let pred_result = vm.call_with(&args[0], [value])?;
|
||||
}
|
||||
|
||||
#[builtin("any")]
|
||||
fn builtin_any(vm: &mut VM, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
for value in list.to_list()?.into_iter() {
|
||||
let pred_result = vm.call_with(&pred, [value])?;
|
||||
|
||||
if pred_result.force(vm)?.as_bool()? {
|
||||
return Ok(Value::Bool(true));
|
||||
|
@ -92,9 +89,11 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
}
|
||||
|
||||
Ok(Value::Bool(false))
|
||||
}),
|
||||
Builtin::new("attrNames", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
let xs = args[0].to_attrs()?;
|
||||
}
|
||||
|
||||
#[builtin("attrNames")]
|
||||
fn builtin_attr_names(_: &mut VM, set: Value) -> Result<Value, ErrorKind> {
|
||||
let xs = set.to_attrs()?;
|
||||
let mut output = Vec::with_capacity(xs.len());
|
||||
|
||||
for (key, _val) in xs.iter() {
|
||||
|
@ -102,9 +101,11 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
}
|
||||
|
||||
Ok(Value::List(NixList::construct(output.len(), output)))
|
||||
}),
|
||||
Builtin::new("attrValues", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
let xs = args[0].to_attrs()?;
|
||||
}
|
||||
|
||||
#[builtin("attrValues")]
|
||||
fn builtin_attr_values(_: &mut VM, set: Value) -> Result<Value, ErrorKind> {
|
||||
let xs = set.to_attrs()?;
|
||||
let mut output = Vec::with_capacity(xs.len());
|
||||
|
||||
for (_key, val) in xs.iter() {
|
||||
|
@ -112,27 +113,34 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
}
|
||||
|
||||
Ok(Value::List(NixList::construct(output.len(), output)))
|
||||
}),
|
||||
Builtin::new("baseNameOf", &[true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let s = args[0].coerce_to_string(CoercionKind::Weak, vm)?;
|
||||
}
|
||||
|
||||
#[builtin("baseNameOf")]
|
||||
fn builtin_base_name_of(vm: &mut VM, s: Value) -> Result<Value, ErrorKind> {
|
||||
let s = s.coerce_to_string(CoercionKind::Weak, vm)?;
|
||||
let result: String = s.rsplit_once('/').map(|(_, x)| x).unwrap_or(&s).into();
|
||||
Ok(result.into())
|
||||
}),
|
||||
Builtin::new("bitAnd", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
||||
Ok(Value::Integer(args[0].as_int()? & args[1].as_int()?))
|
||||
}),
|
||||
Builtin::new("bitOr", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
||||
Ok(Value::Integer(args[0].as_int()? | args[1].as_int()?))
|
||||
}),
|
||||
Builtin::new("bitXor", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
||||
Ok(Value::Integer(args[0].as_int()? ^ args[1].as_int()?))
|
||||
}),
|
||||
Builtin::new(
|
||||
"catAttrs",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, vm: &mut VM| {
|
||||
let key = args[0].to_str()?;
|
||||
let list = args[1].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("bitAnd")]
|
||||
fn builtin_bit_and(_: &mut VM, x: Value, y: Value) -> Result<Value, ErrorKind> {
|
||||
Ok(Value::Integer(x.as_int()? & y.as_int()?))
|
||||
}
|
||||
|
||||
#[builtin("bitOr")]
|
||||
fn builtin_bit_or(_: &mut VM, x: Value, y: Value) -> Result<Value, ErrorKind> {
|
||||
Ok(Value::Integer(x.as_int()? | y.as_int()?))
|
||||
}
|
||||
|
||||
#[builtin("bitXor")]
|
||||
fn builtin_bit_xor(_: &mut VM, x: Value, y: Value) -> Result<Value, ErrorKind> {
|
||||
Ok(Value::Integer(x.as_int()? ^ y.as_int()?))
|
||||
}
|
||||
|
||||
#[builtin("catAttrs")]
|
||||
fn builtin_cat_attrs(vm: &mut VM, key: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
let key = key.to_str()?;
|
||||
let list = list.to_list()?;
|
||||
let mut output = vec![];
|
||||
|
||||
for item in list.into_iter() {
|
||||
|
@ -143,18 +151,18 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
}
|
||||
|
||||
Ok(Value::List(NixList::construct(output.len(), output)))
|
||||
},
|
||||
),
|
||||
Builtin::new("ceil", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
Ok(Value::Integer(args[0].as_float()?.ceil() as i64))
|
||||
}),
|
||||
Builtin::new(
|
||||
"compareVersions",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, _: &mut VM| {
|
||||
let s1 = args[0].to_str()?;
|
||||
}
|
||||
|
||||
#[builtin("ceil")]
|
||||
fn builtin_ceil(_: &mut VM, double: Value) -> Result<Value, ErrorKind> {
|
||||
Ok(Value::Integer(double.as_float()?.ceil() as i64))
|
||||
}
|
||||
|
||||
#[builtin("compareVersions")]
|
||||
fn builtin_compare_versions(_: &mut VM, x: Value, y: Value) -> Result<Value, ErrorKind> {
|
||||
let s1 = x.to_str()?;
|
||||
let s1 = VersionPartsIter::new_for_cmp(s1.as_str());
|
||||
let s2 = args[1].to_str()?;
|
||||
let s2 = y.to_str()?;
|
||||
let s2 = VersionPartsIter::new_for_cmp(s2.as_str());
|
||||
|
||||
match s1.cmp(s2) {
|
||||
|
@ -162,10 +170,11 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
std::cmp::Ordering::Equal => Ok(Value::Integer(0)),
|
||||
std::cmp::Ordering::Greater => Ok(Value::Integer(1)),
|
||||
}
|
||||
},
|
||||
),
|
||||
Builtin::new("concatLists", &[true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let list = args[0].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("concatLists")]
|
||||
fn builtin_concat_lists(vm: &mut VM, lists: Value) -> Result<Value, ErrorKind> {
|
||||
let list = lists.to_list()?;
|
||||
let lists = list
|
||||
.into_iter()
|
||||
.map(|elem| {
|
||||
|
@ -177,25 +186,26 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
Ok(Value::List(NixList::from(
|
||||
lists.into_iter().flatten().collect::<Vec<Value>>(),
|
||||
)))
|
||||
}),
|
||||
Builtin::new(
|
||||
"concatMap",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, vm: &mut VM| {
|
||||
let list = args[1].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("concatMap")]
|
||||
fn builtin_concat_map(vm: &mut VM, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
let list = list.to_list()?;
|
||||
let mut res = Vec::new();
|
||||
for val in list {
|
||||
res.extend(vm.call_with(&args[0], [val])?.force(vm)?.to_list()?);
|
||||
res.extend(vm.call_with(&f, [val])?.force(vm)?.to_list()?);
|
||||
}
|
||||
Ok(Value::List(res.into()))
|
||||
},
|
||||
),
|
||||
Builtin::new(
|
||||
"concatStringsSep",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, vm: &mut VM| {
|
||||
let separator = args[0].to_str()?;
|
||||
let list = args[1].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("concatStringsSep")]
|
||||
fn builtin_concat_strings_sep(
|
||||
vm: &mut VM,
|
||||
separator: Value,
|
||||
list: Value,
|
||||
) -> Result<Value, ErrorKind> {
|
||||
let separator = separator.to_str()?;
|
||||
let list = list.to_list()?;
|
||||
let mut res = String::new();
|
||||
for (i, val) in list.into_iter().enumerate() {
|
||||
if i != 0 {
|
||||
|
@ -204,49 +214,50 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
res.push_str(&val.force(vm)?.coerce_to_string(CoercionKind::Weak, vm)?);
|
||||
}
|
||||
Ok(res.into())
|
||||
},
|
||||
),
|
||||
Builtin::new(
|
||||
"deepSeq",
|
||||
&[true, true],
|
||||
|mut args: Vec<Value>, vm: &mut VM| {
|
||||
let arg2 = args.pop().unwrap();
|
||||
let arg1 = args.pop().unwrap();
|
||||
arg1.deep_force(vm, &mut Default::default())?;
|
||||
Ok(arg2)
|
||||
},
|
||||
),
|
||||
Builtin::new(
|
||||
"div",
|
||||
&[false, false],
|
||||
|args: Vec<Value>, vm: &mut VM| arithmetic_op!(&*args[0].force(vm)?, &*args[1].force(vm)?, /),
|
||||
),
|
||||
Builtin::new("dirOf", &[true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let s = args[0].coerce_to_string(CoercionKind::Weak, vm)?;
|
||||
let result = s
|
||||
}
|
||||
|
||||
#[builtin("deepSeq")]
|
||||
fn builtin_deep_seq(vm: &mut VM, x: Value, y: Value) -> Result<Value, ErrorKind> {
|
||||
x.deep_force(vm, &mut Default::default())?;
|
||||
Ok(y)
|
||||
}
|
||||
|
||||
#[builtin("div")]
|
||||
fn builtin_div(vm: &mut VM, #[lazy] x: Value, #[lazy] y: Value) -> Result<Value, ErrorKind> {
|
||||
arithmetic_op!(&*x.force(vm)?, &*y.force(vm)?, /)
|
||||
}
|
||||
|
||||
#[builtin("dirOf")]
|
||||
fn builtin_dir_of(vm: &mut VM, s: Value) -> Result<Value, ErrorKind> {
|
||||
let str = s.coerce_to_string(CoercionKind::Weak, vm)?;
|
||||
let result = str
|
||||
.rsplit_once('/')
|
||||
.map(|(x, _)| match x {
|
||||
"" => "/",
|
||||
_ => x,
|
||||
})
|
||||
.unwrap_or(".");
|
||||
if args[0].is_path() {
|
||||
if s.is_path() {
|
||||
Ok(Value::Path(result.into()))
|
||||
} else {
|
||||
Ok(result.into())
|
||||
}
|
||||
}),
|
||||
Builtin::new("elem", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
for val in args[1].to_list()? {
|
||||
if val.nix_eq(&args[0], vm)? {
|
||||
}
|
||||
|
||||
#[builtin("elem")]
|
||||
fn builtin_elem(vm: &mut VM, x: Value, xs: Value) -> Result<Value, ErrorKind> {
|
||||
for val in xs.to_list()? {
|
||||
if val.nix_eq(&x, vm)? {
|
||||
return Ok(true.into());
|
||||
}
|
||||
}
|
||||
Ok(false.into())
|
||||
}),
|
||||
Builtin::new("elemAt", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
||||
let xs = args[0].to_list()?;
|
||||
let i = args[1].as_int()?;
|
||||
}
|
||||
|
||||
#[builtin("elemAt")]
|
||||
fn builtin_elem_at(_: &mut VM, xs: Value, i: Value) -> Result<Value, ErrorKind> {
|
||||
let xs = xs.to_list()?;
|
||||
let i = i.as_int()?;
|
||||
if i < 0 {
|
||||
Err(ErrorKind::IndexOutOfBounds { index: i })
|
||||
} else {
|
||||
|
@ -255,13 +266,15 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
None => Err(ErrorKind::IndexOutOfBounds { index: i }),
|
||||
}
|
||||
}
|
||||
}),
|
||||
Builtin::new("filter", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let list: NixList = args[1].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("filter")]
|
||||
fn builtin_filter(vm: &mut VM, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
let list: NixList = list.to_list()?;
|
||||
|
||||
list.into_iter()
|
||||
.filter_map(|elem| {
|
||||
let result = match vm.call_with(&args[0], [elem.clone()]) {
|
||||
let result = match vm.call_with(&pred, [elem.clone()]) {
|
||||
Err(err) => return Some(Err(err)),
|
||||
Ok(result) => result,
|
||||
};
|
||||
|
@ -282,27 +295,32 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
.collect::<Result<Vec<Value>, _>>()
|
||||
.map(|list| Value::List(NixList::from(list)))
|
||||
.map_err(Into::into)
|
||||
}),
|
||||
Builtin::new("floor", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
Ok(Value::Integer(args[0].as_float()?.floor() as i64))
|
||||
}),
|
||||
Builtin::new(
|
||||
"foldl'",
|
||||
&[true, false, true],
|
||||
|mut args: Vec<Value>, vm: &mut VM| {
|
||||
let list = args.pop().unwrap().to_list()?;
|
||||
let mut res = args.pop().unwrap();
|
||||
let op = args.pop().unwrap();
|
||||
for val in list {
|
||||
res = vm.call_with(&op, [res, val])?;
|
||||
res.force(vm)?;
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
},
|
||||
),
|
||||
Builtin::new("functionArgs", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
let lambda = args[0].to_closure()?.lambda();
|
||||
#[builtin("floor")]
|
||||
fn builtin_floor(_: &mut VM, double: Value) -> Result<Value, ErrorKind> {
|
||||
Ok(Value::Integer(double.as_float()?.floor() as i64))
|
||||
}
|
||||
|
||||
#[builtin("foldl'")]
|
||||
fn builtin_foldl(
|
||||
vm: &mut VM,
|
||||
op: Value,
|
||||
#[lazy] mut nul: Value,
|
||||
list: Value,
|
||||
) -> Result<Value, ErrorKind> {
|
||||
let list = list.to_list()?;
|
||||
for val in list {
|
||||
nul = vm.call_with(&op, [nul, val])?;
|
||||
nul.force(vm)?;
|
||||
}
|
||||
|
||||
Ok(nul)
|
||||
}
|
||||
|
||||
#[builtin("functionArgs")]
|
||||
fn builtin_function_args(_: &mut VM, f: Value) -> Result<Value, ErrorKind> {
|
||||
let lambda = f.to_closure()?.lambda();
|
||||
let formals = if let Some(formals) = &lambda.formals {
|
||||
formals
|
||||
} else {
|
||||
|
@ -315,23 +333,29 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
.map(|(k, v)| (k.clone(), (*v).into()))
|
||||
.collect(),
|
||||
)))
|
||||
}),
|
||||
Builtin::new("fromJSON", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
let json_str = args[0].to_str()?;
|
||||
}
|
||||
|
||||
#[builtin("fromJSON")]
|
||||
fn builtin_from_json(_: &mut VM, json: Value) -> Result<Value, ErrorKind> {
|
||||
let json_str = json.to_str()?;
|
||||
let json: serde_json::Value = serde_json::from_str(&json_str)?;
|
||||
json.try_into()
|
||||
}),
|
||||
Builtin::new("genList", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let len = args[1].as_int()?;
|
||||
}
|
||||
|
||||
#[builtin("genList")]
|
||||
fn builtin_gen_list(vm: &mut VM, generator: Value, length: Value) -> Result<Value, ErrorKind> {
|
||||
let len = length.as_int()?;
|
||||
(0..len)
|
||||
.map(|i| vm.call_with(&args[0], [i.into()]))
|
||||
.map(|i| vm.call_with(&generator, [i.into()]))
|
||||
.collect::<Result<Vec<Value>, _>>()
|
||||
.map(|list| Value::List(NixList::from(list)))
|
||||
.map_err(Into::into)
|
||||
}),
|
||||
Builtin::new("getAttr", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
||||
let k = args[0].to_str()?;
|
||||
let xs = args[1].to_attrs()?;
|
||||
}
|
||||
|
||||
#[builtin("getAttr")]
|
||||
fn builtin_get_attr(_: &mut VM, key: Value, set: Value) -> Result<Value, ErrorKind> {
|
||||
let k = key.to_str()?;
|
||||
let xs = set.to_attrs()?;
|
||||
|
||||
match xs.select(k.as_str()) {
|
||||
Some(x) => Ok(x.clone()),
|
||||
|
@ -339,100 +363,129 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
name: k.to_string(),
|
||||
}),
|
||||
}
|
||||
}),
|
||||
Builtin::new("groupBy", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("groupBy")]
|
||||
fn builtin_group_by(vm: &mut VM, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
let mut res: BTreeMap<NixString, Value> = BTreeMap::new();
|
||||
for val in args[1].to_list()? {
|
||||
let key = vm.call_with(&args[0], [val.clone()])?.force(vm)?.to_str()?;
|
||||
for val in list.to_list()? {
|
||||
let key = vm.call_with(&f, [val.clone()])?.force(vm)?.to_str()?;
|
||||
res.entry(key)
|
||||
.or_insert_with(|| Value::List(NixList::new()))
|
||||
.as_list_mut()?
|
||||
.push(val);
|
||||
}
|
||||
Ok(Value::attrs(NixAttrs::from_map(res)))
|
||||
}),
|
||||
Builtin::new("hasAttr", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
||||
let k = args[0].to_str()?;
|
||||
let xs = args[1].to_attrs()?;
|
||||
}
|
||||
|
||||
#[builtin("hasAttr")]
|
||||
fn builtin_has_attr(_: &mut VM, key: Value, set: Value) -> Result<Value, ErrorKind> {
|
||||
let k = key.to_str()?;
|
||||
let xs = set.to_attrs()?;
|
||||
|
||||
Ok(Value::Bool(xs.contains(k.as_str())))
|
||||
}),
|
||||
Builtin::new("head", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
match args[0].to_list()?.get(0) {
|
||||
}
|
||||
|
||||
#[builtin("head")]
|
||||
fn builtin_head(_: &mut VM, list: Value) -> Result<Value, ErrorKind> {
|
||||
match list.to_list()?.get(0) {
|
||||
Some(x) => Ok(x.clone()),
|
||||
None => Err(ErrorKind::IndexOutOfBounds { index: 0 }),
|
||||
}
|
||||
}),
|
||||
Builtin::new(
|
||||
"intersectAttrs",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, _: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("intersectAttrs")]
|
||||
fn builtin_intersect_attrs(_: &mut VM, x: Value, y: Value) -> Result<Value, ErrorKind> {
|
||||
let mut res = BTreeMap::new();
|
||||
let attrs1 = args[0].to_attrs()?;
|
||||
let attrs2 = args[1].to_attrs()?;
|
||||
let attrs1 = x.to_attrs()?;
|
||||
let attrs2 = y.to_attrs()?;
|
||||
for (k, v) in attrs2.iter() {
|
||||
if attrs1.contains(k) {
|
||||
res.insert(k.clone(), v.clone());
|
||||
}
|
||||
}
|
||||
Ok(Value::attrs(NixAttrs::from_map(res)))
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
// For `is*` predicates we force manually, as Value::force also unwraps any Thunks
|
||||
Builtin::new("isAttrs", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
|
||||
#[builtin("isAttrs")]
|
||||
fn builtin_is_attrs(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::Attrs(_))))
|
||||
}),
|
||||
Builtin::new("isBool", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isBool")]
|
||||
fn builtin_is_bool(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::Bool(_))))
|
||||
}),
|
||||
Builtin::new("isFloat", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isFloat")]
|
||||
fn builtin_is_float(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::Float(_))))
|
||||
}),
|
||||
Builtin::new("isFunction", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isFunction")]
|
||||
fn builtin_is_function(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(
|
||||
*value,
|
||||
Value::Closure(_) | Value::Builtin(_)
|
||||
)))
|
||||
}),
|
||||
Builtin::new("isInt", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isInt")]
|
||||
fn builtin_is_int(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::Integer(_))))
|
||||
}),
|
||||
Builtin::new("isList", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isList")]
|
||||
fn builtin_is_list(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::List(_))))
|
||||
}),
|
||||
Builtin::new("isNull", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isNull")]
|
||||
fn builtin_is_null(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::Null)))
|
||||
}),
|
||||
Builtin::new("isPath", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isPath")]
|
||||
fn builtin_is_path(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::Path(_))))
|
||||
}),
|
||||
Builtin::new("isString", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let value = args[0].force(vm)?;
|
||||
}
|
||||
|
||||
#[builtin("isString")]
|
||||
fn builtin_is_string(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::Bool(matches!(*value, Value::String(_))))
|
||||
}),
|
||||
Builtin::new("length", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
Ok(Value::Integer(args[0].to_list()?.len() as i64))
|
||||
}),
|
||||
Builtin::new(
|
||||
"lessThan",
|
||||
&[false, false],
|
||||
|args: Vec<Value>, vm: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("length")]
|
||||
fn builtin_length(_: &mut VM, list: Value) -> Result<Value, ErrorKind> {
|
||||
Ok(Value::Integer(list.to_list()?.len() as i64))
|
||||
}
|
||||
|
||||
#[builtin("lessThan")]
|
||||
fn builtin_less_than(
|
||||
vm: &mut VM,
|
||||
#[lazy] x: Value,
|
||||
#[lazy] y: Value,
|
||||
) -> Result<Value, ErrorKind> {
|
||||
Ok(Value::Bool(matches!(
|
||||
args[0].force(vm)?.nix_cmp(&*args[1].force(vm)?, vm)?,
|
||||
x.force(vm)?.nix_cmp(&*y.force(vm)?, vm)?,
|
||||
Some(Ordering::Less)
|
||||
)))
|
||||
},
|
||||
),
|
||||
Builtin::new("listToAttrs", &[true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let list = args[0].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("listToAttrs")]
|
||||
fn builtin_list_to_attrs(vm: &mut VM, list: Value) -> Result<Value, ErrorKind> {
|
||||
let list = list.to_list()?;
|
||||
let mut map = BTreeMap::new();
|
||||
for val in list {
|
||||
let attrs = val.force(vm)?.to_attrs()?;
|
||||
|
@ -447,35 +500,34 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
map.entry(name).or_insert(value);
|
||||
}
|
||||
Ok(Value::attrs(NixAttrs::from_map(map)))
|
||||
}),
|
||||
Builtin::new("map", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let list: NixList = args[1].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("map")]
|
||||
fn builtin_map(vm: &mut VM, f: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
let list: NixList = list.to_list()?;
|
||||
|
||||
list.into_iter()
|
||||
.map(|val| vm.call_with(&args[0], [val]))
|
||||
.map(|val| vm.call_with(&f, [val]))
|
||||
.collect::<Result<Vec<Value>, _>>()
|
||||
.map(|list| Value::List(NixList::from(list)))
|
||||
.map_err(Into::into)
|
||||
}),
|
||||
Builtin::new(
|
||||
"mapAttrs",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, vm: &mut VM| {
|
||||
let attrs = args[1].to_attrs()?;
|
||||
}
|
||||
|
||||
#[builtin("mapAttrs")]
|
||||
fn builtin_map_attrs(vm: &mut VM, f: Value, attrs: Value) -> Result<Value, ErrorKind> {
|
||||
let attrs = attrs.to_attrs()?;
|
||||
let mut res = BTreeMap::new();
|
||||
for (key, value) in attrs.as_ref() {
|
||||
let value = vm.call_with(&args[0], [key.clone().into(), value.clone()])?;
|
||||
let value = vm.call_with(&f, [key.clone().into(), value.clone()])?;
|
||||
res.insert(key.clone(), value);
|
||||
}
|
||||
Ok(Value::attrs(NixAttrs::from_map(res)))
|
||||
},
|
||||
),
|
||||
Builtin::new(
|
||||
"match",
|
||||
&[true, true],
|
||||
|mut args: Vec<Value>, _: &mut VM| {
|
||||
let s = args.pop().unwrap().to_str()?;
|
||||
let re = args.pop().unwrap().to_str()?;
|
||||
}
|
||||
|
||||
#[builtin("match")]
|
||||
fn builtin_match(_: &mut VM, regex: Value, str: Value) -> Result<Value, ErrorKind> {
|
||||
let s = str.to_str()?;
|
||||
let re = regex.to_str()?;
|
||||
let re: Regex = Regex::new(&format!("^{}$", re.as_str())).unwrap();
|
||||
match re.captures(&s) {
|
||||
Some(caps) => Ok(caps
|
||||
|
@ -486,17 +538,18 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
.into()),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
},
|
||||
),
|
||||
Builtin::new(
|
||||
"mul",
|
||||
&[false, false],
|
||||
|args: Vec<Value>, vm: &mut VM| arithmetic_op!(&*args[0].force(vm)?, &*args[1].force(vm)?, *),
|
||||
),
|
||||
Builtin::new("parseDrvName", &[true], |args: Vec<Value>, _vm: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("mul")]
|
||||
fn builtin_mul(vm: &mut VM, #[lazy] x: Value, #[lazy] y: Value) -> Result<Value, ErrorKind> {
|
||||
arithmetic_op!(&*x.force(vm)?, &*y.force(vm)?, *)
|
||||
}
|
||||
|
||||
#[builtin("parseDrvName")]
|
||||
fn builtin_parse_drv_name(_vm: &mut VM, s: Value) -> Result<Value, ErrorKind> {
|
||||
// This replicates cppnix's (mis?)handling of codepoints
|
||||
// above U+007f following 0x2d ('-')
|
||||
let s = args[0].to_str()?;
|
||||
let s = s.to_str()?;
|
||||
let slice: &[u8] = s.as_str().as_ref();
|
||||
let (name, dash_and_version) = slice.split_at(
|
||||
slice
|
||||
|
@ -517,17 +570,15 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
(NixString::NAME, core::str::from_utf8(name)?.into()),
|
||||
("version".into(), version),
|
||||
]))))
|
||||
}),
|
||||
Builtin::new(
|
||||
"partition",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, vm: &mut VM| {
|
||||
}
|
||||
#[builtin("partition")]
|
||||
fn builtin_partition(vm: &mut VM, pred: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
let mut right: Vec<Value> = vec![];
|
||||
let mut wrong: Vec<Value> = vec![];
|
||||
|
||||
let list: NixList = args[1].to_list()?;
|
||||
let list: NixList = list.to_list()?;
|
||||
for elem in list.into_iter() {
|
||||
let result = vm.call_with(&args[0], [elem.clone()])?;
|
||||
let result = vm.call_with(&pred, [elem.clone()])?;
|
||||
|
||||
if result.force(vm)?.as_bool()? {
|
||||
right.push(elem);
|
||||
|
@ -541,14 +592,12 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
res.insert("wrong".into(), Value::List(wrong.into()));
|
||||
|
||||
Ok(Value::attrs(NixAttrs::from_map(res)))
|
||||
},
|
||||
),
|
||||
Builtin::new(
|
||||
"removeAttrs",
|
||||
&[true, true],
|
||||
|args: Vec<Value>, _: &mut VM| {
|
||||
let attrs = args[0].to_attrs()?;
|
||||
let keys = args[1]
|
||||
}
|
||||
|
||||
#[builtin("removeAttrs")]
|
||||
fn builtin_remove_attrs(_: &mut VM, attrs: Value, keys: Value) -> Result<Value, ErrorKind> {
|
||||
let attrs = attrs.to_attrs()?;
|
||||
let keys = keys
|
||||
.to_list()?
|
||||
.into_iter()
|
||||
.map(|v| v.to_str())
|
||||
|
@ -560,17 +609,20 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
}
|
||||
}
|
||||
Ok(Value::attrs(NixAttrs::from_map(res)))
|
||||
},
|
||||
),
|
||||
Builtin::new(
|
||||
"replaceStrings",
|
||||
&[true, true, true],
|
||||
|args: Vec<Value>, vm: &mut VM| {
|
||||
let from = args[0].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("replaceStrings")]
|
||||
fn builtin_replace_strings(
|
||||
vm: &mut VM,
|
||||
from: Value,
|
||||
to: Value,
|
||||
s: Value,
|
||||
) -> Result<Value, ErrorKind> {
|
||||
let from = from.to_list()?;
|
||||
from.force_elements(vm)?;
|
||||
let to = args[1].to_list()?;
|
||||
let to = to.to_list()?;
|
||||
to.force_elements(vm)?;
|
||||
let string = args[2].to_str()?;
|
||||
let string = s.to_str()?;
|
||||
|
||||
let mut res = String::new();
|
||||
|
||||
|
@ -633,20 +685,20 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
}
|
||||
}
|
||||
Ok(Value::String(res.into()))
|
||||
},
|
||||
),
|
||||
Builtin::new("seq", &[true, true], |mut args: Vec<Value>, _: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("seq")]
|
||||
fn builtin_seq(_: &mut VM, _x: Value, y: Value) -> Result<Value, ErrorKind> {
|
||||
// The builtin calling infra has already forced both args for us, so
|
||||
// we just return the second and ignore the first
|
||||
Ok(args.pop().unwrap())
|
||||
}),
|
||||
Builtin::new(
|
||||
"split",
|
||||
&[true, true],
|
||||
|mut args: Vec<Value>, _: &mut VM| {
|
||||
let s = args.pop().unwrap().to_str()?;
|
||||
Ok(y)
|
||||
}
|
||||
|
||||
#[builtin("split")]
|
||||
fn builtin_split(_: &mut VM, regex: Value, str: Value) -> Result<Value, ErrorKind> {
|
||||
let s = str.to_str()?;
|
||||
let text = s.as_str();
|
||||
let re = args.pop().unwrap().to_str()?;
|
||||
let re = regex.to_str()?;
|
||||
let re: Regex = Regex::new(re.as_str()).unwrap();
|
||||
let mut capture_locations = re.capture_locations();
|
||||
let num_captures = capture_locations.len();
|
||||
|
@ -676,11 +728,11 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
ret.push(Value::from(&text[pos..]));
|
||||
|
||||
Ok(Value::List(ret))
|
||||
},
|
||||
),
|
||||
Builtin::new("sort", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||
let mut list = args[1].to_list()?;
|
||||
let comparator = &args[0];
|
||||
}
|
||||
|
||||
#[builtin("sort")]
|
||||
fn builtin_sort(vm: &mut VM, comparator: Value, list: Value) -> Result<Value, ErrorKind> {
|
||||
let mut list = list.to_list()?;
|
||||
|
||||
// Used to let errors "escape" from the sorting closure. If anything
|
||||
// ends up setting an error, it is returned from this function.
|
||||
|
@ -688,7 +740,7 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
|
||||
list.sort_by(|lhs, rhs| {
|
||||
let result = vm
|
||||
.call_with(comparator, [lhs.clone(), rhs.clone()])
|
||||
.call_with(&comparator, [lhs.clone(), rhs.clone()])
|
||||
.map_err(|err| ErrorKind::ThunkForce(Box::new(err)))
|
||||
.and_then(|v| v.force(vm)?.as_bool());
|
||||
|
||||
|
@ -714,9 +766,11 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
None => Ok(Value::List(list)),
|
||||
Some(e) => Err(e),
|
||||
}
|
||||
}),
|
||||
Builtin::new("splitVersion", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
let s = args[0].to_str()?;
|
||||
}
|
||||
|
||||
#[builtin("splitVersion")]
|
||||
fn builtin_split_version(_: &mut VM, s: Value) -> Result<Value, ErrorKind> {
|
||||
let s = s.to_str()?;
|
||||
let s = VersionPartsIter::new(s.as_str());
|
||||
|
||||
let parts = s
|
||||
|
@ -728,24 +782,30 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
})
|
||||
.collect::<Vec<Value>>();
|
||||
Ok(Value::List(NixList::construct(parts.len(), parts)))
|
||||
}),
|
||||
Builtin::new("stringLength", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("stringLength")]
|
||||
fn builtin_string_length(vm: &mut VM, #[lazy] s: Value) -> Result<Value, ErrorKind> {
|
||||
// also forces the value
|
||||
let s = args[0].coerce_to_string(CoercionKind::Weak, vm)?;
|
||||
let s = s.coerce_to_string(CoercionKind::Weak, vm)?;
|
||||
Ok(Value::Integer(s.as_str().len() as i64))
|
||||
}),
|
||||
Builtin::new(
|
||||
"sub",
|
||||
&[false, false],
|
||||
|args: Vec<Value>, vm: &mut VM| arithmetic_op!(&*args[0].force(vm)?, &*args[1].force(vm)?, -),
|
||||
),
|
||||
Builtin::new(
|
||||
"substring",
|
||||
&[true, true, true],
|
||||
|args: Vec<Value>, _: &mut VM| {
|
||||
let beg = args[0].as_int()?;
|
||||
let len = args[1].as_int()?;
|
||||
let x = args[2].to_str()?;
|
||||
}
|
||||
|
||||
#[builtin("sub")]
|
||||
fn builtin_sub(vm: &mut VM, #[lazy] x: Value, #[lazy] y: Value) -> Result<Value, ErrorKind> {
|
||||
arithmetic_op!(&*x.force(vm)?, &*y.force(vm)?, -)
|
||||
}
|
||||
|
||||
#[builtin("substring")]
|
||||
fn builtin_substring(
|
||||
_: &mut VM,
|
||||
start: Value,
|
||||
len: Value,
|
||||
s: Value,
|
||||
) -> Result<Value, ErrorKind> {
|
||||
let beg = start.as_int()?;
|
||||
let len = len.as_int()?;
|
||||
let x = s.to_str()?;
|
||||
|
||||
if beg < 0 {
|
||||
return Err(ErrorKind::IndexOutOfBounds { index: beg });
|
||||
|
@ -769,10 +829,11 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
Ok(Value::String(
|
||||
x.as_str()[(beg as usize)..(end as usize)].into(),
|
||||
))
|
||||
},
|
||||
),
|
||||
Builtin::new("tail", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
let xs = args[0].to_list()?;
|
||||
}
|
||||
|
||||
#[builtin("tail")]
|
||||
fn builtin_tail(_: &mut VM, list: Value) -> Result<Value, ErrorKind> {
|
||||
let xs = list.to_list()?;
|
||||
|
||||
if xs.len() == 0 {
|
||||
Err(ErrorKind::TailEmptyList)
|
||||
|
@ -780,31 +841,38 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
let output = xs.into_iter().skip(1).collect::<Vec<_>>();
|
||||
Ok(Value::List(NixList::construct(output.len(), output)))
|
||||
}
|
||||
}),
|
||||
Builtin::new("throw", &[true], |args: Vec<Value>, _: &mut VM| {
|
||||
Err(ErrorKind::Throw(args[0].to_str()?.to_string()))
|
||||
}),
|
||||
}
|
||||
|
||||
#[builtin("throw")]
|
||||
fn builtin_throw(_: &mut VM, message: Value) -> Result<Value, ErrorKind> {
|
||||
Err(ErrorKind::Throw(message.to_str()?.to_string()))
|
||||
}
|
||||
|
||||
#[builtin("toString")]
|
||||
fn builtin_to_string(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
// coerce_to_string forces for us
|
||||
Builtin::new("toString", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
args[0]
|
||||
.coerce_to_string(CoercionKind::Strong, vm)
|
||||
x.coerce_to_string(CoercionKind::Strong, vm)
|
||||
.map(Value::String)
|
||||
}),
|
||||
Builtin::new(
|
||||
"trace",
|
||||
&[true, true],
|
||||
|mut args: Vec<Value>, _: &mut VM| {
|
||||
let value = args.pop().unwrap();
|
||||
let trace_value = args.pop().unwrap();
|
||||
}
|
||||
|
||||
#[builtin("trace")]
|
||||
fn builtin_trace(_: &mut VM, message: Value, value: Value) -> Result<Value, ErrorKind> {
|
||||
// TODO(grfn): `trace` should be pluggable and capturable, probably via a method on
|
||||
// the VM
|
||||
println!("trace: {} :: {}", trace_value, trace_value.type_of());
|
||||
println!("trace: {} :: {}", message, message.type_of());
|
||||
Ok(value)
|
||||
},
|
||||
),
|
||||
Builtin::new("tryEval", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("toPath")]
|
||||
fn builtin_to_path(vm: &mut VM, #[lazy] s: Value) -> Result<Value, ErrorKind> {
|
||||
let path: Value = crate::value::canon_path(coerce_value_to_path(&s, vm)?).into();
|
||||
Ok(path.coerce_to_string(CoercionKind::Weak, vm)?.into())
|
||||
}
|
||||
|
||||
#[builtin("tryEval")]
|
||||
fn builtin_try_eval(vm: &mut VM, #[lazy] e: Value) -> Result<Value, ErrorKind> {
|
||||
let mut res = BTreeMap::new();
|
||||
match args[0].force(vm) {
|
||||
match e.force(vm) {
|
||||
Ok(value) => {
|
||||
res.insert("value".into(), (*value).clone());
|
||||
res.insert("success".into(), true.into());
|
||||
|
@ -816,23 +884,19 @@ fn pure_builtins() -> Vec<Builtin> {
|
|||
Err(e) => return Err(e),
|
||||
}
|
||||
Ok(Value::attrs(NixAttrs::from_map(res)))
|
||||
}),
|
||||
Builtin::new("toPath", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
let path: Value = crate::value::canon_path(coerce_value_to_path(&args[0], vm)?).into();
|
||||
Ok(path.coerce_to_string(CoercionKind::Weak, vm)?.into())
|
||||
}),
|
||||
Builtin::new("typeOf", &[false], |args: Vec<Value>, vm: &mut VM| {
|
||||
}
|
||||
|
||||
#[builtin("typeOf")]
|
||||
fn builtin_type_of(vm: &mut VM, #[lazy] x: Value) -> Result<Value, ErrorKind> {
|
||||
// We force manually here because it also unwraps the Thunk
|
||||
// representation, if any.
|
||||
// TODO(sterni): it'd be nice if we didn't have to worry about this
|
||||
let value = args[0].force(vm)?;
|
||||
let value = x.force(vm)?;
|
||||
Ok(Value::String(value.type_of().into()))
|
||||
}),
|
||||
];
|
||||
|
||||
bs.extend(pure_builtins::builtins());
|
||||
bs
|
||||
}
|
||||
}
|
||||
|
||||
pub use pure_builtins::builtins as pure_builtins;
|
||||
|
||||
/// Placeholder builtins that technically have a function which we do
|
||||
/// not yet implement, but which is also not easily observable from
|
||||
|
|
Loading…
Reference in a new issue