diff options
Diffstat (limited to 'tests/programs')
| -rw-r--r-- | tests/programs/bareio.zc | 2 | ||||
| -rw-r--r-- | tests/programs/parity_ops.zc | 102 | ||||
| -rw-r--r-- | tests/programs/typedef.zc | 89 | ||||
| -rw-r--r-- | tests/programs/zc0bstr.zc | 96 | ||||
| -rw-r--r-- | tests/programs/zc0umd.zc | 58 |
5 files changed, 346 insertions, 1 deletions
diff --git a/tests/programs/bareio.zc b/tests/programs/bareio.zc index a06ef38..21d2b40 100644 --- a/tests/programs/bareio.zc +++ b/tests/programs/bareio.zc @@ -2,7 +2,7 @@ namespace; include rt; // bare-metal syscalls: clock, a RAM file, random, and the machine size. -// zc0 subset, so a run-only image can carry it. names stay off u/m/d. +// zc0 subset, so a run-only image can carry it. fn main() { let buf[16], n, t0, t1, i, fd, r, board[8]; t0 = rt.syscall(6, 0, 0, 0); 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; +} diff --git a/tests/programs/typedef.zc b/tests/programs/typedef.zc new file mode 100644 index 0000000..307ef75 --- /dev/null +++ b/tests/programs/typedef.zc @@ -0,0 +1,89 @@ +namespace; +include rt; +typecheck on; + +// typedef T name; makes name another way to write T: the same type, so the two mix freely +struct node { int v; node* next; }; +struct pair<A, B> { A a; B b; }; + +typedef int count; +typedef char* label; +typedef node* link; +typedef link* links; +typedef int[4] quad; +typedef int(int, int) binop; +typedef pair<int, int> ipair; +typedef int[?] ints; +typedef count counter; + +struct box { count n; link head; ipair p; }; + +count twice(count x) { return x + x; } +count add(int a, int b) { return a + b; } +count apply(binop f, count a, count b) { return f(a, b); } +count sum(link n) { count s = 0; while (n) { s += n.v; n = n.next; } return s; } +label hello() { return "hello"; } +string greet(string s) { return s; } +// string is only a type where a type is expected: an untyped parameter can still be called string +fn twice_name(string) { return string + string; } +count first_of(links ls) { return ls[0].v; } +T pick<T>(T x) { typedef T item; item y = x; return y; } +count scoped() { + count total = 0; + { typedef int cell; cell c = 3; total += c; } + { typedef char* cell; cell c = "ab"; total += rt.len_w(c); } + return total; +} +count scoped_again() { typedef quad cell; cell c; c[2] = 7; return c[2] + sizeof(cell); } + +// a link is a node*: every use below mixes the two +count same_ptr(node* p, link q) { return p == q; } +count casts(link p) { + word w = p as word; + link back = w as link; + node* n = (node*)back; + return back.v + ((link)n == p); +} +count boxed(link p) { + box bx; bx.n = 6; bx.head = 0; bx.p.a = 1; bx.p.b = 2; + pair<link, count> pl; pl.a = 0; pl.b = 5; + return bx.n + p.v + bx.p.a + bx.p.b + pl.b + !bx.head + !pl.a; +} +count by_ref(links ls) { return first_of(ls); } + +fn main() { + link a = rt.new(node), b = rt.new(node); + a.v = 3; b.v = 4; a.next = b; + rt.put_n(sum(a)); rt.put_c(' '); + rt.put_n(same_ptr(a, a)); rt.put_c(' '); + rt.put_n(twice(21)); rt.put_c(' '); + rt.put_n(apply(add, 2, 3)); rt.put_c(' '); + binop op = add; + rt.put_n(op(10, 20)); rt.put_c(10); + + quad q; q[3] = 9; + rt.put_n(q[3] + sizeof(quad)); rt.put_c(' '); + rt.put_n(sizeof(count) + sizeof(link) + sizeof(ipair)); rt.put_c(' '); + rt.put_n(boxed(a)); rt.put_c(' '); + ints xs = {1, 2, 3}; + push(xs, 4); + rt.put_n(len(xs)); rt.put_c(10); + + rt.put_n(casts(a)); rt.put_c(' '); + counter k = (count)3; + rt.put_n(k); rt.put_c(' '); + links ls = &a; + rt.put_n(by_ref(ls)); rt.put_c(' '); + rt.put_n(pick<count>(11) + pick(1)); rt.put_c(10); + + rt.put_n(scoped()); rt.put_c(' '); + rt.put_n(scoped_again()); rt.put_c(10); + + string s = "hi"; + label l = s; + char* c = l; + rt.put_s(s); rt.put_s(l); rt.put_s(c); rt.put_s(hello()); rt.put_s(greet("ok")); rt.put_c(10); + rt.put_n(twice_name(4)); rt.put_c(10); + rt.free(d*a); + return 0; +} diff --git a/tests/programs/zc0bstr.zc b/tests/programs/zc0bstr.zc new file mode 100644 index 0000000..bb4ffbc --- /dev/null +++ b/tests/programs/zc0bstr.zc @@ -0,0 +1,96 @@ +namespace; +include rt; + +// packed byte strings in the zc0 subset: the same program runs on the resident +// compiler and, built into a run-only image, on stage 0 (src/tools/zc0.c). it +// covers every b"..." escape, the packed layout, bstr locals, globals, +// parameters and returns, + and the six comparisons, indexing, slicing, len +// and embed. run from the repository root: the embeds read tests/data/embed. + +bstr greeting = b"hello"; +bstr shout; +bstr plain = b"plain"; +embed "tests/data/embed/text.txt" as bstr text; +embed "tests/data/embed/nul.bin" as bstr nul; +embed "tests/data/embed/text.txt" as untyped; + +bstr tag(bstr s) { return b"<" + s + b">"; } +bstr twice(bstr s); +bstr twice(bstr s) { return s + s; } +bstr pick(int n) { + bstr r; + if (n) r = b"yes"; else r = b"no"; + return r; +} +int rank(bstr a, bstr b) { return (a < b) * 8 + (a <= b) * 4 + (a == b) * 2 + (a > b); } +int count(bstr s, int c) { + int n = 0, i = 0; + while (i < len(s)) { if (s[i] == c) n++; i++; } + return n; +} +int num(int n) { rt.put_n(n); rt.put_c(32); return 0; } +int nl() { rt.put_c(10); return 0; } +int bytes(bstr s) { + int i = 0; + num(len(s)); + while (i < len(s)) { num(s[i]); i++; } + nl(); + return 0; +} +int words(bstr s) { + word* w = rt.bstr_storage(s); + int n = 1 + (w[0] >> 3) + 1, i = 0; + while (i < n) { num(w[i]); i++; } + nl(); + return 0; +} + +fn main() { + bstr a = b"abc", b, c; + bstr e = b""; + let u = b"x"; + // every escape the lexer knows: n t r 0 e, and any other character stands for itself + bytes(b"\n\t\r\e\\\"\'\q\x41"); + bytes(b"ab\0cd"); + bytes(b"\0"); + bytes(b"café"); + bytes(b"caf\303\251"); + bytes(b"quote \" inside, 'single', back\\slash"); + // the layout: a length word, bytes packed 8 to a word, a 0 word after a full last word + words(e); + words(b"a"); + words(b"abcdefg"); + words(b"abcdefgh"); + words(b"abcdefghi"); + words(b"0123456789abcdef"); + words(b"0123456789abcdefg"); + words(text); + words(nul); + // declarations, assignment later, a return value, concatenation + b = tag(a); + c = twice(b) + e + u; + rt.put_s(a); rt.put_c(32); rt.put_s(b); rt.put_c(32); rt.put_s(c); nl(); + shout = twice(greeting) + b"!"; + rt.put_s(greeting); rt.put_c(32); rt.put_s(shout); rt.put_c(32); rt.put_s(plain); nl(); + rt.put_s(tag(twice(tag(b"z")))); nl(); + rt.put_s(pick(1) + b"/" + pick(0)); nl(); + // comparisons: below, equal, above, a prefix, the empty string, a 9 byte string + num(rank(b"abc", b"abd")); num(rank(b"abc", b"abc")); num(rank(b"abd", b"abc")); + num(rank(b"ab", b"abc")); num(rank(b"", b"")); num(rank(b"", b"a")); + num(rank(b"abcdefghi", b"abcdefghi")); num(rank(b"abcdefgh", b"abcdefghi")); nl(); + num(a == b"abc"); num(a != b"abc"); num(a == b); num(a != b); + num(tag(a) == b"<abc>"); num(shout > greeting); num(greeting >= shout); num(plain <= plain); nl(); + // indexing, slicing, len + num(a[0]); num(a[2]); num(a[3]); num(len(a)); num(len(e)); num(len(c)); num(len(b"123456789")); nl(); + rt.put_s(c[1:4]); rt.put_c(32); rt.put_s(a[1:2]); rt.put_c(32); rt.put_s(a[0:0]); rt.put_c('|'); + rt.put_s(a[2:99]); rt.put_c('|'); rt.put_s(a[3:1]); rt.put_c('|'); rt.put_s((a + a)[2:4]); nl(); + num(count(c, '<')); num(count(shout, 'l')); num(count(b"mississippi", 's')); num(count(e, 'x')); nl(); + num(b"xyz"[1]); num(len(b"xyz")); num(len(a + a + a)); num(len(tag(e))); nl(); + // embed: a global of the file's bytes, with or without the type, and a local + rt.put_s(text); num(len(text)); num(text[0]); num(text == untyped); num(len(nul)); num(nul[2]); nl(); + embed "tests/data/embed/text.txt" as bstr here; + embed "tests/data/embed/answer.bin" as int answer; + embed "tests/data/embed/text.txt" as char* chars; + rt.put_s(here + b"|" + untyped); num(len(here)); num(here == text); num(answer); num(chars[6]); nl(); + return 0; +} diff --git a/tests/programs/zc0umd.zc b/tests/programs/zc0umd.zc new file mode 100644 index 0000000..9693111 --- /dev/null +++ b/tests/programs/zc0umd.zc @@ -0,0 +1,58 @@ +namespace; +include rt; + +// u, m and d are ordinary names, and a tag is written .u, .m or .d after a type. +// u*x, m*x and d*x with no space before the star is a recast, and u * x with a +// space is a product. the same program runs on the resident compiler and, built +// into a run-only image, on stage 0 (src/tools/zc0.c), which reads the tags and +// recasts and does nothing with them. + +int u = 2, m = 3; // globals +int[4] d4; +int d(int x) { return x + 1; } // a function + +int mul3(int u, int m, int d) { return u * m * d; } // parameters +int mixed(int.d u, int m, int d) { return u * m - d; } +int tagged(int(int) f, int.m x) { return f(x); } + +// owned objects through locals named for their tags +word*.u box(int v) { word* m = rt.new(2); m[0] = v; m[1] = v * 2; return u*m; } +word*.u pair(int u, int m) { + word* d = rt.new(2); + d[0] = u; d[1] = m; + return u*d; +} +.u single(int v) { let u = rt.new(1); u[0] = v; return u*u; } +int sum(word*.m m) { return m[0] + m[1]; } +int eat(word*.d d) { return d[0] + d[1]; } +int hold(.m u, .d d) { return u[0] * 100 + d[0]; } +int dig(word*.m u) { int m = u[0], d = u[1]; return m * 10 + d; } + +fn main() { + int a = 4, b = 5; + int.m n = 9; + word*.m p = box(7); + .m q = single(6); + word* r = pair(8, 9); + let c = box(10), e = pair(1, 2); + rt.put_n(u * m); rt.put_c(32); // two globals multiplied + rt.put_n(u*=m); rt.put_c(32); // u *= m is not a recast either + rt.put_n(d(u) * d(m)); rt.put_c(32); + rt.put_n(mul3(2, 3, 4)); rt.put_c(32); + rt.put_n(mixed(7, 6, 5)); rt.put_c(32); + rt.put_n(tagged(d, n)); rt.put_c(10); + { + int u = 6, m = 7, d = 8; // locals shadow the globals + rt.put_n(u * m); rt.put_c(32); + rt.put_n(u * d - m); rt.put_c(32); + rt.put_n(m * u * d); rt.put_c(32); + rt.put_n(a * u + m * b); rt.put_c(10); + } + rt.put_n(sum(p)); rt.put_c(32); + rt.put_n(q[0]); rt.put_c(32); + rt.put_n(r[0] * r[1]); rt.put_c(32); + rt.put_n(dig(c)); rt.put_c(32); + rt.put_n(hold(e, single(5))); rt.put_c(32); + rt.put_n(eat(d*p)); rt.put_c(10); + return 0; +} |
