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

@ -1,12 +1,12 @@
game T {
fn fib(n: int) -> int { if n < 2 { return n } return fib(n-1) + fib(n-2) }
fn fib(n: int) -> int { if n < 2 { return n }; return fib(n-1) + fib(n-2) }
main {
print_int(fib(10)) # 55
let s = 0
for i in 0 .. 10 { if i == 5 { break } if i % 2 == 0 { continue } s = s + i }
for i in 0 .. 10 { if i == 5 { break }; if i % 2 == 0 { continue }; s = s + i }
print_int(s) # 1+3 = 4
let i = 0 let t = 0
while true { i = i + 1 if i > 5 { break } t = t + i }
let i = 0; let t = 0
while true { i = i + 1; if i > 5 { break }; t = t + i }
print_int(t) # 15
if false and (1/0 == 0) { print_int(999) } else { print_int(1) } # short-circuit: no div by zero
}

View file

@ -1,6 +1,6 @@
game T {
fn classify(c: int) -> int {
match c { 65, 66 => { return 1 } 67 => { return 2 } _ => { return 9 } }
match c { 65, 66 => { return 1 }; 67 => { return 2 }; _ => { return 9 } }
return 0
}
main {