feat(lang): L8 registries by declaration - registry and def
registry NAME of RECORD [as PREFIX] is a global table; def NAME key { ... } in
any file is one entry, collected in source order and filled before any code
runs. Each entry gets an index constant (PREFIX_KEY), the table PREFIX_COUNT,
and a record with a key field gets it filled and a NAME_find(key). A record
literal naming a field its record lacks is now an error everywhere; a global's
initializer is lowered as its own file's code (its errors, and what its module
may see, were whichever statement came last).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b0b0b62bce
commit
7e7f3ab297
15 changed files with 48231 additions and 44362 deletions
112
selfhost/frontend/registry.ludic
Normal file
112
selfhost/frontend/registry.ludic
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# registry.ludic — L8: registration by declaration. A registry is a global table of records,
|
||||
# and each `def` is one entry, written where it belongs rather than as a call in an init
|
||||
# function somebody has to remember:
|
||||
#
|
||||
# registry Furnishings of Furnishing as HF
|
||||
# def Furnishings chair { name: "Camp chair", cost: 60, seat: true }
|
||||
#
|
||||
# The parser collects every def (in source order, across files) and, when the program is read,
|
||||
# gives the registry its entries as its initializer, a constant per entry holding its index
|
||||
# (HF_CHAIR - declaration order, so a table saved by position keeps its rule: append, never
|
||||
# insert), HF_COUNT, and, when the record has a `key: string` field, fills it in and adds
|
||||
# furnishings_find(key) -> int. Everything generated belongs to the registry's own file, so it
|
||||
# is in the registry's module and exported only when the registry is.
|
||||
var g_rg_name: []pointer = new []pointer
|
||||
var g_rg_type: []pointer = new []pointer
|
||||
var g_rg_prefix: []pointer = new []pointer
|
||||
var g_rg_var: []Node = new []Node
|
||||
var g_df_reg: []pointer = new []pointer
|
||||
var g_df_key: []pointer = new []pointer
|
||||
var g_df_rec: []Node = new []Node
|
||||
|
||||
function reg_upper(s: pointer) -> pointer {
|
||||
let n = len(s)
|
||||
let out = bytes(n + 1)
|
||||
var i = 0
|
||||
while i < n {
|
||||
var c = s[i]
|
||||
if c >= 'a' and c <= 'z' { c = c - 32 }
|
||||
out[i] = c
|
||||
i += 1
|
||||
}
|
||||
out[n] = 0
|
||||
return out
|
||||
}
|
||||
function reg_lower(s: pointer) -> pointer {
|
||||
let n = len(s)
|
||||
let out = bytes(n + 1)
|
||||
var i = 0
|
||||
while i < n {
|
||||
var c = s[i]
|
||||
if c >= 'A' and c <= 'Z' { c = c + 32 }
|
||||
out[i] = c
|
||||
i += 1
|
||||
}
|
||||
out[n] = 0
|
||||
return out
|
||||
}
|
||||
# registry NAME of TYPE [as PREFIX]
|
||||
function parse_registry() -> void {
|
||||
pi += 1
|
||||
let v = node(N_VAR)
|
||||
v.s = eat_id()
|
||||
if not is_id("of") { perr(`registry {v.s}: say what it holds - registry {v.s} of SomeRecord`) }
|
||||
pi += 1
|
||||
let t = ptype()
|
||||
var prefix = reg_upper(v.s)
|
||||
if is_id("as") {
|
||||
pi += 1
|
||||
prefix = eat_id()
|
||||
}
|
||||
v.ty = "[]" + t
|
||||
push(prog, v)
|
||||
push(g_rg_name, v.s)
|
||||
push(g_rg_type, t)
|
||||
push(g_rg_prefix, prefix)
|
||||
push(g_rg_var, v)
|
||||
}
|
||||
# def REGISTRY key { field: value, ... }
|
||||
function parse_def() -> void {
|
||||
pi += 1
|
||||
let reg = eat_id()
|
||||
let key = eat_id()
|
||||
skipnl()
|
||||
let rec = record()
|
||||
push(g_df_reg, reg)
|
||||
push(g_df_key, key)
|
||||
push(g_df_rec, rec)
|
||||
}
|
||||
function reg_find(name: pointer) -> int {
|
||||
var i = 0
|
||||
while i < len(g_rg_name) {
|
||||
if (g_rg_name[i] == name) { return i }
|
||||
i += 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
function reg_rec_has(rec: Node, field: pointer) -> bool {
|
||||
var i = 0
|
||||
while i < len(rec.kids) {
|
||||
if (rec.kids[i].s == field) { return true }
|
||||
i += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
# a generated declaration: the registry's file, line and export
|
||||
function reg_decl(kind: int, v: Node) -> Node {
|
||||
let d = node(kind)
|
||||
d.file = v.file
|
||||
d.line = v.line
|
||||
d.vis = v.vis
|
||||
return d
|
||||
}
|
||||
function reg_const(v: Node, name: pointer, value: int) -> void {
|
||||
let c = reg_decl(N_CONST, v)
|
||||
c.s = name
|
||||
c.ty = "int"
|
||||
let e = node(E_INT)
|
||||
e.ival = value
|
||||
e.file = v.file
|
||||
c.a = e
|
||||
push(prog, c)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue