use std::rc::Rc;
use crate::value::*;
mod arithmetic;
mod attrs;
mod coerce;
mod context;
mod control;
mod convert;
mod convert_helpers;
mod derivation;
mod fetchers;
mod flake;
mod flake_eval;
mod flake_parse;
mod flake_registry;
mod helpers;
mod import_cache;
mod lists;
mod misc;
mod activation_script_bridge;
mod bridge_helpers;
mod hash_bridge;
mod lock_file_bridge;
mod module_system_bridge;
mod narinfo_bridge;
mod nav;
mod realisation_bridge;
mod registry_bridge;
mod paths;
mod strings;
mod convergence;
mod sui_ext;
mod types;
mod versions;
pub(crate) use coerce::*;
pub(crate) use convert_helpers::*;
pub(crate) use fetchers::{
base64_encode, fetch_git, fetch_mercurial, fetch_tree, fetch_url_bytes,
format_unix_yyyymmddhhmmss, git_result_attrs, hex_to_bytes,
};
pub(crate) use flake_parse::{flake_ref_to_string, parse_flake_ref};
pub(crate) use helpers::*;
pub(crate) use sui_compat::versions::{compare_versions, parse_drv_name, split_version};
pub use derivation::build_derivation;
pub use derivation::parity_strict;
pub use flake_eval::{evaluate_flake, evaluate_flake_attr};
pub(crate) use flake_eval::{FLAKE_EVAL_DEPTH, MAX_FLAKE_EVAL_DEPTH};
pub use import_cache::clear_import_cache;
pub(crate) use import_cache::IMPORT_CACHE;
pub use nav::{navigate_attrs, parse_nix_path, resolve_search_path};
pub fn call_builtin_by_name(name: &str, args: &[Value]) -> Result<Value, EvalError> {
use std::cell::RefCell;
thread_local! {
static BUILTIN_REGISTRY: RefCell<Option<NixAttrs>> = const { RefCell::new(None) };
}
BUILTIN_REGISTRY.with(|reg| {
let mut borrow = reg.borrow_mut();
if borrow.is_none() {
let mut attrs = NixAttrs::new();
types::register(&mut attrs);
arithmetic::register(&mut attrs);
lists::register(&mut attrs);
attrs::register(&mut attrs);
strings::register(&mut attrs);
convert::register(&mut attrs);
control::register(&mut attrs);
context::register(&mut attrs);
paths::register(&mut attrs);
fetchers::register(&mut attrs);
flake::register(&mut attrs);
derivation::register(&mut attrs);
versions::register(&mut attrs);
misc::register(&mut attrs);
convergence::register(&mut attrs);
*borrow = Some(attrs);
}
let attrs = borrow.as_ref().unwrap();
let builtin_val = attrs.get(name).ok_or_else(|| {
EvalError::type_error(format!("bridge: unknown builtin '{name}'"))
})?;
match builtin_val {
Value::Builtin(bf) => {
if args.len() == 1 {
(bf.func)(args)
} else if args.len() == 2 {
let partial = (bf.func)(&args[..1])?;
match partial {
Value::Builtin(ref pf) => (pf.func)(&args[1..]),
_ => Ok(partial),
}
} else if args.is_empty() {
Err(EvalError::type_error(
format!("bridge: builtin '{name}' called with no arguments"),
))
} else {
let mut result = (bf.func)(&args[..1])?;
for arg in &args[1..] {
match result {
Value::Builtin(ref pf) => {
result = (pf.func)(&[arg.clone()])?;
}
_ => break,
}
}
Ok(result)
}
}
_ => Err(EvalError::type_error(
format!("bridge: '{name}' is not a builtin function"),
)),
}
})
}
pub fn register(env: &mut Env) {
let mut builtins_set = NixAttrs::new();
types::register(&mut builtins_set);
arithmetic::register(&mut builtins_set);
lists::register(&mut builtins_set);
attrs::register(&mut builtins_set);
strings::register(&mut builtins_set);
convert::register(&mut builtins_set);
control::register(&mut builtins_set);
context::register(&mut builtins_set);
paths::register(&mut builtins_set);
fetchers::register(&mut builtins_set);
flake::register(&mut builtins_set);
derivation::register(&mut builtins_set);
versions::register(&mut builtins_set);
misc::register(&mut builtins_set);
builtins_set.insert("storeDir".to_string(), Value::string("/nix/store"));
let nix_path_value: Value = {
let entries = parse_nix_path(&std::env::var("NIX_PATH").unwrap_or_default());
let list: Vec<Value> = entries
.into_iter()
.map(|(prefix, path)| {
let mut a = NixAttrs::new();
a.insert("prefix".to_string(), Value::string(prefix));
a.insert("path".to_string(), Value::string(path));
Value::Attrs(Rc::new(a))
})
.collect();
Value::list(list)
};
builtins_set.insert("nixPath".to_string(), nix_path_value);
builtins_set.insert("true".to_string(), Value::Bool(true));
builtins_set.insert("false".to_string(), Value::Bool(false));
builtins_set.insert("null".to_string(), Value::Null);
builtins_set.insert(
"nixVersion".to_string(),
Value::string(sui_compat::versions::IMPERSONATED_NIX_VERSION),
);
builtins_set.insert("currentSystem".to_string(), Value::string(current_system()));
builtins_set.insert(
"langVersion".to_string(),
Value::Int(sui_compat::versions::LANG_VERSION),
);
let mut sui_ext_set = NixAttrs::new();
sui_ext::register(&mut sui_ext_set);
convergence::register(&mut sui_ext_set);
module_system_bridge::register(&mut sui_ext_set);
activation_script_bridge::register(&mut sui_ext_set);
hash_bridge::register(&mut sui_ext_set);
lock_file_bridge::register(&mut sui_ext_set);
narinfo_bridge::register(&mut sui_ext_set);
registry_bridge::register(&mut sui_ext_set);
realisation_bridge::register(&mut sui_ext_set);
builtins_set.insert("sui".to_string(), Value::Attrs(Rc::new(sui_ext_set)));
let builtins_snapshot = Value::Attrs(Rc::new(builtins_set.clone()));
builtins_set.insert("builtins".to_string(), builtins_snapshot);
env.bind("builtins".to_string(), Value::Attrs(Rc::new(builtins_set.clone())));
const DEFAULT_SCOPE: &[&str] = &[
"abort",
"baseNameOf",
"derivation",
"derivationStrict",
"dirOf",
"false",
"fetchGit",
"fetchMercurial",
"fetchTarball",
"fetchTree",
"fromTOML",
"import",
"isNull",
"map",
"null",
"placeholder",
"removeAttrs",
"scopedImport",
"throw",
"toString",
"true",
];
for name in DEFAULT_SCOPE {
if let Some(v) = builtins_set.get(name) {
env.bind((*name).to_string(), v.clone());
}
}
}
#[cfg(test)]
#[path = "tests.rs"]
mod tests;