ludic schema: a components section and a natives list (R4)
Each UI component: module, place, doc, xml and lss paths, props and state (type, default as written, place, doc), states_read (the header's states), derived fields with their types, functions and events as the template calls them (states and instance stripped), and the native tags its template uses. natives: every ui_native / ui_native_input call with a literal tag - tag, via, handler, place. schema_version stays 1; the lists are additions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
28f7b4666b
commit
281ebc23e1
11 changed files with 80436 additions and 71227 deletions
15
LANGUAGE.md
15
LANGUAGE.md
|
|
@ -680,6 +680,19 @@ object with `"schema_version": 1`:
|
|||
`params` (the arguments a caller passes), `states` (what the runtime supplies), `signature`, and
|
||||
`fn_type` - the type a `fn` field sees, the states stripped, spelled as a field's type is
|
||||
(`fn(NpcPerson,float)->bool`), so matching a function to a field is comparing two strings.
|
||||
- `components` - every UI component (see Components): its module, place, doc, `xml` and `lss` (the
|
||||
template's and the stylesheet's paths, `lss` null when it has none); `props` and `state`, the
|
||||
instance's own fields in the order written, each with its type, its default as written (or null),
|
||||
its place and doc (a prop's `attributes` are `[]`: a component's members take none); `states_read`,
|
||||
the program's states its header names, which the runtime supplies and the template never sees;
|
||||
`derived`, the fields worked out each frame, with their types (an inferred one resolved);
|
||||
`functions` (`{"name", "params": [["i", "int"]], "result"}`) and `events` (its `on` handlers,
|
||||
`{"name", "params"}`) as the template calls them, the header's states and the instance stripped;
|
||||
and `natives`, the registered native tags its template uses as elements;
|
||||
- `natives` - every `ui_native` / `ui_native_input` call whose tag is a string literal:
|
||||
`{"tag", "via", "handler", "module", "file", "line", "col"}`, `via` the function called and
|
||||
`handler` the `fn` value it passes last (else null). A tag worked out at run time cannot be known
|
||||
and is left out.
|
||||
|
||||
Each list is sorted by name (then file and line), a registry's entries are in index order, and the
|
||||
paths are the ones the compiler read, so two runs over the same source write the same file. The
|
||||
|
|
@ -2121,7 +2134,7 @@ ludic test -j 4 # four tests at once (default: one per
|
|||
ludic test packages/ludic.base # the test programs under a directory (a package's)
|
||||
ludic build --check # every check a build makes, nothing written
|
||||
ludic build --check --diagnostics=json # the same, every error as a JSON array on stdout
|
||||
ludic schema -o build/schema.json # records, registries, entries and consts, for editors
|
||||
ludic schema -o build/schema.json # records, registries, entries, consts, components and natives, for editors
|
||||
ludic deps # how tangled the modules are, as the compiler resolved them
|
||||
ludic deps --check tests/deps-baseline.txt # fail when a number rose (--baseline FILE writes them)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,3 +22,10 @@ A target no part of the program declares (an `@Ref` registry, an `@Tint` or list
|
|||
a warning and `"unresolved": true` in the schema, so a package can name the game's registry; a name of
|
||||
another kind is an error. `@OneOf` on a string field takes words, and every registry row's value is
|
||||
checked against them.
|
||||
|
||||
The schema has a `components` list: each UI component's module, place, doc, template and stylesheet
|
||||
paths, its `props` and `state` (type, default as written, place, doc), `states_read` (the states its
|
||||
header names, apart from its model), `derived` fields with their types, and the `functions` and
|
||||
`events` its template calls with their parameters (states and instance stripped), and the
|
||||
registered native tags its template uses. A `natives` list gives every `ui_native` /
|
||||
`ui_native_input` call with a literal tag: the tag, the function called, its handler and its place.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Counter.ludic — a component: what it takes (props), keeps (state), works out and does
|
||||
component Counter {
|
||||
prop label: string
|
||||
prop step: int = 1
|
||||
prop step: int = 1 # how much one press adds
|
||||
state count: int = 0
|
||||
doubled: int = count * 2
|
||||
function big() -> bool { return count > 3 }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
# consts every const: its type and its value as written
|
||||
# functions every function a `fn` value can name: fn_type is the type a field sees, the states
|
||||
# stripped (the runtime supplies them), written as a field's type is ("fn(A,B)->R")
|
||||
# components every UI component: props, state, derived fields, functions, events (emit_schema_ui)
|
||||
# natives every native tag registered with ui_native / ui_native_input by a literal
|
||||
#
|
||||
# Deterministic: each list sorted by name (then file and line), an entry list in index order, the
|
||||
# paths as the compiler read them, and nothing about the run. The engine's runtime is left out.
|
||||
|
|
@ -36,6 +38,11 @@ function schema_buf() -> Buf {
|
|||
sc_consts(b)
|
||||
buf_puts(b, "\n ],\n \"functions\": [")
|
||||
sc_functions(b)
|
||||
sc_natives_find()
|
||||
buf_puts(b, "\n ],\n \"components\": [")
|
||||
sc_components(b)
|
||||
buf_puts(b, "\n ],\n \"natives\": [")
|
||||
sc_natives(b)
|
||||
buf_puts(b, "\n ]\n}\n")
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
296
selfhost/backend/emit_schema_ui.ludic
Normal file
296
selfhost/backend/emit_schema_ui.ludic
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
# emit_schema_ui.ludic — the schema's UI side (emit_schema.ludic): every component, as a UI editor
|
||||
# needs to know it, and every native tag the program registers with ludic.ui.
|
||||
#
|
||||
# components each `component` (component.ludic): its module, place, doc, template and stylesheet
|
||||
# paths; its props and its state (both fields of the instance, a prop given by the
|
||||
# parent's attribute, a state kept by the instance and set by the template's `set:`),
|
||||
# each with its type, its default as written, its doc and place; `states_read`, the
|
||||
# program's states its header names (supplied by the runtime, never seen by the
|
||||
# template); `derived`, the fields worked out each frame; `functions` and `events`,
|
||||
# what the template calls, with the header's states and the instance stripped; and
|
||||
# `natives`, the registered native tags its template uses
|
||||
# natives each call of ui_native / ui_native_input whose tag is a string literal: the tag, the
|
||||
# function called, the handler it names (a `fn` value, else null) and the place. A tag
|
||||
# worked out at run time cannot be known here and is left out.
|
||||
|
||||
# ---- natives ----------------------------------------------------------------------------------
|
||||
var g_sn_tag: []pointer = new []pointer
|
||||
var g_sn_via: []pointer = new []pointer
|
||||
var g_sn_fn: []pointer = new []pointer # the handler's name, or null
|
||||
var g_sn_call: []Node = new []Node
|
||||
|
||||
function sc_natives_find() -> void {
|
||||
g_sn_tag = new []pointer
|
||||
g_sn_via = new []pointer
|
||||
g_sn_fn = new []pointer
|
||||
g_sn_call = new []Node
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
sc_nt_walk(prog[i])
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
function sc_nt_walk(n: Node) -> void {
|
||||
if n == null { return }
|
||||
if n.kind == E_CALL and n.a != null and n.a.kind == E_ID { sc_nt_call(n) }
|
||||
sc_nt_walk(n.a)
|
||||
sc_nt_walk(n.b)
|
||||
sc_nt_walk(n.c)
|
||||
var i = 0
|
||||
while i < len(n.kids) {
|
||||
sc_nt_walk(n.kids[i])
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
# ui_native(ui_st, tag, measure, draw) / ui_native_input(ui_st, tag, f): the tag counted from the end,
|
||||
# since the leading state may be written or supplied
|
||||
function sc_nt_call(n: Node) -> void {
|
||||
let via = vis_plain(n.a.s)
|
||||
if not (via == "ui_native") and not (via == "ui_native_input") { return }
|
||||
if n.file == null or n.pos < 0 or is_runtime_file(n.file) { return }
|
||||
let f = find_fn(n.a.s)
|
||||
if f == null { return }
|
||||
var np = 0
|
||||
var ti = -1
|
||||
var k = 0
|
||||
while k < len(f.kids) {
|
||||
if f.kids[k].kind == N_PARAM {
|
||||
if (f.kids[k].s == "tag") { ti = np }
|
||||
np += 1
|
||||
}
|
||||
k += 1
|
||||
}
|
||||
if ti < 0 { return }
|
||||
let ai = len(n.kids) - (np - ti)
|
||||
if ai < 0 or ai >= len(n.kids) { return }
|
||||
let t = n.kids[ai]
|
||||
if t.kind != E_STR or t.s == null { return }
|
||||
var j = 0
|
||||
while j < len(g_sn_call) {
|
||||
let o = g_sn_call[j]
|
||||
if (g_sn_tag[j] == t.s) and (g_sn_via[j] == via) and (o.file == n.file) and o.a.line == n.a.line and o.a.col == n.a.col { return }
|
||||
j += 1
|
||||
}
|
||||
var h: pointer = null
|
||||
let last = n.kids[len(n.kids) - 1]
|
||||
if last.kind == E_FNREF and last.s != null { h = sc_name(last.s) }
|
||||
push(g_sn_tag, t.s)
|
||||
push(g_sn_via, via)
|
||||
push(g_sn_fn, h)
|
||||
push(g_sn_call, n)
|
||||
}
|
||||
function sc_natives(b: Buf) -> void {
|
||||
let xs = new []int
|
||||
let keys = new []pointer
|
||||
var i = 0
|
||||
while i < len(g_sn_tag) {
|
||||
let n = g_sn_call[i]
|
||||
push(xs, i)
|
||||
push(keys, sc_key(g_sn_tag[i], n.file, n.a.line) + "\t" + g_sn_via[i])
|
||||
i += 1
|
||||
}
|
||||
sc_sort(xs, keys)
|
||||
i = 0
|
||||
while i < len(xs) {
|
||||
let j = xs[i]
|
||||
let n = g_sn_call[j]
|
||||
sc_sep(b, i == 0, " ")
|
||||
buf_puts(b, "{\"tag\": ")
|
||||
jq_put(b, g_sn_tag[j])
|
||||
buf_puts(b, ", \"via\": ")
|
||||
jq_put(b, g_sn_via[j])
|
||||
buf_puts(b, ", \"handler\": ")
|
||||
sc_str(b, g_sn_fn[j])
|
||||
buf_puts(b, ", \"module\": ")
|
||||
sc_str(b, sc_mod(n.file))
|
||||
buf_puts(b, ", ")
|
||||
sc_at(b, n.file, n.a.line, n.a.col) # where the function's name is written
|
||||
buf_puts(b, "}")
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
# ---- components -------------------------------------------------------------------------------
|
||||
function sc_components(b: Buf) -> void {
|
||||
let xs = new []int
|
||||
let keys = new []pointer
|
||||
var c = 0
|
||||
while c < len(g_cm_name) {
|
||||
if not is_runtime_file(g_cm_file[c]) {
|
||||
push(xs, c)
|
||||
push(keys, sc_key(g_cm_name[c], g_cm_file[c], g_cm_at[c][0]))
|
||||
} else {
|
||||
push(keys, "")
|
||||
}
|
||||
c += 1
|
||||
}
|
||||
sc_sort(xs, keys)
|
||||
var i = 0
|
||||
while i < len(xs) {
|
||||
sc_component(b, xs[i], i == 0)
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
function sc_component(b: Buf, c: int, first: bool) -> void {
|
||||
let file = g_cm_file[c]
|
||||
sc_sep(b, first, " ")
|
||||
buf_puts(b, "{\"name\": ")
|
||||
jq_put(b, g_cm_name[c])
|
||||
buf_puts(b, ", \"module\": ")
|
||||
sc_str(b, sc_mod(file))
|
||||
buf_puts(b, ", \"exported\": ")
|
||||
sc_bool(b, g_cm_head[c].vis == 1)
|
||||
buf_puts(b, ", ")
|
||||
sc_at(b, file, g_cm_at[c][0], g_cm_at[c][1])
|
||||
buf_puts(b, ",\n \"xml\": ")
|
||||
jq_put(b, g_cm_xml_path[c])
|
||||
buf_puts(b, ", \"lss\": ")
|
||||
var lss: pointer = g_cm_lss_path[c]
|
||||
if len(lss) == 0 { lss = null }
|
||||
sc_str(b, lss)
|
||||
buf_puts(b, ",\n \"doc\": ")
|
||||
sc_str(b, sc_doc(file, g_cm_at[c][2]))
|
||||
buf_puts(b, ",\n \"props\": [")
|
||||
sc_cm_keeps(b, c, true)
|
||||
buf_puts(b, "],\n \"state\": [")
|
||||
sc_cm_keeps(b, c, false)
|
||||
buf_puts(b, "],\n \"states_read\": [")
|
||||
var k = 0
|
||||
while k < len(g_cm_ps[c]) {
|
||||
if k > 0 { buf_puts(b, ", ") }
|
||||
jq_put(b, sc_ty(g_cm_ps[c][k].ty))
|
||||
k += 1
|
||||
}
|
||||
buf_puts(b, "],\n \"derived\": [")
|
||||
k = 0
|
||||
while k < len(g_cm_fields[c]) {
|
||||
sc_sep(b, k == 0, " ")
|
||||
buf_puts(b, "{\"name\": ")
|
||||
jq_put(b, g_cm_fnames[c][k])
|
||||
buf_puts(b, ", \"type\": ")
|
||||
jq_put(b, sc_ty(g_cm_fields[c][k].ty))
|
||||
buf_puts(b, ", \"line\": ")
|
||||
buf_puti(b, g_cm_fline[c][k])
|
||||
buf_puts(b, "}")
|
||||
k += 1
|
||||
}
|
||||
if len(g_cm_fields[c]) > 0 { buf_puts(b, "\n ") }
|
||||
buf_puts(b, "],\n \"functions\": [")
|
||||
sc_cm_calls(b, c, false)
|
||||
buf_puts(b, "],\n \"events\": [")
|
||||
sc_cm_calls(b, c, true)
|
||||
buf_puts(b, "],\n \"natives\": [")
|
||||
sc_cm_natives(b, c)
|
||||
buf_puts(b, "]}")
|
||||
}
|
||||
# its props (or its state), in the order written: the instance's fields
|
||||
function sc_cm_keeps(b: Buf, c: int, props: bool) -> void {
|
||||
let file = g_cm_file[c]
|
||||
var n = 0
|
||||
var i = 0
|
||||
while i < len(g_cm_keep[c]) {
|
||||
if g_cm_prop[c][i] == props {
|
||||
let a = i * 5
|
||||
sc_sep(b, n == 0, " ")
|
||||
buf_puts(b, "{\"name\": ")
|
||||
jq_put(b, g_cm_keep[c][i])
|
||||
buf_puts(b, ", \"type\": ")
|
||||
jq_put(b, sc_ty(g_cm_keep_ty[c][i]))
|
||||
buf_puts(b, ", \"default\": ")
|
||||
sc_str(b, sc_text(file, g_cm_kat[c][a + 3], g_cm_kat[c][a + 4]))
|
||||
buf_puts(b, ", ")
|
||||
sc_at(b, file, g_cm_kat[c][a], g_cm_kat[c][a + 1])
|
||||
if props { buf_puts(b, ", \"attributes\": []") }
|
||||
buf_puts(b, ", \"doc\": ")
|
||||
sc_str(b, sc_doc(file, g_cm_kat[c][a + 2]))
|
||||
buf_puts(b, "}")
|
||||
n += 1
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
if n > 0 { buf_puts(b, "\n ") }
|
||||
}
|
||||
# its functions (or its `on` events) as the template calls them: past the header's states and the
|
||||
# instance, which the runtime supplies
|
||||
function sc_cm_calls(b: Buf, c: int, events: bool) -> void {
|
||||
var n = 0
|
||||
var i = 0
|
||||
while i < len(g_cm_calls[c]) {
|
||||
if g_cm_isev[c][i] == events {
|
||||
let f = g_cm_calls[c][i]
|
||||
sc_sep(b, n == 0, " ")
|
||||
buf_puts(b, "{\"name\": ")
|
||||
jq_put(b, g_cm_cnames[c][i])
|
||||
buf_puts(b, ", \"params\": [")
|
||||
var k = 0
|
||||
var np = 0
|
||||
while k < len(f.kids) {
|
||||
let p = f.kids[k]
|
||||
if p.kind == N_PARAM and not (p.s == "self") and not sc_is_state_param(p) {
|
||||
if np > 0 { buf_puts(b, ", ") }
|
||||
buf_puts(b, "[")
|
||||
jq_put(b, p.s)
|
||||
buf_puts(b, ", ")
|
||||
jq_put(b, sc_ty(p.ty))
|
||||
buf_puts(b, "]")
|
||||
np += 1
|
||||
}
|
||||
k += 1
|
||||
}
|
||||
buf_puts(b, "]")
|
||||
if not events {
|
||||
buf_puts(b, ", \"result\": ")
|
||||
jq_put(b, sc_ty(f.ty))
|
||||
}
|
||||
buf_puts(b, ", \"line\": ")
|
||||
buf_puti(b, f.line)
|
||||
buf_puts(b, "}")
|
||||
n += 1
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
if n > 0 { buf_puts(b, "\n ") }
|
||||
}
|
||||
# the registered native tags its template uses as elements, sorted, each once
|
||||
function sc_cm_natives(b: Buf, c: int) -> void {
|
||||
let xml = g_cm_xml[c]
|
||||
let tags = new []pointer
|
||||
let xs = new []int
|
||||
var i = 0
|
||||
while i < len(g_sn_tag) {
|
||||
let t = g_sn_tag[i]
|
||||
var seen = false
|
||||
var j = 0
|
||||
while j < len(tags) {
|
||||
if (tags[j] == t) { seen = true }
|
||||
j += 1
|
||||
}
|
||||
if not seen and sc_xml_uses(xml, t) {
|
||||
push(xs, len(tags))
|
||||
push(tags, t)
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
sc_sort(xs, tags)
|
||||
i = 0
|
||||
while i < len(xs) {
|
||||
if i > 0 { buf_puts(b, ", ") }
|
||||
jq_put(b, tags[xs[i]])
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
# `<tag` followed by a space, a '/' or a '>' somewhere in the template
|
||||
function sc_xml_uses(xml: pointer, tag: pointer) -> bool {
|
||||
if xml == null { return false }
|
||||
let n = len(xml)
|
||||
let m = len(tag)
|
||||
var i = 0
|
||||
while i + m + 1 < n {
|
||||
if xml[i] == '<' and xml[i + 1] == tag[0] and (xml[i + 1 .. i + 1 + m] == tag) {
|
||||
let e = xml[i + 1 + m]
|
||||
if e == ' ' or e == '/' or e == '>' or e == '\n' or e == '\t' or e == '\r' { return true }
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -34,11 +34,24 @@ var g_cm_cnames: [][]pointer = new [][]pointer
|
|||
var g_cm_head: []Node = new []Node
|
||||
var g_cm_hdr: []int = new []int # 0.S: where state parameters go (after the name)
|
||||
var g_cm_ps: [][]Node = new [][]Node # the states it declares
|
||||
# for the schema (emit_schema_ui.ludic): where the declaration and each prop or state are written,
|
||||
# a prop's or state's default as text offsets, a field's line, which calls are events, and the files
|
||||
var g_cm_at: [][]int = new [][]int # the `component` word: line, col, pos
|
||||
var g_cm_kat: [][]int = new [][]int # per prop or state: line, col, pos, sp0, sp1 (5 each)
|
||||
var g_cm_fline: [][]int = new [][]int
|
||||
var g_cm_isev: [][]bool = new [][]bool
|
||||
var g_cm_xml_path: []pointer = new []pointer
|
||||
var g_cm_lss_path: []pointer = new []pointer # "" when it has no stylesheet
|
||||
var g_cm_xml: []pointer = new []pointer
|
||||
|
||||
function cm_prefix(name: pointer) -> pointer { return `cmp_{reg_lower(name)}_` }
|
||||
|
||||
# component NAME { members }
|
||||
function parse_ui_component() -> void {
|
||||
let at = new []int
|
||||
push(at, toks[pi].line)
|
||||
push(at, toks[pi].col)
|
||||
push(at, toks[pi].pos)
|
||||
pi += 1
|
||||
let name = eat_id()
|
||||
push(g_cm_hdr, toks[pi - 1].end)
|
||||
|
|
@ -58,6 +71,13 @@ function parse_ui_component() -> void {
|
|||
push(g_cm_fnames, new []pointer)
|
||||
push(g_cm_calls, new []Node)
|
||||
push(g_cm_cnames, new []pointer)
|
||||
push(g_cm_at, at)
|
||||
push(g_cm_kat, new []int)
|
||||
push(g_cm_fline, new []int)
|
||||
push(g_cm_isev, new []bool)
|
||||
push(g_cm_xml_path, "")
|
||||
push(g_cm_lss_path, "")
|
||||
push(g_cm_xml, "")
|
||||
skipnl()
|
||||
eat_op("{")
|
||||
while true {
|
||||
|
|
@ -76,6 +96,11 @@ function parse_ui_component() -> void {
|
|||
function cm_member(c: int, px: pointer) -> void {
|
||||
if is_id("prop") or is_id("state") {
|
||||
let is_prop = is_id("prop")
|
||||
push(g_cm_kat[c], toks[pi].line)
|
||||
push(g_cm_kat[c], toks[pi].col)
|
||||
push(g_cm_kat[c], toks[pi].pos)
|
||||
var sp0 = -1
|
||||
var sp1 = -1
|
||||
pi += 1
|
||||
let fname = eat_id()
|
||||
eat_op(":")
|
||||
|
|
@ -86,8 +111,13 @@ function cm_member(c: int, px: pointer) -> void {
|
|||
var def: Node = null
|
||||
if is_op("=") {
|
||||
pi += 1
|
||||
let v0 = pi
|
||||
def = cm_getter(px + "def_" + fname, ty, expr())
|
||||
sp0 = toks[v0].off
|
||||
sp1 = toks[pi - 1].oend
|
||||
}
|
||||
push(g_cm_kat[c], sp0)
|
||||
push(g_cm_kat[c], sp1)
|
||||
if def != null { def.cm = c }
|
||||
push(g_cm_defs[c], def)
|
||||
return
|
||||
|
|
@ -98,11 +128,13 @@ function cm_member(c: int, px: pointer) -> void {
|
|||
let f = parse_fn()
|
||||
f.cm = c
|
||||
push(g_cm_cnames[c], f.s)
|
||||
push(g_cm_isev[c], ev)
|
||||
if ev { f.s = px + "on_" + f.s } else { f.s = px + f.s }
|
||||
push(g_cm_calls[c], f)
|
||||
push(prog, f)
|
||||
return
|
||||
}
|
||||
push(g_cm_fline[c], toks[pi].line)
|
||||
let fname = eat_id()
|
||||
var ty: pointer = null
|
||||
if is_op(":") {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ function cm_class(c: int, px: pointer, head: Node) -> void {
|
|||
lss = ""
|
||||
lss_at = ""
|
||||
} else { lss = cm_lss_inline(c, lss, dir, 0) }
|
||||
g_cm_xml_path[c] = xml_path
|
||||
g_cm_lss_path[c] = lss_at
|
||||
g_cm_xml[c] = xml
|
||||
var src = `function {px}class() -> UiClass {{\n let k = new UiClass\n k.name = "{name}"\n`
|
||||
src = src + ` k.xml_path = "{xml_path}"\n k.xml = {px}xml_text()\n k.lss_path = "{lss_at}"\n k.lss = {px}lss_text()\n`
|
||||
src = src + ` k.make = fn {px}new\n k.renew = fn {px}renew\n k.props = fn {px}props\n k.model = fn {px}model\n k.call = fn {px}call\n return k\n}}\n`
|
||||
|
|
|
|||
73819
selfhost/ludicc.seed.ll
73819
selfhost/ludicc.seed.ll
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -90,6 +90,7 @@ function selfhost_frags() -> []pointer {
|
|||
push(f, "selfhost/backend/emit_fnval.ludic")
|
||||
push(f, "selfhost/backend/emit_vis.ludic")
|
||||
push(f, "selfhost/backend/emit_schema.ludic")
|
||||
push(f, "selfhost/backend/emit_schema_ui.ludic")
|
||||
push(f, "selfhost/backend/emit_schema_hash.ludic")
|
||||
push(f, "selfhost/check/check_state.ludic")
|
||||
push(f, "selfhost/check/check_index.ludic")
|
||||
|
|
|
|||
|
|
@ -1240,6 +1240,12 @@ function cmd_dev_test() -> int {
|
|||
schema_case("lang/attributes", "\"fn_type\": \"fn(Tool,int)->float\", \"params\": [\"Tool\", \"int\"]", "--emit-schema: a function with arguments, its fn_type spelled as a field's")
|
||||
schema_case("lang/attributes", "{\"name\": \"Node\", \"args\": [\"tool\"]}", "--emit-schema: @Node and the field it reads its model from")
|
||||
schema_case("lang/attributes", "{\"name\": \"Ref\", \"args\": [\"Items\"], \"unresolved\": true}", "--emit-schema: an attribute whose target the program lacks is marked unresolved, not refused")
|
||||
schema_case("library/ui_component", "{\"name\": \"step\", \"type\": \"int\", \"default\": \"1\", \"file\": \"examples/library/ui_component_parts/Counter.ludic\", \"line\": 4, \"col\": 3, \"attributes\": [], \"doc\": \"how much one press adds\"}", "--emit-schema: a component's prop, with its default, place and doc")
|
||||
schema_case("library/ui_component", "\"xml\": \"examples/library/ui_component_parts/Counter.xml\", \"lss\": \"examples/library/ui_component_parts/Counter.lss\"", "--emit-schema: a component's template and stylesheet")
|
||||
schema_case("state/component", "\"states_read\": [\"Score\", \"Look\"]", "--emit-schema: the states a component's header names, apart from its model")
|
||||
schema_case("state/component", "{\"name\": \"add\", \"params\": [[\"n\", \"int\"]], \"line\": 8}", "--emit-schema: a component's event as the template calls it, its states and instance stripped")
|
||||
schema_case("library/ui_pointer", "{\"tag\": \"chartmap\", \"via\": \"ui_native_input\", \"handler\": \"map_input\", \"module\": null, \"file\": \"examples/library/ui_pointer.ludic\", \"line\": 35, \"col\": 5}", "--emit-schema: a native tag registered by a literal, and its handler")
|
||||
schema_case("library/ui_pointer", "\"natives\": [\"chartmap\"]}", "--emit-schema: the native tags a component's template uses")
|
||||
reject_case("rejected/registry_twice", "def Furnishings crate is declared twice", "a registry's key is declared once")
|
||||
reject_case("rejected/registry_field", "Furnishing has no field colour", "a def's fields are the record's")
|
||||
feat_case("modules/open_registry", "", "clock animals weather / 2 2 3", "open_registry.ludic (L8+L3: an open registry takes other modules' defs; its own entries first, then by module name)")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue