src/rules/laws/law.bend
bolt@1.27.0.0 · 169 lines · 15 definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29import Base
30import bolt@1.27.0.0/src/lazy/lazy.bend as Lazy
31import bolt@1.27.0.0/src/finding.bend as F
32import bolt@1.27.0.0/src/syntax/outline.bend as Outline
33import bolt@1.27.0.0/src/rules/digest.bend as Digest
34import bolt@1.27.0.0/src/rules/imports.bend as Imports
35
36
37
38
39
40def named.put(laws: Bool, ms: List<&2, Digest.Mention>, more: List<&2, Digest.Mention>) -> List<&2, Digest.Mention>:
41 match laws:
42 case True{}:
43 List.append(&2, Digest.Mention, ms, more)
44 case False{}:
45 more
46
47
48
49def named(ds: List<&2, Digest.Digest>) -> List<&2, Digest.Mention>:
50 match ds:
51 case Nil{}:
52 Nil{}
53 case Con{Digest.Digest{path, norm, dir, is_laws, is_law_file, exempt, tops, says, deps, laws}, rest}:
54 named.put(is_laws, says, named(rest))
55
56
57
58
59
60
61def key(+pp: String, name: String) -> String:
62 name ++ " " ++ pp
63
64
65def keys(ms: List<&2, Digest.Mention>) -> List<&2, String>:
66 match ms:
67 case Nil{}:
68 Nil{}
69 case Con{Digest.Mention{p, n}, rest}:
70 key(p, n) <> keys(rest)
71
72
73def ctor_nodes(cs: List<&2, String>, +pp: String, more: List<&2, Imports.Edge>) -> List<&2, Imports.Edge>:
74 match cs:
75 case Nil{}:
76 more
77 case Con{c, rest}:
78 Imports.Edge{key(pp, c), []} <> ctor_nodes(rest, pp, more)
79
80
81
82def nodes(ts: List<&2, Digest.Top>, +pp: String, more: List<&2, Imports.Edge>) -> List<&2, Imports.Edge>:
83 match ts:
84 case Nil{}:
85 more
86 case Con{Digest.Top{Outline.IDef{}, name, line, cs, calls}, rest}:
87 Imports.Edge{key(pp, name), keys(calls)} <> nodes(rest, pp, more)
88 case Con{Digest.Top{Outline.IType{}, name, line, cs, calls}, rest}:
89 Imports.Edge{key(pp, name), []} <> ctor_nodes(cs, pp, nodes(rest, pp, more))
90 case Con{other, rest}:
91 nodes(rest, pp, more)
92
93
94def graph.items(ds: List<&2, Digest.Digest>) -> List<&2, Imports.Edge>:
95 match ds:
96 case Nil{}:
97 Nil{}
98 case Con{Digest.Digest{path, norm, dir, is_laws, is_law_file, exempt, tops, says, deps, laws}, rest}:
99 nodes(tops, norm, graph.items(rest))
100
101
102
103def graph(+ds: List<&2, Digest.Digest>) -> List<&2, Imports.Edge>:
104 Imports.Edge{"", keys(named(ds))} <> graph.items(ds)
105
106
107def any_item(ns: List<&2, String>, +cl: List<&2, String>, +pp: String) -> Bool:
108 match ns:
109 case Nil{}:
110 False{}
111 case Con{name, rest}:
112 Lazy.or_else(Imports.has(cl, key(pp, name)), _u => any_item(rest, cl, pp))
113
114
115
116
117
118def law_dirs(ds: List<&2, Digest.Digest>) -> List<&2, String>:
119 match ds:
120 case Nil{}:
121 Nil{}
122 case Con{Digest.Digest{path, norm, dir, is_laws, is_law_file, exempt, tops, says, deps, laws}, rest}:
123 +more = law_dirs(rest)
124 Bool.pick(List<&2, String>, is_laws, dir <> more, more)
125
126
127def gaps(ts: List<&2, Digest.Top>, +cl: List<&2, String>, +pp: String, +path: String) -> List<&2, F.Finding>:
128 match ts:
129 case Nil{}:
130 Nil{}
131 case Con{Digest.Top{Outline.IDef{}, +name, +line, cs, calls}, rest}:
132 +more = gaps(rest, cl, pp, path)
133 Bool.pick(List<&2, F.Finding>,
134 Lazy.or_else(String.contains(name, "."), _u => Imports.has(cl, key(pp, name))), more,
135 F.Finding{path, line, 0, 0, "coverage", "No quantified law reaches def " ++ name ++ "."} <> more)
136 case Con{Digest.Top{Outline.IType{}, +name, +line, cs, calls}, rest}:
137 +more = gaps(rest, cl, pp, path)
138 Bool.pick(List<&2, F.Finding>, Lazy.or_else(Imports.has(cl, key(pp, name)), _u => any_item(cs, cl, pp)), more,
139 F.Finding{path, line, 0, 0, "coverage", "No quantified law reaches type " ++ name ++ " or any of its constructors."}
140 <> more)
141 case Con{other, rest}:
142 gaps(rest, cl, pp, path)
143
144
145def check.go(ds: List<&2, Digest.Digest>, +cl: List<&2, String>) -> List<&2, F.Finding>:
146 match ds:
147 case Nil{}:
148 Nil{}
149 case Con{Digest.Digest{path, +norm, dir, is_laws, is_law_file, exempt, tops, says, deps, laws}, rest}:
150 +more = check.go(rest, cl)
151 Lazy.stop(List<&2, F.Finding>, exempt, more,
152 _u => List.append(&2, F.Finding, gaps(tops, cl, norm, path), more))
153
154
155def reached(+es: List<&2, Imports.Edge>) -> List<&2, String>:
156 Imports.closure.go(es, Imports.paths(es), List.length(&2, Imports.Edge, es), "")
157
158
159
160def check.first(+ds: List<&2, Digest.Digest>, dirs: List<&2, String>) -> List<&2, F.Finding>:
161 match dirs:
162 case Nil{}:
163 Nil{}
164 case Con{d, rest}:
165 check.go(ds, reached(graph(ds)))
166
167
168def check(+ds: List<&2, Digest.Digest>) -> List<&2, F.Finding>:
169 check.first(ds, law_dirs(ds))