aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 16:49:25 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 16:49:40 +0330
commitaadfdb87fdb42b42434358e643da8c98dd4647b2 (patch)
tree27b8eb749b600c44fb8f1159cfcce15cdad30c5e
parentenum: a member is defined as soon as it is declared, so later values can name... (diff)
bool: a value stored into a bool is normalised to 0 or 1 (appendix b.2.6)
-rw-r--r--docs/SPEC.md4
-rw-r--r--src/compiler/lex.zc5
-rw-r--r--tests/conformance/2-types/bool_normalises.zc7
-rw-r--r--tests/conformance/2-types/typecheck_number_kinds_convert.zc3
-rw-r--r--tests/conformance/known.txt1
5 files changed, 16 insertions, 4 deletions
diff --git a/docs/SPEC.md b/docs/SPEC.md
index 5f84acc..529b5bf 100644
--- a/docs/SPEC.md
+++ b/docs/SPEC.md
@@ -132,7 +132,7 @@ zc is untyped by default. an untyped name has type `word`, which is compatible w
| `word` | 1 | the untyped type, compatible with everything |
| `int` | 1 | 64-bit signed two's complement |
| `char` | 1 | a full word, treated as a number; `char[n]` takes n words |
-| `bool` | 1 | a number; values are not normalised to 0 or 1 on store (appendix b) |
+| `bool` | 1 | 0 or 1: a value stored into a bool (initializer, assignment, argument, return) becomes 1 when it is nonzero, a float when it is not 0.0 |
| `void` | 0 | function result only; a variable cannot be void |
| `float`, `f64` | 1 | ieee binary64 |
| `f32` | 1 | single precision: a variable holds the value already rounded to float; arrays and pointers of `f32` are packed two per word |
@@ -1109,7 +1109,7 @@ each item gives a minimal program, the expected behavior (per this spec) and the
3. fixed (now error: f: is defined twice): a function could be silently redefined. `int f() { return 1; } int g() { return f() + 10; } int f() { return 2; }`, then `g()` gives 11 and a later call of `f()` gives 2. expected: error `f: is defined twice` (the message exists in the compiler and is unreachable for an ordinary second definition).
4. fixed (the definition stays): a prototype after the definition hid it. `int f() { return 1; } int f();` then `f()` => `zc: line 0: f is used but never defined`. expected: the definition stays.
5. fixed (3.5.5): `?:` with one float branch and one integer branch converted wrongly. `pf(1 ? 1 : 2.5)` prints `0.000000` (the integer 1's bits read as a float); `pf(1 ? 2.5 : 1)` prints `4612811918334230528.000000` (the taken float converted again as if an integer); `pf(0 ? 2.5 : 1)` prints 1.000000 and `pf(0 ? 1 : 2.5)` 2.500000 (these two are right). expected 1.0, 2.5, 1.0, 2.5.
-6. `bool` does not normalise: `bool b = 5; rt.put_n(b); rt.put_n(b == 1); rt.put_n(!b);` prints 5, 0, 0. expected 1, 1, 0 if `bool` is a 0/1 type; it behaves as a plain integer.
+6. fixed (2.1): `bool` did not normalise: `bool b = 5; rt.put_n(b); rt.put_n(b == 1); rt.put_n(!b);` prints 5, 0, 0. expected 1, 1, 0 if `bool` is a 0/1 type; it behaves as a plain integer.
7. fixed (5.3.2): a float literal as a global initializer (`float g = 1.5;`) was rejected.
8. not a bug: a global initializer that names another global uses the other global's address (5.3.2, 3.14.2): `int a = 5; int b = a + 1;` gives `b` the value `&a + 1`.
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.
diff --git a/src/compiler/lex.zc b/src/compiler/lex.zc
index 0348cae..d06b81b 100644
--- a/src/compiler/lex.zc
+++ b/src/compiler/lex.zc
@@ -298,6 +298,11 @@ int fcoerce(word dst) {
if (dst == tf32 && xty != tf32 && !ispk(xty)) { xenh("zf2s"); xenh("zs2f"); xty = tf32; }
return 0;
}
+ if (dst[0] == TY_BOOL && xty[0] != TY_BOOL) { // bool holds 0 or 1: any nonzero value is 1 (spec 2.1)
+ if (xfloat) { op(OP_FLIT); emit(0); op(OP_FEQ); lit(1); op(18); xfloat = 0; }
+ else { lit(0); op(O_PICK); lit(0); op(O_SWAP); op(O_SUB); op(17); lit(63); op(19); lit(0); op(O_SWAP); op(O_SUB); }
+ xty = tbool; return 0;
+ }
if (!xfloat) {
if (tbytes(dst) && !samesz(dst, xty)) tnorm(dst);
return 0;
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/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/known.txt b/tests/conformance/known.txt
index 723098a..8550c07 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
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_06_bool_normalises.zc zy c appendix b.2.6 confirmed, but spec 2.1 documents bool as a number that is not normalised
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 c appendix b.2.11 confirmed, but spec 1.2.2 says an unclosed block comment is not an error
9-appendix-b/b2_12_as_int_star.zc zy c appendix b.2.12 confirmed, but spec 3.2.3 documents it (parenthesise)