diff options
Diffstat (limited to 'contrib/extraction/extract_env.ml')
-rw-r--r-- | contrib/extraction/extract_env.ml | 529 |
1 files changed, 0 insertions, 529 deletions
diff --git a/contrib/extraction/extract_env.ml b/contrib/extraction/extract_env.ml deleted file mode 100644 index 057a7b29..00000000 --- a/contrib/extraction/extract_env.ml +++ /dev/null @@ -1,529 +0,0 @@ -(************************************************************************) -(* v * The Coq Proof Assistant / The Coq Development Team *) -(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *) -(* \VV/ **************************************************************) -(* // * This file is distributed under the terms of the *) -(* * GNU Lesser General Public License Version 2.1 *) -(************************************************************************) - -(*i $Id: extract_env.ml 13201 2010-06-25 22:36:27Z letouzey $ i*) - -open Term -open Declarations -open Names -open Libnames -open Pp -open Util -open Miniml -open Table -open Extraction -open Modutil -open Common -open Mod_subst - -(***************************************) -(*S Part I: computing Coq environment. *) -(***************************************) - -let toplevel_env () = - let seg = Lib.contents_after None in - let get_reference = function - | (_,kn), Lib.Leaf o -> - let mp,_,l = repr_kn kn in - let seb = match Libobject.object_tag o with - | "CONSTANT" -> SFBconst (Global.lookup_constant (constant_of_kn kn)) - | "INDUCTIVE" -> SFBmind (Global.lookup_mind kn) - | "MODULE" -> SFBmodule (Global.lookup_module (MPdot (mp,l))) - | "MODULE TYPE" -> - SFBmodtype (Global.lookup_modtype (MPdot (mp,l))) - | _ -> failwith "caught" - in l,seb - | _ -> failwith "caught" - in - match current_toplevel () with - | MPself msid -> SEBstruct (msid, List.rev (map_succeed get_reference seg)) - | _ -> assert false - -let environment_until dir_opt = - let rec parse = function - | [] when dir_opt = None -> [current_toplevel (), toplevel_env ()] - | [] -> [] - | d :: l -> - match (Global.lookup_module (MPfile d)).mod_expr with - | Some meb -> - if dir_opt = Some d then [MPfile d, meb] - else (MPfile d, meb) :: (parse l) - | _ -> assert false - in parse (Library.loaded_libraries ()) - - -(*s Visit: - a structure recording the needed dependencies for the current extraction *) - -module type VISIT = sig - (* Reset the dependencies by emptying the visit lists *) - val reset : unit -> unit - - (* Add the module_path and all its prefixes to the mp visit list *) - val add_mp : module_path -> unit - - (* Add kernel_name / constant / reference / ... in the visit lists. - These functions silently add the mp of their arg in the mp list *) - val add_kn : kernel_name -> unit - val add_con : constant -> unit - val add_ref : global_reference -> unit - val add_decl_deps : ml_decl -> unit - val add_spec_deps : ml_spec -> unit - - (* Test functions: - is a particular object a needed dependency for the current extraction ? *) - val needed_kn : kernel_name -> bool - val needed_con : constant -> bool - val needed_mp : module_path -> bool -end - -module Visit : VISIT = struct - (* What used to be in a single KNset should now be split into a KNset - (for inductives and modules names) and a Cset for constants - (and still the remaining MPset) *) - type must_visit = - { mutable kn : KNset.t; mutable con : Cset.t; mutable mp : MPset.t } - (* the imperative internal visit lists *) - let v = { kn = KNset.empty ; con = Cset.empty ; mp = MPset.empty } - (* the accessor functions *) - let reset () = v.kn <- KNset.empty; v.con <- Cset.empty; v.mp <- MPset.empty - let needed_kn kn = KNset.mem kn v.kn - let needed_con c = Cset.mem c v.con - let needed_mp mp = MPset.mem mp v.mp - let add_mp mp = - check_loaded_modfile mp; v.mp <- MPset.union (prefixes_mp mp) v.mp - let add_kn kn = v.kn <- KNset.add kn v.kn; add_mp (modpath kn) - let add_con c = v.con <- Cset.add c v.con; add_mp (con_modpath c) - let add_ref = function - | ConstRef c -> add_con c - | IndRef (kn,_) | ConstructRef ((kn,_),_) -> add_kn kn - | VarRef _ -> assert false - let add_decl_deps = decl_iter_references add_ref add_ref add_ref - let add_spec_deps = spec_iter_references add_ref add_ref add_ref -end - -exception Impossible - -let check_arity env cb = - let t = Typeops.type_of_constant_type env cb.const_type in - if Reduction.is_arity env t then raise Impossible - -let check_fix env cb i = - match cb.const_body with - | None -> raise Impossible - | Some lbody -> - match kind_of_term (Declarations.force lbody) with - | Fix ((_,j),recd) when i=j -> check_arity env cb; (true,recd) - | CoFix (j,recd) when i=j -> check_arity env cb; (false,recd) - | _ -> raise Impossible - -let factor_fix env l cb msb = - let _,recd as check = check_fix env cb 0 in - let n = Array.length (let fi,_,_ = recd in fi) in - if n = 1 then [|l|], recd, msb - else begin - if List.length msb < n-1 then raise Impossible; - let msb', msb'' = list_chop (n-1) msb in - let labels = Array.make n l in - list_iter_i - (fun j -> - function - | (l,SFBconst cb') -> - if check <> check_fix env cb' (j+1) then raise Impossible; - labels.(j+1) <- l; - | _ -> raise Impossible) msb'; - labels, recd, msb'' - end - -let build_mb expr typ_opt = - { mod_expr = Some expr; - mod_type = typ_opt; - mod_constraints = Univ.Constraint.empty; - mod_alias = Mod_subst.empty_subst; - mod_retroknowledge = [] } - -let my_type_of_mb env mb = - match mb.mod_type with - | Some mtb -> mtb - | None -> Modops.eval_struct env (Option.get mb.mod_expr) - -(** Ad-hoc update of environment, inspired by [Mod_type.check_with_aux_def]. - To check with Elie. *) - -let env_for_mtb_with env mtb idl = - let msid,sig_b = match Modops.eval_struct env mtb with - | SEBstruct(msid,sig_b) -> msid,sig_b - | _ -> assert false - in - let l = label_of_id (List.hd idl) in - let before = fst (list_split_at (fun (l',_) -> l=l') sig_b) in - Modops.add_signature (MPself msid) before env - -(* From a [structure_body] (i.e. a list of [structure_field_body]) - to specifications. *) - -let rec extract_sfb_spec env mp = function - | [] -> [] - | (l,SFBconst cb) :: msig -> - let kn = make_con mp empty_dirpath l in - let s = extract_constant_spec env kn cb in - let specs = extract_sfb_spec env mp msig in - if logical_spec s then specs - else begin Visit.add_spec_deps s; (l,Spec s) :: specs end - | (l,SFBmind _) :: msig -> - let kn = make_kn mp empty_dirpath l in - let s = Sind (kn, extract_inductive env kn) in - let specs = extract_sfb_spec env mp msig in - if logical_spec s then specs - else begin Visit.add_spec_deps s; (l,Spec s) :: specs end - | (l,SFBmodule mb) :: msig -> - let specs = extract_sfb_spec env mp msig in - let spec = extract_seb_spec env (my_type_of_mb env mb) in - (l,Smodule spec) :: specs - | (l,SFBmodtype mtb) :: msig -> - let specs = extract_sfb_spec env mp msig in - (l,Smodtype (extract_seb_spec env mtb.typ_expr)) :: specs - | (l,SFBalias(mp1,typ_opt,_))::msig -> - let mb = build_mb (SEBident mp1) typ_opt in - extract_sfb_spec env mp ((l,SFBmodule mb) :: msig) - -(* From [struct_expr_body] to specifications *) - -(* Invariant: the [seb] given to [extract_seb_spec] should either come: - - from a [mod_type] or [type_expr] field - - from the output of [Modops.eval_struct]. - This way, any encountered [SEBident] should be a true module type. - For instance, [my_type_of_mb] ensures this invariant. -*) - -and extract_seb_spec env = function - | SEBident mp -> Visit.add_mp mp; MTident mp - | SEBwith(mtb',With_definition_body(idl,cb))-> - let env' = env_for_mtb_with env mtb' idl in - let mtb''= extract_seb_spec env mtb' in - (match extract_with_type env' cb with (* cb peut contenir des kn *) - | None -> mtb'' - | Some (vl,typ) -> MTwith(mtb'',ML_With_type(idl,vl,typ))) - | SEBwith(mtb',With_module_body(idl,mp,_,_))-> - Visit.add_mp mp; - MTwith(extract_seb_spec env mtb', - ML_With_module(idl,mp)) -(* TODO: On pourrait peut-etre oter certaines eta-expansion, du genre: - | SEBfunctor(mbid,_,SEBapply(m,SEBident (MPbound mbid2),_)) - when mbid = mbid2 -> extract_seb_spec env m - (* faudrait alors ajouter un test de non-apparition de mbid dans mb *) -*) - | SEBfunctor (mbid, mtb, mtb') -> - let mp = MPbound mbid in - let env' = Modops.add_module mp (Modops.module_body_of_type mtb) env in - MTfunsig (mbid, extract_seb_spec env mtb.typ_expr, - extract_seb_spec env' mtb') - | SEBstruct (msid, msig) -> - let mp = MPself msid in - let env' = Modops.add_signature mp msig env in - MTsig (msid, extract_sfb_spec env' mp msig) - | SEBapply _ as mtb -> - extract_seb_spec env (Modops.eval_struct env mtb) - - -(* From a [structure_body] (i.e. a list of [structure_field_body]) - to implementations. - - NB: when [all=false], the evaluation order of the list is - important: last to first ensures correct dependencies. -*) - -let rec extract_sfb env mp all = function - | [] -> [] - | (l,SFBconst cb) :: msb -> - (try - let vl,recd,msb = factor_fix env l cb msb in - let vc = Array.map (make_con mp empty_dirpath) vl in - let ms = extract_sfb env mp all msb in - let b = array_exists Visit.needed_con vc in - if all || b then - let d = extract_fixpoint env vc recd in - if (not b) && (logical_decl d) then ms - else begin Visit.add_decl_deps d; (l,SEdecl d) :: ms end - else ms - with Impossible -> - let ms = extract_sfb env mp all msb in - let c = make_con mp empty_dirpath l in - let b = Visit.needed_con c in - if all || b then - let d = extract_constant env c cb in - if (not b) && (logical_decl d) then ms - else begin Visit.add_decl_deps d; (l,SEdecl d) :: ms end - else ms) - | (l,SFBmind mib) :: msb -> - let ms = extract_sfb env mp all msb in - let kn = make_kn mp empty_dirpath l in - let b = Visit.needed_kn kn in - if all || b then - let d = Dind (kn, extract_inductive env kn) in - if (not b) && (logical_decl d) then ms - else begin Visit.add_decl_deps d; (l,SEdecl d) :: ms end - else ms - | (l,SFBmodule mb) :: msb -> - let ms = extract_sfb env mp all msb in - let mp = MPdot (mp,l) in - if all || Visit.needed_mp mp then - (l,SEmodule (extract_module env mp true mb)) :: ms - else ms - | (l,SFBmodtype mtb) :: msb -> - let ms = extract_sfb env mp all msb in - let mp = MPdot (mp,l) in - if all || Visit.needed_mp mp then - (l,SEmodtype (extract_seb_spec env mtb.typ_expr)) :: ms - else ms - | (l,SFBalias (mp1,typ_opt,_)) :: msb -> - let mb = build_mb (SEBident mp1) typ_opt in - extract_sfb env mp all ((l,SFBmodule mb) :: msb) - -(* From [struct_expr_body] to implementations *) - -and extract_seb env mpo all = function - | SEBident mp -> - if is_modfile mp && not (modular ()) then error_MPfile_as_mod mp false; - Visit.add_mp mp; MEident mp - | SEBapply (meb, meb',_) -> - MEapply (extract_seb env None true meb, - extract_seb env None true meb') - | SEBfunctor (mbid, mtb, meb) -> - let mp = MPbound mbid in - let env' = Modops.add_module mp (Modops.module_body_of_type mtb) env in - MEfunctor (mbid, extract_seb_spec env mtb.typ_expr, - extract_seb env' None true meb) - | SEBstruct (msid, msb) -> - let mp,msb = match mpo with - | None -> MPself msid, msb - | Some mp -> mp, Modops.subst_structure (map_msid msid mp) msb - in - let env' = Modops.add_signature mp msb env in - MEstruct (msid, extract_sfb env' mp all msb) - | SEBwith (_,_) -> anomaly "Not available yet" - -and extract_module env mp all mb = - (* [mb.mod_expr <> None ], since we look at modules from outside. *) - (* Example of module with empty [mod_expr] is X inside a Module F [X:SIG]. *) - { ml_mod_expr = extract_seb env (Some mp) all (Option.get mb.mod_expr); - ml_mod_type = extract_seb_spec env (my_type_of_mb env mb) } - - -let unpack = function MEstruct (_,sel) -> sel | _ -> assert false - -let mono_environment refs mpl = - Visit.reset (); - List.iter Visit.add_ref refs; - List.iter Visit.add_mp mpl; - let env = Global.env () in - let l = List.rev (environment_until None) in - List.rev_map - (fun (mp,m) -> mp, unpack (extract_seb env (Some mp) false m)) l - -(**************************************) -(*S Part II : Input/Output primitives *) -(**************************************) - -let descr () = match lang () with - | Ocaml -> Ocaml.ocaml_descr - | Haskell -> Haskell.haskell_descr - | Scheme -> Scheme.scheme_descr - -(* From a filename string "foo.ml" or "foo", builds "foo.ml" and "foo.mli" - Works similarly for the other languages. *) - -let default_id = id_of_string "Main" - -let mono_filename f = - let d = descr () in - match f with - | None -> None, None, default_id - | Some f -> - let f = - if Filename.check_suffix f d.file_suffix then - Filename.chop_suffix f d.file_suffix - else f - in - let id = - if lang () <> Haskell then default_id - else try id_of_string (Filename.basename f) - with _ -> error "Extraction: provided filename is not a valid identifier" - in - Some (f^d.file_suffix), Option.map ((^) f) d.sig_suffix, id - -(* Builds a suitable filename from a module id *) - -let module_filename fc = - let d = descr () in - let fn = if d.capital_file then fc else String.uncapitalize fc - in - Some (fn^d.file_suffix), Option.map ((^) fn) d.sig_suffix, id_of_string fc - -(*s Extraction of one decl to stdout. *) - -let print_one_decl struc mp decl = - let d = descr () in - reset_renaming_tables AllButExternal; - set_phase Pre; - ignore (d.pp_struct struc); - set_phase Impl; - push_visible mp None; - msgnl (d.pp_decl decl); - pop_visible () - -(*s Extraction of a ml struct to a file. *) - -let formatter dry file = - if dry then Format.make_formatter (fun _ _ _ -> ()) (fun _ -> ()) - else match file with - | None -> !Pp_control.std_ft - | Some cout -> - let ft = Pp_control.with_output_to cout in - Option.iter (Format.pp_set_margin ft) (Pp_control.get_margin ()); - ft - -let print_structure_to_file (fn,si,mo) dry struc = - let d = descr () in - reset_renaming_tables AllButExternal; - let unsafe_needs = { - mldummy = struct_ast_search ((=) MLdummy) struc; - tdummy = struct_type_search Mlutil.isDummy struc; - tunknown = struct_type_search ((=) Tunknown) struc; - magic = - if lang () <> Haskell then false - else struct_ast_search (function MLmagic _ -> true | _ -> false) struc } - in - (* First, a dry run, for computing objects to rename or duplicate *) - set_phase Pre; - let devnull = formatter true None in - msg_with devnull (d.pp_struct struc); - let opened = opened_libraries () in - (* Print the implementation *) - let cout = if dry then None else Option.map open_out fn in - let ft = formatter dry cout in - begin try - (* The real printing of the implementation *) - set_phase Impl; - msg_with ft (d.preamble mo opened unsafe_needs); - msg_with ft (d.pp_struct struc); - Option.iter close_out cout; - with e -> - Option.iter close_out cout; raise e - end; - if not dry then Option.iter info_file fn; - (* Now, let's print the signature *) - Option.iter - (fun si -> - let cout = open_out si in - let ft = formatter false (Some cout) in - begin try - set_phase Intf; - msg_with ft (d.sig_preamble mo opened unsafe_needs); - msg_with ft (d.pp_sig (signature_of_structure struc)); - close_out cout; - with e -> - close_out cout; raise e - end; - info_file si) - (if dry then None else si) - - -(*********************************************) -(*s Part III: the actual extraction commands *) -(*********************************************) - - -let reset () = - Visit.reset (); reset_tables (); reset_renaming_tables Everything - -let init modular = - check_inside_section (); check_inside_module (); - set_keywords (descr ()).keywords; - set_modular modular; - reset (); - if modular && lang () = Scheme then error_scheme () - -(* From a list of [reference], let's retrieve whether they correspond - to modules or [global_reference]. Warn the user if both is possible. *) - -let rec locate_ref = function - | [] -> [],[] - | r::l -> - let q = snd (qualid_of_reference r) in - let mpo = try Some (Nametab.locate_module q) with Not_found -> None - and ro = try Some (Nametab.locate q) with Not_found -> None in - match mpo, ro with - | None, None -> Nametab.error_global_not_found q - | None, Some r -> let refs,mps = locate_ref l in r::refs,mps - | Some mp, None -> let refs,mps = locate_ref l in refs,mp::mps - | Some mp, Some r -> - warning_both_mod_and_cst q mp r; - let refs,mps = locate_ref l in refs,mp::mps - -(*s Recursive extraction in the Coq toplevel. The vernacular command is - \verb!Recursive Extraction! [qualid1] ... [qualidn]. Also used when - extracting to a file with the command: - \verb!Extraction "file"! [qualid1] ... [qualidn]. *) - -let full_extr f (refs,mps) = - init false; - List.iter (fun mp -> if is_modfile mp then error_MPfile_as_mod mp true) mps; - let struc = optimize_struct refs (mono_environment refs mps) in - warning_axioms (); - print_structure_to_file (mono_filename f) false struc; - reset () - -let full_extraction f lr = full_extr f (locate_ref lr) - - -(*s Simple extraction in the Coq toplevel. The vernacular command - is \verb!Extraction! [qualid]. *) - -let simple_extraction r = match locate_ref [r] with - | ([], [mp]) as p -> full_extr None p - | [r],[] -> - init false; - let struc = optimize_struct [r] (mono_environment [r] []) in - let d = get_decl_in_structure r struc in - warning_axioms (); - if is_custom r then msgnl (str "(** User defined extraction *)"); - print_one_decl struc (modpath_of_r r) d; - reset () - | _ -> assert false - - -(*s (Recursive) Extraction of a library. The vernacular command is - \verb!(Recursive) Extraction Library! [M]. *) - -let extraction_library is_rec m = - init true; - let dir_m = - let q = make_short_qualid m in - try Nametab.full_name_module q with Not_found -> error_unknown_module q - in - Visit.add_mp (MPfile dir_m); - let env = Global.env () in - let l = List.rev (environment_until (Some dir_m)) in - let select l (mp,meb) = - if Visit.needed_mp mp - then (mp, unpack (extract_seb env (Some mp) true meb)) :: l - else l - in - let struc = List.fold_left select [] l in - let struc = optimize_struct [] struc in - warning_axioms (); - let print = function - | (MPfile dir as mp, sel) as e -> - let dry = not is_rec && dir <> dir_m in - let s = string_of_modfile mp in - print_structure_to_file (module_filename s) dry [e] - | _ -> assert false - in - List.iter print struc; - reset () |