diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-14T22·13+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-08-31T22·26+0000 |
commit | 59f50dc81a6afe8d2cd77d96ffb1d92f40c971cc (patch) | |
tree | 452ca647895b8bd13804b0c10a98101d19ccf5f0 /tvix | |
parent | 911fb96eca84a3059ecc11af9c3ac6fdacc28166 (diff) |
feat(tvix/eval): Implement OpResolveWith instruction r/4556
Change-Id: I4d2a69f28a6b6199b3ff48ef81135e7da9fe1c3b Reviewed-on: https://cl.tvl.fyi/c/depot/+/6222 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org> Reviewed-by: grfn <grfn@gws.fyi>
Diffstat (limited to 'tvix')
-rw-r--r-- | tvix/eval/src/errors.rs | 3 | ||||
-rw-r--r-- | tvix/eval/src/opcode.rs | 1 | ||||
-rw-r--r-- | tvix/eval/src/vm.rs | 21 |
3 files changed, 24 insertions, 1 deletions
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")] |