66 lines
2.9 KiB
Text
66 lines
2.9 KiB
Text
# eval.ludic - an expression's value, here
|
|
function ui_eval(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> Val {
|
|
if x.op == X_LIT { return x.v }
|
|
if x.op == X_NAME { return env_get(ui_st, e, x.s) }
|
|
if x.op == X_MEMBER {
|
|
let o = ui_eval(ui_st, x.a, e)
|
|
if Value.kind(o) == 6 and Value.has(o, x.s) != 0 { return Value.get(o, x.s) }
|
|
if Value.kind(o) == 5 and x.s == "length" { return uv_int(ui_st, Value.count(o)) }
|
|
ui_err(ui_st, `.{x.s}: there is no such field`)
|
|
return Value.null()
|
|
}
|
|
if x.op == X_INDEX { return Value.at(ui_eval(ui_st, x.a, e), Value.as_int(ui_eval(ui_st, x.b, e))) }
|
|
if x.op == X_CALL { return ev_call(ui_st, x, e) }
|
|
if x.op == X_NOT { return vl_bool(ui_st, not vl_truthy(ui_eval(ui_st, x.a, e))) }
|
|
if x.op == X_NEG { return vl_arith(ui_st, "-", mm_ival(ui_st, 0), ui_eval(ui_st, x.a, e)) }
|
|
if x.op == X_AND {
|
|
if not vl_truthy(ui_eval(ui_st, x.a, e)) { return vl_bool(ui_st, false) }
|
|
return vl_bool(ui_st, vl_truthy(ui_eval(ui_st, x.b, e)))
|
|
}
|
|
if x.op == X_OR {
|
|
if vl_truthy(ui_eval(ui_st, x.a, e)) { return vl_bool(ui_st, true) }
|
|
return vl_bool(ui_st, vl_truthy(ui_eval(ui_st, x.b, e)))
|
|
}
|
|
if x.op == X_COND {
|
|
if vl_truthy(ui_eval(ui_st, x.a, e)) { return ui_eval(ui_st, x.b, e) }
|
|
return ui_eval(ui_st, x.c, e)
|
|
}
|
|
if x.op == X_TEXT { return ev_text(ui_st, x, e) }
|
|
return vl_binary(ui_st, x.s, ui_eval(ui_st, x.a, e), ui_eval(ui_st, x.b, e))
|
|
}
|
|
# a call: len() and range() are the template's own, anything else is the view's
|
|
function ev_call(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> Val {
|
|
let depth = ui_st.ev_depth
|
|
while len(ui_st.ev_args) <= depth { push(ui_st.ev_args, Value.list()) }
|
|
let args = ui_st.ev_args[depth]
|
|
Value.clear(args)
|
|
ui_st.ev_depth = depth + 1
|
|
for i in 0 .. len(x.args) { Value.add(args, ui_eval(ui_st, x.args[i], e)) }
|
|
let r = ev_call_with(ui_st, x, e, args)
|
|
ui_st.ev_depth = depth
|
|
return r
|
|
}
|
|
# the call itself, its arguments evaluated; a callee reads them and keeps none
|
|
function ev_call_with(ui_st: mut UiState, x: UiExpr, e: UiEnv, args: Val) -> Val {
|
|
if x.s == "len" and len(x.args) == 1 { return uv_int(ui_st, Value.count(Value.at(args, 0))) }
|
|
if x.s == "range" and len(x.args) == 1 {
|
|
let out = uv_list(ui_st)
|
|
for i in 0 .. Value.as_int(Value.at(args, 0)) { Value.add(out, uv_int(ui_st, i)) }
|
|
return out
|
|
}
|
|
var at = e
|
|
while at != null {
|
|
if at.inst != null {
|
|
let r = at.inst.cls.call(at.inst.ptr, x.s, args)
|
|
if Value.kind(r) != 99 { return r }
|
|
}
|
|
at = at.parent
|
|
}
|
|
if ui_st.ui_view == null or ui_st.ui_view.call == null {
|
|
ui_err(ui_st, `{x.s}(): there is no function or event of that name here`)
|
|
return Value.null()
|
|
}
|
|
return ui_st.ui_view.call(x.s, args)
|
|
}
|
|
function ui_eval_text(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> string { return vl_text(ui_eval(ui_st, x, e)) }
|
|
function ui_eval_bool(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> bool { return vl_truthy(ui_eval(ui_st, x, e)) }
|