feat(lang): a component's event may be called set, a string prop reads a number, one name per component
- An action whose first word is `set` or `emit` followed by `(` is a call, so a component's
`on set(v: int)` is pressed as `set(4)`; `set x = ...` is still the action.
- A `string` prop (or state, or parameter) given a number in a template reads it as text through
ludic.ui's new `ui_val_text`; `label="{3}"` used to arrive as "".
- Two components of one name (or of names that differ only in case, which share their functions'
names) are an error at the second declaration that names the first's file and line, instead of a
"function cmp_x_def_y is defined twice".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
584e455f2d
commit
9ad6347044
7 changed files with 42113 additions and 41882 deletions
|
|
@ -1,5 +1,6 @@
|
|||
# act.ludic - what a press does: `buy(i)` asks the view, `set pick = i` changes a state, and
|
||||
# `emit picked` runs what the component's user said with on-picked. Several are `;` apart.
|
||||
# `emit picked` runs what the component's user said with on-picked. Several are `;` apart. A call
|
||||
# of a function named set or emit (`set(4)`, a component's `on set(v)`) is a call.
|
||||
const A_CALL: int = 0
|
||||
const A_SET: int = 1
|
||||
const A_EMIT: int = 2
|
||||
|
|
@ -18,12 +19,12 @@ function act_parse(src: string, err: []string) -> UiAct {
|
|||
while r.err == "" {
|
||||
rd_ws(r)
|
||||
if r.i >= len(r.s) { break }
|
||||
if rd_word(r, "set") {
|
||||
if act_keyword(r, "set") {
|
||||
push(a.kinds, A_SET)
|
||||
push(a.names, rd_name(r))
|
||||
if not rd_op(r, "=") { rd_fail(r, "'='") }
|
||||
push(a.exprs, px_cond(r))
|
||||
} else if rd_word(r, "emit") {
|
||||
} else if act_keyword(r, "emit") {
|
||||
push(a.kinds, A_EMIT)
|
||||
push(a.names, rd_name(r))
|
||||
push(a.exprs, null)
|
||||
|
|
@ -39,6 +40,17 @@ function act_parse(src: string, err: []string) -> UiAct {
|
|||
if r.err != "" { push(err, r.err) }
|
||||
return a
|
||||
}
|
||||
# `set` or `emit` as the action's first word - not a function of that name, as in `set(4)`
|
||||
function act_keyword(r: UiRd, word: string) -> bool {
|
||||
let at = r.i
|
||||
if not rd_word(r, word) { return false }
|
||||
rd_ws(r)
|
||||
if r.i < len(r.s) and r.s[r.i] == 40 {
|
||||
r.i = at
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
function act_run(a: UiAct, e: UiEnv) -> void {
|
||||
for i in 0 .. len(a.kinds) {
|
||||
if a.kinds[i] == A_SET { env_set(e, a.names[i], ui_eval(a.exprs[i], e)) }
|
||||
|
|
|
|||
|
|
@ -68,3 +68,6 @@ function vl_binary(op: string, a: Val, b: Val) -> Val {
|
|||
if op == ">" { return vl_bool(x > y) }
|
||||
return vl_bool(x >= y)
|
||||
}
|
||||
# a value as text, whatever kind it is: a component's string prop given a number (label="{3}") reads
|
||||
# "3", not nothing
|
||||
export function ui_val_text(v: Val) -> string { return vl_text(v) }
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ function cm_prefix(name: pointer) -> pointer { return `cmp_{reg_lower(name)}_` }
|
|||
function parse_ui_component() -> void {
|
||||
pi += 1
|
||||
let name = eat_id()
|
||||
cm_unique(name)
|
||||
let px = cm_prefix(name)
|
||||
g_uses_value = true
|
||||
let c = len(g_cm_name)
|
||||
|
|
|
|||
|
|
@ -76,3 +76,14 @@ function cm_import_of(line: pointer) -> pointer {
|
|||
while b < len(line) and line[b] != q { b += 1 }
|
||||
return line[a + 1..b]
|
||||
}
|
||||
# a component is used by its name as a tag, so two of one name (or of names that differ only in case,
|
||||
# which would share their functions' names) are an error naming both files
|
||||
function cm_unique(name: pointer) -> void {
|
||||
var i = 0
|
||||
while i < len(g_cm_name) {
|
||||
if (cm_prefix(g_cm_name[i]) == cm_prefix(name)) {
|
||||
perr(`component {name} is declared twice: here and in {g_cm_file[i]}:{g_cm_line[i]} - a component is used by its name as a tag, so each needs a name of its own`)
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ function cm_from(c: int, ty: pointer, x: pointer) -> pointer {
|
|||
if (ty == "int") { return `value_as_int({x})` }
|
||||
if (ty == "float") { return `value_as_float({x})` }
|
||||
if (ty == "bool") { return `value_as_int({x}) != 0` }
|
||||
if (ty == "string") { return `value_as_str({x})` }
|
||||
if (ty == "string") { return `ui_val_text({x})` }
|
||||
cm_err(c, `a prop or state is an int, a float, a bool, a string or a Val, not a {ty}`)
|
||||
return x
|
||||
}
|
||||
|
|
|
|||
41980
selfhost/ludicc.seed.ll
41980
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue