Implement the housekeeping verbs, and stop the REPL spinning after an error

NEW, CLR, CONT, SWAP, TRON, TROFF and HELP. None is in the Go reference, so
what each means here is recorded beside it.

Testing CONT turned up a hang that predates this: the runtime's error class is
deliberately sticky, and with run_finished_mode REPL every later step
re-entered REPL and printed READY -- overwriting the QUIT that end of input
had just set. An interactive session that hit one runtime error printed READY
forever instead of exiting.

RESTORE and RENUMBER are deferred with reasons; RESTORE turns out to need a
DATA pointer this port does not have, which is a defect in its own right.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-31 12:07:50 -04:00
parent f4007d80d4
commit bfac13ff87
11 changed files with 658 additions and 1 deletions

21
TODO.md
View File

@@ -543,7 +543,8 @@ Order by what unblocks the most, and by what does not need `libakgl` to grow fir
| Group | Verbs | Blocked on |
|---|---|---|
| A. Structure | `DO`, `LOOP`, `WHILE`, `UNTIL`, `ON`, `BEGIN`, `BEND`, `END` | nothing — reuses `waitingForCommand` |
| B. Housekeeping | `NEW`, `CLR`, `CONT`, `RESTORE`, `RENUMBER`, `SWAP`, `TRON`, `TROFF`, `HELP` | nothing |
| ~~B. Housekeeping~~ | ~~`NEW`, `CLR`, `CONT`, `SWAP`, `TRON`, `TROFF`, `HELP`~~ | **done**`src/runtime_housekeeping.c`, `tests/housekeeping_verbs.c` |
| B. Housekeeping, deferred | `RESTORE`, `RENUMBER` | neither is small; see below |
| C. Errors | `TRAP`, `RESUME`, `ER`, `ERR` | needs a BASIC-visible error object |
| D. Strings/format | `USING`, `PUDEF`, `WIDTH`, `CHAR` | nothing |
| E. Console | `WINDOW`, `KEY`, `SLEEP`, `WAIT`, `TI` | the sink, or the clock `akbasic_runtime_settime()` now carries |
@@ -555,6 +556,24 @@ Order by what unblocks the most, and by what does not need `libakgl` to grow fir
| ~~E. Console input~~ | ~~`GET`, `GETKEY`, `SCNCLR`~~ | **done**`src/runtime_input.c`, `tests/input_verbs.c` |
| J. Machine | `SYS`, `FETCH`, `STASH`, `POKE`/`PEEK` variants | nothing |
**`RESTORE` and `RENUMBER` are deferred, and neither is a small job.**
- **`RESTORE` needs a DATA pointer, and there isn't one.** `READ` does not read: it declares
that the *next* `DATA` line reached in execution order should fill its identifiers, and skips
forward until one turns up (`akbasic_cmd_read`, ported faithfully). There is no cursor into a
list of `DATA` items, so there is nothing for `RESTORE` to reset. Implementing it honestly
means implementing the pointer, which is worth doing on its own merits, because the current
arrangement has a defect the corpus does not catch: **a `DATA` line that appears *before* its
`READ` is never found**, so `10 DATA 1,2` / `20 READ A#` runs off the end of the program in
silence, and a second `READ` re-reads the same line rather than continuing. The fix is a
pre-scan of every `DATA` statement into a flat list plus a read cursor, at which point
`RESTORE [line]` is three lines. Its own commit, with the golden cases the change would need.
- **`RENUMBER` has to rewrite references or it is worse than useless.** Moving lines is easy —
source is filed under its line number in `source[]`. Rewriting every `GOTO`, `GOSUB`, `THEN`,
`ELSE`, `RUN` and `LIST` target to match is the job, and doing it on source text means
distinguishing a line number from a digit inside a string literal. Refusing it is better than
a `RENUMBER` that silently breaks every branch in the program.
`LOCATE` used to appear in both E and G. It belongs to G alone: in BASIC 7.0 `LOCATE` moves the
*graphics* pixel cursor that `DRAW` starts from, and the text cursor verb is `CHAR`, which is
already in group D.