fix(tvix/eval): ensure OpResolveWith can be traced
The previous implementation of OpResolveWith manually controlled the loop iteration, which skipped over the disassembler's tracing instruction. Instead, the resolution of dynamic variables has been delegated to a new helper function. This has the additional benefit that the loop labels are no longer required, making things a bit cleaner. Change-Id: If22b74c3d49c74bf3a1ec4497cb761a9ee6cf2a4 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6298 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
parent
7c2fdefcd8
commit
10b0879c00
1 changed files with 16 additions and 16 deletions
|
@ -126,7 +126,7 @@ impl VM {
|
||||||
#[cfg(feature = "disassembler")]
|
#[cfg(feature = "disassembler")]
|
||||||
let mut tracer = Tracer::new();
|
let mut tracer = Tracer::new();
|
||||||
|
|
||||||
'dispatch: loop {
|
loop {
|
||||||
if self.frame().ip == self.chunk().code.len() {
|
if self.frame().ip == self.chunk().code.len() {
|
||||||
// If this is the end of the top-level function,
|
// If this is the end of the top-level function,
|
||||||
// return, otherwise pop the call frame.
|
// return, otherwise pop the call frame.
|
||||||
|
@ -330,21 +330,8 @@ impl VM {
|
||||||
|
|
||||||
OpCode::OpResolveWith => {
|
OpCode::OpResolveWith => {
|
||||||
let ident = self.pop().to_string()?;
|
let ident = self.pop().to_string()?;
|
||||||
|
let value = self.resolve_with(ident.as_str())?;
|
||||||
// Attempt to resolve the variable, starting at
|
self.push(value)
|
||||||
// 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(ErrorKind::UnknownDynamicVariable(ident.to_string()).into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpCode::OpAssert => {
|
OpCode::OpAssert => {
|
||||||
|
@ -450,6 +437,19 @@ impl VM {
|
||||||
self.push(Value::String(out.into()));
|
self.push(Value::String(out.into()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve a dynamic identifier through the with-stack at runtime.
|
||||||
|
fn resolve_with(&self, ident: &str) -> EvalResult<Value> {
|
||||||
|
for idx in self.with_stack.iter().rev() {
|
||||||
|
let with = self.stack[*idx].as_attrs()?;
|
||||||
|
match with.select(ident) {
|
||||||
|
None => continue,
|
||||||
|
Some(val) => return Ok(val.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(ErrorKind::UnknownDynamicVariable(ident.to_string()).into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use Rc::unwrap_or_clone once it is stabilised.
|
// TODO: use Rc::unwrap_or_clone once it is stabilised.
|
||||||
|
|
Loading…
Reference in a new issue