namespace; include rt; // defer: code that runs when the enclosing block ends, on every way out of it fn pn(x) { rt.put_n(x); rt.put_c(' '); return 0; } fn nl() { rt.put_c(10); return 0; } // several defers run in reverse order of registration fn order() { pn(1); defer pn(30); defer pn(20); defer { pn(10); pn(11); } pn(2); return 0; } // the deferred code sees the values the variables have when it runs fn late() { let x = 1; defer pn(x); x = 2; x = 7; return 0; } // the value of return is computed before the defers run fn early(a) { let x = a; defer x = x + 100; defer pn(x); if (a > 5) return x * 2; x = x + 1; return x; } // a defer that is never reached registers nothing fn skipped(a) { if (a == 0) return 0 - 1; defer pn(500); if (a == 1) return 1; defer pn(501); return 2; } // a defer inside an if only applies when that branch ran fn branch(a) { defer pn(9); if (a) { defer pn(1); pn(2); } else { defer pn(3); pn(4); } pn(5); return 0; } // break and continue run the defers of the blocks they leave fn loops() { let i = 0; defer pn(900); while (i < 5) { defer pn(100 + i); i++; if (i == 2) continue; if (i == 4) break; pn(i); } pn(777); for (let j = 0; j < 3; j++) { defer { pn(200 + j); } if (j == 1) { defer pn(300); continue; } pn(j); } let k = 0; do { k++; defer pn(400 + k); if (k == 2) continue; if (k == 3) break; } while (k < 10); return 0; } // the deferred code means what it meant where it was written: a variable an // inner block declares again does not capture its names fn lexical(a) { let x = 1; defer pn(x); { let x = 50; defer pn(x + 1); if (a) return x; pn(x); } x = 2; let y = 3; return y; } // a defer outside the loop is not run by break or continue fn outer() { defer pn(1000); for (let i = 0; i < 3; i++) { defer pn(i); { defer pn(50 + i); if (i == 1) continue; pn(60 + i); } if (i == 2) break; } pn(2000); return 0; } // nested blocks, each with its own fn nest() { defer pn(1); { defer pn(2); { defer pn(3); pn(4); } pn(5); } pn(6); return 7; } // switch arms are blocks; break leaves the arm and the arm's defers run fn arms(v) { defer pn(0); switch (v) { case 1: defer pn(11); pn(10); case 2: defer pn(21); if (v == 2) break; pn(20); default: defer pn(31); return 30; } pn(99); return 0; } // a block expression is a block too fn bexpr() { let v = { defer pn(1); pn(2); 40 + 2 }; pn(v); return 0; } // the owner stays usable until the block ends; the defer is the transfer fn owner(n) { let p = rt.new(4); defer rt.free(p); p[0] = n; p[1] = n * 2; if (n == 3) return p[0] + p[1]; pn(p[0] + p[1]); return 0; } fn owner_loop() { for (let i = 0; i < 3; i++) { let p = rt.new(2); defer rt.free(p); p[0] = i; if (i == 1) continue; pn(p[0]); } return 0; } // defer in a closure belongs to the closure fn closure_defer() { let f = fn(a) { defer pn(a + 1); pn(a); return a * 2; }; defer pn(0); pn(f(10)); return 0; } // unchecked code: no analysis, the deferred code still runs unchecked fn fn_in() { defer pn(5); pn(4); if (1) return 0; return 1; } fn unchecked_defer() { unchecked { defer pn(3); pn(2); } fn_in(); return 0; } // a deferred block can have its own loops, with break and continue fn deferred_loop() { defer { for (let i = 0; i < 5; i++) { if (i == 1) continue; if (i == 4) break; pn(i); } } pn(9); return 0; } fn main() { order(); nl(); late(); nl(); pn(early(1)); nl(); pn(early(9)); nl(); pn(skipped(0)); nl(); pn(skipped(1)); nl(); pn(skipped(2)); nl(); branch(1); nl(); branch(0); nl(); loops(); nl(); outer(); nl(); pn(lexical(1)); nl(); pn(lexical(0)); nl(); pn(nest()); nl(); arms(1); nl(); arms(2); nl(); arms(3); nl(); bexpr(); nl(); let before = rt.live_objects(); pn(owner(3)); owner(4); nl(); owner_loop(); nl(); pn(rt.live_objects() - before); nl(); closure_defer(); nl(); unchecked_defer(); nl(); deferred_loop(); nl(); return 0; }