# 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)) }