aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/decl.zc
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 10:39:47 +0000
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 10:39:47 +0000
commit54b8a8918bb63c98a8f58e823033232243647562 (patch)
treee0608f7dab1f568c22390262e5a6d39966519760 /src/compiler/decl.zc
parenttodo: 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/compiler/decl.zc')
-rw-r--r--src/compiler/decl.zc8
1 files changed, 6 insertions, 2 deletions
diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc
index 45269a4..19b1811 100644
--- a/src/compiler/decl.zc
+++ b/src/compiler/decl.zc
@@ -153,7 +153,7 @@ int unit_stdin() {
// that a nested compile would otherwise clobber (locals, depth, frame size,
// loop stack position, the expression-state globals). closures use the same
// pair.
-const int CTX_WORDS = 48;
+const int CTX_WORDS = 49;
int ctx_push() {
af_forget();
word f;
@@ -164,7 +164,7 @@ int ctx_push() {
f[13] = lv; f[14] = lvk; f[15] = lvi; f[16] = kw_expr; f[17] = xcls; f[18] = snaptop;
f[19] = fty; f[20] = ntp; f[21] = xty; rt.copy_w(f + 22, tpn, 8);
f[30] = finsym; f[31] = finfer; f[32] = ifcur; f[33] = ifcall; f[34] = effect_current; f[35] = borrow_slots; f[36] = borrow_pending; f[37] = borrow_depth; f[38] = borrow_jump; f[39] = borrow_entry; f[40] = capture_enabled; f[41] = effect_value; f[42] = xprojection; f[43] = effect_floor; f[44] = module_name; f[45] = module_imports;
- f[46] = fn_return_type; f[47] = if_value;
+ f[46] = fn_return_type; f[47] = if_value; f[48] = dfr_base;
return 0;
}
// pop the innermost function context.
@@ -175,6 +175,7 @@ int ctx_pop() {
local_drop(f[0]);
fdrop(nloc);
lend_drop(1 << 30, f[0]);
+ defer_drop(dfr_base); dfr_base = f[48];
lbase = f[1];
fdepth = f[2];
fslots = f[3];
@@ -204,6 +205,7 @@ int fn_begin(int chk, int ret) {
capture_enabled = 0; effect_value = 0; effect_current = 0; borrow_slots = 0; borrow_pending = 0; borrow_depth = 0; borrow_jump = -1; borrow_entry = 0;
if (cmode && svkind && !dry) rt.fill_w(svkind, 0, nsym); xvk = 0;
lend_drop(1 << 30, nloc);
+ dfr_base = ndfr;
lbase = nloc; fdepth = 1; fslots = 0; fchk = chk && check_on; fret = ret; fty = 0; finfer = 0; fn_return_type = 0;
live = 1; bxdepth = 0; epichain = 0; infn = 1; loopbase = lsp; lv = 0; lvk = LV_NONE; xbor = -1;
return 0;
@@ -258,6 +260,7 @@ int body() {
}
closed = is_op(s_rb); endplace = toff + toklen;
if (probe_off >= 0 && !chkabort && !dry && !ginst && incdepth == 0 && ctxsp <= nclo && toff >= probe_off) { probe_snap(); chkabort = 1; }
+ defer_run(1, 1); // the function's own deferred statements, before its locals are checked
local_hints(lbase);
unused_check(lbase);
if (ifcur) if_fin();
@@ -1343,6 +1346,7 @@ int compile_list_context(int q, int top, char* module, word imports) {
fn_begin(1, 0);
prologue(); borrow_prologue(); borrow_begin();
while (tk != T_EOF) stmt();
+ defer_run(1, 1);
unused_check(lbase);
if (fchk && live) exit_vars(1, 1);
epilogue();