src/rules/style/transcong.bend
bolt@1.27.0.0 · 169 lines · 17 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/src.bend as Src
31import bolt@1.27.0.0/src/finding.bend as F
32import bolt@1.27.0.0/src/syntax/lex.bend as Lex
33import bolt@1.27.0.0/src/syntax/tree.bend as Tree
34
35
36def named(nn: Tree.Node, +tt: String) -> Bool:
37 match nn:
38 case Tree.Leaf{Lex.Tok{k, t, _l, _c}}:
39 Bool.and(Lex.is_name(k), String.eq(t, tt))
40 case _other:
41 False{}
42
43
44def paren(nn: Tree.Node) -> Bool:
45 match nn:
46 case Tree.Group{Lex.Tok{_k, o, _l, _c}, _kids, _cl}:
47 String.eq(o, "(")
48 case _other:
49 False{}
50
51
52def comma(nn: Tree.Node) -> Bool:
53 match nn:
54 case Tree.Leaf{Lex.Tok{k, _t, _l, _c}}:
55 Lex.is_comma(k)
56 case _other:
57 False{}
58
59
60def ends(nn: Tree.Node) -> Bool:
61 match nn:
62 case Tree.NCons{h, _t}:
63 comma(h)
64 case _other:
65 True{}
66
67
68def cong.call(nn: Tree.Node) -> Bool:
69 match nn:
70 case Tree.NCons{g, after}:
71 Bool.and(paren(g), ends(after))
72 case _other:
73 False{}
74
75
76def cong(nn: Tree.Node) -> Bool:
77 match nn:
78 case Tree.NCons{h, t}:
79 Bool.and(named(h, "Equal.cong"), cong.call(t))
80 case _other:
81 False{}
82
83
84def commas(nn: Tree.Node) -> Nat:
85 match nn:
86 case Tree.NCons{h, rest}:
87 Nat.add(Bool.pick(Nat, comma(h), 1n, 0n), commas(rest))
88 case _other:
89 0n
90
91
92def late(+nc: Nat) -> Bool:
93 Bool.or(Nat.is_eq(nc, 4n), Nat.is_eq(nc, 5n))
94
95
96
97
98def fed(nn: Tree.Node, +nc: Nat, +fresh: Bool, +seen: Bool) -> Bool:
99 match nn:
100 case Tree.NCons{+h, +rest}:
101 +here = Bool.and(fresh, Bool.and(late(nc), cong(Tree.NCons{h, rest})))
102 +cm = comma(h)
103 fed(rest, Nat.add(nc, Bool.pick(Nat, cm, 1n, 0n)), cm, Bool.or(seen, here))
104 case _other:
105 seen
106
107
108def shape(+kids: Tree.Node) -> Bool:
109 Bool.and(Nat.is_eq(commas(kids), 5n), fed(kids, 0n, True{}, False{}))
110
111
112def args(nn: Tree.Node) -> Bool:
113 match nn:
114 case Tree.NCons{Tree.Group{Lex.Tok{_k, o, _l, _c}, kids, _cl}, _after}:
115 Bool.and(String.eq(o, "("), shape(kids))
116 case _other:
117 False{}
118
119
120def cite(+ll: U32, +cc: U32, +path: String) -> F.Finding:
121 F.Finding{path, ll, cc, 11, "transcong",
122 "this Equal.trans is fed an Equal.cong: rewrite instead, `%e : {F(_) == c : T}` with the other proof below it, which names the motive once and drops the middle term."}
123
124
125def site(hh: Tree.Node, rest: Tree.Node, +path: String) -> List<&2, F.Finding>:
126 match hh:
127 case Tree.Leaf{Lex.Tok{k, t, +l, +c}}:
128 Bool.pick(List<&2, F.Finding>, Bool.and(Bool.and(Lex.is_name(k), String.eq(t, "Equal.trans")), args(rest)),
129 [cite(l, c, path)], [])
130 case _other:
131 []
132
133
134def binds(nn: Tree.Node) -> Bool:
135 match nn:
136 case Tree.Leaf{Lex.Tok{Lex.TEq{}, _t, _l, _c}}:
137 True{}
138 case Tree.Leaf{Lex.Tok{Lex.TBind{}, _t, _l, _c}}:
139 True{}
140 case _other:
141 False{}
142
143
144def is_let(sk: Tree.StmtKind) -> Bool:
145 match sk:
146 case Tree.SLet{}:
147 True{}
148 case _other:
149 False{}
150
151
152
153def walk(nn: Tree.Node, +top: Bool, +path: String) -> List<&2, F.Finding>:
154 match nn:
155 case Tree.NCons{+h, +rest}:
156 +here = site(h, rest, path)
157 List.concat(&2, F.Finding, [Bool.pick(List<&2, F.Finding>, top, here, []), walk(h, True{}, path),
158 walk(rest, Bool.and(top, Bool.not(binds(h))), path)])
159 case Tree.Group{_o, kids, _cl}:
160 walk(kids, True{}, path)
161 case Tree.Stmt{sk, kids, body}:
162 List.concat(&2, F.Finding, [walk(kids, Bool.not(is_let(sk)), path), walk(body, True{}, path)])
163 case _other:
164 Nil{}
165
166
167def check(ss: Src.Src) -> List<&2, F.Finding>:
168 Src.Src{path, _text, _toks, tree, _bound, _items} = ss
169 walk(tree, True{}, path)