about summary refs log tree commit diff
path: root/tvix
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-12T15·28+0300
committertazjin <tazjin@tvl.su>2022-08-28T11·02+0000
commit6fe5e2d75257504f0321e2e98b6fb675b716fe25 (patch)
treebf0549b862e8bdf25dda9e9b3aa05c16889b0ba5 /tvix
parent1f8aad0ab41eec3db2e892bf80b6b76d54d36bbc (diff)
feat(tvix/eval): resolve relative path literals r/4519
Resolves relative paths (e.g. `./foo`) either relative to the location
of the Nix file, or relative to the working directory if none is
supplied.

Change-Id: I70ec574657b221b458015117a004b6e4a9c25a30
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6185
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Diffstat (limited to 'tvix')
-rw-r--r--tvix/eval/src/compiler.rs26
-rw-r--r--tvix/eval/src/eval.rs6
-rw-r--r--tvix/eval/src/main.rs11
-rw-r--r--tvix/eval/src/tests/mod.rs4
4 files changed, 37 insertions, 10 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs
index c5ec664dc2..63a02f68c0 100644
--- a/tvix/eval/src/compiler.rs
+++ b/tvix/eval/src/compiler.rs
@@ -13,7 +13,7 @@
 //! the code in this module, `debug_assert!` has been used to catch
 //! mistakes early during development.
 
-use std::path::Path;
+use std::path::{Path, PathBuf};
 
 use crate::chunk::Chunk;
 use crate::errors::{Error, EvalResult};
@@ -35,6 +35,7 @@ pub struct CompilationResult {
 struct Compiler {
     chunk: Chunk,
     warnings: Vec<EvalWarning>,
+    root_dir: PathBuf,
 }
 
 impl Compiler {
@@ -175,7 +176,11 @@ impl Compiler {
                 buf
             }
 
-            rnix::value::Anchor::Relative => todo!("resolve relative to file location"),
+            rnix::value::Anchor::Relative => {
+                let mut buf = self.root_dir.clone();
+                buf.push(path);
+                buf
+            }
 
             // This confusingly named variant is actually
             // angle-bracket lookups, which in C++ Nix desugar
@@ -624,8 +629,23 @@ impl Compiler {
     }
 }
 
-pub fn compile(ast: rnix::AST) -> EvalResult<CompilationResult> {
+pub fn compile(ast: rnix::AST, location: Option<PathBuf>) -> EvalResult<CompilationResult> {
+    let mut root_dir = match location {
+        Some(dir) => Ok(dir),
+        None => std::env::current_dir().map_err(|e| {
+            Error::PathResolution(format!("could not determine current directory: {}", e))
+        }),
+    }?;
+
+    // If the path passed from the caller points to a file, the
+    // filename itself needs to be truncated as this must point to a
+    // directory.
+    if root_dir.is_file() {
+        root_dir.pop();
+    }
+
     let mut c = Compiler {
+        root_dir,
         chunk: Chunk::default(),
         warnings: vec![],
     };
diff --git a/tvix/eval/src/eval.rs b/tvix/eval/src/eval.rs
index 31280e4cd1..903708f108 100644
--- a/tvix/eval/src/eval.rs
+++ b/tvix/eval/src/eval.rs
@@ -1,8 +1,10 @@
+use std::path::PathBuf;
+
 use rnix::{self, types::TypedNode};
 
 use crate::{errors::EvalResult, value::Value};
 
-pub fn interpret(code: &str) -> EvalResult<Value> {
+pub fn interpret(code: &str, location: Option<PathBuf>) -> EvalResult<Value> {
     let ast = rnix::parse(code);
 
     let errors = ast.errors();
@@ -14,7 +16,7 @@ pub fn interpret(code: &str) -> EvalResult<Value> {
         println!("{}", ast.root().dump());
     }
 
-    let result = crate::compiler::compile(ast)?;
+    let result = crate::compiler::compile(ast, location)?;
     println!("code: {:?}", result.chunk);
 
     for warning in result.warnings {
diff --git a/tvix/eval/src/main.rs b/tvix/eval/src/main.rs
index 0c4d082783..3d0c29688e 100644
--- a/tvix/eval/src/main.rs
+++ b/tvix/eval/src/main.rs
@@ -1,4 +1,8 @@
-use std::{env, fs, path::PathBuf, process};
+use std::{
+    env, fs,
+    path::{Path, PathBuf},
+    process,
+};
 
 use rustyline::{error::ReadlineError, Editor};
 
@@ -18,8 +22,9 @@ fn main() {
 
 fn run_file(file: &str) {
     let contents = fs::read_to_string(file).expect("failed to read the input file");
+    let path = Path::new(file).to_owned();
 
-    match tvix_eval::interpret(&contents) {
+    match tvix_eval::interpret(&contents, Some(path)) {
         Ok(result) => println!("=> {} :: {}", result, result.type_of()),
         Err(err) => eprintln!("{}", err),
     }
@@ -53,7 +58,7 @@ fn run_prompt() {
                     continue;
                 }
 
-                match tvix_eval::interpret(&line) {
+                match tvix_eval::interpret(&line, None) {
                     Ok(result) => {
                         println!("=> {} :: {}", result, result.type_of());
                         rl.add_history_entry(line);
diff --git a/tvix/eval/src/tests/mod.rs b/tvix/eval/src/tests/mod.rs
index ca8c114ba3..313498eeb7 100644
--- a/tvix/eval/src/tests/mod.rs
+++ b/tvix/eval/src/tests/mod.rs
@@ -11,7 +11,7 @@ fn eval_okay_test(code_path: &str) {
     let code = std::fs::read_to_string(code_path).expect("should be able to read test code");
     let exp = std::fs::read_to_string(exp_path).expect("should be able to read test expectation");
 
-    let result = interpret(&code).expect("evaluation of eval-okay test should succeed");
+    let result = interpret(&code, None).expect("evaluation of eval-okay test should succeed");
     let result_str = format!("{}", result);
 
     assert_eq!(
@@ -27,7 +27,7 @@ fn eval_okay_test(code_path: &str) {
 fn identity(code_path: &str) {
     let code = std::fs::read_to_string(code_path).expect("should be able to read test code");
 
-    let result = interpret(&code).expect("evaluation of identity test should succeed");
+    let result = interpret(&code, None).expect("evaluation of identity test should succeed");
     let result_str = format!("{}", result);
 
     assert_eq!(