scope test_BStack /* Goal: Java code with backtracking, like this, to return 4 different values: S color = "black" or "white"; S shape = "circle" or "square"; return "A " + color + " " + shape; */ sclass #OneBranch extends VStackComputableWithStep { S color; void step(VStack stack) { cast stack to IStackWithOptions; if (step == 0) { step = 1; stack.options(this, ivf1WithToString("black", f -> f.color = "black"), ivf1WithToString("white", f -> f.color = "white")); } else stack.return("Color is " + color); } } sclass #OneBranch3Options extends VStackComputableWithStep { S color; void step(VStack stack) { cast stack to IStackWithOptions; if (step == 0) { step = 1; stack.options(this, ivf1WithToString("black", f -> f.color = "black"), ivf1WithToString("white", f -> f.color = "white"), ivf1WithToString("gray", f -> f.color = "gray")); } else stack.return("Color is " + color); } } sclass #NoOptions extends VStackComputableWithStep { void step(VStack stack) { cast stack to IStackWithOptions; stack.options(this, ll()); // No options should cause error } } sclass #TwoBranches extends VStackComputableWithStep { S color, shape; void step(VStack stack) { cast stack to IStackWithOptions; if (step == 0) { step = 1; print("Creating options at step 0 (black/white)"); stack.options(this, ivf1WithToString("black", f -> f.color = "black"), ivf1WithToString("white", f -> f.color = "white")); } else if (step == 1) { step = 2; print("Creating options at step 1 (circle/square)"); stack.options(this, ivf1WithToString("circle", f -> f.shape = "circle"), ivf1WithToString("square", f -> f.shape = "square")); } else stack.return("A " + color + " " + shape); } } sclass #TwoBranches3Options extends VStackComputableWithStep { S color, shape; void step(VStack stack) { cast stack to IStackWithOptions; if (step == 0) { step = 1; print("Creating options at step 0 (black/white/gray)"); stack.options(this, ivf1WithToString("black", f -> f.color = "black"), ivf1WithToString("white", f -> f.color = "white"), ivf1WithToString("white", f -> f.color = "gray")); } else if (step == 1) { step = 2; print("Creating options at step 1 (circle/square/triangle)"); stack.options(this, ivf1WithToString("circle", f -> f.shape = "circle"), ivf1WithToString("square", f -> f.shape = "square"), ivf1WithToString("square", f -> f.shape = "triangle")); } else stack.return("A " + color + " " + shape); } } srecord noeq #TwoBranchesWithUndos(LS things) extends VStackComputableWithStep { S color, shape; void step(VStack stack) { cast stack to IBStack; if (step == 0) { step = 1; print("Creating options at step 0 (black/white)"); stack.options(this, ivf1WithToString("black", f -> f.color = "black"), ivf1WithToString("white", f -> f.color = "white")); } else if (step == 1) { stack.temp(tempAdd(things, color)); step = 2; } else if (step == 2) { step = 3; print("Creating options at step 2 (circle/square)"); stack.options(this, ivf1WithToString("circle", f -> f.shape = "circle"), ivf1WithToString("square", f -> f.shape = "square")); } else { stack.temp(tempAdd(things, shape)); stack.return("A " + color + " " + shape); } } } svoid test_BStack() { test_BStack_oneBranch(); test_BStack_twoBranches(); test_BStack_undos(); test_BStack_oneBranch3Options(); test_BStack_twoBranches3Options(); test_BStack_noOptions(); } svoid test_BStack_oneBranch() { assertEqualsVerbose( ll("Color is black", "Color is white"), new BStackComputeAllWithPrintStruct(new OneBranch)!); } svoid test_BStack_oneBranch3Options() { assertEqualsVerbose( ll("Color is black", "Color is white", "Color is gray"), new BStackComputeAllWithPrintStruct(new OneBranch3Options)!); } svoid test_BStack_twoBranches() { assertEqualsVerbose( ll("A black circle", "A black square", "A white circle", "A white square"), new BStackComputeAllWithPrintStruct(new TwoBranches)!); } svoid test_BStack_twoBranches3Options() { assertEqualsVerbose( ll("A black circle", "A black square", "A black triangle", "A white circle", "A white square", "A white triangle", "A gray circle", "A gray square", "A gray triangle"), new BStackComputeAllWithPrintStruct(new TwoBranches3Options)!); } svoid test_BStack_undos() { new LS things; // list that is changed during execution to test the undos var stack = new BStack<>(new TwoBranchesWithUndos(things)); for (S color : ll("black", "white")) for (S shape : ll("circle", "square")) { assertEqualsVerbose("A \*color*/ \*shape*/", stack.nextResultWithPrintStruct(10)); assertEqualsVerbose(ll(color, shape), things); stack = stack.backtrack(); } assertNull(stack); } svoid test_BStack_noOptions() { assertInnerExceptionOfTypeVerbose(BStack.NoOptionsException.class, -> new BStackComputeAllWithPrintStruct(new NoOptions)!); }