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