ludic/tools/ludic-cli
Orkuncakilkaya e4265f5fdb feat(lang): 27.1 - a state machine as data: @Machine(Record.field) on a registry of transitions
A registry marked `@Machine(Deer.mood)` is the transitions of a machine over that enum field of the
records a state's Table<Deer> holds. Its record has from and to (the enum's variants), on: string (an
action's name, "" for a transition the tick asks), guard: fn(Row<Deer>, reads...) -> bool and
enter: fn(Row<Deer>, reads...) -> void; the states are the enum's variants and the start is the
field's default. The rows are data (an .lres or defs), the names the studio already edits.

Written by the compiler (machines.ludic, machines_write.ludic): for each action an `on` names, a row
reducer in the registry's file (named ..__machine__DeerSteps, so it sits beside the program's own
row reducer on the same action, after it): the row's state, the first transition from it on that
action whose guard passes, the field set, enter run - guards and enters called by name. When a row
leaves a state on a guard alone, `state DeerStepsMachine` (the kept row view) and
deer_steps_tick(m: mut DeerStepsMachine, s: mut Herd, reads...), one transition a row a tick.
Nothing allocates.

The table is the whole machine: the field written anywhere else - an assignment, or a `machine`
block's become over it - is a type error (check_stmt.ludic, ck_machine_write). Guards and enters take
the row first, are the record's module's, keep a row reducer's rules (and may be handed the row);
a guard writes nothing through it. The graph is checked, each error at its row (in the .lres when
the rows are there): a state never reached from the start, a state with no way out, an `on` naming
no action or an action with no @Target, a self-transition with no guard, two ways out of a state on
one trigger behind an unguarded first. Also refused: @Machine off a registry, a field that is not a
plain enum with a default, a @Column field, no table (or two) of the record, a transitions record of
another shape, a machine outside its table's state's module.

