src/dline.bend
bend-toon-codec@0.1.0.0 · 98 lines · 16 definitions
1import Base
2import bend-toon-codec@0.1.0.0/src/head.bend as Hd
3
4
5
6type DL is Data:
7 DL{no: U32, depth: U32, text: String, blank: Bool}
8
9
10type Ld is Data:
11 Ld{sp: U32, tabs: U32, rest: String}
12
13def lead.pick(+go: Bool, +s: String, +sp: U32, +tabs: U32, +r: Ld) -> Ld:
14 match go:
15 case True{}:
16 r
17 case False{}:
18 Ld{sp, tabs, s}
19
20def inc(+b: Bool) -> U32:
21 match b:
22 case True{}:
23 1
24 case False{}:
25 0
26
27
28
29
30def lead(+s: String, +sp: U32, +tabs: U32, +live: Bool) -> Ld:
31 match s:
32 case SNil{}:
33 Ld{sp, tabs, s}
34 case SCon{Chr{c}, t}:
35 lead.pick(live && (U32.is_eq(c, 32) || U32.is_eq(c, 9)), s, sp, tabs,
36 lead(t, (sp + inc(live && U32.is_eq(c, 32)) : U32), (tabs + inc(live && U32.is_eq(c, 9)) : U32), live && (U32.is_eq(c, 32) || U32.is_eq(c, 9))))
37
38def at(+no: U32, +m: String) -> String:
39 "line " ++ U32.show(no) ++ ": " ++ m
40
41def blank(+no: U32) -> Result<&2, &2, String, DL>:
42 Done{DL{no, 0, SNil{}, True{}}}
43
44
45
46
47def depth.pick(+bad_tab: Bool, +bad_mult: Bool, +no: U32, +depth: U32, +text: String) -> Result<&2, &2, String, DL>:
48 match bad_tab bad_mult:
49 case True{} _:
50 Fail{at(no, "tabs are not allowed in indentation")}
51 case False{} True{}:
52 Fail{at(no, "indentation is not a multiple of the indent size")}
53 case False{} False{}:
54 Done{DL{no, depth, text, False{}}}
55
56def make.nonblank(+no: U32, +l: Ld, +size: U32, +strict: Bool) -> Result<&2, &2, String, DL>:
57 match l:
58 case Ld{sp, tabs, rest}:
59 depth.pick(strict && Bool.not(U32.is_zero(tabs)), strict && Bool.not(U32.is_zero(U32.mod(sp, size)) ), no,
60 (U32.div(sp, size) + tabs : U32), String.trim_end(rest))
61
62def make.pick(+isblank: Bool, +no: U32, +l: Ld, +size: U32, +strict: Bool) -> Result<&2, &2, String, DL>:
63 match isblank:
64 case True{}:
65 blank(no)
66 case False{}:
67 make.nonblank(no, l, size, strict)
68
69def make.of(+no: U32, +l: Ld, +size: U32, +strict: Bool) -> Result<&2, &2, String, DL>:
70 match l:
71 case Ld{sp, tabs, rest}:
72 make.pick(String.is_empty(String.trim(rest)), no, Ld{sp, tabs, rest}, size, strict)
73
74def make(+no: U32, +line: String, +size: U32, +strict: Bool) -> Result<&2, &2, String, DL>:
75 make.of(no, lead(line, 0, 0, True{}), size, strict)
76
77def prep.cons(+r: Result<&2, &2, String, DL>, +rest: Result<&2, &2, String, List<&2, DL>>) -> Result<&2, &2, String, List<&2, DL>>:
78 match r rest:
79 case Done{l} Done{ls}:
80 Done{Con{l, ls}}
81 case Fail{e} _:
82 Fail{e}
83 case _ Fail{e}:
84 Fail{e}
85
86def prep.go(+lines: List<&2, String>, +no: U32, +size: U32, +strict: Bool) -> Result<&2, &2, String, List<&2, DL>>:
87 match lines:
88 case Nil{}:
89 Done{Nil{}}
90 case Con{l, rest}:
91 prep.cons(make(no, l, size, strict), prep.go(rest, (no + 1 : U32), size, strict))
92
93def size.of(+n: U32) -> U32:
94 U32.max(n, 1)
95
96
97def prep(+src: String, +size: U32, +strict: Bool) -> Result<&2, &2, String, List<&2, DL>>:
98 prep.go(String.lines(src), 1, size.of(size), strict)