diff options
| author | 2026-10-14 10:39:47 +0000 | |
|---|---|---|
| committer | 2026-10-14 10:39:47 +0000 | |
| commit | 54b8a8918bb63c98a8f58e823033232243647562 (patch) | |
| tree | e0608f7dab1f568c22390262e5a6d39966519760 /TODO.md | |
| parent | todo: handoff section with state, conventions, in-flight work and architectur... (diff) | |
zc: add the defer statement
defer expr; and defer { ... } register code that runs when the enclosing
block ends: at the end of the block, and at return, break and continue
that leave it. the tokens are kept at the defer and compiled again at each
exit (block_close, body, kw_return, kw_break, kw_continue), newest first,
before the block's variables are released, so the analyzer sees a deferred
rt.free(p) as the transfer of p where it runs. names mean what they meant
at the defer; values are read when it runs. return, break and continue
inside a deferred statement are errors, reported once. works in unchecked
code and closures (own base per function context).
Diffstat (limited to 'TODO.md')
| -rw-r--r-- | TODO.md | 2 |
1 files changed, 1 insertions, 1 deletions
@@ -219,7 +219,7 @@ brief someone without re-reading the code. - [ ] (needs zc0 structs) group the compiler's parallel per-local arrays (`lname`, `ltype`, `lstate`, `lhome`, `lown`, `lslot`, `ltag`, `lpos`, `lnsz`, `lleaf`, ...; many are declared as `word[NL] x_initial; word x = x_initial;` and grow) into one record per local with accessor functions, so a branch snapshot is one block copy and each field's invariant is written once next to the record. then symbols, then types. the genome must keep reaching its fixpoint and the analyzer's behavior must not change (rejection suites and program checks identical). - [ ] continue removing `unchecked` from the runtime. a reverted trial showed: `copy_w`/`fill_w` pass the analyzer when their gate stores go through `syscall(SYS_COPY, ...)`, `dgrow` with `own(w, it)` instead of `w[-2] = it`, `dpush` with `own` before the store, `dnew` as is; but the checked versions changed behavior (7 program checks failed, `tests/programs/share.zc` hung with a checked `cons`), so checked code inserts cleanup these functions can't afford. each needs its contract taught to the analyzer. `free`, `recycle`, `recycle_leaf`, `gc` are the allocator and collector the analyzer's own cleanup calls: document them as the irreducible escapes. `src/lib/actor.zc` has about 20 more. - [ ] revise diagnostics, comments and learning/reference prose using professional compiler documentation guidance, preserving lowercase and adding message regressions. touches messages everywhere, so do it when few other compiler changes are in flight. -- [ ] `defer` statement: `defer expr;` or `defer { ... }` runs when the enclosing block ends, on every exit path, in reverse order, evaluating its expressions when it runs (like the c defer proposal), with ownership awareness: a deferred call that consumes an owner is that owner's transfer. architecture: grab the deferred statement's tokens at the `defer` (like `grab()` in the statements part) and keep a stack of [block depth, token list]. replay a list with `src_push(1, q, 0, 0); next(); stmt(); src_pop();`. block ends go through `block_close` (call it there before `exit_vars`, for entries at the current depth, newest first); `kw_return` evaluates its value first, then must replay every entry of the function (depth >= 1) before `exit_vars(1, 0)`; `kw_break` and `kw_continue` replay entries deeper than the loop's depth (`f[2] + 1`) before their `exit_vars`. after an early exit `live = 0`, so the analyzer state changed by the replay is discarded. closures keep their own base index. reject `return`, `break`, `continue` inside a deferred statement. defer must also work in unchecked code (`exit_vars` returns early there, so replay independently of `fchk`). +- [x] `defer` statement (`kw_defer`, `defer_run`, `block_close`, `kw_return`, `kw_break`, `kw_continue`): see `docs/SPEC.md` 4.14. - [ ] test blocks: `test "name" { ... }` with `expect(cond)`, compiled only by `zy --test file.zc`, which runs each block and prints one line per test with the position of the first failed `expect`; skipped at parse time otherwise. build it as a library through `run.syntax` and `run.statement_hook`, like `src/lib/actor.zc`. - [ ] (in flight) bounds checking on by default, `unbounded` to turn it off (function prefix, block, top-level `unbounded;`, mirroring `unchecked`), implied by `o3`. architecture: indexing is compiled in the postfix `[` handling of the expressions part; growable arrays already check (`dat`, `range_jz`, the `outside` enhancement, `proven()` removing checks a loop test already did). fixed arrays `T[n]` with a variable index get the same inline check against the constant `n`. pointers get a runtime call (for example `rt.bchk(p, i)`) that checks only when `p` is the start of a live heap block (header check word `p ^ MAGIC`, `paylen`), skipping constant index 0 and sizes the analyzer knows (`lnsz`). reports go through `oob`. the runtime, core, compiler parts, server, `run.zc` and `build.zc` start with `unbounded;`, which zc0 accepts and ignores (genome bytes unchanged). keep std, icon and actor checked unless a function touches raw memory on purpose. measure interpreter time before and after. - [ ] after the fuzzing work, add more general functionality to the standard library. |
