about summary refs log tree commit diff
path: root/tvix/eval/src/vm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r--tvix/eval/src/vm.rs18
1 files changed, 18 insertions, 0 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index d6d3de154c7f..58ef67cb5531 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -121,6 +121,7 @@ impl VM {
                 OpCode::OpTrue => self.push(Value::Bool(true)),
                 OpCode::OpFalse => self.push(Value::Bool(false)),
                 OpCode::OpAttrs(count) => self.run_attrset(count)?,
+                OpCode::OpAttrPath(count) => self.run_attr_path(count)?,
                 OpCode::OpList(count) => self.run_list(count)?,
                 OpCode::OpInterpolate(count) => self.run_interpolate(count)?,
             }
@@ -218,6 +219,23 @@ impl VM {
         Ok(())
     }
 
+    // Construct runtime representation of an attr path (essentially
+    // just a list of strings).
+    //
+    // The difference to the list construction operation is that this
+    // forces all elements into strings, as attribute set keys are
+    // required to be strict in Nix.
+    fn run_attr_path(&mut self, count: usize) -> EvalResult<()> {
+        let mut path = vec![NixString(String::new()); count];
+
+        for idx in 0..count {
+            path[count - idx - 1] = self.pop().as_string()?
+        }
+
+        self.push(Value::AttrPath(path));
+        Ok(())
+    }
+
     // Construct runtime representation of a list. Because the list
     // items are on the stack in reverse order, the vector is created
     // initialised and elements are directly assigned to their