Split the flat 38-file selfhost/ into concern-based subdirectories:
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
and split the three oversized emitters at responsibility boundaries so
no file mixes concerns:
emit_game.ludic -> + emit_world.ludic (reflection world table,
tick helpers, @main synthesis)
emit_expr.ludic -> + emit_call.ludic (namespaced builtins, call
lowering, expr dispatch)
emit_text.ludic -> + emit_text_prelude.ludic (emitted string-builder runtime)
FRAGS in tools/x/selfhost.ludic is updated to the new paths with the link
order preserved, and the Python doc/vocabulary tooling is updated to walk
the new layout. Because the build is a plain in-order concatenation and
every split lands on a blank-line boundary, the regenerated seed is
byte-identical: `x reseed` leaves selfhost/ludicc.seed.ll unchanged,
`x bootstrap-cfree` still reaches its fixed point, and both `x test` (56)
and `x selfhost-test` (29, incl. golden renders) stay green.
Closes#29
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expand the abbreviated pointer types to full words on the language surface:
ptr -> pointer (a raw address / FFI handle)
ptrs -> pointers (a buffer of pointers)
The Ludic type name is distinct from LLVM's own `ptr` spelling: llty() maps
`pointer`/`pointers` to LLVM `ptr`, and the emitted IR keeps `ptr`, so only
the Ludic-level surface changes. Rewrites type annotations across all
sources, the 8 hardcoded pointer type-tags, the `pointers`-buffer indexing
in emit_addr, the grammars/LSP/JetBrains tokens, and the docs
(type-ptr -> type-pointer, type-ptrs -> type-pointers). int/bool keep their
conventional short spelling (like Math).
Reseeded; C-free fixpoint holds; all suites green (45/24/29); site + check.py OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expand the function-declaration keyword to the full word across the whole
language and toolchain:
fn name(...) -> T { ... } -> function name(...) -> T { ... }
Done as a self-hosting migration: teach the parser both spellings, reseed,
rewrite every .ludic definition to `function`, then drop `fn`. The compiler
now rejects `fn`. Touches the parser, all selfhost/tools/runtime/example/test
sources, the grammars (TextMate shared+vscode, ludic_syntax.h, JetBrains
LudicTokens.kt), the LSP and formatter, the Python doc/vocab tools
(check-impl, check-docs, validate, palette, test-lsp), and the docs
(fences, prose, kw-fn -> kw-function).
Reseeded; C-free bootstrap fixpoint holds. All suites green (45 regression,
24 self-host, 29 tool); the docs site generates and check.py passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Finish the unblocked "Math / Ease" half of #25: the fixed-point
transcendentals deferred from #2. Vec.* stays blocked on the vec2 type
in #1.
- Math.exp, Math.log (natural), Math.pow — deterministic Q16.16 via two
new prelude fns in emit_math_prelude: @fn_fx_exp2 (range-reduced 5th-order
Taylor 2^f, then a clamped shift by the integer part) and @fn_fx_log2
(llvm.ctlz for the exponent + an atanh series on (m-1)/(m+1) for the
mantissa). exp=2^(x·log2 e), log=log2(x)·ln2, pow=2^(b·log2 a).
- Ease.elastic — ease-out elastic 2^(-10t)·sin((10t-0.75)·2pi/3)+1.
- Pure integer IR, so bit-identical on every platform. Results must fit the
Q16.16 range (|x| < 32768); larger magnitudes saturate (documented).
Test selfhost/tests/transcend.ludic (registered in the self-host suite) +
docs for all four. Reseeded; the C-free bootstrap fixpoint holds. All suites
green (24 self-host, 45 regression, 29 tool).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implement the bulk of the namespaced-stdlib proposal (workshopsoft/ludic#2):
156 namespace methods across Math, Text, List, Ease, Collide, World, Net,
Sys, Save, Mem, extended Screen, Color functions, extended Random, and Time.
All deterministic fixed-point; self-hosting (C-free bootstrap fixpoint holds).
Compiler (selfhost/):
- Math.*: sqrt/sin/cos/tan/atan2/asin/acos (fixed-point runtime prelude —
bit-by-bit isqrt, 256-entry interpolated sine table, Ross atan2), plus
hypot/dist/dist2/deg_to_rad/rad_to_deg/posmod/wrap/ping_pong/snapped/
move_toward/smoothstep/lerp/remap/sign/floor/ceil/round.
- Text.* (complete): upper/lower/trim/repeat/pad, split/join/replace,
and the libc-backed queries.
- List.* (complete): insert/remove_at/remove/sort plus the earlier ops.
- Ease.* (in/out/in_out/back/bounce) and Collide.* (rects/point_rect/
circles/rect_circle).
- Phase 3: World/Net/Sys/Save namespaced over the bare builtins (byte-
identical IR) and Mem.* (bytes/words/copy/fill/peek/poke).
- Screen.* extended (line/circle/fill_circle/triangle/fill_triangle via new
runtime primitives; sprite/sprite_scaled aliases), Color.* functions,
Random.* (value/int/sign), Time.* (frame/delta/elapsed/now — new
game-loop frame counter).
- Fix a lexer bug: fixed-point literals with >4 fractional digits overflowed.
Docs & tooling:
- 129 new per-symbol doc pages; gen.py made data-driven (namespaces
discovered from the docs, no hardcoded list); new check-impl.py enforces
that every implemented namespace method / keyword / type / phase has a
doc page, wired into `x test-tools`. Document the previously-undocumented
keywords (break/continue/where/entry/new/public + and/or/not tokens).
- LSP: namespaced signature help (ns_method_sig) covering every namespace.
Tests: 12 new self-host/regression tests + a golden render for the drawing
primitives. All suites green (selfhost 21, regression 45, tools 29).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>