43 structure Code_Runtime : CODE_RUNTIME = |
43 structure Code_Runtime : CODE_RUNTIME = |
44 struct |
44 struct |
45 |
45 |
46 open Basic_Code_Symbol; |
46 open Basic_Code_Symbol; |
47 |
47 |
48 (** computation **) |
48 (** ML compiler as evaluation environment **) |
49 |
49 |
50 (* technical prerequisites *) |
50 (* technical prerequisites *) |
51 |
51 |
52 val this = "Code_Runtime"; |
52 val this = "Code_Runtime"; |
53 val s_truth = Long_Name.append this "truth"; |
53 val s_truth = Long_Name.append this "truth"; |
80 let |
80 let |
81 val code = |
81 val code = |
82 prelude ^ "\nval _ = Context.put_generic_context (SOME (Context.map_proof (" ^ |
82 prelude ^ "\nval _ = Context.put_generic_context (SOME (Context.map_proof (" ^ |
83 put_ml ^ " (fn () => " ^ value ^ ")) (Context.the_generic_context ())))"; |
83 put_ml ^ " (fn () => " ^ value ^ ")) (Context.the_generic_context ())))"; |
84 val ctxt' = ctxt |
84 val ctxt' = ctxt |
85 |> put (fn () => error ("Bad computation for " ^ quote put_ml)) |
85 |> put (fn () => error ("Bad compilation for " ^ quote put_ml)) |
86 |> Context.proof_map (compile_ML false code); |
86 |> Context.proof_map (compile_ML false code); |
87 val computator = get ctxt'; |
87 val computator = get ctxt'; |
88 in Code_Preproc.timed_exec "running ML" computator ctxt' end; |
88 in Code_Preproc.timed_exec "running ML" computator ctxt' end; |
89 |
89 |
90 |
90 |
91 (* computation as evaluation into ML language values *) |
91 (* evaluation into ML language values *) |
92 |
92 |
93 type 'a cookie = (Proof.context -> unit -> 'a) * ((unit -> 'a) -> Proof.context -> Proof.context) * string; |
93 type 'a cookie = (Proof.context -> unit -> 'a) * ((unit -> 'a) -> Proof.context -> Proof.context) * string; |
94 |
94 |
95 fun reject_vars ctxt t = |
95 fun reject_vars ctxt t = |
96 ((Sign.no_frees ctxt o Sign.no_vars ctxt o map_types (K dummyT)) t; t); |
96 ((Sign.no_frees ctxt o Sign.no_vars ctxt o map_types (K dummyT)) t; t); |
97 |
97 |
98 fun build_computation_text ctxt some_target program consts = |
98 fun build_compilation_text ctxt some_target program consts = |
99 Code_Target.computation_text ctxt (the_default target some_target) program consts false |
99 Code_Target.compilation_text ctxt (the_default target some_target) program consts false |
100 #>> (fn ml_modules => space_implode "\n\n" (map snd ml_modules)); |
100 #>> (fn ml_modules => space_implode "\n\n" (map snd ml_modules)); |
101 |
101 |
102 fun run_computation_text cookie ctxt comp vs_t args = |
102 fun run_compilation_text cookie ctxt comp vs_t args = |
103 let |
103 let |
104 val (program_code, value_name) = comp vs_t; |
104 val (program_code, value_name) = comp vs_t; |
105 val value_code = space_implode " " |
105 val value_code = space_implode " " |
106 (value_name :: "()" :: map (enclose "(" ")") args); |
106 (value_name :: "()" :: map (enclose "(" ")") args); |
107 in Exn.interruptible_capture (value ctxt cookie) (program_code, value_code) end; |
107 in Exn.interruptible_capture (value ctxt cookie) (program_code, value_code) end; |
116 val _ = reject_vars ctxt t; |
116 val _ = reject_vars ctxt t; |
117 val _ = if Config.get ctxt trace |
117 val _ = if Config.get ctxt trace |
118 then tracing ("Evaluation of term " ^ quote (Syntax.string_of_term ctxt t)) |
118 then tracing ("Evaluation of term " ^ quote (Syntax.string_of_term ctxt t)) |
119 else () |
119 else () |
120 fun comp program _ vs_ty_t deps = |
120 fun comp program _ vs_ty_t deps = |
121 run_computation_text cookie ctxt (build_computation_text ctxt some_target program deps) vs_ty_t args; |
121 run_compilation_text cookie ctxt (build_compilation_text ctxt some_target program deps) vs_ty_t args; |
122 in Code_Thingol.dynamic_value ctxt (Exn.map_res o postproc) comp t end; |
122 in Code_Thingol.dynamic_value ctxt (Exn.map_res o postproc) comp t end; |
123 |
123 |
124 fun dynamic_value_strict cookie ctxt some_target postproc t args = |
124 fun dynamic_value_strict cookie ctxt some_target postproc t args = |
125 Exn.release (dynamic_value_exn cookie ctxt some_target postproc t args); |
125 Exn.release (dynamic_value_exn cookie ctxt some_target postproc t args); |
126 |
126 |
127 fun dynamic_value cookie ctxt some_target postproc t args = |
127 fun dynamic_value cookie ctxt some_target postproc t args = |
128 partiality_as_none (dynamic_value_exn cookie ctxt some_target postproc t args); |
128 partiality_as_none (dynamic_value_exn cookie ctxt some_target postproc t args); |
129 |
129 |
130 fun static_value_exn cookie { ctxt, target, lift_postproc, consts } = |
130 fun static_value_exn cookie { ctxt, target, lift_postproc, consts } = |
131 let |
131 let |
132 fun computation' { program, deps } = |
132 fun compilation' { program, deps } = |
133 let |
133 let |
134 val computation'' = run_computation_text cookie ctxt |
134 val compilation'' = run_compilation_text cookie ctxt |
135 (build_computation_text ctxt target program (map Constant deps)); |
135 (build_compilation_text ctxt target program (map Constant deps)); |
136 in fn _ => fn _ => fn vs_ty_t => fn _ => computation'' vs_ty_t [] end; |
136 in fn _ => fn _ => fn vs_ty_t => fn _ => compilation'' vs_ty_t [] end; |
137 val computation = Code_Thingol.static_value { ctxt = ctxt, |
137 val compilation = Code_Thingol.static_value { ctxt = ctxt, |
138 lift_postproc = Exn.map_res o lift_postproc, consts = consts } |
138 lift_postproc = Exn.map_res o lift_postproc, consts = consts } |
139 computation'; |
139 compilation'; |
140 in fn ctxt' => computation ctxt' o reject_vars ctxt' end; |
140 in fn ctxt' => compilation ctxt' o reject_vars ctxt' end; |
141 |
141 |
142 fun static_value_strict cookie x = Exn.release oo static_value_exn cookie x; |
142 fun static_value_strict cookie x = Exn.release oo static_value_exn cookie x; |
143 |
143 |
144 fun static_value cookie x = partiality_as_none oo static_value_exn cookie x; |
144 fun static_value cookie x = partiality_as_none oo static_value_exn cookie x; |
145 |
145 |
164 val t = Thm.term_of ct; |
164 val t = Thm.term_of ct; |
165 val _ = if fastype_of t <> propT |
165 val _ = if fastype_of t <> propT |
166 then error ("Not a proposition: " ^ Syntax.string_of_term ctxt t) |
166 then error ("Not a proposition: " ^ Syntax.string_of_term ctxt t) |
167 else (); |
167 else (); |
168 val iff = Thm.cterm_of ctxt (Term.Const (@{const_name Pure.eq}, propT --> propT --> propT)); |
168 val iff = Thm.cterm_of ctxt (Term.Const (@{const_name Pure.eq}, propT --> propT --> propT)); |
169 val result = case partiality_as_none (run_computation_text truth_cookie ctxt evaluator vs_t []) |
169 val result = case partiality_as_none (run_compilation_text truth_cookie ctxt evaluator vs_t []) |
170 of SOME Holds => true |
170 of SOME Holds => true |
171 | _ => false; |
171 | _ => false; |
172 in |
172 in |
173 Thm.mk_binop iff ct (if result then @{cprop "PROP Code_Generator.holds"} else ct) |
173 Thm.mk_binop iff ct (if result then @{cprop "PROP Code_Generator.holds"} else ct) |
174 end; |
174 end; |
182 |
182 |
183 in |
183 in |
184 |
184 |
185 fun dynamic_holds_conv ctxt = Code_Thingol.dynamic_conv ctxt |
185 fun dynamic_holds_conv ctxt = Code_Thingol.dynamic_conv ctxt |
186 (fn program => fn vs_t => fn deps => |
186 (fn program => fn vs_t => fn deps => |
187 check_holds_oracle ctxt (build_computation_text ctxt NONE program deps) vs_t) |
187 check_holds_oracle ctxt (build_compilation_text ctxt NONE program deps) vs_t) |
188 o reject_vars ctxt; |
188 o reject_vars ctxt; |
189 |
189 |
190 fun static_holds_conv (ctxt_consts as { ctxt, ... }) = |
190 fun static_holds_conv (ctxt_consts as { ctxt, ... }) = |
191 Code_Thingol.static_conv_thingol ctxt_consts (fn { program, deps } => fn ctxt' => fn vs_t => |
191 Code_Thingol.static_conv_thingol ctxt_consts (fn { program, deps } => fn ctxt' => fn vs_t => |
192 K (check_holds_oracle ctxt' (build_computation_text ctxt NONE program (map Constant deps)) vs_t o reject_vars ctxt')); |
192 K (check_holds_oracle ctxt' (build_compilation_text ctxt NONE program (map Constant deps)) vs_t o reject_vars ctxt')); |
193 |
193 |
194 end; (*local*) |
194 end; (*local*) |
195 |
195 |
196 |
196 |
197 (** computations -- experimental! **) |
197 (** generator for computations -- partial implementations of the universal morphism from Isabelle to ML terms **) |
198 |
198 |
199 fun monomorphic T = fold_atyps ((K o K) false) T true; |
199 (* auxiliary *) |
|
200 |
|
201 val generated_computationN = "Generated_Computation"; |
|
202 |
|
203 |
|
204 (* possible type signatures of constants *) |
200 |
205 |
201 fun typ_signatures_for T = |
206 fun typ_signatures_for T = |
202 let |
207 let |
203 val (Ts, T') = strip_type T; |
208 val (Ts, T') = strip_type T; |
204 in map_range (fn n => (drop n Ts ---> T', take n Ts)) (length Ts + 1) end; |
209 in map_range (fn n => (drop n Ts ---> T', take n Ts)) (length Ts + 1) end; |
211 in |
216 in |
212 Typtab.empty |
217 Typtab.empty |
213 |> fold add cTs |
218 |> fold add cTs |
214 |> Typtab.lookup_list |
219 |> Typtab.lookup_list |
215 end; |
220 end; |
|
221 |
|
222 |
|
223 (* name mangling *) |
|
224 |
|
225 local |
|
226 |
|
227 fun tycos_of (Type (tyco, Ts)) = maps tycos_of Ts @ [tyco] |
|
228 | tycos_of _ = []; |
|
229 |
|
230 val ml_name_of = Name.desymbolize NONE o Long_Name.base_name; |
|
231 |
|
232 in |
|
233 |
|
234 fun of_term_for_typ Ts = |
|
235 let |
|
236 val names = Ts |
|
237 |> map (suffix "_of_term" o space_implode "_" o map ml_name_of o tycos_of) |
|
238 |> Name.variant_list []; |
|
239 in the o AList.lookup (op =) (Ts ~~ names) end; |
|
240 |
|
241 fun eval_for_const ctxt cTs = |
|
242 let |
|
243 fun symbol_list (c, T) = c :: maps tycos_of (Sign.const_typargs (Proof_Context.theory_of ctxt) (c, T)) |
|
244 val names = cTs |
|
245 |> map (prefix "eval_" o space_implode "_" o map ml_name_of o symbol_list) |
|
246 |> Name.variant_list []; |
|
247 in the o AList.lookup (op =) (cTs ~~ names) end; |
|
248 |
|
249 end; |
|
250 |
|
251 |
|
252 (* checks for input terms *) |
|
253 |
|
254 fun monomorphic T = fold_atyps ((K o K) false) T true; |
|
255 |
|
256 fun check_typ ctxt T t = |
|
257 Syntax.check_term ctxt (Type.constraint T t); |
|
258 |
|
259 fun check_computation_input ctxt cTs t = |
|
260 let |
|
261 fun check t = check_comb (strip_comb t) |
|
262 and check_comb (t as Abs _, _) = |
|
263 error ("Bad term, contains abstraction: " ^ Syntax.string_of_term ctxt t) |
|
264 | check_comb (t as Const (cT as (c, T)), ts) = |
|
265 let |
|
266 val _ = if not (member (op =) cTs cT) |
|
267 then error ("Bad term, computation cannot proceed on constant " ^ Syntax.string_of_term ctxt t) |
|
268 else (); |
|
269 val _ = if not (monomorphic T) |
|
270 then error ("Bad term, contains polymorphic constant " ^ Syntax.string_of_term ctxt t) |
|
271 else (); |
|
272 val _ = map check ts; |
|
273 in () end; |
|
274 val _ = check t; |
|
275 in t end; |
|
276 |
|
277 |
|
278 (* code generation for of the universal morphism *) |
216 |
279 |
217 fun print_of_term_funs { typ_sign_for, eval_for_const, of_term_for_typ } Ts = |
280 fun print_of_term_funs { typ_sign_for, eval_for_const, of_term_for_typ } Ts = |
218 let |
281 let |
219 val var_names = map_range (fn n => "t" ^ string_of_int (n + 1)); |
282 val var_names = map_range (fn n => "t" ^ string_of_int (n + 1)); |
220 fun print_lhs c xs = "Const (" ^ quote c ^ ", _)" |
283 fun print_lhs c xs = "Const (" ^ quote c ^ ", _)" |
240 map print_eqs Ts |
303 map print_eqs Ts |
241 |> space_implode "\nand " |
304 |> space_implode "\nand " |
242 |> prefix "fun " |
305 |> prefix "fun " |
243 end; |
306 end; |
244 |
307 |
245 local |
|
246 |
|
247 fun tycos_of (Type (tyco, Ts)) = maps tycos_of Ts @ [tyco] |
|
248 | tycos_of _ = []; |
|
249 |
|
250 val ml_name_of = Name.desymbolize NONE o Long_Name.base_name; |
|
251 |
|
252 in |
|
253 |
|
254 fun of_term_for_typ Ts = |
|
255 let |
|
256 val names = Ts |
|
257 |> map (suffix "_of_term" o space_implode "_" o map ml_name_of o tycos_of) |
|
258 |> Name.variant_list []; |
|
259 in the o AList.lookup (op =) (Ts ~~ names) end; |
|
260 |
|
261 fun eval_for_const ctxt cTs = |
|
262 let |
|
263 fun symbol_list (c, T) = c :: maps tycos_of (Sign.const_typargs (Proof_Context.theory_of ctxt) (c, T)) |
|
264 val names = cTs |
|
265 |> map (prefix "eval_" o space_implode "_" o map ml_name_of o symbol_list) |
|
266 |> Name.variant_list []; |
|
267 in the o AList.lookup (op =) (cTs ~~ names) end; |
|
268 |
|
269 end; |
|
270 |
|
271 val generated_computationN = "Generated_Computation"; |
|
272 |
|
273 fun print_computation_code ctxt compiled_value requested_Ts cTs = |
308 fun print_computation_code ctxt compiled_value requested_Ts cTs = |
274 let |
309 let |
275 val proper_cTs = map_filter I cTs; |
310 val proper_cTs = map_filter I cTs; |
276 val typ_sign_for = typ_signatures proper_cTs; |
311 val typ_sign_for = typ_signatures proper_cTs; |
277 fun add_typ T Ts = |
312 fun add_typ T Ts = |
305 "", |
340 "", |
306 "end" |
341 "end" |
307 ], map (prefix (generated_computationN ^ ".") o of_term_for_typ') requested_Ts) |
342 ], map (prefix (generated_computationN ^ ".") o of_term_for_typ') requested_Ts) |
308 end; |
343 end; |
309 |
344 |
310 fun check_typ ctxt T t = |
345 fun mount_computation ctxt cTs T raw_computation lift_postproc = |
311 Syntax.check_term ctxt (Type.constraint T t); |
346 Code_Preproc.static_value { ctxt = ctxt, lift_postproc = lift_postproc, consts = [] } |
312 |
347 (fn _ => fn ctxt' => |
313 fun check_computation_input ctxt cTs t = |
348 check_typ ctxt' T |
314 let |
349 #> reject_vars ctxt' |
315 fun check t = check_comb (strip_comb t) |
350 #> check_computation_input ctxt' cTs |
316 and check_comb (t as Abs _, _) = |
351 #> raw_computation); |
317 error ("Bad term, contains abstraction: " ^ Syntax.string_of_term ctxt t) |
|
318 | check_comb (t as Const (cT as (c, T)), ts) = |
|
319 let |
|
320 val _ = if not (member (op =) cTs cT) |
|
321 then error ("Bad term, computation cannot proceed on constant " ^ Syntax.string_of_term ctxt t) |
|
322 else (); |
|
323 val _ = if not (monomorphic T) |
|
324 then error ("Bad term, contains polymorphic constant " ^ Syntax.string_of_term ctxt t) |
|
325 else (); |
|
326 val _ = map check ts; |
|
327 in () end; |
|
328 val _ = check t; |
|
329 in t end; |
|
330 |
352 |
331 fun compile_computation cookie ctxt T program evals vs_ty_evals deps = |
353 fun compile_computation cookie ctxt T program evals vs_ty_evals deps = |
332 let |
354 let |
333 fun the_const (Const cT) = cT |
355 fun the_const (Const cT) = cT |
334 | the_const t = error ("No constant after preprocessing: " ^ Syntax.string_of_term ctxt t) |
356 | the_const t = error ("No constant after preprocessing: " ^ Syntax.string_of_term ctxt t) |
338 val cTs = fold_rev (fn cT => fn cTs => |
360 val cTs = fold_rev (fn cT => fn cTs => |
339 (if member (op =) cTs (SOME cT) then NONE else SOME cT) :: cTs) raw_cTs []; |
361 (if member (op =) cTs (SOME cT) then NONE else SOME cT) :: cTs) raw_cTs []; |
340 fun comp' vs_ty_evals = |
362 fun comp' vs_ty_evals = |
341 let |
363 let |
342 val (generated_code, compiled_value) = |
364 val (generated_code, compiled_value) = |
343 build_computation_text ctxt NONE program deps vs_ty_evals; |
365 build_compilation_text ctxt NONE program deps vs_ty_evals; |
344 val (of_term_code, [of_term]) = print_computation_code ctxt compiled_value [T] cTs; |
366 val (of_term_code, [of_term]) = print_computation_code ctxt compiled_value [T] cTs; |
345 in |
367 in |
346 (generated_code ^ "\n" ^ of_term_code, |
368 (generated_code ^ "\n" ^ of_term_code, |
347 enclose "(" ")" ("fn () => " ^ of_term)) |
369 enclose "(" ")" ("fn () => " ^ of_term)) |
348 end; |
370 end; |
349 val compiled_computation = |
371 val compiled_computation = |
350 Exn.release (run_computation_text cookie ctxt comp' vs_ty_evals []); |
372 Exn.release (run_compilation_text cookie ctxt comp' vs_ty_evals []); |
351 in fn ctxt' => |
373 in (map_filter I cTs, compiled_computation) end; |
352 check_typ ctxt' T |
|
353 #> reject_vars ctxt' |
|
354 #> check_computation_input ctxt (map_filter I cTs) |
|
355 #> compiled_computation |
|
356 end; |
|
357 |
374 |
358 fun experimental_computation cookie { ctxt, lift_postproc, terms = ts, T } = |
375 fun experimental_computation cookie { ctxt, lift_postproc, terms = ts, T } = |
359 let |
376 let |
360 val _ = if not (monomorphic T) |
377 val _ = if not (monomorphic T) |
361 then error ("Polymorphic type: " ^ Syntax.string_of_typ ctxt T) |
378 then error ("Polymorphic type: " ^ Syntax.string_of_typ ctxt T) |
363 val cTs = (fold o fold_aterms) |
380 val cTs = (fold o fold_aterms) |
364 (fn (t as Const (cT as (_, T))) => |
381 (fn (t as Const (cT as (_, T))) => |
365 if not (monomorphic T) then error ("Polymorphic constant:" ^ Syntax.string_of_term ctxt t) |
382 if not (monomorphic T) then error ("Polymorphic constant:" ^ Syntax.string_of_term ctxt t) |
366 else insert (op =) cT | _ => I) ts []; |
383 else insert (op =) cT | _ => I) ts []; |
367 val evals = Abs ("eval", map snd cTs ---> TFree (Name.aT, []), list_comb (Bound 0, map Const cTs)); |
384 val evals = Abs ("eval", map snd cTs ---> TFree (Name.aT, []), list_comb (Bound 0, map Const cTs)); |
368 val computation = Code_Thingol.dynamic_value ctxt |
385 val (cTs, raw_computation) = Code_Thingol.dynamic_value ctxt |
369 (K I) (compile_computation cookie ctxt T) evals; |
386 (K I) (compile_computation cookie ctxt T) evals; |
370 in |
387 in |
371 Code_Preproc.static_value { ctxt = ctxt, lift_postproc = lift_postproc, consts = [] } |
388 mount_computation ctxt cTs T raw_computation lift_postproc |
372 (K computation) |
|
373 end; |
389 end; |
374 |
390 |
375 |
391 |
376 (** code antiquotation **) |
392 (** code antiquotation **) |
377 |
393 |
378 fun evaluation_code ctxt module_name program tycos consts = |
394 fun runtime_code ctxt module_name program tycos consts = |
379 let |
395 let |
380 val thy = Proof_Context.theory_of ctxt; |
396 val thy = Proof_Context.theory_of ctxt; |
381 val (ml_modules, target_names) = |
397 val (ml_modules, target_names) = |
382 Code_Target.produce_code_for ctxt |
398 Code_Target.produce_code_for ctxt |
383 target NONE module_name [] program false (map Constant consts @ map Type_Constructor tycos); |
399 target NONE module_name [] program false (map Constant consts @ map Type_Constructor tycos); |
420 |
436 |
421 fun lazy_code ctxt consts = Lazy.lazy (fn () => |
437 fun lazy_code ctxt consts = Lazy.lazy (fn () => |
422 let |
438 let |
423 val program = Code_Thingol.consts_program ctxt consts; |
439 val program = Code_Thingol.consts_program ctxt consts; |
424 val (code, (_, consts_map)) = |
440 val (code, (_, consts_map)) = |
425 evaluation_code ctxt Code_Target.generatedN program [] consts |
441 runtime_code ctxt Code_Target.generatedN program [] consts |
426 in { code = code, consts_map = consts_map } end); |
442 in { code = code, consts_map = consts_map } end); |
427 |
443 |
428 fun register_const const ctxt = |
444 fun register_const const ctxt = |
429 let |
445 let |
430 val consts = insert (op =) const ((#named_consts o Code_Antiq_Data.get) ctxt); |
446 val consts = insert (op =) const ((#named_consts o Code_Antiq_Data.get) ctxt); |
530 val (tycos, constrs) = map_split (uncurry (check_datatype thy)) datatypes |
546 val (tycos, constrs) = map_split (uncurry (check_datatype thy)) datatypes |
531 |> apsnd flat; |
547 |> apsnd flat; |
532 val functions = map (prep_const thy) raw_functions; |
548 val functions = map (prep_const thy) raw_functions; |
533 val consts = constrs @ functions; |
549 val consts = constrs @ functions; |
534 val program = Code_Thingol.consts_program ctxt consts; |
550 val program = Code_Thingol.consts_program ctxt consts; |
535 val result = evaluation_code ctxt module_name program tycos consts |
551 val result = runtime_code ctxt module_name program tycos consts |
536 |> (apsnd o apsnd) (chop (length constrs)); |
552 |> (apsnd o apsnd) (chop (length constrs)); |
537 in |
553 in |
538 thy |
554 thy |
539 |> process_reflection result module_name some_file |
555 |> process_reflection result module_name some_file |
540 end; |
556 end; |