aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 17:09:14 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 17:09:14 +0330
commitf1eba8ef04e8902d7b797d9421d3e0c6f0045ae0 (patch)
tree159dd6fc86dbb3dfc0381f109681751085011c77 /tests
parentmerge work/xref: zc0 u*d redo and follow-ups (diff)
parentMerge branch 'main' into work/spec (diff)
merge work/spec: appendix b round, zc0umd rewrite
Diffstat (limited to 'tests')
-rw-r--r--tests/conformance/1-source/comment_block_unclosed.zc3
-rw-r--r--tests/conformance/1-source/ident_tags_global_glued_star.zc8
-rw-r--r--tests/conformance/2-types/bool_normalises.zc7
-rw-r--r--tests/conformance/2-types/enum_names_own_member.zc8
-rw-r--r--tests/conformance/2-types/typecheck_number_kinds_convert.zc3
-rw-r--r--tests/conformance/3-expressions/cast_as_then_multiply_parenthesised.zc5
-rw-r--r--tests/conformance/3-expressions/closure_24_parameters.zc6
-rw-r--r--tests/conformance/3-expressions/ternary_int_float_variables.zc8
-rw-r--r--tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc8
-rw-r--r--tests/conformance/5-declarations/global_float_init_f32_and_list.zc8
-rw-r--r--tests/conformance/5-declarations/global_float_int_init.zc9
-rw-r--r--tests/conformance/5-declarations/include_in_function_b9.zc2
-rw-r--r--tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc2
-rw-r--r--tests/conformance/9-appendix-b/b2_12_as_int_star.zc6
-rw-r--r--tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc4
-rw-r--r--tests/conformance/known.txt13
-rw-r--r--tests/langerrors/closure_params_25.zc3
-rw-r--r--tests/langerrors/fn_defined_twice.zc4
-rw-r--r--tests/langerrors/include_in_function.zc2
-rw-r--r--tests/langerrors/param_unnamed_with_body.zc3
-rw-r--r--tests/langerrors/proto_after_def_mismatch.zc4
-rw-r--r--tests/langerrors/unterminated_comment_docs.zc4
-rw-r--r--tests/programs/zc0umd.zc19
23 files changed, 106 insertions, 33 deletions
diff --git a/tests/conformance/1-source/comment_block_unclosed.zc b/tests/conformance/1-source/comment_block_unclosed.zc
index 4ae34e7..cb410f9 100644
--- a/tests/conformance/1-source/comment_block_unclosed.zc
+++ b/tests/conformance/1-source/comment_block_unclosed.zc
@@ -1,4 +1,5 @@
-// expect: 4/
+// expect error: unterminated comment
+// spec 1.2.2: a block comment that is never closed is an error
include rt;
fn main() { rt.put_n(4); rt.put_c(10); return 0; }
/* never closed: rt.put_n(9);
diff --git a/tests/conformance/1-source/ident_tags_global_glued_star.zc b/tests/conformance/1-source/ident_tags_global_glued_star.zc
new file mode 100644
index 0000000..516f9a3
--- /dev/null
+++ b/tests/conformance/1-source/ident_tags_global_glued_star.zc
@@ -0,0 +1,8 @@
+// expect: 12/10/
+// spec 1.6.3: u*x and m*x are not recasts when u or m is a visible global variable
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int u = 3;
+int m = 5;
+fn main() { int d = 4; int k = 2; pn(u*d); pn(m*k); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/bool_normalises.zc b/tests/conformance/2-types/bool_normalises.zc
new file mode 100644
index 0000000..c734fc5
--- /dev/null
+++ b/tests/conformance/2-types/bool_normalises.zc
@@ -0,0 +1,7 @@
+// expect: 1/1/0/1/0/1/1/
+// spec 2.1: a value stored in a bool is 0 or 1; any nonzero value becomes 1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+bool id(bool x) { return x; }
+fn main() { bool b = 5; pn(b); pn(b == 1); pn(!b); b = -7; pn(b); b = 0; pn(b); pn(id(42)); bool f = 0.5; pn(f); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_names_own_member.zc b/tests/conformance/2-types/enum_names_own_member.zc
index 26d4739..1a49106 100644
--- a/tests/conformance/2-types/enum_names_own_member.zc
+++ b/tests/conformance/2-types/enum_names_own_member.zc
@@ -1,4 +1,8 @@
-// expect error: expected a constant
+// expect: 17/3/6/
+// spec 2.8.1: a member is defined as soon as it is declared; a later value can name it
include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
enum e { HI = 16, LO = HI + 1 };
-fn main() { return 0; }
+enum f { A, B, C, D = C + 1, E = D * 2 };
+fn main() { pn(LO); pn(D); pn(E); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/typecheck_number_kinds_convert.zc b/tests/conformance/2-types/typecheck_number_kinds_convert.zc
index 9c3d76e..f41b42d 100644
--- a/tests/conformance/2-types/typecheck_number_kinds_convert.zc
+++ b/tests/conformance/2-types/typecheck_number_kinds_convert.zc
@@ -1,4 +1,5 @@
-// expect: 44/
+// expect: 1/
+// spec 2.1, 2.9: numbers convert freely; the bool normalises 44 to 1
include rt;
typecheck on;
void pn(int x) { rt.put_n(x); rt.put_c(10); }
diff --git a/tests/conformance/3-expressions/cast_as_then_multiply_parenthesised.zc b/tests/conformance/3-expressions/cast_as_then_multiply_parenthesised.zc
new file mode 100644
index 0000000..ab11217
--- /dev/null
+++ b/tests/conformance/3-expressions/cast_as_then_multiply_parenthesised.zc
@@ -0,0 +1,5 @@
+// expect: 6/
+// spec 3.2.3: (x as int) * y multiplies
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = 2; int y = 3; pn((x as int) * y); return 0; }
diff --git a/tests/conformance/3-expressions/closure_24_parameters.zc b/tests/conformance/3-expressions/closure_24_parameters.zc
new file mode 100644
index 0000000..e12d258
--- /dev/null
+++ b/tests/conformance/3-expressions/closure_24_parameters.zc
@@ -0,0 +1,6 @@
+// expect: 300/
+// spec 3.15.1 and 5.2.2: a closure takes up to 24 parameters, like a function
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { let f = fn(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8,int a9,int a10,int a11,int a12,int a13,int a14,int a15,int a16,int a17,int a18,int a19,int a20,int a21,int a22,int a23,int a24) { return a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15+a16+a17+a18+a19+a20+a21+a22+a23+a24; }; pn(f(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/3-expressions/ternary_int_float_variables.zc b/tests/conformance/3-expressions/ternary_int_float_variables.zc
new file mode 100644
index 0000000..4bd2d57
--- /dev/null
+++ b/tests/conformance/3-expressions/ternary_int_float_variables.zc
@@ -0,0 +1,8 @@
+// expect: 3.000000/0.500000/3.000000/0.500000/
+// spec 3.5 and appendix b.2.5: ?: with an int side and a float side gives a float on both paths, also in o3
+include rt;
+fn pf(float f) { asm { f @ #1220 } rt.put_c(10); return 0; }
+float pick(int k, int i, float f) { return k ? i : f; }
+o3 float pick3(int k, int i, float f) { return k ? i : f; }
+fn main() { pf(pick(1, 3, 0.5)); pf(pick(0, 3, 0.5)); pf(pick3(1, 3, 0.5)); pf(pick3(0, 3, 0.5)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc b/tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc
new file mode 100644
index 0000000..7136bee
--- /dev/null
+++ b/tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc
@@ -0,0 +1,8 @@
+// expect: 7/
+// spec 5.2.1: a prototype's parameters may be unnamed, pointers included
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int, int*);
+fn main() { int[1] a; a[0] = 5; pn(f(2, a)); return 0; }
+int f(int k, int* p) { return k + p[0]; }
+// zc0: skip
diff --git a/tests/conformance/5-declarations/global_float_init_f32_and_list.zc b/tests/conformance/5-declarations/global_float_init_f32_and_list.zc
new file mode 100644
index 0000000..57df35b
--- /dev/null
+++ b/tests/conformance/5-declarations/global_float_init_f32_and_list.zc
@@ -0,0 +1,8 @@
+// expect: 1/1/
+// spec 5.3.2 and appendix b.2.7: float globals take a float literal initializer
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+float a = 0.25, b = 2.5;
+f32 c = 0.5;
+fn main() { pn(a + b == 2.75); pn(c * 4.0 == 2.0); return 0; }
+// zc0: skip
diff --git a/tests/conformance/5-declarations/global_float_int_init.zc b/tests/conformance/5-declarations/global_float_int_init.zc
new file mode 100644
index 0000000..ac0e187
--- /dev/null
+++ b/tests/conformance/5-declarations/global_float_int_init.zc
@@ -0,0 +1,9 @@
+// expect: 1/1/1/1/1/
+// spec 5.3.2: an integer constant initializing a float or f32 converts to float, for globals and locals
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+float g = 2;
+f32 h = 1 + 2;
+float n = -4;
+fn main() { float l = 2; f32 m = 3; pn(g == 2.0); pn(h == 3.0); pn(n == -4.0); pn(l == 2.0); pn(m == 3.0); return 0; }
+// zc0: skip
diff --git a/tests/conformance/5-declarations/include_in_function_b9.zc b/tests/conformance/5-declarations/include_in_function_b9.zc
index cccaea5..64f170c 100644
--- a/tests/conformance/5-declarations/include_in_function_b9.zc
+++ b/tests/conformance/5-declarations/include_in_function_b9.zc
@@ -1,4 +1,4 @@
-// expect error: include
+// expect error: include is top level only
// spec 5.12.7 and appendix b.2.9: expected an error saying include is top level only
include rt;
void pn(int x) { rt.put_n(x); rt.put_c(10); }
diff --git a/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc b/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc
index e6e6bbf..ce4b236 100644
--- a/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc
+++ b/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc
@@ -1,4 +1,4 @@
-// expect error: unterminated
+// expect error: unterminated comment
// spec appendix b.2.11: an unterminated /* is accepted silently
include rt;
void pn(int x) { rt.put_n(x); rt.put_c(10); }
diff --git a/tests/conformance/9-appendix-b/b2_12_as_int_star.zc b/tests/conformance/9-appendix-b/b2_12_as_int_star.zc
index fc12792..da54802 100644
--- a/tests/conformance/9-appendix-b/b2_12_as_int_star.zc
+++ b/tests/conformance/9-appendix-b/b2_12_as_int_star.zc
@@ -1,6 +1,6 @@
-// expect: 6/
-// spec appendix b.2.12: x as int * y should multiply
+// expect error: expected ')', found 'y'
+// spec 3.2.3 and appendix b.2.12: the type after as is read greedily, so x as int * y reads int* and then fails; write (x as int) * y
include rt;
void pn(int x) { rt.put_n(x); rt.put_c(10); }
fn main() { int x = 2; int y = 3; pn(x as int * y); return 0; }
-// zc0: skip
+// zc0: error
diff --git a/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc b/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc
index b0d0d45..0953328 100644
--- a/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc
+++ b/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc
@@ -1,5 +1,5 @@
-// expect: 3/
-// spec appendix b.2.14: len(char*) with typecheck off returns word 0
+// expect error: len needs an array, not a char*
+// spec 3.13.5 and appendix b.2.14: len on a char* is an error with typecheck off too
include rt;
void pn(int x) { rt.put_n(x); rt.put_c(10); }
typecheck off;
diff --git a/tests/conformance/known.txt b/tests/conformance/known.txt
index 54e7141..8eeb0d3 100644
--- a/tests/conformance/known.txt
+++ b/tests/conformance/known.txt
@@ -2,18 +2,7 @@
# class a: self-hosted compiler bug; b: zc0 deviation (appendix a/b); c: spec issue to settle
# appendix b.2.8 (a global named in an initializer is its address) is documented behavior per 5.3.2 and 3.14.2: no entry
4-statements/o3_outside_function_ordinary_block.zc zy c top-level o3 { } is rejected; spec 4.10.2 says it is an ordinary block
-5-declarations/enum_member_names_earlier_b2.zc zy a appendix b.2.2 confirmed: enum members can't name earlier members
-5-declarations/fn_prototype_after_definition_b4.zc zy a appendix b.2.4 confirmed: a prototype after the definition hides it
-5-declarations/fn_prototype_unnamed_params_b13.zc zy a appendix b.2.13 confirmed (message now: doesn't match its earlier declaration)
-5-declarations/fn_redefined_b3.zc zy a appendix b.2.3 confirmed: a plain redefinition silently shadows the first
-5-declarations/global_float_init_b7.zc zy a appendix b.2.7 confirmed: float global initializer rejected
-5-declarations/include_in_function_b9.zc zy a appendix b.2.9 confirmed: include in a body gives "return outside a function"
-9-appendix-b/b2_05_ternary_int_float.zc zy a appendix b.2.5 confirmed
-9-appendix-b/b2_06_bool_normalises.zc zy a appendix b.2.6 confirmed
9-appendix-b/b2_10_recovery_hides_errors.zc zy c appendix b.2.10 confirmed; by design per 8.2
-9-appendix-b/b2_11_unterminated_comment.zc zy a appendix b.2.11 confirmed
-9-appendix-b/b2_12_as_int_star.zc zy a appendix b.2.12 confirmed
-9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc zy a appendix b.2.14 confirmed
9-appendix-b/b2_15_duplicate_case.zc zy c appendix b.2.15 confirmed; 4.7.2 says duplicates are allowed
9-appendix-b/b2_16_local_const_in_const_expr.zc zy c appendix b.2.16 confirmed; 3.14.2 documents it
2-types/conv_argument_and_return.zc zc0 b types are read and dropped: no conversion, no sized cut (appendix a)
@@ -37,8 +26,6 @@
3-expressions/float_division_int_stored.zc zc0 b types are read and dropped: no conversion, no sized cut (appendix a)
3-expressions/float_int_ops_on_bits.zc zc0 b types are read and dropped: no conversion, no sized cut (appendix a)
3-expressions/incr_on_float_changes_bits.zc zc0 b types are read and dropped: no conversion, no sized cut (appendix a)
-3-expressions/int_min_div_minus1.zc zc0 b INT_MIN / -1 gives 0 and % gives INT_MIN in zc0
-3-expressions/int_min_mod_minus1.zc zc0 b INT_MIN / -1 gives 0 and % gives INT_MIN in zc0
3-expressions/prec_as_binds_tight.zc zc0 b types are read and dropped: no conversion, no sized cut (appendix a)
4-statements/return_value_converted_float.zc zc0 b types are read and dropped: no conversion, no sized cut (appendix a)
4-statements/return_value_converted_int.zc zc0 b types are read and dropped: no conversion, no sized cut (appendix a)
diff --git a/tests/langerrors/closure_params_25.zc b/tests/langerrors/closure_params_25.zc
new file mode 100644
index 0000000..0444007
--- /dev/null
+++ b/tests/langerrors/closure_params_25.zc
@@ -0,0 +1,3 @@
+// expect: too many parameters
+include rt;
+fn main() { let f = fn(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8,int a9,int a10,int a11,int a12,int a13,int a14,int a15,int a16,int a17,int a18,int a19,int a20,int a21,int a22,int a23,int a24, int a25) { return 0; }; return 0; }
diff --git a/tests/langerrors/fn_defined_twice.zc b/tests/langerrors/fn_defined_twice.zc
new file mode 100644
index 0000000..7af57e8
--- /dev/null
+++ b/tests/langerrors/fn_defined_twice.zc
@@ -0,0 +1,4 @@
+// expect: f: is defined twice
+int f() { return 1; }
+int f() { return 2; }
+fn main() { return f(); }
diff --git a/tests/langerrors/include_in_function.zc b/tests/langerrors/include_in_function.zc
new file mode 100644
index 0000000..06136f9
--- /dev/null
+++ b/tests/langerrors/include_in_function.zc
@@ -0,0 +1,2 @@
+// expect: include is top level only
+fn main() { include std; return 0; }
diff --git a/tests/langerrors/param_unnamed_with_body.zc b/tests/langerrors/param_unnamed_with_body.zc
new file mode 100644
index 0000000..bf96698
--- /dev/null
+++ b/tests/langerrors/param_unnamed_with_body.zc
@@ -0,0 +1,3 @@
+// expect: a parameter needs a name
+int f(int*) { return 1; }
+fn main() { return 0; }
diff --git a/tests/langerrors/proto_after_def_mismatch.zc b/tests/langerrors/proto_after_def_mismatch.zc
new file mode 100644
index 0000000..94a04e6
--- /dev/null
+++ b/tests/langerrors/proto_after_def_mismatch.zc
@@ -0,0 +1,4 @@
+// expect: f: doesn't match its earlier declaration
+int f(int a) { return a; }
+int f(int a, int b);
+fn main() { return f(1); }
diff --git a/tests/langerrors/unterminated_comment_docs.zc b/tests/langerrors/unterminated_comment_docs.zc
new file mode 100644
index 0000000..02f4335
--- /dev/null
+++ b/tests/langerrors/unterminated_comment_docs.zc
@@ -0,0 +1,4 @@
+// expect: unterminated comment
+docs on;
+fn main() { return 0; }
+/* never closed, with docs on
diff --git a/tests/programs/zc0umd.zc b/tests/programs/zc0umd.zc
index 9693111..b5a6d2a 100644
--- a/tests/programs/zc0umd.zc
+++ b/tests/programs/zc0umd.zc
@@ -2,12 +2,13 @@ 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
+// u*x, m*x and d*x with no space before the star is a recast when no variable
+// named u, m or d is visible there (spec 1.6.3); otherwise, and with a space, it
+// 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 uu = 2, m = 3; // globals (no global u, so u*x recasts below; m*x with m visible is a product)
int[4] d4;
int d(int x) { return x + 1; } // a function
@@ -17,12 +18,12 @@ 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*.u pair(int x, int m) {
word* d = rt.new(2);
- d[0] = u; d[1] = m;
+ d[0] = x; d[1] = m;
return u*d;
}
-.u single(int v) { let u = rt.new(1); u[0] = v; return u*u; }
+.u single(int v) { let d = rt.new(1); d[0] = v; return u*d; }
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]; }
@@ -35,9 +36,9 @@ fn main() {
.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(uu * m); rt.put_c(32); // two globals multiplied
+ rt.put_n(uu*=m); rt.put_c(32); // *= is not a recast either
+ rt.put_n(d(uu) * 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);