json.bend
cswap-bend-cli@0.1.0.0 · 457 lines · 55 definitions
1import Base
2import cswap-bend-cli@0.1.0.0/json/lex.bend as Lex
3import cswap-bend-cli@0.1.0.0/json/quote.bend as Quote
4import cswap-bend-cli@0.1.0.0/json/scan.bend as Scan
5
6
7
8
9
10
11
12
13
14
15
16
17type Json is Data:
18 JNull{}
19 JBool{b: Bool}
20 JNum{text: String}
21 JStr{s: String}
22 JArr{items: Json}
23 JObj{fields: Json}
24 JNil{}
25 JCons{head: Json, tail: Json}
26 JField{key: String, val: Json, tail: Json}
27
28
29
30type Mode is Data:
31 MVal{}
32 MAFirst{}
33 MANext{}
34 MAAfter{}
35 MOFirst{}
36 MONext{}
37 MOAfter{}
38
39def only(t: List<&2, Lex.Tok>, v: Json) -> Result<&2, &2, String, Json>:
40 match t:
41 case Nil{}:
42 Done{v}
43 case Con{h, r}:
44 Fail{"trailing data after the value"}
45
46def wrap.arr(ok: Bool, r: Result<&2, &2, String, Json>) -> Result<&2, &2, String, Json>:
47 match ok r:
48 case True{} Done{items}:
49 Done{JArr{items}}
50 case True{} Fail{e}:
51 Fail{e}
52 case False{} _:
53 Fail{"unclosed array"}
54
55def wrap.obj(ok: Bool, r: Result<&2, &2, String, Json>) -> Result<&2, &2, String, Json>:
56 match ok r:
57 case True{} Done{fields}:
58 Done{JObj{fields}}
59 case True{} Fail{e}:
60 Fail{e}
61 case False{} _:
62 Fail{"unclosed object"}
63
64def item.cons(x: Result<&2, &2, String, Json>, rest: Result<&2, &2, String, Json>) -> Result<&2, &2, String, Json>:
65 match x rest:
66 case Done{a} Done{b}:
67 Done{JCons{a, b}}
68 case Fail{e} _:
69 Fail{e}
70 case _ Fail{e}:
71 Fail{e}
72
73def field.cons(k: String, x: Result<&2, &2, String, Json>, rest: Result<&2, &2, String, Json>) -> Result<&2, &2, String, Json>:
74 match x rest:
75 case Done{a} Done{b}:
76 Done{JField{k, a, b}}
77 case Fail{e} _:
78 Fail{e}
79 case _ Fail{e}:
80 Fail{e}
81
82
83
84
85
86
87type Plan is Data:
88 PRes{r: Result<&2, &2, String, Json>}
89 PArr{t: List<&2, Lex.Tok>}
90 PObj{t: List<&2, Lex.Tok>}
91 PItems{first: List<&2, Lex.Tok>, rest: List<&2, Lex.Tok>}
92 PFields{k: String, vt: List<&2, Lex.Tok>, rest: List<&2, Lex.Tok>}
93 PNext{mode: Mode, t: List<&2, Lex.Tok>}
94
95def plan.val(+toks: List<&2, Lex.Tok>) -> Plan:
96 match toks:
97 case Con{Lex.TNull{}, t}:
98 PRes{only(t, JNull{})}
99 case Con{Lex.TTrue{}, t}:
100 PRes{only(t, JBool{True{}})}
101 case Con{Lex.TFalse{}, t}:
102 PRes{only(t, JBool{False{}})}
103 case Con{Lex.TNum{x}, t}:
104 PRes{only(t, JNum{x})}
105 case Con{Lex.TStr{x}, t}:
106 PRes{only(t, JStr{x})}
107 case Con{Lex.TLBrack{}, +t}:
108 PArr{t}
109 case Con{Lex.TLBrace{}, +t}:
110 PObj{t}
111 case Nil{}:
112 PRes{Fail{"unexpected end of input"}}
113 case _:
114 PRes{Fail{"unexpected token"}}
115
116def plan.items(+toks: List<&2, Lex.Tok>) -> Plan:
117 match toks:
118 case Nil{}:
119 PRes{Fail{"unexpected end of input"}}
120 case Con{+h, +t}:
121 PItems{List.take(&2, Lex.Tok, Con{h, t}, Scan.scan(Con{h, t}, 0)), List.drop(&2, Lex.Tok, Con{h, t}, Scan.scan(Con{h, t}, 0))}
122
123def plan.arr_first(+toks: List<&2, Lex.Tok>) -> Plan:
124 match toks:
125 case Nil{}:
126 PRes{Done{JNil{}}}
127 case _:
128 plan.items(toks)
129
130def plan.arr_next(+toks: List<&2, Lex.Tok>) -> Plan:
131 match toks:
132 case Nil{}:
133 PRes{Fail{"trailing comma in array"}}
134 case _:
135 plan.items(toks)
136
137def plan.arr_after(+toks: List<&2, Lex.Tok>) -> Plan:
138 match toks:
139 case Nil{}:
140 PRes{Done{JNil{}}}
141 case Con{Lex.TComma{}, t}:
142 PNext{MANext{}, t}
143 case _:
144 PRes{Fail{"expected , or ] in array"}}
145
146def plan.field(k: String, +t: List<&2, Lex.Tok>) -> Plan:
147 PFields{k, List.take(&2, Lex.Tok, t, Scan.scan(t, 0)), List.drop(&2, Lex.Tok, t, Scan.scan(t, 0))}
148
149def plan.obj_first(+toks: List<&2, Lex.Tok>) -> Plan:
150 match toks:
151 case Nil{}:
152 PRes{Done{JNil{}}}
153 case Con{Lex.TStr{k}, Con{Lex.TColon{}, +t}}:
154 plan.field(k, t)
155 case _:
156 PRes{Fail{"expected a string key and :"}}
157
158def plan.obj_next(+toks: List<&2, Lex.Tok>) -> Plan:
159 match toks:
160 case Nil{}:
161 PRes{Fail{"trailing comma in object"}}
162 case Con{Lex.TStr{k}, Con{Lex.TColon{}, +t}}:
163 plan.field(k, t)
164 case _:
165 PRes{Fail{"expected a string key and :"}}
166
167def plan.obj_after(+toks: List<&2, Lex.Tok>) -> Plan:
168 match toks:
169 case Nil{}:
170 PRes{Done{JNil{}}}
171 case Con{Lex.TComma{}, t}:
172 PNext{MONext{}, t}
173 case _:
174 PRes{Fail{"expected , or } in object"}}
175
176def plan(mode: Mode, +toks: List<&2, Lex.Tok>) -> Plan:
177 match mode:
178 case MVal{}:
179 plan.val(toks)
180 case MAFirst{}:
181 plan.arr_first(toks)
182 case MANext{}:
183 plan.arr_next(toks)
184 case MAAfter{}:
185 plan.arr_after(toks)
186 case MOFirst{}:
187 plan.obj_first(toks)
188 case MONext{}:
189 plan.obj_next(toks)
190 case MOAfter{}:
191 plan.obj_after(toks)
192
193def body(+t: List<&2, Lex.Tok>) -> List<&2, Lex.Tok>:
194 List.take(&2, Lex.Tok, t, Nat.sub(List.length(&2, Lex.Tok, t), 1n))
195
196
197
198
199def val(fuel: Nat, pl: Plan) -> Result<&2, &2, String, Json>:
200 match fuel pl:
201 case 0n _:
202 Fail{"nesting too deep"}
203 case 1n++p PRes{r}:
204 r
205 case 1n++p PArr{+t}:
206 wrap.arr(Scan.closed_by(t, 22), val(p, plan(MAFirst{}, body(t))))
207 case 1n++p PObj{+t}:
208 wrap.obj(Scan.closed_by(t, 21), val(p, plan(MOFirst{}, body(t))))
209 case 1n++p PItems{f, r}:
210 item.cons(val(p, plan(MVal{}, f)), val(p, plan(MAAfter{}, r)))
211 case 1n++p PFields{k, vt, r}:
212 field.cons(k, val(p, plan(MVal{}, vt)), val(p, plan(MOAfter{}, r)))
213 case 1n++p PNext{m, t}:
214 val(p, plan(m, t))
215
216def parse.pick(msg: String, r: Result<&2, &2, String, Json>) -> Result<&2, &2, String, Json>:
217 match msg r:
218 case SNil{} _:
219 r
220 case _ _:
221 Fail{msg}
222
223def parse.toks(+toks: List<&2, Lex.Tok>) -> Result<&2, &2, String, Json>:
224 parse.pick(Scan.err.of(toks), val(Nat.add(Nat.mul(3n, List.length(&2, Lex.Tok, toks)), 5n), plan(MVal{}, toks)))
225
226
227def parse(+s: String) -> Result<&2, &2, String, Json>:
228 parse.toks(Lex.lex(String.length(s), s))
229
230
231
232def sep.of(next: Json, +style: U32, d: Nat) -> String:
233 match next:
234 case JNil{}:
235 ""
236 case _:
237 Quote.sep(style, d)
238
239def bool.show(b: Bool) -> String:
240 Lex.sel.s(b, "true", "false")
241
242
243def emit.wrap(open: String, close: String, items: Json, inner: String, +style: U32, +d: Nat) -> String:
244 match items:
245 case JNil{}:
246 open ++ close
247 case _:
248 open ++ Quote.nl(style, Nat.add(d, 1n)) ++ inner ++ Quote.nl(style, d) ++ close
249
250
251def emit.go(j: Json, +style: U32, +ascii: Bool, +d: Nat) -> String:
252 match j:
253 case JNull{}:
254 "null"
255 case JBool{b}:
256 bool.show(b)
257 case JNum{t}:
258 t
259 case JStr{s}:
260 Quote.quote(s, ascii)
261 case JArr{+items}:
262 emit.wrap("[", "]", items, emit.go(items, style, ascii, Nat.add(d, 1n)), style, d)
263 case JObj{+fields}:
264 emit.wrap("{", "}", fields, emit.go(fields, style, ascii, Nat.add(d, 1n)), style, d)
265 case JNil{}:
266 ""
267 case JCons{h, +t}:
268 emit.go(h, style, ascii, d) ++ sep.of(t, style, d) ++ emit.go(t, style, ascii, d)
269 case JField{k, v, +t}:
270 Quote.quote(k, ascii) ++ Quote.colon(style) ++ emit.go(v, style, ascii, d) ++ sep.of(t, style, d) ++ emit.go(t, style, ascii, d)
271
272
273def emit(j: Json) -> String:
274 emit.go(j, 0, False{}, 0n)
275
276
277def emit_py(j: Json) -> String:
278 emit.go(j, 1, True{}, 0n)
279
280
281
282
283def emit_pretty(j: Json) -> String:
284 emit.go(j, 2, True{}, 0n)
285
286
287def emit_pretty_utf8(j: Json) -> String:
288 emit.go(j, 2, False{}, 0n)
289
290def field.pick(hit: Bool, v: Json, rest: Maybe<&2, Json>) -> Maybe<&2, Json>:
291 match hit:
292 case True{}:
293 Some{v}
294 case False{}:
295 rest
296
297
298
299def field.get(+key: String, fields: Json) -> Maybe<&2, Json>:
300 match fields:
301 case JField{k, v, t}:
302 field.pick(String.eq(k, key), v, field.get(key, t))
303 case _:
304 None{}
305
306
307def get(key: String, j: Json) -> Maybe<&2, Json>:
308 match j:
309 case JObj{fields}:
310 field.get(key, fields)
311 case _:
312 None{}
313
314def as_string(j: Json) -> Maybe<&2, String>:
315 match j:
316 case JStr{s}:
317 Some{s}
318 case _:
319 None{}
320
321def as_bool(j: Json) -> Maybe<&2, Bool>:
322 match j:
323 case JBool{b}:
324 Some{b}
325 case _:
326 None{}
327
328
329def as_u32(j: Json) -> Maybe<&2, U32>:
330 match j:
331 case JNum{t}:
332 U32.read(t)
333 case _:
334 None{}
335
336
337def arr.chain(xs: List<&2, Json>) -> Json:
338 match xs:
339 case Nil{}:
340 JNil{}
341 case Con{h, t}:
342 JCons{h, arr.chain(t)}
343
344def arr(xs: List<&2, Json>) -> Json:
345 JArr{arr.chain(xs)}
346
347
348def items.list(items: Json) -> List<&2, Json>:
349 match items:
350 case JCons{h, t}:
351 h <> items.list(t)
352 case _:
353 []
354
355def to_list(j: Json) -> List<&2, Json>:
356 match j:
357 case JArr{items}:
358 items.list(items)
359 case _:
360 []
361
362def field.of(kv: String & Json, rest: Json) -> Json:
363 (k, v) = kv
364 JField{k, v, rest}
365
366def obj.chain(kvs: List<(String & Json)>) -> Json:
367 match kvs:
368 case Nil{}:
369 JNil{}
370 case Con{kv, t}:
371 field.of(kv, obj.chain(t))
372
373
374def of_pairs(kvs: List<(String & Json)>) -> Json:
375 JObj{obj.chain(kvs)}
376
377def pairs.list(fields: Json) -> List<(String & Json)>:
378 match fields:
379 case JField{k, v, t}:
380 (k, v) <> pairs.list(t)
381 case _:
382 []
383
384
385def to_pairs(j: Json) -> List<(String & Json)>:
386 match j:
387 case JObj{fields}:
388 pairs.list(fields)
389 case _:
390 []
391
392def keys.list(fields: Json) -> List<&2, String>:
393 match fields:
394 case JField{k, v, t}:
395 k <> keys.list(t)
396 case _:
397 []
398
399def keys(j: Json) -> List<&2, String>:
400 match j:
401 case JObj{fields}:
402 keys.list(fields)
403 case _:
404 []
405
406def set.pick(hit: Bool, key: String, val: Json, v: Json, t: Json, rest: Json) -> Json:
407 match hit:
408 case True{}:
409 JField{key, val, t}
410 case False{}:
411 JField{key, v, rest}
412
413def set.go(+key: String, +val: Json, fields: Json) -> Json:
414 match fields:
415 case JField{+k, v, +t}:
416 set.pick(String.eq(k, key), k, val, v, t, set.go(key, val, t))
417 case _:
418 JField{key, val, JNil{}}
419
420
421def set(+key: String, +val: Json, j: Json) -> Json:
422 match j:
423 case JObj{fields}:
424 JObj{set.go(key, val, fields)}
425 case _:
426 j
427
428def del.pick(hit: Bool, k: String, v: Json, t: Json, rest: Json) -> Json:
429 match hit:
430 case True{}:
431 t
432 case False{}:
433 JField{k, v, rest}
434
435def del.go(+key: String, fields: Json) -> Json:
436 match fields:
437 case JField{+k, v, +t}:
438 del.pick(String.eq(k, key), k, v, t, del.go(key, t))
439 case _:
440 JNil{}
441
442
443def del(+key: String, j: Json) -> Json:
444 match j:
445 case JObj{fields}:
446 JObj{del.go(key, fields)}
447 case _:
448 j
449
450
451
452def unwrap(+r: Result<&2, &2, String, Json>) -> Json:
453 match r:
454 case Done{v}:
455 v
456 case Fail{e}:
457 JNull{}