diff options
| author | 2026-10-14 10:39:47 +0000 | |
|---|---|---|
| committer | 2026-10-14 10:39:47 +0000 | |
| commit | 54b8a8918bb63c98a8f58e823033232243647562 (patch) | |
| tree | e0608f7dab1f568c22390262e5a6d39966519760 /src/lsp | |
| 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 'src/lsp')
| -rw-r--r-- | src/lsp/server.zc | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/src/lsp/server.zc b/src/lsp/server.zc index afa8de4..3698236 100644 --- a/src/lsp/server.zc +++ b/src/lsp/server.zc @@ -1365,7 +1365,7 @@ word hl_is(int base, int q, int e, char* w) { word hl_kw(int base, int q) { int e = q; while (hid(dc(base, e))) e++; - return hl_is(base, q, e, "return") || hl_is(base, q, e, "if") || hl_is(base, q, e, "while") || hl_is(base, q, e, "else") || hl_is(base, q, e, "break") || hl_is(base, q, e, "continue"); + return hl_is(base, q, e, "return") || hl_is(base, q, e, "if") || hl_is(base, q, e, "while") || hl_is(base, q, e, "else") || hl_is(base, q, e, "break") || hl_is(base, q, e, "continue") || hl_is(base, q, e, "defer"); } // where a declaration's name ends on the line from q: at = ; , { ( or a [ that // follows a name (let b[24]); the [ of a type (fixed int[?]) is passed over @@ -1691,6 +1691,7 @@ char* kwtext() { if (hname_is("switch")) return "switch (e) { case 1, 2: ... default: ... }~a branch on constant labels. the cases don't fall through, and break leaves early."; if (hname_is("break")) return "break;~leaves the innermost loop or switch."; if (hname_is("continue")) return "continue;~goes on to the next pass of the innermost loop."; + if (hname_is("defer")) return "defer e; or defer { }~runs the statement when the enclosing block ends, on every way out of it (falling off the end, return, break, continue). several run last registered first, and what they name is read when they run. return, break and continue are not allowed inside. defer rt.free(p); is the transfer of p for the ownership analysis."; if (hname_is("return")) return "return e; or return;~leaves the function with a value, or leaves a void function. returning an owned local transfers it to the caller automatically."; if (hname_is("enum")) return "enum name { A, B = 5 };~global constants. under typecheck on they are a type of their own, and a member can carry fields to make a constructor."; if (hname_is("struct")) return "struct name { fields };~a record type. struct name<T> { } makes it generic, one copy for each set of type arguments."; |
