runtime, ludic.ui: a scalar Value is one allocation, not three (lists only for a list or an object); layout and cascade lists kept a depth; small numbers' text made once - benchmark 63 -> 36 KB a frame
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1d40f6d95a
commit
46888b6716
14 changed files with 84 additions and 33 deletions
|
|
@ -12,7 +12,7 @@ function el_apply(ui_st: mut UiState, n: UiNode, key: string, v0: Val) -> bool {
|
||||||
ui_st.el_cur = n
|
ui_st.el_cur = n
|
||||||
ui_st.el_key = k
|
ui_st.el_key = k
|
||||||
if len(k) > 2 and sat(k, 0, "--") {
|
if len(k) > 2 and sat(k, 0, "--") {
|
||||||
cs_var_set(n, k, vl_text(v0))
|
cs_var_set(n, k, vl_text_u(ui_st, v0))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let v = cs_vars_in(ui_st, n, v0)
|
let v = cs_vars_in(ui_st, n, v0)
|
||||||
|
|
@ -48,7 +48,7 @@ function el_size(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
function el_flex(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
function el_flex(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if key == "dir" {
|
if key == "dir" {
|
||||||
n.dir = UI_COL
|
n.dir = UI_COL
|
||||||
if s == "row" { n.dir = UI_ROW }
|
if s == "row" { n.dir = UI_ROW }
|
||||||
|
|
@ -56,7 +56,7 @@ function el_flex(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
function el_look(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
function el_look(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if key == "size" { n.size = el_len(ui_st, v) } else if key == "color" {
|
if key == "size" { n.size = el_len(ui_st, v) } else if key == "color" {
|
||||||
n.fg = ui_color(ui_st, s)
|
n.fg = ui_color(ui_st, s)
|
||||||
n.fg_a = ui_st.cl_alpha
|
n.fg_a = ui_st.cl_alpha
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ function el_sides(ui_st: mut UiState, v: Val) -> void {
|
||||||
ui_st.el_s0 = el_px(ui_st, Value.as_float(v))
|
ui_st.el_s0 = el_px(ui_st, Value.as_float(v))
|
||||||
n = 1
|
n = 1
|
||||||
} else {
|
} else {
|
||||||
let words = mm_words(ui_st, vl_text(v))
|
let words = mm_words(ui_st, vl_text_u(ui_st, v))
|
||||||
for i in 0 .. len(words) {
|
for i in 0 .. len(words) {
|
||||||
if len(words[i]) > 0 and n < 4 {
|
if len(words[i]) > 0 and n < 4 {
|
||||||
el_side_set(ui_st, n, el_word_len(ui_st, words[i]))
|
el_side_set(ui_st, n, el_word_len(ui_st, words[i]))
|
||||||
|
|
@ -43,7 +43,7 @@ function el_side_set(ui_st: mut UiState, i: int, v: float) -> void {
|
||||||
# a length: a number, 10px, 1.5em, 2rem, 50vw, calc(...), fill, fit or auto (a percentage is el_pct's)
|
# a length: a number, 10px, 1.5em, 2rem, 50vw, calc(...), fill, fit or auto (a percentage is el_pct's)
|
||||||
function el_len(ui_st: mut UiState, v: Val) -> float {
|
function el_len(ui_st: mut UiState, v: Val) -> float {
|
||||||
if vl_num(v) { return el_px(ui_st, Value.as_float(v)) }
|
if vl_num(v) { return el_px(ui_st, Value.as_float(v)) }
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if s == "fill" { return UI_FILL }
|
if s == "fill" { return UI_FILL }
|
||||||
if ca_is(s) { return el_calc_len(ui_st, s) }
|
if ca_is(s) { return el_calc_len(ui_st, s) }
|
||||||
if s == "fit" or s == "auto" or (len(s) > 0 and s[len(s) - 1] == 37) { return 0.0 }
|
if s == "fit" or s == "auto" or (len(s) > 0 and s[len(s) - 1] == 37) { return 0.0 }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# attr_edge.ludic - border-radius, outline (and its width, colour and offset), scrollbar-color
|
# attr_edge.ludic - border-radius, outline (and its width, colour and offset), scrollbar-color
|
||||||
function el_edge(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
function el_edge(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if key == "border-radius" { n.radius = el_len(ui_st, v) } else if key == "outline" { el_outline(ui_st, n, s) } else if key == "outline-width" { n.outline_w = el_len(ui_st, v) } else if key == "outline-offset" { n.outline_off = el_len(ui_st, v) } else if key == "outline-color" {
|
if key == "border-radius" { n.radius = el_len(ui_st, v) } else if key == "outline" { el_outline(ui_st, n, s) } else if key == "outline-width" { n.outline_w = el_len(ui_st, v) } else if key == "outline-offset" { n.outline_off = el_len(ui_st, v) } else if key == "outline-color" {
|
||||||
n.outline_c = ui_color(ui_st, s)
|
n.outline_c = ui_color(ui_st, s)
|
||||||
n.outline_a = ui_st.cl_alpha
|
n.outline_a = ui_st.cl_alpha
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# percentage is kept apart and taken of the containing block's width (left, right) or height (top,
|
# percentage is kept apart and taken of the containing block's width (left, right) or height (top,
|
||||||
# bottom) when the element is placed
|
# bottom) when the element is placed
|
||||||
function el_inset(ui_st: mut UiState, n: UiNode, side: int, v: Val) -> float {
|
function el_inset(ui_st: mut UiState, n: UiNode, side: int, v: Val) -> float {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
var pct = 0.0
|
var pct = 0.0
|
||||||
var px = UI_AUTO
|
var px = UI_AUTO
|
||||||
if s != "auto" {
|
if s != "auto" {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
# attr_more.ludic - width and height (where 0 is 0 and calc() may hold a percentage), the flex
|
# attr_more.ludic - width and height (where 0 is 0 and calc() may hold a percentage), the flex
|
||||||
# shorthand, flex-shrink, order, text-shadow, pointer-events, text-fit and line-height (text_fit.ludic)
|
# shorthand, flex-shrink, order, text-shadow, pointer-events, text-fit and line-height (text_fit.ludic)
|
||||||
function el_more(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
function el_more(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if key == "shrink" { nx(n).shrink = Math.max(el_num(s), 0.0) } else if key == "order" { nx(n).order = int(el_num(s)) } else if key == "text-shadow" { el_text_shadow(ui_st, n, s) } else if key == "pointer-events" { nx(n).no_pointer = tpl_words(s) == "none" } else if key == "text-fit" { el_text_fit(ui_st, n, s) } else if key == "line-height" { el_line_h(ui_st, n, s) } else { return el_fit_props(ui_st, n, key, s) }
|
if key == "shrink" { nx(n).shrink = Math.max(el_num(s), 0.0) } else if key == "order" { nx(n).order = int(el_num(s)) } else if key == "text-shadow" { el_text_shadow(ui_st, n, s) } else if key == "pointer-events" { nx(n).no_pointer = tpl_words(s) == "none" } else if key == "text-fit" { el_text_fit(ui_st, n, s) } else if key == "line-height" { el_line_h(ui_st, n, s) } else { return el_fit_props(ui_st, n, key, s) }
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
# width or height: a length (0 included), fill, a percentage, calc(), or auto/fit (none)
|
# width or height: a length (0 included), fill, a percentage, calc(), or auto/fit (none)
|
||||||
function el_dim(ui_st: mut UiState, n: UiNode, wide: bool, v: Val) -> void {
|
function el_dim(ui_st: mut UiState, n: UiNode, wide: bool, v: Val) -> void {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
var fixed = UI_AUTO
|
var fixed = UI_AUTO
|
||||||
var pct = 0.0
|
var pct = 0.0
|
||||||
var off = 0.0
|
var off = 0.0
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# attr_place.ludic - position and its insets, z-index, overflow, white-space and text-overflow
|
# attr_place.ludic - position and its insets, z-index, overflow, white-space and text-overflow
|
||||||
function el_place_prop(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
function el_place_prop(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if key == "position" {
|
if key == "position" {
|
||||||
n.pos = 0
|
n.pos = 0
|
||||||
if s == "relative" { n.pos = 1 }
|
if s == "relative" { n.pos = 1 }
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,12 @@ export state UiState {
|
||||||
pl_cur: UiPool = null
|
pl_cur: UiPool = null
|
||||||
mm: UiMemo = null # memo.ludic: splits, gradients and keys by their text
|
mm: UiMemo = null # memo.ludic: splits, gradients and keys by their text
|
||||||
mm_ints: []string = null
|
mm_ints: []string = null
|
||||||
|
ly_depth: int = 0 # layout_run.ludic: the lists a line lays out with, one a depth
|
||||||
|
ly_sizes: [][]float = new [][]float
|
||||||
|
ly_frozen: [][]bool = new [][]bool
|
||||||
|
cs_rules: []UiRule = new []UiRule # cascade_merge.ludic: a component root's rules, gathered
|
||||||
|
cs_envs: []UiEnv = new []UiEnv
|
||||||
|
cs_seen: []UiSheet = new []UiSheet
|
||||||
an_frames: []UiKeyframes = new []UiKeyframes
|
an_frames: []UiKeyframes = new []UiKeyframes
|
||||||
an_keys: []string = new []string
|
an_keys: []string = new []string
|
||||||
an_start: []float = new []float
|
an_start: []float = new []float
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,12 @@
|
||||||
# specificity as one sheet's are. On a tie the user's rule wins (the outermost user's last), as a
|
# specificity as one sheet's are. On a tie the user's rule wins (the outermost user's last), as a
|
||||||
# later rule does. Then `order`, which rearranges a flex box's children without touching the tree.
|
# later rule does. Then `order`, which rearranges a flex box's children without touching the tree.
|
||||||
function cs_merged(ui_st: mut UiState, n: UiNode) -> void {
|
function cs_merged(ui_st: mut UiState, n: UiNode) -> void {
|
||||||
let rules = new []UiRule
|
let rules = ui_st.cs_rules # kept and emptied: a merge runs once an element, never inside another
|
||||||
let envs = new []UiEnv
|
let envs = ui_st.cs_envs
|
||||||
let seen = new []UiSheet
|
let seen = ui_st.cs_seen
|
||||||
|
List.clear(rules)
|
||||||
|
List.clear(envs)
|
||||||
|
List.clear(seen)
|
||||||
if n.sheet != null { cs_gather(ui_st, n, n.sheet, n.env, rules, envs, seen) }
|
if n.sheet != null { cs_gather(ui_st, n, n.sheet, n.env, rules, envs, seen) }
|
||||||
for i in 0 .. len(n.ups) {
|
for i in 0 .. len(n.ups) {
|
||||||
if n.ups[i].sheet != null { cs_gather(ui_st, n, n.ups[i].sheet, n.ups[i].env, rules, envs, seen) }
|
if n.ups[i].sheet != null { cs_gather(ui_st, n, n.ups[i].sheet, n.ups[i].env, rules, envs, seen) }
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ function bd_elem(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string) -> UiNode
|
||||||
n.sheet = k.sheet
|
n.sheet = k.sheet
|
||||||
n.style = k.style
|
n.style = k.style
|
||||||
el_kind(ui_st, n, k.tag)
|
el_kind(ui_st, n, k.tag)
|
||||||
for i in 0 .. len(k.keys) { el_keep(n, k.keys[i], ui_eval(ui_st, k.vals[i], e)) }
|
for i in 0 .. len(k.keys) { el_keep(ui_st, n, k.keys[i], ui_eval(ui_st, k.vals[i], e)) }
|
||||||
n.hovered = fr_was_hovered(ui_st, key)
|
n.hovered = fr_was_hovered(ui_st, key)
|
||||||
n.on_names = k.on_keys
|
n.on_names = k.on_keys
|
||||||
n.on_acts = k.on_acts
|
n.on_acts = k.on_acts
|
||||||
|
|
@ -52,8 +52,8 @@ function el_text(ui_st: mut UiState, n: UiNode, s: string) -> void {
|
||||||
push(n.children, t)
|
push(n.children, t)
|
||||||
}
|
}
|
||||||
# id, class, hidden, disabled and src say what the element is; the rest are applied after the rules
|
# id, class, hidden, disabled and src say what the element is; the rest are applied after the rules
|
||||||
function el_keep(n: UiNode, key: string, v: Val) -> void {
|
function el_keep(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> void {
|
||||||
let s = vl_text(v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if key == "id" { n.id = s } else if key == "class" {
|
if key == "id" { n.id = s } else if key == "class" {
|
||||||
let parts = lss_split(s, 32)
|
let parts = lss_split(s, 32)
|
||||||
for i in 0 .. len(parts) {
|
for i in 0 .. len(parts) {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export function ui_nodes(ui_st: mut UiState, screen: string, view: UiView) -> Ui
|
||||||
root.sheet = t.sheet
|
root.sheet = t.sheet
|
||||||
root.tag = "screen"
|
root.tag = "screen"
|
||||||
for i in 0 .. len(t.keys) {
|
for i in 0 .. len(t.keys) {
|
||||||
if t.keys[i] != "name" { el_keep(root, t.keys[i], ui_eval(ui_st, t.vals[i], e)) }
|
if t.keys[i] != "name" { el_keep(ui_st, root, t.keys[i], ui_eval(ui_st, t.vals[i], e)) }
|
||||||
}
|
}
|
||||||
bd_kids(ui_st, t.kids, e, screen, root.children)
|
bd_kids(ui_st, t.kids, e, screen, root.children)
|
||||||
cs_tree(ui_st, root)
|
cs_tree(ui_st, root)
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ function ly_place_line(ui_st: mut UiState, n: UiNode, from: int, to: int, top: f
|
||||||
var used = 0.0
|
var used = 0.0
|
||||||
var grows = 0.0
|
var grows = 0.0
|
||||||
var count = 0
|
var count = 0
|
||||||
let sizes = new []float
|
let depth = ui_st.ly_depth
|
||||||
|
ui_st.ly_depth += 1
|
||||||
|
let sizes = ly_scratch(ui_st, depth)
|
||||||
for i in from .. to {
|
for i in from .. to {
|
||||||
push(sizes, ly_basis(n.children[i], n.dir, main_room))
|
push(sizes, ly_basis(n.children[i], n.dir, main_room))
|
||||||
if n.children[i].pos < 2 {
|
if n.children[i].pos < 2 {
|
||||||
|
|
@ -52,7 +54,7 @@ function ly_place_line(ui_st: mut UiState, n: UiNode, from: int, to: int, top: f
|
||||||
}
|
}
|
||||||
used = used + n.gap * float(Math.max(count - 1, 0))
|
used = used + n.gap * float(Math.max(count - 1, 0))
|
||||||
let free = main_room - used
|
let free = main_room - used
|
||||||
if free < 0.0 { ly_shrink_line(n, from, sizes, 0.0 - free) }
|
if free < 0.0 { ly_shrink_line(ui_st, depth, n, from, sizes, 0.0 - free) }
|
||||||
ly_justify(ui_st, n, free, count, grows)
|
ly_justify(ui_st, n, free, count, grows)
|
||||||
let extra = ui_st.ly_extra
|
let extra = ui_st.ly_extra
|
||||||
var at = ui_st.ly_lead
|
var at = ui_st.ly_lead
|
||||||
|
|
@ -65,6 +67,17 @@ function ly_place_line(ui_st: mut UiState, n: UiNode, from: int, to: int, top: f
|
||||||
if c.pos == 1 { ly_nudge(n, c) }
|
if c.pos == 1 { ly_nudge(n, c) }
|
||||||
at = at + m + n.gap + extra
|
at = at + m + n.gap + extra
|
||||||
}
|
}
|
||||||
|
ui_st.ly_depth = depth
|
||||||
|
}
|
||||||
|
# a line's sizes, and its shrink's frozen flags, in lists kept one a depth (a line's children lay out
|
||||||
|
# their own lines while it is still placing them), emptied rather than made anew
|
||||||
|
function ly_scratch(ui_st: mut UiState, depth: int) -> []float {
|
||||||
|
while len(ui_st.ly_sizes) <= depth {
|
||||||
|
push(ui_st.ly_sizes, new []float)
|
||||||
|
push(ui_st.ly_frozen, new []bool)
|
||||||
|
}
|
||||||
|
List.clear(ui_st.ly_sizes[depth])
|
||||||
|
return ui_st.ly_sizes[depth]
|
||||||
}
|
}
|
||||||
# one child: `m` along the run and its own size (or the whole room, stretched) across, less margins
|
# one child: `m` along the run and its own size (or the whole room, stretched) across, less margins
|
||||||
function ly_place_child(ui_st: mut UiState, n: UiNode, c: UiNode, at: float, top: float, m: float, cross_room: float) -> void {
|
function ly_place_child(ui_st: mut UiState, n: UiNode, c: UiNode, at: float, top: float, m: float, cross_room: float) -> void {
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,10 @@ function ly_min_h(c: UiNode) -> float {
|
||||||
return c.mh
|
return c.mh
|
||||||
}
|
}
|
||||||
# `sizes` (the children from..to) shrunk by `over` in all
|
# `sizes` (the children from..to) shrunk by `over` in all
|
||||||
function ly_shrink_line(n: UiNode, from: int, sizes: []float, over0: float) -> void {
|
function ly_shrink_line(ui_st: mut UiState, depth: int, n: UiNode, from: int, sizes: []float, over0: float) -> void {
|
||||||
var over = over0
|
var over = over0
|
||||||
let frozen = new []bool
|
let frozen = ui_st.ly_frozen[depth]
|
||||||
|
List.clear(frozen)
|
||||||
for k in 0 .. len(sizes) { push(frozen, n.children[from + k].pos >= 2) }
|
for k in 0 .. len(sizes) { push(frozen, n.children[from + k].pos >= 2) }
|
||||||
for pass in 0 .. 8 {
|
for pass in 0 .. 8 {
|
||||||
var wsum = 0.0
|
var wsum = 0.0
|
||||||
|
|
|
||||||
|
|
@ -71,3 +71,14 @@ function vl_binary(op: string, a: Val, b: Val) -> Val {
|
||||||
# a value as text, whatever kind it is: a component's string prop given a number (label="{3}") reads
|
# a value as text, whatever kind it is: a component's string prop given a number (label="{3}") reads
|
||||||
# "3", not nothing
|
# "3", not nothing
|
||||||
export function ui_val_text(v: Val) -> string { return vl_text(v) }
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,22 @@ property Val {
|
||||||
kids: []Val
|
kids: []Val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# a number, a string or a null is one record; only a list or an object carries lists (made when first
|
||||||
|
# filled) - three allocations for every scalar was most of what a UI frame made and never gave back
|
||||||
function value_new(tag: int) -> Val {
|
function value_new(tag: int) -> Val {
|
||||||
let v = new Val
|
let v = new Val
|
||||||
v.tag = tag
|
v.tag = tag
|
||||||
|
if tag == 5 or tag == 6 { value_lists(v) }
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
function value_lists(v: Val) -> void {
|
||||||
|
if v.kids != null { return }
|
||||||
v.keys = new []pointer
|
v.keys = new []pointer
|
||||||
v.kids = new []Val
|
v.kids = new []Val
|
||||||
return v
|
}
|
||||||
|
function value_n(v: Val) -> int {
|
||||||
|
if v.kids == null { return 0 }
|
||||||
|
return len(v.kids)
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- constructors -----------------------------------------------------------
|
# --- constructors -----------------------------------------------------------
|
||||||
|
|
@ -43,8 +53,13 @@ function value_float(x: float) -> Val { let v = value_new(7); v.num = float_bits
|
||||||
function value_object() -> Val { return value_new(6) }
|
function value_object() -> Val { return value_new(6) }
|
||||||
|
|
||||||
# --- builders (return the container, so calls chain) ------------------------
|
# --- builders (return the container, so calls chain) ------------------------
|
||||||
function value_add(list: Val, item: Val) -> Val { push(list.kids, item); return list }
|
function value_add(list: Val, item: Val) -> Val {
|
||||||
|
value_lists(list)
|
||||||
|
push(list.kids, item)
|
||||||
|
return list
|
||||||
|
}
|
||||||
function value_put(obj: Val, key: pointer, item: Val) -> Val {
|
function value_put(obj: Val, key: pointer, item: Val) -> Val {
|
||||||
|
value_lists(obj)
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(obj.keys) { if obj.keys[i] == key { obj.kids[i] = item; return obj }; i += 1 }
|
while i < len(obj.keys) { if obj.keys[i] == key { obj.kids[i] = item; return obj }; i += 1 }
|
||||||
push(obj.keys, key); push(obj.kids, item)
|
push(obj.keys, key); push(obj.kids, item)
|
||||||
|
|
@ -53,7 +68,7 @@ function value_put(obj: Val, key: pointer, item: Val) -> Val {
|
||||||
|
|
||||||
# --- accessors --------------------------------------------------------------
|
# --- accessors --------------------------------------------------------------
|
||||||
function value_kind(v: Val) -> int { return v.tag }
|
function value_kind(v: Val) -> int { return v.tag }
|
||||||
function value_count(v: Val) -> int { return len(v.kids) }
|
function value_count(v: Val) -> int { return value_n(v) }
|
||||||
function value_as_int(v: Val) -> int {
|
function value_as_int(v: Val) -> int {
|
||||||
if v.tag == 7 { return int(float_from_bits(v.num)) }
|
if v.tag == 7 { return int(float_from_bits(v.num)) }
|
||||||
return v.num
|
return v.num
|
||||||
|
|
@ -66,21 +81,21 @@ function value_as_float(v: Val) -> float {
|
||||||
}
|
}
|
||||||
function value_as_str(v: Val) -> string { if v.txt == null { return "" }; return v.txt }
|
function value_as_str(v: Val) -> string { if v.txt == null { return "" }; return v.txt }
|
||||||
function value_at(list: Val, i: int) -> Val {
|
function value_at(list: Val, i: int) -> Val {
|
||||||
if i < 0 or i >= len(list.kids) { return value_null() }
|
if i < 0 or i >= value_n(list) { return value_null() }
|
||||||
return list.kids[i]
|
return list.kids[i]
|
||||||
}
|
}
|
||||||
function value_key_at(obj: Val, i: int) -> string {
|
function value_key_at(obj: Val, i: int) -> string {
|
||||||
if i < 0 or i >= len(obj.keys) { return "" }
|
if i < 0 or i >= value_n(obj) { return "" }
|
||||||
return obj.keys[i]
|
return obj.keys[i]
|
||||||
}
|
}
|
||||||
function value_get(obj: Val, key: pointer) -> Val {
|
function value_get(obj: Val, key: pointer) -> Val {
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(obj.keys) { if obj.keys[i] == key { return obj.kids[i] }; i += 1 }
|
while i < value_n(obj) { if obj.keys[i] == key { return obj.kids[i] }; i += 1 }
|
||||||
return value_null()
|
return value_null()
|
||||||
}
|
}
|
||||||
function value_has(obj: Val, key: pointer) -> int {
|
function value_has(obj: Val, key: pointer) -> int {
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(obj.keys) { if obj.keys[i] == key { return 1 }; i += 1 }
|
while i < value_n(obj) { if obj.keys[i] == key { return 1 }; i += 1 }
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,7 +147,7 @@ function json_encode(v: Val) -> string {
|
||||||
if v.tag == 5 {
|
if v.tag == 5 {
|
||||||
var out = "["
|
var out = "["
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(v.kids) {
|
while i < value_n(v) {
|
||||||
if i > 0 { out += "," }
|
if i > 0 { out += "," }
|
||||||
out += json_encode(v.kids[i])
|
out += json_encode(v.kids[i])
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -141,7 +156,7 @@ function json_encode(v: Val) -> string {
|
||||||
}
|
}
|
||||||
var out = "{"
|
var out = "{"
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(v.keys) {
|
while i < value_n(v) {
|
||||||
if i > 0 { out += "," }
|
if i > 0 { out += "," }
|
||||||
out = out + json_quote(v.keys[i]) + ":" + json_encode(v.kids[i])
|
out = out + json_quote(v.keys[i]) + ":" + json_encode(v.kids[i])
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -176,9 +191,11 @@ function json_parse(s: pointer) -> Val {
|
||||||
# a node or hold a literal, is not for this (Ludic has no collector; plan 23 of maroon-lake).
|
# a node or hold a literal, is not for this (Ludic has no collector; plan 23 of maroon-lake).
|
||||||
function value_free(v: Val) -> void {
|
function value_free(v: Val) -> void {
|
||||||
if v == null { return }
|
if v == null { return }
|
||||||
for i in 0 .. len(v.kids) { value_free(v.kids[i]) }
|
if v.kids != null {
|
||||||
free(v.kids)
|
for i in 0 .. len(v.kids) { value_free(v.kids[i]) }
|
||||||
free(v.keys)
|
free(v.kids)
|
||||||
|
free(v.keys)
|
||||||
|
}
|
||||||
free(v)
|
free(v)
|
||||||
}
|
}
|
||||||
function json_free(v: Val) -> void { value_free(v) }
|
function json_free(v: Val) -> void { value_free(v) }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue