src/expand.bend
bend-toon-codec@0.1.0.0 · 216 lines · 24 definitions
1import Base
2import bend-toon-codec@0.1.0.0/src/json.bend as J
3import bend-toon-codec@0.1.0.0/src/split.bend as S
4import bend-toon-codec@0.1.0.0/src/head.bend as Hd
5import bend-toon-codec@0.1.0.0/src/fold.bend as K
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21def all_ident(+ks: List<&2, String>) -> Bool:
22 match ks:
23 case Nil{}:
24 True{}
25 case Con{k, t}:
26 K.ident(k) && all_ident(t)
27
28
29def eligible(+k: String) -> Bool:
30 K.has_dot(k) && all_ident(S.split(k, 46))
31
32def segs.bare(+e: Bool, +k: String) -> List<&2, String>:
33 match e:
34 case True{}:
35 S.split(k, 46)
36 case False{}:
37 Con{k, Nil{}}
38
39def segs.pick(+quoted: Bool, +k: String) -> List<&2, String>:
40 match quoted:
41 case True{}:
42 Con{Hd.unmark(k), Nil{}}
43 case False{}:
44 segs.bare(eligible(k), k)
45
46def segs_of(+k: String) -> List<&2, String>:
47 segs.pick(Hd.marked(k), k)
48
49def snoc(+ks: List<&2, String>, +k: String) -> List<&2, String>:
50 match ks:
51 case Nil{}:
52 Con{k, Nil{}}
53 case Con{h, t}:
54 Con{h, snoc(t, k)}
55
56
57
58
59def build(+segs: List<&2, String>, +leaf: J.Json) -> J.Json:
60 match segs:
61 case Nil{}:
62 leaf
63 case Con{s, rest}:
64 J.JObj{J.JField{s, build(rest, leaf), J.JNil{}}}
65
66def conflict(+strict: Bool, +segs: List<&2, String>, +leaf: J.Json) -> Result<&2, &2, String, J.Json>:
67 match strict:
68 case True{}:
69 Fail{"expansion conflict"}
70 case False{}:
71 Done{build(segs, leaf)}
72
73def empty_obj(+j: J.Json) -> Bool:
74 match j:
75 case J.JObj{J.JNil{}}:
76 True{}
77 case _:
78 False{}
79
80
81def same.pick(+ok: Bool, +strict: Bool, +e: J.Json, +leaf: J.Json) -> Result<&2, &2, String, J.Json>:
82 match ok:
83 case True{}:
84 Done{e}
85 case False{}:
86 conflict(strict, Nil{}, leaf)
87
88def wrap.obj(+r: Result<&2, &2, String, J.Json>) -> Result<&2, &2, String, J.Json>:
89 match r:
90 case Done{fs}:
91 Done{J.JObj{fs}}
92 case Fail{e}:
93 Fail{e}
94
95
96
97def cell(+hit: Bool, +k: String, +ev: J.Json, +t: J.Json, +rv: Result<&2, &2, String, J.Json>, +rt: Result<&2, &2, String, J.Json>) -> Result<&2, &2, String, J.Json>:
98 match hit rv rt:
99 case True{} Done{v} _:
100 Done{J.JField{k, v, t}}
101 case True{} Fail{e} _:
102 Fail{e}
103 case False{} _ Done{t2}:
104 Done{J.JField{k, ev, t2}}
105 case False{} _ Fail{e}:
106 Fail{e}
107
108
109
110def ins(+e: J.Json, +segs: List<&2, String>, +leaf: J.Json, +strict: Bool) -> Result<&2, &2, String, J.Json>:
111 match e segs:
112 case J.JObj{efs} Nil{}:
113 same.pick(empty_obj(leaf), strict, e, leaf)
114 case J.JObj{efs} Con{s, rest}:
115 wrap.obj(ins(efs, segs, leaf, strict))
116 case J.JField{k, ev, t} Con{s, rest}:
117 cell(Hd.keq(k, s), k, ev, t, ins(ev, rest, leaf, strict), ins(t, segs, leaf, strict))
118 case J.JNil{} Con{s, rest}:
119 Done{J.JField{s, build(rest, leaf), J.JNil{}}}
120 case J.JField{k, ev, t} Nil{}:
121 Done{e}
122 case J.JNil{} Nil{}:
123 Done{e}
124 case _ _:
125 conflict(strict, segs, leaf)
126
127def ins.r(+acc: Result<&2, &2, String, J.Json>, +segs: List<&2, String>, +leaf: J.Json, +strict: Bool) -> Result<&2, &2, String, J.Json>:
128 match acc:
129 case Done{a}:
130 ins(a, segs, leaf, strict)
131 case Fail{e}:
132 Fail{e}
133
134
135def fl.pick(+empty: Bool, +j: J.Json, +segs: List<&2, String>, +acc: Result<&2, &2, String, J.Json>, +strict: Bool, +r: Result<&2, &2, String, J.Json>) -> Result<&2, &2, String, J.Json>:
136 match empty:
137 case True{}:
138 ins.r(acc, segs, j, strict)
139 case False{}:
140 r
141
142def fl(+j: J.Json, +segs: List<&2, String>, +acc: Result<&2, &2, String, J.Json>, +strict: Bool) -> Result<&2, &2, String, J.Json>:
143 match j:
144 case J.JObj{fs}:
145 fl.pick(empty_obj(j), j, segs, acc, strict, fl(fs, segs, acc, strict))
146 case J.JField{k, v, t}:
147 fl(t, segs, fl(v, snoc(segs, k), acc, strict), strict)
148 case J.JNil{}:
149 acc
150 case _:
151 ins.r(acc, segs, j, strict)
152
153
154
155def init() -> Result<&2, &2, String, J.Json>:
156 Done{J.JObj{J.JNil{}}}
157
158def fl.r(+vr: Result<&2, &2, String, J.Json>, +segs: List<&2, String>, +acc: Result<&2, &2, String, J.Json>, +strict: Bool) -> Result<&2, &2, String, J.Json>:
159 match vr:
160 case Done{v}:
161 fl(v, segs, acc, strict)
162 case Fail{e}:
163 Fail{e}
164
165def arr.r(+r: Result<&2, &2, String, J.Json>) -> Result<&2, &2, String, J.Json>:
166 match r:
167 case Done{items}:
168 Done{J.JArr{items}}
169 case Fail{e}:
170 Fail{e}
171
172def cons.r(+h: Result<&2, &2, String, J.Json>, +t: Result<&2, &2, String, J.Json>) -> Result<&2, &2, String, J.Json>:
173 match h t:
174 case Done{x} Done{y}:
175 Done{J.JCons{x, y}}
176 case Fail{e} _:
177 Fail{e}
178 case _ Fail{e}:
179 Fail{e}
180
181def nil() -> Result<&2, &2, String, J.Json>:
182 Done{J.JNil{}}
183
184
185
186def ex(+j: J.Json, +acc: Result<&2, &2, String, J.Json>, +strict: Bool) -> Result<&2, &2, String, J.Json>:
187 match j:
188 case J.JObj{fs}:
189 ex(fs, init(), strict)
190 case J.JField{k, v, t}:
191 ex(t, fl.r(ex(v, init(), strict), segs_of(k), acc, strict), strict)
192 case J.JNil{}:
193 acc
194 case J.JArr{items}:
195 arr.r(ex(items, nil(), strict))
196 case J.JCons{h, t}:
197 cons.r(ex(h, init(), strict), ex(t, nil(), strict))
198 case _:
199 Done{j}
200
201
202def strip(+j: J.Json) -> J.Json:
203 match j:
204 case J.JObj{x}:
205 J.JObj{strip(x)}
206 case J.JArr{x}:
207 J.JArr{strip(x)}
208 case J.JCons{h, t}:
209 J.JCons{strip(h), strip(t)}
210 case J.JField{k, v, t}:
211 J.JField{Hd.unmark(k), strip(v), strip(t)}
212 case _:
213 j
214
215def expand(+j: J.Json, +strict: Bool) -> Result<&2, &2, String, J.Json>:
216 ex(j, init(), strict)