ludic/packages/ludic.ui/calc_terms.ludic
2026-09-24 21:53:44 +03:00

78 lines
2.3 KiB
Text

# calc_terms.ludic - calc()'s products and its terms: a number with its unit, a bracket, a nested
# calc(), a minus in front; a product or a quotient needs a plain number on one side (on the right
# of a /), as CSS's does
function ca_product() -> CaVal {
var a = ca_factor()
while ca_bad == "" {
ca_ws()
if ca_i >= len(ca_s) or (ca_s[ca_i] != 42 and ca_s[ca_i] != 47) { return a }
let div = ca_s[ca_i] == 47
ca_i += 1
let b = ca_factor()
if div and not b.bare {
ca_bad = "a plain number after /"
return a
}
if div and b.n == 0.0 {
ca_bad = "a number that is not 0 after /"
return a
}
if div { a = ca_scale(a, 1.0 / b.n) } else if a.bare { a = ca_scale(b, a.n) } else if b.bare { a = ca_scale(a, b.n) } else {
ca_bad = "a plain number on one side of *"
return a
}
}
return a
}
function ca_scale(a: CaVal, k: float) -> CaVal {
let r = new CaVal
r.bare = a.bare
r.n = a.n * k
r.px = a.px * k
r.pct = a.pct * k
return r
}
function ca_factor() -> CaVal {
ca_ws()
if ca_i >= len(ca_s) {
ca_bad = "a value"
return new CaVal
}
let c = ca_s[ca_i]
if c == 45 {
ca_i += 1
return ca_scale(ca_factor(), -1.0)
}
let f = ca_fn_at(ca_s, ca_i)
if f == "min" or f == "max" or f == "clamp" { return ca_fn(f) }
if c == 40 or f == "calc" {
while ca_s[ca_i] != 40 { ca_i += 1 }
ca_i += 1
let v = ca_sum()
ca_ws()
if ca_i < len(ca_s) and ca_s[ca_i] == 41 { ca_i += 1 } else if ca_bad == "" { ca_bad = "a closing )" }
return v
}
return ca_number()
}
# 12, 1.5em, 50%, 20vw
function ca_number() -> CaVal {
let at = ca_i
while ca_i < len(ca_s) and ((ca_s[ca_i] >= 48 and ca_s[ca_i] <= 57) or ca_s[ca_i] == 46) { ca_i += 1 }
let num_end = ca_i
while ca_i < len(ca_s) and ((ca_s[ca_i] >= 97 and ca_s[ca_i] <= 122) or ca_s[ca_i] == 37) { ca_i += 1 }
let r = new CaVal
if num_end == at {
ca_bad = "a number"
return r
}
let word: string = ca_s[at..ca_i]
let unit: string = ca_s[num_end..ca_i]
if unit == "" {
r.n = el_num(word)
return r
}
r.bare = false
if unit == "%" { r.pct = el_num(word) } else if unit == "px" or unit == "em" or unit == "rem" or unit == "vw" or unit == "vh" { r.px = el_unit(word) } else { ca_bad = `a unit calc() knows, not {unit}` }
return r
}