Baseline: Ludic compiler + toolchain, Phase 1 syntax fixes complete

Self-hosted compiler (selfhost/*.ludic), runtime, examples, editor tooling,
and docs. Phase 1 of the syntax-redesign cohesion pass has landed:
edge-system fix, signature-query, when-alias, and the documentation truth-pass.
Suite green (14/14), C-free bootstrap fixpoint holds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-08-27 15:15:35 +03:00
commit 985f9ad8f2
418 changed files with 39065 additions and 0 deletions

88
selfhost/emit_new.ludic Normal file
View file

@ -0,0 +1,88 @@
# emit_new.ludic — heap construction and slice operations: `new S`, `new []T`,
# push(slice, v) and len(slice). Slices are a { data, len, cap } header the
# holder points at, so growth is visible to every holder.
fn emit_sizeof(llt: ptr) -> ptr {
let p = emit_bind(sconcat("getelementptr ", sconcat(llt, ", ptr null, i32 1")))
return emit_bind(sconcat("ptrtoint ptr ", sconcat(p, " to i64")))
}
fn emit_new_struct(name: ptr) -> Val {
let s = find_struct(name)
if ptr_is_null(s) { perr("unknown struct in new") }
let sz = emit_sizeof(sconcat("%Str_", name))
let obj = emit_bind(sconcat("call ptr @malloc(i64 ", sconcat(sz, ")")))
let f = 0
while f < len(s.kids) {
let fd = s.kids[f]
let addr = nreg()
emit(" ") emit(addr) emit(" = getelementptr inbounds %Str_") emit(name)
emit(", ptr ") emit(obj) emit(", i32 0, i32 ") emit(itoa(f)) emit("\n")
let lt = llty(fd.ty)
let v = "0"
if streq(lt, "ptr") { v = "null" }
if not ptr_is_null(fd.a) { let dv = emit_expr(fd.a) v = dv.code }
emit(" store ") emit(lt) emit(" ") emit(v) emit(", ptr ") emit(addr) emit("\n")
f = f + 1
}
return val(obj, name)
}
fn emit_new_slice(ty: ptr) -> Val {
let sz = emit_sizeof("%LSlice")
let h = emit_bind(sconcat("call ptr @malloc(i64 ", sconcat(sz, ")")))
let d0 = nreg() emit(" ") emit(d0) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h) emit(", i32 0, i32 0\n")
emit(" store ptr null, ptr ") emit(d0) emit("\n")
let d1 = nreg() emit(" ") emit(d1) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h) emit(", i32 0, i32 1\n")
emit(" store i32 0, ptr ") emit(d1) emit("\n")
let d2 = nreg() emit(" ") emit(d2) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h) emit(", i32 0, i32 2\n")
emit(" store i32 0, ptr ") emit(d2) emit("\n")
return val(h, ty)
}
fn slice_field(h: ptr, i: int) -> ptr {
let r = nreg()
emit(" ") emit(r) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h)
emit(", i32 0, i32 ") emit(itoa(i)) emit("\n")
return r
}
fn emit_len(e: Node) -> Val {
let s = emit_expr(e.kids[0])
let lp = slice_field(s.code, 1)
return val(emit_bind(sconcat("load i32, ptr ", lp)), "int")
}
fn emit_push(e: Node) -> Val {
let s = emit_expr(e.kids[0])
let el = slice_elem(s.ty)
let elt = llty(el)
let h = s.code
let lp = slice_field(h, 1) let cp = slice_field(h, 2) let dp = slice_field(h, 0)
let l = emit_bind(sconcat("load i32, ptr ", lp))
let c = emit_bind(sconcat("load i32, ptr ", cp))
let full = emit_bind(sconcat("icmp sge i32 ", sconcat(l, sconcat(", ", c))))
let grow = lbl("grow") let put = lbl("put")
emit(" br i1 ") emit(full) emit(", label %") emit(grow) emit(", label %") emit(put) emit("\n")
emit(grow) emit(":\n")
let dbl = emit_bind(sconcat("mul i32 ", sconcat(c, ", 2")))
let isz = emit_bind(sconcat("icmp eq i32 ", sconcat(c, ", 0")))
let nc = emit_bind(sconcat("select i1 ", sconcat(isz, sconcat(", i32 8, i32 ", dbl))))
let esz = emit_sizeof(elt)
let ncw = emit_bind(sconcat("zext i32 ", sconcat(nc, " to i64")))
let bytes = emit_bind(sconcat("mul i64 ", sconcat(ncw, sconcat(", ", esz))))
let old = emit_bind(sconcat("load ptr, ptr ", dp))
let nd = emit_bind(sconcat("call ptr @realloc(ptr ", sconcat(old, sconcat(", i64 ", sconcat(bytes, ")")))))
emit(" store ptr ") emit(nd) emit(", ptr ") emit(dp) emit("\n")
emit(" store i32 ") emit(nc) emit(", ptr ") emit(cp) emit("\n")
emit(" br label %") emit(put) emit("\n")
emit(put) emit(":\n")
let v = emit_expr(e.kids[1])
let data = emit_bind(sconcat("load ptr, ptr ", dp))
let slot = nreg()
emit(" ") emit(slot) emit(" = getelementptr inbounds ") emit(elt) emit(", ptr ") emit(data) emit(", i32 ") emit(l) emit("\n")
emit(" store ") emit(elt) emit(" ") emit(v.code) emit(", ptr ") emit(slot) emit("\n")
let l1 = emit_bind(sconcat("add i32 ", sconcat(l, ", 1")))
emit(" store i32 ") emit(l1) emit(", ptr ") emit(lp) emit("\n")
return val("0", "void")
}