feat(lang): L4 type checker between parse and emit
selfhost/check/ walks every function, the entry, tests, globals' initializers and @On listeners with real scopes, and refuses mixed number kinds, text and numbers, two record types, mismatched slices and fn types, wrong argument counts, wrong returns and wrong push elements - every mix-up at once, each at its line. LUDIC_CHECK_REPORT=1 lists them by category. pointer stays untyped (L7's). What it found is fixed: render3d's HDR scan calling the float-bits extern f_lt with floats; ludic.shooter's right-stick aim overflowing past half a push; prof.ludic storing longs in []int; extern arguments now coerced to their parameters. Text-returning runtime functions say string; Assets.ready says bool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0677aee93f
commit
57b66bdf47
52 changed files with 27005 additions and 11844 deletions
|
|
@ -1377,13 +1377,24 @@ function emit_call(e: Node) -> Val {
|
|||
let ext = find_extern(name)
|
||||
if (ext != null) {
|
||||
reorder_named(e, param_labels(ext))
|
||||
# each argument is coerced to its parameter, as a function's are: passed as its own
|
||||
# type, a float given to an int parameter arrived in a float register the callee
|
||||
# never reads, and the callee compared whatever the integer register held
|
||||
let eptys = param_types(ext)
|
||||
let eargs = new []pointer
|
||||
let eatys = new []pointer
|
||||
var ei = 0
|
||||
while ei < len(e.kids) { let v = emit_expr(e.kids[ei]); push(eargs, v.code); push(eatys, v.ty); ei += 1 }
|
||||
while ei < len(e.kids) {
|
||||
let v = emit_expr(e.kids[ei])
|
||||
var pty = v.ty
|
||||
if ei < len(eptys) { pty = eptys[ei] }
|
||||
push(eargs, coerce_code(v, pty))
|
||||
push(eatys, pty)
|
||||
ei += 1
|
||||
}
|
||||
let erl = llty(ext.ty)
|
||||
emit(" ")
|
||||
var erreg = "0"
|
||||
var erreg: pointer = "0"
|
||||
if not (erl == "void") { erreg = nreg(); emit(erreg); emit(" = ") }
|
||||
emit("call "); emit(erl); emit(" @"); emit(ext.a.s); emit("(")
|
||||
ei = 0
|
||||
|
|
@ -1425,7 +1436,7 @@ function emit_call(e: Node) -> Val {
|
|||
}
|
||||
let rl = llty(fn2.ty)
|
||||
emit(" ")
|
||||
var rreg = "0"
|
||||
var rreg: pointer = "0"
|
||||
if not (rl == "void") { rreg = nreg(); emit(rreg); emit(" = ") }
|
||||
emit("call "); emit(rl); emit(" @fn_"); emit(cname); emit("(")
|
||||
i = 0
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ function lit_as_fixed(v: Val) -> Val {
|
|||
function emit_fp_bin(op: pointer, a: Val, b: Val) -> Val {
|
||||
if (a.ty == "fixed") and not (fixed_lit_code(b) == "") { return emit_bin_vals(op, a, lit_as_fixed(b), false) }
|
||||
if (b.ty == "fixed") and not (fixed_lit_code(a) == "") { return emit_bin_vals(op, lit_as_fixed(a), b, false) }
|
||||
var t = "float"
|
||||
var t: pointer = "float"
|
||||
if is_fp(a.ty) and is_fp(b.ty) { t = fp_result(a.ty, b.ty) }
|
||||
else { if is_fp(a.ty) { t = a.ty } else { t = b.ty } }
|
||||
let ac = to_fp(a, t, `the left side of {op}`)
|
||||
|
|
@ -336,7 +336,7 @@ function fp_pick(meth: pointer, t: pointer, x: pointer, y: pointer) -> pointer {
|
|||
# the float type a Math call works in, given its already-evaluated first
|
||||
# argument and the static types of the rest; "" when it is not a float call
|
||||
function fp_math_type(first: Val, e: Node) -> pointer {
|
||||
var t = ""
|
||||
var t: pointer = ""
|
||||
if is_fp(first.ty) { t = first.ty }
|
||||
var i = 1
|
||||
while i < len(e.kids) {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ function emit_indirect_call(fv: Val, e: Node) -> Val {
|
|||
}
|
||||
let rl = llty(ret)
|
||||
emit(" ")
|
||||
var rreg = "0"
|
||||
var rreg: pointer = "0"
|
||||
if not (rl == "void") {
|
||||
rreg = nreg()
|
||||
emit(rreg)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ function compound_op(tok: pointer) -> pointer {
|
|||
function emit_assign(st: Node) -> void {
|
||||
# resolve the target's address and type
|
||||
let t = st.a
|
||||
var addr = "0"
|
||||
var ty = "int"
|
||||
var addr: pointer = "0"
|
||||
var ty: pointer = "int"
|
||||
if t.kind == E_ID {
|
||||
let li = loc_find(t.s)
|
||||
if li >= 0 {
|
||||
|
|
@ -209,7 +209,7 @@ function emit_match_tagged(st: Node, sv: Val, en: Node) -> void {
|
|||
let arm = st.kids[i]
|
||||
if arm_is_default(arm) { deflt = arm }
|
||||
else {
|
||||
var acc = "0"
|
||||
var acc: pointer = "0"
|
||||
var first = true
|
||||
var bindPat: Node = null
|
||||
var p = 0
|
||||
|
|
@ -262,7 +262,7 @@ function emit_match(st: Node) -> void {
|
|||
let arm = st.kids[i]
|
||||
if arm_is_default(arm) { deflt = arm }
|
||||
else {
|
||||
var acc = "0"
|
||||
var acc: pointer = "0"
|
||||
var first = true
|
||||
var p = 0
|
||||
while p < len(arm.kids) {
|
||||
|
|
@ -303,7 +303,7 @@ function emit_emit(st: Node) -> Val {
|
|||
var j = 0
|
||||
while j < len(st.a.kids) { if (st.a.kids[j].s == fd.s) { av = st.a.kids[j].a }; j += 1 }
|
||||
let lt = llty(fd.ty)
|
||||
var code = "0"
|
||||
var code: pointer = "0"
|
||||
if (lt == "ptr") { code = "null" }
|
||||
if (av != null) { let v = emit_expr(av); code = v.code }
|
||||
else { if (fd.a != null) { let dv = emit_expr(fd.a); code = dv.code } } # declared default
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ function machine_state_value(m: Node, state: Node) -> pointer {
|
|||
|
||||
function emit_machine(st: Node) -> void {
|
||||
let gv = machine_var(st.a)
|
||||
var s = ""
|
||||
var s: pointer = ""
|
||||
if (gv != null) { s = emit_bind(`load i32, ptr @g_{st.a.s}`) }
|
||||
else {
|
||||
let regv = emit_expr(st.a)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ function emit_query(st: Node) -> void {
|
|||
while t < len(terms.kids) {
|
||||
let tm = terms.kids[t]
|
||||
let ak = find_arch_id(tm.s)
|
||||
var ok = "0"
|
||||
var ok: pointer = "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}`)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue