property Pool<T> { ... }, function first<T>(xs: []T) -> T, map<T, U> over fn
types; a type writes an instance as Pool<Thing>, nested as deep as needed. The
parser names an instance Pool$Thing and remembers its generic and arguments; the
checker takes the generic declarations out, infers a call's type arguments from
its arguments or its result's declared slot, and makes each instance once as an
ordinary record or function, checked like any other. Errors print Pool<Thing>.
An instance keeps its generic's module and export (L3). ludic-fmt keeps type
arguments together while spacing comparisons and shifts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
2.5 KiB
Text
78 lines
2.5 KiB
Text
# check_index.ludic — L4: the checker's name index. The emitter finds a declaration by scanning
|
|
# every one (find_fn, find_global, find_comp); a pass that asks about every call and every name
|
|
# builds a hash of them once instead. One table per kind of declaration.
|
|
const CK_SLOTS: int = 65536
|
|
var ck_fn_k: []pointer = new []pointer
|
|
var ck_fn_v: []Node = new []Node
|
|
var ck_gl_k: []pointer = new []pointer
|
|
var ck_gl_v: []Node = new []Node
|
|
var ck_rec_k: []pointer = new []pointer
|
|
var ck_rec_v: []Node = new []Node
|
|
var ck_en_k: []pointer = new []pointer
|
|
var ck_en_v: []Node = new []Node
|
|
var ck_ex_k: []pointer = new []pointer
|
|
var ck_ex_v: []Node = new []Node
|
|
|
|
function ck_hash(s: pointer) -> int {
|
|
var h = 5381
|
|
var i = 0
|
|
let n = len(s)
|
|
while i < n {
|
|
h = (h * 33 + s[i]) % 1000003
|
|
i += 1
|
|
}
|
|
return h % CK_SLOTS
|
|
}
|
|
function ck_tab_init(k: []pointer, v: []Node) -> void {
|
|
var i = 0
|
|
while i < CK_SLOTS {
|
|
push(k, null)
|
|
push(v, null)
|
|
i += 1
|
|
}
|
|
}
|
|
# the first declaration of a name wins, as it does in the emitter
|
|
function ck_tab_put(k: []pointer, v: []Node, name: pointer, d: Node) -> void {
|
|
var h = ck_hash(name)
|
|
while k[h] != null {
|
|
if k[h] == name { return }
|
|
h = (h + 1) % CK_SLOTS
|
|
}
|
|
k[h] = name
|
|
v[h] = d
|
|
}
|
|
function ck_tab_get(k: []pointer, v: []Node, name: pointer) -> Node {
|
|
if name == null { return null }
|
|
var h = ck_hash(name)
|
|
while k[h] != null {
|
|
if k[h] == name { return v[h] }
|
|
h = (h + 1) % CK_SLOTS
|
|
}
|
|
return null
|
|
}
|
|
function ck_index() -> void {
|
|
ck_tab_init(ck_fn_k, ck_fn_v)
|
|
ck_tab_init(ck_gl_k, ck_gl_v)
|
|
ck_tab_init(ck_rec_k, ck_rec_v)
|
|
ck_tab_init(ck_en_k, ck_en_v)
|
|
ck_tab_init(ck_ex_k, ck_ex_v)
|
|
var i = 0
|
|
while i < len(prog) {
|
|
let d = prog[i]
|
|
if d.kind == N_FN { ck_tab_put(ck_fn_k, ck_fn_v, d.s, d) }
|
|
if d.kind == N_VAR or d.kind == N_CONST { ck_tab_put(ck_gl_k, ck_gl_v, d.s, d) }
|
|
if d.kind == N_COMP { ck_tab_put(ck_rec_k, ck_rec_v, d.s, d) }
|
|
if d.kind == N_ENUM { ck_tab_put(ck_en_k, ck_en_v, d.s, d) }
|
|
if d.kind == N_EXTERN { ck_tab_put(ck_ex_k, ck_ex_v, d.s, d) }
|
|
i += 1
|
|
}
|
|
}
|
|
function ck_fn(name: pointer) -> Node { return ck_tab_get(ck_fn_k, ck_fn_v, name) }
|
|
function ck_global(name: pointer) -> Node { return ck_tab_get(ck_gl_k, ck_gl_v, name) }
|
|
function ck_record(name: pointer) -> Node {
|
|
let r = ck_tab_get(ck_rec_k, ck_rec_v, name)
|
|
if r != null { return r }
|
|
return gen_record(name)
|
|
}
|
|
function ck_enum(name: pointer) -> Node { return ck_tab_get(ck_en_k, ck_en_v, name) }
|
|
function ck_extern(name: pointer) -> Node { return ck_tab_get(ck_ex_k, ck_ex_v, name) }
|