src/yaml.bend
bend-kube-runtime@0.2.0.0 · 1,157 lines · 150 definitions
1import Base
2import bend-kube-runtime@0.2.0.0/src/json.bend as J
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19type Line is Data:
20 Line{indent: U32, text: String}
21
22
23
24
25type YFrame is Data:
26 YMap{indent: U32, members: List<&2, J.KV>, pend: Maybe<&2, String>}
27 YSeq{indent: U32, items: List<&2, J.Json>, pend: Maybe<&2, String>}
28 YRoot{value: J.Json}
29
30
31
32type Flow is Data:
33 Flow{mode: U32, buf: String, out: String, esc: Bool}
34
35
36
37
38
39type Blk is Data:
40 Blk{ki: U32, prefix: String, folded: Bool, chomp: U32, bi: U32, acc: List<&2, String>}
41
42type BH is Data:
43 BH{prefix: String, folded: Bool, chomp: U32}
44
45
46type LS is Data:
47 LS{out: List<&2, Line>, blk: Maybe<&2, Blk>}
48
49
50type AV is Data:
51 AV{anchor: String, rest: String}
52
53type YR is Data:
54 YR{json: J.Json, anchors: Map<&2, J.Json>}
55
56
57
58
59def Yaml.indent(s: String, +n: U32) -> U32:
60 match s:
61 case SCon{' ', t}:
62 Yaml.indent(t, (n + 1 : U32))
63 case _:
64 n
65
66def Yaml.quote.go(+q: U32, +k: U32, none: Bool, same: Bool) -> U32:
67 match none same:
68 case True{} _:
69 k
70 case False{} True{}:
71 0
72 case _ _:
73 q
74
75
76def Yaml.quote(+q: U32, +k: U32) -> U32:
77 Yaml.quote.go(q, k, U32.is_eq(q, 0), U32.is_eq(q, k))
78
79
80def Yaml.nq(+c: Char, +q: U32) -> U32:
81 match c:
82 case '"':
83 Yaml.quote(q, 2)
84 case '\'':
85 Yaml.quote(q, 1)
86 case _:
87 q
88
89
90
91def Yaml.cut_at(s: String, +q: U32, prev: Bool) -> Bool:
92 match s:
93 case SCon{'#', t}:
94 Bool.and(prev, U32.is_eq(q, 0))
95 case _:
96 False{}
97
98
99def Yaml.uncomment(s: String, +q: U32, cut: Bool) -> String:
100 match s cut:
101 case _ True{}:
102 SNil{}
103 case SNil{} False{}:
104 SNil{}
105 case SCon{+c, +t} False{}:
106 SCon{c, Yaml.uncomment(t, Yaml.nq(c, q), Yaml.cut_at(t, Yaml.nq(c, q), Char.is_space(c)))}
107
108def Yaml.keep(+t: String) -> Bool:
109 Bool.and(Bool.not(String.is_empty(t)), Bool.not(String.eq(t, "---")))
110
111def Yaml.lines.put.go(+i: U32, text: String, rest: List<&2, Line>, keep: Bool) -> List<&2, Line>:
112 match keep:
113 case True{}:
114 Line{i, text} <> rest
115 case False{}:
116 rest
117
118def Yaml.lines.put(+i: U32, +text: String, rest: List<&2, Line>) -> List<&2, Line>:
119 Yaml.lines.put.go(i, text, rest, Yaml.keep(text))
120
121
122
123def Yaml.head.go(r: String) -> Maybe<&2, BH>:
124 match r:
125 case SCon{'|', SCon{' ', t}}:
126 Some{BH{String.reverse(t) ++ " ", False{}, 0}}
127 case SCon{'>', SCon{' ', t}}:
128 Some{BH{String.reverse(t) ++ " ", True{}, 0}}
129 case SCon{'-', SCon{'|', SCon{' ', t}}}:
130 Some{BH{String.reverse(t) ++ " ", False{}, 1}}
131 case SCon{'-', SCon{'>', SCon{' ', t}}}:
132 Some{BH{String.reverse(t) ++ " ", True{}, 1}}
133 case SCon{'+', SCon{'|', SCon{' ', t}}}:
134 Some{BH{String.reverse(t) ++ " ", False{}, 2}}
135 case SCon{'+', SCon{'>', SCon{' ', t}}}:
136 Some{BH{String.reverse(t) ++ " ", True{}, 2}}
137 case _:
138 None{}
139
140def Yaml.head(t: String) -> Maybe<&2, BH>:
141 Yaml.head.go(String.reverse(t))
142
143def Yaml.clean(+l: String) -> String:
144 String.trim(Yaml.uncomment(l, 0, Yaml.cut_at(l, 0, True{})))
145
146
147def Yaml.blanks(xs: List<&2, String>, +n: U32) -> U32:
148 match xs:
149 case Con{SNil{}, t}:
150 Yaml.blanks(t, (n + 1 : U32))
151 case _:
152 n
153
154def Yaml.unblank(xs: List<&2, String>) -> List<&2, String>:
155 match xs:
156 case Con{SNil{}, t}:
157 Yaml.unblank(t)
158 case x:
159 x
160
161def Yaml.fold.sep(prev: Bool) -> String:
162 match prev:
163 case True{}:
164 " "
165 case False{}:
166 ""
167
168
169
170def Yaml.fold(xs: List<&2, String>, prev: Bool) -> String:
171 match xs:
172 case Nil{}:
173 ""
174 case Con{SNil{}, t}:
175 "\n" ++ Yaml.fold(t, False{})
176 case Con{l, t}:
177 Yaml.fold.sep(prev) ++ l ++ Yaml.fold(t, True{})
178
179def Yaml.block.body(lines: List<&2, String>, folded: Bool) -> String:
180 match folded:
181 case True{}:
182 Yaml.fold(lines, False{})
183 case False{}:
184 String.join(lines, "\n")
185
186def Yaml.block.tail.go(+chomp: U32, +n: U32, strip: Bool, keep: Bool) -> String:
187 match strip keep:
188 case True{} _:
189 ""
190 case False{} True{}:
191 String.repeat("\n", U32.to_nat((n + 1 : U32)))
192 case _ _:
193 "\n"
194
195def Yaml.block.tail(+chomp: U32, +n: U32, empty: Bool) -> String:
196 match empty:
197 case True{}:
198 ""
199 case False{}:
200 Yaml.block.tail.go(chomp, n, U32.is_eq(chomp, 1), U32.is_eq(chomp, 2))
201
202
203def Yaml.block.line(b: Blk) -> Line:
204 match b:
205 case Blk{ki, prefix, folded, +chomp, bi, +acc}:
206 Line{ki, prefix ++ J.Json.show(J.JStr{
207 Yaml.block.body(List.reverse(&2, String, Yaml.unblank(acc)), folded)
208 ++ Yaml.block.tail(chomp, Yaml.blanks(acc, 0), List.is_empty(&2, String, Yaml.unblank(acc)))})}
209
210def Yaml.normal.go(out: List<&2, Line>, +i: U32, +t: String, h: Maybe<&2, BH>) -> LS:
211 match h:
212 case Some{BH{p, f, c}}:
213 LS{out, Some{Blk{i, p, f, c, 0, Nil{}}}}
214 case None{}:
215 LS{Yaml.lines.put(i, t, out), None{}}
216
217
218def Yaml.normal(out: List<&2, Line>, +raw: String) -> LS:
219 Yaml.normal.go(out, Yaml.indent(raw, 0), Yaml.clean(raw), Yaml.head(Yaml.clean(raw)))
220
221def Yaml.in_block.go(out: List<&2, Line>, b: Blk, +raw: String, blank: Bool, deeper: Bool,
222 first: Bool) -> LS:
223 match b blank deeper first:
224 case Blk{ki, p, f, c, bi, acc} True{} _ _:
225 LS{out, Some{Blk{ki, p, f, c, bi, SNil{} <> acc}}}
226 case Blk{ki, p, f, c, bi, acc} False{} True{} True{}:
227 LS{out, Some{Blk{ki, p, f, c, Yaml.indent(raw, 0), String.drop(raw, U32.to_nat(Yaml.indent(raw, 0))) <> acc}}}
228 case Blk{ki, p, f, c, +bi, acc} False{} True{} False{}:
229 LS{out, Some{Blk{ki, p, f, c, bi, String.drop(raw, U32.to_nat(bi)) <> acc}}}
230 case +x False{} False{} _:
231 Yaml.normal(Yaml.block.line(x) <> out, raw)
232
233
234
235def Yaml.in_block(out: List<&2, Line>, b: Blk, +raw: String) -> LS:
236 match b:
237 case Blk{+ki, p, f, c, +bi, acc}:
238 Yaml.in_block.go(out, Blk{ki, p, f, c, bi, acc}, raw, String.is_empty(String.trim(raw)),
239 U32.is_gt(Yaml.indent(raw, 0), ki), U32.is_eq(bi, 0))
240
241def Yaml.step_line(st: LS, +raw: String) -> LS:
242 match st:
243 case LS{out, None{}}:
244 Yaml.normal(out, raw)
245 case LS{out, Some{b}}:
246 Yaml.in_block(out, b, raw)
247
248def Yaml.lines.fold(ls: List<&2, String>, st: LS) -> LS:
249 match ls:
250 case Nil{}:
251 st
252 case Con{l, t}:
253 Yaml.lines.fold(t, Yaml.step_line(st, l))
254
255def Yaml.lines.fin(st: LS) -> List<&2, Line>:
256 match st:
257 case LS{out, None{}}:
258 List.reverse(&2, Line, out)
259 case LS{out, Some{b}}:
260 List.reverse(&2, Line, Yaml.block.line(b) <> out)
261
262
263
264def Yaml.lines(s: String) -> List<&2, Line>:
265 Yaml.lines.fin(Yaml.lines.fold(String.lines(s), LS{Nil{}, None{}}))
266
267
268
269
270def Yaml.unsingle(s: String) -> String:
271 match s:
272 case SNil{}:
273 SNil{}
274 case SCon{'\'', SCon{'\'', t}}:
275 SCon{'\'', Yaml.unsingle(t)}
276 case SCon{c, t}:
277 SCon{c, Yaml.unsingle(t)}
278
279def Yaml.strip_ends(+s: String) -> String:
280 String.take(String.drop(s, 1n), Nat.sub(String.length(s), 2n))
281
282def Yaml.json_or(r: Result<&2, &2, String, J.Json>, s: String) -> J.Json:
283 match r:
284 case Done{j}:
285 j
286 case Fail{e}:
287 J.JStr{s}
288
289
290
291
292type Num is Data:
293 NStart{}
294 NSign{neg: Bool}
295 NInt{neg: Bool, int: List<&2, Char>}
296 NDot0{neg: Bool}
297 NFrac{neg: Bool, int: List<&2, Char>, frac: List<&2, Char>}
298 NExp0{neg: Bool, int: List<&2, Char>, frac: List<&2, Char>, exp: List<&2, Char>}
299 NExp1{neg: Bool, int: List<&2, Char>, frac: List<&2, Char>, exp: List<&2, Char>}
300 NExpD{neg: Bool, int: List<&2, Char>, frac: List<&2, Char>, exp: List<&2, Char>}
301 NBad{}
302
303def Num.step(st: Num, +c: Char, dig: Bool, dot: Bool, ex: Bool, sg: Bool) -> Num:
304 match st dig dot ex sg:
305 case NStart{} True{} d e s:
306 NInt{False{}, [c]}
307 case NStart{} False{} True{} e s:
308 NDot0{False{}}
309 case NStart{} False{} False{} e True{}:
310 NSign{Char.is_eq(c, '-')}
311 case NStart{} False{} False{} e False{}:
312 NBad{}
313 case NSign{n} True{} d e s:
314 NInt{n, [c]}
315 case NSign{n} False{} True{} e s:
316 NDot0{n}
317 case NSign{n} False{} False{} e s:
318 NBad{}
319 case NInt{n, i} True{} d e s:
320 NInt{n, Con{c, i}}
321 case NInt{n, i} False{} True{} e s:
322 NFrac{n, i, Nil{}}
323 case NInt{n, i} False{} False{} True{} s:
324 NExp0{n, i, Nil{}, [c]}
325 case NInt{n, i} False{} False{} False{} s:
326 NBad{}
327 case NDot0{n} True{} d e s:
328 NFrac{n, Nil{}, [c]}
329 case NDot0{n} False{} d e s:
330 NBad{}
331 case NFrac{n, i, f} True{} d e s:
332 NFrac{n, i, Con{c, f}}
333 case NFrac{n, i, f} False{} d True{} s:
334 NExp0{n, i, f, [c]}
335 case NFrac{n, i, f} False{} d False{} s:
336 NBad{}
337 case NExp0{n, i, f, x} True{} d e s:
338 NExpD{n, i, f, Con{c, x}}
339 case NExp0{n, i, f, x} False{} d e True{}:
340 NExp1{n, i, f, Con{c, x}}
341 case NExp0{n, i, f, x} False{} d e False{}:
342 NBad{}
343 case NExp1{n, i, f, x} True{} d e s:
344 NExpD{n, i, f, Con{c, x}}
345 case NExp1{n, i, f, x} False{} d e s:
346 NBad{}
347 case NExpD{n, i, f, x} True{} d e s:
348 NExpD{n, i, f, Con{c, x}}
349 case NExpD{n, i, f, x} False{} d e s:
350 NBad{}
351 case NBad{} g d e s:
352 NBad{}
353
354def Num.go(s: String, st: Num) -> Num:
355 match s:
356 case SNil{}:
357 st
358 case SCon{+c, t}:
359 Num.go(t, Num.step(st, c, Char.is_digit(c), Char.is_eq(c, '.'),
360 Bool.or(Char.is_eq(c, 'e'), Char.is_eq(c, 'E')),
361 Bool.or(Char.is_eq(c, '-'), Char.is_eq(c, '+'))))
362
363def Num.sign(neg: Bool) -> String:
364 match neg:
365 case True{}:
366 "-"
367 case False{}:
368 ""
369
370
371def Num.int(cs: List<&2, Char>) -> String:
372 match cs:
373 case Nil{}:
374 "0"
375 case Con{'0', t}:
376 Num.int(t)
377 case Con{c, t}:
378 String.from_list(Con{c, t})
379
380def Num.frac(f: List<&2, Char>) -> String:
381 match f:
382 case Nil{}:
383 ""
384 case Con{c, t}:
385 "." ++ String.from_list(List.reverse(&2, Char, Con{c, t}))
386
387
388def Num.fin(st: Num) -> Maybe<&2, String>:
389 match st:
390 case NInt{n, i}:
391 Some{Num.sign(n) ++ Num.int(List.reverse(&2, Char, i))}
392 case NFrac{n, i, f}:
393 Some{Num.sign(n) ++ Num.int(List.reverse(&2, Char, i)) ++ Num.frac(f)}
394 case NExpD{n, i, f, x}:
395 Some{Num.sign(n) ++ Num.int(List.reverse(&2, Char, i)) ++ Num.frac(f) ++
396 String.from_list(List.reverse(&2, Char, x))}
397 case _:
398 None{}
399
400def Num.parse(s: String) -> Maybe<&2, String>:
401 Num.fin(Num.go(s, NStart{}))
402
403def Yaml.plain.num(x: String, n: Maybe<&2, String>) -> J.Json:
404 match n:
405 case Some{t}:
406 J.JNum{t}
407 case None{}:
408 J.JStr{x}
409
410
411def Yaml.plain(s: String) -> J.Json:
412 match s:
413 case "null":
414 J.JNull{}
415 case "~":
416 J.JNull{}
417 case "true":
418 J.JBool{True{}}
419 case "false":
420 J.JBool{False{}}
421 case +x:
422 Yaml.plain.num(x, Num.parse(x))
423
424def Flow.peek(s: String) -> Char:
425 match s:
426 case SCon{c, t}:
427 c
428 case SNil{}:
429 ' '
430
431
432
433type KR is Data:
434 KR{key: String, rest: String}
435
436def Flow.punct(+c: Char) -> Bool:
437 match c:
438 case '{':
439 True{}
440 case '}':
441 True{}
442 case '[':
443 True{}
444 case ']':
445 True{}
446 case ',':
447 True{}
448 case ':':
449 True{}
450 case _:
451 False{}
452
453def Flow.out0.go(+c: Char, out: String, punct: Bool, space: Bool) -> Flow:
454 match punct space:
455 case True{} _:
456 Flow{0, "", SCon{c, out}, False{}}
457 case False{} True{}:
458 Flow{0, "", out, False{}}
459 case False{} False{}:
460 Flow{3, SCon{c, SNil{}}, out, False{}}
461
462def Flow.out0(+c: Char, out: String) -> Flow:
463 match c:
464 case '"':
465 Flow{1, "", SCon{'"', out}, False{}}
466 case '\'':
467 Flow{2, "", SCon{'"', out}, False{}}
468 case x:
469 Flow.out0.go(x, out, Flow.punct(x), Char.is_space(x))
470
471def Flow.dq(esc: Bool, +c: Char, out: String) -> Flow:
472 match esc c:
473 case True{} x:
474 Flow{1, "", SCon{x, out}, False{}}
475 case False{} '\\':
476 Flow{1, "", SCon{'\\', out}, True{}}
477 case False{} '"':
478 Flow{0, "", SCon{'"', out}, False{}}
479 case False{} x:
480 Flow{1, "", SCon{x, out}, False{}}
481
482def Flow.sq.quote(out: String, doubled: Bool) -> Flow:
483 match doubled:
484 case True{}:
485 Flow{2, "", out, True{}}
486 case False{}:
487 Flow{0, "", SCon{'"', out}, False{}}
488
489def Flow.sq(esc: Bool, +c: Char, +nxt: Char, out: String) -> Flow:
490 match esc c:
491 case True{} _:
492 Flow{2, "", SCon{'\'', out}, False{}}
493 case False{} '\'':
494 Flow.sq.quote(out, Char.is_eq(nxt, '\''))
495 case False{} '"':
496 Flow{2, "", SCon{'"', SCon{'\\', out}}, False{}}
497 case False{} '\\':
498 Flow{2, "", SCon{'\\', SCon{'\\', out}}, False{}}
499 case False{} x:
500 Flow{2, "", SCon{x, out}, False{}}
501
502def Flow.closer(+c: Char) -> Bool:
503 match c:
504 case '}':
505 True{}
506 case ']':
507 True{}
508 case ',':
509 True{}
510 case _:
511 False{}
512
513
514def Flow.ends(+c: Char, +nxt: Char) -> Bool:
515 Bool.or(Flow.closer(c), Bool.and(Char.is_eq(c, ':'), Bool.or(Char.is_space(nxt), Flow.closer(nxt))))
516
517def Flow.emit(buf: String, out: String) -> String:
518 String.reverse(J.Json.show(Yaml.plain(String.trim(String.reverse(buf))))) ++ out
519
520def Flow.plain.go(+c: Char, buf: String, out: String, ends: Bool) -> Flow:
521 match ends:
522 case True{}:
523 Flow{0, "", SCon{c, Flow.emit(buf, out)}, False{}}
524 case False{}:
525 Flow{3, SCon{c, buf}, out, False{}}
526
527def Flow.plain(+c: Char, +nxt: Char, buf: String, out: String) -> Flow:
528 Flow.plain.go(c, buf, out, Flow.ends(c, nxt))
529
530def Flow.step.go(+m: U32, b: String, o: String, e: Bool, +c: Char, +nxt: Char, m0: Bool, m1: Bool,
531 m2: Bool) -> Flow:
532 match m0 m1 m2:
533 case True{} _ _:
534 Flow.out0(c, o)
535 case False{} True{} _:
536 Flow.dq(e, c, o)
537 case False{} False{} True{}:
538 Flow.sq(e, c, nxt, o)
539 case _ _ _:
540 Flow.plain(c, nxt, b, o)
541
542def Flow.step(st: Flow, +c: Char, +nxt: Char) -> Flow:
543 match st:
544 case Flow{+m, b, o, e}:
545 Flow.step.go(m, b, o, e, c, nxt, U32.is_eq(m, 0), U32.is_eq(m, 1), U32.is_eq(m, 2))
546
547def Flow.go(s: String, st: Flow) -> Flow:
548 match s:
549 case SNil{}:
550 st
551 case SCon{+c, +t}:
552 Flow.go(t, Flow.step(st, c, Flow.peek(t)))
553
554def Flow.fin.go(b: String, o: String, plain: Bool) -> String:
555 match plain:
556 case True{}:
557 Flow.emit(b, o)
558 case False{}:
559 o
560
561def Flow.fin(st: Flow) -> String:
562 match st:
563 case Flow{+m, b, o, e}:
564 String.reverse(Flow.fin.go(b, o, U32.is_eq(m, 3)))
565
566
567def Yaml.flow(s: String) -> String:
568 Flow.fin(Flow.go(s, Flow{0, "", "", False{}}))
569
570
571
572
573
574
575
576
577
578
579
580def Yaml.split_word.go(s: String, acc: String) -> AV:
581 match s:
582 case SNil{}:
583 AV{String.reverse(acc), ""}
584 case SCon{' ', t}:
585 AV{String.reverse(acc), String.trim(t)}
586 case SCon{c, t}:
587 Yaml.split_word.go(t, SCon{c, acc})
588
589
590def Yaml.split_word(s: String) -> AV:
591 Yaml.split_word.go(s, "")
592
593def Yaml.scalar.untagged(+s: String) -> J.Json:
594 match s:
595 case SCon{'"', t}:
596 Yaml.json_or(J.Json.parse(s), s)
597 case SCon{'\'', t}:
598 J.JStr{Yaml.unsingle(Yaml.strip_ends(s))}
599 case x:
600 Yaml.plain(x)
601
602
603def Yaml.tagged(av: AV) -> J.Json:
604 match av:
605 case AV{"!str", r}:
606 J.JStr{r}
607 case AV{t, +r}:
608 Yaml.scalar.untagged(r)
609
610
611def Yaml.scalar(+s: String) -> J.Json:
612 match s:
613 case SCon{'*', t}:
614 J.JStr{SCon{Chr{0}, SCon{'*', t}}}
615 case SCon{'!', t}:
616 Yaml.tagged(Yaml.split_word(t))
617 case SCon{'"', t}:
618 Yaml.json_or(J.Json.parse(s), s)
619 case SCon{'\'', t}:
620 J.JStr{Yaml.unsingle(Yaml.strip_ends(s))}
621 case SCon{'[', t}:
622 Yaml.json_or(J.Json.parse(Yaml.flow(s)), s)
623 case SCon{'{', t}:
624 Yaml.json_or(J.Json.parse(Yaml.flow(s)), s)
625 case x:
626 Yaml.plain(x)
627
628def Yaml.key.go(s: String, acc: String) -> Maybe<&2, KR>:
629 match s:
630 case SNil{}:
631 None{}
632 case SCon{':', SNil{}}:
633 Some{KR{String.reverse(acc), ""}}
634 case SCon{':', SCon{' ', t}}:
635 Some{KR{String.reverse(acc), String.trim(t)}}
636 case SCon{c, t}:
637 Yaml.key.go(t, SCon{c, acc})
638
639def Yaml.unquote_key(+k: String) -> String:
640 match k:
641 case SCon{'"', t}:
642 Yaml.strip_ends(k)
643 case SCon{'\'', t}:
644 Yaml.strip_ends(k)
645 case x:
646 x
647
648def Yaml.key.fin(m: Maybe<&2, KR>) -> Maybe<&2, KR>:
649 match m:
650 case Some{KR{k, r}}:
651 Some{KR{Yaml.unquote_key(String.trim(k)), r}}
652 case None{}:
653 None{}
654
655def Yaml.key(+s: String) -> Maybe<&2, KR>:
656 match s:
657 case SCon{'"', t}:
658 Yaml.key.fin(Yaml.key.go(s, ""))
659 case SCon{'[', t}:
660 None{}
661 case SCon{'{', t}:
662 None{}
663 case x:
664 Yaml.key.fin(Yaml.key.go(x, ""))
665
666
667
668
669def Yaml.rev_kv(xs: List<&2, J.KV>, acc: J.Json) -> J.Json:
670 match xs:
671 case Nil{}:
672 acc
673 case Con{J.KV{k, v}, t}:
674 Yaml.rev_kv(t, J.JMem{k, v, acc})
675
676def Yaml.rev_items(xs: List<&2, J.Json>, acc: J.Json) -> J.Json:
677 match xs:
678 case Nil{}:
679 acc
680 case Con{h, t}:
681 Yaml.rev_items(t, J.JCons{h, acc})
682
683def Yaml.pend_null(p: Maybe<&2, String>, ms: List<&2, J.KV>) -> List<&2, J.KV>:
684 match p:
685 case Some{k}:
686 J.KV{k, J.JNull{}} <> ms
687 case None{}:
688 ms
689
690def Yaml.wrap.go(a: String, v: J.Json, none: Bool) -> J.Json:
691 match none:
692 case True{}:
693 v
694 case False{}:
695 J.JObj{J.JMem{SCon{Chr{0}, SCon{'&', a}}, v, J.JNil{}}}
696
697def Yaml.wrap(+a: String, v: J.Json) -> J.Json:
698 Yaml.wrap.go(a, v, String.is_empty(a))
699
700
701def Yaml.value(f: YFrame) -> J.Json:
702 match f:
703 case YMap{i, ms, p}:
704 J.JObj{Yaml.rev_kv(Yaml.pend_null(p, ms), J.JNil{})}
705 case YSeq{i, xs, None{}}:
706 J.JArr{Yaml.rev_items(xs, J.JNil{})}
707 case YSeq{i, xs, Some{a}}:
708 J.JArr{Yaml.rev_items(Yaml.wrap(a, J.JNull{}) <> xs, J.JNil{})}
709 case YRoot{v}:
710 v
711
712
713def Yaml.ctl(s: String, +n: U32) -> Bool:
714 match s:
715 case SCon{Chr{+c}, t}:
716 U32.is_eq(c, n)
717 case _:
718 False{}
719
720def Yaml.member.split(parts: List<&2, String>, v: J.Json) -> J.KV:
721 match parts:
722 case Con{a, Con{k, rest}}:
723 J.KV{String.join(k <> rest, SCon{Chr{1}, SNil{}}), Yaml.wrap(a, v)}
724 case _:
725 J.KV{"", v}
726
727def Yaml.member.go(k: String, v: J.Json, marked: Bool) -> J.KV:
728 match marked:
729 case True{}:
730 Yaml.member.split(String.split(String.drop(k, 1n), Chr{1}), v)
731 case False{}:
732 J.KV{k, v}
733
734
735def Yaml.member(+k: String, v: J.Json) -> J.KV:
736 Yaml.member.go(k, v, Yaml.ctl(k, 1))
737
738
739
740def Yaml.give(v: J.Json, st: List<&2, YFrame>) -> List<&2, YFrame>:
741 match st:
742 case Con{YMap{i, ms, Some{k}}, t}:
743 YMap{i, Yaml.member(k, v) <> ms, None{}} <> t
744 case Con{YSeq{i, xs, None{}}, t}:
745 YSeq{i, v <> xs, None{}} <> t
746 case Con{YSeq{i, xs, Some{a}}, t}:
747 YSeq{i, Yaml.wrap(a, v) <> xs, None{}} <> t
748 case Con{YMap{i, ms, None{}}, t}:
749 YMap{i, ms, None{}} <> t
750 case Con{YRoot{x}, t}:
751 YRoot{v} <> t
752 case Nil{}:
753 [YRoot{v}]
754
755def Yaml.top_indent(st: List<&2, YFrame>) -> U32:
756 match st:
757 case Con{YMap{i, ms, p}, t}:
758 i
759 case Con{YSeq{i, xs, p}, t}:
760 i
761 case _:
762 0
763
764
765
766def Yaml.ends(+st: List<&2, YFrame>, +i: U32, dash: Bool) -> Bool:
767 match st:
768 case Con{YMap{+j, ms, p}, t}:
769 U32.is_gt(j, i)
770 case Con{YSeq{+j, xs, p}, t}:
771 Bool.or(U32.is_gt(j, i), Bool.and(U32.is_eq(j, i), Bool.not(dash)))
772 case _:
773 False{}
774
775def Yaml.pop(st: List<&2, YFrame>) -> List<&2, YFrame>:
776 match st:
777 case Con{f, t}:
778 Yaml.give(Yaml.value(f), t)
779 case Nil{}:
780 Nil{}
781
782def Yaml.close(fuel: Nat, +st: List<&2, YFrame>, +i: U32, +dash: Bool, ends: Bool) -> List<&2, YFrame>:
783 match fuel ends:
784 case 1n+f True{}:
785 Yaml.close(f, Yaml.pop(st), i, dash, Yaml.ends(Yaml.pop(st), i, dash))
786 case _ _:
787 st
788
789def Yaml.map_at(+st: List<&2, YFrame>, +i: U32) -> Bool:
790 match st:
791 case Con{YMap{+j, ms, p}, t}:
792 U32.is_eq(j, i)
793 case _:
794 False{}
795
796def Yaml.mark.go(a: String, k: String, none: Bool) -> String:
797 match none:
798 case True{}:
799 k
800 case False{}:
801 SCon{Chr{1}, a ++ SCon{Chr{1}, k}}
802
803def Yaml.mark(+a: String, k: String) -> String:
804 Yaml.mark.go(a, k, String.is_empty(a))
805
806def Yaml.entry.put.go(st: List<&2, YFrame>, k: String, +a: String, +r: String, empty: Bool) ->
807 List<&2, YFrame>:
808 match st empty:
809 case Con{YMap{i, ms, p}, t} True{}:
810 YMap{i, ms, Some{Yaml.mark(a, k)}} <> t
811 case Con{YMap{i, ms, p}, t} False{}:
812 YMap{i, J.KV{k, Yaml.wrap(a, Yaml.scalar(r))} <> ms, None{}} <> t
813 case s _:
814 s
815
816def Yaml.entry.put.av(st: List<&2, YFrame>, k: String, av: AV) -> List<&2, YFrame>:
817 match av:
818 case AV{+a, +r}:
819 Yaml.entry.put.go(st, k, a, r, String.is_empty(r))
820
821def Yaml.split_anchor(+s: String) -> AV:
822 match s:
823 case SCon{'&', t}:
824 Yaml.split_word(t)
825 case x:
826 AV{"", x}
827
828def Yaml.entry.put(st: List<&2, YFrame>, k: String, +r: String, empty: Bool) -> List<&2, YFrame>:
829 Yaml.entry.put.av(st, k, Yaml.split_anchor(r))
830
831
832
833
834
835
836
837def Yaml.entry.go(st: List<&2, YFrame>, +i: U32, kr: KR, here: Bool) -> List<&2, YFrame>:
838 match kr here:
839 case KR{k, +r} True{}:
840 Yaml.entry.put(st, k, r, String.is_empty(r))
841 case KR{k, +r} False{}:
842 Yaml.entry.put(YMap{i, Nil{}, None{}} <> st, k, r, String.is_empty(r))
843
844
845def Yaml.entry(+st: List<&2, YFrame>, +i: U32, kr: KR) -> List<&2, YFrame>:
846 Yaml.entry.go(st, i, kr, Yaml.map_at(st, i))
847
848def Yaml.seq_at(+st: List<&2, YFrame>, +i: U32) -> Bool:
849 match st:
850 case Con{YSeq{+j, xs, p}, t}:
851 U32.is_eq(j, i)
852 case _:
853 False{}
854
855
856def Yaml.item.seq.go(st: List<&2, YFrame>, +i: U32, here: Bool) -> List<&2, YFrame>:
857 match st here:
858 case Con{YSeq{j, xs, Some{a}}, t} True{}:
859 YSeq{j, Yaml.wrap(a, J.JNull{}) <> xs, None{}} <> t
860 case x True{}:
861 x
862 case x False{}:
863 YSeq{i, Nil{}, None{}} <> x
864
865def Yaml.item.seq(+st: List<&2, YFrame>, +i: U32) -> List<&2, YFrame>:
866 Yaml.item.seq.go(st, i, Yaml.seq_at(st, i))
867
868def Yaml.item.value.go(st: List<&2, YFrame>, +a: String, +r: String, empty: Bool) -> List<&2, YFrame>:
869 match st empty:
870 case Con{YSeq{i, xs, p}, t} True{}:
871 YSeq{i, xs, Some{a}} <> t
872 case x _:
873 Yaml.give(Yaml.wrap(a, Yaml.scalar(r)), x)
874
875
876
877def Yaml.item.value(st: List<&2, YFrame>, av: AV) -> List<&2, YFrame>:
878 match av:
879 case AV{+a, +r}:
880 Yaml.item.value.go(st, a, r, String.is_empty(r))
881
882
883
884def Yaml.item.go(st: List<&2, YFrame>, +i: U32, rest: String, kr: Maybe<&2, KR>) -> List<&2, YFrame>:
885 match kr:
886 case Some{x}:
887 Yaml.entry.go(st, (i + 2 : U32), x, False{})
888 case None{}:
889 Yaml.item.value(st, Yaml.split_anchor(rest))
890
891
892def Yaml.item(+st: List<&2, YFrame>, +i: U32, +rest: String) -> List<&2, YFrame>:
893 Yaml.item.go(Yaml.item.seq(st, i), i, rest, Yaml.key(rest))
894
895def Yaml.is_dash(t: String) -> Bool:
896 match t:
897 case SCon{'-', SCon{' ', r}}:
898 True{}
899 case "-":
900 True{}
901 case _:
902 False{}
903
904def Yaml.after_dash(t: String) -> String:
905 String.trim(String.drop(t, 1n))
906
907def Yaml.step.entry(+st: List<&2, YFrame>, +i: U32, +t: String, kr: Maybe<&2, KR>) -> List<&2, YFrame>:
908 match kr:
909 case Some{x}:
910 Yaml.entry(st, i, x)
911 case None{}:
912 Yaml.give(Yaml.scalar(t), st)
913
914def Yaml.step.go(+st: List<&2, YFrame>, +i: U32, +t: String, dash: Bool) -> List<&2, YFrame>:
915 match dash:
916 case True{}:
917 Yaml.item(st, i, Yaml.after_dash(t))
918 case False{}:
919 Yaml.step.entry(st, i, t, Yaml.key(t))
920
921
922def Yaml.step(+st: List<&2, YFrame>, l: Line) -> List<&2, YFrame>:
923 match l:
924 case Line{+i, +t}:
925 Yaml.step.go(Yaml.close(64n, st, i, Yaml.is_dash(t), Yaml.ends(st, i, Yaml.is_dash(t))), i, t,
926 Yaml.is_dash(t))
927
928def Yaml.feed(ls: List<&2, Line>, +st: List<&2, YFrame>) -> List<&2, YFrame>:
929 match ls:
930 case Nil{}:
931 st
932 case Con{l, t}:
933 Yaml.feed(t, Yaml.step(st, l))
934
935def Yaml.result(st: List<&2, YFrame>) -> J.Json:
936 match st:
937 case Con{YRoot{v}, t}:
938 v
939 case Con{f, t}:
940 Yaml.value(f)
941 case Nil{}:
942 J.JNull{}
943
944def Yaml.is_open(st: List<&2, YFrame>) -> Bool:
945 match st:
946 case Con{YRoot{v}, t}:
947 False{}
948 case Con{f, t}:
949 True{}
950 case Nil{}:
951 False{}
952
953def Yaml.close_all.go(fuel: Nat, +st: List<&2, YFrame>, open: Bool) -> List<&2, YFrame>:
954 match fuel open:
955 case 1n+f True{}:
956 Yaml.close_all.go(f, Yaml.pop(st), Yaml.is_open(Yaml.pop(st)))
957 case _ _:
958 st
959
960
961def Yaml.close_all(fuel: Nat, +st: List<&2, YFrame>) -> List<&2, YFrame>:
962 Yaml.close_all.go(fuel, st, Yaml.is_open(st))
963
964def YR.json(r: YR) -> J.Json:
965 match r:
966 case YR{j, a}:
967 j
968
969
970
971
972
973def YR.anchors(r: YR) -> Map<&2, J.Json>:
974 match r:
975 case YR{j, a}:
976 a
977
978def Yaml.marker.go(n: String, hit: Bool) -> Maybe<&2, String>:
979 match hit:
980 case True{}:
981 Some{n}
982 case False{}:
983 None{}
984
985def Yaml.marker(s: String, +kind: Char) -> Maybe<&2, String>:
986 match s:
987 case SCon{Chr{+c}, SCon{+k, n}}:
988 Yaml.marker.go(n, Bool.and(U32.is_eq(c, 0), Char.is_eq(k, kind)))
989 case _:
990 None{}
991
992def Yaml.anchor_name(k: String) -> Maybe<&2, String>:
993 Yaml.marker(k, '&')
994
995def Yaml.res.mem(k: String, h: YR, t: YR) -> YR:
996 match h t:
997 case YR{v, a} YR{rest, a2}:
998 YR{J.JMem{k, v, rest}, a2}
999
1000def Yaml.res.cons(h: YR, t: YR) -> YR:
1001 match h t:
1002 case YR{v, a} YR{rest, a2}:
1003 YR{J.JCons{v, rest}, a2}
1004
1005def Yaml.merge.take(+ms: J.Json) -> J.Json:
1006 J.Json.lookup(ms, "<<")
1007
1008def Yaml.merge.missing.put(k: String, v: J.Json, rest: J.Json, h: Bool, has: Bool) -> J.Json:
1009 match has:
1010 case True{}:
1011 rest
1012 case False{}:
1013 J.JMem{k, v, rest}
1014
1015def Yaml.has(ms: J.Json, +k: String) -> Bool:
1016 Bool.not(J.Json.is_null(J.Json.lookup(ms, k)))
1017
1018
1019def Yaml.merge.missing(src: J.Json, +ms: J.Json) -> J.Json:
1020 match src:
1021 case J.JMem{+k, v, t}:
1022 Yaml.merge.missing.put(k, v, Yaml.merge.missing(t, ms), J.Json.head_is(ms, k), Yaml.has(ms, k))
1023 case _:
1024 J.JNil{}
1025
1026def Yaml.append_mem(ms: J.Json, extra: J.Json) -> J.Json:
1027 match ms:
1028 case J.JMem{k, v, t}:
1029 J.JMem{k, v, Yaml.append_mem(t, extra)}
1030 case _:
1031 extra
1032
1033def Yaml.merge.go(src: J.Json, +rest: J.Json) -> J.Json:
1034 match src:
1035 case J.JObj{m}:
1036 Yaml.append_mem(rest, Yaml.merge.missing(m, rest))
1037 case _:
1038 rest
1039
1040
1041def Yaml.merge(+ms: J.Json) -> J.Json:
1042 Yaml.merge.go(Yaml.merge.take(ms), J.Json.del_mem(ms, "<<"))
1043
1044def Yaml.res.obj(r: YR) -> YR:
1045 match r:
1046 case YR{ms, a}:
1047 YR{J.JObj{Yaml.merge(ms)}, a}
1048
1049def Yaml.res.arr(r: YR) -> YR:
1050 match r:
1051 case YR{xs, a}:
1052 YR{J.JArr{xs}, a}
1053
1054def Yaml.is_alias(s: String) -> Maybe<&2, String>:
1055 Yaml.marker(s, '*')
1056
1057def Yaml.lookup.fin(r: Map<&2, J.Json> & J.Json) -> J.Json:
1058 match r:
1059 case (m, v):
1060 v
1061
1062def Yaml.alias(+name: String, +anchors: Map<&2, J.Json>) -> J.Json:
1063 Yaml.lookup.fin(Map.get(J.Json, J.JNull{}, anchors, name))
1064
1065def Yaml.res.str(s: String, +a: Map<&2, J.Json>, alias: Maybe<&2, String>) -> YR:
1066 match alias:
1067 case Some{n}:
1068 YR{Yaml.alias(n, a), a}
1069 case None{}:
1070 YR{J.JStr{s}, a}
1071
1072def Yaml.res.anchor(+n: String, r: YR) -> YR:
1073 match r:
1074 case YR{+v, a}:
1075 YR{v, Map.set(&2, J.Json, a, n, v)}
1076
1077
1078def Yaml.res.single(+k: String, n: Maybe<&2, String>, +rv: YR, tail: J.Json, a: Map<&2, J.Json>) -> YR:
1079 match n:
1080 case Some{name}:
1081 Yaml.res.anchor(name, rv)
1082 case None{}:
1083 Yaml.res.obj(Yaml.res.mem(k, rv, YR{tail, YR.anchors(rv)}))
1084
1085
1086def Yaml.res(j: J.Json, +a: Map<&2, J.Json>) -> YR:
1087 match j:
1088 case J.JStr{+s}:
1089 Yaml.res.str(s, a, Yaml.is_alias(s))
1090 case J.JObj{J.JMem{+k, v, J.JNil{}}}:
1091 Yaml.res.single(k, Yaml.anchor_name(k), Yaml.res(v, a), J.JNil{}, a)
1092 case J.JObj{ms}:
1093 Yaml.res.obj(Yaml.res(ms, a))
1094 case J.JArr{xs}:
1095 Yaml.res.arr(Yaml.res(xs, a))
1096 case J.JCons{h, t}:
1097 +rh = Yaml.res(h, a)
1098 Yaml.res.cons(rh, Yaml.res(t, YR.anchors(rh)))
1099 case J.JMem{k, v, t}:
1100 +rv = Yaml.res(v, a)
1101 Yaml.res.mem(k, rv, Yaml.res(t, YR.anchors(rv)))
1102 case x:
1103 YR{x, a}
1104
1105def Yaml.resolve(j: J.Json) -> J.Json:
1106 YR.json(Yaml.res(j, Map.new(&2, J.Json)))
1107
1108
1109def Yaml.parse(s: String) -> J.Json:
1110 Yaml.resolve(Yaml.result(Yaml.close_all(64n, Yaml.feed(Yaml.lines(s), Nil{}))))
1111
1112
1113
1114
1115def Yaml.is_sep(+l: String) -> Bool:
1116 Bool.or(String.starts_with(l, "---"), String.eq(String.trim_end(l), "..."))
1117
1118def Yaml.docs.cur(+l: String, cur: List<&2, String>, sep: Bool) -> List<&2, String>:
1119 match sep:
1120 case True{}:
1121 Nil{}
1122 case False{}:
1123 l <> cur
1124
1125def Yaml.docs.done(+cur: List<&2, String>, done: List<&2, String>, sep: Bool) -> List<&2, String>:
1126 match sep:
1127 case True{}:
1128 String.join(List.reverse(&2, String, cur), "\n") <> done
1129 case False{}:
1130 done
1131
1132
1133def Yaml.docs.go(ls: List<&2, String>, +cur: List<&2, String>, done: List<&2, String>) -> List<&2, String>:
1134 match ls:
1135 case Nil{}:
1136 String.join(List.reverse(&2, String, cur), "\n") <> done
1137 case Con{+l, t}:
1138 Yaml.docs.go(t, Yaml.docs.cur(l, cur, Yaml.is_sep(l)), Yaml.docs.done(cur, done, Yaml.is_sep(l)))
1139
1140def Yaml.docs.keep(d: String, acc: List<&2, J.Json>, empty: Bool) -> List<&2, J.Json>:
1141 match empty:
1142 case True{}:
1143 acc
1144 case False{}:
1145 Yaml.parse(d) <> acc
1146
1147def Yaml.docs.parse(ds: List<&2, String>, acc: List<&2, J.Json>) -> List<&2, J.Json>:
1148 match ds:
1149 case Nil{}:
1150 acc
1151 case Con{+d, t}:
1152 Yaml.docs.parse(t, Yaml.docs.keep(d, acc, List.is_empty(&2, Line, Yaml.lines(d))))
1153
1154
1155
1156def Yaml.parse_all(s: String) -> List<&2, J.Json>:
1157 Yaml.docs.parse(Yaml.docs.go(String.lines(s), Nil{}, Nil{}), Nil{})