implement WithLookup
This commit is contained in:
+54
-2
@@ -891,8 +891,60 @@ impl Runtime {
|
||||
root.with_scope = scope.prev;
|
||||
}),
|
||||
WithLookup => {
|
||||
let _name = self.read_string_id();
|
||||
todo!("implement WithLookup (force with_scope)");
|
||||
let name = self.read_string_id();
|
||||
let mut depth = 0;
|
||||
|
||||
loop {
|
||||
let found_scope = self.arena.mutate_root(|_, root| {
|
||||
let mut cur = root.with_scope;
|
||||
for _ in 0..depth {
|
||||
if let Some(s) = cur {
|
||||
cur = s.prev;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(scope) = cur {
|
||||
root.push_stack(scope.env);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if !found_scope {
|
||||
let name_str = self.strings.resolve(name.0).unwrap_or("«unknown»");
|
||||
return Runtime::handle_vm_error(
|
||||
self,
|
||||
vm_err(format!("undefined variable '{name_str}'")),
|
||||
);
|
||||
}
|
||||
|
||||
if let err @ Action::Done(Err(_)) = self.force_tos() {
|
||||
return err;
|
||||
}
|
||||
|
||||
let lookup_result = self.arena.mutate_root(|_, root| {
|
||||
let val = root.pop_stack();
|
||||
let Some(attrs) = val.as_gc::<AttrSet<'_>>() else {
|
||||
return Err(vm_err("value in 'with' scope must be a set"));
|
||||
};
|
||||
|
||||
if let Some(v) = attrs.lookup(name) {
|
||||
root.push_stack(v);
|
||||
Ok(true) // Found it
|
||||
} else {
|
||||
Ok(false) // Not in this scope, try the next one
|
||||
}
|
||||
});
|
||||
|
||||
match lookup_result {
|
||||
Ok(true) => break, // Successfully resolved and pushed to stack
|
||||
Ok(false) => depth += 1, // Move to the parent 'with' scope
|
||||
Err(e) => return Runtime::handle_vm_error(self, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoadBuiltins => {
|
||||
|
||||
Reference in New Issue
Block a user