add defer

This commit is contained in:
2026-06-27 03:36:47 +02:00
parent 81ae939bf0
commit b4ce2c2117
8 changed files with 375 additions and 13 deletions
+18 -3
View File
@@ -286,9 +286,24 @@
- the LLVM emitter opens a fresh recovery block after any terminator (not just `ret`),
so dead code following a `break`/`continue` branch stays well-formed
19. add `defer` statement (inspired by zig)
- now unblocked: `defer` reuses the loop-target stack and loop tracking added in
milestone 18 to flush deferred statements on `break`/`continue` exits too
19. add `defer` statement (inspired by zig) (implemented; also adds bare block statements)
- `defer <stmt>` runs the statement when the enclosing block scope exits, in reverse
(LIFO) order, on every exit path: fall-through, `return`, `break`, `continue`. The
deferred statement may be a block (`defer { ... }`)
- bare block statements `{ ... }` were added as the enabling feature: a `{ ... }`
introduces a nested scope (locals are name-scoped to it; defers inside it fire at the
closing brace). A leading `{` is unambiguous since struct literals are postfix only
- the return value is captured *before* defers run (a `defer` that mutates the returned
local can't change what is returned) — the checker spills the return value into a temp
local, then flushes, matching Zig
- `return` flushes all active defers; `break`/`continue` flush only down to and including
the innermost loop body; fall-through flushes the current block's own defers. Deferring
a `return`/`break`/`continue`/`defer`, a `return` inside a `defer`, or a `break`/
`continue` that would escape a `defer` are all rejected
- implemented entirely in lexer/parser/checker (new `Keyword_Defer`; `Block`/`Defer` AST
kinds reusing `body`/`update`; `parse_block_statement`/`parse_defer`). No HIR opcode:
a bare block is built and spliced inline, and a deferred statement is built once at the
`defer` site and its hir replayed at each exit, so lowering/codegen are unchanged
20. add `yield` statement (see below)