ludic/selfhost/frontend/registry_finish.ludic

110 lines
3.2 KiB
Text

# registry_finish.ludic — L8: when the program is read, each registry gets its entries.
function registries_finish() -> void {
var d = 0
while d < len(g_df_reg) {
if reg_find(g_df_reg[d]) < 0 {
g_err_file = g_df_rec[d].file
g_err_line = g_df_rec[d].line
g_parsing = false
perr(`def {g_df_reg[d]} {g_df_key[d]}: there is no registry {g_df_reg[d]}`)
}
pm_def_check(d) # permap.ludic: a map-scoped registry takes no def
reg_def_check(d) # registry_open.ludic: open, and visible
d += 1
}
var r = 0
while r < len(g_rg_name) {
if not pm_is(r) { reg_fill(r) }
r += 1
}
pm_finish() # permap.ludic: each map-scoped registry's state and verbs
}
function reg_fill(r: int) -> void {
let v = g_rg_var[r]
let t = g_rg_type[r]
let comp = find_comp(t)
let keyed = comp != null and field_index(comp, "key") >= 0
let lst = node(E_LIST)
lst.file = v.file
lst.line = v.line
let seen = new []pointer
var n = 0
let order = reg_order(r)
var o = 0
while o < len(order) {
let d = order[o]
let key = g_df_key[d]
let rec = g_df_rec[d]
var j = 0
while j < len(seen) {
if (seen[j] == key) {
g_err_file = rec.file
g_err_line = rec.line
g_parsing = false
perr(`def {g_rg_name[r]} {key} is declared twice`)
}
j += 1
}
push(seen, key)
if (reg_upper(key) == "COUNT") {
g_err_file = rec.file
g_err_line = rec.line
g_parsing = false
perr(`def {g_rg_name[r]} {key}: its constant would be {g_rg_prefix[r]}_COUNT, which is the registry's size; give the entry another key`)
}
if keyed and not reg_rec_has(rec, "key") {
let fi = node(E_FINIT)
fi.s = "key"
let ks = node(E_STR)
ks.s = key
fi.a = ks
push(rec.kids, fi)
}
if comp != null { res_type_fields(rec, comp) } # L9: nested records take their field's type
i18n_fill_row(r, key, rec, comp, g_df_kline[d], g_df_kcol[d]) # a @Text Key left out: its derived key
let nw = node(E_NEW)
nw.s = t
nw.a = rec
nw.file = rec.file
nw.line = rec.line
push(lst.kids, nw)
reg_const(v, `{g_rg_prefix[r]}_{reg_upper(key)}`, n)
n += 1
o += 1
}
reg_const(v, `{g_rg_prefix[r]}_COUNT`, n)
if n == 0 {
let empty = node(E_NEW)
empty.s = v.ty
empty.file = v.file
v.a = empty
} else {
v.a = lst
}
if keyed { reg_find_fn(v) }
}
# NAME_find(key) -> int: the entry's index, or -1 - written as Ludic and read like the rest
function reg_find_fn(v: Node) -> void {
let fname = `{reg_lower(v.s)}_find`
let src = `function {fname}(key: string) -> int {{\n var i = 0\n while i < len({v.s}) {{\n if {v.s}[i].key == key {{ return i }}\n i += 1\n }}\n return -1\n}}\n`
let saved_toks = toks
let saved_pi = pi
let saved_file = g_parse_file
let saved_parsing = g_parsing
g_parse_file = v.file
g_parsing = true
lex_at(src, v.line)
pi = 0
let at = len(prog)
skipnl()
parse_one_decl()
var k = at
while k < len(prog) {
prog[k].vis = v.vis
k += 1
}
toks = saved_toks
pi = saved_pi
g_parse_file = saved_file
g_parsing = saved_parsing
}