From 0e9f5d6890df5820be836cff78622d3f1dcfe155 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Sun, 9 Oct 2022 21:59:41 -0400 Subject: feat(tvix/eval): Allow adding strings to paths Implement adding paths and strings via OpAdd. Since the nix rules are quite obscure, I'm electing to test this one with an oracle test to avoid the danger of getting the actual asserted result wrong. Change-Id: Icdcca3690ca2e8459e386c1f29cc48eaaa39e9a3 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6914 Autosubmit: grfn Reviewed-by: tazjin Tested-by: BuildkiteCI --- .../eval/src/tests/tvix_tests/eval-okay-add-paths.exp | 1 + .../eval/src/tests/tvix_tests/eval-okay-add-paths.nix | 9 +++++++++ tvix/eval/src/value/mod.rs | 6 ++++++ tvix/eval/src/vm.rs | 19 ++++++++++++++----- tvix/eval/tests/nix_oracle.rs | 11 ++++++++++- 5 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.exp create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.nix diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.exp new file mode 100644 index 0000000000..94ba9a881a --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.exp @@ -0,0 +1 @@ +[ /bin /binbar /binbar /binbar /binbar /bin/bar /bin/bin ] diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.nix new file mode 100644 index 0000000000..462f670882 --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.nix @@ -0,0 +1,9 @@ +[ + (/bin + "/") + (/bin + "bar") + (let name = "bar"; in /bin + name) + (let name = "bar"; in /bin + "${name}") + (let name = "bar"; in /bin + "/" + "${name}") + (let name = "bar"; in /bin + "/${name}") + (/bin + /bin) +] diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs index 0e9d013fdf..31ac0c07d4 100644 --- a/tvix/eval/src/value/mod.rs +++ b/tvix/eval/src/value/mod.rs @@ -383,6 +383,12 @@ impl From for Value { } } +impl From for Value { + fn from(path: PathBuf) -> Self { + Self::Path(path) + } +} + fn type_error(expected: &'static str, actual: &Value) -> ErrorKind { ErrorKind::TypeError { expected, diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs index 01299ccc17..cf766fb335 100644 --- a/tvix/eval/src/vm.rs +++ b/tvix/eval/src/vm.rs @@ -1,7 +1,9 @@ //! This module implements the virtual (or abstract) machine that runs //! Tvix bytecode. -use std::{cell::RefMut, rc::Rc}; +use std::{cell::RefMut, path::PathBuf, rc::Rc}; + +use path_clean::PathClean; use crate::{ chunk::Chunk, @@ -347,10 +349,17 @@ impl<'o> VM<'o> { let b = self.pop(); let a = self.pop(); - let result = if let (Value::String(s1), Value::String(s2)) = (&a, &b) { - Value::String(s1.concat(s2)) - } else { - fallible!(self, arithmetic_op!(&a, &b, +)) + let result = match (&a, &b) { + (Value::String(s1), Value::String(s2)) => Value::String(s1.concat(s2)), + (Value::Path(p), v) => { + let mut path = p.to_string_lossy().into_owned(); + path.push_str( + &v.coerce_to_string(CoercionKind::Weak, self) + .map_err(|ek| self.error(ek))?, + ); + PathBuf::from(path).clean().into() + } + _ => fallible!(self, arithmetic_op!(&a, &b, +)), }; self.push(result) diff --git a/tvix/eval/tests/nix_oracle.rs b/tvix/eval/tests/nix_oracle.rs index 61f2be674e..34ed503510 100644 --- a/tvix/eval/tests/nix_oracle.rs +++ b/tvix/eval/tests/nix_oracle.rs @@ -15,7 +15,7 @@ fn nix_eval(expr: &str) -> String { let store_dir = TempDir::new("store-dir").unwrap(); let output = Command::new(nix_binary_path()) - .args(["--eval", "-E"]) + .args(["--eval", "--strict", "-E"]) .arg(format!("({expr})")) .env( "NIX_REMOTE", @@ -66,4 +66,13 @@ compare_eval_tests! { literal_int("1"); add_ints("1 + 1"); add_lists("[1 2] ++ [3 4]"); + add_paths(r#"[ + (./. + "/") + (./foo + "bar") + (let name = "bar"; in ./foo + name) + (let name = "bar"; in ./foo + "${name}") + (let name = "bar"; in ./foo + "/" + "${name}") + (let name = "bar"; in ./foo + "/${name}") + (./. + ./.) + ]"#); } -- cgit 1.4.1