feat(tvix/eval): Implement OpResolveWith instruction

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>
This commit is contained in:
Vincent Ambo 2022-08-15 01:13:17 +03:00 committed by tazjin
parent 911fb96eca
commit 59f50dc81a
3 changed files with 24 additions and 1 deletions

View file

@ -28,6 +28,9 @@ pub enum Error {
// Unknown variable in statically known scope. // Unknown variable in statically known scope.
UnknownStaticVariable(rnix::types::Ident), UnknownStaticVariable(rnix::types::Ident),
// Unknown variable in dynamic scope (with, rec, ...).
UnknownDynamicVariable(String),
} }
impl Display for Error { impl Display for Error {

View file

@ -55,6 +55,7 @@ pub enum OpCode {
// `with`-handling // `with`-handling
OpPushWith(usize), OpPushWith(usize),
OpPopWith, OpPopWith,
OpResolveWith,
// Lists // Lists
OpList(usize), OpList(usize),

View file

@ -98,7 +98,7 @@ impl VM {
#[cfg(feature = "disassembler")] #[cfg(feature = "disassembler")]
let mut tracer = Tracer::new(); let mut tracer = Tracer::new();
loop { 'dispatch: loop {
let op = self.inc_ip(); let op = self.inc_ip();
match op { match op {
OpCode::OpConstant(idx) => { OpCode::OpConstant(idx) => {
@ -285,6 +285,25 @@ impl VM {
OpCode::OpPopWith => { OpCode::OpPopWith => {
self.with_stack.pop(); 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")] #[cfg(feature = "disassembler")]