about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--corp/tvixbolt/src/main.rs4
-rw-r--r--tvix/eval/src/builtins/impure.rs8
-rw-r--r--tvix/eval/src/compiler/mod.rs14
-rw-r--r--tvix/eval/src/eval.rs20
4 files changed, 32 insertions, 14 deletions
diff --git a/corp/tvixbolt/src/main.rs b/corp/tvixbolt/src/main.rs
index a389a33f04ed..f81ae070a2ce 100644
--- a/corp/tvixbolt/src/main.rs
+++ b/corp/tvixbolt/src/main.rs
@@ -1,4 +1,6 @@
+use std::cell::RefCell;
 use std::fmt::Write;
+use std::rc::Rc;
 
 use serde::{Deserialize, Serialize};
 use tvix_eval::observer::TracingObserver;
@@ -256,7 +258,7 @@ fn eval(trace: bool, code: &str) -> Output {
         &root_expr,
         Some("/nixbolt".into()),
         file.clone(),
-        tvix_eval::global_builtins(),
+        Rc::new(RefCell::new(tvix_eval::global_builtins())),
         &mut compilation_observer,
     )
     .unwrap();
diff --git a/tvix/eval/src/builtins/impure.rs b/tvix/eval/src/builtins/impure.rs
index 675bdd50950e..7c98fcb4e192 100644
--- a/tvix/eval/src/builtins/impure.rs
+++ b/tvix/eval/src/builtins/impure.rs
@@ -1,4 +1,5 @@
 use std::{
+    cell::RefCell,
     collections::{BTreeMap, HashMap},
     rc::Rc,
     time::{SystemTime, UNIX_EPOCH},
@@ -43,7 +44,10 @@ pub(super) fn builtins() -> BTreeMap<NixString, Value> {
 /// it needs to capture the [crate::SourceCode] structure to correctly track
 /// source code locations while invoking a compiler.
 // TODO: need to be able to pass through a CompilationObserver, too.
-pub fn builtins_import(source: SourceCode) -> Builtin {
+pub fn builtins_import(
+    globals: Rc<RefCell<HashMap<&'static str, Value>>>,
+    source: SourceCode,
+) -> Builtin {
     Builtin::new(
         "import",
         &[true],
@@ -83,7 +87,7 @@ pub fn builtins_import(source: SourceCode) -> Builtin {
                 &parsed.tree().expr().unwrap(),
                 Some(path.clone()),
                 file,
-                HashMap::new(), // TODO: pass through globals
+                globals.clone(),
                 &mut NoOpObserver::default(),
             )
             .map_err(|err| ErrorKind::ImportCompilerError {
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs
index eb617b227351..472f4aaf363d 100644
--- a/tvix/eval/src/compiler/mod.rs
+++ b/tvix/eval/src/compiler/mod.rs
@@ -21,6 +21,7 @@ use codemap::Span;
 use path_clean::PathClean;
 use rnix::ast::{self, AstToken};
 use smol_str::SmolStr;
+use std::cell::RefCell;
 use std::collections::HashMap;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
@@ -103,7 +104,7 @@ impl<'observer> Compiler<'observer> {
     pub(crate) fn new(
         location: Option<PathBuf>,
         file: Arc<codemap::File>,
-        globals: HashMap<&'static str, Value>,
+        globals: Rc<RefCell<HashMap<&'static str, Value>>>,
         observer: &'observer mut dyn CompilerObserver,
     ) -> EvalResult<Self> {
         let mut root_dir = match location {
@@ -124,11 +125,13 @@ impl<'observer> Compiler<'observer> {
             root_dir.pop();
         }
 
+        let globals = globals.borrow();
+
         Ok(Self {
             root_dir,
             file,
             observer,
-            globals: prepare_globals(globals),
+            globals: prepare_globals(&globals),
             contexts: vec![LambdaCtx::new()],
             warnings: vec![],
             errors: vec![],
@@ -1103,7 +1106,7 @@ fn optimise_tail_call(chunk: &mut Chunk) {
 /// Note that all builtin functions are *not* considered part of the
 /// language in this sense and MUST be supplied as additional global
 /// values, including the `builtins` set itself.
-fn prepare_globals(additional: HashMap<&'static str, Value>) -> GlobalsMap {
+fn prepare_globals(additional: &HashMap<&'static str, Value>) -> GlobalsMap {
     let mut globals: GlobalsMap = HashMap::new();
 
     globals.insert(
@@ -1127,7 +1130,8 @@ fn prepare_globals(additional: HashMap<&'static str, Value>) -> GlobalsMap {
         }),
     );
 
-    for (ident, value) in additional.into_iter() {
+    for (ident, value) in additional.iter() {
+        let value: Value = value.clone();
         globals.insert(
             ident,
             Rc::new(move |compiler, span| compiler.emit_constant(value.clone(), &span)),
@@ -1141,7 +1145,7 @@ pub fn compile(
     expr: &ast::Expr,
     location: Option<PathBuf>,
     file: Arc<codemap::File>,
-    globals: HashMap<&'static str, Value>,
+    globals: Rc<RefCell<HashMap<&'static str, Value>>>,
     observer: &mut dyn CompilerObserver,
 ) -> EvalResult<CompilationOutput> {
     let mut c = Compiler::new(location, file, globals, observer)?;
diff --git a/tvix/eval/src/eval.rs b/tvix/eval/src/eval.rs
index aed4292282b9..4e50b7279c38 100644
--- a/tvix/eval/src/eval.rs
+++ b/tvix/eval/src/eval.rs
@@ -1,4 +1,4 @@
-use std::path::PathBuf;
+use std::{cell::RefCell, path::PathBuf, rc::Rc};
 
 use crate::{
     builtins::global_builtins,
@@ -59,13 +59,21 @@ pub fn interpret(code: &str, location: Option<PathBuf>, options: Options) -> Eva
     }
 
     // TODO: encapsulate this import weirdness in builtins
-    let mut builtins = global_builtins();
+
+    let builtins = Rc::new(RefCell::new(global_builtins()));
 
     #[cfg(feature = "impure")]
-    builtins.insert(
-        "import",
-        Value::Builtin(crate::builtins::impure::builtins_import(source.clone())),
-    );
+    {
+        // We need to insert import into the builtins, but the
+        // builtins passed to import must have import *in it*.
+        let import = Value::Builtin(crate::builtins::impure::builtins_import(
+            builtins.clone(),
+            source.clone(),
+        ));
+
+        builtins.borrow_mut().insert("import", import);
+        // TODO: also add it into the inner builtins set
+    };
 
     let result = if options.dump_bytecode {
         crate::compiler::compile(