diff options
| author | 2026-10-14 09:43:55 +0000 | |
|---|---|---|
| committer | 2026-10-14 09:43:55 +0000 | |
| commit | 52972fe525abde6e107d7240be91a8985abf0683 (patch) | |
| tree | 571fcb7b8f424eb131421b63bc91cae9ceccf051 /tests/programs | |
| parent | todo: record the reverted unchecked trial and what it showed (diff) | |
parity: compare what zc0 and the self-hosted compiler print
src/tools/parity.sh compiles each program of tests/programs, examples and
examples/learn with zc0 (runtime, program, mkgenome, a microcore with the image
embedded, kept under build/parity/) and runs it beside build/bin/zy < prog.zc,
then compares stdout. what zc0 rejects is skipped and counted. tests/parity.known
lists the differences that are by design (zc0 has no ownership analysis or
memdebug checks). make parity runs it. tests/programs/parity_ops.zc pins operator
precedence and associativity across every binary operator, unary operators,
assignment and short-circuit order; its output matches a c compiler's.
Diffstat (limited to 'tests/programs')
| -rw-r--r-- | tests/programs/parity_ops.zc | 102 |
1 files changed, 102 insertions, 0 deletions
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; +} |
