aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/stmt.zc12
1 files changed, 12 insertions, 0 deletions
diff --git a/src/compiler/stmt.zc b/src/compiler/stmt.zc
index 6d5abe7..703f2db 100644
--- a/src/compiler/stmt.zc
+++ b/src/compiler/stmt.zc
@@ -232,8 +232,18 @@ int kw_if() {
// loops and switches share a frame stack (R_LOOP, 8 words each). a break adds
// an exit record (the analyzer state at that point) with a jump to patch;
// loop_end joins all of them with the normal fall-out and patches the jumps.
+// lpo3[k]: how many o3 blocks were open when loop or switch k began; a break or
+// continue out of an o3 { } block to it leaves those blocks (rt.o3_leave), as a return does
+word lpo3; int lpo3cap;
+int o3_leave_to(int k) {
+ int n = o3blk - lpo3[k];
+ while (n > 0) { callname(intern("rt.o3_leave")); op(O_DROP); n--; }
+ return 0;
+}
int loop_push(int cont, int s0) {
word f;
+ if (lsp >= lpo3cap) { lpo3 = chk_resize(lpo3, lpo3cap, lsp * 2 + 16); lpo3cap = lsp * 2 + 16; }
+ lpo3[lsp] = o3blk;
reserve_R_LOOP((lsp + 1) * 8);
if (lsp >= loopfacts_cap) { lpfact = chk_resize(lpfact, loopfacts_cap, loopfacts_cap * 2); loopfacts_cap = loopfacts_cap * 2; }
f = R_LOOP + lsp * 8;
@@ -412,6 +422,7 @@ int kw_break() {
if (dfr_on && dfr_ctx == ctxsp && lsp <= dfr_lsp) { serr("break can't leave a deferred statement"); return 0; }
defer_run(f[2] + 1, 0);
exit_vars(f[2] + 1, 0);
+ o3_leave_to(lsp - 1);
if (live) exit_rec(hole()); else hole();
op(O_JMP);
live = 0;
@@ -430,6 +441,7 @@ int kw_continue() {
defer_run(f[2] + 1, 0);
backedge(f[3]);
exit_vars(f[2] + 1, 0);
+ o3_leave_to(j);
if (f[0] == -2) { f[7] = fixnew(hole(), f[7]); op(O_JMP); } // do/while: the condition isn't placed yet
else jmp(f[0]);
live = 0;