diff options
Diffstat (limited to 'tvix')
-rw-r--r-- | tvix/eval/src/compiler.rs | 2 | ||||
-rw-r--r-- | tvix/eval/src/opcode.rs | 1 | ||||
-rw-r--r-- | tvix/eval/src/value/mod.rs | 10 | ||||
-rw-r--r-- | tvix/eval/src/vm.rs | 18 |
4 files changed, 30 insertions, 1 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs index 5da844448860..5b6f748dc72d 100644 --- a/tvix/eval/src/compiler.rs +++ b/tvix/eval/src/compiler.rs @@ -224,7 +224,7 @@ impl Compiler { // otherwise we need to emit an instruction to construct // the attribute path. if key_count > 1 { - todo!("emit OpAttrPath(n) instruction") + self.chunk.add_op(OpCode::OpAttrPath(2)); } // The value is just compiled as normal so that its diff --git a/tvix/eval/src/opcode.rs b/tvix/eval/src/opcode.rs index 0af8f23fc79d..622a02ac85f8 100644 --- a/tvix/eval/src/opcode.rs +++ b/tvix/eval/src/opcode.rs @@ -32,6 +32,7 @@ pub enum OpCode { // Attribute sets OpAttrs(usize), + OpAttrPath(usize), // Lists OpList(usize), diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs index d00fc56e2a73..8a95d00f416a 100644 --- a/tvix/eval/src/value/mod.rs +++ b/tvix/eval/src/value/mod.rs @@ -21,6 +21,10 @@ pub enum Value { String(NixString), Attrs(Rc<NixAttrs>), List(NixList), + + // Internal values that, while they technically exist at runtime, + // are never returned to or created directly by users. + AttrPath(Vec<NixString>), } impl Value { @@ -41,6 +45,9 @@ impl Value { Value::String(_) => "string", Value::Attrs(_) => "set", Value::List(_) => "list", + + // Internal types + Value::AttrPath(_) => "internal", } } @@ -76,6 +83,9 @@ impl Display for Value { Value::String(s) => s.fmt(f), Value::Attrs(attrs) => attrs.fmt(f), Value::List(list) => list.fmt(f), + + // internal types + Value::AttrPath(_) => f.write_str("internal"), } } } 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 |