135 lines
3.9 KiB
Text
135 lines
3.9 KiB
Text
# check_gen_call.ludic — L5: a call to a generic function. Its arguments' types bind the type
|
|
# parameters (a literal only binds what nothing else did, so first(xs, 0) is decided by xs), the
|
|
# slot the call is written into binds what they cannot, and the call is rewritten to name the
|
|
# instance: `first(xs)` on a []int calls first$int, which is made and checked once however many
|
|
# calls reach it.
|
|
function gen_instance_name(name: pointer, binds: []pointer) -> pointer {
|
|
var out: pointer = name
|
|
var i = 0
|
|
while i < len(binds) {
|
|
out = out + "$" + gen_mangle(binds[i])
|
|
i += 1
|
|
}
|
|
return out
|
|
}
|
|
function gen_fn_instance(t: Node, iname: pointer, binds: []pointer) -> Node {
|
|
let have = ck_fn(iname)
|
|
if have != null { return have }
|
|
let f = gen_clone(t, gen_split(t.tps), binds)
|
|
f.s = iname
|
|
if g_migrate { f.mg = mg_unit(t, 0) } # an instance's needs are its generic's
|
|
push(g_gen_out, f)
|
|
push(g_gen_work, f)
|
|
ck_tab_put(ck_fn_k, ck_fn_v, iname, f)
|
|
return f
|
|
}
|
|
# each parameter's argument node, positional or named
|
|
function gen_arg_nodes(e: Node, labels: []pointer) -> []Node {
|
|
let out = new []Node
|
|
var i = 0
|
|
while i < len(labels) {
|
|
push(out, null)
|
|
i += 1
|
|
}
|
|
var j = 0
|
|
while j < len(e.kids) {
|
|
let k = e.kids[j]
|
|
if k.kind == E_FINIT {
|
|
let at = gen_index(labels, k.s)
|
|
if at >= 0 { out[at] = k.a }
|
|
} else {
|
|
if j < len(out) { out[j] = k }
|
|
}
|
|
j += 1
|
|
}
|
|
return out
|
|
}
|
|
function gen_call(e: Node, name: pointer, t: Node) -> pointer {
|
|
mg_call(e, t)
|
|
let expect = ck_call_expect
|
|
call_fill_defaults(e, t)
|
|
let tps = gen_split(t.tps)
|
|
let labels = new []pointer
|
|
let ptys = new []pointer
|
|
ck_params(t, labels, ptys)
|
|
if len(e.kids) != len(ptys) { ck_err("arity", e, `{name} takes {itoa(len(ptys))} argument(s) and this call gives {itoa(len(e.kids))}`) }
|
|
let nodes = gen_arg_nodes(e, labels)
|
|
let atys = new []pointer
|
|
let binds = new []pointer
|
|
var i = 0
|
|
while i < len(tps) {
|
|
push(binds, null)
|
|
i += 1
|
|
}
|
|
i = 0
|
|
while i < len(nodes) {
|
|
var at: pointer = "?"
|
|
if nodes[i] != null { at = ck_expr(nodes[i]) }
|
|
push(atys, at)
|
|
if nodes[i] != null and not ck_is_lit(nodes[i]) { gen_unify(ptys[i], at, tps, binds) }
|
|
i += 1
|
|
}
|
|
gen_unify(t.ty, expect, tps, binds)
|
|
i = 0
|
|
while i < len(nodes) {
|
|
if nodes[i] != null and ck_is_lit(nodes[i]) { gen_unify(ptys[i], atys[i], tps, binds) }
|
|
i += 1
|
|
}
|
|
var k = 0
|
|
while k < len(tps) {
|
|
if binds[k] == null {
|
|
ck_err("generic", e, `cannot tell what {tps[k]} is in this call to {name}: pass it an argument that says, or write the call where its result has a declared type`)
|
|
return "?"
|
|
}
|
|
k += 1
|
|
}
|
|
let f = gen_fn_instance(t, gen_instance_name(name, binds), binds)
|
|
e.a.s = f.s
|
|
let fl = new []pointer
|
|
let fp = new []pointer
|
|
ck_params(f, fl, fp)
|
|
var j = 0
|
|
while j < len(nodes) {
|
|
if nodes[j] != null { ck_give(fp[j], atys[j], nodes[j], `argument {itoa(j + 1)} of {name}`) }
|
|
j += 1
|
|
}
|
|
return f.ty
|
|
}
|
|
# every instance a generic body asks for is made and checked in turn; then the records the
|
|
# program only ever names in a type, and the instances go back in where the program's own
|
|
# declarations end
|
|
function gen_finish() -> void {
|
|
var w = 0
|
|
while w < len(g_gen_work) {
|
|
ck_fn_body(g_gen_work[w])
|
|
w += 1
|
|
}
|
|
var r = 0
|
|
while r < len(g_gi_name) {
|
|
if g_gi_open[r] == 0 and gen_template(g_gen_recs, g_gi_gen[r]) != null { ck_record(g_gi_name[r]) }
|
|
r += 1
|
|
}
|
|
if len(g_gen_out) == 0 { return }
|
|
let np = new []Node
|
|
var i = 0
|
|
while i < len(prog) {
|
|
if i == g_prog_user_end {
|
|
var o = 0
|
|
while o < len(g_gen_out) {
|
|
push(np, g_gen_out[o])
|
|
o += 1
|
|
}
|
|
}
|
|
push(np, prog[i])
|
|
i += 1
|
|
}
|
|
if g_prog_user_end >= len(prog) {
|
|
var o2 = 0
|
|
while o2 < len(g_gen_out) {
|
|
push(np, g_gen_out[o2])
|
|
o2 += 1
|
|
}
|
|
}
|
|
prog = np
|
|
g_prog_user_end += len(g_gen_out)
|
|
}
|