From 6fe5e2d75257504f0321e2e98b6fb675b716fe25 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 12 Aug 2022 18:28:45 +0300 Subject: feat(tvix/eval): resolve relative path literals 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 --- tvix/eval/src/compiler.rs | 26 +++++++++++++++++++++++--- tvix/eval/src/eval.rs | 6 ++++-- tvix/eval/src/main.rs | 11 ++++++++--- tvix/eval/src/tests/mod.rs | 4 ++-- 4 files changed, 37 insertions(+), 10 deletions(-) (limited to 'tvix') diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs index c5ec664dc2cf..63a02f68c013 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, + 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 { +pub fn compile(ast: rnix::AST, location: Option) -> EvalResult { + 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 31280e4cd197..903708f108b3 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 { +pub fn interpret(code: &str, location: Option) -> EvalResult { let ast = rnix::parse(code); let errors = ast.errors(); @@ -14,7 +16,7 @@ pub fn interpret(code: &str) -> EvalResult { 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 0c4d082783e2..3d0c29688e6d 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 ca8c114ba320..313498eeb777 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!( -- cgit 1.4.1