diff options
| author | 2026-10-14 16:25:05 +0330 | |
|---|---|---|
| committer | 2026-10-14 16:25:05 +0330 | |
| commit | 8a7092df7b7fc8a5eb4f02ef14588246bd111daf (patch) | |
| tree | 0d9d28ca93ccbddb1f99cb02b88ed466e0ade481 /docs | |
| parent | history: 43-stdlib notes point forward to zc0 no longer reserving u, m and d (diff) | |
| parent | merge bounds checking (diff) | |
Merge branch 'main' into work/xref
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/SPEC.md | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/docs/SPEC.md b/docs/SPEC.md index 5618a5e..6df55f6 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -60,6 +60,7 @@ a name that looks like `x.y` where `x` is not a known module is the three tokens | `memdebug` | S | T | | 4.11 | | `hints` | S | T | | 4.12 | | `unchecked` | S | | | 4.9, 5.1 | +| `unbounded` | S | | | 4.15, 5.1 | | `o3` | S | | | 4.10 | | `asm` | S | | E | raw vm words (4.13) | | `run.method` | S | T | | register a receiver method (7.7) | @@ -190,7 +191,7 @@ u32 z = 0; z--; // z is 4294967295 ### 2.6 arrays -2.6.1 `T[n]`: `n` is a constant expression (3.14) and the array lives in place: in a frame, a global, or inside a struct. its value is its address. `sizeof(T[n])` is the words the elements take (packed for sized types). there is no run-time bound check; a constant index outside `0..n-1` is error: the index is out of range for this array. +2.6.1 `T[n]`: `n` is a constant expression (3.14) and the array lives in place: in a frame, a global, or inside a struct. its value is its address. `sizeof(T[n])` is the words the elements take (packed for sized types). a variable index is checked at run time against `n` (3.7.4) unless the code is unbounded (4.15); a constant index outside `0..n-1` is error: the index is out of range for this array. 2.6.2 `T[]` is an in-place array whose length comes from its initializer: `int[] a = {1, 2, 3};` has length 3. without an initializer, error: T[] needs an initializer to determine its length. @@ -426,7 +427,7 @@ pn((int)(p + 1) - (int)p); // 1: p + 1 moves one word 3.7.3 `&x` is the address of a variable, field or element. it applies to a local (which then lives in memory and cannot be an o3 variable), a global, a field and an element of a non-packed array. an element of a packed array has no address (2.3.3). -3.7.4 indexing a new object (`rt.new(int)[0]`) is error: index a new object only after binding it to a name. indexing a `T[?]` is bounds checked (3.13). indexing a `T[n]` or a pointer is not checked at run time. +3.7.4 indexing a new object (`rt.new(int)[0]`) is error: index a new object only after binding it to a name. indexing is bounds checked at run time unless the function, block, statement or unit is unbounded or the code is o3 (4.15). a `T[?]` is checked against its length (3.13), a `T[n]` against `n`, and a pointer only when it points at the first word of a live heap block, against that block's payload (a buddy block rounds the payload up: `rt.new(4)` has 11 words). a pointer into the middle of a block, a frame array, a global or memory managed by hand is not checked. a constant index 0, and an index a loop test `i < k` with constant `k` (or `i < len(a)`) has already proved, are not checked again. a failed check prints `zy: index I out of range (length N)` and stops, as in 3.13.4. 3.7.5 an index must be a number (typecheck on). @@ -480,7 +481,7 @@ pn((int)(p + 1) - (int)p); // 1: p + 1 moves one word 3.13.3 `push(a, x)` appends and grows; `pop(a)` removes and returns the last element; `resize(a, n)` sets the length, zero-filling new elements and dropping the rest (freeing owned elements). `push` and `pop` on aggregate element types are errors (push takes scalar or reference elements; use resize for aggregates). `push`, `pop`, `resize` on a `fixed` array: error: a fixed array can't grow or shrink. -3.13.4 indexing: `a[i]` with `i < 0` or `i >= len(a)` prints `zy: index I out of range (length N)` on the output and stops the program (`rt.halt`, exit status 0). `pop` on an empty array reports the same with index -1. a constant index known to be out of range also produces a compile-time warning: `zc: line N: warning: out-of-bounds access: index 2 is outside length 2 (storage declared or allocated on line N)`, and the program still runs. +3.13.4 indexing (outside unbounded and o3 code, 4.15): `a[i]` with `i < 0` or `i >= len(a)` prints `zy: index I out of range (length N)` on the output and stops the program (`rt.halt`, exit status 0). `pop` on an empty array reports the same with index -1. a constant index known to be out of range also produces a compile-time warning: `zc: line N: warning: out-of-bounds access: index 2 is outside length 2 (storage declared or allocated on line N)`, and the program still runs. ``` int[?] a = {1, 2}; push(a, 3); a.push(4); @@ -611,7 +612,7 @@ switch (s) { case circle(r): pn(r); case rect(w, h): pn(w * h); case dot: ps("do ### 4.10 o3 -4.10.1 `o3 { ... }` marks a block, `o3 T x = e;` one variable, and `o3 T f(...) { ... }` / `o3 fn f(...)` a function, for the optimising tier. o3 changes speed, not meaning, subject to these restrictions on code in an o3 region: +4.10.1 `o3 { ... }` marks a block, `o3 T x = e;` one variable, and `o3 T f(...) { ... }` / `o3 fn f(...)` a function, for the optimising tier. o3 changes speed, not meaning, except that o3 code is unbounded (4.15), subject to these restrictions on code in an o3 region: - every variable and parameter must be typed (errors: o3 variables need a type, o3 parameters need a type). - no address-of on an o3 variable and no naming one in `asm` (errors: an o3 variable has no address, asm can't reach an o3 variable). - no closures (3.15.3). @@ -655,11 +656,17 @@ int y = 7; asm { y @ 1 + y ! } // y is 8 4.14.8 defer works in `unchecked` code: the analyzer's cleanup is off there, but the deferred code runs. a defer keeps the checked or unchecked mode it was written in. a function that falls off its end runs its function-level defers before returning 0. +### 4.15 unbounded + +4.15.1 `unbounded stmt` (a block or a single statement) compiles the statement without index bounds checks (3.7.4). `unbounded;` at top level does it for the rest of the unit. `unbounded fn f() {}` (also `unbounded T f(...)`, a method or a closure) makes one function unbounded; the prefix combines with `unchecked`, `immediate` and `o3` in any order. o3 code is unbounded. `unbounded` changes no result of a program whose indexes are in range. + +4.15.2 the runtime, the core, the compiler, the language server, `run.zc` and `build.zc` are unbounded; std, icon and actor are checked except where a function reads headers on purpose. + ## 5. declarations at the top level ### 5.1 items -5.1.1 a unit is a sequence of items. an item is: a function definition or prototype, a global variable, `const`, `struct`, `type`, `enum`, `include`, `embed`, `namespace`, `typecheck`, `docs`, `lines`, `memdebug`, `hints`, `enhance`, `extern`, `unchecked;`, or a use of a top-level parse word (7.2). +5.1.1 a unit is a sequence of items. an item is: a function definition or prototype, a global variable, `const`, `struct`, `type`, `enum`, `include`, `embed`, `namespace`, `typecheck`, `docs`, `lines`, `memdebug`, `hints`, `enhance`, `extern`, `unchecked;`, `unbounded;`, or a use of a top-level parse word (7.2). 5.1.2 `struct`, `type`, `typecheck`, `docs`, `lines`, `namespace`, `enhance` and `extern` are valid only at the top level. `enum`, `embed`, `memdebug`, `hints` and `const` also appear as statements in functions. `include` is top-level only (5.12.7). |
