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