You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Summary
Closes#459 — `break` and `continue` now parse, type-check (rejected
outside loop bodies with a clear error), and lower to JS
`break;`/`continue;` in the Deno-ESM and Node JS backends. Pre-fix:
`BREAK`/`CONTINUE` were lexer-reserved tokens with no parser production
consuming them; any use was a syntax error.
## Pipeline changes
| File | Change |
|---|---|
| `lib/ast.ml` | `ExprBreak of Span.t`, `ExprContinue of Span.t` |
| `lib/parser.mly` | `BREAK`/`CONTINUE` productions in `expr_assign`
(diverging prefix, next to `RETURN`/`RESUME`) |
| `lib/resolve.ml` | pass-through (`resolve_expr` + `lower_expr`) |
| `lib/typecheck.ml` | new `ctx.in_loop : mutable bool` flipped on
`StmtWhile`/`StmtFor` body entry; `synth` returns `ty_never`; new
`NotInLoop of string` error |
| `lib/borrow.ml` | pass-through (span lookup, visit-recurse, free-var
collection, main checker) |
| `lib/quantity.ml`, `lib/effect_sites.ml` | pass-through (no resources,
no call sites) |
| `lib/codegen_deno.ml`, `lib/js_codegen.ml` | statement-position
lowering to bare JS keywords |
## Test fixture
`tests/codegen-deno/loop_break_continue.affine` + harness — 14
assertions across:
- `while` + `break` (threshold-driven early exit)
- `while` + `continue` (skip-evens accumulator)
- `for` + `break` (find-first-match)
- `for` + `continue` (count-positive filter)
- Edge cases: break on first iteration, no-break path, empty array
## Out of scope
- **Non-JS backends** (wasm/GC/lua/c/rust/etc.): fall through existing
wildcards. Full backend support files separately if needed.
- **JS-codegen expression-position IIFE wrapper** (legacy MVP path)
emits `(() => { break; })()` which would throw `SyntaxError: Illegal
break statement` at runtime — legal AffineScript places break/continue
inside loop bodies so the statement path fires. Deno backend uses the
correct statement-position emit.
## Test plan
- [x] `./tools/run_codegen_deno_tests.sh`: 15/15 harnesses green
- [x] `dune test`: 352/352 unit tests green
- [x] Misuse check: `pub fn bad() -> () { break; }` emits the new
`NotInLoop` error with the expected message
## Refs
- Closes#459
- Refs hyperpolymath/standards#284 (workarounds documented in the "Seam
findings" section that surfaced this gap)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments