Adds the rest of the game/entity/property lifecycle as @-hooks, each firing at
one timeline moment and reducing to ordinary code:
- @OnStart / @OnQuit (program): @OnStart aliases the Start phase; @OnQuit runs in
the frame loop's done: block, after the loop stops and before teardown.
- @OnDespawn(Model) (entity): a destructor. Despawn doesn't statically know the
entity's model, so hooks compile to @on_despawn_<Model>(entity) functions and
emit_despawn dispatches on @L_kind. Symmetric with @OnSpawn.
- @OnAttach(Property): fires in emit_init_component once a property is attached
and seeded, with the property bound by name.
Registries + parsing mirror @OnSpawn. examples/lifecycle.ludic narrates the whole
timeline (output 1 700 50 950 2). Behaviour-preserving (goldens byte-identical,
despawn users unaffected when no hooks registered); test.sh 16/16, fixpoint holds.
Deferred: @OnDetach (per-property runtime dispatch) and scene @OnEnter/@OnExit
(need scene support in the compiler).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds two annotations that give properties/models a scriptable feel WITHOUT
reattaching behavior to data — both reduce to code the data-oriented model
already emits:
- @Computed field on a property: a derived value that is NOT stored; x.field
expands inline to its expression (bare names read as fields of x) at each use.
Zero storage, zero runtime dispatch. Reuses qualify_fields (now non-destructive,
base-node based); a g_computed registry keeps derived fields out of the layout.
- @OnSpawn(Model) on a handler: a constructor that runs at each spawn of Model
with the model's properties bound by name. Spawn statically knows the model, so
no runtime dispatch; emit_spawn binds the properties and inlines the hook body.
examples/annotations.ludic now exercises @Handles/@Queries/@Computed/@OnSpawn
(output 3 25 0 0); test.sh 15/15, fixpoint holds, goldens byte-identical.
Deferred (need more machinery, by design): @OnDespawn (despawn doesn't statically
know the entity's model) and @OnChange (needs change-tracking).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The parser now requires a newline or ';' between statements (block() in
selfhost/parse.ludic); two statements may no longer sit adjacent with only
spaces. Also fixed if-without-else swallowing its trailing separator.
Migration: tools/ludic-tools/migrate_separators.c inserts ';' at statement
boundaries corpus-wide (examples, runtime, 25 self-host fragments, ~1100
boundaries). Verified semantically identical — the migrated compiler compiles
itself to IR byte-identical to the pre-migration seed, and every golden game
renders identically. Reseeded to the strict compiler; C-free fixpoint holds;
test.sh 14/14.
Docs: Rule B documented in LANGUAGE.md; BOOTSTRAP.md R1 + stale fences updated;
check-docs green across all docs. Fixed a multi-line string literal in
emit_expr.ludic (byte-identical \n escape) that the C toolchain lexer mis-lexes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Self-hosted compiler (selfhost/*.ludic), runtime, examples, editor tooling,
and docs. Phase 1 of the syntax-redesign cohesion pass has landed:
edge-system fix, signature-query, when-alias, and the documentation truth-pass.
Suite green (14/14), C-free bootstrap fixpoint holds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>