snix_eval/compiler/
import.rs1use super::GlobalsMap;
9use genawaiter::rc::Gen;
10use std::rc::Weak;
11
12use crate::{
13 ErrorKind, SourceCode, Value,
14 builtins::coerce_value_to_path,
15 generators::pin_generator,
16 try_cek_to_value,
17 value::{Builtin, Thunk},
18 vm::generators::{self, GenCo},
19};
20
21async fn import_impl(
22 co: GenCo,
23 globals: Weak<GlobalsMap>,
24 source: SourceCode,
25 mut args: Vec<Value>,
26) -> Result<Value, ErrorKind> {
27 let mut path = try_cek_to_value!(coerce_value_to_path(&co, args.pop().unwrap()).await?);
29
30 if path.is_dir() {
31 path.push("default.nix");
32 }
33
34 if let Some(cached) = generators::request_import_cache_lookup(&co, path.clone()).await {
35 return Ok(cached);
36 }
37
38 let mut reader = generators::request_open_file(&co, path.clone()).await;
39 let mut contents = String::new();
42 reader.read_to_string(&mut contents)?;
43
44 let parsed = rnix::ast::Root::parse(&contents);
45 let errors = parsed.errors();
46 let file = source.add_file(path.to_string_lossy().to_string(), contents.to_owned());
47
48 if !errors.is_empty() {
49 return Err(ErrorKind::ImportParseError {
50 path,
51 file,
52 errors: errors.to_vec(),
53 });
54 }
55
56 let result = crate::compiler::compile(
57 &parsed.tree().expr().unwrap(),
58 Some(path.clone()),
59 globals
63 .upgrade()
64 .expect("globals dropped while still in use"),
65 None,
66 &source,
67 &file,
68 Default::default(),
69 )
70 .map_err(|err| ErrorKind::ImportCompilerError {
71 path: path.clone(),
72 errors: vec![err],
73 })?;
74
75 if !result.errors.is_empty() {
76 return Err(ErrorKind::ImportCompilerError {
77 path,
78 errors: result.errors,
79 });
80 }
81
82 for warning in result.warnings {
83 generators::emit_warning(&co, warning).await;
84 }
85
86 let res = Value::Thunk(Thunk::new_suspended(
89 result.lambda,
90 generators::request_span(&co).await,
91 ));
92
93 generators::request_import_cache_put(&co, path, res.clone()).await;
94
95 Ok(res)
96}
97
98pub(super) fn builtins_import(globals: &Weak<GlobalsMap>, source: SourceCode) -> Builtin {
104 let globals = globals.clone();
109
110 Builtin::new(
111 "import",
112 Some("Import the given file and return the Nix value it evaluates to"),
113 1,
114 move |args| {
115 Gen::new(|co| pin_generator(import_impl(co, globals.clone(), source.clone(), args)))
116 },
117 )
118}