feat(lang): L11 views and templates - the UI is markup, not code
A `view Name { field = x; function q(..); on e(..) }` declaration is the one bridge between a
program and its UI: it writes view_<name>() -> UiView, whose model is a Value of every field and
whose call runs a query or an event by name.
ludic.ui is a template runtime:
- HTML-shaped XML screens and components, loaded at run time;
- {expression} bindings, if/else/each, props, slots, per-instance state;
- on-press / onclick actions (event, set, emit);
- component libraries (export="true", <import src as>).
Styling:
- stylesheets in <style> or importable .lss files (@import);
- CSS selectors (#id, .class, [attr=v], descendant and > combinators, :hover, :disabled,
:first-child, :last-child, :nth-child, :not) weighed by specificity;
- the box model and flex under CSS's property names.
Also:
- default parameters, and positional-then-named calls;
- Value gains a float kind;
- a function shadowing a runtime one is refused;
- an index is evaluated before the slice is read;
- runtime errors name the right file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
334469ef61
commit
66a2bc2214
64 changed files with 74806 additions and 63975 deletions
|
|
@ -13,6 +13,7 @@ function ck_params(f: Node, labels: []pointer, tys: []pointer) -> void {
|
|||
}
|
||||
}
|
||||
function ck_call_fn(e: Node, name: pointer, f: Node) -> pointer {
|
||||
call_fill_defaults(e, f)
|
||||
let labels = new []pointer
|
||||
let tys = new []pointer
|
||||
ck_params(f, labels, tys)
|
||||
|
|
@ -21,6 +22,7 @@ function ck_call_fn(e: Node, name: pointer, f: Node) -> pointer {
|
|||
return f.ty
|
||||
}
|
||||
function ck_call_alias(e: Node, name: pointer, al: int, f: Node) -> pointer {
|
||||
if g_al_labels[al] == null { call_fill_defaults(e, f) } else { call_mixed_to_named(e, ns_alias_labels(al)) }
|
||||
let labels = new []pointer
|
||||
let tys = new []pointer
|
||||
ck_params(f, labels, tys)
|
||||
|
|
@ -50,11 +52,18 @@ function ck_args(e: Node, name: pointer, labels: []pointer, tys: []pointer) -> v
|
|||
let vt = ck_expr(fi.a)
|
||||
let at = ck_label_at(labels, fi.s)
|
||||
if at >= 0 { ck_give(tys[at], vt, fi.a, `argument {fi.s} of {name}`) }
|
||||
if at < 0 and len(labels) > 0 { ck_err("arity", fi.a, `{name} has no parameter {fi.s}`) }
|
||||
j += 1
|
||||
}
|
||||
var m = 0
|
||||
while m < len(labels) {
|
||||
if not ck_named_has(e, labels[m]) { ck_err("arity", e, `this call to {name} leaves out {labels[m]}, which has no default`) }
|
||||
m += 1
|
||||
}
|
||||
return
|
||||
}
|
||||
if n != len(tys) { ck_err("arity", e, `{name} takes {itoa(len(tys))} argument(s) and this call gives {itoa(n)}`) }
|
||||
if n < len(tys) and len(labels) == len(tys) { ck_err("arity", e, `this call to {name} leaves out {labels[n]}, which has no default`) }
|
||||
else { if n != len(tys) { ck_err("arity", e, `{name} takes {itoa(len(tys))} argument(s) and this call gives {itoa(n)}`) } }
|
||||
var i = 0
|
||||
while i < n {
|
||||
if i < len(tys) { ck_expect = tys[i] }
|
||||
|
|
@ -63,6 +72,14 @@ function ck_args(e: Node, name: pointer, labels: []pointer, tys: []pointer) -> v
|
|||
i += 1
|
||||
}
|
||||
}
|
||||
function ck_named_has(e: Node, label: pointer) -> bool {
|
||||
var i = 0
|
||||
while i < len(e.kids) {
|
||||
if (e.kids[i].s == label) { return true }
|
||||
i += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
function ck_walk_args(e: Node) -> void {
|
||||
var i = 0
|
||||
while i < len(e.kids) {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ function gen_arg_nodes(e: Node, labels: []pointer) -> []Node {
|
|||
}
|
||||
function gen_call(e: Node, name: pointer, t: Node) -> pointer {
|
||||
let expect = ck_call_expect
|
||||
call_fill_defaults(e, t)
|
||||
let tps = gen_split(t.tps)
|
||||
let labels = new []pointer
|
||||
let ptys = new []pointer
|
||||
|
|
|
|||
|
|
@ -147,10 +147,24 @@ function ck_listener(l: Node) -> void {
|
|||
ck_block(l.a)
|
||||
ck_pop(m)
|
||||
}
|
||||
# a program's function named like one of the runtime's takes every call the runtime makes to its
|
||||
# own - the runtime's ui_measure started answering to a package's - so the name is refused
|
||||
function ck_runtime_shadows() -> void {
|
||||
var r = g_prog_user_end
|
||||
while r < len(prog) {
|
||||
let d = prog[r]
|
||||
if d.kind == N_FN {
|
||||
let u = ck_fn(d.s)
|
||||
if u != null and u != d { ck_err("shadow", u, `{d.s} is also a function of the engine runtime ({d.file}); choose another name`) }
|
||||
}
|
||||
r += 1
|
||||
}
|
||||
}
|
||||
# the pass also makes the generics real (check_gen.ludic), so it always runs
|
||||
function check_program() -> void {
|
||||
gen_collect()
|
||||
ck_index()
|
||||
ck_runtime_shadows()
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let d = prog[i]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue