Phase 2: enforce statement separators (Rule B)

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>
This commit is contained in:
Orkun ÇAKILKAYA 2026-08-27 15:41:29 +03:00
parent 985f9ad8f2
commit eac8f8f335
35 changed files with 3861 additions and 3588 deletions

View file

@ -6,8 +6,8 @@
var g_iok: int = 0
fn emit_io(fn2: ptr, p: ptr, bytes: ptr) -> void {
let r = sconcat("%io", itoa(g_iok)) g_iok = g_iok + 1
emit(" ") emit(r) emit(" = call i64 @") emit(fn2) emit("(ptr ") emit(p) emit(", i64 1, i64 ") emit(bytes) emit(", ptr %f)\n")
let r = sconcat("%io", itoa(g_iok)); g_iok = g_iok + 1
emit(" "); emit(r); emit(" = call i64 @"); emit(fn2); emit("(ptr "); emit(p); emit(", i64 1, i64 "); emit(bytes); emit(", ptr %f)\n")
}
fn emit_snapshot_blocks(fn2: ptr) -> void {
@ -15,19 +15,19 @@ fn emit_snapshot_blocks(fn2: ptr) -> void {
let me = itoa(MAX_ENT)
emit_io(fn2, "@L_entc", "4")
emit_io(fn2, "@L_freen", "4")
emit(" %nalive = mul i64 ") emit(me) emit(", 4\n")
emit(" %nalive = mul i64 "); emit(me); emit(", 4\n")
emit_io(fn2, "@L_alive", "%nalive")
emit_io(fn2, "@L_freelist", "%nalive")
emit_io(fn2, "@L_kind", "%nalive")
let i = 0
while i < len(prog) { if prog[i].kind == N_VAR { emit_io(fn2, sconcat("@g_", prog[i].s), "4") } i = i + 1 }
while i < len(prog) { if prog[i].kind == N_VAR { emit_io(fn2, sconcat("@g_", prog[i].s), "4") }; i = i + 1 }
let ci = 0
i = 0
while i < len(prog) {
if prog[i].kind == N_COMP {
let c = prog[i].s
let csz = sconcat("%csz", itoa(ci))
emit(" ") emit(csz) emit(" = ptrtoint ptr getelementptr (%Cmp_") emit(c) emit(", ptr null, i32 ") emit(me) emit(") to i64\n")
emit(" "); emit(csz); emit(" = ptrtoint ptr getelementptr (%Cmp_"); emit(c); emit(", ptr null, i32 "); emit(me); emit(") to i64\n")
emit_io(fn2, sconcat("@S_", c), csz)
emit_io(fn2, sconcat("@H_", c), me)
ci = ci + 1