// A represents the return type of the backtrackable main computation
sclass BStack_v2 extends VStack is IBStack {
static int idCounter;
int stackID = ++idCounter; // for debugging
// cloned version made at last branch point
BStack_v2 snapshot;
// remaining options at last branch point
Iterator options;
// steps to undo before switching to the alternative
L undos;
*() {}
*(Computable computation) { push(computation); }
*(Iterable l) { pushAll(l); }
sclass NoOptionsException extends RuntimeException {}
BStack_v2 cloneStack() {
new BStack_v2 s;
s.snapshot = snapshot;
s.options = options;
s.undos = undos;
undos = null;
s.stack = shallowCloneElements(stack);
ret s;
}
public void addUndo(AutoCloseable undo) {
if (undo == null || snapshot == null) ret;
if (undos == null) undos = new L;
undos.add(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) {
snapshot = cloneStack();
this.options = (Iterator) options;
}
// Try to backtrack one step and return a new stack
// Returns null if no backtracking possible
public BStack_v2 backtrack() ctex {
// 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_v2 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;
}
}