aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 09:44:36 +0000
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 09:44:36 +0000
commit6da86b1e45113c708f54bf28500eeb90365439b2 (patch)
tree6a6e686eeea4ceb65e632124e38819331a8fa1b9 /tests
parenttodo: compiler file split, cross-reference report, local records, x86-64 jit (diff)
parentparity: compare what zc0 and the self-hosted compiler print (diff)
Merge branch 'worktree-agent-aaf6bc066598a6622' into ccr-0054c02e-dfdvnd
Diffstat (limited to 'tests')
-rw-r--r--tests/drivers/cli_help_test.py2
-rw-r--r--tests/parity.known15
-rw-r--r--tests/programs/parity_ops.zc102
3 files changed, 118 insertions, 1 deletions
diff --git a/tests/drivers/cli_help_test.py b/tests/drivers/cli_help_test.py
index 97eebea..1231f74 100644
--- a/tests/drivers/cli_help_test.py
+++ b/tests/drivers/cli_help_test.py
@@ -14,7 +14,7 @@ commands = []
if args.group in ('binaries', 'all'):
commands += [[str(Path(args.bin_dir) / name)] for name in ['zy', 'zym', 'zclsp', 'zc0', 'mkgenome', 'genmap']]
if args.group in ('scripts', 'all'):
- commands += [['bash', name] for name in ['tinyvm.sh', 'src/tools/zcc', 'src/tools/automap.sh', 'src/tools/findcc.sh', 'src/tools/bootstrap-check.sh', 'src/tools/mklsp.sh', 'src/tools/mklspwasm.sh', 'src/tools/mkvsix.sh', 'src/web/build.sh', 'src/baremetal/run.sh']]
+ commands += [['bash', name] for name in ['tinyvm.sh', 'src/tools/zcc', 'src/tools/automap.sh', 'src/tools/findcc.sh', 'src/tools/bootstrap-check.sh', 'src/tools/parity.sh', 'src/tools/mklsp.sh', 'src/tools/mklspwasm.sh', 'src/tools/mkvsix.sh', 'src/web/build.sh', 'src/baremetal/run.sh']]
if args.group in ('js', 'all'):
commands += [['node', name] for name in [str(Path(args.js_dir) / 'tinyvm.js'), 'src/js/mklayout.js', 'src/js/extract_lsp.js']]
diff --git a/tests/parity.known b/tests/parity.known
new file mode 100644
index 0000000..0a73eb3
--- /dev/null
+++ b/tests/parity.known
@@ -0,0 +1,15 @@
+# programs where zc0 and the self-hosted compiler print different things on purpose.
+# src/tools/parity.sh still runs them and shows the difference as known, and it does
+# not fail the run; when one starts to agree it says so, and its line can go.
+# one program per line: the path, then # and the reason.
+#
+# zc0 reads types and ownership tags and throws them away. it has no ownership
+# analysis and no memdebug checks, so it neither warns about, traps on nor frees what
+# the self-hosted compiler does.
+tests/programs/doublefree.zc # memdebug on: only the self-hosted compiler emits the double free check
+tests/programs/scrub.zc # ownership: the analyzer warns about the use after free, zc0 runs it
+tests/programs/uaf.zc # ownership: the analyzer warns about the use after free; zc0 prints nothing
+tests/programs/uaf_in.zc # memdebug on: only the self-hosted compiler emits the use after free check
+examples/lists.zc # ownership: the block's owner frees at its end, zc0 never frees
+# the next program reads a local it never sets when stdin is empty, so it prints stack garbage
+tests/programs/bench_strings.zc # reads the repeat count from stdin; with none, acc is uninitialized
diff --git a/tests/programs/parity_ops.zc b/tests/programs/parity_ops.zc
new file mode 100644
index 0000000..1c3c760
--- /dev/null
+++ b/tests/programs/parity_ops.zc
@@ -0,0 +1,102 @@
+// operator precedence and associativity, the same in both compilers. every binary
+// operator is placed next to its neighbours in the table and between two of the same
+// kind, so a wrong binding changes a printed number. src/tools/parity.sh compiles
+// this program with zc0 and with the self-hosted compiler and compares the output.
+// it stays inside zc0's subset: no ?: (zc0 has none), no types beyond int.
+//
+// the table, tightest first: unary - ! ~ * &, then * / %, + -, << >>, < > <= >=,
+// == !=, &, ^, |, &&, ||, then the assignments, which group to the right. every
+// binary operator groups to the left. the expected output follows the c rules and
+// was checked by compiling the same expressions with a c compiler.
+namespace;
+include rt;
+
+int trace, calls;
+int seen(int v) { calls++; trace = trace * 10 + v; return v; }
+int id(int v) { return v; }
+int out(int v) { rt.put_n(v); rt.put_c(32); return v; }
+int endl() { rt.put_c(10); return 0; }
+
+int main() {
+ // operands the compilers cannot fold away
+ int a = id(2), b = id(3), c = id(4), e = id(5), z = id(0), one = id(1);
+
+ // * / % against + -, and left grouping
+ out(a + b * c); out(a * b + c); out(a - b * c); out(a * b - c); out((a + b) * c);
+ out(id(100) - 30 - 20); out(1 - 2 + 3); out(id(100) / 5 / 2); out(id(20) / 3 * 3);
+ out(a * b % c); out(id(100) % 7 % 3); out(id(100) / 10 % 4); out(id(7) % 4 * 3);
+ endl();
+
+ // + - against << >>, and left grouping
+ out(one << a + one); out(id(32) >> a - one); out(one << a << b); out(id(256) >> a >> one);
+ out(one << b * a); out(id(8) >> one << one);
+ endl();
+
+ // shifts against < > <= >=, and the relational chain
+ out(one << a < e); out(id(16) >> one > 7); out(a < b < c); out(e > c > b);
+ out(z <= e <= z); out(a >= b >= z);
+ endl();
+
+ // relations against == !=, and the equality chain
+ out(a < b == one); out(one == a > b); out(e == e == one); out(b != c != one);
+ out(id(3) > a == one < a);
+ endl();
+
+ // == against & ^ |
+ out(c & c == c); out(one | a == a); out(b ^ b == b); out(a == a & one); out(c != z | z);
+ endl();
+
+ // & ^ | against each other, and against + and <<
+ out(c | b & one); out(id(7) ^ e & b); out(one | 6 ^ b); out(id(6) & b | 8);
+ out(a + 6 & c); out(one & b << one); out(id(12) | one << a);
+ endl();
+
+ // && and || against | & and each other; the result of both is 0 or 1
+ out(one || z && z); out(z && z || one); out(z || one && one || z); out(z && one | one);
+ out(one || z & z); out(b && c); out(b & c); out(z || id(9)); out(id(7) && id(8) && z);
+ out(a < b && c < e || z); out(z == z || z && z);
+ endl();
+
+ // unary operators
+ out(-a * b); out(- -b); out(-a + e); out(!z + one); out(!a == z); out(!!id(7));
+ out(~z & 255); out(~one + one); out(~a & 7); out(-a * -b); out(a - -b); out(-id(7) % 4);
+ out(!(a < b) + one); out(*&a + one); out(-*&b);
+ endl();
+
+ // assignment groups to the right and takes the whole expression on its right
+ int x, y, w;
+ x = y = w = id(7); out(x); out(y); out(w);
+ x = id(10); x -= 3 - 1; out(x);
+ x *= a + b; out(x);
+ x <<= one + one; out(x);
+ x |= one << b; out(x);
+ x += y -= 2; out(x); out(y);
+ x = id(100); x /= a * b; out(x);
+ x %= 7 - 2; out(x);
+ x = id(6); x &= 3 | 8; out(x);
+ x ^= 1 + 2 * 3; out(x);
+ x = id(255); x >>= 2 + 2; out(x);
+ endl();
+
+ // division, remainder and shifts of negative numbers
+ out(id(0) - 7 / 2); out((id(0) - 7) / 2); out((id(0) - 7) % 3); out(id(7) % (id(0) - 3));
+ out((id(0) - 8) >> 1); out((id(0) - 8) << 1);
+ endl();
+
+ // short circuit: how many operands ran, and in what order
+ calls = 0; trace = 0; x = seen(0) && seen(1); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = seen(1) || seen(2); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = seen(1) || seen(2) && seen(3); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = seen(0) || seen(2) && seen(3); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = seen(0) && seen(2) || seen(3); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = seen(1) && seen(0) || seen(2) && seen(3); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = seen(1) | seen(2) && seen(0) & seen(3); out(x); out(calls); out(trace);
+ endl();
+
+ // operands run left to right whatever their binding
+ calls = 0; trace = 0; x = seen(1) + seen(2) * seen(3) - seen(4); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = seen(1) << seen(2) < seen(3) == seen(4); out(x); out(calls); out(trace);
+ calls = 0; trace = 0; x = out(seen(1) - seen(2)) * out(seen(3)); out(x); out(calls); out(trace);
+ endl();
+ return 0;
+}