about summary refs log tree commit diff
path: root/tvix/eval/src
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2022-10-10T01·59-0400
committergrfn <grfn@gws.fyi>2022-10-10T20·23+0000
commit0e9f5d6890df5820be836cff78622d3f1dcfe155 (patch)
treec1fc503c54e0858082449e5b630df641a4189982 /tvix/eval/src
parent66a35de3b67dd441185b7badaf559c8a25ab9967 (diff)
feat(tvix/eval): Allow adding strings to paths r/5085
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 <grfn@gws.fyi>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src')
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.exp1
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-add-paths.nix9
-rw-r--r--tvix/eval/src/value/mod.rs6
-rw-r--r--tvix/eval/src/vm.rs19
4 files changed, 30 insertions, 5 deletions
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 000000000000..94ba9a881ae6
--- /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 000000000000..462f670882a0
--- /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 0e9d013fdf61..31ac0c07d4c2 100644
--- a/tvix/eval/src/value/mod.rs
+++ b/tvix/eval/src/value/mod.rs
@@ -383,6 +383,12 @@ impl From<String> for Value {
     }
 }
 
+impl From<PathBuf> 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 01299ccc17da..cf766fb33523 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)