ludic/selfhost/check/check_index.ludic
Orkuncakilkaya 6a24b14f0e feat(lang): L5 generic records and functions
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>
2026-09-24 02:21:15 +03:00

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