src/text.bend
ezsys@0.1.0.0 · 215 lines · 21 definitions
1
2
3
4
5
6
7
8import Base
9
10
11
12type Mode is Data:
13 Plain{}
14 Opening{left: Nat}
15 InKey{key: String}
16 Closing{left: Nat}
17
18
19def text.Pairs() -> Data:
20 List<&2, Sigma<&2, &2, String, _ => String>>
21
22
23def text.own(xs: List<(String & String)>) -> text.Pairs():
24 match xs:
25 case Nil{}:
26 Nil{}
27 case Con{(+key, +value), rest}:
28 Con{(key, value), text.own(rest)}
29
30
31def text.value.pick(
32 hit: Bool,
33 value: String,
34 rest: Unit -> Maybe<&2, String>
35) -> Maybe<&2, String>:
36 match hit:
37 case True{}:
38 Some{value}
39 case False{}:
40 rest(Unit{})
41
42
43def text.value(pairs: text.Pairs(), +key: String) -> Maybe<&2, String>:
44 match pairs:
45 case Nil{}:
46 None{}
47 case Con{(name, value), rest}:
48 text.value.pick(String.eq(name, key), value,
49 _u => text.value(rest, key))
50
51
52def text.tail(delim: String) -> Nat:
53 match delim:
54 case SNil{}:
55 0n
56 case SCon{_hd, tl}:
57 String.length(tl)
58
59
60def text.enter(left: Nat) -> Mode:
61 match left:
62 case 0n:
63 InKey{""}
64 case 1n+more:
65 Opening{more}
66
67
68def text.leave(left: Nat) -> Mode:
69 match left:
70 case 0n:
71 Plain{}
72 case 1n+more:
73 Closing{more}
74
75
76def text.put(
77 +open: String,
78 +close: String,
79 key: String,
80 got: Maybe<&2, String>
81) -> String:
82 match got:
83 case None{}:
84 open ++ (key ++ close)
85 case Some{value}:
86 value
87
88
89def text.plain(at: Bool, hd: Char, +open: String) -> String & Mode:
90 match at:
91 case False{}:
92 (SCon{hd, SNil{}}, Plain{})
93 case True{}:
94 ("", text.enter(text.tail(open)))
95
96
97def text.shut(
98 at: Bool,
99 hd: Char,
100 +key: String,
101 +open: String,
102 +close: String,
103 +pairs: text.Pairs()
104) -> String & Mode:
105 match at:
106 case False{}:
107 ("", InKey{key ++ SCon{hd, SNil{}}})
108 case True{}:
109 (text.put(open, close, key, text.value(pairs, key)),
110 text.leave(text.tail(close)))
111
112
113def text.step(
114 +hd: Char,
115 +tl: String,
116 mode: Mode,
117 +open: String,
118 +close: String,
119 +pairs: text.Pairs()
120) -> String & Mode:
121 match mode:
122 case Plain{}:
123 text.plain(String.starts_with(SCon{hd, tl}, open), hd, open)
124 case Opening{left}:
125 ("", text.enter(left))
126 case InKey{key}:
127 text.shut(String.starts_with(SCon{hd, tl}, close), hd, key, open, close,
128 pairs)
129 case Closing{left}:
130 ("", text.leave(left))
131
132
133def text.end(mode: Mode, +open: String) -> String:
134 match mode:
135 case Plain{}:
136 ""
137 case Opening{_left}:
138 ""
139 case InKey{key}:
140 open ++ key
141 case Closing{_left}:
142 ""
143
144
145def text.join(pair: String & Mode, rest: Mode -> String) -> String:
146 (out, next) = pair
147 out ++ rest(next)
148
149
150def text.go(
151 tpl: String,
152 mode: Mode,
153 +open: String,
154 +close: String,
155 +pairs: text.Pairs()
156) -> String:
157 match tpl:
158 case SNil{}:
159 text.end(mode, open)
160 case SCon{+hd, +tl}:
161 text.join(text.step(hd, tl, mode, open, close, pairs),
162 next => text.go(tl, next, open, close, pairs))
163
164
165def text.any(here: Bool, rest: Unit -> Bool) -> Bool:
166 match here:
167 case True{}:
168 True{}
169 case False{}:
170 rest(Unit{})
171
172
173def text.all(here: Bool, rest: Unit -> Bool) -> Bool:
174 match here:
175 case False{}:
176 False{}
177 case True{}:
178 rest(Unit{})
179
180
181def text.marked(+open: String, tpl: String) -> Bool:
182 match tpl:
183 case SNil{}:
184 False{}
185 case SCon{+hd, +tl}:
186 text.any(String.starts_with(SCon{hd, tl}, open),
187 _u => text.marked(open, tl))
188
189
190def text.free(+close: String, key: String, +after: String) -> Bool:
191 match key:
192 case SNil{}:
193 True{}
194 case SCon{+hd, +tl}:
195 text.all(Bool.not(String.starts_with(SCon{hd, tl ++ after}, close)),
196 _u => text.free(close, tl, after))
197
198
199def text.fill_with(
200 open: String,
201 close: String,
202 tpl: String,
203 pairs: text.Pairs()
204) -> String:
205 match open close:
206 case SNil{} _:
207 tpl
208 case SCon{_oh, _ot} SNil{}:
209 tpl
210 case SCon{oh, ot} SCon{ch, ct}:
211 text.go(tpl, Plain{}, SCon{oh, ot}, SCon{ch, ct}, pairs)
212
213
214def text.fill(tpl: String, pairs: text.Pairs()) -> String:
215 text.fill_with("{{", "}}", tpl, pairs)