src/ez/prove.bend
ezx@1.11.0.0 · 166 lines · 19 definitions
1
2
3
4
5
6
7
8
9
10
11
12import Base
13import snap@1.4.0.0/main.bend as R
14import ezx@1.11.0.0/src/share/args.bend as Args
15import ezx@1.11.0.0/src/share/env.bend as Env
16import ezx@1.11.0.0/src/share/cap.bend as Cap
17import ezx@1.11.0.0/src/ez/quiet.bend as Q
18import ezx@1.11.0.0/src/ez/sorted.bend as Sort
19import ezx@1.11.0.0/src/ez/ends.bend as E
20import ezx@1.11.0.0/src/lock/run.bend as Run
21
22
23
24
25
26def find.at(+what: String, +how: String) -> IO(List<&2, String>):
27 do IO<List<&2, String>>:
28 out : String <- R.exec(["find", ".", how, what,
29 "-not", "-path", "./.ez/*",
30 "-not", "-path", "./.git/*", "-not", "-path", "./.claude/*"])
31 return Sort.sort(Args.nonempty(String.lines(R.text(out))))
32
33
34def find.proofs() -> IO(List<&2, String>):
35 find.at("PROOF.bend", "-name")
36
37
38
39
40
41def width() -> IO(String):
42 Env.var("EZ_JOBS", "")
43
44
45
46def fresh.dir(+at: String) -> IO(Unit):
47 do IO<Unit>:
48 _rm : String <- R.exec(["rm", "-rf", at])
49 _mk : String <- R.exec(["mkdir", "-p", at])
50 return Unit{}
51
52
53def out.at() -> String:
54 ".ez/run/prove"
55
56
57def head.of(ls: List<&2, String>) -> String:
58 match ls:
59 case []:
60 ""
61 case h <> _t:
62 h
63
64
65def head(text: String) -> String:
66 head.of(String.lines(text))
67
68
69def verdict() -> String:
70 "ALL PROOFS CHECK"
71
72
73def indent.go(ls: List<&2, String>) -> List<&2, String>:
74 match ls:
75 case []:
76 []
77 case h <> t:
78 (" " ++ h ++ "\n") <> indent.go(t)
79
80
81def indent(text: String) -> String:
82 String.concat(indent.go(String.lines(text)))
83
84
85
86def cmd(cap: Bool, +gigs: String, +at: String, +path: String) -> List<&2, String>:
87 Cap.argv(cap, gigs, at, ["bend", path])
88
89
90def cmds(ps: List<&2, String>, +cap: Bool, +gigs: String, +at: String) -> List<&2, List<&2, String>>:
91 match ps:
92 case Nil{}:
93 Nil{}
94 case Con{+h, t}:
95 cmd(cap, gigs, at, h) <> cmds(t, cap, gigs, at)
96
97
98
99
100def say(ok: Bool, +path: String, +text: String) -> IO(Unit):
101 match ok:
102 case True{}:
103 IO.print("ok: " ++ path)
104 case False{}:
105 IO.write("FAIL: " ++ path ++ "\n" ++ indent(text))
106
107
108def count(ok: Bool, +passed: Nat) -> Nat:
109 Bool.pick(Nat, ok, (1n + passed : Nat), passed)
110
111
112
113def one(+path: String, +gigs: String, +output: String, +passed: Nat) -> IO(Nat):
114 do IO<Nat>:
115 +text : String <- IO.pure(String, R.text(output))
116 +ok : Bool <- IO.pure(Bool, String.eq(head(text), verdict()))
117 say(ok, path, Cap.why(output, gigs) ++ Q.chomp(text))
118 return count(ok, passed)
119
120
121
122
123def short(ps: List<&2, String>) -> IO(Unit):
124 match ps:
125 case Nil{}:
126 IO.pure(Unit, Unit{})
127 case Con{+h, t}:
128 do IO<Unit>:
129 IO.print("FAIL: " ++ h ++ ": the run never answered for it")
130 short(t)
131
132
133def report(ps: List<&2, String>, as: List<&2, String>, +gigs: String, +passed: Nat) -> IO(Nat):
134 match ps as:
135 case Con{+h, pt} Con{+x, xt}:
136 do IO<Nat>:
137 next : Nat <- one(h, gigs, x, passed)
138 report(pt, xt, gigs, next)
139 case rest _x:
140 do IO<Nat>:
141 short(rest)
142 return passed
143
144
145
146
147def done(+passed: Nat, +total: Nat) -> IO(Unit):
148 do IO<Unit>:
149 IO.print("PASS: " ++ Nat.show(passed) ++ " / " ++ Nat.show(total))
150 Run.end(E.counted(passed, total))
151
152
153
154
155def run() -> IO(Unit):
156 do IO<Unit>:
157 +cap : Bool <- Cap.ok()
158 Cap.warn(cap)
159 +g : String <- Cap.gb()
160 +at : String <- Env.lib()
161 +jobs : String <- width()
162 +ps : List<&2, String> <- find.proofs()
163 fresh.dir(out.at())
164 as : List<&2, String> <- R.par(cmds(ps, cap, g, at), jobs, g, out.at(), "0")
165 +passed : Nat <- report(ps, as, g, 0n)
166 done(passed, List.length(&2, String, ps))