# style_rule.ludic - a rule read, the cascade a file sees, and a node's rules applied to it function lss_rule(f: UiFile, sels: string, body: string, err: []string, line: int) -> void { let decls = lss_decls(body, err) let each = lss_split(sels, 44) for i in 0 .. len(each) { let sel = tpl_words(each[i]) if len(sel) > 0 { lss_rule_add(f, decls, sel, err, line) } unsafe { # a selector keeps its parsed parts, never its text if not tpl_clean(each[i]) { free(sel) } free(each[i]) } } unsafe { free(each) free(decls) # the holder only: each rule keeps its keys and values lists } } function lss_rule_add(f: UiFile, decls: UiRule, sel: string, err: []string, line: int) -> void { let r = new UiRule r.keys = decls.keys r.vals = decls.vals r.text = `{sel}` # a copy: the selector's text is given back below r.at = `{f.path}:{line}` 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 { let r = new UiRule r.keys = new []string r.vals = new []UiExpr let decls = lss_split(body, 59) for i in 0 .. len(decls) { let d = decls[i] var colon = -1 for k in 0 .. len(d) { if colon < 0 and d[k] == 58 { colon = k } } if colon < 0 { if len(tpl_words(d)) > 0 { push(err, `"{tpl_words(d)}" is not a property: value`) } continue } 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 } @alloc_ok("a memo miss (mm_split) or a stylesheet being read: once per text") function lss_split(s: string, c: int) -> []string { let out = new []string var at = 0 for i in 0 .. len(s) { if s[i] == c { push(out, s[at..i]) at = i + 1 } } push(out, s[at..len(s)]) return out } # the imports' rules, then the file's own, ordered by specificity and otherwise as written function sheet_of(f: UiFile) -> UiSheet { let sh = new UiSheet sh.rules = new []UiRule for i in 0 .. len(f.imp) { if f.imp[i].sheet != null { for k in 0 .. len(f.imp[i].sheet.rules) { sheet_add(sh, f.imp[i].sheet.rules[k]) } } } for k in 0 .. len(f.own) { sheet_add(sh, f.own[k]) } return sh } function sheet_add(sh: UiSheet, r: UiRule) -> void { push(sh.rules, r) var i = len(sh.rules) - 1 while i > 0 and sh.rules[i - 1].spec > r.spec { sh.rules[i] = sh.rules[i - 1] i -= 1 } 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) } }