Phase 7g: the compiler builds its IR with interpolation, not +

Answering your readability point directly: the compiler's own string-building —
left uglier by the 7c `+` migration, e.g. `emit_bind(("load i32, ptr " + ip))` —
now reads as interpolation:

  emit_bind(("load i32, ptr " + ip))            -> emit_bind(`load i32, ptr {ip}`)
  emit_bind(("icmp eq i32 " + (kv + (", " + itoa(ak)))))
                                                -> emit_bind(`icmp eq i32 {kv}, {itoa(ak)}`)
  perr(("assign to unknown " + t.s))            -> perr(`assign to unknown {t.s}`)

164 concat chains across selfhost converted by a tool that flattens the `+` tree,
keeps call/index parens (only grouping parens are rewritten), and converts only
**brace-free** literals — LLVM IR structure strings full of `{`/`}` stay as `+`
rather than becoming awkward `{{`/`}}`. No new language surface; interpolation
already desugars to the same concat.

Reseeded (22565 lines); C-free fixpoint holds byte-for-byte (the strongest proof
the reconstruction is exact); goldens identical; 18/18.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-08-28 01:30:37 +03:00
parent 4faf91abdc
commit df6955e609
20 changed files with 566 additions and 566 deletions

View file

@ -27,9 +27,9 @@ fn emit_ecs_storage() -> void {
emith("@L_key = internal global i32 0\n")
emith("@L_entc = internal global i32 0\n")
let me = itoa(MAX_ENT)
emith(("@L_alive = internal global [" + (me + " x i32] zeroinitializer\n")))
emith(("@L_kind = internal global [" + (me + " x i32] zeroinitializer\n")))
emith(("@L_freelist = internal global [" + (me + " x i32] zeroinitializer\n")))
emith(`@L_alive = internal global [{me} x i32] zeroinitializer\n`)
emith(`@L_kind = internal global [{me} x i32] zeroinitializer\n`)
emith(`@L_freelist = internal global [{me} x i32] zeroinitializer\n`)
emith("@L_freen = internal global i32 0\n")
var i = 0
while i < len(prog) {
@ -38,12 +38,12 @@ fn emit_ecs_storage() -> void {
# header). Every property in an ECS program is a component today; a property
# used only via `new` would not need these, but no such program mixes the two.
if c.kind == N_COMP {
emith(("@S_" + (c.s + (" = internal global [" + (me + ((" x %Cmp_") + (c.s + "] zeroinitializer\n")))))))
emith(("@H_" + (c.s + (" = internal global [" + (me + " x i8] zeroinitializer\n")))))
emith(`@S_{c.s} = internal global [{me} x %Cmp_{c.s}] zeroinitializer\n`)
emith(`@H_{c.s} = internal global [{me} x i8] zeroinitializer\n`)
}
# one enabled-flag global per model and per handler (default enabled)
if c.kind == N_ARCH { emith(("@ME_" + (c.s + " = internal global i32 1\n"))) }
if c.kind == N_SYS { emith(("@HE_" + (c.s + " = internal global i32 1\n"))) }
if c.kind == N_ARCH { emith(`@ME_{c.s} = internal global i32 1\n`) }
if c.kind == N_SYS { emith(`@HE_{c.s} = internal global i32 1\n`) }
i = i + 1
}
}
@ -55,7 +55,7 @@ fn emit_ecs_allocator() -> void {
var i = 0
while i < len(prog) {
if prog[i].kind == N_COMP {
let hn = (("%h") + itoa(i))
let hn = `%h{itoa(i)}`
emit(" "); emit(hn); emit(" = getelementptr inbounds ["); emit(me); emit(" x i8], ptr @H_"); emit(prog[i].s); emit(", i32 0, i32 %e\n")
emit(" store i8 0, ptr "); emit(hn); emit("\n")
}