# 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_rg_from: []pointer = new []pointer # its resource file as written, or null var g_rg_at: []int = new []int # its attributes (@AppendOnly, @ByKey), a group or -1 var g_df_reg: []pointer = new []pointer var g_df_key: []pointer = new []pointer var g_df_rec: []Node = new []Node var g_df_kline: []int = new []int # where its key is written (the schema's) var g_df_kcol: []int = new []int var g_df_src: []pointer = new []pointer # the resource file it came from, or "" for a `def` var g_df_via: []pointer = new []pointer # the declaration that brought it in: file:line # one def, and where it came from function df_push(reg: pointer, key: pointer, rec: Node, kline: int, kcol: int, src: pointer, via: pointer) -> void { push(g_df_reg, reg) push(g_df_key, key) push(g_df_rec, rec) push(g_df_kline, kline) push(g_df_kcol, kcol) push(g_df_src, src) push(g_df_via, via) } 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 { let pm = g_pm_pending # @PerMap / @Chunked(n) (permap.ludic) let chunk = g_pm_chunk_pending 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") { if pm { perr(`registry {v.s}: a @PerMap registry has no 'as PREFIX' - its keys are not known when the game compiles, so it has no constants; find a row by its key with {pm_snake(v.s)}_find`) } pi += 1 prefix = eat_id() } var from: pointer = null if is_id("from") { pi += 1 from = toks[pi].text pi += 1 } v.ty = "[]" + t if not pm { push(prog, v) } # a map-scoped table is a state, written when the program is read 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) push(g_rg_from, from) i18n_registry_declared() # i18n.ludic: its @TextKey, before the attributes are taken mc_take(v, pm) # 27.1: @Machine(Record.field) (machines.ludic) push(g_rg_at, at_registry_take()) # attrs.ludic pm_declared(pm, chunk, v.s) if from != null and not pm { 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 kt = toks[pi] let key = eat_id() skipnl() let rec = record() df_push(reg, key, rec, kt.line, kt.col, "", `{g_parse_file}:{itoa(kt.line)}`) } 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) }