diff options
| author | 2026-10-12 08:46:23 +0330 | |
|---|---|---|
| committer | 2026-10-12 08:46:23 +0330 | |
| commit | ecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch) | |
| tree | 70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /docs/history/13-gap-fixes/code/tests | |
a
Diffstat (limited to 'docs/history/13-gap-fixes/code/tests')
49 files changed, 440 insertions, 0 deletions
diff --git a/docs/history/13-gap-fixes/code/tests/basics.zc b/docs/history/13-gap-fixes/code/tests/basics.zc new file mode 100644 index 0000000..c1f1faf --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/borrowmove.zc b/docs/history/13-gap-fixes/code/tests/borrowmove.zc new file mode 100644 index 0000000..43f27b2 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/buddy.zc b/docs/history/13-gap-fixes/code/tests/buddy.zc new file mode 100644 index 0000000..2000598 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/enhance.zc b/docs/history/13-gap-fixes/code/tests/enhance.zc new file mode 100644 index 0000000..6acc742 --- /dev/null +++ b/docs/history/13-gap-fixes/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 divmod(a, b) -> 2 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/13-gap-fixes/code/tests/errors/back_to_m.zc b/docs/history/13-gap-fixes/code/tests/errors/back_to_m.zc new file mode 100644 index 0000000..b8c160f --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/borrow_escape.zc b/docs/history/13-gap-fixes/code/tests/errors/borrow_escape.zc new file mode 100644 index 0000000..ce24480 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/branch_mismatch.zc b/docs/history/13-gap-fixes/code/tests/errors/branch_mismatch.zc new file mode 100644 index 0000000..bd19968 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/child_dies.zc b/docs/history/13-gap-fixes/code/tests/errors/child_dies.zc new file mode 100644 index 0000000..67caca9 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/child_recast.zc b/docs/history/13-gap-fixes/code/tests/errors/child_recast.zc new file mode 100644 index 0000000..c9ccd62 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/copy_owned.zc b/docs/history/13-gap-fixes/code/tests/errors/copy_owned.zc new file mode 100644 index 0000000..862c7ef --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/d_into_block.zc b/docs/history/13-gap-fixes/code/tests/errors/d_into_block.zc new file mode 100644 index 0000000..2d7f526 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/d_kept.zc b/docs/history/13-gap-fixes/code/tests/errors/d_kept.zc new file mode 100644 index 0000000..dcbfb86 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/discard_u.zc b/docs/history/13-gap-fixes/code/tests/errors/discard_u.zc new file mode 100644 index 0000000..dd76e94 --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/errors/discard_u.zc @@ -0,0 +1,3 @@ +// expect: can't be thrown away +fn mk() -> .u { let p = new(1); return u*p; } +fn main() { mk(); return 0; } diff --git a/docs/history/13-gap-fixes/code/tests/errors/give_m.zc b/docs/history/13-gap-fixes/code/tests/errors/give_m.zc new file mode 100644 index 0000000..cd67896 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/global_store.zc b/docs/history/13-gap-fixes/code/tests/errors/global_store.zc new file mode 100644 index 0000000..dc0e546 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/leak_overwrite.zc b/docs/history/13-gap-fixes/code/tests/errors/leak_overwrite.zc new file mode 100644 index 0000000..d19b5fd --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/lend_d.zc b/docs/history/13-gap-fixes/code/tests/errors/lend_d.zc new file mode 100644 index 0000000..55ac7e0 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/loop_move.zc b/docs/history/13-gap-fixes/code/tests/errors/loop_move.zc new file mode 100644 index 0000000..df3c94a --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/plain_return.zc b/docs/history/13-gap-fixes/code/tests/errors/plain_return.zc new file mode 100644 index 0000000..4540714 --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/errors/plain_return.zc @@ -0,0 +1,3 @@ +// expect: returns a new object; declare the function with -> .u +fn mk() { return new(1); } +fn main() { return mk(); } diff --git a/docs/history/13-gap-fixes/code/tests/errors/return_m.zc b/docs/history/13-gap-fixes/code/tests/errors/return_m.zc new file mode 100644 index 0000000..1acc4be --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/errors/return_m.zc @@ -0,0 +1,3 @@ +// expect: x: has to be u to be returned +fn mk() -> .u { let x = new(1); return x; } +fn main() { let y = mk(); return y[0]; } diff --git a/docs/history/13-gap-fixes/code/tests/errors/tag_mismatch.zc b/docs/history/13-gap-fixes/code/tests/errors/tag_mismatch.zc new file mode 100644 index 0000000..079f249 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/u_dropped.zc b/docs/history/13-gap-fixes/code/tests/errors/u_dropped.zc new file mode 100644 index 0000000..e1ca68a --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/u_skip_level.zc b/docs/history/13-gap-fixes/code/tests/errors/u_skip_level.zc new file mode 100644 index 0000000..6caeeb3 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/unchecked_touch.zc b/docs/history/13-gap-fixes/code/tests/errors/unchecked_touch.zc new file mode 100644 index 0000000..141639d --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/unused.zc b/docs/history/13-gap-fixes/code/tests/errors/unused.zc new file mode 100644 index 0000000..64aff1f --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/errors/use_after_give.zc b/docs/history/13-gap-fixes/code/tests/errors/use_after_give.zc new file mode 100644 index 0000000..8a10922 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/gc.zc b/docs/history/13-gap-fixes/code/tests/gc.zc new file mode 100644 index 0000000..41f14a0 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/joins.zc b/docs/history/13-gap-fixes/code/tests/joins.zc new file mode 100644 index 0000000..a272e08 --- /dev/null +++ b/docs/history/13-gap-fixes/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 +fn mk(int v) -> *int.u { *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/13-gap-fixes/code/tests/manyerrors.zc b/docs/history/13-gap-fixes/code/tests/manyerrors.zc new file mode 100644 index 0000000..7c9febf --- /dev/null +++ b/docs/history/13-gap-fixes/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; } +fn h() -> int { *char s = 5; return 1; } +fn main() { return 0 } diff --git a/docs/history/13-gap-fixes/code/tests/meta.zc b/docs/history/13-gap-fixes/code/tests/meta.zc new file mode 100644 index 0000000..bc89454 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/misc.zc b/docs/history/13-gap-fixes/code/tests/misc.zc new file mode 100644 index 0000000..25fc53b --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/overflow_data.zc b/docs/history/13-gap-fixes/code/tests/overflow_data.zc new file mode 100644 index 0000000..3042f0a --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/overflow_data.zc @@ -0,0 +1 @@ +fn main() { while (1) asm { 1 } return 0; } diff --git a/docs/history/13-gap-fixes/code/tests/overflow_frame.zc b/docs/history/13-gap-fixes/code/tests/overflow_frame.zc new file mode 100644 index 0000000..3897bf4 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/overflow_return.zc b/docs/history/13-gap-fixes/code/tests/overflow_return.zc new file mode 100644 index 0000000..9d5c622 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/runerr.sh b/docs/history/13-gap-fixes/code/tests/runerr.sh new file mode 100755 index 0000000..23ea054 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeerrors/arg.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/arg.zc new file mode 100644 index 0000000..b762c19 --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/typeerrors/arg.zc @@ -0,0 +1,5 @@ +// expect: type error: argument: expected *point, got *int +typecheck on; +struct point { int x, y; }; +fn f(*point p) -> int { return p.x; } +fn main() { *int q = new(int); f(q); free(d*q); return 0; } diff --git a/docs/history/13-gap-fixes/code/tests/typeerrors/arith.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/arith.zc new file mode 100644 index 0000000..76e3111 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeerrors/assign.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/assign.zc new file mode 100644 index 0000000..8b8a888 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeerrors/call.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/call.zc new file mode 100644 index 0000000..7b03dbf --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeerrors/deref.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/deref.zc new file mode 100644 index 0000000..ed030f5 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeerrors/field.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/field.zc new file mode 100644 index 0000000..ba03697 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeerrors/generic.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/generic.zc new file mode 100644 index 0000000..4a502ce --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/typeerrors/generic.zc @@ -0,0 +1,4 @@ +// expect: type error: argument: expected int, got *char +typecheck on; +fn same<T>(T a, T b) -> T { return a; } +fn main() { return same(1, "x"); } diff --git a/docs/history/13-gap-fixes/code/tests/typeerrors/notstruct.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/notstruct.zc new file mode 100644 index 0000000..0dff6bd --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeerrors/ret.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/ret.zc new file mode 100644 index 0000000..cedd534 --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/typeerrors/ret.zc @@ -0,0 +1,4 @@ +// expect: type error: return value: expected bool, got *char +typecheck on; +fn f() -> bool { return "no"; } +fn main() { return f(); } diff --git a/docs/history/13-gap-fixes/code/tests/typeerrors/voidret.zc b/docs/history/13-gap-fixes/code/tests/typeerrors/voidret.zc new file mode 100644 index 0000000..a897290 --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/typeerrors/voidret.zc @@ -0,0 +1,4 @@ +// expect: type error: return value: expected void, got int +typecheck on; +fn f() -> void { return 3; } +fn main() { f(); return 0; } diff --git a/docs/history/13-gap-fixes/code/tests/typeoff.zc b/docs/history/13-gap-fixes/code/tests/typeoff.zc new file mode 100644 index 0000000..e44e450 --- /dev/null +++ b/docs/history/13-gap-fixes/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/13-gap-fixes/code/tests/typeok.zc b/docs/history/13-gap-fixes/code/tests/typeok.zc new file mode 100644 index 0000000..3cdee0c --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/typeok.zc @@ -0,0 +1,22 @@ +// 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; }; +fn mk<A, B>(A x, B y) -> *pair<A, B>.u { *pair<A, B> p = new(pair<A, B>); p.a = x; p.b = y; return u*p; } +fn left<A, B>(*pair<A, B> p) -> A { return p.a; } +fn strlen2(*char s) -> int { int n = 0; while (s[n]) n++; return n; } +fn main() -> int +{ + *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/13-gap-fixes/code/tests/types.zc b/docs/history/13-gap-fixes/code/tests/types.zc new file mode 100644 index 0000000..ccbbd26 --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/types.zc @@ -0,0 +1,57 @@ +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; + +fn area(*rect r) -> int { return (r.b.x - r.a.x) * (r.b.y - r.a.y); } +fn mklist<T>(int cap) -> *list<T>.u +{ + *list<T> l = new(list<T>); + l.len = 0; + l.items = new(T, cap) as *T; + return u*l; +} +fn first<T>(*list<T> l) -> T { return l.items[0]; } +fn sum(*node n) -> int { 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/13-gap-fixes/code/tests/umd.zc b/docs/history/13-gap-fixes/code/tests/umd.zc new file mode 100644 index 0000000..ee463bf --- /dev/null +++ b/docs/history/13-gap-fixes/code/tests/umd.zc @@ -0,0 +1,52 @@ +// lists as [len, items...], items owned by the list +fn mklist(n) -> .u +{ + 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; } +fn box(v) -> .u { 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; +} |
