From ccbc77c2d3fa348d0de6f32fc540468401e6880b Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:50:41 +0330 Subject: lexer: a block comment that is never closed is 'unterminated comment' (appendix b.2.11) --- tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/conformance/9-appendix-b') 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); } -- cgit v1.2.3 From 82f8b735f966be69f9892350fb0a719f3fc436f1 Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:51:03 +0330 Subject: as: the type after as is read greedily in both compilers; x as int * y is a syntax error (appendix b.2.12 settled, no compiler change) --- docs/SPEC.md | 4 ++-- .../3-expressions/cast_as_then_multiply_parenthesised.zc | 5 +++++ tests/conformance/9-appendix-b/b2_12_as_int_star.zc | 6 +++--- tests/conformance/known.txt | 1 - 4 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 tests/conformance/3-expressions/cast_as_then_multiply_parenthesised.zc (limited to 'tests/conformance/9-appendix-b') diff --git a/docs/SPEC.md b/docs/SPEC.md index cc94451..30d547d 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -361,7 +361,7 @@ a = b = 7 // assigns both, value 7 ``` `&&` and `||` are lower than `|`. this matches c. -3.2.3 `as` is a postfix operator: it applies to the operand to its left and binds tighter than every binary operator, so `a + b as T` is `a + (b as T)`. a type after `as` takes following stars: `x as int * y` parses `int*` then fails. parenthesise. +3.2.3 `as` is a postfix operator: it applies to the operand to its left and binds tighter than every binary operator, so `a + b as T` is `a + (b as T)`. the type after `as` is read greedily, stars included (`x as char**`), in both compilers: `x as int * y` reads `int*` and then is a syntax error; write `(x as int) * y`. 3.2.4 the condition of `?:` is a `binary` expression (so `a = b ? c : d` is `a = (b ? c : d)`), the middle operand and the last operand are full `expr` (assignments allowed). `a ? b : c = 5` therefore parses as `a ? b : (c = 5)`: with `a` 1 the assignment does not run. @@ -1115,7 +1115,7 @@ each item gives a minimal program, the expected behavior (per this spec) and the 9. fixed (5.12.7): `include std;` inside a function body gave `return outside a function`; it is now error: include is top level only. 10. a syntax error hides errors in the statements skipped by recovery: `int a = ; int b = 3 +;` reports only the first error (8.2). by design, but easy to miss. 11. fixed (1.2.2): an unterminated `/* ...` comment was accepted silently; it is error: unterminated comment. (an unterminated string literal is still only reported as a later syntax error.) -12. `x as int * y` parses `int*` as the type (3.2.3). +12. settled (3.2.3): `x as int * y` parses `int*` as the type. this is the rule (the type is read greedily, as zc0 does too), so the program is a syntax error. 13. prototypes need parameter names: `int f(int);` => `expected a name, found ')'`. 14. `len(s)` on a `char*` returns word 0 of the string when `typecheck` is off. 15. duplicate `case` labels are not diagnosed (4.7.2). 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/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/known.txt b/tests/conformance/known.txt index f666106..7cb703e 100644 --- a/tests/conformance/known.txt +++ b/tests/conformance/known.txt @@ -4,7 +4,6 @@ 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/fn_prototype_unnamed_params_b13.zc zy c spec 5.2.1 says prototype parameter names are required, and a type name alone is read as an untyped parameter of that name (paramstart); b.2.13 is a spec choice, not fixed 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_12_as_int_star.zc zy c appendix b.2.12 confirmed, but spec 3.2.3 documents it (parenthesise) 9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc zy c appendix b.2.14 confirmed, but spec 3.13.5 leaves it unspecified 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 -- cgit v1.2.3 From 6ef2efb750622819a3ba3ae9ee061e512c1266d6 Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 17:00:26 +0330 Subject: len: len on a char* is an error with typecheck off too (appendix b.2.14) --- docs/SPEC.md | 4 ++-- src/compiler/builtins.zc | 3 ++- tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc | 4 ++-- tests/conformance/known.txt | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tests/conformance/9-appendix-b') diff --git a/docs/SPEC.md b/docs/SPEC.md index 128f961..dd04cde 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -490,7 +490,7 @@ pn(pop(a)); pn(a.pop()); pn(a.len()); // 4 3 2 a[2]; // zy: index 2 out of range (length 2) ``` -3.13.5 the length of a non-array (`len("text")` on a `char*`) is unspecified when `typecheck` is off (it reads word 0) and error: len needs an array under `typecheck on;`. use `rt.len_w` for word strings and `len` for `bstr`. +3.13.5 `len` on a `char*` is error: len needs an array, not a char* when `typecheck` is off, and error: len needs an array under `typecheck on;`. use `rt.len_w` for word strings and `len` for `bstr`. ### 3.14 constant expressions @@ -1117,7 +1117,7 @@ each item gives a minimal program, the expected behavior (per this spec) and the 11. fixed (1.2.2): an unterminated `/* ...` comment was accepted silently; it is error: unterminated comment. (an unterminated string literal is still only reported as a later syntax error.) 12. settled (3.2.3): `x as int * y` parses `int*` as the type. this is the rule (the type is read greedily, as zc0 does too), so the program is a syntax error. 13. fixed (5.2.1): a prototype's parameters may be unnamed (`int f(int, int*);`). a lone type name counts as a type only in a prototype; with a body it is still the parameter's name, and an unnamed typed parameter there is `a parameter needs a name`. -14. `len(s)` on a `char*` returns word 0 of the string when `typecheck` is off. +14. fixed (3.13.5): `len(s)` on a `char*` used to return word 0 of the string when `typecheck` was off; it is now a compile error. 15. duplicate `case` labels are not diagnosed (4.7.2). 16. a local `const` cannot be used in a constant expression (b.1.7). 17. fixed: a bad float or character literal in a function's first statement was not reported (1.4). diff --git a/src/compiler/builtins.zc b/src/compiler/builtins.zc index 6dc586a..cbc380e 100644 --- a/src/compiler/builtins.zc +++ b/src/compiler/builtins.zc @@ -706,7 +706,8 @@ int array_len(word t) { return 0; } if (t[0] == TY_ARR) { op(O_DROP); lit(t[3]); } - else { tcneed(t[0] == TY_DYN || t == tword, "len needs an array", t); if (argloc >= 0) { op(O_DROP); vaddr(o3cache[argloc] + 1); op(O_LD); } else if (o3on && t[0] == TY_DYN) op(O_LD); else callname(s_dlen); } + else { if (!tc_on && t[0] == TY_PTR && t[4][0] == TY_CHAR) serr("len needs an array, not a char* (use rt.len_w, or a bstr)"); // b.2.14: it would read word 0 + tcneed(t[0] == TY_DYN || t == tword, "len needs an array", t); if (argloc >= 0) { op(O_DROP); vaddr(o3cache[argloc] + 1); op(O_LD); } else if (o3on && t[0] == TY_DYN) op(O_LD); else callname(s_dlen); } xty = tint; xlenloc = -1; xstamp = 0; if (a >= 0 && t[0] == TY_DYN && t[3]) xlenloc = a; // the whole expression is len of a fixed array 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 2fbd331..8e6ea97 100644 --- a/tests/conformance/known.txt +++ b/tests/conformance/known.txt @@ -3,7 +3,6 @@ # 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 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_14_len_char_ptr_typecheck_off.zc zy c appendix b.2.14 confirmed, but spec 3.13.5 leaves it unspecified 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 1-source/ident_tags_as_variables_glued_star.zc zc0 b u*d with visible u and d is read as a recast (no code); zy follows 1.6.3 -- cgit v1.2.3