Fix generator teardown leaks, add RETURN-in-GEN and LOOP conditions on DO EACH
All checks were successful
akbasic CI Build / cmake_build (push) Successful in 3m26s
akbasic CI Build / coverage (push) Successful in 4m0s
akbasic CI Build / sanitizers (push) Successful in 6m33s
akbasic CI Build / akgl_build (push) Successful in 9m32s
akbasic CI Build / mutation_test (push) Successful in 18m47s
All checks were successful
akbasic CI Build / cmake_build (push) Successful in 3m26s
akbasic CI Build / coverage (push) Successful in 4m0s
akbasic CI Build / sanitizers (push) Successful in 6m33s
akbasic CI Build / akgl_build (push) Successful in 9m32s
akbasic CI Build / mutation_test (push) Successful in 18m47s
Review findings and follow-ups from PR #61 review: - runtime_generator.c: akbasic_runtime_release_generator() now releases the forGeneratorEnv of every scope it walks through. Abandoning a generator that was itself suspended inside a FOR EACH over another generator stranded the inner generator's pool slot; a loop doing so exhausted the twelve-slot pool and died far from the cause. - runtime.c/runtime.h: new akbasic_runtime_unwind_to_environment(), the shared teardown for the error unwinds in pump_generator() and call_function() -- both previously bare prev_environment() loops with the same suspended-generator blindness. - runtime_commands.c: bare RETURN standing in a GEN's own frame ends the generator exactly as END GEN does -- a GEN is a function at heart. RETURN with a value there is refused (values leave a GEN only through EMIT). The no-frame error message now says "GOSUB, DEF, or GEN". - runtime_structure.c: LOOP WHILE/UNTIL composes with DO EACH -- checked after each trip with the loop variable still holding that trip's value; a condition that stops the loop abandons the generator exactly as EXIT does. Previously the condition was silently ignored, while the verb reference documented it as working. - parser_commands.c: trailing tokens after the generator call on a FOR EACH/DO EACH line are refused at parse. Previously they sat unparsed and blew up only after the loop completed, when the parent scope resumed the line mid-statement -- an error at the loop's end pointing at its start. - tests/generators.c: pool-exhaustion tests for the nested-abandonment and LOOP-condition paths, RETURN semantics tests, and a direct test of the unwind primitive. Three new golden pairs cover RETURN, LOOP conditions and the misplaced-condition parse error. - docs: RETURN and LOOP-condition semantics in 04-control-flow.md and 11-verb-reference.md; corrected the self-recursion analogy (functions are re-entrant here). TODO.md 1.10 records the generator design decisions the code comments were already citing, plus the zero-arg parameter-list limitation. MAINTENANCE.md gains the abandoned-generators invariant those comments also cited. Co-Authored-By: Andrew Kesterson <andrew@aklabs.net> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ for the reasoning in each case.
|
||||
| `DIM` … `AS` | `DIM S@ AS T`, `DIM P@ AS PTR TO T` | Make a structure, or a strict pointer to one. See Chapter 16. |
|
||||
| `DIRECTORY` | `DIRECTORY` | **Refused.** Not written yet; the standard-library wrapper it waited on has landed. |
|
||||
| `DLOAD` | `DLOAD "name"` | Load a program from a file. |
|
||||
| `DO` | `DO [WHILE c | UNTIL c]`, `DO EACH V IN gen(args)` | Start a loop. The condition may be here, on the `LOOP`, or neither. `EACH` consumes a `GEN` instead; see Chapter 4. |
|
||||
| `DO` | `DO [WHILE c | UNTIL c]`, `DO EACH V IN gen(args)` | Start a loop. The condition may be here, on the `LOOP`, or neither. `EACH` consumes a `GEN` instead, and takes its condition only on the `LOOP`; see Chapter 4. |
|
||||
| `DOPEN` | `DOPEN n, "name" [,W]` | Open a file on channel `n`. `W` opens it for writing. |
|
||||
| `DRAW` | `DRAW src, x, y [TO x, y ...]` | Plot a point or draw a polyline. |
|
||||
| `DSAVE` | `DSAVE "name"` | Save the program to a file. |
|
||||
@@ -90,7 +90,7 @@ for the reasoning in each case.
|
||||
| `RENUMBER` | `RENUMBER [start [,step [,from]]]` | Renumber lines, rewriting every branch to match. |
|
||||
| `RESTORE` | `RESTORE [line]` | Reset the `READ` cursor, optionally to a line. |
|
||||
| `RESUME` | `RESUME [NEXT | line]` | Return from a `TRAP` handler. |
|
||||
| `RETURN` | `RETURN [expr]` | Return from a `GOSUB` or a multi-line `DEF`. |
|
||||
| `RETURN` | `RETURN [expr]` | Return from a `GOSUB` or a multi-line `DEF`. Inside a `GEN`, a bare `RETURN` ends the generator early; `RETURN expr` there is an error. |
|
||||
| `RUN` | `RUN [line]` | Run the program, optionally from a line. |
|
||||
| `SAVE` | `SAVE "name"` | The other name for `DSAVE`. |
|
||||
| `SCALE` | `SCALE on [,xmax, ymax]` | Turn user coordinates on or off. |
|
||||
|
||||
Reference in New Issue
Block a user