src/syntax/word.bend
bolt@1.27.0.0 · 157 lines · 23 definitions
1
2
3
4
5import Base
6import bolt@1.27.0.0/src/lazy/lazy.bend as Lazy
7import bolt@1.27.0.0/src/rchars.bend as Rchars
8
9
10
11type W is Data:
12 W{i: U32, start: U32, run: List<&2, Char>, hit: Maybe<&2, String>}
13
14
15def is_name(+cc: Char) -> Bool:
16 Bool.or(Bool.or(Char.is_alpha(cc), Char.is_digit(cc)), Bool.or(Char.is_eq(cc, '_'), Char.is_eq(cc, '.')))
17
18
19def text(run: List<&2, Char>) -> String:
20 Rchars.text(run)
21
22
23def close.yes(ok: Bool, run: List<&2, Char>, hit: Maybe<&2, String>) -> Maybe<&2, String>:
24 match ok:
25 case True{}:
26 Some{text(run)}
27 case False{}:
28 hit
29
30
31def close.run(run: List<&2, Char>, +start: U32, +ii: U32, +col: U32, hit: Maybe<&2, String>) -> Maybe<&2, String>:
32 match run:
33 case Nil{}:
34 hit
35 case h <> t:
36 close.yes(Bool.and(U32.is_le(start, col), U32.is_le(col, ii)), h <> t, hit)
37
38
39def close(+ii: U32, +start: U32, run: List<&2, Char>, hit: Maybe<&2, String>, +col: U32) -> Maybe<&2, String>:
40 match hit:
41 case Some{s}:
42 Some{s}
43 case None{}:
44 close.run(run, start, ii, col, None{})
45
46
47def step.on(name: Bool, cc: Char, +ii: U32, +start: U32, run: List<&2, Char>, hit: Maybe<&2, String>, +col: U32) -> W:
48 match name:
49 case True{}:
50 W{(ii + 1 : U32), start, cc <> run, hit}
51 case False{}:
52 W{(ii + 1 : U32), (ii + 1 : U32), [], close(ii, start, run, hit, col)}
53
54
55
56def step(+cc: Char, st: W, +col: U32) -> W:
57 W{i, start, run, hit} = st
58 step.on(is_name(cc), cc, i, start, run, hit, col)
59
60
61def finish(st: W, col: U32) -> String:
62 W{i, start, run, hit} = st
63 Maybe.default(&2, String, close(i, start, run, hit, col), "")
64
65
66def at.skip.n(nl: Bool, nn: U32) -> U32:
67 match nl:
68 case True{}:
69 (nn - 1 : U32)
70 case False{}:
71 nn
72
73
74def at.skip.done(nl: Bool, nn: U32) -> Bool:
75 match nl:
76 case True{}:
77 U32.is_eq(nn, 1)
78 case False{}:
79 False{}
80
81
82def at.skip(ss: String, +nn: U32, done: Bool) -> String:
83 match ss done:
84 case SNil{} _:
85 SNil{}
86 case SCon{h, t} True{}:
87 SCon{h, t}
88 case SCon{+h, t} False{}:
89 at.skip(t, at.skip.n(Char.is_eq(h, '\n'), nn), at.skip.done(Char.is_eq(h, '\n'), nn))
90
91
92def at.advance(nl: Bool, hh: Char, st: W, +col: U32) -> W:
93 match nl:
94 case True{}:
95 st
96 case False{}:
97 step(hh, st, col)
98
99
100def at.read(ss: String, stop: Bool, st: W, +col: U32) -> String:
101 match ss stop:
102 case SNil{} _:
103 finish(st, col)
104 case SCon{h, t} True{}:
105 finish(st, col)
106 case SCon{+h, t} False{}:
107 at.read(t, Char.is_eq(h, '\n'), at.advance(Char.is_eq(h, '\n'), h, st, col), col)
108
109
110def at(source: String, +line: U32, col: U32) -> String:
111 at.read(at.skip(source, line, U32.is_eq(line, 0)), False{}, W{0, 0, [], None{}}, col)
112
113
114def cut.go(cs: List<&2, Char>, acc: List<&2, Char>) -> String & String:
115 match cs:
116 case Nil{}:
117 (text(acc), "")
118 case Con{'.', t}:
119 (text(acc), String.from_list(t))
120 case Con{c, t}:
121 cut.go(t, c <> acc)
122
123
124def cut(name: String) -> String & String:
125 cut.go(String.to_list(name), [])
126
127
128def fst(pp: String & String) -> String:
129 (h, r) = pp
130 h
131
132
133def snd(pp: String & String) -> String:
134 (h, r) = pp
135 r
136
137
138def head(name: String) -> String:
139 fst(cut(name))
140
141
142def rest(name: String) -> String:
143 snd(cut(name))
144
145
146def run_of(cs: List<&2, Char>) -> List<&2, Char>:
147 match cs:
148 case Nil{}:
149 Nil{}
150 case Con{+c, t}:
151 Lazy.stop(List<&2, Char>, Bool.not(is_name(c)), Nil{}, _u => c <> run_of(t))
152
153
154def before(source: String, line: U32, col: U32) -> String:
155 text(run_of(List.reverse(&2, Char, String.to_list(String.take(
156 Maybe.default(&2, String, List.get(&2, String, String.lines(source), U32.to_nat(line)), ""),
157 U32.to_nat(col))))))