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:
parent
911fb96eca
commit
59f50dc81a
3 changed files with 24 additions and 1 deletions
|
@ -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 {
|
||||
|
|
|
@ -55,6 +55,7 @@ pub enum OpCode {
|
|||
// `with`-handling
|
||||
OpPushWith(usize),
|
||||
OpPopWith,
|
||||
OpResolveWith,
|
||||
|
||||
// Lists
|
||||
OpList(usize),
|
||||
|
|
|
@ -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")]
|
||||
|
|
Loading…
Reference in a new issue