diff options
Diffstat (limited to 'docs/history/17-o3-boundaries/code/tests')
64 files changed, 639 insertions, 0 deletions
diff --git a/docs/history/17-o3-boundaries/code/tests/arrays.zc b/docs/history/17-o3-boundaries/code/tests/arrays.zc new file mode 100644 index 0000000..f8d46d8 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/arrays.zc @@ -0,0 +1,24 @@ +// growable arrays and fixed ones +struct point { int x, y; }; +fn main() +{ + let before = live_objects(); + { + []int a = new([]int); + for (int i = 0; i < 100; i++) push(a, i * i); + putn(len(a)); putc(' '); putn(cap(a)); putc(' '); putn(a[99]); putc(' '); + putn(pop(a)); putc(' '); putn(len(a)); putc(' '); + resize(a, 3); putn(len(a)); putc(' '); putn(a[2]); putc(' '); + fixed []int f = new(fixed []int, 5); + f[4] = 7; putn(f[4] + len(f)); putc(' '); + []point ps = new([]point, 2); + ps[1].y = 9; resize(ps, 10); putn(ps[1].y + len(ps)); putc(' '); + [8]int st; putn(len(st)); putc(' '); + []*point owned = new([]*point); + for (int i = 0; i < 20; i++) { *point p = new(point); p.x = i; push(owned, d*p); } + putn(owned[19].x); putc(' '); + putn(live_objects() - before); putc(10); + } + putn(live_objects() - before); putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/basics.zc b/docs/history/17-o3-boundaries/code/tests/basics.zc new file mode 100644 index 0000000..c1f1faf --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/basics.zc @@ -0,0 +1,22 @@ +let table[10]; +let greeting = "hey"; +const N = 10, BIG = 0x100 * 2; +fn fib(n) { if (n < 2) return n; return fib(n - 1) + fib(n - 2); } +fn twice(f, x) { return f(f(x)); } +fn inc(x) { return x + 1; } +fn main() +{ + let i, s = 0, a[5]; + for (i = 0; i < N; i++) table[i] = i * i; + for (let j = 0; j < N; j++) s += table[j]; + putn(s); putc(' '); putn(fib(15)); putc(' '); putn(twice(inc, 40)); putc(' '); putn(BIG); putc(10); + puts(greeting); putc(' '); putn('A'); putc(' '); putn(-17 / 5); putc(' '); putn(-17 % 5); putc(' '); putn(1 << 10); putc(' '); putn(-64 >> 3); putc(10); + i = 0; while (1) { i++; if (i == 3) continue; if (i > 6) break; putn(i); } putc(10); + a[0] = 5; a[1] = a[0]++; a[2] = ++a[0]; putn(a[0]); putn(a[1]); putn(a[2]); putc(10); + let b = { let t = 3; t * t }; + putn(b); putc(' '); putn(3 > 2 && 2 > 1); putn(0 || 0); putn(!5); putn(~0); putn(5 != 5); putn(4 >= 4); putc(10); + let x = asm { 2 3 + }; + putn(x); putc(10); + asm { 'o' . 'k' . 10 . } + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/bench.zc b/docs/history/17-o3-boundaries/code/tests/bench.zc new file mode 100644 index 0000000..a7e53f5 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/bench.zc @@ -0,0 +1,30 @@ +// four kernels with and without o3; bench.sh runs each one on each backend +int csum(int lim) { int s = 0; for (int n = 1; n < lim; n++) { int x = n; while (x != 1) { if (x & 1) x = 3 * x + 1; else x = x / 2; s++; } } return s; } +o3 int csum3(int lim) { int s = 0; for (int n = 1; n < lim; n++) { int x = n; while (x != 1) { if (x & 1) x = 3 * x + 1; else x = x / 2; s++; } } return s; } +int sieve(fixed []int f) { int c = 0, n = len(f); for (int i = 0; i < n; i++) f[i] = 1; for (int i = 2; i < n; i++) if (f[i]) { c++; for (int j = i + i; j < n; j += i) f[j] = 0; } return c; } +o3 int sieve3(fixed []int f) { int c = 0, n = len(f); for (int i = 0; i < n; i++) f[i] = 1; for (int i = 2; i < n; i++) if (f[i]) { c++; for (int j = i + i; j < n; j += i) f[j] = 0; } return c; } +int digits(int n) { int s = 0; for (int i = 0; i < n; i++) { int x = i; while (x) { s = s + x % 10; x = x / 10; } } return s; } +o3 int digits3(int n) { int s = 0; for (int i = 0; i < n; i++) { int x = i; while (x) { s = s + x % 10; x = x / 10; } } return s; } +int fib(int n) { if (n < 2) return n; return fib(n - 1) + fib(n - 2); } +o3 int fib3(int n) { if (n < 2) return n; return fib3(n - 1) + fib3(n - 2); } +// input: a letter (the kernel; z runs none) and how many times to run it +fn main() +{ + fixed []int f = new(fixed []int, 50000); + let which = getc(), reps = 0, ch = getc(), r = 0; + while (ch >= '0' && ch <= '9') { reps = reps * 10 + ch - '0'; ch = getc(); } + while (reps > 0) { + if (which == 'a') r = csum(30000); + if (which == 'b') r = csum3(30000); + if (which == 'c') r = sieve(f); + if (which == 'd') r = sieve3(f); + if (which == 'e') r = digits(300000); + if (which == 'f') r = digits3(300000); + if (which == 'g') r = fib(22); + if (which == 'h') r = fib3(22); + reps--; + } + putn(r); putc(10); + free(d*f); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/borrowmove.zc b/docs/history/17-o3-boundaries/code/tests/borrowmove.zc new file mode 100644 index 0000000..43f27b2 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/borrowmove.zc @@ -0,0 +1,2 @@ +fn put(.m box, int v) { *int c = new(int); *c = v; box[0] = c; return 0; } +fn main() { let b = new(1); put(b, 6); putn(*(b[0] as *int)); putc(10); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/buddy.zc b/docs/history/17-o3-boundaries/code/tests/buddy.zc new file mode 100644 index 0000000..2000598 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/buddy.zc @@ -0,0 +1,15 @@ +// the buddy allocator: 20000 small blocks, freed, merge back into one big one +let keep[20000]; +fn main() +{ + let i = 0, p; + while (i < 20000) { keep[i] = new(2); i++; } // 20000 8-word blocks + putn(largest_free()); putc(' '); + i = 0; while (i < 20000) { free(keep[i]); i++; } + putn(largest_free()); putc(' '); + p = new(200000); // only possible if the small blocks merged back + putn(osize(p) >= 200000); putc(' '); + free(d*p); + putn(live_objects()); putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/enhance.zc b/docs/history/17-o3-boundaries/code/tests/enhance.zc new file mode 100644 index 0000000..33eb85b --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/enhance.zc @@ -0,0 +1,29 @@ +// custom opcodes: recipes, lifted vm code, several outputs, and a fallback +enhance clampadd(a, b) micro "a = add a b; a = min a 100; a = max a 0"; +enhance cube(x) vm { 0 $ 0 $ * * }; +enhance 2 divmod(a, b) micro "r2 = sdiv a b" "\n r1 = srem a b\n r0 = r2"; +enhance div7(a) micro "a = sdiv a 7"; +enhance urem10(a) micro "a = urem a 10"; +enhance hi(a, b) micro "a = mulhu a b"; +enhance noisy(x) vm { 0 $ . } else soft_noisy; // i/o can't be lifted, so calls use the fallback +fn soft_noisy(x) { return x + 1; } +let qq, rr, seed = 7; +fn rnd() { seed = seed * 1103515245 + 12345; return seed ^ (seed >> 11); } +fn main() +{ + let i = 0, a, bad = 0; + putn(clampadd(70, 50)); putc(' '); putn(clampadd(-50, 2)); putc(' '); putn(cube(7)); putc(' '); + asm { 17 5 divmod rr ! qq ! } + putn(qq); putc(','); putn(rr); putc(' '); + putn(noisy(4)); putc(' '); + putn(hi(-1, -1)); putc(' '); + while (i < 5000) { + a = rnd(); + if (div7(a) != zdiv(a, 7)) bad++; + if (urem10(a) < 0 || urem10(a) > 9) bad++; + if (a / (i + 1) != zdiv(a, i + 1)) bad++; + i++; + } + putn(bad); putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/errors/back_to_m.zc b/docs/history/17-o3-boundaries/code/tests/errors/back_to_m.zc new file mode 100644 index 0000000..b8c160f --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/back_to_m.zc @@ -0,0 +1,2 @@ +// expect: x: can't be recast back to m +fn main() { let x = new(3); d*x; m*x; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/borrow_escape.zc b/docs/history/17-o3-boundaries/code/tests/errors/borrow_escape.zc new file mode 100644 index 0000000..ce24480 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/borrow_escape.zc @@ -0,0 +1,3 @@ +// expect: p: is owned and can't be returned +fn f(.m p) { return p; } +fn main() { let x = new(1); f(x); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/branch_mismatch.zc b/docs/history/17-o3-boundaries/code/tests/errors/branch_mismatch.zc new file mode 100644 index 0000000..bd19968 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/branch_mismatch.zc @@ -0,0 +1,3 @@ +// expect: x: ends the branches of an if in different states +fn take(.d p) { return p[0]; } +fn main() { let x = new(1); if (x[0]) take(d*x); else u*x; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/child_dies.zc b/docs/history/17-o3-boundaries/code/tests/errors/child_dies.zc new file mode 100644 index 0000000..67caca9 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/child_dies.zc @@ -0,0 +1,3 @@ +// expect: c: used after it was given away +fn take(.d p) { return p[0]; } +fn main() { let p = new(2), c = new(1); p[0] = c; take(d*p); return c[0]; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/child_recast.zc b/docs/history/17-o3-boundaries/code/tests/errors/child_recast.zc new file mode 100644 index 0000000..c9ccd62 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/child_recast.zc @@ -0,0 +1,2 @@ +// expect: c: belongs to a container; recast the container instead +fn main() { let p = new(2), c = new(1); p[0] = c; d*c; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/copy_owned.zc b/docs/history/17-o3-boundaries/code/tests/errors/copy_owned.zc new file mode 100644 index 0000000..862c7ef --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/copy_owned.zc @@ -0,0 +1,2 @@ +// expect: x: is an owned object and can't be copied +fn main() { let x = new(1); let y = x; return y[0]; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/d_into_block.zc b/docs/history/17-o3-boundaries/code/tests/errors/d_into_block.zc new file mode 100644 index 0000000..2d7f526 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/d_into_block.zc @@ -0,0 +1,2 @@ +// expect: x: used after it was given away +fn main() { let x = new(1); d*x; { x[0] = 5; } return x[0]; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/d_kept.zc b/docs/history/17-o3-boundaries/code/tests/errors/d_kept.zc new file mode 100644 index 0000000..dcbfb86 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/d_kept.zc @@ -0,0 +1,2 @@ +// expect: x: d object was never given away +fn main() { let x = new(3); d*x; x[0] = 1; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/discard_u.zc b/docs/history/17-o3-boundaries/code/tests/errors/discard_u.zc new file mode 100644 index 0000000..9293378 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/discard_u.zc @@ -0,0 +1,3 @@ +// expect: can't be thrown away +.u mk() { let p = new(1); return u*p; } +fn main() { mk(); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/give_m.zc b/docs/history/17-o3-boundaries/code/tests/errors/give_m.zc new file mode 100644 index 0000000..cd67896 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/give_m.zc @@ -0,0 +1,3 @@ +// expect: x: is m; write d*x +fn take(.d p) { return p[0]; } +fn main() { let x = new(3); take(x); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/global_store.zc b/docs/history/17-o3-boundaries/code/tests/errors/global_store.zc new file mode 100644 index 0000000..dc0e546 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/global_store.zc @@ -0,0 +1,3 @@ +// expect: x: must be d to be stored in a global +let g; +fn main() { let x = new(1); g = x; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/leak_overwrite.zc b/docs/history/17-o3-boundaries/code/tests/errors/leak_overwrite.zc new file mode 100644 index 0000000..d19b5fd --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/leak_overwrite.zc @@ -0,0 +1,2 @@ +// expect: x: still owns an object +fn main() { let x = new(1); x = new(2); return x[0]; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/lend_d.zc b/docs/history/17-o3-boundaries/code/tests/errors/lend_d.zc new file mode 100644 index 0000000..55ac7e0 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/lend_d.zc @@ -0,0 +1,4 @@ +// expect: x: is d; pass it to a d parameter +fn look(.m p) { return p[0]; } +fn take(.d p) { return p[0]; } +fn main() { let x = new(3); d*x; look(x); take(x); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/loop_move.zc b/docs/history/17-o3-boundaries/code/tests/errors/loop_move.zc new file mode 100644 index 0000000..df3c94a --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/loop_move.zc @@ -0,0 +1,3 @@ +// expect: x: is given away inside a loop that comes back around to it +fn take(.d p) { return p[0]; } +fn main() { let x = new(1); let i = 0; d*x; while (i < 3) { take(x); i++; } return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/plain_return.zc b/docs/history/17-o3-boundaries/code/tests/errors/plain_return.zc new file mode 100644 index 0000000..45fb545 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/plain_return.zc @@ -0,0 +1,3 @@ +// expect: returns a new object; give the function a .u return type +fn mk() { return new(1); } +fn main() { return mk(); } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/return_m.zc b/docs/history/17-o3-boundaries/code/tests/errors/return_m.zc new file mode 100644 index 0000000..b5ef519 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/return_m.zc @@ -0,0 +1,3 @@ +// expect: x: has to be u to be returned +.u mk() { let x = new(1); return x; } +fn main() { let y = mk(); return y[0]; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/tag_mismatch.zc b/docs/history/17-o3-boundaries/code/tests/errors/tag_mismatch.zc new file mode 100644 index 0000000..079f249 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/tag_mismatch.zc @@ -0,0 +1,2 @@ +// expect: c: its tag doesn't match its container's +fn main() { let p = new(2), c = new(1); u*p; p[0] = c; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/u_dropped.zc b/docs/history/17-o3-boundaries/code/tests/errors/u_dropped.zc new file mode 100644 index 0000000..e1ca68a --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/u_dropped.zc @@ -0,0 +1,2 @@ +// expect: x: u object must leave this block +fn main() { let x = new(3); u*x; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/u_skip_level.zc b/docs/history/17-o3-boundaries/code/tests/errors/u_skip_level.zc new file mode 100644 index 0000000..6caeeb3 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/u_skip_level.zc @@ -0,0 +1,2 @@ +// expect: t: is u; it can only be handed to a variable of the enclosing block +fn main() { let r; { { let t = new(1); u*t; r = t; } } return r[0]; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/unchecked_touch.zc b/docs/history/17-o3-boundaries/code/tests/errors/unchecked_touch.zc new file mode 100644 index 0000000..141639d --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/unchecked_touch.zc @@ -0,0 +1,2 @@ +// expect: x: is tracked by the analyzer and can't be used in unchecked code +fn main() { let x = new(1); unchecked { x[0] = 1; } return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/unused.zc b/docs/history/17-o3-boundaries/code/tests/errors/unused.zc new file mode 100644 index 0000000..64aff1f --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/unused.zc @@ -0,0 +1,2 @@ +// expect: x: m object is never used +fn main() { let x = new(3); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/errors/use_after_give.zc b/docs/history/17-o3-boundaries/code/tests/errors/use_after_give.zc new file mode 100644 index 0000000..8a10922 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/errors/use_after_give.zc @@ -0,0 +1,3 @@ +// expect: x: used after it was given away +fn take(.d p) { return p[0]; } +fn main() { let x = new(3); take(d*x); return x[0]; } diff --git a/docs/history/17-o3-boundaries/code/tests/gc.zc b/docs/history/17-o3-boundaries/code/tests/gc.zc new file mode 100644 index 0000000..41f14a0 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/gc.zc @@ -0,0 +1,20 @@ +let keep; +unchecked fn churn(n) +{ + let i = 0, p; + while (i < n) { p = new(10); p[0] = i; if (i % 100 == 0) keep = p; i++; } + return 0; +} +fn main() +{ + let base = live_objects(), f; + churn(1000); + putn(live_objects() - base); putc(' '); + f = gc(); + putn(f >= 990); putc(' '); // conservative: a stale word or two may keep one alive + putn(keep[0]); putc(' '); // the one a global still points at survives + churn(200000); // 3.2m words through a 393k word heap: needs the automatic collector + putn(gc_runs > 1); putc(' '); + putn(keep[0]); putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/joins.zc b/docs/history/17-o3-boundaries/code/tests/joins.zc new file mode 100644 index 0000000..913929b --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/joins.zc @@ -0,0 +1,32 @@ +// joins: something given away on one path is dead afterwards, and the paths +// that still own it free it on the way in. nothing here leaks. +fn take(.d p) { return p[0]; } +fn later(.d p); // not needed any more, but still allowed +*int.u mk(int v) { *int p = new(int); *p = v; return u*p; } +fn count(int n) { let s = 0; switch (n % 4) { case 0: s = 10; case 1, 2: s = 20; break; default: s = 30; } return s; } +fn main() +{ + let base = live_objects(), i = 0, hits = 0, k; + while (i < 50) { + let x = mk(i); + if (i % 3 == 0) take(d*x); // else: freed here by the fixup + i++; + } + putn(live_objects() - base); putc(' '); + // give away and break: fine now; the normal exit frees it + i = 0; + let y = mk(7); + while (i < 10) { if (i == 4) { take(d*y); break; } i++; } + putn(live_objects() - base); putc(' '); + let z = mk(5); + while (1) { if (z[0] == 5) { hits = take(d*z); break; } } + putn(hits); putc(' '); + putn(count(0) + count(1) + count(2) + count(3)); putc(' '); + k = i > 3 ? i * 2 : 0 - 1; + putn(k); putc(' '); + putn(forward(new(int))); putc(' '); // tagged and defined below: the prescan knows .d + **int pp; *int q = new(int); *q = 9; pp = &q; putn(**pp); free(d*q); putc(' '); + putn(live_objects() - base); putc(10); + return 0; +} +fn forward(*int.d p) { return 3 + *p; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/const_index.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/const_index.zc new file mode 100644 index 0000000..03e927b --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/const_index.zc @@ -0,0 +1,2 @@ +// expect: the index is out of range for this array +fn main() { [4]int a; a[4] = 1; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_nolen.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_nolen.zc new file mode 100644 index 0000000..b79c31e --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_nolen.zc @@ -0,0 +1,2 @@ +// expect: a fixed array needs its length +fn main() { fixed []int f = new(fixed []int); free(d*f); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_push.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_push.zc new file mode 100644 index 0000000..a19bcb4 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_push.zc @@ -0,0 +1,2 @@ +// expect: a fixed array can't grow or shrink +fn main() { fixed []int f = new(fixed []int, 3); push(f, 1); free(d*f); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_to_dyn.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_to_dyn.zc new file mode 100644 index 0000000..483f62f --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/fixed_to_dyn.zc @@ -0,0 +1,4 @@ +// expect: type error: argument: expected []int, got fixed []int +typecheck on; +int take([]int.m g) { return len(g); } +fn main() { fixed []int f = new(fixed []int, 3); take(f); free(d*f); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/gen_undeclared.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/gen_undeclared.zc new file mode 100644 index 0000000..919fb51 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/gen_undeclared.zc @@ -0,0 +1,3 @@ +// expect: T: isn't a type +T first(*int l) { return l[0]; } +fn main() { return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/o3_addr.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_addr.zc new file mode 100644 index 0000000..815253d --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_addr.zc @@ -0,0 +1,2 @@ +// expect: an o3 variable has no address +fn main() { o3 int z = 2; *int q = &z; return *q; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/o3_asm.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_asm.zc new file mode 100644 index 0000000..c8afb44 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_asm.zc @@ -0,0 +1,2 @@ +// expect: asm can't reach an o3 variable +fn main() { o3 int zz = 2; asm { zz @ _ } return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/o3_let.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_let.zc new file mode 100644 index 0000000..d2aff9a --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_let.zc @@ -0,0 +1,2 @@ +// expect: o3 variables need a type +fn main() { o3 { let x = 1; x++; } return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/langerrors/o3_param.zc b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_param.zc new file mode 100644 index 0000000..5694720 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/langerrors/o3_param.zc @@ -0,0 +1,3 @@ +// expect: o3 parameters need a type +o3 int f(x) { return x; } +fn main() { return f(1); } diff --git a/docs/history/17-o3-boundaries/code/tests/manyerrors.zc b/docs/history/17-o3-boundaries/code/tests/manyerrors.zc new file mode 100644 index 0000000..f4c0c68 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/manyerrors.zc @@ -0,0 +1,6 @@ +// several errors in one run: a syntax error, an analyzer error, a type error +typecheck on; +fn f() { let a = ; return 0; } +fn g() { let x = new(3); return 0; } +int h() { *char s = 5; return 1; } +fn main() { return 0 } diff --git a/docs/history/17-o3-boundaries/code/tests/meta.zc b/docs/history/17-o3-boundaries/code/tests/meta.zc new file mode 100644 index 0000000..bc89454 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/meta.zc @@ -0,0 +1,46 @@ +fn ipow(a, b) { let r = 1; while (b > 0) { r *= a; b--; } return r; } +// a parse word that adds an operator to the compiler's tables +immediate fn pow_op() { next(); add_binop("**", 11, "ipow c"); return 0; } +pow_op + +// unless (cond) stmt: a parse word that emits code itself +immediate fn unless() +{ + let a; + next(); + expect(intern("(")); rval(); plainuse(expr()); rval(); expect(intern(")")); + emitseq(useq[0], ulen[0]); // not + a = hole(); op(O_JZ); // skip the body when the condition was true + substmt(); + setlit(a, here); + return 0; +} +// repeat N { body }: a macro, built from token lists +immediate fn repeat() +{ + let n, body, i = 0; + next(); n = tv; next(); + body = grab(); + while (i < n) { feed(qdup(body)); i++; } + free(d*body); + return 0; +} +fn main() +{ + putn(2 ** 10); putc(' '); putn(3 + 2 ** 3 * 2); putc(10); + unless (1 > 2) puts("unless ok\n"); + unless (2 > 1) puts("wrong\n"); + repeat 3 { putc('r'); } + putc(10); + let q = quote { putn(40 + 2); putc(10); return 7; }; + putn(q[0]); putc(' '); + putn(eval(q)); putc(10); + let f = compile(q); + putn(f()); putc(10); + free(d*q); + let defs = quote { fn sq(x) { return x * x; } }; + load(defs); + free(d*defs); + putn(evals("return sq(12);")); putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/misc.zc b/docs/history/17-o3-boundaries/code/tests/misc.zc new file mode 100644 index 0000000..25fc53b --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/misc.zc @@ -0,0 +1,30 @@ +// ct { ... } runs a block while compiling and leaves its result as a constant +immediate fn ct() +{ + let q, v; + next(); + q = grab(); + v = eval(q); + free(d*q); + lit(v); + return 0; +} +// teach the asm syntax that p means out, like the old repl demo +immediate fn teach() { next(); mnem[12] = 'p'; return 0; } +teach + +fn countdown() +{ + asm { 5 :top 0 $ '0' + p 1 - 0 $ done z top j :done _ 10 p } + return 0; +} +fn main() +{ + putn(ct { let i = 0, s = 0; while (i < 10) { s += i; i++; } return s; }); putc(10); + countdown(); + puts(lazy()); putc(10); + return 0; +} +// the analyzer is off from here on +unchecked; +fn lazy() { let p = new(3); p[0] = 'o'; p[1] = 'k'; return p; } diff --git a/docs/history/17-o3-boundaries/code/tests/o3.zc b/docs/history/17-o3-boundaries/code/tests/o3.zc new file mode 100644 index 0000000..296d1d5 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/o3.zc @@ -0,0 +1,83 @@ +// o3 regions: every kind of control flow, against the same code without o3 +struct pt { int x; int y; }; +int g = 3; +int sq(int x) { return x * x; } +o3 int collatz(int n) +{ + int steps = 0; + while (n != 1) { if (n % 2 == 0) n = n / 2; else n = 3 * n + 1; steps++; } + return steps; +} +o3 int ack(int am, int n) +{ + if (am == 0) return n + 1; + if (n == 0) return ack(am - 1, 1); + return ack(am - 1, ack(am, n - 1)); +} +o3 int many(int a, int b, int c) +{ + int dd = a + b, e = b + c, f = c + a, h = dd * e, i2 = e * f, j = f * dd, k = h + i2 + j, l = k / 7; + for (int t = 0; t < 5; t++) { dd += t; e -= t; f = f ^ t; l = l + dd * e - f; } + return dd + e + f + h + i2 + j + k + l; +} +o3 int mix(int n) +{ + int acc = 0; + for (int i = 0; i < n; i++) { + if (i % 3 == 0 && i % 5 == 0) acc += 15; + else if (i % 3 == 0 || i > 90) acc += 3; + else acc = acc + (i & 1 ? sq(i) : g); + switch (i % 4) { case 0: acc += 1; case 1: acc -= 2; default: acc = acc ^ 1; } + if (acc > 100000) break; + if (i == 7) continue; + acc = acc + i / 10 - i % 7 + (i << 2) - (i >> 1); + } + return acc; +} +o3 int dyn(int n) +{ + []int a = new([]int, n); + fixed []int f = new(fixed []int, n); + int s = 0; + for (int i = 0; i < len(a); i++) { a[i] = i * i; f[i] = n - i; } + for (int i = 0; i < n; i++) s = s + a[i] * f[i]; + free(d*a); free(d*f); + return s; +} +o3 int pts(int n) +{ + *pt p = new(pt); + int s = 0; + p->x = 1; p->y = 2; + for (int i = 0; i < n; i++) { p->x = p->x + p->y; p->y = p->x - p->y; s = s + p->x % 1000; } + free(d*p); + return s; +} +o3 int divs(int x) +{ + int s = 0; + for (int i = -50; i < 50; i++) s = s + (x + i) / 7 + (x + i) % 7 + (x - i) / -3 + i / 16 + i % 16; + return s; +} +fn main() +{ + o3 int lone = 2; + let r = 0; + lone = lone * 21; + o3 { + int i = 0, s = 0; + while (i < 100) { s = s + collatz(i + 1); i++; } + putn(s); putc(' '); + putn(lone); putc(' '); + lone++; + } + putn(lone); putc(' '); + putn(ack(2, 3)); putc(' '); + putn(many(1, 2, 3)); putc(' '); + putn(mix(100)); putc(' '); + putn(dyn(50)); putc(' '); + putn(pts(30)); putc(' '); + putn(divs(1000)); putc(' '); + putn(divs(-77)); putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/o3_bounds.zc b/docs/history/17-o3-boundaries/code/tests/o3_bounds.zc new file mode 100644 index 0000000..fb347c0 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/o3_bounds.zc @@ -0,0 +1,2 @@ +// an index outside a []T inside o3 code: caught by the inline check +fn main() { []int a = new([]int, 5); o3 { int i = 7; a[i] = 1; } free(d*a); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/o3fat.zc b/docs/history/17-o3-boundaries/code/tests/o3fat.zc new file mode 100644 index 0000000..313c87c --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/o3fat.zc @@ -0,0 +1,22 @@ +// o3 objects reaching normal code get their types: through a return (all the way down the list), an assignment, a store into a field +struct node { int v; *node next; }; +struct box { [3]*node slots; int n; }; +unchecked o3 *node build(int n) +{ + *node head = 0; + for (int i = 0; i < n; i++) { *node k = new(node); k.v = i; k.next = head; head = k; } + return head; +} +unchecked fn main() +{ + *node l = build(5); + tprint(typeof_obj(l)); putc(' '); tprint(typeof_obj(l.next.next.next)); putc(' '); + putn(l.next.v); putc(' '); + *box b = 0; + o3 { b = new(box); b.slots[1] = new(node); b.n = 2; } + tprint(typeof_obj(b)); putc(' '); tprint(typeof_obj(b.slots[1])); putc(' '); + *int raw = 0; + o3 { raw = new(int, 6); } + tprint(typeof_obj(raw)); putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/o3scopes.zc b/docs/history/17-o3-boundaries/code/tests/o3scopes.zc new file mode 100644 index 0000000..9457c77 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/o3scopes.zc @@ -0,0 +1,19 @@ +// registers reused by scopes that never overlap, and a fixed array read through its cached items and length +o3 int scopes(fixed []int f) +{ + int total = 0; + for (int a = 0; a < 3; a++) { int x = a * 2; total += x; } + for (int b = 0; b < 3; b++) { int y = b * 3; total += y; } + for (int c = 0; c < 3; c++) { int z = c * 5; total += z; } + for (int e = 0; e < len(f); e++) { int w = f[e]; total += w; } + for (int g = 0; g < 4; g++) { int h = g + 1, q = h * h, r = q - 1; total += r; } + return total; +} +fn main() +{ + fixed []int f = new(fixed []int, 4); + for (int i = 0; i < 4; i++) f[i] = 10 * i; + putn(scopes(f)); putc(10); + free(d*f); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/overflow_data.zc b/docs/history/17-o3-boundaries/code/tests/overflow_data.zc new file mode 100644 index 0000000..3042f0a --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/overflow_data.zc @@ -0,0 +1 @@ +fn main() { while (1) asm { 1 } return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/overflow_frame.zc b/docs/history/17-o3-boundaries/code/tests/overflow_frame.zc new file mode 100644 index 0000000..3897bf4 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/overflow_frame.zc @@ -0,0 +1,2 @@ +fn big(n) { let a[500]; a[0] = n; return big(n + 1) + a[0]; } +fn main() { return big(0); } diff --git a/docs/history/17-o3-boundaries/code/tests/overflow_return.zc b/docs/history/17-o3-boundaries/code/tests/overflow_return.zc new file mode 100644 index 0000000..9d5c622 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/overflow_return.zc @@ -0,0 +1,2 @@ +fn deep(n) { return deep(n + 1) + 1; } +fn main() { return deep(0); } diff --git a/docs/history/17-o3-boundaries/code/tests/runerr.sh b/docs/history/17-o3-boundaries/code/tests/runerr.sh new file mode 100755 index 0000000..23ea054 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/runerr.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# runs every .zc in a folder (tests/errors by default) and checks the compiler +# rejects it with the message on its first line: // expect: ... +vm=${1:-zy}; dir=${2:-$(dirname "$0")/errors}; pass=0; fail=0 +for f in "$dir"/*.zc; do + want=$(head -1 "$f" | sed 's#^// expect: ##') + got=$($vm < "$f" 2>&1 | head -1) + if [[ "$got" == *"$want"* ]]; then pass=$((pass+1)); else fail=$((fail+1)); echo "FAIL $(basename $f): got [$got]"; fi +done +echo "rejected: $pass passed, $fail failed" diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/arg.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/arg.zc new file mode 100644 index 0000000..909672a --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/arg.zc @@ -0,0 +1,5 @@ +// expect: type error: argument: expected *point, got *int +typecheck on; +struct point { int x, y; }; +int f(*point p) { return p.x; } +fn main() { *int q = new(int); f(q); free(d*q); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/arith.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/arith.zc new file mode 100644 index 0000000..76e3111 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/arith.zc @@ -0,0 +1,3 @@ +// expect: type error: arithmetic needs numbers, got *int +typecheck on; +fn main() { *int p = 0; int x = p * 2; return x; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/assign.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/assign.zc new file mode 100644 index 0000000..8b8a888 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/assign.zc @@ -0,0 +1,3 @@ +// expect: type error: initializer: expected *char, got int +typecheck on; +fn main() { *char s = 5; return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/call.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/call.zc new file mode 100644 index 0000000..7b03dbf --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/call.zc @@ -0,0 +1,3 @@ +// expect: type error: only functions can be called, got int +typecheck on; +fn main() { int k = 3; return k(1); } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/deref.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/deref.zc new file mode 100644 index 0000000..ed030f5 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/deref.zc @@ -0,0 +1,3 @@ +// expect: type error: only pointers can be dereferenced, got int +typecheck on; +fn main() { int x = 3; return *x; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/field.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/field.zc new file mode 100644 index 0000000..ba03697 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/field.zc @@ -0,0 +1,3 @@ +// expect: point has no field z +struct point { int x, y; }; +fn main() { point p; return p.z; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/generic.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/generic.zc new file mode 100644 index 0000000..49f2c10 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/generic.zc @@ -0,0 +1,4 @@ +// expect: type error: argument: expected int, got *char +typecheck on; +T same<T>(T a, T b) { return a; } +fn main() { return same(1, "x"); } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/notstruct.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/notstruct.zc new file mode 100644 index 0000000..0dff6bd --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/notstruct.zc @@ -0,0 +1,2 @@ +// expect: .x: that's a int, not a struct or a pointer to one +fn main() { int n = 1; return n.x; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/ret.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/ret.zc new file mode 100644 index 0000000..be951d5 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/ret.zc @@ -0,0 +1,4 @@ +// expect: type error: return value: expected bool, got *char +typecheck on; +bool f() { return "no"; } +fn main() { return f(); } diff --git a/docs/history/17-o3-boundaries/code/tests/typeerrors/voidret.zc b/docs/history/17-o3-boundaries/code/tests/typeerrors/voidret.zc new file mode 100644 index 0000000..86c9c17 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeerrors/voidret.zc @@ -0,0 +1,4 @@ +// expect: type error: return value: expected void, got int +typecheck on; +void f() { return 3; } +fn main() { f(); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeoff.zc b/docs/history/17-o3-boundaries/code/tests/typeoff.zc new file mode 100644 index 0000000..e44e450 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeoff.zc @@ -0,0 +1,2 @@ +// the typechecker is off unless asked for: this mismatch compiles and runs +fn main() { *char s = 5; putn(s as int + 1); putc(10); return 0; } diff --git a/docs/history/17-o3-boundaries/code/tests/typeok.zc b/docs/history/17-o3-boundaries/code/tests/typeok.zc new file mode 100644 index 0000000..93462bd --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/typeok.zc @@ -0,0 +1,21 @@ +// passes the typechecker: words mix with everything, literal 0 is null, +// arrays decay to pointers, generic calls bind their parameters +typecheck on; +struct pair<A, B> { A a; B b; }; +*pair<A, B>.u mk<A, B>(A x, B y) { *pair<A, B> p = new(pair<A, B>); p.a = x; p.b = y; return u*p; } +A left<A, B>(*pair<A, B> p) { return p.a; } +int strlen2(*char s) { int n = 0; while (s[n]) n++; return n; } +int main() { + *pair<int, *char> p = mk(3, "four"); + int a = left(p); + *char s = p.b; + [8]char buf; + *char q = buf; + *int nothing = 0; + let w = 5; + int mixed = w + 1; + q[0] = 'h'; q[1] = 0; + putn(a + strlen2(s) + strlen2(buf) + mixed); putc(10); + free(d*p); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/types.zc b/docs/history/17-o3-boundaries/code/tests/types.zc new file mode 100644 index 0000000..c988499 --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/types.zc @@ -0,0 +1,56 @@ +struct point { int x, y; }; +struct rect { point a, b; int tag; }; +struct list<T> { int len; *T items; }; +struct node { int v; *node next; }; +type num = int; + +int counter = 5; +[4]int squares; +point origin; + +int area(*rect r) { return (r.b.x - r.a.x) * (r.b.y - r.a.y); } +*list<T>.u mklist<T>(int cap) { + *list<T> l = new(list<T>); + l.len = 0; + l.items = new(T, cap) as *T; + return u*l; +} +T first<T>(*list<T> l) { return l.items[0]; } +int sum(*node n) { int s = 0; while (n) { s += n.v; n = n.next; } return s; } + +fn main() +{ + rect r; + r.a.x = 1; r.a.y = 2; r.b.x = 4; r.b.y = 6; + putn(area(&r)); putc(' '); + putn(sizeof(rect)); putc(' '); putn(sizeof(point)); putc(' '); putn(sizeof([3]rect)); putc(' '); + let p = new(point); // let infers *point + p.x = 7; p->y = 8; + putn(p.x * p.y); putc(' '); + free(d*p); + *list<int> l = mklist<int>(4); + l.items[0] = 42; l.len = 1; + putn(first(l)); putc(' '); + free(d*l); + *node a = new(node), b = new(node); + a.v = 3; b.v = 4; a.next = b; + putn(sum(a)); putc(' '); + free(d*a); // b went with it: a.next = b made a its owner + [3]point pts; + pts[2].y = 9; + putn(pts[2].y + counter); putc(' '); + num k = 3; + putn(k); putc(10); + + // reflection + tprint(typeof(r)); putc(' '); tprint(typeof(&r)); putc(' '); tprint(typeof(l)); putc(' '); + tprint(sigof(mklist)); putc(' '); tprint(sigof(first)); putc(' '); tprint(sigofs("free")); putc(10); + let t = typeof(r), i = 0; + while (i < tnfields(t)) { puts(tfname(t, i)); putc(':'); tprint(tftype(t, i)); putc('@'); putn(tfoff(t, i)); putc(' '); i++; } + putc(10); + *point q = new(point); + tprint(typeof_obj(q)); putc(' '); putn(typeof_obj(q) == typeof(point)); putc(' '); putn(tkind(typeof_obj(q)) == TY_STRUCT); + free(d*q); + putc(10); + return 0; +} diff --git a/docs/history/17-o3-boundaries/code/tests/umd.zc b/docs/history/17-o3-boundaries/code/tests/umd.zc new file mode 100644 index 0000000..497c9fc --- /dev/null +++ b/docs/history/17-o3-boundaries/code/tests/umd.zc @@ -0,0 +1,51 @@ +// lists as [len, items...], items owned by the list +.u mklist(n) { + let l = new(n + 1); + l[0] = 0; + return u*l; +} +fn push(.m l, .d item) { l[l[0] + 1] = d*item; l[0] = l[0] + 1; return 0; } +fn sum(.m l) { let s = 0, i = 1; while (i <= l[0]) { s += l[i][0]; i++; } return s; } +.u box(v) { let b = new(1); b[0] = v; return u*b; } +fn consume(.d b) { return b[0]; } + +fn main() +{ + let base = live_objects(); + { + let l = mklist(8); // u from mklist arrives m*here + let i = 0; + while (i < 5) { + let b = box(i * 10); // m in the loop body + d*b; // give it down + push(l, b); + i++; + } + putn(sum(l)); putc(' '); + putn(live_objects() - base); putc(' '); // list + 5 boxes + } + putn(live_objects() - base); putc(' '); // freed at the block's end, children too + + // u handed up one block by assignment, and as a block value + let outer; + { + let t = box(7); + u*t; + outer = t; + } + let v = { let w = box(8); u*w }; + putn(outer[0] + v[0]); putc(' '); + + // d given away to a callee + let g = box(99); + putn(consume(d*g)); putc(' '); + + // containers: child takes its parent's tag + let p = new(2), c = new(1); + c[0] = 5; + p[0] = c; + p[1] = new(3); + putn(p[0][0]); putc(' '); + putn(live_objects() - base); putc(10); + return 0; +} |
