ludic/selfhost/buf.ludic
Orkuncakilkaya 86948d2b19 Phase 7k: bytes(n) / words(n) allocators (retire mem_alloc)
Allocation reads as intent, not malloc:

  mem_alloc(64)          -> bytes(64)              (64 bytes -> a byte buffer)
  mem_alloc(w * h * 4)   -> words(w * h)           (w*h 32-bit words)

bytes(n) mallocs n bytes and returns a plain pointer (byte-indexed); words(n)
mallocs n*4 bytes and returns a `words` pointer (int-indexed). Since words(X) and
mem_alloc(X*4) allocate the identical number of bytes, the migration cannot change
any allocation size — the `* 4` factor just moves from the argument into the
allocator name, pairing naturally with the Phase-7j `words` retyping
(`var fb: words = words(w * h)`).

Migrated 102 sites (mem_alloc(E*4) -> words(E), else bytes(E)); deleted the
mem_alloc intrinsic. mem_realloc/free/copy/set stay as the low-level
reallocation/free family. Reseeded (22565 lines); C-free fixpoint holds; goldens
byte-identical; 18/18; vocab + doc-fences clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 02:26:15 +03:00

29 lines
894 B
Text

# buf.ludic — a growable byte buffer for building IR text. The emitter writes
# module-level material (types, globals, string constants) into one buffer and
# function bodies into another, then prints them in order.
property Buf { data: ptr = null, len: int = 0, cap: int = 0 }
fn buf_new() -> Buf {
let b = new Buf
b.cap = 256
b.data = bytes(b.cap)
b.len = 0
return b
}
fn buf_ensure(b: Buf, extra: int) -> void {
if b.len + extra + 1 <= b.cap { return }
while b.len + extra + 1 > b.cap { b.cap = b.cap * 2 }
b.data = mem_realloc(b.data, b.cap)
}
fn buf_putc(b: Buf, c: int) -> void {
buf_ensure(b, 1)
b.data[b.len] = c
b.len = b.len + 1
}
fn buf_puts(b: Buf, s: ptr) -> void {
var i = 0
while s[i] != 0 { buf_putc(b, s[i]); i = i + 1 }
}
fn buf_puti(b: Buf, n: int) -> void { buf_puts(b, itoa(n)) }
fn buf_str(b: Buf) -> ptr { b.data[b.len] = 0; return b.data }