src/head.bend

bend-toon-codec@0.1.0.0 · 61 lines · 9 definitions

1import Base
2
3# Looking at the front of a string without matching on character codes
4# (a numeric pattern expands to a match per bit, which the linter counts).
5
6# Is the first character the code point `c`?
7def lead(+s: String, +c: U32) -> Bool:
8  match s:
9    case SNil{}:
10      False{}
11    case SCon{Chr{x}, t}:
12      U32.is_eq(x, c)
13
14# Without the first character.
15def drop(+s: String) -> String:
16  match s:
17    case SNil{}:
18      SNil{}
19    case SCon{h, t}:
20      t
21
22# Are the first two characters `a` then `b`?
23def lead2(+s: String, +a: U32, +b: U32) -> Bool:
24  lead(s, a) && lead(drop(s), b)
25
26# Has the string at least `n` characters?
27def at_least(+s: String, +n: Nat) -> Bool:
28  match s n:
29    case _ 0n:
30      True{}
31    case SNil{} _:
32      False{}
33    case SCon{h, t} 1n+p:
34      at_least(t, p)
35
36# ---- quoted-key marker -------------------------------------------------------
37#
38# The decoder prefixes a key that was written in quotes with one character that
39# no text holds (code 4294967295, beyond U+10FFFF), so path expansion can tell
40# `"a.b"` (literal) from `a.b` (a path). Markers never leave the decoder.
41
42def mark() -> String:
43  SCon{Chr{4294967295}, SNil{}}
44
45def marked(+k: String) -> Bool:
46  lead(k, 4294967295)
47
48def unmark.pick(+m: Bool, +k: String) -> String:
49  match m:
50    case True{}:
51      drop(k)
52    case False{}:
53      k
54
55# The key without its marker.
56def unmark(+k: String) -> String:
57  unmark.pick(marked(k), k)
58
59# Same key, ignoring markers.
60def keq(+a: String, +b: String) -> Bool:
61  String.eq(unmark(a), unmark(b))