fun reject_vars ctxt t =
((Sign.no_frees ctxt o Sign.no_vars ctxt o map_types (K dummyT)) t; t);
fun build_compilation_text ctxt some_target program consts =
Code_Target.compilation_text ctxt (the_default target some_target) program consts false
#>> (fn ml_modules => space_implode "\n\n" (map (Bytes.content o snd) ml_modules));
fun run_compilation_text cookie ctxt comp vs_t args = let val (program_code, value_name) = comp vs_t; val value_code = implode_space
(value_name :: "()" :: map (enclose "("")") args); in Exn.result (value ctxt cookie) (program_code, value_code) end;
fun partiality_as_none e = SOME (Exn.release e) handle General.Match => NONE
| General.Bind => NONE
| General.Fail _ => NONE;
fun dynamic_value_exn cookie ctxt some_target postproc t args = let val _ = reject_vars ctxt t; val _ = if Config.get ctxt trace then tracing ("Evaluation of term " ^ quote (Syntax.string_of_term ctxt t)) else () fun comp program _ vs_ty_t deps =
run_compilation_text cookie ctxt (build_compilation_text ctxt some_target program deps) vs_ty_t args; in Code_Thingol.dynamic_value ctxt (Exn.map_res o postproc) comp t end;
fun dynamic_value_strict cookie ctxt some_target postproc t args =
Exn.release (dynamic_value_exn cookie ctxt some_target postproc t args);
fun dynamic_value cookie ctxt some_target postproc t args =
partiality_as_none (dynamic_value_exn cookie ctxt some_target postproc t args);
(* evaluation for truth or nothing *)
structure Truth_Result = Proof_Data
( type T = unit -> truth; val empty: T = fn () => raise Fail "Truth_Result"; fun init _ = empty;
); val put_truth = Truth_Result.put; val truth_cookie = (Truth_Result.get, put_truth, prefix_this "put_truth");
local
val reject_vars = fn ctxt => tap (reject_vars ctxt o Thm.term_of);
fun check_holds ctxt evaluator vs_t ct = let val t = Thm.term_of ct; val _ = if fastype_of t <> propT then error ("Not a proposition: " ^ Syntax.string_of_term ctxt t) else (); val iff = Thm.cterm_of ctxt (Term.Const (\<^const_name>\<open>Pure.eq\<close>, propT --> propT --> propT)); val result = case partiality_as_none (run_compilation_text truth_cookie ctxt evaluator vs_t []) of SOME Holds => true
| _ => false; in
Thm.mk_binop iff ct (if result then \<^cprop>\<open>PROP Code_Generator.holds\<close> else ct) end;
val ml_name_of = Name.desymbolize NONE o Long_Name.base_name;
in
val covered_constsN = "covered_consts";
fun of_term_for_typ Ts = let val names = Ts
|> map (suffix "_of_term" o space_implode "_" o map ml_name_of o tycos_of)
|> Name.variant_list []; in the o AList.lookup (op =) (Ts ~~ names) end;
fun eval_for_const ctxt cTs = let fun symbol_list (c, T) = c :: maps tycos_of (Sign.const_typargs (Proof_Context.theory_of ctxt) (c, T)) val names = cTs
|> map (prefix "eval_" o space_implode "_" o map ml_name_of o symbol_list)
|> Name.variant_list []; in the o AList.lookup (op =) (cTs ~~ names) end;
end;
(* checks for input terms *)
fun monomorphic T = fold_atyps ((K o K) false) T true;
fun check_typ ctxt T t =
Syntax.check_term ctxt (Type.constraint T t);
fun check_computation_input ctxt cTs t = let fun check t = check_comb (strip_comb t) and check_comb (t as Abs _, _) =
error ("Bad term, contains abstraction: " ^ Syntax.string_of_term ctxt t)
| check_comb (t as Const (cT as (c, T)), ts) = let val _ = ifnot (member (op =) cTs cT) then error ("Bad term, computation cannot proceed on constant " ^ Syntax.string_of_term ctxt t) else (); val _ = ifnot (monomorphic T) then error ("Bad term, contains polymorphic constant " ^ Syntax.string_of_term ctxt t) else (); val _ = map check ts; in () end; val _ = check t; in t end;
(* code generation for of the universal morphism *)
val print_const = ML_Syntax.print_pair ML_Syntax.print_string ML_Syntax.print_typ;
fun print_of_term_funs { typ_signatures_for, eval_for_const, of_term_for_typ } Ts = let val var_names = map_range (fn n => "t" ^ string_of_int (n + 1)); fun print_lhs c xs = "Const (" ^ quote c ^ ", _)"
|> fold (fn x => fn s => s ^ " $ " ^ x) xs
|> enclose "("")"; fun print_rhs c Ts T xs = eval_for_const (c, Ts ---> T)
|> fold2 (fn T' => fn x => fn s =>
s ^ (" (" ^ of_term_for_typ T' ^ " " ^ x ^ ")")) Ts xs fun print_eq T (c, Ts) = let val xs = var_names (length Ts); in print_lhs c xs ^ " = " ^ print_rhs c Ts T xs end; fun print_eqs T = let val typ_signs = typ_signatures_for T; val name = of_term_for_typ T; in map (print_eq T) typ_signs
|> map (prefix (name ^ " "))
|> space_implode "\n | " end; in map print_eqs Ts
|> space_implode "\nand "
|> prefix "fun " end;
fun print_computation_code ctxt compiled_value [] requested_Ts = if null requested_Ts then ("", []) else error ("No equation available for requested type "
^ Syntax.string_of_typ ctxt (hd requested_Ts))
| print_computation_code ctxt compiled_value cTs requested_Ts = let val proper_cTs = map_filter I cTs; val typ_signatures_for = typ_signatures proper_cTs; fun add_typ T Ts = if member (op =) Ts T then Ts elsecase typ_signatures_for T of
[] => error ("No equation available for requested type "
^ Syntax.string_of_typ ctxt T)
| typ_signs =>
Ts
|> cons T
|> fold (fold add_typ o snd) typ_signs; val required_Ts = build (fold add_typ requested_Ts); val of_term_for_typ' = of_term_for_typ required_Ts; val eval_for_const' = eval_for_const ctxt proper_cTs; val eval_for_const'' = the_default "_" o Option.map eval_for_const'; val eval_tuple = enclose "("")" (commas (map eval_for_const' proper_cTs)); fun mk_abs s = "fn " ^ s ^ " => "; val eval_abs = space_implode ""
(map (mk_abs o eval_for_const'') cTs); val of_term_code = print_of_term_funs {
typ_signatures_for = typ_signatures_for,
eval_for_const = eval_for_const',
of_term_for_typ = of_term_for_typ' } required_Ts; val of_term_names = map (Long_Name.append generated_computationN
o of_term_for_typ') requested_Ts; in
cat_lines [ "structure " ^ generated_computationN ^ " =", "struct", "", "val " ^ covered_constsN ^ " = " ^ ML_Syntax.print_list print_const proper_cTs ^ ";", "", "val " ^ eval_tuple ^ " = " ^ compiled_value ^ " ()", " (" ^ eval_abs, " " ^ eval_tuple ^ ");", "",
of_term_code, "", "end"
] |> rpair of_term_names end;
(* dedicated preprocessor for computations *)
structure Computation_Preproc_Data = Theory_Data
( type T = thm list; val empty = []; val merge = Library.merge Thm.eq_thm_prop;
);
local
fun add thm thy = let val thms = Simplifier.mksimps (Proof_Context.init_global thy) thm; in
thy
|> Computation_Preproc_Data.map (fold (insert Thm.eq_thm_prop o Thm.trim_context) thms) end;
fun get ctxt =
Computation_Preproc_Data.get (Proof_Context.theory_of ctxt)
|> map (Thm.transfer' ctxt)
in
fun preprocess_conv { ctxt } = let val rules = get ctxt; in fn ctxt' => Simplifier.rewrite_wrt ctxt'false rules end;
fun preprocess_term { ctxt } = let val rules = map (Logic.dest_equals o Thm.plain_prop_of) (get ctxt); in fn ctxt' => Pattern.rewrite_term (Proof_Context.theory_of ctxt') rules [] end;
val _ = Theory.setup
(Attrib.setup \<^binding>\<open>code_computation_unfold\<close>
(Scan.succeed (Thm.declaration_attribute (fn thm => Context.mapping (add thm) I))) "preprocessing equations for computation");
end;
(* mounting computations *)
fun prechecked_computation T raw_computation ctxt =
check_typ ctxt T
#> reject_vars ctxt
#> raw_computation ctxt;
fun prechecked_conv T raw_conv ctxt =
tap (check_typ ctxt T o reject_vars ctxt o Thm.term_of)
#> raw_conv ctxt;
fun mount_computation ctxt cTs T raw_computation lift_postproc = let val preprocess = preprocess_term { ctxt = ctxt }; val computation = prechecked_computation T (Code_Preproc.static_value
{ ctxt = ctxt, lift_postproc = lift_postproc, consts = [] }
(K (checked_computation cTs raw_computation))); in fn ctxt' => preprocess ctxt' #> computation ctxt' end;
fun mount_computation_conv ctxt cTs T raw_computation conv = let val preprocess = preprocess_conv { ctxt = ctxt }; val computation_conv = prechecked_conv T (Code_Preproc.static_conv
{ ctxt = ctxt, consts = [] }
(K (fn ctxt' => fn t => case checked_computation cTs raw_computation ctxt' t of
SOME x => conv ctxt' x
| NONE => Conv.all_conv))); in fn ctxt' => preprocess ctxt' then_conv computation_conv ctxt' end;
val (_, holds_oracle) = Theory.setup_result (Thm.add_oracle (\<^binding>\<open>holds\<close>, holds));
in
fun mount_computation_check ctxt cTs raw_computation =
mount_computation_conv ctxt cTs \<^typ>\<open>prop\<close> raw_computation
((K o K) holds_oracle);
end;
(** variants of universal runtime code generation **)
(*FIXME consolidate variants*)
fun runtime_code'' ctxt module_name program tycos consts = let val thy = Proof_Context.theory_of ctxt; val (ml_modules, target_names) =
Code_Target.produce_code_for ctxt
target module_name NONE [] program false (map Constant consts @ map Type_Constructor tycos); val ml_code = space_implode "\n\n" (map (Bytes.content o snd) ml_modules); val (consts', tycos') = chop (length consts) target_names; val consts_map = map2 (fn const =>
fn NONE =>
error ("Constant " ^ (quote o Code.string_of_const thy) const ^ "\nhas a user-defined serialization")
| SOME const' => (const, const')) consts consts' val tycos_map = map2 (fn tyco =>
fn NONE =>
error ("Type " ^ quote (Proof_Context.markup_type ctxt tyco) ^ "\nhas a user-defined serialization")
| SOME tyco' => (tyco, tyco')) tycos tycos'; in (ml_code, (tycos_map, consts_map)) end;
fun runtime_code' ctxt some_module_name named_tycos named_consts computation_Ts program evals vs_ty_evals deps = let val thy = Proof_Context.theory_of ctxt; fun the_const (Const cT) = cT
| the_const t = error ("No constant after preprocessing: " ^ Syntax.string_of_term ctxt t) val raw_computation_cTs = case evals of
Abs (_, _, t) => (map the_const o snd o strip_comb) t
| _ => error ("Bad term after preprocessing: " ^ Syntax.string_of_term ctxt evals); val computation_cTs = fold_rev (fn cT => fn cTs =>
(if member (op =) cTs (SOME cT) then NONE else SOME cT) :: cTs) raw_computation_cTs []; val consts' = fold (fn NONE => I | SOME (c, _) => insert (op =) c)
computation_cTs named_consts; val program' = Code_Thingol.consts_program ctxt consts'; (*FIXME insufficient interfaces require double invocation of code generator*) val program'' = Code_Symbol.Graph.merge (K true) (program, program'); val ((ml_modules, compiled_value), deresolve) =
Code_Target.compilation_text' ctxt target some_module_name program''
(map Code_Symbol.Type_Constructor named_tycos @ map Code_Symbol.Constant consts' @ deps) true vs_ty_evals; (*FIXME constrain signature*) fun deresolve_tyco tyco = case (deresolve o Code_Symbol.Type_Constructor) tyco of
NONE => error ("Type " ^ quote (Proof_Context.markup_type ctxt tyco) ^ "\nhas a user-defined serialization")
| SOME c' => c'; fun deresolve_const c = case (deresolve o Code_Symbol.Constant) c of
NONE => error ("Constant " ^ (quote o Code.string_of_const thy) c ^ "\nhas a user-defined serialization")
| SOME c' => c'; val tyco_names = map deresolve_tyco named_tycos; val const_names = map deresolve_const named_consts; val generated_code = space_implode "\n\n" (map (Bytes.content o snd) ml_modules); val (of_term_code, of_term_names) =
print_computation_code ctxt compiled_value computation_cTs computation_Ts; val compiled_computation = generated_code ^ "\n" ^ of_term_code; in
compiled_computation
|> rpair { tyco_map = named_tycos ~~ tyco_names,
const_map = named_consts ~~ const_names,
of_term_map = computation_Ts ~~ of_term_names } end;
fun funs_of_maps { tyco_map, const_map, of_term_map } =
{ name_for_tyco = the o AList.lookup (op =) tyco_map,
name_for_const = the o AList.lookup (op =) const_map,
of_term_for_typ = the o AList.lookup (op =) of_term_map };
fun runtime_code ctxt some_module_name named_tycos named_consts computation_Ts program evals vs_ty_evals deps =
runtime_code' ctxt some_module_name named_tycos named_consts computation_Ts program evals vs_ty_evals deps
||> funs_of_maps;
(** code and computation antiquotations **)
local
val mount_computationN = prefix_this "mount_computation"; val mount_computation_convN = prefix_this "mount_computation_conv"; val mount_computation_checkN = prefix_this "mount_computation_check";
fun register_computation cTs T =
register { named_consts = [],
computation_Ts = [T],
computation_cTs = cTs };
funprint body_code_for ctxt ctxt' = let val position_index = current_position_index ctxt; val (code, name_ofs) = (Lazy.force o #generated_code o Code_Antiq_Data.get) ctxt'; val context_code = if position_index = 0 then code else""; val body_code = body_code_for name_ofs (ML_Context.struct_name ctxt'); in (context_code, body_code) end;
fun add_all_constrs ctxt (dT as Type (tyco, Ts)) = case Code.get_type (Proof_Context.theory_of ctxt) tyco of
((vs, constrs), false) => let val subst_TFree = the o AList.lookup (op =) (map fst vs ~~ Ts); val cs = map (fn (c, (_, Ts')) =>
(c, (map o map_atyps) (fn TFree (v, _) => subst_TFree v) Ts'
---> dT)) constrs; in
union (op =) cs
#> fold (add_all_constrs ctxt) Ts end
| (_, true) => I;
fun prep_spec ctxt (raw_ts, raw_dTs) = let val ts = map (Syntax.check_term ctxt) raw_ts; val dTs = map (Syntax.check_typ ctxt) raw_dTs; in
[]
|> (fold o fold_aterms)
(fn (t as Const (cT as (_, T))) => ifnot (monomorphic T) then error ("Polymorphic constant: " ^ Syntax.string_of_term ctxt t) else insert (op =) cT | _ => I) ts
|> fold (fn dT => ifnot (monomorphic dT) then error ("Polymorphic datatype: " ^ Syntax.string_of_typ ctxt dT) else add_all_constrs ctxt dT) dTs end;
in
fun ml_code_antiq raw_const ctxt = let val thy = Proof_Context.theory_of ctxt; valconst = Code.check_const thy raw_const; in (print_code ctxt const, register_const const ctxt) end;
fun gen_ml_computation_antiq kind (raw_T, raw_spec) ctxt = let val cTs = prep_spec ctxt raw_spec; val T = Syntax.check_typ ctxt raw_T; val _ = ifnot (monomorphic T) then error ("Polymorphic type: " ^ Syntax.string_of_typ ctxt T) else (); in (print_computation kind ctxt T, register_computation cTs T ctxt) end;
val ml_computation_antiq = gen_ml_computation_antiq mount_computationN;
val ml_computation_conv_antiq = gen_ml_computation_antiq mount_computation_convN;
fun ml_computation_check_antiq raw_spec ctxt = let val cTs = insert (op =) (dest_Const \<^Const>\<open>holds\<close>) (prep_spec ctxt raw_spec); in (print_computation_check ctxt, register_computation cTs \<^typ>\<open>prop\<close> ctxt) end;
end; (*local*)
(** reflection support **)
fun check_datatype thy tyco some_consts = let val declared_constrs = (map fst o snd o fst o Code.get_type thy) tyco; val constrs = case some_consts of SOME [] => []
| SOME consts => let val missing_constrs = subtract (op =) consts declared_constrs; val _ = if null missing_constrs then [] else error ("Missing constructor(s) " ^ commas_quote missing_constrs
^ " for datatype " ^ quote tyco); val false_constrs = subtract (op =) declared_constrs consts; val _ = if null false_constrs then [] else error ("Non-constructor(s) " ^ commas_quote false_constrs
^ " for datatype " ^ quote tyco) in consts end
| NONE => declared_constrs; in (tyco, constrs) end;
fun add_eval_tyco (tyco, tyco') thy = let val k = Sign.arity_number thy tyco; fun pr pr' _ [] = tyco'
| pr pr' _ [ty] =
Code_Printer.concat [pr' Code_Printer.BR ty, tyco']
| pr pr' _ tys =
Code_Printer.concat [Pretty.enum ",""("")" (map (pr' Code_Printer.BR) tys), tyco'] in
thy
|> Code_Target.set_printings (Type_Constructor (tyco, [(target, SOME (k, pr))])) end;
fun add_eval_constr (const, const') thy = let val k = Code.args_number thy const; fun pr pr' fxy ts = Code_Printer.brackify fxy
(const' :: the_list (Code_Printer.tuplify pr' Code_Printer.BR (map fst ts))); in
thy
|> Code_Target.set_printings (Constant (const,
[(target, SOME (Code_Printer.simple_const_syntax (k, pr)))])) end;
fun add_eval_const (const, const') = Code_Target.set_printings (Constant
(const, [(target, SOME (Code_Printer.simple_const_syntax (0, (K o K o K) const')))]));
fun process_reflection (code, (tyco_map, (constr_map, const_map))) module_name NONE thy =
thy
|> Code_Target.add_reserved target module_name
|> Context.theory_map (compile_ML true code)
|> fold (add_eval_tyco o apsnd Pretty.str) tyco_map
|> fold (add_eval_constr o apsnd Pretty.str) constr_map
|> fold (add_eval_const o apsnd Pretty.str) const_map
| process_reflection (code, _) _ (SOME binding) thy = let val code_binding = Path.map_binding Code_Target.code_path binding; val preamble = "(* Generated from " ^
Path.implode (Resources.thy_path (Path.basic (Context.theory_base_name thy))) ^ "; DO NOT EDIT! *)"; val thy' = Code_Target.export code_binding (Bytes.string (preamble ^ "\n\n" ^ code)) thy; val _ = Code_Target.code_export_message thy'; in thy' end;
fun gen_code_reflect prep_type prep_const raw_datatypes raw_functions module_name file_prefix thy = let val ctxt = Proof_Context.init_global thy; val datatypes = map (fn (raw_tyco, raw_cos) =>
(prep_type ctxt raw_tyco, (Option.map o map) (prep_const ctxt) raw_cos)) raw_datatypes; val (tycos, constrs) = map_split (uncurry (check_datatype thy)) datatypes
|> apsnd flat; val functions = map (prep_const ctxt) raw_functions; val consts = constrs @ functions; val program = Code_Thingol.consts_program ctxt consts; val result = runtime_code'' ctxt module_name program tycos consts
|> (apsnd o apsnd) (chop (length constrs)); in
thy
|> process_reflection result module_name file_prefix end;
val code_reflect = gen_code_reflect Code_Target.cert_tyco (K I); val code_reflect_cmd = gen_code_reflect Code_Target.read_tyco Code.read_const;
(** using external SML files as substitute for proper definitions -- only for polyml! **)
local
structure Loaded_Values = Theory_Data
( type T = stringlist val empty = [] fun merge data : T = Library.merge (op =) data
);
fun notify_val (string, value) = let val _ = #enterVal ML_Env.name_space (string, value); val _ = Theory.setup (Loaded_Values.map (insert (op =) string)); in () end;
fun abort _ = error "Only value bindings allowed.";
fun use_file filepath thy = let val thy' = Loaded_Values.put [] thy; val _ = Context.put_generic_context ((SOME o Context.Theory) thy'); val _ =
ML_Compiler0.ML notifying_context
{line = 0, file = Path.implode filepath, verbose = false, debug = false}
(File.read filepath); val thy'' = Context.the_global_context (); val names = Loaded_Values.get thy''; in (names, thy'') end;
end;
fun add_definiendum (ml_name, (b, T)) thy =
thy
|> Code_Target.add_reserved target ml_name
|> Specification.axiomatization [(b, SOME T, NoSyn)] [] [] []
|-> (fn ([Const (const, _)], _) =>
Code_Target.set_printings (Constant (const,
[(target, SOME (Code_Printer.simple_const_syntax (0, (K o K o K o Pretty.str) ml_name)))]))
#> tap (fn thy => Code_Target.produce_code (Proof_Context.init_global thy) false [const] target Code_Target.generatedN NONE []));
fun process_file filepath (definienda, thy) = let val (ml_names, thy') = use_file filepath thy; val superfluous = subtract (fn ((name1, _), name2) => name1 = name2) definienda ml_names; val _ = if null superfluous then () else error ("Value binding(s) " ^ commas_quote superfluous
^ " found in external file " ^ Path.print filepath
^ " not present among the given contants binding(s)."); val these_definienda = AList.make (the o AList.lookup (op =) definienda) ml_names; val thy'' = fold add_definiendum these_definienda thy'; val definienda' = fold (AList.delete (op =)) ml_names definienda; in (definienda', thy'') end;
fun polyml_as_definition bTs filepaths thy = let val definienda = map (fn bT => ((Binding.name_of o fst) bT, bT)) bTs; val (remaining, thy') = fold process_file filepaths (definienda, thy); val _ = if null remaining then () else error ("Constant binding(s) " ^ commas_quote (map fst remaining)
^ " not present in external file(s)."); in thy' end;
end; (*struct*)
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.