Commit Graph

4 Commits

Author SHA1 Message Date
13f1df03ef Unbreak the three example programs the RND merge left behind
All checks were successful
akbasic CI Build / cmake_build (push) Successful in 3m46s
akbasic CI Build / coverage (push) Successful in 4m16s
akbasic CI Build / sanitizers (push) Successful in 8m10s
akbasic CI Build / akgl_build (push) Successful in 8m10s
akbasic CI Build / mutation_test (push) Successful in 17m55s
Adding native RND and ASC (ae2c702) made RND a function name, and a suffixed
identifier that collides with one is refused -- "SYNTAX ERROR Reserved word in
variable name". Three example programs held their PRNG output in a variable
called RND#, or a host field called RND%, and none of them had run since:

  - examples/galaga/ bound RND% as a host field on both ENEMY and GAME. The
    BASIC-visible name is ROLL% now; the C member stays `rnd`. This one was
    caught by example_galaga and example_galaga_interop, which have been
    failing.
  - examples/breakout/characters/breakout.bas and examples/megademo/
    megademo.bas both use RND# for their LCG output, renamed to ROLL#. Neither
    is in any test, so neither failure was visible.

examples/breakout/sprites/breakout.bas was broken a second way: seven REM lines
the reader refuses. Worth recording that the ceiling is not the one the message
names -- src/sink_stdio.c fails when the read filled the buffer without seeing
a terminator, so with AKBASIC_MAX_LINE_LENGTH at 80 the message says "79
character limit" and the real maximum is 78, because a 79-character line leaves
no room for the newline. The sweeps that fixed the corpus and the megademo for
this did not reach this file. The seven comments are reflowed.

The prose went stale with the code. Chapter 21 said "there is no RND verb in
this dialect; issue #16 tracks adding one", chapter 17's historical aside
offered an LCG that no longer parses, and four REM blocks across the two games
said the same thing. All of them now say RND exists, and say why these programs
keep their own generator anyway: the sequence has to be reproducible for a
headless run to be the same game on every machine, which is what lets
interop_test.c assert exact counts.

Chapter 21 also gains the rule that bit them, since a reader writing a host
type will hit it: a host field name is a bare word and shares a namespace with
every verb and function.

None of this came from the submodule bump -- all three were already broken on
main. It was found by running the tutorial games, which nothing else does;
that gap is akbasic issue #58.

Verified: all three run clean under the dummy drivers, and 114/114 default,
116/116 with akgl.

Co-Authored-By: Andrew Kesterson <andrew@aklabs.net>
Co-Authored-By: Claude Code (Claude Opus 5, claude-opus-5[1m]) <noreply@anthropic.com>
2026-08-05 23:26:33 -04:00
bb2d896e4b Close the remaining cold-read gaps: bind, labels, menus and main's shape
Three more Haiku-class cold reads of the chapters, each against the
amended text. What each surfaced is now shown rather than described: the
akbasic_host_register_type()/akbasic_host_bind() boot calls, the
declare_play() label listing, the akgl_UiMenu static and its
handle_event signature, one control-handler pair, and main()'s
ATTEMPT/HANDLE_DEFAULT/FINISH_NORETURN shape with the CATCH-inside-
ATTEMPT rule stated. By the fourth read the generated player.c and
enemies.c compiled untouched and every remaining guess was a tuning
value the chapters deliberately leave open.

Co-authored-by: andrew <andrew@aklabs.net>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XiGgpHuXUm2mR4Wzndw3dc
2026-08-04 20:05:41 -04:00
3183908012 Benchmark the boundary and close the cold read's tutorial gaps
The interop test now ends with a measured comparison: 24,000 formation
updates through the script boundary against a line-for-line C
translation of the same state machine. 881 us against 0.01 us per call
on this machine, quoted verbatim in the new chapter 21 Step 11 with the
architectural decisions it prices.

A Haiku-class cold read of the chapters produced a build whose failures
were all mechanical -- invented include paths, never-shown sink statics,
guessed status codes and character names. The chapters now carry the
include lists, the script.c statics, the status-code roster, the
sprite/character table, the full CMake recipe and the explosion spawn's
HANDLE example, so none of those have to be guessed again.

Co-authored-by: andrew <andrew@aklabs.net>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XiGgpHuXUm2mR4Wzndw3dc
2026-08-04 20:05:41 -04:00
ed99d38534 Write the GALAGA tutorial chapters and the repeated-host-calls guide
docs/20 builds the engine and the boundary: the startup order, the
starfield, actors and collision, booting a DEF-only script, the issue #8
mode workaround, the custom update hook, first light, screens, and the
headless harness. docs/21 builds the three shared structures and the AI:
the host type tables, the actor binding, the randomness route around
issue #16, the measured case against structure arguments (issue #36),
the three language rules that shape the script, the maneuvers, the
argued formation decision, the script-death policy, and the interop
proof. Every fenced block runs under tests/docs_examples.sh in both
build configurations; five new preludes carry the C fragments.

docs/10 gains the 'Calling a function every frame' section the chapters
lean on: the per-call akbasic_environment_zero() rule, the set_mode(RUN)
workaround, the clear_error() revival, and the case for rebinding over
structure arguments. Index rows and chapter counts updated.

Co-authored-by: andrew <andrew@aklabs.net>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XiGgpHuXUm2mR4Wzndw3dc
2026-08-04 20:05:41 -04:00