src/line.bend
ezmcp@0.1.0.0 · 221 lines · 29 definitions
1
2
3
4
5import Base
6import emerging-ezjson@1.2.0.0/main.bend as Json
7import emerging-ezjson@1.2.0.0/src/value.bend as Value
8import ezmcp@0.1.0.0/src/server.bend as Server
9
10
11type Cut is Data:
12 Cut{lines: List<&2, List<&2, U32>>, rest: List<&2, U32>}
13
14
15def nl(+byte: U32) -> Bool:
16 U32.is_eq(byte, 10)
17
18
19def split.put(byte: U32, ps: List<&2, List<&2, U32>>) -> List<&2, List<&2, U32>>:
20 match ps:
21 case []:
22 [[byte]]
23 case p <> rest:
24 (byte <> p) <> rest
25
26
27
28def split.at(
29 byte: U32,
30 ps: List<&2, List<&2, U32>>,
31 cut: Bool
32) -> List<&2, List<&2, U32>>:
33 match cut:
34 case True{}:
35 [byte] <> ps
36 case False{}:
37 split.put(byte, ps)
38
39
40
41def split(bs: List<&2, U32>) -> List<&2, List<&2, U32>>:
42 match bs:
43 case []:
44 [[]]
45 case +b <> t:
46 split.at(b, split(t), nl(b))
47
48def cut.cons(piece: List<&2, U32>, cb: Cut) -> Cut:
49 match cb:
50 case Cut{lines, rest}:
51 Cut{piece <> lines, rest}
52
53def cut.go(rest: List<&2, List<&2, U32>>, piece: List<&2, U32>) -> Cut:
54 match rest:
55 case []:
56 Cut{[], piece}
57 case q <> more:
58 cut.cons(piece, cut.go(more, q))
59
60def cut.of(ps: List<&2, List<&2, U32>>) -> Cut:
61 match ps:
62 case []:
63 Cut{[], []}
64 case p <> rest:
65 cut.go(rest, p)
66
67
68def cut(bs: List<&2, U32>) -> Cut:
69 cut.of(split(bs))
70
71
72
73
74def cont(+byte: U32) -> Bool:
75 Bool.and(U32.is_ge(byte, 128), U32.is_le(byte, 191))
76
77
78def bad() -> Char:
79 Chr{65533}
80
81
82def low6(+byte: U32) -> U32:
83 U32.sub(byte, 128)
84
85
86def two(+lead: U32, +byte: U32) -> U32:
87 U32.add(U32.mul(U32.sub(lead, 192), 64), low6(byte))
88
89
90def three(+lead: U32, +byte: U32, +cb: U32) -> U32:
91 U32.add(U32.mul(U32.add(U32.mul(U32.sub(lead, 224), 64), low6(byte)), 64), low6(cb))
92
93
94def four(+lead: U32, +byte: U32, +cb: U32, +db: U32) -> U32:
95 U32.add(U32.mul(U32.add(U32.mul(U32.add(U32.mul(U32.sub(lead, 240), 64),
96 low6(byte)), 64), low6(cb)), 64), low6(db))
97
98
99type Width is Data:
100 W0{}
101 W1{}
102 W2{}
103 W3{}
104 W4{}
105
106
107def width(+byte: U32) -> Width:
108 Bool.pick(Width, U32.is_lt(byte, 128), W1{},
109 Bool.pick(Width, Bool.and(U32.is_ge(byte, 194), U32.is_le(byte, 223)), W2{},
110 Bool.pick(Width, Bool.and(U32.is_ge(byte, 224), U32.is_le(byte, 239)), W3{},
111 Bool.pick(Width, Bool.and(U32.is_ge(byte, 240), U32.is_le(byte, 244)), W4{},
112 W0{}))))
113
114
115
116
117def dec.take(
118 ch: Char,
119 ok: Bool,
120 after_lead: List<&2, U32>,
121 after_seq: List<&2, U32>,
122 go: List<&2, U32> -> String
123) -> String:
124 match ok:
125 case True{}:
126 SCon{ch, go(after_seq)}
127 case False{}:
128 SCon{bad(), go(after_lead)}
129
130def dec.two(+lead: U32, bs: List<&2, U32>, go: List<&2, U32> -> String) -> String:
131 match bs:
132 case +b <> +t:
133 dec.take(Chr{two(lead, b)}, cont(b), b <> t, t, go)
134 case []:
135 SCon{bad(), SNil{}}
136
137def dec.three(
138 +lead: U32,
139 bs: List<&2, U32>,
140 go: List<&2, U32> -> String
141) -> String:
142 match bs:
143 case +b <> +c <> +t:
144 dec.take(Chr{three(lead, b, c)}, Bool.and(cont(b), cont(c)), b <> c <> t,
145 t, go)
146 case other:
147 SCon{bad(), go(other)}
148
149def dec.four(+lead: U32, bs: List<&2, U32>, go: List<&2, U32> -> String) -> String:
150 match bs:
151 case +b <> +c <> +d <> +t:
152 dec.take(Chr{four(lead, b, c, d)},
153 Bool.and(cont(b), Bool.and(cont(c), cont(d))), b <> c <> d <> t, t, go)
154 case other:
155 SCon{bad(), go(other)}
156
157
158def dec.lead(
159 +byte: U32,
160 tail: List<&2, U32>,
161 wid: Width,
162 go: List<&2, U32> -> String
163) -> String:
164 match wid:
165 case W1{}:
166 SCon{Chr{byte}, go(tail)}
167 case W2{}:
168 dec.two(byte, tail, go)
169 case W3{}:
170 dec.three(byte, tail, go)
171 case W4{}:
172 dec.four(byte, tail, go)
173 case W0{}:
174 SCon{bad(), go(tail)}
175
176def decode.step(bs: List<&2, U32>, go: List<&2, U32> -> String) -> String:
177 match bs:
178 case []:
179 SNil{}
180 case +b <> t:
181 dec.lead(b, t, width(b), go)
182
183
184
185def decode.go(fuel: Nat, bs: List<&2, U32>) -> String:
186 match fuel:
187 case 0n:
188 SNil{}
189 case 1n+f:
190 decode.step(bs, xs => decode.go(f, xs))
191
192
193def decode(+bs: List<&2, U32>) -> String:
194 decode.go(List.length(&2, U32, bs), bs)
195
196
197
198def line.of(
199 srv: Server.Server,
200 +rev: String,
201 +text: String,
202 blank: Bool
203) -> Server.Turn:
204 match blank:
205 case True{}:
206 Server.Turn{Server.Quiet{}, rev}
207 case False{}:
208 Server.turn(srv, rev, text)
209
210def line.text(srv: Server.Server, +rev: String, +text: String) -> Server.Turn:
211 line.of(srv, rev, text, String.is_empty(String.trim(text)))
212
213
214
215
216def line(srv: Server.Server, rev: String, bs: List<&2, U32>) -> Server.Turn:
217 line.text(srv, rev, decode(bs))
218
219
220def frame(val: Value.Json) -> String:
221 Json.print(val) ++ "\n"