17 struct |
17 struct |
18 |
18 |
19 (* configurations *) |
19 (* configurations *) |
20 |
20 |
21 val finite_functions = Attrib.setup_config_bool @{binding quickcheck_finite_functions} (K true) |
21 val finite_functions = Attrib.setup_config_bool @{binding quickcheck_finite_functions} (K true) |
22 |
22 val overlord = Attrib.setup_config_bool @{binding quickcheck_narrowing_overlord} (K false) |
23 (* narrowing specific names and types *) |
23 |
|
24 (* partial_term_of instances *) |
|
25 |
|
26 fun mk_partial_term_of (x, T) = |
|
27 Const (@{const_name Quickcheck_Narrowing.partial_term_of_class.partial_term_of}, |
|
28 Term.itselfT T --> @{typ narrowing_term} --> @{typ Code_Evaluation.term}) |
|
29 $ Const ("TYPE", Term.itselfT T) $ x |
|
30 |
|
31 (** formal definition **) |
|
32 |
|
33 fun add_partial_term_of tyco raw_vs thy = |
|
34 let |
|
35 val vs = map (fn (v, _) => (v, @{sort typerep})) raw_vs; |
|
36 val ty = Type (tyco, map TFree vs); |
|
37 val lhs = Const (@{const_name partial_term_of}, |
|
38 Term.itselfT ty --> @{typ narrowing_term} --> @{typ Code_Evaluation.term}) |
|
39 $ Free ("x", Term.itselfT ty) $ Free ("t", @{typ narrowing_term}); |
|
40 val rhs = @{term "undefined :: Code_Evaluation.term"}; |
|
41 val eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs)); |
|
42 fun triv_name_of t = (fst o dest_Free o fst o strip_comb o fst |
|
43 o HOLogic.dest_eq o HOLogic.dest_Trueprop) t ^ "_triv"; |
|
44 in |
|
45 thy |
|
46 |> Class.instantiation ([tyco], vs, @{sort partial_term_of}) |
|
47 |> `(fn lthy => Syntax.check_term lthy eq) |
|
48 |-> (fn eq => Specification.definition (NONE, ((Binding.name (triv_name_of eq), []), eq))) |
|
49 |> snd |
|
50 |> Class.prove_instantiation_exit (K (Class.intro_classes_tac [])) |
|
51 end; |
|
52 |
|
53 fun ensure_partial_term_of (tyco, (raw_vs, _)) thy = |
|
54 let |
|
55 val need_inst = not (can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort partial_term_of}) |
|
56 andalso can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort typerep}; |
|
57 in if need_inst then add_partial_term_of tyco raw_vs thy else thy end; |
|
58 |
|
59 |
|
60 (** code equations for datatypes **) |
|
61 |
|
62 fun mk_partial_term_of_eq thy ty (i, (c, (_, tys))) = |
|
63 let |
|
64 val frees = map Free (Name.names Name.context "a" (map (K @{typ narrowing_term}) tys)) |
|
65 val narrowing_term = @{term "Quickcheck_Narrowing.Ctr"} $ HOLogic.mk_number @{typ code_int} i |
|
66 $ (HOLogic.mk_list @{typ narrowing_term} frees) |
|
67 val rhs = fold (fn u => fn t => @{term "Code_Evaluation.App"} $ t $ u) |
|
68 (map mk_partial_term_of (frees ~~ tys)) |
|
69 (@{term "Code_Evaluation.Const"} $ HOLogic.mk_literal c $ HOLogic.mk_typerep (tys ---> ty)) |
|
70 val insts = |
|
71 map (SOME o Thm.cterm_of thy o map_types Logic.unvarifyT_global o Logic.varify_global) |
|
72 [Free ("ty", Term.itselfT ty), narrowing_term, rhs] |
|
73 val cty = Thm.ctyp_of thy ty; |
|
74 in |
|
75 @{thm partial_term_of_anything} |
|
76 |> Drule.instantiate' [SOME cty] insts |
|
77 |> Thm.varifyT_global |
|
78 end |
|
79 |
|
80 fun add_partial_term_of_code tyco raw_vs raw_cs thy = |
|
81 let |
|
82 val algebra = Sign.classes_of thy; |
|
83 val vs = map (fn (v, sort) => |
|
84 (v, curry (Sorts.inter_sort algebra) @{sort typerep} sort)) raw_vs; |
|
85 val ty = Type (tyco, map TFree vs); |
|
86 val cs = (map o apsnd o apsnd o map o map_atyps) |
|
87 (fn TFree (v, _) => TFree (v, (the o AList.lookup (op =) vs) v)) raw_cs; |
|
88 val const = AxClass.param_of_inst thy (@{const_name partial_term_of}, tyco); |
|
89 val eqs = map_index (mk_partial_term_of_eq thy ty) cs; |
|
90 in |
|
91 thy |
|
92 |> Code.del_eqns const |
|
93 |> fold Code.add_eqn eqs |
|
94 end; |
|
95 |
|
96 fun ensure_partial_term_of_code (tyco, (raw_vs, cs)) thy = |
|
97 let |
|
98 val has_inst = can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort partial_term_of}; |
|
99 in if has_inst then add_partial_term_of_code tyco raw_vs cs thy else thy end; |
|
100 |
|
101 |
|
102 (* narrowing generators *) |
|
103 |
|
104 (** narrowing specific names and types **) |
24 |
105 |
25 exception FUNCTION_TYPE; |
106 exception FUNCTION_TYPE; |
26 |
107 |
27 val narrowingN = "narrowing"; |
108 val narrowingN = "narrowing"; |
28 |
109 |
93 |
174 |
94 (* testing framework *) |
175 (* testing framework *) |
95 |
176 |
96 val target = "Haskell" |
177 val target = "Haskell" |
97 |
178 |
98 (* invocation of Haskell interpreter *) |
179 (** invocation of Haskell interpreter **) |
99 |
180 |
100 val narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs") |
181 val narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs") |
101 |
182 |
102 fun exec verbose code = |
183 fun exec verbose code = |
103 ML_Context.exec (fn () => Secure.use_text ML_Env.local_context (0, "generated code") verbose code) |
184 ML_Context.exec (fn () => Secure.use_text ML_Env.local_context (0, "generated code") verbose code) |
104 |
185 |
|
186 fun with_tmp_dir name f = |
|
187 let |
|
188 val path = Path.append (Path.explode "~/.isabelle") (Path.basic (name ^ serial_string ())) |
|
189 val _ = Isabelle_System.mkdirs path; |
|
190 in Exn.release (Exn.capture f path) end; |
|
191 |
105 fun value ctxt (get, put, put_ml) (code, value) size = |
192 fun value ctxt (get, put, put_ml) (code, value) size = |
106 let |
193 let |
107 val tmp_prefix = "Quickcheck_Narrowing" |
194 val tmp_prefix = "Quickcheck_Narrowing" |
|
195 val with_tmp_dir = if Config.get ctxt overlord |
|
196 then Isabelle_System.with_tmp_dir else Quickcheck_Narrowing.with_tmp_dir |
108 fun run in_path = |
197 fun run in_path = |
109 let |
198 let |
110 val code_file = Path.append in_path (Path.basic "Code.hs") |
199 val code_file = Path.append in_path (Path.basic "Code.hs") |
111 val narrowing_engine_file = Path.append in_path (Path.basic "Narrowing_Engine.hs") |
200 val narrowing_engine_file = Path.append in_path (Path.basic "Narrowing_Engine.hs") |
112 val main_file = Path.append in_path (Path.basic "Main.hs") |
201 val main_file = Path.append in_path (Path.basic "Main.hs") |
125 (space_implode " " (map File.shell_path [code_file, narrowing_engine_file, main_file])) ^ |
214 (space_implode " " (map File.shell_path [code_file, narrowing_engine_file, main_file])) ^ |
126 " -o " ^ executable ^ "; ) && " ^ executable |
215 " -o " ^ executable ^ "; ) && " ^ executable |
127 in |
216 in |
128 bash_output cmd |
217 bash_output cmd |
129 end |
218 end |
130 val result = Isabelle_System.with_tmp_dir tmp_prefix run |
219 val result = with_tmp_dir tmp_prefix run |
131 val output_value = the_default "NONE" |
220 val output_value = the_default "NONE" |
132 (try (snd o split_last o filter_out (fn s => s = "") o split_lines o fst) result) |
221 (try (snd o split_last o filter_out (fn s => s = "") o split_lines o fst) result) |
133 |> translate_string (fn s => if s = "\\" then "\\\\" else s) |
222 |> translate_string (fn s => if s = "\\" then "\\\\" else s) |
134 val ml_code = "\nval _ = Context.set_thread_data (SOME (Context.map_proof (" ^ put_ml |
223 val ml_code = "\nval _ = Context.set_thread_data (SOME (Context.map_proof (" ^ put_ml |
135 ^ " (fn () => " ^ output_value ^ ")) (ML_Context.the_generic_context ())))"; |
224 ^ " (fn () => " ^ output_value ^ ")) (ML_Context.the_generic_context ())))"; |
150 let |
239 let |
151 fun evaluator naming program ((_, vs_ty), t) deps = |
240 fun evaluator naming program ((_, vs_ty), t) deps = |
152 evaluation cookie thy (Code_Target.evaluator thy target naming program deps) (vs_ty, t) args size; |
241 evaluation cookie thy (Code_Target.evaluator thy target naming program deps) (vs_ty, t) args size; |
153 in Exn.release (Code_Thingol.dynamic_value thy (Exn.map_result o postproc) evaluator t) end; |
242 in Exn.release (Code_Thingol.dynamic_value thy (Exn.map_result o postproc) evaluator t) end; |
154 |
243 |
155 (* counterexample generator *) |
244 (** counterexample generator **) |
156 |
245 |
157 structure Counterexample = Proof_Data |
246 structure Counterexample = Proof_Data |
158 ( |
247 ( |
159 type T = unit -> term list option |
248 type T = unit -> term list option |
160 fun init _ () = error "Counterexample" |
249 fun init _ () = error "Counterexample" |
201 thy (Option.map o map) (ensure_testable t'') [] size |
290 thy (Option.map o map) (ensure_testable t'') [] size |
202 in |
291 in |
203 (result, NONE) |
292 (result, NONE) |
204 end; |
293 end; |
205 |
294 |
|
295 (* setup *) |
206 |
296 |
207 val setup = |
297 val setup = |
208 Datatype.interpretation (Quickcheck_Common.ensure_sort_datatype |
298 Code.datatype_interpretation ensure_partial_term_of |
|
299 #> Code.datatype_interpretation ensure_partial_term_of_code |
|
300 #> Datatype.interpretation (Quickcheck_Common.ensure_sort_datatype |
209 (((@{sort typerep}, @{sort term_of}), @{sort narrowing}), instantiate_narrowing_datatype)) |
301 (((@{sort typerep}, @{sort term_of}), @{sort narrowing}), instantiate_narrowing_datatype)) |
210 #> Context.theory_map |
302 #> Context.theory_map |
211 (Quickcheck.add_generator ("narrowing", compile_generator_expr)) |
303 (Quickcheck.add_generator ("narrowing", compile_generator_expr)) |
212 |
304 |
213 end; |
305 end; |