iso8601.bend
bend-datetime@0.4.0.0 · 792 lines · 0 definitions
1import Base
2import bend-scanner@0.1.0.0/parse.bend as P
3import bend-datetime@0.4.0.0/duration.bend as Dur
4import bend-datetime@0.4.0.0/period.bend as Per
5type Iso8601.Error is Data:
6 Unexpected{offset: Nat, char: Char}
7 Eof{offset: Nat}
8 Overflow{offset: Nat}
9 Extra{offset: Nat, char: Char}
10 Invalid{}
11type Iso8601.DurS is Data:
12 DurS{
13 days: U32, h: U32, mi: U32, s: U32, nanos: U32,
14 saw_d: Bool, saw_t: Bool, saw_h: Bool, saw_m: Bool, saw_s: Bool
15 }
16type Iso8601.DurM is Data:
17 DSeek{}
18 DNum{acc: U32}
19 DFrac{sec: U32, acc: U32, left: Nat}
20type Iso8601.DurC is Data:
21 DurFail{e: Iso8601.Error}
22 DurCont{st: Iso8601.DurS, mode: Iso8601.DurM}
23type Iso8601.PerS is Data:
24 PerS{
25 years: U32, months: U32, days: U32,
26 saw_y: Bool, saw_m: Bool, saw_w: Bool, saw_d: Bool
27 }
28type Iso8601.PerM is Data:
29 PSeek{}
30 PNum{acc: U32}
31type Iso8601.PerC is Data:
32 PerFail{e: Iso8601.Error}
33 PerCont{st: Iso8601.PerS, mode: Iso8601.PerM}
34def Iso8601.from_parse(e: P.Parse.Error) -> Iso8601.Error:
35 match e:
36 case P.Unexpected{offset, char}:
37 Unexpected{offset, char}
38 case P.Eof{offset}:
39 Eof{offset}
40 case P.Overflow{offset}:
41 Overflow{offset}
42 case P.Extra{offset, char}:
43 Extra{offset, char}
44def Iso8601.digit(n: U32) -> Char:
45 Char.from_u32((Char.to_u32('0') + n : U32))
46def Iso8601.pad_n.go(k: Nat, +n: U32, acc: String) -> String:
47 match k:
48 case 0n:
49 acc
50 case 1n++p:
51 Iso8601.pad_n.go(
52 p, U32.div(n, 10), SCon{Iso8601.digit(U32.mod(n, 10)), acc}
53 )
54def Iso8601.pad_n(n: U32, k: Nat) -> String:
55 Iso8601.pad_n.go(k, n, SNil{})
56def Iso8601.lead0(s: String) -> Bool:
57 match s:
58 case SNil{}:
59 False{}
60 case SCon{h, _}:
61 Char.is_eq(h, '0')
62def Iso8601.strip0(k: Nat, s: String, z: Bool) -> String:
63 match k:
64 case 0n:
65 SCon{'0', SNil{}}
66 case 1n++p:
67 match s:
68 case SNil{}:
69 SCon{'0', SNil{}}
70 case SCon{+h, +t}:
71 match z:
72 case False{}:
73 SCon{h, t}
74 case True{}:
75 Iso8601.strip0(p, t, Iso8601.lead0(t))
76def Iso8601.show_u32(+n: U32) -> String:
77 +s = Iso8601.pad_n(n, 10n)
78 Iso8601.strip0(10n, s, Iso8601.lead0(s))
79def Iso8601.show.unit.go(+n: U32, c: Char, z: Bool) -> String:
80 match z:
81 case True{}:
82 SNil{}
83 case False{}:
84 String.append(Iso8601.show_u32(n), SCon{c, SNil{}})
85def Iso8601.show.unit(+n: U32, c: Char) -> String:
86 Iso8601.show.unit.go(n, c, U32.is_eq(n, 0))
87def Iso8601.frac.strip.go(+k: Nat, +n: U32, z: Bool) -> U32 & Nat:
88 match k:
89 case 0n:
90 (n, 1n)
91 case 1n:
92 (n, 1n)
93 case 1n++p:
94 match z:
95 case True{}:
96 Iso8601.frac.strip.go(
97 p, U32.div(n, 10), U32.is_eq(U32.mod(U32.div(n, 10), 10), 0)
98 )
99 case False{}:
100 (n, k)
101def Iso8601.frac.strip(+n: U32, k: Nat) -> U32 & Nat:
102 Iso8601.frac.strip.go(k, n, U32.is_eq(U32.mod(n, 10), 0))
103def Iso8601.show.frac2(nk: U32 & Nat) -> String:
104 (n, k) = nk
105 Iso8601.pad_n(n, k)
106def Iso8601.show.frac(+nanos: U32) -> String:
107 Iso8601.show.frac2(Iso8601.frac.strip(nanos, 9n))
108def Iso8601.show.s2(+s: U32, +nanos: U32, z: Bool) -> String:
109 match z:
110 case True{}:
111 String.append(Iso8601.show_u32(s), "S")
112 case False{}:
113 String.append(
114 Iso8601.show_u32(s),
115 String.append(".", String.append(Iso8601.show.frac(nanos), "S"))
116 )
117def Iso8601.show.s(+s: U32, +nanos: U32, need: Bool) -> String:
118 match need:
119 case False{}:
120 SNil{}
121 case True{}:
122 Iso8601.show.s2(s, nanos, U32.is_eq(nanos, 0))
123def Iso8601.show.t(
124 +h: U32, +mi: U32, +s: U32, +nanos: U32
125) -> String:
126 String.append(
127 Iso8601.show.unit(h, 'H'),
128 String.append(
129 Iso8601.show.unit(mi, 'M'),
130 Iso8601.show.s(s, nanos, Bool.or(U32.is_gt(s, 0), U32.is_gt(nanos, 0)))
131 )
132 )
133def Iso8601.show_duration.go(
134 +days: U32, +h: U32, +mi: U32, +s: U32, +nanos: U32, has_d: Bool, has_t: Bool
135) -> String:
136 match has_d has_t:
137 case False{} False{}:
138 "PT0S"
139 case True{} False{}:
140 String.append("P", String.append(Iso8601.show_u32(days), "D"))
141 case False{} True{}:
142 String.append("PT", Iso8601.show.t(h, mi, s, nanos))
143 case True{} True{}:
144 String.append(
145 "P",
146 String.append(
147 Iso8601.show_u32(days),
148 String.append("DT", Iso8601.show.t(h, mi, s, nanos))
149 )
150 )
151def Iso8601.show_duration.has(
152 +days: U32, +h: U32, +mi: U32, +s: U32, +nanos: U32
153) -> String:
154 Iso8601.show_duration.go(
155 days, h, mi, s, nanos,
156 U32.is_gt(days, 0),
157 Bool.or(
158 U32.is_gt(h, 0),
159 Bool.or(
160 U32.is_gt(mi, 0),
161 Bool.or(U32.is_gt(s, 0), U32.is_gt(nanos, 0))
162 )
163 )
164 )
165def Iso8601.show_duration(d: Dur.Duration) -> String:
166 match d:
167 case Dur.Duration{+days, +sod, +nanos}:
168 Iso8601.show_duration.has(
169 days,
170 U32.div(sod, 3600),
171 U32.div(U32.mod(sod, 3600), 60),
172 U32.mod(sod, 60),
173 nanos
174 )
175def Iso8601.show_period.body(+y: U32, +m: U32, +d: U32) -> String:
176 String.append(
177 Iso8601.show.unit(y, 'Y'),
178 String.append(Iso8601.show.unit(m, 'M'), Iso8601.show.unit(d, 'D'))
179 )
180def Iso8601.show_period.p(body: String) -> String:
181 match body:
182 case SNil{}:
183 "P0D"
184 case SCon{_, _}:
185 String.append("P", body)
186def Iso8601.show_period(p: Per.Period) -> String:
187 match p:
188 case Per.Period{+y, +m, +d}:
189 Iso8601.show_period.p(Iso8601.show_period.body(y, m, d))
190def Iso8601.dur0() -> Iso8601.DurS:
191 DurS{0, 0, 0, 0, 0, False{}, False{}, False{}, False{}, False{}}
192def Iso8601.per0() -> Iso8601.PerS:
193 PerS{0, 0, 0, False{}, False{}, False{}, False{}}
194def Iso8601.or3(+a: Bool, +b: Bool, +c: Bool) -> Bool:
195 Bool.or(a, Bool.or(b, c))
196def Iso8601.or4(+a: Bool, +b: Bool, +c: Bool, +d: Bool) -> Bool:
197 Bool.or(a, Iso8601.or3(b, c, d))
198def Iso8601.expect.map(
199 r: Result<&2, &2, P.Parse.Error, P.Parse.Cur>
200) -> Result<&2, &2, Iso8601.Error, P.Parse.Cur>:
201 match r:
202 case Fail{e}:
203 Fail{Iso8601.from_parse(e)}
204 case Done{cur}:
205 Done{cur}
206def Iso8601.expect(
207 cur: P.Parse.Cur, +c: Char
208) -> Result<&2, &2, Iso8601.Error, P.Parse.Cur>:
209 Iso8601.expect.map(P.Parse.expect_char(cur, c))
210def Iso8601.dur.mk.ns2(
211 r: Result<&2, &2, Dur.Duration.Error, Dur.Duration>
212) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
213 match r:
214 case Fail{_}:
215 Fail{Invalid{}}
216 case Done{d}:
217 Done{d}
218def Iso8601.dur.mk.ns(
219 r: Result<&2, &2, Dur.Duration.Error, Dur.Duration>, nanos: U32
220) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
221 match r:
222 case Fail{_}:
223 Fail{Invalid{}}
224 case Done{d}:
225 Iso8601.dur.mk.ns2(Dur.Duration.add(d, Dur.Duration{0, 0, nanos}))
226def Iso8601.dur.mk.s(
227 r: Result<&2, &2, Dur.Duration.Error, Dur.Duration>, +s: U32, nanos: U32
228) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
229 match r:
230 case Fail{_}:
231 Fail{Invalid{}}
232 case Done{d}:
233 Iso8601.dur.mk.ns(Dur.Duration.add(d, Dur.Duration.from_secs(s)), nanos)
234def Iso8601.dur.mk.mi2(
235 d: Dur.Duration, rm: Result<&2, &2, Dur.Duration.Error, Dur.Duration>,
236 s: U32, nanos: U32
237) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
238 match rm:
239 case Fail{_}:
240 Fail{Invalid{}}
241 case Done{dm}:
242 Iso8601.dur.mk.s(Dur.Duration.add(d, dm), s, nanos)
243def Iso8601.dur.mk.mi(
244 r: Result<&2, &2, Dur.Duration.Error, Dur.Duration>, +mi: U32, s: U32, nanos: U32
245) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
246 match r:
247 case Fail{_}:
248 Fail{Invalid{}}
249 case Done{d}:
250 Iso8601.dur.mk.mi2(d, Dur.Duration.from_mins(mi), s, nanos)
251def Iso8601.dur.mk.h2(
252 d: Dur.Duration, rh: Result<&2, &2, Dur.Duration.Error, Dur.Duration>,
253 mi: U32, s: U32, nanos: U32
254) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
255 match rh:
256 case Fail{_}:
257 Fail{Invalid{}}
258 case Done{dh}:
259 Iso8601.dur.mk.mi(Dur.Duration.add(d, dh), mi, s, nanos)
260def Iso8601.dur.mk.h(
261 r: Result<&2, &2, Dur.Duration.Error, Dur.Duration>, +h: U32, mi: U32, s: U32, nanos: U32
262) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
263 match r:
264 case Fail{_}:
265 Fail{Invalid{}}
266 case Done{d}:
267 Iso8601.dur.mk.h2(d, Dur.Duration.from_hours(h), mi, s, nanos)
268def Iso8601.dur.mk(st: Iso8601.DurS) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
269 match st:
270 case DurS{+days, +h, +mi, +s, +nanos, _, _, _, _, _}:
271 Iso8601.dur.mk.h(
272 Done{Dur.Duration.from_days(days)}, h, mi, s, nanos
273 )
274def Iso8601.dur.valid3(
275 st: Iso8601.DurS, has: Bool, tok: Bool
276) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
277 match has:
278 case False{}:
279 Fail{Invalid{}}
280 case True{}:
281 match tok:
282 case False{}:
283 Fail{Invalid{}}
284 case True{}:
285 Iso8601.dur.mk(st)
286def Iso8601.dur.valid(+st: Iso8601.DurS) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
287 match st:
288 case DurS{_, _, _, _, _, +saw_d, +saw_t, +saw_h, +saw_m, +saw_s}:
289 Iso8601.dur.valid3(
290 st,
291 Iso8601.or4(saw_d, saw_h, saw_m, saw_s),
292 Bool.or(Bool.not(saw_t), Iso8601.or3(saw_h, saw_m, saw_s))
293 )
294def Iso8601.dur.eof(
295 st: Iso8601.DurS, mode: Iso8601.DurM
296) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
297 match mode:
298 case DSeek{}:
299 Iso8601.dur.valid(st)
300 case DNum{_}:
301 Fail{Invalid{}}
302 case DFrac{_, _, _}:
303 Fail{Invalid{}}
304def Iso8601.dur.put_t2(
305 days: U32, h: U32, mi: U32, s: U32, nanos: U32,
306 saw_d: Bool, saw_h: Bool, saw_m: Bool, saw_s: Bool, dup: Bool
307) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
308 match dup:
309 case True{}:
310 Fail{Invalid{}}
311 case False{}:
312 Done{DurS{days, h, mi, s, nanos, saw_d, True{}, saw_h, saw_m, saw_s}}
313def Iso8601.dur.put_t(st: Iso8601.DurS) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
314 match st:
315 case DurS{days, h, mi, s, nanos, saw_d, +saw_t, saw_h, saw_m, saw_s}:
316 Iso8601.dur.put_t2(
317 days, h, mi, s, nanos, saw_d, saw_h, saw_m, saw_s, saw_t
318 )
319def Iso8601.dur.put_d2(
320 n: U32, h: U32, mi: U32, s: U32, nanos: U32,
321 saw_h: Bool, saw_m: Bool, saw_s: Bool, bad: Bool
322) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
323 match bad:
324 case True{}:
325 Fail{Invalid{}}
326 case False{}:
327 Done{DurS{n, h, mi, s, nanos, True{}, False{}, saw_h, saw_m, saw_s}}
328def Iso8601.dur.put_d(
329 st: Iso8601.DurS, n: U32
330) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
331 match st:
332 case DurS{_, h, mi, s, nanos, +saw_d, +saw_t, saw_h, saw_m, saw_s}:
333 Iso8601.dur.put_d2(
334 n, h, mi, s, nanos, saw_h, saw_m, saw_s, Bool.or(saw_d, saw_t)
335 )
336def Iso8601.dur.put_h2(
337 days: U32, n: U32, mi: U32, s: U32, nanos: U32,
338 saw_d: Bool, saw_m: Bool, saw_s: Bool, bad: Bool
339) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
340 match bad:
341 case True{}:
342 Fail{Invalid{}}
343 case False{}:
344 Done{DurS{days, n, mi, s, nanos, saw_d, True{}, True{}, saw_m, saw_s}}
345def Iso8601.dur.put_h(
346 st: Iso8601.DurS, n: U32
347) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
348 match st:
349 case DurS{days, _, mi, s, nanos, saw_d, +saw_t, +saw_h, +saw_m, +saw_s}:
350 Iso8601.dur.put_h2(
351 days, n, mi, s, nanos, saw_d, saw_m, saw_s,
352 Bool.or(Bool.not(saw_t), Iso8601.or3(saw_h, saw_m, saw_s))
353 )
354def Iso8601.dur.put_m2(
355 days: U32, h: U32, n: U32, s: U32, nanos: U32,
356 saw_d: Bool, saw_h: Bool, saw_s: Bool, bad: Bool
357) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
358 match bad:
359 case True{}:
360 Fail{Invalid{}}
361 case False{}:
362 Done{DurS{days, h, n, s, nanos, saw_d, True{}, saw_h, True{}, saw_s}}
363def Iso8601.dur.put_m(
364 st: Iso8601.DurS, n: U32
365) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
366 match st:
367 case DurS{days, h, _, s, nanos, saw_d, +saw_t, saw_h, +saw_m, +saw_s}:
368 Iso8601.dur.put_m2(
369 days, h, n, s, nanos, saw_d, saw_h, saw_s,
370 Bool.or(Bool.not(saw_t), Bool.or(saw_m, saw_s))
371 )
372def Iso8601.dur.put_s2(
373 days: U32, h: U32, mi: U32, n: U32, nanos: U32,
374 saw_d: Bool, saw_h: Bool, saw_m: Bool, bad: Bool
375) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
376 match bad:
377 case True{}:
378 Fail{Invalid{}}
379 case False{}:
380 Done{DurS{days, h, mi, n, nanos, saw_d, True{}, saw_h, saw_m, True{}}}
381def Iso8601.dur.put_s(
382 st: Iso8601.DurS, n: U32, nanos: U32
383) -> Result<&2, &2, Iso8601.Error, Iso8601.DurS>:
384 match st:
385 case DurS{days, h, mi, _, _, saw_d, +saw_t, saw_h, saw_m, +saw_s}:
386 Iso8601.dur.put_s2(
387 days, h, mi, n, nanos, saw_d, saw_h, saw_m,
388 Bool.or(Bool.not(saw_t), saw_s)
389 )
390def Iso8601.dur.frac.scale(+acc: U32, got: Nat) -> U32:
391 U32.mul(acc, U32.pow(10, Nat.sub(9n, got)))
392def Iso8601.dur.cont_r(
393 r: Result<&2, &2, Iso8601.Error, Iso8601.DurS>, mode: Iso8601.DurM
394) -> Iso8601.DurC:
395 match r:
396 case Fail{e}:
397 DurFail{e}
398 case Done{st}:
399 DurCont{st, mode}
400def Iso8601.dur.ndig2(
401 off: Nat, st: Iso8601.DurS, +acc: U32, +h: Char, s: P.Parse.St
402) -> Iso8601.DurC:
403 match s:
404 case P.StOv{}:
405 DurFail{Overflow{off}}
406 case P.StBad{_}:
407 DurFail{Invalid{}}
408 case P.StOk{}:
409 DurCont{st, DNum{P.Parse.nacc(acc, h)}}
410def Iso8601.dur.ndig(
411 off: Nat, st: Iso8601.DurS, +acc: U32, +h: Char
412) -> Iso8601.DurC:
413 Iso8601.dur.ndig2(off, st, acc, h, P.Parse.st.of(acc, h, U32.not(0)))
414def Iso8601.dur.unit_dot(
415 st: Iso8601.DurS, n: U32, is_dot: Bool
416) -> Iso8601.DurC:
417 match is_dot:
418 case True{}:
419 DurCont{st, DFrac{n, 0, 9n}}
420 case False{}:
421 DurFail{Invalid{}}
422def Iso8601.dur.unit_s(
423 st: Iso8601.DurS, n: U32, +c: Char, is_s: Bool
424) -> Iso8601.DurC:
425 match is_s:
426 case True{}:
427 Iso8601.dur.cont_r(Iso8601.dur.put_s(st, n, 0), DSeek{})
428 case False{}:
429 Iso8601.dur.unit_dot(st, n, Char.is_eq(c, '.'))
430def Iso8601.dur.unit_m(
431 st: Iso8601.DurS, n: U32, +c: Char, is_m: Bool
432) -> Iso8601.DurC:
433 match is_m:
434 case True{}:
435 Iso8601.dur.cont_r(Iso8601.dur.put_m(st, n), DSeek{})
436 case False{}:
437 Iso8601.dur.unit_s(st, n, c, Char.is_eq(c, 'S'))
438def Iso8601.dur.unit_h(
439 st: Iso8601.DurS, n: U32, +c: Char, is_h: Bool
440) -> Iso8601.DurC:
441 match is_h:
442 case True{}:
443 Iso8601.dur.cont_r(Iso8601.dur.put_h(st, n), DSeek{})
444 case False{}:
445 Iso8601.dur.unit_m(st, n, c, Char.is_eq(c, 'M'))
446def Iso8601.dur.unit(
447 st: Iso8601.DurS, n: U32, +c: Char
448) -> Iso8601.DurC:
449 Iso8601.dur.unit_h(st, n, c, Char.is_eq(c, 'H'))
450def Iso8601.dur.unit_d(
451 st: Iso8601.DurS, n: U32, +c: Char, is_d: Bool
452) -> Iso8601.DurC:
453 match is_d:
454 case True{}:
455 Iso8601.dur.cont_r(Iso8601.dur.put_d(st, n), DSeek{})
456 case False{}:
457 Iso8601.dur.unit(st, n, c)
458def Iso8601.dur.num(
459 off: Nat, st: Iso8601.DurS, acc: U32, +h: Char, is_dig: Bool
460) -> Iso8601.DurC:
461 match is_dig:
462 case True{}:
463 Iso8601.dur.ndig(off, st, acc, h)
464 case False{}:
465 Iso8601.dur.unit_d(st, acc, h, Char.is_eq(h, 'D'))
466def Iso8601.dur.frac.s2(
467 st: Iso8601.DurS, sec: U32, acc: U32, left: Nat, empty: Bool
468) -> Iso8601.DurC:
469 match empty:
470 case True{}:
471 DurFail{Invalid{}}
472 case False{}:
473 Iso8601.dur.cont_r(
474 Iso8601.dur.put_s(st, sec, Iso8601.dur.frac.scale(acc, Nat.sub(9n, left))),
475 DSeek{}
476 )
477def Iso8601.dur.frac.s(
478 st: Iso8601.DurS, sec: U32, acc: U32, +left: Nat, is_s: Bool
479) -> Iso8601.DurC:
480 match is_s:
481 case True{}:
482 Iso8601.dur.frac.s2(st, sec, acc, left, Nat.is_eq(left, 9n))
483 case False{}:
484 DurFail{Invalid{}}
485def Iso8601.dur.frac.dig(
486 st: Iso8601.DurS, sec: U32, +acc: U32, left: Nat, +h: Char
487) -> Iso8601.DurC:
488 match left:
489 case 0n:
490 DurFail{Invalid{}}
491 case 1n++p:
492 DurCont{st, DFrac{sec, P.Parse.nacc(acc, h), p}}
493def Iso8601.dur.frac(
494 st: Iso8601.DurS, sec: U32, acc: U32, left: Nat, +h: Char, is_dig: Bool
495) -> Iso8601.DurC:
496 match is_dig:
497 case True{}:
498 Iso8601.dur.frac.dig(st, sec, acc, left, h)
499 case False{}:
500 Iso8601.dur.frac.s(st, sec, acc, left, Char.is_eq(h, 'S'))
501def Iso8601.dur.seek2(
502 off: Nat, st: Iso8601.DurS, +h: Char, is_dig: Bool
503) -> Iso8601.DurC:
504 match is_dig:
505 case True{}:
506 DurCont{st, DNum{P.Parse.nacc(0, h)}}
507 case False{}:
508 DurFail{Extra{off, h}}
509def Iso8601.dur.seek(
510 off: Nat, st: Iso8601.DurS, h: Char, is_t: Bool, is_dig: Bool
511) -> Iso8601.DurC:
512 match is_t:
513 case True{}:
514 Iso8601.dur.cont_r(Iso8601.dur.put_t(st), DSeek{})
515 case False{}:
516 Iso8601.dur.seek2(off, st, h, is_dig)
517def Iso8601.dur.act(
518 off: Nat, st: Iso8601.DurS, mode: Iso8601.DurM, +h: Char, is_t: Bool, is_dig: Bool
519) -> Iso8601.DurC:
520 match mode:
521 case DSeek{}:
522 Iso8601.dur.seek(off, st, h, is_t, is_dig)
523 case DNum{acc}:
524 Iso8601.dur.num(off, st, acc, h, is_dig)
525 case DFrac{sec, acc, left}:
526 Iso8601.dur.frac(st, sec, acc, left, h, is_dig)
527def Iso8601.dur.go(
528 s: String, +off: Nat, c: Iso8601.DurC
529) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
530 match s c:
531 case _ DurFail{e}:
532 Fail{e}
533 case SNil{} DurCont{st, mode}:
534 Iso8601.dur.eof(st, mode)
535 case SCon{+h, t} DurCont{st, mode}:
536 Iso8601.dur.go(
537 t, 1n+off,
538 Iso8601.dur.act(
539 off, st, mode, h, Char.is_eq(h, 'T'), Char.is_digit(h)
540 )
541 )
542def Iso8601.read_duration.p(
543 r: Result<&2, &2, Iso8601.Error, P.Parse.Cur>
544) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
545 match r:
546 case Fail{e}:
547 Fail{e}
548 case Done{P.Cur{s, off}}:
549 Iso8601.dur.go(s, off, DurCont{Iso8601.dur0(), DSeek{}})
550def Iso8601.read_duration(
551 text: String
552) -> Result<&2, &2, Iso8601.Error, Dur.Duration>:
553 Iso8601.read_duration.p(Iso8601.expect(P.Parse.start(text), 'P'))
554def Iso8601.per.mk2(
555 r: Result<&2, &2, Per.Period.Error, Per.Period>
556) -> Result<&2, &2, Iso8601.Error, Per.Period>:
557 match r:
558 case Fail{_}:
559 Fail{Invalid{}}
560 case Done{p}:
561 Done{p}
562def Iso8601.per.valid2(
563 y: U32, m: U32, d: U32, ok: Bool
564) -> Result<&2, &2, Iso8601.Error, Per.Period>:
565 match ok:
566 case False{}:
567 Fail{Invalid{}}
568 case True{}:
569 Iso8601.per.mk2(Per.Period.from(y, m, d))
570def Iso8601.per.valid(st: Iso8601.PerS) -> Result<&2, &2, Iso8601.Error, Per.Period>:
571 match st:
572 case PerS{+y, +m, +d, +saw_y, +saw_m, +saw_w, +saw_d}:
573 Iso8601.per.valid2(y, m, d, Iso8601.or4(saw_y, saw_m, saw_w, saw_d))
574def Iso8601.per.eof(
575 st: Iso8601.PerS, mode: Iso8601.PerM
576) -> Result<&2, &2, Iso8601.Error, Per.Period>:
577 match mode:
578 case PSeek{}:
579 Iso8601.per.valid(st)
580 case PNum{_}:
581 Fail{Invalid{}}
582def Iso8601.add_u32.go(+a: U32, +b: U32, ov: Bool) -> Result<&2, &2, Iso8601.Error, U32>:
583 match ov:
584 case True{}:
585 Fail{Invalid{}}
586 case False{}:
587 Done{U32.add(a, b)}
588def Iso8601.add_u32(+a: U32, +b: U32) -> Result<&2, &2, Iso8601.Error, U32>:
589 Iso8601.add_u32.go(a, b, U32.is_gt(b, U32.sub(U32.not(0), a)))
590def Iso8601.per.weeks2(+n: U32, ov: Bool) -> Result<&2, &2, Iso8601.Error, U32>:
591 match ov:
592 case True{}:
593 Fail{Invalid{}}
594 case False{}:
595 Done{U32.mul(n, 7)}
596def Iso8601.per.weeks(+n: U32) -> Result<&2, &2, Iso8601.Error, U32>:
597 Iso8601.per.weeks2(n, U32.is_gt(n, U32.div(U32.not(0), 7)))
598def Iso8601.per.put_y2(
599 n: U32, m: U32, d: U32, saw_m: Bool, saw_w: Bool, saw_d: Bool, bad: Bool
600) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
601 match bad:
602 case True{}:
603 Fail{Invalid{}}
604 case False{}:
605 Done{PerS{n, m, d, True{}, saw_m, saw_w, saw_d}}
606def Iso8601.per.put_y(
607 st: Iso8601.PerS, n: U32
608) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
609 match st:
610 case PerS{_, m, d, +saw_y, +saw_m, +saw_w, +saw_d}:
611 Iso8601.per.put_y2(
612 n, m, d, saw_m, saw_w, saw_d, Iso8601.or4(saw_y, saw_m, saw_w, saw_d)
613 )
614def Iso8601.per.put_m2(
615 y: U32, n: U32, d: U32, saw_y: Bool, saw_w: Bool, saw_d: Bool, bad: Bool
616) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
617 match bad:
618 case True{}:
619 Fail{Invalid{}}
620 case False{}:
621 Done{PerS{y, n, d, saw_y, True{}, saw_w, saw_d}}
622def Iso8601.per.put_m(
623 st: Iso8601.PerS, n: U32
624) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
625 match st:
626 case PerS{y, _, d, saw_y, +saw_m, +saw_w, +saw_d}:
627 Iso8601.per.put_m2(
628 y, n, d, saw_y, saw_w, saw_d, Iso8601.or3(saw_m, saw_w, saw_d)
629 )
630def Iso8601.per.put_w.go(
631 y: U32, m: U32, saw_y: Bool, saw_m: Bool,
632 rw: Result<&2, &2, Iso8601.Error, U32>
633) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
634 match rw:
635 case Fail{e}:
636 Fail{e}
637 case Done{w}:
638 Done{PerS{y, m, w, saw_y, saw_m, True{}, False{}}}
639def Iso8601.per.put_w2(
640 y: U32, m: U32, saw_y: Bool, saw_m: Bool, n: U32, bad: Bool
641) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
642 match bad:
643 case True{}:
644 Fail{Invalid{}}
645 case False{}:
646 Iso8601.per.put_w.go(y, m, saw_y, saw_m, Iso8601.per.weeks(n))
647def Iso8601.per.put_w(
648 st: Iso8601.PerS, n: U32
649) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
650 match st:
651 case PerS{y, m, _, saw_y, saw_m, +saw_w, +saw_d}:
652 Iso8601.per.put_w2(y, m, saw_y, saw_m, n, Bool.or(saw_w, saw_d))
653def Iso8601.per.put_d.go(
654 y: U32, m: U32, saw_y: Bool, saw_m: Bool, saw_w: Bool,
655 rd: Result<&2, &2, Iso8601.Error, U32>
656) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
657 match rd:
658 case Fail{e}:
659 Fail{e}
660 case Done{days}:
661 Done{PerS{y, m, days, saw_y, saw_m, saw_w, True{}}}
662def Iso8601.per.put_d2(
663 y: U32, m: U32, d: U32, saw_y: Bool, saw_m: Bool, saw_w: Bool, n: U32, bad: Bool
664) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
665 match bad:
666 case True{}:
667 Fail{Invalid{}}
668 case False{}:
669 Iso8601.per.put_d.go(y, m, saw_y, saw_m, saw_w, Iso8601.add_u32(d, n))
670def Iso8601.per.put_d(
671 st: Iso8601.PerS, n: U32
672) -> Result<&2, &2, Iso8601.Error, Iso8601.PerS>:
673 match st:
674 case PerS{y, m, d, saw_y, saw_m, saw_w, +saw_d}:
675 Iso8601.per.put_d2(y, m, d, saw_y, saw_m, saw_w, n, saw_d)
676def Iso8601.per.cont_r(
677 r: Result<&2, &2, Iso8601.Error, Iso8601.PerS>, mode: Iso8601.PerM
678) -> Iso8601.PerC:
679 match r:
680 case Fail{e}:
681 PerFail{e}
682 case Done{st}:
683 PerCont{st, mode}
684def Iso8601.per.ndig2(
685 off: Nat, st: Iso8601.PerS, +acc: U32, +h: Char, s: P.Parse.St
686) -> Iso8601.PerC:
687 match s:
688 case P.StOv{}:
689 PerFail{Overflow{off}}
690 case P.StBad{_}:
691 PerFail{Invalid{}}
692 case P.StOk{}:
693 PerCont{st, PNum{P.Parse.nacc(acc, h)}}
694def Iso8601.per.ndig(
695 off: Nat, st: Iso8601.PerS, +acc: U32, +h: Char
696) -> Iso8601.PerC:
697 Iso8601.per.ndig2(off, st, acc, h, P.Parse.st.of(acc, h, U32.not(0)))
698def Iso8601.per.unit_d(
699 st: Iso8601.PerS, n: U32, is_d: Bool
700) -> Iso8601.PerC:
701 match is_d:
702 case True{}:
703 Iso8601.per.cont_r(Iso8601.per.put_d(st, n), PSeek{})
704 case False{}:
705 PerFail{Invalid{}}
706def Iso8601.per.unit_w(
707 st: Iso8601.PerS, n: U32, +c: Char, is_w: Bool
708) -> Iso8601.PerC:
709 match is_w:
710 case True{}:
711 Iso8601.per.cont_r(Iso8601.per.put_w(st, n), PSeek{})
712 case False{}:
713 Iso8601.per.unit_d(st, n, Char.is_eq(c, 'D'))
714def Iso8601.per.unit_m(
715 st: Iso8601.PerS, n: U32, +c: Char, is_m: Bool
716) -> Iso8601.PerC:
717 match is_m:
718 case True{}:
719 Iso8601.per.cont_r(Iso8601.per.put_m(st, n), PSeek{})
720 case False{}:
721 Iso8601.per.unit_w(st, n, c, Char.is_eq(c, 'W'))
722def Iso8601.per.unit(
723 st: Iso8601.PerS, n: U32, +c: Char
724) -> Iso8601.PerC:
725 Iso8601.per.unit_m(st, n, c, Char.is_eq(c, 'M'))
726def Iso8601.per.unit_y(
727 st: Iso8601.PerS, n: U32, +c: Char, is_y: Bool
728) -> Iso8601.PerC:
729 match is_y:
730 case True{}:
731 Iso8601.per.cont_r(Iso8601.per.put_y(st, n), PSeek{})
732 case False{}:
733 Iso8601.per.unit(st, n, c)
734def Iso8601.per.num(
735 off: Nat, st: Iso8601.PerS, acc: U32, +h: Char, is_dig: Bool
736) -> Iso8601.PerC:
737 match is_dig:
738 case True{}:
739 Iso8601.per.ndig(off, st, acc, h)
740 case False{}:
741 Iso8601.per.unit_y(st, acc, h, Char.is_eq(h, 'Y'))
742def Iso8601.per.seek2(
743 off: Nat, st: Iso8601.PerS, +h: Char, is_dig: Bool
744) -> Iso8601.PerC:
745 match is_dig:
746 case True{}:
747 PerCont{st, PNum{P.Parse.nacc(0, h)}}
748 case False{}:
749 PerFail{Extra{off, h}}
750def Iso8601.per.seek(
751 off: Nat, st: Iso8601.PerS, h: Char, is_t: Bool, is_dig: Bool
752) -> Iso8601.PerC:
753 match is_t:
754 case True{}:
755 PerFail{Invalid{}}
756 case False{}:
757 Iso8601.per.seek2(off, st, h, is_dig)
758def Iso8601.per.act(
759 off: Nat, st: Iso8601.PerS, mode: Iso8601.PerM, +h: Char, is_t: Bool, is_dig: Bool
760) -> Iso8601.PerC:
761 match mode:
762 case PSeek{}:
763 Iso8601.per.seek(off, st, h, is_t, is_dig)
764 case PNum{acc}:
765 Iso8601.per.num(off, st, acc, h, is_dig)
766def Iso8601.per.go(
767 s: String, +off: Nat, c: Iso8601.PerC
768) -> Result<&2, &2, Iso8601.Error, Per.Period>:
769 match s c:
770 case _ PerFail{e}:
771 Fail{e}
772 case SNil{} PerCont{st, mode}:
773 Iso8601.per.eof(st, mode)
774 case SCon{+h, t} PerCont{st, mode}:
775 Iso8601.per.go(
776 t, 1n+off,
777 Iso8601.per.act(
778 off, st, mode, h, Char.is_eq(h, 'T'), Char.is_digit(h)
779 )
780 )
781def Iso8601.read_period.p(
782 r: Result<&2, &2, Iso8601.Error, P.Parse.Cur>
783) -> Result<&2, &2, Iso8601.Error, Per.Period>:
784 match r:
785 case Fail{e}:
786 Fail{e}
787 case Done{P.Cur{s, off}}:
788 Iso8601.per.go(s, off, PerCont{Iso8601.per0(), PSeek{}})
789def Iso8601.read_period(
790 text: String
791) -> Result<&2, &2, Iso8601.Error, Per.Period>:
792 Iso8601.read_period.p(Iso8601.expect(P.Parse.start(text), 'P'))