ludic/packages/ludic.ui/values.ludic

82 lines
3.6 KiB
Text

# values.ludic - arithmetic, comparison, truth and text over a template's values. A sum of two
# whole numbers stays whole; anything with a fraction in it is a float; a string in a sum joins.
function vl_bool(ui_st: mut UiState, b: bool) -> Val { return uv_bool(ui_st, b) }
function vl_num(v: Val) -> bool { return Value.kind(v) == 1 or Value.kind(v) == 2 or Value.kind(v) == 7 }
function vl_truthy(v: Val) -> bool {
let k = Value.kind(v)
if k == 0 { return false }
if k == 1 or k == 3 { return Value.as_int(v) != 0 }
if k == 2 or k == 7 { return Value.as_float(v) != 0.0 }
if k == 4 { return len(Value.as_str(v)) > 0 }
return true
}
function vl_text(v: Val) -> string {
let k = Value.kind(v)
if k == 0 { return "" }
if k == 1 or k == 2 or k == 7 { return Value.num_text(v) } # kept on the Value until it changes
if k == 3 {
if Value.as_int(v) != 0 { return "true" }
return "false"
}
if k == 4 { return Value.as_str(v) }
return Json.encode(v)
}
function vl_arith(ui_st: mut UiState, op: string, a: Val, b: Val) -> Val {
if Value.kind(a) == 1 and Value.kind(b) == 1 {
let x = Value.as_int(a)
let y = Value.as_int(b)
if op == "+" { return uv_int(ui_st, x + y) }
if op == "-" { return uv_int(ui_st, x - y) }
if op == "*" { return uv_int(ui_st, x * y) }
if y == 0 { return uv_int(ui_st, 0) }
if op == "/" { return uv_int(ui_st, x / y) }
return uv_int(ui_st, x % y)
}
let x = Value.as_float(a)
let y = Value.as_float(b)
if op == "+" { return uv_float(ui_st, x + y) }
if op == "-" { return uv_float(ui_st, x - y) }
if op == "*" { return uv_float(ui_st, x * y) }
if y == 0.0 { return uv_float(ui_st, 0.0) }
if op == "/" { return uv_float(ui_st, x / y) }
return uv_float(ui_st, x - y * float(int(x / y)))
}
function vl_equal(a: Val, b: Val) -> bool {
if vl_num(a) and vl_num(b) { return Value.as_float(a) == Value.as_float(b) }
if Value.kind(a) != Value.kind(b) { return false }
if Value.kind(a) == 4 { return Value.as_str(a) == Value.as_str(b) }
if Value.kind(a) == 3 { return Value.as_int(a) == Value.as_int(b) }
return Value.kind(a) == 0
}
function vl_binary(ui_st: mut UiState, op: string, a: Val, b: Val) -> Val {
if op == "==" { return vl_bool(ui_st, vl_equal(a, b)) }
if op == "!=" { return vl_bool(ui_st, not vl_equal(a, b)) }
if op == "+" and (Value.kind(a) == 4 or Value.kind(b) == 4) { return uv_str(ui_st, vl_text_u(ui_st, a) + vl_text_u(ui_st, b)) }
if op == "+" or op == "-" or op == "*" or op == "/" or op == "%" { return vl_arith(ui_st, op, a, b) }
let x = Value.as_float(a)
let y = Value.as_float(b)
if op == "<" { return vl_bool(ui_st, x < y) }
if op == "<=" { return vl_bool(ui_st, x <= y) }
if op == ">" { return vl_bool(ui_st, x > y) }
return vl_bool(ui_st, 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) }
# vl_text for what is asked per element per frame: a small whole number's text comes from the table
# made once (mm_int) rather than being written out again
function vl_text_u(ui_st: mut UiState, v: Val) -> string {
let k = Value.kind(v)
if k == 1 { return mm_int(ui_st, Value.as_int(v)) }
if k == 2 or k == 7 {
let f = Value.as_float(v)
if f == float(int(f)) { return mm_int(ui_st, int(f)) }
}
return vl_text(v)
}
# a value as a number: a number read as one, only text parsed (a float's text written per frame to be
# read straight back was a leak - an animation's opacity, a flex-grow)
function el_numv(ui_st: mut UiState, v: Val) -> float {
if vl_num(v) { return Value.as_float(v) }
return el_num(vl_text_u(ui_st, v))
}