Merge Phase 7g: compiler IR uses interpolation

This commit is contained in:
Orkun ÇAKILKAYA 2026-08-28 01:30:37 +03:00
commit 0efa06dca2
20 changed files with 566 additions and 566 deletions

View file

@ -8,9 +8,9 @@ var g_addr_ty: ptr # out-param: the type at the computed address
fn emit_member_addr(e: Node) -> ptr {
let base = emit_expr(e.a)
let s = layout_node(base.ty)
if (s == null) { perr((("member access on non-aggregate ") + base.ty)) }
if (s == null) { perr(`member access on non-aggregate {base.ty}`) }
let fidx = field_index(s, e.s)
if fidx < 0 { perr(("no such field " + e.s)) }
if fidx < 0 { perr(`no such field {e.s}`) }
g_addr_ty = field_type(s, e.s)
let r = nreg()
emit(" "); emit(r); emit(" = getelementptr inbounds "); emit(layout_ty(base.ty))

View file

@ -39,13 +39,13 @@ fn emith(s: ptr) -> void { buf_puts(head, s) }
# stack slots MUST live in the entry block (an alloca in a loop walks the stack
# off its end), so they go into a per-function buffer spliced in at entry.
fn emit_alloca(llt: ptr) -> ptr {
let r = (("%t") + itoa(ll_t)); ll_t = ll_t + 1
let r = `%t{itoa(ll_t)}`; ll_t = ll_t + 1
buf_puts(falloc, " "); buf_puts(falloc, r); buf_puts(falloc, " = alloca "); buf_puts(falloc, llt); buf_puts(falloc, "\n")
return r
}
# "%t<n>" fresh register
fn nreg() -> ptr { let r = (("%t") + itoa(ll_t)); ll_t = ll_t + 1; return r }
fn nreg() -> ptr { let r = `%t{itoa(ll_t)}`; ll_t = ll_t + 1; return r }
fn lbl(pfx: ptr) -> ptr { let r = (pfx + itoa(ll_lbl)); ll_lbl = ll_lbl + 1; return r }
# Ludic type -> LLVM type. int/bool are i32; everything else (ptr/str/struct/
@ -123,12 +123,12 @@ fn find_fn(name: ptr) -> Node {
var g_computed: []Node # each: s = "Prop.field", ty = result type, a = expr
fn register_computed(prop: ptr, field: ptr, ty: ptr, e: Node) -> void {
let cf = node(N_FIELD); cf.s = (prop + ("." + field)); cf.ty = ty; cf.a = e
let cf = node(N_FIELD); cf.s = `{prop}.{field}`; cf.ty = ty; cf.a = e
push(g_computed, cf)
}
fn computed_expr(prop: ptr, field: ptr) -> Node {
if (prop == null) { return null }
let key = (prop + ("." + field))
let key = `{prop}.{field}`
var i = 0
while i < len(g_computed) { if (g_computed[i].s == key) { return g_computed[i].a }; i = i + 1 }
return null

View file

@ -33,7 +33,7 @@ fn emit_fn(d: Node) -> void {
if not g_term { emit(" br label %ret\n") }
emit("ret:\n")
if (rl == "void") { emit(" ret void\n") }
else { let r = emit_bind(("load " + (rl + (", ptr %retval")))); emit(" ret "); emit(rl); emit(" "); emit(r); emit("\n") }
else { let r = emit_bind(`load {rl}, ptr %retval`); emit(" ret "); emit(rl); emit(" "); emit(r); emit("\n") }
code = saved
emit("define "); emit(rl); emit(" @fn_"); emit(d.s); emit("("); emit_params_sig(d); emit(") {\nentry:\n")
emit(buf_str(falloc))

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")
}

View file

@ -1,7 +1,7 @@
# emit_expr.ludic — lower an expression to IR, returning its register and type.
fn emit_load_at(addr: ptr, ty: ptr) -> Val {
let r = emit_bind(("load " + (llty(ty) + (", ptr " + addr))))
let r = emit_bind(`load {llty(ty)}, ptr {addr}`)
return val(r, ty)
}
@ -10,20 +10,20 @@ fn emit_load_at(addr: ptr, ty: ptr) -> Val {
fn emit_logic(e: Node) -> Val {
let slot = emit_alloca("i32")
let la = emit_expr(e.a)
let lc = emit_bind(("icmp ne i32 " + (la.code + ", 0")))
let lz = emit_bind(("zext i1 " + (lc + " to i32")))
let lc = emit_bind(`icmp ne i32 {la.code}, 0`)
let lz = emit_bind(`zext i1 {lc} to i32`)
emit(" store i32 "); emit(lz); emit(", ptr "); emit(slot); emit("\n")
let ev = lbl("sc"); let done = lbl("scend")
if (e.s == "and") { emit(" br i1 "); emit(lc); emit(", label %"); emit(ev); emit(", label %"); emit(done); emit("\n") }
else { emit(" br i1 "); emit(lc); emit(", label %"); emit(done); emit(", label %"); emit(ev); emit("\n") }
emit(ev); emit(":\n")
let rb = emit_expr(e.b)
let rc = emit_bind(("icmp ne i32 " + (rb.code + ", 0")))
let rz = emit_bind(("zext i1 " + (rc + " to i32")))
let rc = emit_bind(`icmp ne i32 {rb.code}, 0`)
let rz = emit_bind(`zext i1 {rc} to i32`)
emit(" store i32 "); emit(rz); emit(", ptr "); emit(slot); emit("\n")
emit(" br label %"); emit(done); emit("\n")
emit(done); emit(":\n")
return val(emit_bind(("load i32, ptr " + slot)), "bool")
return val(emit_bind(`load i32, ptr {slot}`), "bool")
}
fn cmp_code(op: ptr) -> ptr {
@ -53,7 +53,7 @@ fn arith_code(op: ptr) -> ptr {
# widen an int value to Q16.16 by shifting left 16 (a fixed value passes through)
fn to_fixed(v: Val) -> ptr {
if (v.ty == "fixed") { return v.code }
return emit_bind(("shl i32 " + (v.code + ", 16")))
return emit_bind(`shl i32 {v.code}, 16`)
}
# string operators: `a + b` concatenates, `a == b` / `a != b` compare by content.
@ -61,12 +61,12 @@ fn to_fixed(v: Val) -> ptr {
fn emit_str_op(op: ptr, a: Val, b: Val) -> Val {
g_uses_str = true
if (op == ("+")) {
return val(emit_bind(("call ptr @fn_str_concat(ptr " + (a.code + (", ptr " + (b.code + ")"))))), "str")
return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "str")
}
let r = emit_bind(("call i32 @fn_str_eq(ptr " + (a.code + (", ptr " + (b.code + ")")))))
let r = emit_bind(`call i32 @fn_str_eq(ptr {a.code}, ptr {b.code})`)
if (op == ("!=")) {
let c = emit_bind(("icmp eq i32 " + (r + ", 0")))
return val(emit_bind(("zext i1 " + (c + " to i32"))), "bool")
let c = emit_bind(`icmp eq i32 {r}, 0`)
return val(emit_bind(`zext i1 {c} to i32`), "bool")
}
return val(r, "bool")
}
@ -90,35 +90,35 @@ fn emit_bin(e: Node) -> Val {
var ct = "i32"
if fx { ac = to_fixed(a); bc = to_fixed(b) }
else { if (llty(a.ty) == "ptr") or (llty(b.ty) == "ptr") { ct = "ptr" } } # `p == null`, str/record identity
let c = emit_bind(("icmp " + (cmp_code(e.s) + ((" " + (ct + " ")) + (ac + (", " + bc))))))
return val(emit_bind(("zext i1 " + (c + " to i32"))), "bool")
let c = emit_bind(`icmp {cmp_code(e.s)} {ct} {ac}, {bc}`)
return val(emit_bind(`zext i1 {c} to i32`), "bool")
}
if fx {
let af = to_fixed(a); let bf = to_fixed(b)
if (e.s == ("*")) {
let a64 = emit_bind(("sext i32 " + (af + " to i64")))
let b64 = emit_bind(("sext i32 " + (bf + " to i64")))
let m = emit_bind(("mul i64 " + (a64 + (", " + b64))))
let sh = emit_bind(("ashr i64 " + (m + ", 16")))
return val(emit_bind(("trunc i64 " + (sh + " to i32"))), "fixed")
let a64 = emit_bind(`sext i32 {af} to i64`)
let b64 = emit_bind(`sext i32 {bf} to i64`)
let m = emit_bind(`mul i64 {a64}, {b64}`)
let sh = emit_bind(`ashr i64 {m}, 16`)
return val(emit_bind(`trunc i64 {sh} to i32`), "fixed")
}
if (e.s == ("/")) {
let a64 = emit_bind(("sext i32 " + (af + " to i64")))
let ash = emit_bind(("shl i64 " + (a64 + ", 16")))
let b64 = emit_bind(("sext i32 " + (bf + " to i64")))
let dv = emit_bind(("sdiv i64 " + (ash + (", " + b64))))
return val(emit_bind(("trunc i64 " + (dv + " to i32"))), "fixed")
let a64 = emit_bind(`sext i32 {af} to i64`)
let ash = emit_bind(`shl i64 {a64}, 16`)
let b64 = emit_bind(`sext i32 {bf} to i64`)
let dv = emit_bind(`sdiv i64 {ash}, {b64}`)
return val(emit_bind(`trunc i64 {dv} to i32`), "fixed")
}
let r = emit_bind((arith_code(e.s) + (" i32 " + (af + (", " + bf)))))
let r = emit_bind(`{arith_code(e.s)} i32 {af}, {bf}`)
return val(r, "fixed")
}
let r = emit_bind((arith_code(e.s) + (" i32 " + (a.code + (", " + b.code)))))
let r = emit_bind(`{arith_code(e.s)} i32 {a.code}, {b.code}`)
return val(r, "int")
}
fn emit_call(e: Node) -> Val {
let name = e.a.s
if (name == "self") { if nself == 0 { return val("0", "entity") }; return val(emit_bind(("load i32, ptr " + self_stk[nself - 1])), "entity") }
if (name == "self") { if nself == 0 { return val("0", "entity") }; return val(emit_bind(`load i32, ptr {self_stk[nself - 1]}`), "entity") }
if (name == "key") { return val(emit_bind("load i32, ptr @L_key"), "int") }
if (name == "save") { emit(" call void @L_save()\n"); return val("0", "void") }
if (name == "ui_build") { emit(" call void @ui_build()\n"); return val("0", "void") }
@ -130,16 +130,16 @@ fn emit_call(e: Node) -> Val {
let a = emit_expr(e.kids[0])
if (llty(a.ty) == "ptr") { return a }
g_uses_intstr = true
return val(emit_bind(("call ptr @fn_int_str(i32 " + (a.code + ")"))), "str")
return val(emit_bind(`call ptr @fn_int_str(i32 {a.code})`), "str")
}
if (name == "print") { # print(x): a value + newline (int or string)
let a = emit_expr(e.kids[0])
if (llty(a.ty) == "ptr") { emit(" call i32 (ptr, ...) @printf(ptr @.fmt_line, ptr " + (a.code + ")\n")) }
else { emit(" call i32 (ptr, ...) @printf(ptr @.fmt_int, i32 " + (a.code + ")\n")) }
if (llty(a.ty) == "ptr") { emit(" call i32 (ptr, ...) @printf(ptr @.fmt_line, ptr " + `{a.code})\n`) }
else { emit(" call i32 (ptr, ...) @printf(ptr @.fmt_int, i32 " + `{a.code})\n`) }
return val("0", "void")
}
if (name == "fx") { let a = emit_expr(e.kids[0]); return val(emit_bind(("shl i32 " + (a.code + ", 16"))), "fixed") }
if (name == "flr") { let a = emit_expr(e.kids[0]); return val(emit_bind(("ashr i32 " + (a.code + ", 16"))), "int") }
if (name == "fx") { let a = emit_expr(e.kids[0]); return val(emit_bind(`shl i32 {a.code}, 16`), "fixed") }
if (name == "flr") { let a = emit_expr(e.kids[0]); return val(emit_bind(`ashr i32 {a.code}, 16`), "int") }
if is_intrinsic(name) { return emit_intrinsic(name, e) }
if is_intrinsic2(name) { return emit_intrinsic2(name, e) }
if is_math_builtin(name) { return emit_math_builtin(name, e) }
@ -147,9 +147,9 @@ fn emit_call(e: Node) -> Val {
var cname = name
if (fn2 == null) {
# a builtin like clear()/reg() is satisfied by its rt_ function
let rtname = ("rt_" + name)
let rtname = `rt_{name}`
fn2 = find_fn(rtname)
if (fn2 == null) { perr(("unknown function " + name)) }
if (fn2 == null) { perr(`unknown function {name}`) }
cname = rtname
}
# evaluate args first (their IR is emitted before the call instruction)
@ -189,12 +189,12 @@ fn emit_expr(e: Node) -> Val {
let g = find_global(e.s)
if (g != null) {
if g.kind == N_CONST { return val(itoa(g.a.ival), "int") }
let r = emit_bind(("load " + (llty(g.ty) + (", ptr @g_" + e.s))))
let r = emit_bind(`load {llty(g.ty)}, ptr @g_{e.s}`)
return val(r, g.ty)
}
# a UI_<name> that is not a const/var resolves to its widget index
if is_ui_ident(e.s) { return val(itoa(ui_index_of(e.s)), "int") }
perr(("unknown identifier " + e.s))
perr(`unknown identifier {e.s}`)
}
if e.kind == E_MEMBER {
if e.a.kind == E_ID { # `Enum.Variant` -> its ordinal, a compile-time int
@ -213,10 +213,10 @@ fn emit_expr(e: Node) -> Val {
if e.kind == E_BIN { return emit_bin(e) }
if e.kind == E_UN {
let a = emit_expr(e.a)
if (e.s == ("-")) { return val(emit_bind(("sub i32 0, " + a.code)), "int") }
if (e.s == "~") { return val(emit_bind(("xor i32 " + (a.code + (", -1")))), "int") }
let c = emit_bind(("icmp eq i32 " + (a.code + ", 0")))
return val(emit_bind(("zext i1 " + (c + " to i32"))), "bool")
if (e.s == ("-")) { return val(emit_bind(`sub i32 0, {a.code}`), "int") }
if (e.s == "~") { return val(emit_bind(`xor i32 {a.code}, -1`), "int") }
let c = emit_bind(`icmp eq i32 {a.code}, 0`)
return val(emit_bind(`zext i1 {c} to i32`), "bool")
}
perr("cannot emit expression")
return val("0", "int")

View file

@ -25,8 +25,8 @@ fn emit_calls_for_phase(phase: ptr) -> void {
while i < len(prog) {
let d = prog[i]
if d.kind == N_SYS and (d.ty == phase) { # skip a disabled handler
let he = emit_bind(("load i32, ptr @HE_" + d.s))
let hc = emit_bind(("icmp ne i32 " + (he + ", 0")))
let he = emit_bind(`load i32, ptr @HE_{d.s}`)
let hc = emit_bind(`icmp ne i32 {he}, 0`)
let run = lbl("hrun"); let skip = lbl("hskip")
emit(" br i1 "); emit(hc); emit(", label %"); emit(run); emit(", label %"); emit(skip); emit("\n")
emit(run); emit(":\n call void @sys_"); emit(d.s); emit("()\n")
@ -76,11 +76,11 @@ fn emit_game_main() -> void {
emit(" br label %loop\n")
emit("loop:\n")
let r = emit_bind("load i32, ptr @L_running")
let rc = emit_bind(("icmp ne i32 " + (r + ", 0")))
let rc = emit_bind(`icmp ne i32 {r}, 0`)
if (find_fn("rt_running") != null) {
let pr = emit_bind("call i32 @fn_rt_running()")
let pc = emit_bind(("icmp ne i32 " + (pr + ", 0")))
let go = emit_bind(("and i1 " + (rc + (", " + pc))))
let pc = emit_bind(`icmp ne i32 {pr}, 0`)
let go = emit_bind(`and i1 {rc}, {pc}`)
emit(" br i1 "); emit(go); emit(", label %body, label %done\n")
} else {
emit(" br i1 "); emit(rc); emit(", label %body, label %done\n")

View file

@ -5,7 +5,7 @@ fn hexdig(n: int) -> int { if n < 10 { return 48 + n }; return 55 + n } # 0-9
# emit `@.strN = ... c"escaped\00"` and return its name; % and non-print -> \XX
fn emit_str_const(s: ptr) -> ptr {
let name = ("@.str" + itoa(ll_str))
let name = `@.str{itoa(ll_str)}`
ll_str = ll_str + 1
let n = len(s)
emith(name); emith(" = private unnamed_addr constant [")

View file

@ -27,48 +27,48 @@ fn emit_intrinsic(name: ptr, e: Node) -> Val {
# ptr_null / ptr_is_null are the `null` literal and `x == null` now.
if (name == "mem_alloc") {
let n = arg_code(e, 0)
let w = emit_bind(("zext i32 " + (n + " to i64")))
return val(emit_bind(("call ptr @malloc(i64 " + (w + ")"))), "ptr")
let w = emit_bind(`zext i32 {n} to i64`)
return val(emit_bind(`call ptr @malloc(i64 {w})`), "ptr")
}
if (name == "mem_realloc") {
let p = arg_code(e, 0); let n = arg_code(e, 1)
let w = emit_bind(("zext i32 " + (n + " to i64")))
return val(emit_bind(("call ptr @realloc(ptr " + (p + (", i64 " + (w + ")"))))), "ptr")
let w = emit_bind(`zext i32 {n} to i64`)
return val(emit_bind(`call ptr @realloc(ptr {p}, i64 {w})`), "ptr")
}
if (name == "peek8") {
let p = arg_code(e, 0); let i = arg_code(e, 1)
let a = emit_gep_i8(p, i)
let b = emit_bind(("load i8, ptr " + a))
return val(emit_bind(("zext i8 " + (b + " to i32"))), "int")
let b = emit_bind(`load i8, ptr {a}`)
return val(emit_bind(`zext i8 {b} to i32`), "int")
}
if (name == "poke8") {
let p = arg_code(e, 0); let i = arg_code(e, 1); let v = arg_code(e, 2)
let a = emit_gep_i8(p, i)
let t = emit_bind(("trunc i32 " + (v + " to i8")))
let t = emit_bind(`trunc i32 {v} to i8`)
emit(" store i8 "); emit(t); emit(", ptr "); emit(a); emit("\n")
return val("0", "void")
}
if (name == "file_open") {
let p = arg_code(e, 0); let m = arg_code(e, 1)
return val(emit_bind(("call ptr @fopen(ptr " + (p + (", ptr " + (m + ")"))))), "ptr")
return val(emit_bind(`call ptr @fopen(ptr {p}, ptr {m})`), "ptr")
}
if (name == "file_read") or (name == "file_write") {
let f = arg_code(e, 0); let b = arg_code(e, 1); let n = arg_code(e, 2)
let w = emit_bind(("zext i32 " + (n + " to i64")))
let w = emit_bind(`zext i32 {n} to i64`)
var fn2 = "@fread"
if (name == "file_write") { fn2 = "@fwrite" }
let r = emit_bind(("call i64 " + (fn2 + ("(ptr " + (b + (", i64 1, i64 " + (w + (", ptr " + (f + ")")))))))))
return val(emit_bind(("trunc i64 " + (r + " to i32"))), "int")
let r = emit_bind(`call i64 {fn2}(ptr {b}, i64 1, i64 {w}, ptr {f})`)
return val(emit_bind(`trunc i64 {r} to i32`), "int")
}
if (name == "file_seek") {
let f = arg_code(e, 0); let off = arg_code(e, 1); let wh = arg_code(e, 2)
let o = emit_bind(("sext i32 " + (off + " to i64")))
return val(emit_bind(("call i32 @fseek(ptr " + (f + (", i64 " + (o + (", i32 " + (wh + ")"))))))), "int")
let o = emit_bind(`sext i32 {off} to i64`)
return val(emit_bind(`call i32 @fseek(ptr {f}, i64 {o}, i32 {wh})`), "int")
}
if (name == "file_tell") {
let f = arg_code(e, 0)
let r = emit_bind(("call i64 @ftell(ptr " + (f + ")")))
return val(emit_bind(("trunc i64 " + (r + " to i32"))), "int")
let r = emit_bind(`call i64 @ftell(ptr {f})`)
return val(emit_bind(`trunc i64 {r} to i32`), "int")
}
if (name == "file_close") {
let f = arg_code(e, 0)
@ -80,8 +80,8 @@ fn emit_intrinsic(name: ptr, e: Node) -> Val {
if (name == "os_arg") {
let i = arg_code(e, 0)
let v = emit_bind("load ptr, ptr @L_argv")
let q = emit_bind(("getelementptr ptr, ptr " + (v + (", i32 " + i))))
return val(emit_bind(("load ptr, ptr " + q)), "str")
let q = emit_bind(`getelementptr ptr, ptr {v}, i32 {i}`)
return val(emit_bind(`load ptr, ptr {q}`), "str")
}
if (name == "os_exit") {
let n = arg_code(e, 0)
@ -94,18 +94,18 @@ fn emit_intrinsic(name: ptr, e: Node) -> Val {
if (name == "file_stdout") { return val(emit_bind("load ptr, ptr @__stdoutp"), "ptr") }
if (name == "os_system") {
let c = arg_code(e, 0)
return val(emit_bind(("call i32 @system(ptr " + (c + ")"))), "int")
return val(emit_bind(`call i32 @system(ptr {c})`), "int")
}
if (name == "os_getenv") {
let n = arg_code(e, 0)
return val(emit_bind(("call ptr @getenv(ptr " + (n + ")"))), "str")
return val(emit_bind(`call ptr @getenv(ptr {n})`), "str")
}
# bitwise ops are the operators & | ^ << >> ~ now (see emit_bin / p_mul).
if (name == "peek32") {
let p = arg_code(e, 0); let i = arg_code(e, 1)
let g = nreg()
emit(" "); emit(g); emit(" = getelementptr inbounds i32, ptr "); emit(p); emit(", i32 "); emit(i); emit("\n")
return val(emit_bind(("load i32, ptr " + g)), "int")
return val(emit_bind(`load i32, ptr {g}`), "int")
}
if (name == "poke32") {
let p = arg_code(e, 0); let i = arg_code(e, 1); let v = arg_code(e, 2)

View file

@ -22,13 +22,13 @@ fn emit_intrinsic2(name: ptr, e: Node) -> Val {
}
if (name == "mem_copy") {
let d = arg_code(e, 0); let s = arg_code(e, 1); let n = arg_code(e, 2)
let w = emit_bind(("zext i32 " + (n + " to i64")))
let w = emit_bind(`zext i32 {n} to i64`)
emit(" call ptr @memcpy(ptr "); emit(d); emit(", ptr "); emit(s); emit(", i64 "); emit(w); emit(")\n")
return val("0", "void")
}
if (name == "mem_set") {
let p = arg_code(e, 0); let v = arg_code(e, 1); let n = arg_code(e, 2)
let w = emit_bind(("zext i32 " + (n + " to i64")))
let w = emit_bind(`zext i32 {n} to i64`)
emit(" call ptr @memset(ptr "); emit(p); emit(", i32 "); emit(v); emit(", i64 "); emit(w); emit(")\n")
return val("0", "void")
}
@ -44,17 +44,17 @@ fn emit_intrinsic2(name: ptr, e: Node) -> Val {
}
if (name == "str_len") {
let s = arg_code(e, 0)
let r = emit_bind(("call i64 @strlen(ptr " + (s + ")")))
return val(emit_bind(("trunc i64 " + (r + " to i32"))), "int")
let r = emit_bind(`call i64 @strlen(ptr {s})`)
return val(emit_bind(`trunc i64 {r} to i32`), "int")
}
if (name == "os_time") {
let r = emit_bind("call i64 @time(ptr null)")
return val(emit_bind(("trunc i64 " + (r + " to i32"))), "int")
return val(emit_bind(`trunc i64 {r} to i32`), "int")
}
if (name == "peekf") {
let p = arg_code(e, 0); let i = arg_code(e, 1)
let g = nreg(); emit(" "); emit(g); emit(" = getelementptr inbounds i32, ptr "); emit(p); emit(", i32 "); emit(i); emit("\n")
return val(emit_bind(("load i32, ptr " + g)), "fixed")
return val(emit_bind(`load i32, ptr {g}`), "fixed")
}
if (name == "pokef") {
let p = arg_code(e, 0); let i = arg_code(e, 1); let v = arg_code(e, 2)
@ -65,7 +65,7 @@ fn emit_intrinsic2(name: ptr, e: Node) -> Val {
if (name == "peekp") {
let p = arg_code(e, 0); let i = arg_code(e, 1)
let g = nreg(); emit(" "); emit(g); emit(" = getelementptr inbounds ptr, ptr "); emit(p); emit(", i32 "); emit(i); emit("\n")
return val(emit_bind(("load ptr, ptr " + g)), "ptr")
return val(emit_bind(`load ptr, ptr {g}`), "ptr")
}
if (name == "pokep") {
let p = arg_code(e, 0); let i = arg_code(e, 1); let v = arg_code(e, 2)

View file

@ -4,7 +4,7 @@
fn emit_machine(st: Node) -> void {
let regv = emit_expr(st.a)
let s = emit_bind(("call i32 @fn_rt_reg(i32 " + (regv.code + ")")))
let s = emit_bind(`call i32 @fn_rt_reg(i32 {regv.code})`)
if nmach < len(mach_stk) { mach_stk[nmach] = st } else { push(mach_stk, st) }
nmach = nmach + 1
let endl = lbl("smend")
@ -12,7 +12,7 @@ fn emit_machine(st: Node) -> void {
while i < len(st.kids) {
let state = st.kids[i]
let v = emit_expr(state.b)
let c = emit_bind(("icmp eq i32 " + (s + (", " + v.code))))
let c = emit_bind(`icmp eq i32 {s}, {v.code}`)
let body = lbl("sbody"); let nxt = lbl("sarm")
emit(" br i1 "); emit(c); emit(", label %"); emit(body); emit(", label %"); emit(nxt); emit("\n")
emit(body); emit(":\n"); g_term = false
@ -32,7 +32,7 @@ fn emit_become(st: Node) -> void {
var target: Node = null
var i = 0
while i < len(m.kids) { if (m.kids[i].s == st.s) { target = m.kids[i] }; i = i + 1 }
if (target == null) { perr(("become: no state " + st.s)) }
if (target == null) { perr(`become: no state {st.s}`) }
let regv = emit_expr(m.a)
let sv = emit_expr(target.b)
emit(" call void @fn_rt_set_reg(i32 "); emit(regv.code); emit(", i32 "); emit(sv.code); emit(")\n")

View file

@ -9,21 +9,21 @@ fn is_math_builtin(name: ptr) -> bool {
fn emit_math_builtin(name: ptr, e: Node) -> Val {
if (name == "abs") {
let a = emit_expr(e.kids[0])
let c = emit_bind(("icmp slt i32 " + (a.code + ", 0")))
let n = emit_bind(("sub i32 0, " + a.code))
return val(emit_bind(("select i1 " + (c + (", i32 " + (n + (", i32 " + a.code)))))), "int")
let c = emit_bind(`icmp slt i32 {a.code}, 0`)
let n = emit_bind(`sub i32 0, {a.code}`)
return val(emit_bind(`select i1 {c}, i32 {n}, i32 {a.code}`), "int")
}
if (name == "min") or (name == "max") {
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
var op = "slt"
if (name == "max") { op = "sgt" }
let c = emit_bind(("icmp " + (op + (" i32 " + (a.code + (", " + b.code))))))
return val(emit_bind(("select i1 " + (c + (", i32 " + (a.code + (", i32 " + b.code)))))), "int")
let c = emit_bind(`icmp {op} i32 {a.code}, {b.code}`)
return val(emit_bind(`select i1 {c}, i32 {a.code}, i32 {b.code}`), "int")
}
# clamp(v, lo, hi) = max(lo, min(v, hi))
let v = emit_expr(e.kids[0]); let lo = emit_expr(e.kids[1]); let hi = emit_expr(e.kids[2])
let c1 = emit_bind(("icmp slt i32 " + (v.code + (", " + hi.code))))
let t = emit_bind(("select i1 " + (c1 + (", i32 " + (v.code + (", i32 " + hi.code))))))
let c2 = emit_bind(("icmp sgt i32 " + (lo.code + (", " + t))))
return val(emit_bind(("select i1 " + (c2 + (", i32 " + (lo.code + (", i32 " + t)))))), "int")
let c1 = emit_bind(`icmp slt i32 {v.code}, {hi.code}`)
let t = emit_bind(`select i1 {c1}, i32 {v.code}, i32 {hi.code}`)
let c2 = emit_bind(`icmp sgt i32 {lo.code}, {t}`)
return val(emit_bind(`select i1 {c2}, i32 {lo.code}, i32 {t}`), "int")
}

View file

@ -3,8 +3,8 @@
# holder points at, so growth is visible to every holder.
fn emit_sizeof(llt: ptr) -> ptr {
let p = emit_bind(("getelementptr " + (llt + ", ptr null, i32 1")))
return emit_bind(("ptrtoint ptr " + (p + " to i64")))
let p = emit_bind(`getelementptr {llt}, ptr null, i32 1`)
return emit_bind(`ptrtoint ptr {p} to i64`)
}
fn emit_new_struct(name: ptr) -> Val {
@ -12,7 +12,7 @@ fn emit_new_struct(name: ptr) -> Val {
if (s == null) { perr("unknown record type in new") }
let lty = layout_ty(name)
let sz = emit_sizeof(lty)
let obj = emit_bind(("call ptr @malloc(i64 " + (sz + ")")))
let obj = emit_bind(`call ptr @malloc(i64 {sz})`)
var f = 0
while f < len(s.kids) {
let fd = s.kids[f]
@ -31,7 +31,7 @@ fn emit_new_struct(name: ptr) -> Val {
fn emit_new_slice(ty: ptr) -> Val {
let sz = emit_sizeof("%LSlice")
let h = emit_bind(("call ptr @malloc(i64 " + (sz + ")")))
let h = emit_bind(`call ptr @malloc(i64 {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")
@ -52,10 +52,10 @@ fn emit_len(e: Node) -> Val {
let s = emit_expr(e.kids[0])
if is_slice_ty(s.ty) { # a slice: read its header length
let lp = slice_field(s.code, 1)
return val(emit_bind(("load i32, ptr " + lp)), "int")
return val(emit_bind(`load i32, ptr {lp}`), "int")
}
let r = emit_bind(("call i64 @strlen(ptr " + (s.code + ")"))) # a string: byte length
return val(emit_bind(("trunc i64 " + (r + " to i32"))), "int")
let r = emit_bind(`call i64 @strlen(ptr {s.code})`) # a string: byte length
return val(emit_bind(`trunc i64 {r} to i32`), "int")
}
fn emit_push(e: Node) -> Val {
@ -64,30 +64,30 @@ fn emit_push(e: Node) -> Val {
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(("load i32, ptr " + lp))
let c = emit_bind(("load i32, ptr " + cp))
let full = emit_bind(("icmp sge i32 " + (l + (", " + c))))
let l = emit_bind(`load i32, ptr {lp}`)
let c = emit_bind(`load i32, ptr {cp}`)
let full = emit_bind(`icmp sge i32 {l}, {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(("mul i32 " + (c + ", 2")))
let isz = emit_bind(("icmp eq i32 " + (c + ", 0")))
let nc = emit_bind(("select i1 " + (isz + (", i32 8, i32 " + dbl))))
let dbl = emit_bind(`mul i32 {c}, 2`)
let isz = emit_bind(`icmp eq i32 {c}, 0`)
let nc = emit_bind(`select i1 {isz}, i32 8, i32 {dbl}`)
let esz = emit_sizeof(elt)
let ncw = emit_bind(("zext i32 " + (nc + " to i64")))
let bytes = emit_bind(("mul i64 " + (ncw + (", " + esz))))
let old = emit_bind(("load ptr, ptr " + dp))
let nd = emit_bind(("call ptr @realloc(ptr " + (old + (", i64 " + (bytes + ")")))))
let ncw = emit_bind(`zext i32 {nc} to i64`)
let bytes = emit_bind(`mul i64 {ncw}, {esz}`)
let old = emit_bind(`load ptr, ptr {dp}`)
let nd = emit_bind(`call ptr @realloc(ptr {old}, i64 {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(("load ptr, ptr " + dp))
let data = emit_bind(`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(("add i32 " + (l + ", 1")))
let l1 = emit_bind(`add i32 {l}, 1`)
emit(" store i32 "); emit(l1); emit(", ptr "); emit(lp); emit("\n")
return val("0", "void")
}

View file

@ -18,16 +18,16 @@ fn emit_query(st: Node) -> void {
let cond = lbl("qcond"); let body = lbl("qbody"); let nxt = lbl("qnext"); let endl = lbl("qend")
emit(" br label %"); emit(cond); emit("\n")
emit(cond); emit(":\n")
let i0 = emit_bind(("load i32, ptr " + ip))
let i0 = emit_bind(`load i32, ptr {ip}`)
let ec = emit_bind("load i32, ptr @L_entc")
let lt = emit_bind(("icmp slt i32 " + (i0 + (", " + ec))))
let lt = emit_bind(`icmp slt i32 {i0}, {ec}`)
emit(" br i1 "); emit(lt); emit(", label %"); emit(body); emit(", label %"); emit(endl); emit("\n")
emit(body); emit(":\n"); g_term = false
let i1 = emit_bind(("load i32, ptr " + ip))
let i1 = emit_bind(`load i32, ptr {ip}`)
# alive?
let ap = nreg(); emit(" "); emit(ap); emit(" = getelementptr inbounds ["); emit(me); emit(" x i32], ptr @L_alive, i32 0, i32 "); emit(i1); emit("\n")
let al = emit_bind(("load i32, ptr " + ap))
let alc = emit_bind(("icmp ne i32 " + (al + ", 0")))
let al = emit_bind(`load i32, ptr {ap}`)
let alc = emit_bind(`icmp ne i32 {al}, 0`)
let ka = lbl("qa")
emit(" br i1 "); emit(alc); emit(", label %"); emit(ka); emit(", label %"); emit(nxt); emit("\n")
emit(ka); emit(":\n")
@ -41,15 +41,15 @@ fn emit_query(st: Node) -> void {
var ok = "0"
if ak > 0 {
let kp = nreg(); emit(" "); emit(kp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i32], ptr @L_kind, i32 0, i32 "); emit(i1); emit("\n")
let kv = emit_bind(("load i32, ptr " + kp))
let kok = emit_bind(("icmp eq i32 " + (kv + (", " + itoa(ak)))))
let mev = emit_bind(("load i32, ptr @ME_" + tm.s)) # model-enabled flag
let meok = emit_bind(("icmp ne i32 " + (mev + ", 0")))
ok = emit_bind(("and i1 " + (kok + (", " + meok))))
let kv = emit_bind(`load i32, ptr {kp}`)
let kok = emit_bind(`icmp eq i32 {kv}, {itoa(ak)}`)
let mev = emit_bind(`load i32, ptr @ME_{tm.s}`) # model-enabled flag
let meok = emit_bind(`icmp ne i32 {mev}, 0`)
ok = emit_bind(`and i1 {kok}, {meok}`)
} else {
let hp = nreg(); emit(" "); emit(hp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i8], ptr @H_"); emit(tm.s); emit(", i32 0, i32 "); emit(i1); emit("\n")
let hv = emit_bind(("load i8, ptr " + hp))
ok = emit_bind(("icmp ne i8 " + (hv + ", 0")))
let hv = emit_bind(`load i8, ptr {hp}`)
ok = emit_bind(`icmp ne i8 {hv}, 0`)
}
let keep = lbl("qt")
emit(" br i1 "); emit(ok); emit(", label %"); emit(keep); emit(", label %"); emit(nxt); emit("\n")
@ -79,7 +79,7 @@ fn emit_query(st: Node) -> void {
# optional where-clause
if (st.b != null) {
let w = emit_expr(st.b)
let wc = emit_bind(("icmp ne i32 " + (w.code + ", 0")))
let wc = emit_bind(`icmp ne i32 {w.code}, 0`)
let kw = lbl("qw")
emit(" br i1 "); emit(wc); emit(", label %"); emit(kw); emit(", label %"); emit(nxt); emit("\n")
emit(kw); emit(":\n")
@ -92,8 +92,8 @@ fn emit_query(st: Node) -> void {
if not g_term { emit(" br label %"); emit(nxt); emit("\n") }
emit(nxt); emit(":\n")
let i2 = emit_bind(("load i32, ptr " + ip))
let i3 = emit_bind(("add i32 " + (i2 + ", 1")))
let i2 = emit_bind(`load i32, ptr {ip}`)
let i3 = emit_bind(`add i32 {i2}, 1`)
store_at("i32", i3, ip)
emit(" br label %"); emit(cond); emit("\n")
emit(endl); emit(":\n"); g_term = false

View file

@ -6,7 +6,7 @@
var g_iok: int = 0
fn emit_io(fn2: ptr, p: ptr, bytes: ptr) -> void {
let r = (("%io") + itoa(g_iok)); g_iok = g_iok + 1
let r = `%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")
}
@ -20,16 +20,16 @@ fn emit_snapshot_blocks(fn2: ptr) -> void {
emit_io(fn2, "@L_freelist", "%nalive")
emit_io(fn2, "@L_kind", "%nalive")
var i = 0
while i < len(prog) { if prog[i].kind == N_VAR { emit_io(fn2, ("@g_" + prog[i].s), "4") }; i = i + 1 }
while i < len(prog) { if prog[i].kind == N_VAR { emit_io(fn2, `@g_{prog[i].s}`, "4") }; i = i + 1 }
var ci = 0
i = 0
while i < len(prog) {
if prog[i].kind == N_COMP {
let c = prog[i].s
let csz = (("%csz") + itoa(ci))
let csz = `%csz{itoa(ci)}`
emit(" "); emit(csz); emit(" = ptrtoint ptr getelementptr (%Cmp_"); emit(c); emit(", ptr null, i32 "); emit(me); emit(") to i64\n")
emit_io(fn2, ("@S_" + c), csz)
emit_io(fn2, ("@H_" + c), me)
emit_io(fn2, `@S_{c}`, csz)
emit_io(fn2, `@H_{c}`, me)
ci = ci + 1
}
i = i + 1

View file

@ -4,7 +4,7 @@
fn emit_init_component(e: ptr, comp: ptr, rec: Node) -> void {
let me = itoa(MAX_ENT)
let c = find_comp(comp)
if (c == null) { perr(("spawn: unknown property " + comp)) }
if (c == null) { perr(`spawn: unknown property {comp}`) }
let hp = nreg(); emit(" "); emit(hp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i8], ptr @H_"); emit(comp); emit(", i32 0, i32 "); emit(e); emit("\n")
emit(" store i8 1, ptr "); emit(hp); emit("\n")
let slot = nreg()
@ -101,11 +101,11 @@ fn emit_despawn(st: Node) -> void {
if len(g_ondespawn) > 0 {
let me = itoa(MAX_ENT)
let kp = nreg(); emit(" "); emit(kp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i32], ptr @L_kind, i32 0, i32 "); emit(v.code); emit("\n")
let kind = emit_bind(("load i32, ptr " + kp))
let kind = emit_bind(`load i32, ptr {kp}`)
var i = 0
while i < len(g_ondespawn) {
let mname = g_ondespawn[i].s
let c = emit_bind(("icmp eq i32 " + (kind + (", " + itoa(find_arch_id(mname))))))
let c = emit_bind(`icmp eq i32 {kind}, {itoa(find_arch_id(mname))}`)
let yes = lbl("dh"); let no = lbl("dhn")
emit(" br i1 "); emit(c); emit(", label %"); emit(yes); emit(", label %"); emit(no); emit("\n")
emit(yes); emit(":\n call void @on_despawn_"); emit(mname); emit("(i32 "); emit(v.code); emit(")\n")

View file

@ -25,13 +25,13 @@ fn emit_assign(st: Node) -> void {
if li >= 0 {
# a `let` binding is immutable: rebinding it is an error (mutating THROUGH
# it — `x.field = …`, `x[i] = …` — is fine, and lands in the branches below).
if loc_mut[li] == 0 { perr(("cannot assign to immutable '" + (t.s + ("' (declared with let; use var) — line " + itoa(st.line))))) }
if loc_mut[li] == 0 { perr(`cannot assign to immutable '{t.s}' (declared with let; use var) — line {itoa(st.line)}`) }
addr = loc_reg[li]; ty = loc_ty[li]
}
else {
let g = find_global(t.s)
if (g == null) { perr(("assign to unknown " + t.s)) }
addr = ("@g_" + t.s); ty = g.ty
if (g == null) { perr(`assign to unknown {t.s}`) }
addr = `@g_{t.s}`; ty = g.ty
}
} else {
if t.kind == E_MEMBER { addr = emit_member_addr(t); ty = g_addr_ty }
@ -42,19 +42,19 @@ fn emit_assign(st: Node) -> void {
let rv = emit_expr(st.b)
var v = rv.code
if not (st.s == "=") {
let cur = emit_bind(("load " + (lt + (", ptr " + addr))))
let cur = emit_bind(`load {lt}, ptr {addr}`)
var opc = "add"
if (st.s == ("-=")) { opc = "sub" }
if (st.s == ("*=")) { opc = "mul" }
if (st.s == ("/=")) { opc = "sdiv" }
v = emit_bind((opc + (" i32 " + (cur + (", " + v)))))
v = emit_bind(`{opc} i32 {cur}, {v}`)
}
store_at(lt, v, addr)
}
fn emit_if(st: Node) -> void {
let c = emit_expr(st.a)
let cc = emit_bind(("icmp ne i32 " + (c.code + ", 0")))
let cc = emit_bind(`icmp ne i32 {c.code}, 0`)
let has_else = (st.c != null)
let tl = lbl("then"); let el = lbl("else"); let en = lbl("ifend")
if has_else { emit(" br i1 "); emit(cc); emit(", label %"); emit(tl); emit(", label %"); emit(el); emit("\n") }
@ -76,7 +76,7 @@ fn emit_while(st: Node) -> void {
emit(" br label %"); emit(cl); emit("\n")
emit(cl); emit(":\n")
let c = emit_expr(st.a)
let cc = emit_bind(("icmp ne i32 " + (c.code + ", 0")))
let cc = emit_bind(`icmp ne i32 {c.code}, 0`)
emit(" br i1 "); emit(cc); emit(", label %"); emit(bl); emit(", label %"); emit(en); emit("\n")
emit(bl); emit(":\n"); g_term = false
loop_push(cl, en)
@ -94,9 +94,9 @@ fn emit_for(st: Node) -> void {
let cl = lbl("fcond"); let bl = lbl("fbody"); let ct = lbl("fcont"); let en = lbl("fend")
emit(" br label %"); emit(cl); emit("\n")
emit(cl); emit(":\n")
let iv = emit_bind(("load i32, ptr " + slot))
let iv = emit_bind(`load i32, ptr {slot}`)
let hi = emit_expr(st.b)
let cc = emit_bind(("icmp slt i32 " + (iv + (", " + hi.code))))
let cc = emit_bind(`icmp slt i32 {iv}, {hi.code}`)
emit(" br i1 "); emit(cc); emit(", label %"); emit(bl); emit(", label %"); emit(en); emit("\n")
emit(bl); emit(":\n"); g_term = false
loop_push(ct, en)
@ -104,8 +104,8 @@ fn emit_for(st: Node) -> void {
loop_pop()
if not g_term { emit(" br label %"); emit(ct); emit("\n") }
emit(ct); emit(":\n")
let i2 = emit_bind(("load i32, ptr " + slot))
let i3 = emit_bind(("add i32 " + (i2 + ", 1")))
let i2 = emit_bind(`load i32, ptr {slot}`)
let i3 = emit_bind(`add i32 {i2}, 1`)
store_at("i32", i3, slot)
emit(" br label %"); emit(cl); emit("\n")
emit(en); emit(":\n"); g_term = false
@ -140,9 +140,9 @@ fn emit_match(st: Node) -> void {
var p = 0
while p < len(arm.kids) {
let pv = emit_expr(arm.kids[p])
let c = emit_bind(("icmp eq i32 " + (sv.code + (", " + pv.code))))
let c = emit_bind(`icmp eq i32 {sv.code}, {pv.code}`)
if first { acc = c; first = false }
else { acc = emit_bind(("or i1 " + (acc + (", " + c)))) }
else { acc = emit_bind(`or i1 {acc}, {c}`) }
p = p + 1
}
let bodyl = lbl("mbody"); let nextl = lbl("marm")

View file

@ -97,7 +97,7 @@ fn emit_ui_build() -> void {
emit(" call void @fn_rt_ui_static_text(i32 "); emit(itoa(i)); emit(", ptr "); emit(sv.code); emit(")\n")
} else { if (k == "skin") or (k == "image") {
let sv = emit_expr(v)
let r = emit_bind(("call i32 @fn_rt_image_load(ptr " + (sv.code + ")")))
let r = emit_bind(`call i32 @fn_rt_image_load(ptr {sv.code})`)
if (k == "skin") { ll_ui_set(i, 20, r) } else { ll_ui_set(i, 19, r) }
} else { if (k == "align") {
if v.kind == E_ID {

File diff suppressed because it is too large Load diff

View file

@ -77,7 +77,7 @@ entry {
# an unknown flag is ignored (with a note) rather than mistaken for the
# input file — '-' is ASCII 45
if peek8(a, 0) == 45 {
let m = ("ludicc: ignoring unknown flag " + (a + "\n"))
let m = `ludicc: ignoring unknown flag {a}\n`
file_write(file_stderr(), m, len(m))
} else { path = a }
} } } } } } }
@ -117,14 +117,14 @@ entry {
# a run with no explicit -o lands in a temp file
if run and (out == null) {
out = (("/tmp/ludic-run-") + strip_ludic(base_name(path)))
out = `/tmp/ludic-run-{strip_ludic(base_name(path))}`
}
# make the output directory if the user asked for e.g. bin/app
let odir = dir_of(out)
if len(odir) > 0 { os_system((("mkdir -p ") + odir)) }
if len(odir) > 0 { os_system(`mkdir -p {odir}`) }
let ll = (out + ".ll")
let ll = `{out}.ll`
if not ir_flush(ll) { die("ludicc: cannot write IR\n") }
let cc = getenv_or("LUDIC_CC", "clang")
@ -134,15 +134,15 @@ entry {
# platform layer and the Cocoa framework.
# -Wno-override-module: our IR carries an explicit target triple, which clang
# would otherwise warn about on every build.
var cmd = (cc + ((" -O2 -Wno-override-module ") + ll))
var cmd = `{cc} -O2 -Wno-override-module {ll}`
if g_windowed {
let cocoa = path_join(home, "runtime/native/cocoa.ll")
cmd = (cmd + (" " + (cocoa + (" -framework Cocoa -Wl,-rpath,@loader_path"))))
cmd = `{cmd} {cocoa} -framework Cocoa -Wl,-rpath,@loader_path`
}
cmd = (cmd + ((" -o ") + out))
cmd = `{cmd} -o {out}`
let rc = os_system(cmd)
if not save { os_system((("rm -f ") + ll)) }
if not save { os_system(`rm -f {ll}`) }
if rc != 0 { die("ludicc: link failed\n") }
# run mode: execute the binary we just built and forward its exit code

View file

@ -393,7 +393,7 @@ fn do_import(rel: ptr) -> void {
if already_loaded(full) { return }
push(loaded_paths, full)
let src = read_file(full)
if (src == null) { perr(("cannot open import " + full)) }
if (src == null) { perr(`cannot open import {full}`) }
let saved_toks = toks; let saved_pi = pi; let saved_dir = cur_dir
cur_dir = dir_of(full)
lex(src) # resets the global token stream