35 SOME Boogie_VCs.Proved => error ("The verification condition " ^ |
40 SOME Boogie_VCs.Proved => error ("The verification condition " ^ |
36 quote vc_name ^ " has already been proved.") |
41 quote vc_name ^ " has already been proved.") |
37 | _ => error ("There is no verification condition " ^ |
42 | _ => error ("There is no verification condition " ^ |
38 quote vc_name ^ "."))) |
43 quote vc_name ^ "."))) |
39 |
44 |
40 fun boogie_vc (vc_opts, vc_name) lthy = |
45 fun boogie_vc (vc_name, vc_opts) lthy = |
41 let |
46 let |
42 val thy = ProofContext.theory_of lthy |
47 val thy = ProofContext.theory_of lthy |
43 val vc = get_vc thy vc_name |
48 val vc = get_vc thy vc_name |
44 |
49 |
45 val (sks, ts) = split_list |
50 val vcs = |
46 (case vc_opts of |
51 (case vc_opts of |
47 VC_full paths => [vc] |> paths ? maps Boogie_VCs.paths_of |
52 VC_Complete => [vc] |
48 | VC_only assertions => map_filter (Boogie_VCs.extract vc) assertions) |
53 | VC_Take (ps, NONE) => [Boogie_VCs.paths_and ps [] vc] |
|
54 | VC_Take (ps, SOME (true, ls)) => [Boogie_VCs.paths_and ps ls vc] |
|
55 | VC_Take (ps, SOME (false, ls)) => [Boogie_VCs.paths_without ps ls vc] |
|
56 | VC_Only ls => [Boogie_VCs.only ls vc] |
|
57 | VC_Without ls => [Boogie_VCs.without ls vc] |
|
58 | VC_Examine ls => map_filter (Boogie_VCs.extract vc) ls) |
|
59 val ts = map Boogie_VCs.prop_of_vc vcs |
49 |
60 |
50 val discharge = fold (Boogie_VCs.discharge o pair vc_name) |
61 val discharge = fold (Boogie_VCs.discharge o pair vc_name) |
51 fun after_qed [thms] = Local_Theory.theory (discharge (sks ~~ thms)) |
62 fun after_qed [thms] = Local_Theory.theory (discharge (vcs ~~ thms)) |
52 | after_qed _ = I |
63 | after_qed _ = I |
53 in |
64 in |
54 lthy |
65 lthy |
55 |> fold Variable.auto_fixes ts |
66 |> fold Variable.auto_fixes ts |
56 |> Proof.theorem_i NONE after_qed [map (rpair []) ts] |
67 |> Proof.theorem_i NONE after_qed [map (rpair []) ts] |
57 end |
68 end |
58 |
69 |
59 |
70 |
60 fun write_list head xs = |
71 fun write_list head = |
61 Pretty.writeln (Pretty.big_list head (map Pretty.str xs)) |
72 map Pretty.str o sort (dict_ord string_ord o pairself explode) #> |
62 |
73 Pretty.writeln o Pretty.big_list head |
63 val prefix_string_ord = dict_ord string_ord o pairself explode |
74 |
|
75 fun parens s = "(" ^ s ^ ")" |
64 |
76 |
65 fun boogie_status thy = |
77 fun boogie_status thy = |
66 let |
78 let |
67 fun string_of_state Boogie_VCs.Proved = "proved" |
79 fun string_of_state Boogie_VCs.Proved = "proved" |
68 | string_of_state Boogie_VCs.NotProved = "not proved" |
80 | string_of_state Boogie_VCs.NotProved = "not proved" |
69 | string_of_state Boogie_VCs.PartiallyProved = "partially proved" |
81 | string_of_state Boogie_VCs.PartiallyProved = "partially proved" |
70 in |
82 in |
71 Boogie_VCs.state_of thy |
83 Boogie_VCs.state_of thy |
72 |> map (fn (name, proved) => name ^ " (" ^ string_of_state proved ^ ")") |
84 |> map (fn (name, proved) => name ^ " " ^ parens (string_of_state proved)) |
73 |> sort prefix_string_ord |
|
74 |> write_list "Boogie verification conditions:" |
85 |> write_list "Boogie verification conditions:" |
75 end |
86 end |
76 |
87 |
77 fun boogie_status_vc (full, vc_name) thy = |
88 fun boogie_status_vc full vc_name thy = |
78 let |
89 let |
79 fun pretty tag s = s ^ " (" ^ tag ^ ")" |
90 fun pretty tag s = s ^ " " ^ parens tag |
80 |
91 |
81 val (ps, us) = Boogie_VCs.state_of_vc thy vc_name |
92 val (not_proved, proved) = Boogie_VCs.state_of_vc thy vc_name |
82 in |
93 in |
83 if full |
94 if full |
84 then write_list ("Assertions of Boogie verification condition " ^ |
95 then write_list ("Assertions of Boogie verification condition " ^ |
85 quote vc_name ^ ":") (sort prefix_string_ord |
96 quote vc_name ^ ":") |
86 (map (pretty "proved") ps @ map (pretty "not proved") us)) |
97 (map (pretty "proved") proved @ map (pretty "not proved") not_proved) |
87 else write_list ("Unproved assertions of Boogie verification condition " ^ |
98 else write_list ("Unproved assertions of Boogie verification condition " ^ |
88 quote vc_name ^ ":") (sort prefix_string_ord us) |
99 quote vc_name ^ ":") not_proved |
|
100 end |
|
101 |
|
102 fun boogie_status_vc_paths full vc_name thy = |
|
103 let |
|
104 fun labels ls = Pretty.blk (0, Pretty.breaks (map Pretty.str ls)) |
|
105 |
|
106 fun pp (i, ns) = |
|
107 if full |
|
108 then |
|
109 [Pretty.big_list ("Path " ^ string_of_int (i+1) ^ ":") |
|
110 [labels (map (fn (n, true) => n | (n, _) => parens n) ns)]] |
|
111 else |
|
112 let val ns' = map_filter (fn (n, true) => SOME n | _ => NONE) ns |
|
113 in |
|
114 if null ns' then [] |
|
115 else |
|
116 [Pretty.big_list ("Unproved assertions of path " ^ |
|
117 string_of_int (i+1) ^ ":") [labels ns']] |
|
118 end |
|
119 in |
|
120 Pretty.writeln |
|
121 (Pretty.big_list |
|
122 ("Paths of Boogie verification condition " ^ quote vc_name ^ ":") |
|
123 (flat (map_index pp (Boogie_VCs.path_names_of (get_vc thy vc_name))))) |
89 end |
124 end |
90 |
125 |
91 |
126 |
92 local |
127 local |
93 fun trying s = tracing ("Trying " ^ s ^ " ...") |
128 fun trying s = tracing ("Trying " ^ s ^ " ...") |
94 fun success_on s = tracing ("Succeeded on " ^ s ^ ".") |
129 fun success_on s = tracing ("Succeeded on " ^ s ^ ".") |
95 fun failure_on s c = tracing ("Failed on " ^ s ^ c) |
130 fun failure_on s c = tracing ("Failed on " ^ s ^ c) |
96 |
131 |
97 fun string_of_asserts goal = space_implode ", " (Boogie_VCs.names_of goal) |
132 fun string_of_asserts vc = space_implode ", " (fst (Boogie_VCs.names_of vc)) |
98 |
133 |
99 fun string_of_path (i, n) = |
134 fun string_of_path (i, n) = |
100 "path " ^ string_of_int i ^ " of " ^ string_of_int n |
135 "path " ^ string_of_int i ^ " of " ^ string_of_int n |
101 |
136 |
102 fun itemize_paths ps = |
137 fun itemize_paths ps = |
103 let val n = length ps |
138 let val n = length ps |
104 in fst (fold_map (fn p => fn i => (((i, n), p), i+1)) ps 1) end |
139 in fst (fold_map (fn p => fn i => (((i, n), p), i+1)) ps 1) end |
105 |
140 |
106 fun par_map f = flat o Par_List.map f |
141 fun par_map f = flat o Par_List.map f |
107 |
142 |
108 fun divide f goal = |
143 fun divide f vc = |
109 let val n = Boogie_VCs.size_of goal |
144 let val n = Boogie_VCs.size_of vc |
110 in |
145 in |
111 if n = 1 then Boogie_VCs.names_of goal |
146 if n <= 1 then fst (Boogie_VCs.names_of vc) |
112 else |
147 else |
113 let val (goal1, goal2) = Boogie_VCs.split_path (n div 2) goal |
148 let val (vc1, vc2) = the (Boogie_VCs.split_path (n div 2) vc) |
114 in par_map f [goal1, goal2] end |
149 in par_map f [vc1, vc2] end |
115 end |
150 end |
116 |
151 |
117 fun prove thy meth (_, goal) = |
152 fun prove thy meth vc = |
118 ProofContext.init thy |
153 ProofContext.init thy |
119 |> Proof.theorem_i NONE (K I) [[(goal, [])]] |
154 |> Proof.theorem_i NONE (K I) [[(Boogie_VCs.prop_of_vc vc, [])]] |
120 |> Proof.apply meth |
155 |> Proof.apply meth |
121 |> Seq.hd |
156 |> Seq.hd |
122 |> Proof.global_done_proof |
157 |> Proof.global_done_proof |
123 in |
158 in |
124 fun boogie_narrow_vc ((timeout, vc_name), meth) thy = |
159 fun boogie_narrow_vc timeout vc_name meth thy = |
125 let |
160 let |
126 val tp = TimeLimit.timeLimit (Time.fromSeconds timeout) (prove thy meth) |
161 val tp = TimeLimit.timeLimit (Time.fromSeconds timeout) (prove thy meth) |
127 |
162 |
128 fun try_goal (tag, split_tag) split goal = (trying tag; |
163 fun try_vc (tag, split_tag) split vc = (trying tag; |
129 (case try tp goal of |
164 (case try tp vc of |
130 SOME _ => (success_on tag; []) |
165 SOME _ => (success_on tag; []) |
131 | NONE => (failure_on tag split_tag; split goal))) |
166 | NONE => (failure_on tag split_tag; split vc))) |
132 |
167 |
133 fun group_goal goal = |
168 fun some_asserts vc = |
134 try_goal (string_of_asserts goal, |
169 try_vc (string_of_asserts vc, |
135 if Boogie_VCs.size_of goal = 1 then "." else ", further splitting ...") |
170 if Boogie_VCs.size_of vc = 1 then "." else ", further splitting ...") |
136 (divide group_goal) goal |
171 (divide some_asserts) vc |
137 |
172 |
138 fun path_goal p = |
173 fun single_path p = |
139 try_goal (string_of_path p, ", splitting into assertions ...") |
174 try_vc (string_of_path p, ", splitting into assertions ...") |
140 (divide group_goal) |
175 (divide some_asserts) |
141 |
176 |
142 val full_goal = |
177 val complete_vc = |
143 try_goal ("full goal", ", splitting into paths ...") |
178 try_vc ("full goal", ", splitting into paths ...") |
144 (par_map (uncurry path_goal) o itemize_paths o Boogie_VCs.paths_of) |
179 (par_map (uncurry single_path) o itemize_paths o Boogie_VCs.paths_of) |
145 |
180 |
146 val unsolved = full_goal (get_vc thy vc_name) |
181 val unsolved = complete_vc (get_vc thy vc_name) |
147 in |
182 in |
148 if null unsolved |
183 if null unsolved |
149 then writeln ("Completely solved Boogie verification condition " ^ |
184 then writeln ("Completely solved Boogie verification condition " ^ |
150 quote vc_name ^ ".") |
185 quote vc_name ^ ".") |
151 else write_list ("Unsolved assertions of Boogie verification condition " ^ |
186 else write_list ("Unsolved assertions of Boogie verification condition " ^ |
152 quote vc_name ^ ":") (sort prefix_string_ord unsolved) |
187 quote vc_name ^ ":") unsolved |
|
188 end |
|
189 |
|
190 fun boogie_scan_vc timeout vc_name meth thy = |
|
191 let |
|
192 val tp = TimeLimit.timeLimit (Time.fromSeconds timeout) (prove thy meth) |
|
193 |
|
194 val vc = get_vc thy vc_name |
|
195 fun prove_assert name = |
|
196 (trying name; tp (the (Boogie_VCs.extract vc name))) |
|
197 val find_first_failure = find_first (is_none o try prove_assert) |
|
198 in |
|
199 (case find_first_failure (fst (Boogie_VCs.names_of vc)) of |
|
200 SOME name => writeln ("failed on " ^ quote name) |
|
201 | NONE => writeln "succeeded") |
153 end |
202 end |
154 end |
203 end |
155 |
204 |
156 |
205 |
157 |
206 |
172 |
221 |
173 (* syntax and setup *) |
222 (* syntax and setup *) |
174 |
223 |
175 fun scan_val n f = Args.$$$ n -- Args.colon |-- f |
224 fun scan_val n f = Args.$$$ n -- Args.colon |-- f |
176 fun scan_arg f = Args.parens f |
225 fun scan_arg f = Args.parens f |
177 fun scan_opt n = Scan.optional (scan_arg (Args.$$$ n) >> K true) false |
226 fun scan_opt n = Scan.optional (scan_arg (Args.$$$ n >> K true)) false |
178 |
|
179 |
227 |
180 val _ = |
228 val _ = |
181 OuterSyntax.command "boogie_open" |
229 OuterSyntax.command "boogie_open" |
182 "Open a new Boogie environment and load a Boogie-generated .b2i file." |
230 "Open a new Boogie environment and load a Boogie-generated .b2i file." |
183 OuterKeyword.thy_decl |
231 OuterKeyword.thy_decl |
184 (scan_opt "quiet" -- OuterParse.name >> (Toplevel.theory o boogie_load)) |
232 (scan_opt "quiet" -- OuterParse.name >> (Toplevel.theory o boogie_open)) |
185 |
233 |
186 |
234 |
187 val vc_name = OuterParse.name |
235 val vc_name = OuterParse.name |
|
236 |
|
237 val vc_labels = Scan.repeat1 OuterParse.name |
|
238 |
|
239 val vc_paths = |
|
240 OuterParse.nat -- (Args.$$$ "-" |-- OuterParse.nat) >> (op upto) || |
|
241 OuterParse.nat >> single |
|
242 |
188 val vc_opts = |
243 val vc_opts = |
189 scan_arg (scan_val "only" (Scan.repeat1 OuterParse.name)) >> VC_only || |
244 scan_arg |
190 scan_opt "paths" >> VC_full |
245 (scan_val "examine" vc_labels >> VC_Examine || |
191 |
246 scan_val "take" ((OuterParse.list vc_paths >> flat) -- Scan.option ( |
192 fun vc_cmd f = Toplevel.print o Toplevel.local_theory_to_proof NONE f |
247 scan_val "without" vc_labels >> pair false || |
|
248 scan_val "and_also" vc_labels >> pair true) >> VC_Take) || |
|
249 scan_val "only" vc_labels >> VC_Only || |
|
250 scan_val "without" vc_labels >> VC_Without) || |
|
251 Scan.succeed VC_Complete |
193 |
252 |
194 val _ = |
253 val _ = |
195 OuterSyntax.command "boogie_vc" |
254 OuterSyntax.command "boogie_vc" |
196 "Enter into proof mode for a specific verification condition." |
255 "Enter into proof mode for a specific verification condition." |
197 OuterKeyword.thy_goal |
256 OuterKeyword.thy_goal |
198 (vc_opts -- vc_name >> (vc_cmd o boogie_vc)) |
257 (vc_name -- vc_opts >> (fn args => |
|
258 (Toplevel.print o Toplevel.local_theory_to_proof NONE (boogie_vc args)))) |
199 |
259 |
200 |
260 |
201 val default_timeout = 5 |
261 val default_timeout = 5 |
202 |
262 |
203 val status_narrow_vc = |
263 val status_test = |
204 scan_arg (Args.$$$ "narrow" |-- |
264 scan_arg ( |
|
265 (Args.$$$ "scan" >> K boogie_scan_vc || |
|
266 Args.$$$ "narrow" >> K boogie_narrow_vc) -- |
205 Scan.optional (scan_val "timeout" OuterParse.nat) default_timeout) -- |
267 Scan.optional (scan_val "timeout" OuterParse.nat) default_timeout) -- |
206 vc_name -- |
268 vc_name -- Method.parse >> |
207 scan_arg (scan_val "try" Method.parse) |
269 (fn (((f, timeout), vc_name), meth) => f timeout vc_name meth) |
208 |
270 |
209 val status_vc_opts = scan_opt "full" |
271 val status_vc = |
|
272 (scan_arg |
|
273 (Args.$$$ "full" |-- |
|
274 (Args.$$$ "paths" >> K (boogie_status_vc_paths true) || |
|
275 Scan.succeed (boogie_status_vc true)) || |
|
276 Args.$$$ "paths" >> K (boogie_status_vc_paths false)) || |
|
277 Scan.succeed (boogie_status_vc false)) -- |
|
278 vc_name >> (fn (f, vc_name) => f vc_name) |
210 |
279 |
211 fun status_cmd f = Toplevel.no_timing o Toplevel.keep (fn state => |
280 fun status_cmd f = Toplevel.no_timing o Toplevel.keep (fn state => |
212 f (Toplevel.theory_of state)) |
281 f (Toplevel.theory_of state)) |
213 |
282 |
214 val _ = |
283 val _ = |
215 OuterSyntax.improper_command "boogie_status" |
284 OuterSyntax.improper_command "boogie_status" |
216 "Show the name and state of all loaded verification conditions." |
285 "Show the name and state of all loaded verification conditions." |
217 OuterKeyword.diag |
286 OuterKeyword.diag |
218 (status_narrow_vc >> (status_cmd o boogie_narrow_vc) || |
287 (status_test >> status_cmd || |
219 status_vc_opts -- vc_name >> (status_cmd o boogie_status_vc) || |
288 status_vc >> status_cmd || |
220 Scan.succeed (status_cmd boogie_status)) |
289 Scan.succeed (status_cmd boogie_status)) |
221 |
290 |
222 |
291 |
223 val _ = |
292 val _ = |
224 OuterSyntax.command "boogie_end" |
293 OuterSyntax.command "boogie_end" |