boehmes@33408
|
1 |
(* Title: HOL/Boogie/Tools/boogie_loader.ML
|
boehmes@33408
|
2 |
Author: Sascha Boehme, TU Muenchen
|
boehmes@33408
|
3 |
|
boehmes@33408
|
4 |
Loading and interpreting Boogie-generated files.
|
boehmes@33408
|
5 |
*)
|
boehmes@33408
|
6 |
|
boehmes@33408
|
7 |
signature BOOGIE_LOADER =
|
boehmes@33408
|
8 |
sig
|
boehmes@35125
|
9 |
val load_b2i: bool -> (string * int) list -> Path.T -> theory -> theory
|
boehmes@33408
|
10 |
end
|
boehmes@33408
|
11 |
|
boehmes@33408
|
12 |
structure Boogie_Loader: BOOGIE_LOADER =
|
boehmes@33408
|
13 |
struct
|
boehmes@33408
|
14 |
|
boehmes@34002
|
15 |
fun log verbose text args x =
|
boehmes@34002
|
16 |
if verbose andalso not (null args)
|
boehmes@34002
|
17 |
then (Pretty.writeln (Pretty.big_list text (map Pretty.str args)); x)
|
boehmes@34002
|
18 |
else x
|
boehmes@33408
|
19 |
|
boehmes@33408
|
20 |
val isabelle_name =
|
boehmes@33408
|
21 |
let
|
boehmes@33441
|
22 |
fun purge s = if Symbol.is_letter s orelse Symbol.is_digit s then s else
|
boehmes@33408
|
23 |
(case s of
|
boehmes@33408
|
24 |
"." => "_o_"
|
boehmes@33408
|
25 |
| "_" => "_n_"
|
boehmes@33408
|
26 |
| "$" => "_S_"
|
boehmes@33408
|
27 |
| "@" => "_G_"
|
boehmes@33408
|
28 |
| "#" => "_H_"
|
boehmes@33408
|
29 |
| "^" => "_T_"
|
boehmes@33408
|
30 |
| _ => ("_" ^ string_of_int (ord s) ^ "_"))
|
boehmes@33408
|
31 |
in prefix "b_" o translate_string purge end
|
boehmes@33408
|
32 |
|
boehmes@34946
|
33 |
fun drop_underscore s =
|
boehmes@34946
|
34 |
try (unsuffix "_") s
|
boehmes@34946
|
35 |
|> Option.map drop_underscore
|
boehmes@34946
|
36 |
|> the_default s
|
boehmes@34946
|
37 |
|
boehmes@33441
|
38 |
val short_name =
|
boehmes@34946
|
39 |
translate_string (fn s => if Symbol.is_letdig s then s else "") #>
|
boehmes@34946
|
40 |
drop_underscore
|
boehmes@33441
|
41 |
|
boehmes@34068
|
42 |
(* these prefixes must be distinct: *)
|
boehmes@34068
|
43 |
val var_prefix = "V_"
|
boehmes@34068
|
44 |
val label_prefix = "L_"
|
boehmes@34068
|
45 |
val position_prefix = "P_"
|
boehmes@34068
|
46 |
|
boehmes@34068
|
47 |
val no_label_name = label_prefix ^ "unknown"
|
boehmes@34068
|
48 |
fun label_name line col =
|
boehmes@34068
|
49 |
if line = 0 orelse col = 0 then no_label_name
|
boehmes@34068
|
50 |
else label_prefix ^ string_of_int line ^ "_" ^ string_of_int col
|
boehmes@34068
|
51 |
|
boehmes@35358
|
52 |
fun mk_syntax name i =
|
boehmes@35358
|
53 |
let
|
wenzelm@35390
|
54 |
val syn = Syntax.escape name
|
wenzelm@35391
|
55 |
val args = space_implode ",/ " (replicate i "_")
|
boehmes@35358
|
56 |
in
|
boehmes@35358
|
57 |
if i = 0 then Mixfix (syn, [], 1000)
|
boehmes@35358
|
58 |
else Mixfix (syn ^ "()'(/" ^ args ^ "')", replicate i 0, 1000)
|
boehmes@35358
|
59 |
end
|
boehmes@35358
|
60 |
|
boehmes@33441
|
61 |
|
boehmes@34002
|
62 |
datatype attribute_value = StringValue of string | TermValue of term
|
boehmes@33408
|
63 |
|
boehmes@33408
|
64 |
|
boehmes@33408
|
65 |
|
boehmes@33408
|
66 |
local
|
boehmes@33408
|
67 |
fun lookup_type_name thy name arity =
|
boehmes@33408
|
68 |
let val intern = Sign.intern_type thy name
|
boehmes@33408
|
69 |
in
|
boehmes@33408
|
70 |
if Sign.declared_tyname thy intern
|
boehmes@33408
|
71 |
then
|
boehmes@33408
|
72 |
if Sign.arity_number thy intern = arity then SOME intern
|
boehmes@33408
|
73 |
else error ("Boogie: type already declared with different arity: " ^
|
boehmes@33408
|
74 |
quote name)
|
boehmes@33408
|
75 |
else NONE
|
boehmes@33408
|
76 |
end
|
boehmes@33408
|
77 |
|
boehmes@34002
|
78 |
fun log_new bname name = bname ^ " (as " ^ name ^ ")"
|
boehmes@34002
|
79 |
fun log_ex bname name = "[" ^ bname ^ " has already been declared as " ^
|
boehmes@34002
|
80 |
name ^ "]"
|
boehmes@34002
|
81 |
|
boehmes@33408
|
82 |
fun declare (name, arity) thy =
|
boehmes@33408
|
83 |
let val isa_name = isabelle_name name
|
boehmes@33408
|
84 |
in
|
boehmes@33408
|
85 |
(case lookup_type_name thy isa_name arity of
|
boehmes@34002
|
86 |
SOME type_name => (((name, type_name), log_ex name type_name), thy)
|
boehmes@33408
|
87 |
| NONE =>
|
boehmes@33408
|
88 |
let
|
boehmes@33408
|
89 |
val args = Name.variant_list [] (replicate arity "'")
|
wenzelm@35625
|
90 |
val (T, thy') =
|
wenzelm@35625
|
91 |
Object_Logic.typedecl (Binding.name isa_name, args, mk_syntax name arity) thy
|
boehmes@33408
|
92 |
val type_name = fst (Term.dest_Type T)
|
boehmes@34002
|
93 |
in (((name, type_name), log_new name type_name), thy') end)
|
boehmes@33408
|
94 |
end
|
boehmes@33408
|
95 |
in
|
boehmes@33408
|
96 |
fun declare_types verbose tys =
|
boehmes@34002
|
97 |
fold_map declare tys #>> split_list #-> (fn (tds, logs) =>
|
boehmes@34002
|
98 |
log verbose "Declared types:" logs #>
|
boehmes@34002
|
99 |
rpair (Symtab.make tds))
|
boehmes@33408
|
100 |
end
|
boehmes@33408
|
101 |
|
boehmes@33408
|
102 |
|
boehmes@33408
|
103 |
|
boehmes@33408
|
104 |
local
|
boehmes@33893
|
105 |
fun maybe_builtin T =
|
boehmes@33408
|
106 |
let
|
boehmes@33408
|
107 |
fun const name = SOME (Const (name, T))
|
boehmes@34068
|
108 |
fun const2_abs name =
|
boehmes@34181
|
109 |
let val U = Term.domain_type T
|
boehmes@34068
|
110 |
in
|
boehmes@34068
|
111 |
SOME (Abs (Name.uu, U, Abs (Name.uu, U,
|
boehmes@34068
|
112 |
Const (name, T) $ Bound 0 $ Bound 1)))
|
boehmes@34068
|
113 |
end
|
boehmes@33408
|
114 |
|
boehmes@33408
|
115 |
fun choose builtin =
|
boehmes@33408
|
116 |
(case builtin of
|
boehmes@34068
|
117 |
"bvnot" => const @{const_name bitNOT}
|
boehmes@34068
|
118 |
| "bvand" => const @{const_name bitAND}
|
boehmes@34068
|
119 |
| "bvor" => const @{const_name bitOR}
|
boehmes@34068
|
120 |
| "bvxor" => const @{const_name bitXOR}
|
boehmes@34068
|
121 |
| "bvadd" => const @{const_name plus}
|
boehmes@34068
|
122 |
| "bvneg" => const @{const_name uminus}
|
boehmes@34068
|
123 |
| "bvsub" => const @{const_name minus}
|
boehmes@34068
|
124 |
| "bvmul" => const @{const_name times}
|
boehmes@34068
|
125 |
| "bvudiv" => const @{const_name div}
|
boehmes@34068
|
126 |
| "bvurem" => const @{const_name mod}
|
boehmes@34068
|
127 |
| "bvsdiv" => const @{const_name sdiv}
|
boehmes@34068
|
128 |
| "bvsrem" => const @{const_name srem}
|
boehmes@34068
|
129 |
| "bvshl" => const @{const_name bv_shl}
|
boehmes@34068
|
130 |
| "bvlshr" => const @{const_name bv_lshr}
|
boehmes@34068
|
131 |
| "bvashr" => const @{const_name bv_ashr}
|
boehmes@34068
|
132 |
| "bvult" => const @{const_name less}
|
boehmes@34068
|
133 |
| "bvule" => const @{const_name less_eq}
|
boehmes@34068
|
134 |
| "bvugt" => const2_abs @{const_name less}
|
boehmes@34068
|
135 |
| "bvuge" => const2_abs @{const_name less_eq}
|
boehmes@34068
|
136 |
| "bvslt" => const @{const_name word_sless}
|
boehmes@34068
|
137 |
| "bvsle" => const @{const_name word_sle}
|
boehmes@34068
|
138 |
| "bvsgt" => const2_abs @{const_name word_sless}
|
boehmes@34068
|
139 |
| "bvsge" => const2_abs @{const_name word_sle}
|
boehmes@34068
|
140 |
| "zero_extend" => const @{const_name ucast}
|
boehmes@34068
|
141 |
| "sign_extend" => const @{const_name scast}
|
boehmes@33408
|
142 |
| _ => NONE)
|
boehmes@33408
|
143 |
|
boehmes@33408
|
144 |
fun is_builtin att =
|
boehmes@33408
|
145 |
(case att of
|
boehmes@33408
|
146 |
("bvbuiltin", [StringValue builtin]) => choose builtin
|
boehmes@33408
|
147 |
| ("bvint", [StringValue "ITE"]) => const @{const_name If}
|
boehmes@33408
|
148 |
| _ => NONE)
|
boehmes@33408
|
149 |
in get_first is_builtin end
|
boehmes@33408
|
150 |
|
boehmes@33408
|
151 |
fun lookup_const thy name T =
|
boehmes@33458
|
152 |
let val intern = Sign.intern_const thy name
|
boehmes@33408
|
153 |
in
|
boehmes@33408
|
154 |
if Sign.declared_const thy intern
|
boehmes@33408
|
155 |
then
|
boehmes@33458
|
156 |
if Sign.typ_instance thy (T, Sign.the_const_type thy intern)
|
boehmes@33408
|
157 |
then SOME (Const (intern, T))
|
boehmes@33408
|
158 |
else error ("Boogie: function already declared with different type: " ^
|
boehmes@33408
|
159 |
quote name)
|
boehmes@33408
|
160 |
else NONE
|
boehmes@33408
|
161 |
end
|
boehmes@33408
|
162 |
|
boehmes@34002
|
163 |
fun log_term thy t = Syntax.string_of_term_global thy t
|
boehmes@34002
|
164 |
fun log_new thy name t = name ^ " (as " ^ log_term thy t ^ ")"
|
boehmes@34002
|
165 |
fun log_ex thy name t = "[" ^ name ^ " has already been declared as " ^
|
boehmes@34002
|
166 |
log_term thy t ^ "]"
|
boehmes@34002
|
167 |
fun log_builtin thy name t = "[" ^ name ^ " has been identified as " ^
|
boehmes@34002
|
168 |
log_term thy t ^ "]"
|
boehmes@33408
|
169 |
|
boehmes@34002
|
170 |
fun declare' name isa_name T arity atts thy =
|
boehmes@34002
|
171 |
(case lookup_const thy isa_name T of
|
boehmes@34002
|
172 |
SOME t => (((name, t), log_ex thy name t), thy)
|
boehmes@34002
|
173 |
| NONE =>
|
boehmes@34002
|
174 |
(case maybe_builtin T atts of
|
boehmes@34002
|
175 |
SOME t => (((name, t), log_builtin thy name t), thy)
|
boehmes@34002
|
176 |
| NONE =>
|
boehmes@34002
|
177 |
thy
|
boehmes@34002
|
178 |
|> Sign.declare_const ((Binding.name isa_name, T),
|
boehmes@34002
|
179 |
mk_syntax name arity)
|
boehmes@34002
|
180 |
|> (fn (t, thy') => (((name, t), log_new thy' name t), thy'))))
|
boehmes@34002
|
181 |
fun declare (name, ((Ts, T), atts)) =
|
boehmes@34002
|
182 |
declare' name (isabelle_name name) (Ts ---> T) (length Ts) atts
|
boehmes@33893
|
183 |
|
boehmes@33893
|
184 |
fun uniques fns fds =
|
boehmes@33893
|
185 |
let
|
boehmes@34068
|
186 |
fun is_unique (name, (([], _), atts)) =
|
boehmes@33893
|
187 |
(case AList.lookup (op =) atts "unique" of
|
boehmes@33893
|
188 |
SOME _ => Symtab.lookup fds name
|
boehmes@33893
|
189 |
| NONE => NONE)
|
boehmes@33893
|
190 |
| is_unique _ = NONE
|
boehmes@33893
|
191 |
fun mk_unique_axiom T ts =
|
boehmes@33893
|
192 |
Const (@{const_name distinct}, HOLogic.listT T --> @{typ bool}) $
|
boehmes@33893
|
193 |
HOLogic.mk_list T ts
|
boehmes@33893
|
194 |
in
|
boehmes@33893
|
195 |
map_filter is_unique fns
|
boehmes@33893
|
196 |
|> map (swap o Term.dest_Const)
|
boehmes@33893
|
197 |
|> AList.group (op =)
|
boehmes@33893
|
198 |
|> map (fn (T, ns) => mk_unique_axiom T (map (Const o rpair T) ns))
|
boehmes@33893
|
199 |
end
|
boehmes@33408
|
200 |
in
|
boehmes@33408
|
201 |
fun declare_functions verbose fns =
|
boehmes@34002
|
202 |
fold_map declare fns #>> split_list #-> (fn (fds, logs) =>
|
boehmes@34002
|
203 |
log verbose "Loaded constants:" logs #>
|
boehmes@34002
|
204 |
rpair (` (uniques fns) (Symtab.make fds)))
|
boehmes@33408
|
205 |
end
|
boehmes@33408
|
206 |
|
boehmes@33408
|
207 |
|
boehmes@33408
|
208 |
|
boehmes@33408
|
209 |
local
|
boehmes@33408
|
210 |
fun name_axioms axs =
|
boehmes@33408
|
211 |
let fun mk_name idx = "axiom_" ^ string_of_int (idx + 1)
|
boehmes@33408
|
212 |
in map_index (fn (idx, t) => (mk_name idx, HOLogic.mk_Trueprop t)) axs end
|
boehmes@33408
|
213 |
|
boehmes@34002
|
214 |
datatype kind = Unused of thm | Used of thm | New of string
|
boehmes@34002
|
215 |
|
boehmes@34002
|
216 |
fun mark (name, t) axs =
|
boehmes@34002
|
217 |
(case Termtab.lookup axs t of
|
boehmes@34002
|
218 |
SOME (Unused thm) => Termtab.update (t, Used thm) axs
|
boehmes@34002
|
219 |
| NONE => Termtab.update (t, New name) axs
|
boehmes@34002
|
220 |
| SOME _ => axs)
|
boehmes@34002
|
221 |
|
boehmes@34002
|
222 |
val sort_fst_str = sort (prod_ord fast_string_ord (K EQUAL))
|
boehmes@34002
|
223 |
fun split_list_kind thy axs =
|
boehmes@34002
|
224 |
let
|
boehmes@34002
|
225 |
fun split (_, Used thm) (used, new) = (thm :: used, new)
|
boehmes@34002
|
226 |
| split (t, New name) (used, new) = (used, (name, t) :: new)
|
boehmes@34068
|
227 |
| split (_, Unused thm) (used, new) =
|
boehmes@34002
|
228 |
(warning (Pretty.str_of
|
boehmes@34002
|
229 |
(Pretty.big_list "This background axiom has not been loaded:"
|
boehmes@34002
|
230 |
[Display.pretty_thm_global thy thm]));
|
boehmes@34002
|
231 |
(used, new))
|
boehmes@34002
|
232 |
in apsnd sort_fst_str (fold split axs ([], [])) end
|
boehmes@34002
|
233 |
|
boehmes@34002
|
234 |
fun mark_axioms thy axs =
|
boehmes@34002
|
235 |
Boogie_Axioms.get (ProofContext.init thy)
|
boehmes@34002
|
236 |
|> Termtab.make o map (fn thm => (Thm.prop_of thm, Unused thm))
|
boehmes@34002
|
237 |
|> fold mark axs
|
boehmes@34002
|
238 |
|> split_list_kind thy o Termtab.dest
|
boehmes@33408
|
239 |
in
|
boehmes@33408
|
240 |
fun add_axioms verbose axs thy =
|
boehmes@34002
|
241 |
let val (used, new) = mark_axioms thy (name_axioms axs)
|
boehmes@33408
|
242 |
in
|
boehmes@33408
|
243 |
thy
|
boehmes@34002
|
244 |
|> PureThy.add_axioms (map (rpair [] o apfst Binding.name) new)
|
boehmes@33408
|
245 |
|-> Context.theory_map o fold Boogie_Axioms.add_thm
|
boehmes@34002
|
246 |
|> log verbose "The following axioms were added:" (map fst new)
|
boehmes@34002
|
247 |
|> (fn thy' => log verbose "The following axioms already existed:"
|
boehmes@34002
|
248 |
(map (Display.string_of_thm_global thy') used) thy')
|
boehmes@33408
|
249 |
end
|
boehmes@33408
|
250 |
end
|
boehmes@33408
|
251 |
|
boehmes@33408
|
252 |
|
boehmes@33408
|
253 |
|
boehmes@33441
|
254 |
local
|
boehmes@33441
|
255 |
fun burrow_distinct eq f xs =
|
boehmes@33441
|
256 |
let
|
boehmes@33441
|
257 |
val ys = distinct eq xs
|
boehmes@33441
|
258 |
val tab = ys ~~ f ys
|
boehmes@33441
|
259 |
in map (the o AList.lookup eq tab) xs end
|
boehmes@33441
|
260 |
|
boehmes@33441
|
261 |
fun indexed names =
|
boehmes@33441
|
262 |
let
|
boehmes@33441
|
263 |
val dup = member (op =) (duplicates (op =) (map fst names))
|
boehmes@33441
|
264 |
fun make_name (n, i) = n ^ (if dup n then "_" ^ string_of_int i else "")
|
boehmes@33441
|
265 |
in map make_name names end
|
boehmes@33441
|
266 |
|
boehmes@33441
|
267 |
fun rename idx_names =
|
boehmes@33441
|
268 |
idx_names
|
boehmes@33441
|
269 |
|> burrow_fst (burrow_distinct (op =)
|
boehmes@33441
|
270 |
(map short_name #> ` (duplicates (op =)) #-> Name.variant_list))
|
boehmes@33441
|
271 |
|> indexed
|
boehmes@33441
|
272 |
in
|
boehmes@33408
|
273 |
fun add_vcs verbose vcs thy =
|
boehmes@34068
|
274 |
let val vcs' = burrow_fst rename vcs
|
boehmes@33408
|
275 |
in
|
boehmes@33408
|
276 |
thy
|
boehmes@33408
|
277 |
|> Boogie_VCs.set vcs'
|
boehmes@33408
|
278 |
|> log verbose "The following verification conditions were loaded:"
|
boehmes@33408
|
279 |
(map fst vcs')
|
boehmes@33408
|
280 |
end
|
boehmes@33441
|
281 |
end
|
boehmes@33408
|
282 |
|
boehmes@33408
|
283 |
|
boehmes@33408
|
284 |
|
boehmes@33408
|
285 |
local
|
boehmes@33408
|
286 |
fun mk_bitT i T =
|
boehmes@33408
|
287 |
if i = 0
|
boehmes@33408
|
288 |
then Type (@{type_name "Numeral_Type.bit0"}, [T])
|
boehmes@33408
|
289 |
else Type (@{type_name "Numeral_Type.bit1"}, [T])
|
boehmes@33408
|
290 |
|
boehmes@33408
|
291 |
fun mk_binT size =
|
boehmes@33408
|
292 |
if size = 0 then @{typ "Numeral_Type.num0"}
|
boehmes@33408
|
293 |
else if size = 1 then @{typ "Numeral_Type.num1"}
|
boehmes@33408
|
294 |
else let val (q, r) = Integer.div_mod size 2 in mk_bitT r (mk_binT q) end
|
boehmes@33408
|
295 |
in
|
boehmes@33408
|
296 |
fun mk_wordT size =
|
boehmes@33408
|
297 |
if size >= 0 then Type (@{type_name "word"}, [mk_binT size])
|
boehmes@33408
|
298 |
else raise TYPE ("mk_wordT: " ^ quote (string_of_int size), [], [])
|
boehmes@33408
|
299 |
end
|
boehmes@33408
|
300 |
|
boehmes@33408
|
301 |
local
|
boehmes@33408
|
302 |
fun dest_binT T =
|
boehmes@33408
|
303 |
(case T of
|
boehmes@33408
|
304 |
Type (@{type_name "Numeral_Type.num0"}, _) => 0
|
boehmes@33408
|
305 |
| Type (@{type_name "Numeral_Type.num1"}, _) => 1
|
boehmes@33408
|
306 |
| Type (@{type_name "Numeral_Type.bit0"}, [T]) => 2 * dest_binT T
|
boehmes@33408
|
307 |
| Type (@{type_name "Numeral_Type.bit1"}, [T]) => 1 + 2 * dest_binT T
|
boehmes@33408
|
308 |
| _ => raise TYPE ("dest_binT", [T], []))
|
boehmes@33408
|
309 |
in
|
boehmes@33408
|
310 |
val dest_wordT = (fn
|
boehmes@33408
|
311 |
Type (@{type_name "word"}, [T]) => dest_binT T
|
boehmes@33408
|
312 |
| T => raise TYPE ("dest_wordT", [T], []))
|
boehmes@33408
|
313 |
end
|
boehmes@33408
|
314 |
|
boehmes@33408
|
315 |
fun mk_arrayT (Ts, T) = Type (@{type_name "fun"}, [HOLogic.mk_tupleT Ts, T])
|
boehmes@33408
|
316 |
|
boehmes@33408
|
317 |
|
boehmes@33408
|
318 |
|
boehmes@33408
|
319 |
datatype token = Token of string | Newline | EOF
|
boehmes@33408
|
320 |
|
boehmes@33408
|
321 |
fun tokenize path =
|
boehmes@33408
|
322 |
let
|
boehmes@33408
|
323 |
fun blank c = (c = #" " orelse c = #"\t" orelse c = #"\n" orelse c = #"\r")
|
boehmes@33408
|
324 |
fun split line (i, tss) = (i + 1,
|
boehmes@33408
|
325 |
map (pair i) (map Token (String.tokens blank line) @ [Newline]) :: tss)
|
boehmes@33408
|
326 |
in apsnd (flat o rev) (File.fold_lines split path (1, [])) end
|
boehmes@33408
|
327 |
|
boehmes@33408
|
328 |
fun stopper i = Scan.stopper (K (i, EOF)) (fn (_, EOF) => true | _ => false)
|
boehmes@33408
|
329 |
|
boehmes@33408
|
330 |
fun scan_err msg [] = "Boogie (at end of input): " ^ msg
|
boehmes@33408
|
331 |
| scan_err msg ((i, _) :: _) = "Boogie (at line " ^ string_of_int i ^ "): " ^
|
boehmes@33408
|
332 |
msg
|
boehmes@33408
|
333 |
|
boehmes@33408
|
334 |
fun scan_fail msg = Scan.fail_with (scan_err msg)
|
boehmes@33408
|
335 |
|
boehmes@33408
|
336 |
fun finite scan path =
|
boehmes@33408
|
337 |
let val (i, ts) = tokenize path
|
boehmes@33408
|
338 |
in
|
boehmes@33408
|
339 |
(case Scan.error (Scan.finite (stopper i) scan) ts of
|
boehmes@33408
|
340 |
(x, []) => x
|
boehmes@33408
|
341 |
| (_, ts) => error (scan_err "unparsed input" ts))
|
boehmes@33408
|
342 |
end
|
boehmes@33408
|
343 |
|
boehmes@33408
|
344 |
fun read_int' s = (case read_int (explode s) of (i, []) => SOME i | _ => NONE)
|
boehmes@33408
|
345 |
|
boehmes@33408
|
346 |
fun $$$ s = Scan.one (fn (_, Token s') => s = s' | _ => false)
|
boehmes@33497
|
347 |
fun str st = Scan.some (fn (_, Token s) => SOME s | _ => NONE) st
|
boehmes@33497
|
348 |
fun num st = Scan.some (fn (_, Token s) => read_int' s | _ => NONE) st
|
boehmes@33408
|
349 |
|
boehmes@33408
|
350 |
fun scan_line key scan =
|
boehmes@33408
|
351 |
$$$ key |-- scan --| Scan.one (fn (_, Newline) => true | _ => false)
|
boehmes@33408
|
352 |
fun scan_line' key = scan_line key (Scan.succeed ())
|
boehmes@33408
|
353 |
|
boehmes@33408
|
354 |
fun scan_count scan i =
|
boehmes@33408
|
355 |
if i > 0 then scan ::: scan_count scan (i - 1) else Scan.succeed []
|
boehmes@33408
|
356 |
|
boehmes@33408
|
357 |
fun scan_lookup kind tab key =
|
boehmes@33408
|
358 |
(case Symtab.lookup tab key of
|
boehmes@33408
|
359 |
SOME value => Scan.succeed value
|
boehmes@33408
|
360 |
| NONE => scan_fail ("undefined " ^ kind ^ ": " ^ quote key))
|
boehmes@33408
|
361 |
|
boehmes@33408
|
362 |
fun typ tds =
|
boehmes@33408
|
363 |
let
|
boehmes@33408
|
364 |
fun tp st =
|
boehmes@33408
|
365 |
(scan_line' "bool" >> K @{typ bool} ||
|
boehmes@33408
|
366 |
scan_line' "int" >> K @{typ int} ||
|
boehmes@33408
|
367 |
scan_line "bv" num >> mk_wordT ||
|
boehmes@33408
|
368 |
scan_line "type-con" (str -- num) :|-- (fn (name, arity) =>
|
boehmes@33408
|
369 |
scan_lookup "type constructor" tds name -- scan_count tp arity >>
|
boehmes@33408
|
370 |
Type) ||
|
boehmes@33408
|
371 |
scan_line "array" num :|-- (fn arity =>
|
boehmes@33408
|
372 |
scan_count tp (arity - 1) -- tp >> mk_arrayT) ||
|
boehmes@33408
|
373 |
scan_fail "illegal type") st
|
boehmes@33408
|
374 |
in tp end
|
boehmes@33408
|
375 |
|
boehmes@33408
|
376 |
local
|
boehmes@33408
|
377 |
fun mk_nary _ t [] = t
|
boehmes@33661
|
378 |
| mk_nary f _ ts = uncurry (fold_rev f) (split_last ts)
|
boehmes@33408
|
379 |
|
boehmes@33408
|
380 |
fun mk_distinct T ts =
|
boehmes@33408
|
381 |
Const (@{const_name distinct}, HOLogic.listT T --> @{typ bool}) $
|
boehmes@33408
|
382 |
HOLogic.mk_list T ts
|
boehmes@33408
|
383 |
|
boehmes@33408
|
384 |
fun quant name f = scan_line name (num -- num -- num) >> pair f
|
boehmes@33408
|
385 |
val quants =
|
boehmes@33408
|
386 |
quant "forall" HOLogic.all_const ||
|
boehmes@33408
|
387 |
quant "exists" HOLogic.exists_const ||
|
boehmes@33408
|
388 |
scan_fail "illegal quantifier kind"
|
boehmes@33441
|
389 |
fun mk_quant q (n, T) t = q T $ Term.absfree (n, T, t)
|
boehmes@33408
|
390 |
|
boehmes@33408
|
391 |
val patternT = @{typ pattern}
|
boehmes@33408
|
392 |
fun mk_pattern _ [] = raise TERM ("mk_pattern", [])
|
boehmes@33408
|
393 |
| mk_pattern n [t] = Const (n, Term.fastype_of t --> patternT) $ t
|
boehmes@33408
|
394 |
| mk_pattern n (t :: ts) =
|
boehmes@33408
|
395 |
let val T = patternT --> Term.fastype_of t --> patternT
|
boehmes@33408
|
396 |
in Const (@{const_name andpat}, T) $ mk_pattern n ts $ t end
|
boehmes@33408
|
397 |
fun patt n c scan =
|
boehmes@33408
|
398 |
scan_line n num :|-- scan_count scan >> (mk_pattern c)
|
boehmes@33408
|
399 |
fun pattern scan =
|
boehmes@33408
|
400 |
patt "pat" @{const_name pat} scan ||
|
boehmes@33408
|
401 |
patt "nopat" @{const_name nopat} scan ||
|
boehmes@33408
|
402 |
scan_fail "illegal pattern kind"
|
boehmes@33408
|
403 |
fun mk_trigger [] t = t
|
boehmes@33408
|
404 |
| mk_trigger ps t = @{term trigger} $ HOLogic.mk_list patternT ps $ t
|
boehmes@33408
|
405 |
|
boehmes@34068
|
406 |
fun make_label (line, col) = Free (label_name line col, @{typ bool})
|
boehmes@34068
|
407 |
fun labelled_by kind pos t = kind $ make_label pos $ t
|
boehmes@35125
|
408 |
fun label offset =
|
boehmes@35125
|
409 |
$$$ "pos" |-- num -- num >> (fn (line, col) =>
|
boehmes@34068
|
410 |
if label_name line col = no_label_name then I
|
boehmes@35125
|
411 |
else labelled_by @{term block_at} (line - offset, col)) ||
|
boehmes@35125
|
412 |
$$$ "neg" |-- num -- num >> (fn (line, col) =>
|
boehmes@35125
|
413 |
labelled_by @{term assert_at} (line - offset, col)) ||
|
boehmes@33408
|
414 |
scan_fail "illegal label kind"
|
boehmes@33408
|
415 |
|
boehmes@33408
|
416 |
fun mk_store ((m, k), v) =
|
boehmes@33408
|
417 |
let
|
boehmes@33408
|
418 |
val mT = Term.fastype_of m and kT = Term.fastype_of k
|
boehmes@33408
|
419 |
val vT = Term.fastype_of v
|
boehmes@34068
|
420 |
in Const (@{const_name fun_upd}, mT --> kT --> vT --> mT) $ m $ k $ v end
|
boehmes@33408
|
421 |
|
boehmes@33408
|
422 |
fun mk_extract ((msb, lsb), t) =
|
boehmes@33408
|
423 |
let
|
boehmes@33408
|
424 |
val dT = Term.fastype_of t and rT = mk_wordT (msb - lsb)
|
boehmes@33408
|
425 |
val nT = @{typ nat}
|
boehmes@33408
|
426 |
val mk_nat_num = HOLogic.mk_number @{typ nat}
|
boehmes@34068
|
427 |
in Const (@{const_name slice}, [nT, dT] ---> rT) $ mk_nat_num lsb $ t end
|
boehmes@33408
|
428 |
|
boehmes@33408
|
429 |
fun mk_concat (t1, t2) =
|
boehmes@33408
|
430 |
let
|
boehmes@33408
|
431 |
val T1 = Term.fastype_of t1 and T2 = Term.fastype_of t2
|
boehmes@33408
|
432 |
val U = mk_wordT (dest_wordT T1 + dest_wordT T2)
|
boehmes@34068
|
433 |
in Const (@{const_name word_cat}, [T1, T2] ---> U) $ t1 $ t2 end
|
boehmes@33441
|
434 |
|
boehmes@34068
|
435 |
fun unique_labels t =
|
boehmes@34068
|
436 |
let
|
boehmes@34068
|
437 |
fun names_of (@{term assert_at} $ Free (n, _) $ t) = cons n #> names_of t
|
boehmes@34068
|
438 |
| names_of (t $ u) = names_of t #> names_of u
|
boehmes@34068
|
439 |
| names_of (Abs (_, _, t)) = names_of t
|
boehmes@34068
|
440 |
| names_of _ = I
|
boehmes@34068
|
441 |
val nctxt = Name.make_context (duplicates (op =) (names_of t []))
|
boehmes@34068
|
442 |
|
boehmes@34068
|
443 |
fun fresh (i, nctxt) = (position_prefix ^ string_of_int i, (i+1, nctxt))
|
boehmes@34068
|
444 |
fun renamed n (i, nctxt) =
|
boehmes@34068
|
445 |
yield_singleton Name.variants n nctxt ||> pair i
|
boehmes@34068
|
446 |
fun mk_label (name, t) = @{term assert_at} $ Free (name, @{typ bool}) $ t
|
boehmes@34068
|
447 |
|
boehmes@34068
|
448 |
fun unique t =
|
boehmes@34068
|
449 |
(case t of
|
boehmes@34068
|
450 |
@{term assert_at} $ Free (n, _) $ u =>
|
boehmes@34068
|
451 |
if n = no_label_name
|
boehmes@34068
|
452 |
then fresh ##>> unique u #>> mk_label
|
boehmes@34068
|
453 |
else renamed n ##>> unique u #>> mk_label
|
boehmes@34068
|
454 |
| u1 $ u2 => unique u1 ##>> unique u2 #>> (op $)
|
boehmes@34068
|
455 |
| Abs (n, T, u) => unique u #>> (fn u' => Abs (n, T, u'))
|
boehmes@34068
|
456 |
| _ => pair t)
|
boehmes@34068
|
457 |
in fst (unique t (1, nctxt)) end
|
boehmes@34068
|
458 |
|
boehmes@34068
|
459 |
val var_name = str >> prefix var_prefix
|
boehmes@34068
|
460 |
val dest_var_name = unprefix var_prefix
|
boehmes@33441
|
461 |
fun rename_variables t =
|
boehmes@33441
|
462 |
let
|
boehmes@33441
|
463 |
fun short_var_name n = short_name (dest_var_name n)
|
boehmes@33441
|
464 |
|
boehmes@34068
|
465 |
val all_names = Term.add_free_names t []
|
boehmes@33441
|
466 |
val (names, nctxt) =
|
boehmes@34068
|
467 |
all_names
|
boehmes@33441
|
468 |
|> map_filter (try (fn n => (n, short_var_name n)))
|
boehmes@33441
|
469 |
|> split_list
|
boehmes@34068
|
470 |
||>> (fn names => Name.variants names (Name.make_context all_names))
|
boehmes@33441
|
471 |
|>> Symtab.make o (op ~~)
|
boehmes@33441
|
472 |
|
boehmes@33441
|
473 |
fun rename_free n = the_default n (Symtab.lookup names n)
|
boehmes@33441
|
474 |
fun rename_abs n = yield_singleton Name.variants (short_var_name n)
|
boehmes@33441
|
475 |
|
boehmes@33441
|
476 |
fun rename _ (Free (n, T)) = Free (rename_free n, T)
|
boehmes@33441
|
477 |
| rename nctxt (Abs (n, T, t)) =
|
boehmes@33441
|
478 |
let val (n', nctxt') = rename_abs n nctxt
|
boehmes@33441
|
479 |
in Abs (n', T, rename nctxt' t) end
|
boehmes@33441
|
480 |
| rename nctxt (t $ u) = rename nctxt t $ rename nctxt u
|
boehmes@33441
|
481 |
| rename _ t = t
|
boehmes@33441
|
482 |
in rename nctxt t end
|
boehmes@33408
|
483 |
in
|
boehmes@35125
|
484 |
fun expr offset tds fds =
|
boehmes@33408
|
485 |
let
|
boehmes@33408
|
486 |
fun binop t (u1, u2) = t $ u1 $ u2
|
boehmes@33408
|
487 |
fun binexp s f = scan_line' s |-- exp -- exp >> f
|
boehmes@33408
|
488 |
|
boehmes@33408
|
489 |
and exp st =
|
boehmes@33408
|
490 |
(scan_line' "true" >> K @{term True} ||
|
boehmes@33408
|
491 |
scan_line' "false" >> K @{term False} ||
|
boehmes@33408
|
492 |
scan_line' "not" |-- exp >> HOLogic.mk_not ||
|
boehmes@33408
|
493 |
scan_line "and" num :|-- scan_count exp >>
|
boehmes@33408
|
494 |
mk_nary (curry HOLogic.mk_conj) @{term True} ||
|
boehmes@33408
|
495 |
scan_line "or" num :|-- scan_count exp >>
|
boehmes@33408
|
496 |
mk_nary (curry HOLogic.mk_disj) @{term False} ||
|
boehmes@33408
|
497 |
binexp "implies" (binop @{term "op -->"}) ||
|
boehmes@33408
|
498 |
scan_line "distinct" num :|-- scan_count exp >>
|
boehmes@33408
|
499 |
(fn [] => @{term True}
|
boehmes@33408
|
500 |
| ts as (t :: _) => mk_distinct (Term.fastype_of t) ts) ||
|
boehmes@33408
|
501 |
binexp "=" HOLogic.mk_eq ||
|
boehmes@33441
|
502 |
scan_line "var" var_name -- typ tds >> Free ||
|
boehmes@33408
|
503 |
scan_line "fun" (str -- num) :|-- (fn (name, arity) =>
|
boehmes@33408
|
504 |
scan_lookup "constant" fds name -- scan_count exp arity >>
|
boehmes@33408
|
505 |
Term.list_comb) ||
|
boehmes@33408
|
506 |
quants :|-- (fn (q, ((n, k), i)) =>
|
boehmes@33441
|
507 |
scan_count (scan_line "var" var_name -- typ tds) n --
|
boehmes@33408
|
508 |
scan_count (pattern exp) k --
|
boehmes@35125
|
509 |
scan_count (attribute offset tds fds) i --
|
boehmes@33408
|
510 |
exp >> (fn (((vs, ps), _), t) =>
|
boehmes@33408
|
511 |
fold_rev (mk_quant q) vs (mk_trigger ps t))) ||
|
boehmes@35125
|
512 |
scan_line "label" (label offset) -- exp >> (fn (mk, t) => mk t) ||
|
boehmes@33408
|
513 |
scan_line "int-num" num >> HOLogic.mk_number @{typ int} ||
|
boehmes@33408
|
514 |
binexp "<" (binop @{term "op < :: int => _"}) ||
|
boehmes@33408
|
515 |
binexp "<=" (binop @{term "op <= :: int => _"}) ||
|
boehmes@33408
|
516 |
binexp ">" (binop @{term "op < :: int => _"} o swap) ||
|
boehmes@33408
|
517 |
binexp ">=" (binop @{term "op <= :: int => _"} o swap) ||
|
boehmes@33408
|
518 |
binexp "+" (binop @{term "op + :: int => _"}) ||
|
boehmes@33661
|
519 |
binexp "-" (binop @{term "op - :: int => _"}) ||
|
boehmes@33661
|
520 |
binexp "*" (binop @{term "op * :: int => _"}) ||
|
boehmes@33408
|
521 |
binexp "/" (binop @{term boogie_div}) ||
|
boehmes@33408
|
522 |
binexp "%" (binop @{term boogie_mod}) ||
|
boehmes@33408
|
523 |
scan_line "select" num :|-- (fn arity =>
|
boehmes@34068
|
524 |
exp -- (scan_count exp (arity - 1) >> HOLogic.mk_tuple) >> (op $)) ||
|
boehmes@33408
|
525 |
scan_line "store" num :|-- (fn arity =>
|
boehmes@33408
|
526 |
exp -- (scan_count exp (arity - 2) >> HOLogic.mk_tuple) -- exp >>
|
boehmes@33408
|
527 |
mk_store) ||
|
boehmes@33408
|
528 |
scan_line "bv-num" (num -- num) >> (fn (size, i) =>
|
boehmes@33408
|
529 |
HOLogic.mk_number (mk_wordT size) i) ||
|
boehmes@33408
|
530 |
scan_line "bv-extract" (num -- num) -- exp >> mk_extract ||
|
boehmes@33408
|
531 |
binexp "bv-concat" mk_concat ||
|
boehmes@33408
|
532 |
scan_fail "illegal expression") st
|
boehmes@34068
|
533 |
in exp >> (rename_variables o unique_labels) end
|
boehmes@33408
|
534 |
|
boehmes@35125
|
535 |
and attribute offset tds fds =
|
boehmes@33408
|
536 |
let
|
boehmes@33408
|
537 |
val attr_val =
|
boehmes@35125
|
538 |
scan_line' "expr-attr" |-- expr offset tds fds >> TermValue ||
|
boehmes@33408
|
539 |
scan_line "string-attr" (Scan.repeat1 str) >>
|
boehmes@33408
|
540 |
(StringValue o space_implode " ") ||
|
boehmes@33408
|
541 |
scan_fail "illegal attribute value"
|
boehmes@33408
|
542 |
in
|
boehmes@33408
|
543 |
scan_line "attribute" (str -- num) :|-- (fn (name, i) =>
|
boehmes@33408
|
544 |
scan_count attr_val i >> pair name) ||
|
boehmes@33408
|
545 |
scan_fail "illegal attribute"
|
boehmes@33408
|
546 |
end
|
boehmes@33408
|
547 |
end
|
boehmes@33408
|
548 |
|
boehmes@33408
|
549 |
fun type_decls verbose = Scan.depend (fn thy =>
|
boehmes@33408
|
550 |
Scan.repeat (scan_line "type-decl" (str -- num -- num) :|-- (fn (ty, i) =>
|
boehmes@35125
|
551 |
scan_count (attribute 0 Symtab.empty Symtab.empty) i >> K ty)) >>
|
boehmes@33408
|
552 |
(fn tys => declare_types verbose tys thy))
|
boehmes@33408
|
553 |
|
boehmes@33408
|
554 |
fun fun_decls verbose tds = Scan.depend (fn thy =>
|
boehmes@33408
|
555 |
Scan.repeat (scan_line "fun-decl" (str -- num -- num) :|--
|
boehmes@33408
|
556 |
(fn ((name, arity), i) =>
|
boehmes@33408
|
557 |
scan_count (typ tds) (arity - 1) -- typ tds --
|
boehmes@35125
|
558 |
scan_count (attribute 0 tds Symtab.empty) i >> pair name)) >>
|
boehmes@33408
|
559 |
(fn fns => declare_functions verbose fns thy))
|
boehmes@33408
|
560 |
|
boehmes@33893
|
561 |
fun axioms verbose tds fds unique_axs = Scan.depend (fn thy =>
|
boehmes@33408
|
562 |
Scan.repeat (scan_line "axiom" num :|-- (fn i =>
|
boehmes@35125
|
563 |
expr 0 tds fds --| scan_count (attribute 0 tds fds) i)) >>
|
boehmes@33893
|
564 |
(fn axs => (add_axioms verbose (unique_axs @ axs) thy, ())))
|
boehmes@33408
|
565 |
|
boehmes@33408
|
566 |
fun var_decls tds fds = Scan.depend (fn thy =>
|
boehmes@33408
|
567 |
Scan.repeat (scan_line "var-decl" (str -- num) :|-- (fn (_, i) =>
|
boehmes@35125
|
568 |
typ tds -- scan_count (attribute 0 tds fds) i >> K ())) >> K (thy, ()))
|
boehmes@33408
|
569 |
|
boehmes@35125
|
570 |
fun local_vc_offset offsets vc_name =
|
boehmes@35125
|
571 |
Integer.add ~1 (the_default 1 (AList.lookup (op =) offsets vc_name))
|
boehmes@33408
|
572 |
|
boehmes@35125
|
573 |
fun vcs verbose offsets tds fds = Scan.depend (fn thy =>
|
boehmes@35125
|
574 |
Scan.repeat (scan_line "vc" (str -- num) :-- (fn (name, _) =>
|
boehmes@35125
|
575 |
(expr (local_vc_offset offsets name) tds fds))) >>
|
boehmes@35125
|
576 |
(fn vcs => ((), add_vcs verbose vcs thy)))
|
boehmes@35125
|
577 |
|
boehmes@35125
|
578 |
fun parse verbose offsets thy = Scan.pass thy
|
boehmes@33408
|
579 |
(type_decls verbose :|-- (fn tds =>
|
boehmes@33893
|
580 |
fun_decls verbose tds :|-- (fn (unique_axs, fds) =>
|
boehmes@33893
|
581 |
axioms verbose tds fds unique_axs |--
|
boehmes@33408
|
582 |
var_decls tds fds |--
|
boehmes@35125
|
583 |
vcs verbose offsets tds fds)))
|
boehmes@33408
|
584 |
|
boehmes@35125
|
585 |
fun load_b2i verbose offsets path thy = finite (parse verbose offsets thy) path
|
boehmes@33408
|
586 |
|
boehmes@33408
|
587 |
end
|