Commit 8405ecbf authored by Jeff Smits's avatar Jeff Smits

Fixed interaction between closures and backtracking of guarded choice

parent befbc71d
......@@ -72,17 +72,29 @@ impl StrategyDef {
if actual_sargs.len() != sargs.len() || actual_targs.len() != targs.len() {
Err(Error::UndefinedStrategy(name.clone()))
} else if let Some(no_of_scopes) = no_of_scopes {
// This is a closure, we need to keep only the number of scopes from when the
// closure was made.
// This works because closure cannot be returned, so the number of scopes always
// reflects the environment in which the closure was made.
// Only problem complicating matters is that an overlay may be popped off here,
// but it's supposed to catch variable bindings. Therefore after popping things
// off, we always add an overlay. After the call the overlay is put on top of
// the entire stack and then applied, to get the desired effect.
context.stack_tracer.borrow_mut().push(name.clone());
let popped_scopes = context.scopes.borrow_mut().split_off(no_of_scopes);
context.push_scope(Scope::overlay());
context.push_scope(Scope::new(targs.iter().cloned().zip(actual_targs),
sargs.iter().cloned().zip(actual_sargs)));
let result = body.eval(context, current);
context.pop_scope();
let overlay = context.scopes.borrow_mut().pop().expect("Interpreter bug, too many scopes popped somewhere. ");
context
.scopes
.borrow_mut()
.extend_from_slice(&popped_scopes);
if result.is_ok() {
context.scopes.borrow_mut().push(overlay);
context.apply_overlay()?;
context.stack_tracer.borrow_mut().pop_on_success();
} else {
context.stack_tracer.borrow_mut().pop_on_failure();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment