ludic/selfhost/frontend/component_gen.ludic
Orkuncakilkaya ce80e64b24 feat(lang): 0.S - components take states in their header; migrate writes them, never inside a name, never outside the programs given, never into a package's state
- component Name (a: mut A, b: B) { ... }: every getter, default, function and event takes the
  header's states before the instance; a member's call to another passes them on; the glue is
  supplied them; the template never sees them; a read-only one is read-only in every member
- ludic migrate state: a component's members' needs go into its header (added to an existing one,
  mut added where now changed); a field read or a member call inside a component is the compiler's,
  so nothing is written inside a name and no ', )' is left; an entry point that declares states
  already gets the rest after them
- a program's module named like a package gets <Name>AppState; a program's own file its own state;
  a friend module's files go by directory; a package's settable var stays state
- it writes only under the programs and directories given (and runtime/ with --runtime), and
  refuses the whole run naming any other file that would have to change
- a name a package already moved into its state is rewritten through it; a read of the runtime's
  var through the runtime function that answers it (gl_w: gl_width())
- a state's instance supplied by the runtime is not a uses reference
- tests: state/component, rejected/state_component_ro, rendering/ui_render3d, migrate component
  and foreign cases

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 17:11:15 +03:00

102 lines
3.2 KiB
Text

# component_gen.ludic — L11: when the program is read, each component gets its record, its
# constructor, a props setter, a model, a call and its class, registered with ludic.ui at start
function components_finish() -> void {
var c = 0
while c < len(g_cm_name) {
cm_finish(c)
c += 1
}
}
function cm_err(c: int, msg: pointer) -> void {
g_err_file = g_cm_file[c]
g_err_line = g_cm_line[c]
g_parsing = false
perr(`component {g_cm_name[c]}: {msg}`)
}
function cm_finish(c: int) -> void {
if find_comp("UiClass") == null { cm_err(c, `a component is shown by ludic.ui - import "ludic.ui"`) }
let name = g_cm_name[c]
let px = cm_prefix(name)
let rec = "Cmp" + name
let head = g_cm_head[c]
let file = g_cm_file[c]
let line = g_cm_line[c]
var src = `property {rec} {{\n`
var i = 0
while i < len(g_cm_keep[c]) {
src = src + ` {g_cm_keep[c][i]}: {g_cm_keep_ty[c][i]}\n`
i += 1
}
vw_parse(src + "}\n", file, line, head.vis)
cm_bodies(c, rec)
vw_parse(cm_new_src(c, px, rec), file, line, head.vis)
vw_parse(cm_props_src(c, px, rec), file, line, head.vis)
vw_parse(cm_model_src(c, px, rec, head), file, line, head.vis)
vw_parse(cm_call_src(c, px, rec, head), file, line, head.vis)
cm_class(c, px, head)
}
# every function of the component (getters, defaults, functions, events) takes the instance
function cm_bodies(c: int, rec: pointer) -> void {
var i = 0
while i < len(g_cm_defs[c]) {
if g_cm_defs[c][i] != null { cm_rewrite(c, g_cm_defs[c][i], rec) }
i += 1
}
i = 0
while i < len(g_cm_fields[c]) {
let g = g_cm_fields[c][i]
if g.ty == null { g.ty = cm_infer(c, g, g_cm_fnames[c][i]) }
cm_rewrite(c, g, rec)
i += 1
}
i = 0
while i < len(g_cm_calls[c]) {
cm_rewrite(c, g_cm_calls[c][i], rec)
i += 1
}
}
function cm_infer(c: int, g: Node, fname: pointer) -> pointer {
let e = g.a.kids[0].a
if e.kind == E_ID and cm_is_keep(c, e.s) {
var i = 0
while i < len(g_cm_keep[c]) {
if (g_cm_keep[c][i] == e.s) { return g_cm_keep_ty[c][i] }
i += 1
}
}
# 0.S: a state's field, through the header (`purse = home.purse`)
if e.kind == E_MEMBER and e.a != null and e.a.kind == E_ID {
var j = 0
while j < len(g_cm_ps[c]) {
if (g_cm_ps[c][j].s == e.a.s) {
let r = find_comp(g_cm_ps[c][j].ty)
if r != null and field_index(r, e.s) >= 0 { return field_type(r, e.s) }
}
j += 1
}
}
if e.kind == E_ID {
let d = find_global(e.s)
if d != null and d.ty != null { return d.ty }
}
if e.kind == E_INT { return "int" }
if e.kind == E_FLOAT { return "float" }
if e.kind == E_BOOL { return "bool" }
if e.kind == E_STR { return "string" }
if e.kind == E_CALL and e.a != null and e.a.kind == E_ID {
let f = find_fn(e.a.s)
if f != null and f.ty != null and not (f.ty == "void") { return f.ty }
}
g_cm_line[c] = g.line
cm_err(c, `say what type {fname} is - {fname}: int = ...`)
return "int"
}
function cm_new_src(c: int, px: pointer, rec: pointer) -> pointer {
var src = `function {px}new() -> pointer {{\n let s = new {rec}\n`
var i = 0
while i < len(g_cm_keep[c]) {
if g_cm_defs[c][i] != null { src = src + ` s.{g_cm_keep[c][i]} = {px}def_{g_cm_keep[c][i]}(s)\n` }
i += 1
}
return src + " return s\n}\n"
}