diff options
Diffstat (limited to 'tests/programs/defer.zc')
| -rw-r--r-- | tests/programs/defer.zc | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/tests/programs/defer.zc b/tests/programs/defer.zc new file mode 100644 index 0000000..bdf85e1 --- /dev/null +++ b/tests/programs/defer.zc @@ -0,0 +1,235 @@ +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; +} |
