// A represents the return type of the backtrackable main computation
sclass BStack_v2b extends VStack is IBStack {
static int idCounter;
int stackID = ++idCounter; // for debugging
// Last backtracking point where we will go next when backtracking
// this stack.
Branch branch;
sclass Branch {
// stack that the branch starts with
BStack_v2b stack;
// remaining options to execute on top of stack
Iterator options;
// what to undo before branching
L undos;
void addUndo(AutoCloseable undo) {
if (undos == null) undos = new L;
undos.add(undo);
}
}
*() {}
*(Computable computation) { push(computation); }
*(Iterable l) { pushAll(l); }
sclass NoOptionsException extends RuntimeException {}
BStack_v2b newBranch() {
new BStack_v2b b;
b.branchsnapshot = snapshot;
s.options = options;
s.undos = undos;
undos = null;
s.stack = shallowCloneElements(stack);
ret s;
}
public void addUndo(AutoCloseable undo) {
if (undo == null || branch == null) ret;
branch.addUndo(undo);
}
public void options(B function, IVF1... options) {
options(function, arrayIterator(options));
}
public void options(B function, Iterable> options) {
Iterator> iterator = nonNullIterator(iterator(options));
if (!iterator.hasNext())
throw new NoOptionsException;
IVF1 firstOption = iterator.next();
// All options except first are stored as alternatives
// in cloned stacks.
setOptions(iterator);
// Execute the first option
firstOption.get(function);
}
srecord noeq ExecuteOption(IVF1 option) is VStack.Computable {
public void step(VStack stack, O subComputationResult) {
O target = stack.caller();
stack.return();
option.get(target);
}
}
void setOptions(Iterator> options) {
branch = new Branch;
snapshot = cloneStack();
this.options = (Iterator) options;
}
// Try to backtrack one step and return a new stack
// Returns null if no backtracking possible
public BStack_v2b backtrack() ctex {
if (branch == null) null;
ret branch.backtrack();
// Apply undos in reverse order
for (int i = l(undos)-1; i >= 0; i--)
undos.get(i).close();
// no more options? done
if (options == null || !options.hasNext()) null;
// get snapshot and option to execute
BStack_v2b nextStack = snapshot;
var option = options.next();
// If there are more options in the list, make another clone
// of the snapshot
bool moreOptions = options.hasNext();
if (moreOptions) {
nextStack = new BStack_v2;
nextStack.stack = shallowCloneElements(snapshot.stack);
nextStack.snapshot = snapshot;
nextStack.options = options;
}
nextStack.push(new ExecuteOption(option));
ret nextStack;
}
public A nextResult() {
stepAll(this);
return (A) latestResult;
}
// calculate next result and print stack at every step
public A nextResultWithPrintStruct(long maxSteps) {
stepMaxWithPrintIndentedStruct(this, maxSteps);
return (A) latestResult;
}
}