From 59f50dc81a6afe8d2cd77d96ffb1d92f40c971cc Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Mon, 15 Aug 2022 01:13:17 +0300 Subject: feat(tvix/eval): Implement OpResolveWith instruction Change-Id: I4d2a69f28a6b6199b3ff48ef81135e7da9fe1c3b Reviewed-on: https://cl.tvl.fyi/c/depot/+/6222 Tested-by: BuildkiteCI Reviewed-by: sterni Reviewed-by: grfn --- tvix/eval/src/errors.rs | 3 +++ tvix/eval/src/opcode.rs | 1 + tvix/eval/src/vm.rs | 21 ++++++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) (limited to 'tvix/eval') diff --git a/tvix/eval/src/errors.rs b/tvix/eval/src/errors.rs index e262d9def417..a5ba5bf40059 100644 --- a/tvix/eval/src/errors.rs +++ b/tvix/eval/src/errors.rs @@ -28,6 +28,9 @@ pub enum Error { // Unknown variable in statically known scope. UnknownStaticVariable(rnix::types::Ident), + + // Unknown variable in dynamic scope (with, rec, ...). + UnknownDynamicVariable(String), } impl Display for Error { diff --git a/tvix/eval/src/opcode.rs b/tvix/eval/src/opcode.rs index 7d2de537d522..7dcfea93aaf7 100644 --- a/tvix/eval/src/opcode.rs +++ b/tvix/eval/src/opcode.rs @@ -55,6 +55,7 @@ pub enum OpCode { // `with`-handling OpPushWith(usize), OpPopWith, + OpResolveWith, // Lists OpList(usize), diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs index 8a6959114fff..09e3aa247555 100644 --- a/tvix/eval/src/vm.rs +++ b/tvix/eval/src/vm.rs @@ -98,7 +98,7 @@ impl VM { #[cfg(feature = "disassembler")] let mut tracer = Tracer::new(); - loop { + 'dispatch: loop { let op = self.inc_ip(); match op { OpCode::OpConstant(idx) => { @@ -285,6 +285,25 @@ impl VM { OpCode::OpPopWith => { self.with_stack.pop(); } + + OpCode::OpResolveWith => { + let ident = self.pop().to_string()?; + + // Attempt to resolve the variable, starting at + // the back of the with_stack. + 'with: for idx in self.with_stack.iter().rev() { + let with = self.stack[*idx].as_attrs()?; + match with.select(ident.as_str()) { + None => continue 'with, + Some(val) => { + self.push(val.clone()); + continue 'dispatch; + } + } + } + + return Err(Error::UnknownDynamicVariable(ident.to_string())); + } } #[cfg(feature = "disassembler")] -- cgit 1.4.1