!include #1007935 // isTrue for coroutines static O evalAll(L l) { O result = null; for (O o : unnull(l)) result = eval(o); ret result; } static O eval(O o) { // for more convenient code making (string literals) if (o instanceof S) ret (S) o; ret callOpt(o); } static int stepAll_steps; static bool stepAll_verbose; // step until state = null static O stepAll(O o) { O result = null; while (o != null) { ++stepAll_steps; if (stepAll_verbose) print("step " + stepAll_steps + ": " + structure(o)); Pair p = cast call(o, "step"); result = p.a; o = p.b; } ret result; } static Pair doStep(O o) { if (stepAll_verbose) print("doStep " + structure(o)); if (o == null) ret pair(null, null); if (hasMethod(o, "step")) ret (Pair) call(o, "step"); // it's something simple, let's just eval ret pair(eval(o), null); } sclass Block { L statements; *() {} *(L *statements) {} O get() { ret evalAll(statements); } class Step { int i; Block block = Block.this; // for structure() *() {} *(int *i) {} Pair step() { Pair p = doStep(statements.get(i)); O nextStep = i+1 < l(statements) ? new Step(i+1) : null; ret pair(p.a, _block(p.b, nextStep)); } } // result + new state Pair step() { ret isEmpty(statements) ? new Pair(null, null) : new Step().step(); } } static O _block(O... statements) { L l = withoutNulls(newList(statements)); if (isEmpty(l)) null; if (l(l) == 1) ret first(l); ret new Block(l); } sclass ResultFinder { O exp; Var dest; *() {} *(O *exp, Var *dest) {} O step() { Pair p = doStep(exp); if (p.b == null) { dest.set(p.a); ret p; } else // keep evaluating until done ret pair(null, _block(p.b, this)); } } sclass If { O a, b, c; // condition, then, else *() {} *(O *a, O *b) {} *(O *a, O *b, O *c) {} O get() { ret eval(isTrue(a) ? b : c); } // rewrite so it's steppable Pair step() { final new Var result; ret doStep(_block( new ResultFinder(a, result), new O { O step() { ret doStep(booleanValue(result.get()) ? b : c); } })); } } static O _if(O a, O b) { ret new If(a, b); } static O _if(O a, O b, O c) { ret new If(a, b, c); } sclass While { O condition, code; *() {} *(O *condition, O *code) {} void get() { while (isTrue(condition)) eval(code); } // rewrite so it's steppable Pair step() { ret doStep(_if(condition, _block(code, this))); } } static O _while(O a, O code) { ret new While(a, code); } static O _for(O a, O b, O c, O code) { ret _block(a, _while(b, _block(code, c))); }