- 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>
74 lines
2.1 KiB
Text
74 lines
2.1 KiB
Text
# 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. 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
|
|
export property UiAct {
|
|
kinds: []int = null
|
|
names: []string = null
|
|
exprs: []UiExpr = null
|
|
}
|
|
function act_parse(src: string, err: []string) -> UiAct {
|
|
let a = new UiAct
|
|
a.kinds = new []int
|
|
a.names = new []string
|
|
a.exprs = new []UiExpr
|
|
let r = new UiRd
|
|
r.s = src
|
|
while r.err == "" {
|
|
rd_ws(r)
|
|
if r.i >= len(r.s) { break }
|
|
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 act_keyword(r, "emit") {
|
|
push(a.kinds, A_EMIT)
|
|
push(a.names, rd_name(r))
|
|
push(a.exprs, null)
|
|
} else {
|
|
push(a.kinds, A_CALL)
|
|
push(a.names, "")
|
|
push(a.exprs, px_cond(r))
|
|
}
|
|
if not rd_op(r, ";") { break }
|
|
}
|
|
rd_ws(r)
|
|
if r.err == "" and r.i < len(r.s) { rd_fail(r, "';' or the end") }
|
|
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)) }
|
|
if a.kinds[i] == A_CALL { ui_eval(a.exprs[i], e) }
|
|
if a.kinds[i] == A_EMIT { act_emit(a.names[i], e) }
|
|
}
|
|
}
|
|
function act_emit(name: string, e: UiEnv) -> void {
|
|
var at = e
|
|
while at != null {
|
|
if at.on_names != null {
|
|
for i in 0 .. len(at.on_names) {
|
|
if at.on_names[i] == name {
|
|
act_run(at.on_acts[i], at.on_envs[i])
|
|
return
|
|
}
|
|
}
|
|
}
|
|
at = at.parent
|
|
}
|
|
}
|