ludic/selfhost/frontend/registry.ludic
Orkuncakilkaya a5f52c4581 feat(lang): def REGISTRY from "file.lres" - a game fills an open registry from its own file
The entries are read and checked against the registry's record as a
registry ... from file is, errors at the resource file's line, and they
are defs of the module that wrote the line: the registry must be open to
it, and they take that module's place in the stable order. Reseed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 07:22:05 +03:00

128 lines
3.5 KiB
Text

# 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_rg_open: []int = new []int # 1: `open registry` - other modules may def into it
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()
}
var from: pointer = null
if is_id("from") {
pi += 1
from = toks[pi].text
pi += 1
}
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)
push(g_rg_open, 0)
if from != null { res_read(v, from) }
}
# def REGISTRY key { field: value, ... }
# def REGISTRY from "file.lres" - every entry of a resource file, as defs of this file's module
function parse_def() -> void {
pi += 1
let reg = eat_id()
if is_id("from") and toks[pi + 1].kind == TK_STR {
let from = toks[pi + 1].text
pi += 2
res_read_into(reg, from, `def {reg} from`)
return
}
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)
}