Repo cleanup: reorganise selfhost/ into concern-based subdirectories #29

Closed
opened 2026-08-30 12:50:18 +02:00 by orkun · 1 comment
Owner

Problem

selfhost/ is 38 flat .ludic files at a single level with no categorisation
— just golden/ and tests/ subdirs. The compiler is one big undifferentiated
pile:

  • 30+ emit_*.ludic files (emit_core, emit_expr, emit_stmt, emit_game,
    emit_math, emit_net, emit_crypto, emit_datetime, emit_ui, emit_ecs,
    emit_query, emit_spawn, emit_save, emit_text, emit_vector, …) all
    sitting next to lex.ludic, parse.ludic, ast.ludic, io.ludic, str.ludic.
  • Some files clearly do more than one job (emit_game.ludic is 764 lines,
    emit_expr.ludic 624, emit_text.ludic 558).

Per the project's own structure rule (one job per file; a directory may own one
namespace, no more), this is overdue for a split.

Proposal

Reorganise into concern-based subdirectories, e.g.:

selfhost/
  frontend/     lex.ludic, parse.ludic, parse_game.ludic, ast.ludic
  backend/      emit_core, emit_expr, emit_stmt, emit_decl, emit_head, emit_machine …
  backend/stdlib/  emit_math, emit_vector, emit_net, emit_crypto, emit_datetime,
                   emit_hash, emit_color, emit_ease, emit_text, emit_ui, emit_ecs …
  support/      io.ludic, str.ludic, buf.ludic, mem.ludic
  • Split the oversized emitters (emit_game, emit_expr, emit_text) so each
    file has a single responsibility.
  • Update the concatenation list (tools/x/selfhost.ludic FRAGS) and the
    bootstrap/reseed flow to match; keep bin/x reseed && bin/x bootstrap-cfree && bin/x test green.

Acceptance criteria

  • selfhost/ organised into concern-based subdirectories.
  • No file mixes unrelated responsibilities; oversized emitters split.
  • FRAGS/build updated; full bootstrap + test still passes byte-identical.

Part of the repository-cleanup / DX pass.

## Problem `selfhost/` is **38 flat `.ludic` files** at a single level with no categorisation — just `golden/` and `tests/` subdirs. The compiler is one big undifferentiated pile: - **30+ `emit_*.ludic`** files (`emit_core`, `emit_expr`, `emit_stmt`, `emit_game`, `emit_math`, `emit_net`, `emit_crypto`, `emit_datetime`, `emit_ui`, `emit_ecs`, `emit_query`, `emit_spawn`, `emit_save`, `emit_text`, `emit_vector`, …) all sitting next to `lex.ludic`, `parse.ludic`, `ast.ludic`, `io.ludic`, `str.ludic`. - Some files clearly do more than one job (`emit_game.ludic` is 764 lines, `emit_expr.ludic` 624, `emit_text.ludic` 558). Per the project's own structure rule (one job per file; a directory may own one namespace, no more), this is overdue for a split. ## Proposal Reorganise into concern-based subdirectories, e.g.: ``` selfhost/ frontend/ lex.ludic, parse.ludic, parse_game.ludic, ast.ludic backend/ emit_core, emit_expr, emit_stmt, emit_decl, emit_head, emit_machine … backend/stdlib/ emit_math, emit_vector, emit_net, emit_crypto, emit_datetime, emit_hash, emit_color, emit_ease, emit_text, emit_ui, emit_ecs … support/ io.ludic, str.ludic, buf.ludic, mem.ludic ``` - Split the oversized emitters (`emit_game`, `emit_expr`, `emit_text`) so each file has a single responsibility. - Update the concatenation list (`tools/x/selfhost.ludic` `FRAGS`) and the bootstrap/reseed flow to match; keep `bin/x reseed && bin/x bootstrap-cfree && bin/x test` green. ## Acceptance criteria - [ ] `selfhost/` organised into concern-based subdirectories. - [ ] No file mixes unrelated responsibilities; oversized emitters split. - [ ] `FRAGS`/build updated; full bootstrap + test still passes byte-identical. Part of the repository-cleanup / DX pass.
orkun added the
priority:medium
area:tooling
area:repo
cleanup
labels 2026-08-30 12:50:18 +02:00
orkun closed this issue 2026-08-30 23:26:08 +02:00
Author
Owner

Done in 23726af (pushed to main).

New layout — selfhost/ went from 38 flat files to concern-based subdirectories:

selfhost/
  frontend/        lex, parse, parse_game, ast
  support/         str, buf, io
  backend/         core IR + expression/statement lowering
  backend/game/    ECS / scene / event / world lowering
  backend/stdlib/  the namespaced Math.* / Text.* / Crypto.* / … intrinsics
  main.ludic       (driver, kept at the root)

Oversized emitters split at responsibility boundaries so no file mixes concerns:

was now (764/654/558 → …)
emit_game.ludic (764) emit_game.ludic (388, systems/scenes/events) + emit_world.ludic (377, reflection world table, tick helpers, @main synthesis)
emit_expr.ludic (654) emit_expr.ludic (189, operators/binary/coercion) + emit_call.ludic (466, namespaced builtins, call lowering, expr dispatch)
emit_text.ludic (558) emit_text.ludic (137, Text.* dispatch) + emit_text_prelude.ludic (422, emitted string-builder runtime)

Build/tooling updated: the FRAGS list in tools/x/selfhost.ludic now points at the new paths (link order preserved), and the Python doc/vocabulary tooling (check-vocabulary.py, docgen/check-impl.py, palette.py) walks the new layout.

Byte-identity held — the build is a plain in-order concatenation and every split lands on a blank-line boundary, so nothing about the emitted IR changed:

  • x reseed leaves selfhost/ludicc.seed.ll byte-for-byte unchanged
  • x bootstrap-cfree still reaches its fixed point (out.ll == seed.ll, no C compiler)
  • x test → 56 passed, 0 failed
  • x selfhost-test → 29 passed, 0 failed (incl. the golden renders)

All three acceptance criteria met: organised into concern-based subdirectories; no file mixes unrelated responsibilities (oversized emitters split); FRAGS/build updated with the full bootstrap + tests still passing byte-identical.

Done in 23726af (pushed to `main`). **New layout** — `selfhost/` went from 38 flat files to concern-based subdirectories: ``` selfhost/ frontend/ lex, parse, parse_game, ast support/ str, buf, io backend/ core IR + expression/statement lowering backend/game/ ECS / scene / event / world lowering backend/stdlib/ the namespaced Math.* / Text.* / Crypto.* / … intrinsics main.ludic (driver, kept at the root) ``` **Oversized emitters split** at responsibility boundaries so no file mixes concerns: | was | now (764/654/558 → …) | |---|---| | `emit_game.ludic` (764) | `emit_game.ludic` (388, systems/scenes/events) + `emit_world.ludic` (377, reflection world table, tick helpers, `@main` synthesis) | | `emit_expr.ludic` (654) | `emit_expr.ludic` (189, operators/binary/coercion) + `emit_call.ludic` (466, namespaced builtins, call lowering, expr dispatch) | | `emit_text.ludic` (558) | `emit_text.ludic` (137, `Text.*` dispatch) + `emit_text_prelude.ludic` (422, emitted string-builder runtime) | **Build/tooling updated:** the `FRAGS` list in `tools/x/selfhost.ludic` now points at the new paths (link order preserved), and the Python doc/vocabulary tooling (`check-vocabulary.py`, `docgen/check-impl.py`, `palette.py`) walks the new layout. **Byte-identity held** — the build is a plain in-order concatenation and every split lands on a blank-line boundary, so nothing about the emitted IR changed: - `x reseed` leaves `selfhost/ludicc.seed.ll` **byte-for-byte unchanged** - `x bootstrap-cfree` still reaches its fixed point (`out.ll == seed.ll`, no C compiler) - `x test` → **56 passed, 0 failed** - `x selfhost-test` → **29 passed, 0 failed** (incl. the golden renders) All three acceptance criteria met: organised into concern-based subdirectories; no file mixes unrelated responsibilities (oversized emitters split); `FRAGS`/build updated with the full bootstrap + tests still passing byte-identical.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: workshopsoft/ludic#29
No description provided.