diff --git a/packages/ludic.ui/anim.ludic b/packages/ludic.ui/anim.ludic index 505c1d2e..8dbcf165 100644 --- a/packages/ludic.ui/anim.ludic +++ b/packages/ludic.ui/anim.ludic @@ -23,15 +23,23 @@ function an_read(ui_st: mut UiState, name: string, body: string, err: []string) while r.err == "" { rd_ws(r) if r.i >= len(r.s) { break } - let stop = tpl_words(lss_upto(r, 123)) - let decls = lss_decls(lss_upto(r, 125), err) + let sr = lss_upto(r, 123) + let stop = tpl_words(sr) + let db = lss_upto(r, 125) + let decls = lss_decls(db, err) var at = el_num(stop) / 100.0 if stop == "from" { at = 0.0 } if stop == "to" { at = 1.0 } push(k.stops, at) push(k.rules, decls) + unsafe { # the stop and its body are read, never kept + if not tpl_clean(sr) { free(stop) } + free(sr) + free(db) + } } push(ui_st.an_frames, k) + unsafe { free(r) } } function an_find(ui_st: UiState, name: string) -> UiKeyframes { for i in 0 .. len(ui_st.an_frames) { diff --git a/packages/ludic.ui/style.ludic b/packages/ludic.ui/style.ludic index 433a3cf4..00dcbd58 100644 --- a/packages/ludic.ui/style.ludic +++ b/packages/ludic.ui/style.ludic @@ -51,13 +51,17 @@ function lss_block(ui_st: mut UiState, f: UiFile, src: string, md: UiMedia, err: continue } if rd_op(r, "@keyframes") { - let name = lss_upto(r, 123) - an_read(ui_st, name, lss_upto(r, 125), err) + let name = lss_upto(r, 123) # kept: the keyframes' name may be this very text + let kb = lss_upto(r, 125) + an_read(ui_st, name, kb, err) + unsafe { free(kb) } continue } if rd_op(r, "@media") { let cond = md_parse(lss_upto(r, 123)) - lss_block(ui_st, f, lss_upto(r, 125), cond, err) + let mb = lss_upto(r, 125) + lss_block(ui_st, f, mb, cond, err) + unsafe { free(mb) } continue } let sels = lss_upto(r, 123) @@ -65,6 +69,10 @@ function lss_block(ui_st: mut UiState, f: UiFile, src: string, md: UiMedia, err: let at = len(f.own) lss_rule(f, sels, body, err) for i in at .. len(f.own) { f.own[i].md = md } + unsafe { # a rule keeps what it parsed, never the text it was sliced from + free(sels) + free(body) + } } if r.err != "" { push(err, r.err) } unsafe { free(r) } # the reader only: its text is the caller's @@ -95,20 +103,25 @@ function lss_upto(r: UiRd, c: int) -> string { } function lss_strip(src: string) -> string { if not lss_has_comment(src) { return src } # no comment: nothing to strip, nothing made - var out = "" - var at = 0 + # written once into bytes of its own (lss_text frees them): joined a piece at a time, every + # comment left the text so far behind + var p: pointer = null + unsafe { p = bytes(len(src) + 1) } + var n = 0 var i = 0 - while i + 1 < len(src) { - if src[i] == 47 and src[i + 1] == 42 { - out = out + src[at..i] + while i < len(src) { + if i + 1 < len(src) and src[i] == 47 and src[i + 1] == 42 { var j = i + 2 while j + 1 < len(src) and not (src[j] == 42 and src[j + 1] == 47) { j += 1 } i = j + 2 - at = i - } else { i += 1 } + } else { + unsafe { p[n] = src[i] } + n += 1 + i += 1 + } } - if at < len(src) { out = out + src[at..len(src)] } - return out + unsafe { p[n] = 0 } + return p } function lss_has_comment(src: string) -> bool { for i in 0 .. len(src) - 1 { diff --git a/packages/ludic.ui/style_rule.ludic b/packages/ludic.ui/style_rule.ludic index 45c30e18..4243927c 100644 --- a/packages/ludic.ui/style_rule.ludic +++ b/packages/ludic.ui/style_rule.ludic @@ -4,16 +4,23 @@ function lss_rule(f: UiFile, sels: string, body: string, err: []string) -> void let each = lss_split(sels, 44) for i in 0 .. len(each) { let sel = tpl_words(each[i]) - if len(sel) == 0 { continue } - let r = new UiRule - r.keys = decls.keys - r.vals = decls.vals - r.sel = sel_parse(sel, err) - if r.sel != null { - r.spec = sel_spec(r.sel) - push(f.own, r) + if len(sel) > 0 { lss_rule_add(f, decls, sel, err) } + unsafe { # a selector keeps its parsed parts, never its text + if not tpl_clean(each[i]) { free(sel) } + free(each[i]) } } + unsafe { free(each) } +} +function lss_rule_add(f: UiFile, decls: UiRule, sel: string, err: []string) -> void { + let r = new UiRule + r.keys = decls.keys + r.vals = decls.vals + r.sel = sel_parse(sel, err) + if r.sel != null { + r.spec = sel_spec(r.sel) + push(f.own, r) + } } # `key: value; key: value`, a rule's body or a style="..." attribute function lss_decls(body: string, err: []string) -> UiRule { @@ -31,8 +38,11 @@ function lss_decls(body: string, err: []string) -> UiRule { if len(tpl_words(d)) > 0 { push(err, `"{tpl_words(d)}" is not a property: value`) } continue } - push(r.keys, tpl_words(d[0..colon])) - push(r.vals, tpl_value(tpl_words(d[colon + 1..len(d)]), err)) + lss_decl_add(r, d, colon, err) + } + unsafe { # the pieces the declarations were sliced from + for i in 0 .. len(decls) { free(decls[i]) } + free(decls) } return r } @@ -70,3 +80,18 @@ function sheet_add(sh: UiSheet, r: UiRule) -> void { } sh.rules[i] = r } + +# one `key: value` into the rule: the key kept as read (a clean slice is its own words), the +# value parsed (its expression copies what it keeps), and the slices nothing keeps given back +function lss_decl_add(r: UiRule, d: string, colon: int, err: []string) -> void { + let kr: string = d[0..colon] + push(r.keys, tpl_words(kr)) + if not tpl_clean(kr) { unsafe { free(kr) } } + let vr: string = d[colon + 1..len(d)] + let vt = tpl_words(vr) + push(r.vals, tpl_value(vt, err)) + unsafe { + if not tpl_clean(vr) { free(vt) } + free(vr) + } +}