about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/compiler/mod.rs20
-rw-r--r--tvix/eval/src/opcode.rs3
-rw-r--r--tvix/eval/src/vm.rs20
3 files changed, 31 insertions, 12 deletions
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs
index 11537e76b5c9..95de69487071 100644
--- a/tvix/eval/src/compiler/mod.rs
+++ b/tvix/eval/src/compiler/mod.rs
@@ -268,19 +268,15 @@ impl Compiler<'_> {
         let path = if raw_path.starts_with('/') {
             Path::new(&raw_path).to_owned()
         } else if raw_path.starts_with('~') {
-            let mut buf = match dirs::home_dir() {
-                Some(buf) => buf,
-                None => {
-                    self.emit_error(
-                        node,
-                        ErrorKind::PathResolution("failed to determine home directory".into()),
-                    );
-                    return;
-                }
-            };
+            return self.thunk(slot, node, move |c, _| {
+                // We assume that paths that home paths start with ~/ or fail to parse
+                // TODO: this should be checked using a parse-fail test.
+                debug_assert!(raw_path.len() > 2 && raw_path.starts_with("~/"));
 
-            buf.push(&raw_path);
-            buf
+                let home_relative_path = &raw_path[2..(raw_path.len())];
+                c.emit_constant(Value::UnresolvedPath(home_relative_path.into()), node);
+                c.push_op(OpCode::OpResolveHomePath, node);
+            });
         } else if raw_path.starts_with('.') {
             let mut buf = self.root_dir.clone();
             buf.push(&raw_path);
diff --git a/tvix/eval/src/opcode.rs b/tvix/eval/src/opcode.rs
index fdc916ca7f79..70ef1a3b5324 100644
--- a/tvix/eval/src/opcode.rs
+++ b/tvix/eval/src/opcode.rs
@@ -117,6 +117,9 @@ pub enum OpCode {
     /// [`NixSearchPath`]: crate::nix_search_path::NixSearchPath
     OpFindFile,
 
+    /// Attempt to resolve a path literal relative to the home dir
+    OpResolveHomePath,
+
     // Type assertion operators
     OpAssertBool,
 
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index 05adec5f6ea6..7fcdb9ea739b 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -536,6 +536,26 @@ impl<'o> VM<'o> {
                 _ => panic!("tvix compiler bug: OpFindFile called on non-UnresolvedPath"),
             },
 
+            OpCode::OpResolveHomePath => match self.pop() {
+                Value::UnresolvedPath(path) => {
+                    match dirs::home_dir() {
+                        None => {
+                            return Err(self.error(ErrorKind::PathResolution(
+                                "failed to determine home directory".into(),
+                            )));
+                        }
+                        Some(mut buf) => {
+                            buf.push(path);
+                            self.push(buf.into());
+                        }
+                    };
+                }
+
+                _ => {
+                    panic!("tvix compiler bug: OpResolveHomePath called on non-UnresolvedPath")
+                }
+            },
+
             OpCode::OpJump(JumpOffset(offset)) => {
                 debug_assert!(offset != 0);
                 self.frame_mut().ip += offset;