ludic schema's code section gains `machines` (registry, record, field, enum, table, start, states,
actions, tick, module, at); ludic deps names a machine's reducer `reducer Deer in Herd.deer on Spook
(machine DeerSteps)`. vocab @Machine; docs annot-machine, kw-machine; LANGUAGE.md "A machine as
data"; examples actions/machine (+ deer_steps.lres) and ten rejects; test.ludic feat, reject and
schema cases (not run); changes/machines.md. Reseeded; bootstrap-cfree fixpoint holds (317642
lines); Maroon Lake's `ludic build --check` is clean against this tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:37:37 +03:00
..
assets.ludic feat(windows): the ludic CLI and ludic bundle on Windows 2026-09-13 03:01:33 +03:00
build.ludic Build.schema_hash(): FNV-1a 64 of the program's own schema (the bytes ludic schema prints), worked out only when a program names it, 0 under ludicc --release, which ludic bundle now passes (Mac and Windows); reseeded 2026-09-29 19:05:28 +03:00
bundle.ludic Build.schema_hash(): FNV-1a 64 of the program's own schema (the bytes ludic schema prints), worked out only when a program names it, 0 under ludicc --release, which ludic bundle now passes (Mac and Windows); reseeded 2026-09-29 19:05:28 +03:00
checks.ludic ludic syntax, and ludic-dev syntax: every grammar written from the compiler's vocabulary and checked against it 2026-09-29 23:59:30 +03:00
deps.ludic feat(lang): 27.1 - a state machine as data: @Machine(Record.field) on a registry of transitions 2026-09-30 16:37:37 +03:00
dev.ludic Merge lang/foundations (9391695) into lang/editortools: no conflicts, selfhost/ identical to lang/foundations (the seeds unchanged; bootstrap-cfree fixpoint holds at 289532 lines), the help lists R10's --stdin-file, R8's syntax and R9's fmt / remove lines together 2026-09-30 00:26:26 +03:00
docgen.ludic feat(lang): L4 type checker between parse and emit 2026-09-24 01:34:49 +03:00
docgen_check.ludic refactor(cli)!: split the contributor tool out of the ludic CLI 2026-09-05 23:15:12 +03:00
docgen_gen.ludic feat(windows): the ludic CLI and ludic bundle on Windows 2026-09-13 03:01:33 +03:00
forgejo.ludic feat(windows): the ludic CLI and ludic bundle on Windows 2026-09-13 03:01:33 +03:00
glgen.ludic feat(lang): L4 type checker between parse and emit 2026-09-24 01:34:49 +03:00
json.ludic feat(lang): L4 type checker between parse and emit 2026-09-24 01:34:49 +03:00
lsp_test.ludic ludic-lsp: every declaration by its own kind, every field a child, attribute arguments resolve 2026-09-29 23:59:40 +03:00
main.ludic Merge lang/foundations (9391695) into lang/editortools: no conflicts, selfhost/ identical to lang/foundations (the seeds unchanged; bootstrap-cfree fixpoint holds at 289532 lines), the help lists R10's --stdin-file, R8's syntax and R9's fmt / remove lines together 2026-09-30 00:26:26 +03:00
migrate.ludic feat(migrate): 0.R5 - ludic migrate state --tighten takes mut off every state parameter nothing down the chain writes; --root DIR lets the edits reach a directory without running its programs; a write through a local holding part of a mut state counts as a write to it 2026-09-27 00:20:44 +03:00
pack.ludic docs(packages): an index of the packages; the pack skips what is not a package directory 2026-09-25 07:22:05 +03:00
packignore.ludic feat(pack): .packignore, so a pack root can leave build artefacts out 2026-09-11 18:29:32 +03:00
pkg.ludic ludic remove <module> and ludic get --json (R9) 2026-09-30 00:24:49 +03:00
pkg_lock.ludic ludic remove <module> and ludic get --json (R9) 2026-09-30 00:24:49 +03:00
pkg_remove.ludic ludic remove <module> and ludic get --json (R9) 2026-09-30 00:24:49 +03:00
pkg_test.ludic ludic remove <module> and ludic get --json (R9) 2026-09-30 00:24:49 +03:00
prelude.ludic feat(test): ludic test -j N runs tests side by side 2026-09-25 11:38:09 +03:00
project.ludic ludic fmt for editors: --lint --json, and a buffer on stdin (R9) 2026-09-30 00:24:43 +03:00
release.ludic ludic ui-preview: ludic.ui components previewed for a studio over stdio (R5) 2026-09-29 19:53:26 +03:00
schema.ludic compiler: ludic schema gains a "code" section (R7) - the code map from the compiler, so the studio's scan is only a fallback: modules (package, layer, uses and where, friend, files), states, actions, reducers, every dispatch, events (cancellable, net) with every emit and their @On listeners, ports (members with fn types, defaults, required) and binds (port, member, fn, value, at), handlers (phase, hook and target, @Public, @Server / @Predicted, @Queries with filters as written, scene and layer), models (@Owned, @Sync), prefabs, scenes (start, public, shows, lasts / then, loads, enter / exit, layers) and fn_refs - every fn name in code or a resource file with the slot it fills (registry field and row, port member or default, record field, emit field, call argument, assignment, let). Places are "file:line:col"; sorted by name, sites by place; schema_version stays 1 (additive). The parser records emits, fn refs, handlers and scenes' layers / lasts / loads for it (emit_schema_code.ludic, emit_schema_code_game.ludic); LANGUAGE.md and the changeset say so; schema_case lines added (not run); reseeded, bootstrap-cfree fixpoint holds 2026-09-30 00:19:24 +03:00
scripts.ludic ludic remove <module> and ludic get --json (R9) 2026-09-30 00:24:49 +03:00
selfhost.ludic feat(lang): 27.1 - a state machine as data: @Machine(Record.field) on a registry of transitions 2026-09-30 16:37:37 +03:00
selfhost_test.ludic wip(0.S1, 0.S2): state records, mut and read-only state parameters, entry injection, module var refused; ludic migrate state 2026-09-25 13:45:09 +03:00
shaders.ludic render3d: a renderer that cannot draw says so and stops - LUDIC_HOME's leading ~ expanded (an unexpanded one left a run without shaders, logging 27 missing variants and drawing on), the SPIR-V manifest ends with E <count> and a cut or miscounted one is refused, and every such failure is a fault: r3d_open / r3d_load_step fail on it, r3d_fault() / r3d_fault_exit(code) for the game; tests/manifest_test 2026-09-29 22:12:39 +03:00
split.ludic ludic build on every core: the IR split with llvm-split and compiled by a clang per part at once 2026-09-29 17:12:27 +03:00
syntax_cli.ludic ludic syntax, and ludic-dev syntax: every grammar written from the compiler's vocabulary and checked against it 2026-09-29 23:59:30 +03:00
syntax_gen.ludic checker: a function named like a built-in a call always takes is refused at its declaration - function words(st, k) compiled and every call became words(n) with a pointer for n (invalid IR, far from the cause); the table is selfhost/check/check_builtins.ludic, emit_call's built-ins no find_fn guard lets a declared function take, and ludic-dev syntax --check holds it to emit_call both ways; every other built-in (buffer, floats, double, ...) yields to a declared function in the checker as it already did in codegen. string_temps' keep and cross_heap_test's keep renamed (hand, keep_cell); rejected/builtin_call_name and functions/builtin_yield with their cases (added, not run); reseeded, bootstrap-cfree fixpoint holds 2026-09-30 01:10:24 +03:00
test.ludic feat(lang): 27.1 - a state machine as data: @Machine(Record.field) on a registry of transitions 2026-09-30 16:37:37 +03:00
testpar.ludic feat(pkg): phase 15 - a package can carry a native library 2026-09-26 23:35:45 +03:00
toolchain.ludic ludic ui-preview: ludic.ui components previewed for a studio over stdio (R5) 2026-09-29 19:53:26 +03:00
tools.ludic ludic fmt for editors: --lint --json, and a buffer on stdin (R9) 2026-09-30 00:24:43 +03:00
ui_preview.ludic ludic ui-preview: ludic.ui components previewed for a studio over stdio (R5) 2026-09-29 19:53:26 +03:00
vkgen.ludic feat(lang): L7 memory is safe unless it says unsafe 2026-09-24 12:53:27 +03:00