diff options
Diffstat (limited to 'contrib/extraction/common.ml')
| -rw-r--r-- | contrib/extraction/common.ml | 403 |
1 files changed, 279 insertions, 124 deletions
diff --git a/contrib/extraction/common.ml b/contrib/extraction/common.ml index 28f560d96b..0f07658fb7 100644 --- a/contrib/extraction/common.ml +++ b/contrib/extraction/common.ml @@ -11,15 +11,16 @@ open Pp open Util open Names +open Term +open Declarations open Nameops open Libnames -open Nametab open Table open Miniml open Mlutil open Ocaml -(*s Get all references used in one [ml_decl list]. *) +(*s Get all references used in one [ml_structure]. *) module Orefset = struct type t = { set : Refset.t ; list : global_reference list } @@ -33,51 +34,12 @@ end type updown = { mutable up : Orefset.t ; mutable down : Orefset.t } -let decl_get_references ld = +let struct_get_references struc = let o = { up = Orefset.empty ; down = Orefset.empty } in - let do_term r = o.down <- Orefset.add r o.down in - let do_cons r = o.up <- Orefset.add r o.up in + let do_term r = o.down <- Orefset.add (long_r r) o.down in + let do_cons r = o.up <- Orefset.add (long_r r) o.up in let do_type = if lang () = Haskell then do_cons else do_term in - List.iter (decl_iter_references do_term do_cons do_type) ld; o - -(*S Modules considerations. *) - -let long_module r = - match modpath (kn_of_r r) with - | MPfile d -> d - | _ -> anomaly "TODO: extraction not ready for true modules" - -let short_module r = List.hd (repr_dirpath (long_module r)) - -(*s [extract_module m] returns all the global reference declared - in a module. This is done by traversing the segment of module [m]. - We just keep constants and inductives. *) - -let segment_contents seg = - let get_reference = function - | (_,kn), Lib.Leaf o -> - (match Libobject.object_tag o with - | "CONSTANT" -> ConstRef kn - | "INDUCTIVE" -> IndRef (kn,0) - | _ -> failwith "caught") - | _ -> failwith "caught" - in - Util.map_succeed get_reference seg - -let module_contents m = - segment_contents (Declaremods.module_objects (MPfile m)) - -(*s The next function finds all names common to at least two used modules. *) - -let modules_reference_clashes modules = - let id_of_r r = lowercase_id (id_of_global None r) in - let map = - Dirset.fold - (fun mod_name map -> - let rl = List.map id_of_r (module_contents mod_name) in - List.fold_left (fun m id -> Idmap.add id (Idmap.mem id m) m) map rl) - modules Idmap.empty - in Idmap.fold (fun i b s -> if b then Idset.add i s else s) map Idset.empty + struct_iter_references do_term do_cons do_type struc; o (*S Renamings. *) @@ -85,80 +47,238 @@ let modules_reference_clashes modules = let keywords = ref Idset.empty let global_ids = ref Idset.empty +let modular = ref false let renamings = Hashtbl.create 97 let rename r s = Hashtbl.add renamings r s let get_renamings r = Hashtbl.find renamings r -let create_mono_renamings decls = - let { up = u ; down = d } = decl_get_references decls in - let add upper r = - try if not (to_inline r) then raise Not_found; - rename r (find_ml_extraction r) +let must_qualify = ref Refset.empty + +let is_upper s = match s.[0] with 'A' .. 'Z' -> true | _ -> false + +let is_lower s = match s.[0] with 'a' .. 'z' | '_' -> true | _ -> false + +let modular_rename up id = + let s = string_of_id id in + let prefix = if up then "Coq_" else "coq_" in + let check = if up then is_upper else is_lower in + if not (check s) || + (Idset.mem id !keywords) || + (String.length s >= 4 && String.sub s 0 4 = prefix) + then prefix ^ s + else s + +let rename_module = modular_rename true + +let mp_to_list mp = + let rec f ls = function + | MPfile d -> + String.capitalize (string_of_id (List.hd (repr_dirpath d))) :: ls + | MPself msid -> rename_module (id_of_msid msid) :: ls + | MPbound mbid -> rename_module (id_of_mbid mbid) :: ls + | MPdot (mp,l) -> f (rename_module (id_of_label l) :: ls) mp + in f [] mp + +let mp_to_list' mp = + let rec f ls = function + | mp when at_toplevel mp -> ls + | MPself msid -> rename_module (id_of_msid msid) :: ls + | MPbound mbid -> rename_module (id_of_mbid mbid) :: ls + | MPdot (mp,l) -> f (rename_module (id_of_label l) :: ls) mp + | _ -> assert false + in f [] mp + +let string_of_modlist l = + List.fold_right (fun s s' -> if s' = "" then s else s ^ "." ^ s') l "" + +let string_of_ren l s = + if l = [] then s else (string_of_modlist l)^"."^s + +let contents_first_level mp = + let s = ref Stringset.empty in + let add b id = s := Stringset.add (modular_rename b id) !s in + let upper_type = (lang () = Haskell) in + let contents_seb = function + | (l, SEBconst cb) -> + let id = id_of_label l in + (match Extraction.constant_kind !cur_env cb with + | Extraction.Logical -> () + | Extraction.Type -> add upper_type (id_of_label l) + | Extraction.Term -> add false (id_of_label l)) + | (_, SEBmind mib) -> + Array.iter + (fun mip -> + if mip.mind_sort = (Prop Null) then () + else begin + add upper_type mip.mind_typename; + Array.iter (add true) mip.mind_consnames + end) + mib.mind_packets + | _ -> () + in + match (Environ.lookup_module mp !cur_env).mod_expr with + | Some (MEBstruct (_,msb)) -> List.iter contents_seb msb; (mp,!s) + | _ -> mp,!s + +let modules_first_level mp = + let s = ref Stringset.empty in + let add id = s := Stringset.add (rename_module id) !s in + let contents_seb = function + | (l, (SEBmodule _ | SEBmodtype _)) -> add (id_of_label l) + | _ -> () + in + match (Environ.lookup_module mp !cur_env).mod_expr with + | Some (MEBstruct (_,msb)) -> List.iter contents_seb msb; !s + | _ -> !s + +let contents_first_level = + let cache = ref MPmap.empty in + fun mp -> + try MPmap.find mp !cache with Not_found -> - let id = id_of_global None r in - let id = if upper then uppercase_id id else lowercase_id id in - let id = rename_id id !global_ids in - global_ids := Idset.add id !global_ids; - rename r (string_of_id id) + let res = contents_first_level mp in + cache := MPmap.add mp res !cache; + res + +let rec clash_in_contents mp0 s = function + | [] -> false + | (mp,_) :: _ when mp = mp0 -> false + | (mp,ss) :: l -> (Stringset.mem s ss) || (clash_in_contents mp0 s l) + +let create_modular_renamings struc = + let cur_mp = fst (List.hd struc) in + let modfiles = ref MPset.empty in + let { up = u ; down = d } = struct_get_references struc in - List.iter (add true) (List.rev (Orefset.list u)); - List.iter (add false) (List.rev (Orefset.list d)) - -let create_modular_renamings current_module decls = - let { up = u ; down = d } = decl_get_references decls in - let modules = - let f r s = Dirset.add (long_module r) s in - Refset.fold f (Orefset.set u) (Refset.fold f (Orefset.set d) Dirset.empty) - in - let modular_clashs = modules_reference_clashes modules + (* 1) create renamings of objects *) + let add upper r = + let mp = modpath (kn_of_r r) in + begin try + let mp = modfile_of_mp mp in + if mp <> cur_mp then modfiles := MPset.add mp !modfiles + with Not_found -> () + end; + let mplist = mp_to_list (modpath (kn_of_r r)) in + let s = modular_rename upper (id_of_global r) in + global_ids := Idset.add (id_of_string s) !global_ids; + Hashtbl.add renamings r (mplist,s) + in + Refset.iter (add true) (Orefset.set u); + Refset.iter (add false) (Orefset.set d); + + (* 2) determine the opened libraries and the potential clashes *) + let used_modules = MPset.elements !modfiles in + let s = ref (modules_first_level cur_mp) in + List.iter + (function + | MPfile d -> + let s_mp = + String.capitalize (string_of_id (List.hd (repr_dirpath d))) in + if Stringset.mem s_mp !s then error_module_clash s_mp + else s:= Stringset.add s_mp !s + | _ -> assert false) + used_modules; + let env = List.rev_map contents_first_level used_modules in + let needs_qualify r = + let mp = modpath (kn_of_r r) in + if not (is_modfile mp) || mp = cur_mp then () + else + let s = snd (get_renamings r) in + if clash_in_contents mp s env + then must_qualify := Refset.add r !must_qualify in - let clash r id = - exists_cci (make_path (dirpath (sp_of_global None r)) id) + Refset.iter needs_qualify (Orefset.set u); + Refset.iter needs_qualify (Orefset.set d); + used_modules + +let create_mono_renamings struc = + let fst_level_modules = ref Idmap.empty in + let { up = u ; down = d } = struct_get_references struc in - let prefix upper r id = - let prefix = if upper then "Coq_" else "coq_" in - let id' = if upper then uppercase_id id else lowercase_id id in - if (Idset.mem id' !keywords) || (id <> id' && clash r id') then - id_of_string (prefix^(string_of_id id)) - else id' - in + (* 1) create renamings of objects *) let add upper r = - try if not (to_inline r) then raise Not_found; - rename r (find_ml_extraction r) - with Not_found -> - let id = id_of_global None r in - let m = short_module r in - let id' = prefix upper r id in - let qualify = - (m <> current_module) && (Idset.mem (lowercase_id id) modular_clashs) - in - if qualify then - let s = String.capitalize (string_of_id m) ^ "." ^ (string_of_id id') in - Hashtbl.add renamings r s - else begin - global_ids := Idset.add id' !global_ids; - Hashtbl.add renamings r (string_of_id id') - end + let mp = modpath (kn_of_r r) in + begin try + let mp,l = fst_level_module_of_mp mp in + let id = id_of_label l in + if Idmap.find id !fst_level_modules <> mp then + error_module_clash (string_of_id id) + else fst_level_modules := Idmap.add id mp !fst_level_modules + with Not_found -> () + end; + let mplist = mp_to_list' (modpath (kn_of_r r)) in + let my_id = if upper then uppercase_id else lowercase_id in + let id = + if mplist = [] then + next_ident_away (my_id (id_of_global r)) (Idset.elements !global_ids) + else id_of_string (modular_rename upper (id_of_global r)) + in + global_ids := Idset.add id !global_ids; + Hashtbl.add renamings r (mplist,string_of_id id) in List.iter (add true) (List.rev (Orefset.list u)); - List.iter (add false) (List.rev (Orefset.list d)); - Idset.remove current_module - (Dirset.fold (fun m s -> Idset.add (List.hd (repr_dirpath m)) s) - modules Idset.empty) + List.iter (add false) (List.rev (Orefset.list d)) (*s Renaming issues at toplevel *) module ToplevelParams = struct let globals () = Idset.empty - let pp_global r = Printer.pr_global r + let pp_global _ r = pr_global r + let pp_long_module mp = str (string_of_mp mp) + let pp_short_module id = pr_id id end (*s Renaming issues for a monolithic or modular extraction. *) +let rec remove_common l l' = match l,l' with + | [], _ -> l' + | s::q, s'::q' -> if s = s' then remove_common q q' else l' + | _ -> assert false + +let rec length_common_prefix l l' = match l,l' with + | [],_ -> 0 + | _, [] -> 0 + | s::q, s'::q' -> if s <> s' then 0 else 1+(length_common_prefix q q') + +let rec decreasing_contents mp = match mp with + | MPdot (mp',_) -> (contents_first_level mp) :: (decreasing_contents mp') + | mp when is_toplevel mp -> [] + | _ -> [contents_first_level mp] + module StdParams = struct + let globals () = !global_ids - let pp_global r = str (Hashtbl.find renamings r) + + let pp_global cur_mp r = + let cur_mp = long_mp cur_mp in + let cur_l = if !modular then mp_to_list cur_mp else mp_to_list' cur_mp in + let r = long_r r in + let mp = modpath (kn_of_r r) in + let l,s = get_renamings r in + let n = length_common_prefix cur_l l in + if n = 0 && !modular (* [r] is in another module *) + then + if (Refset.mem r !must_qualify) || (lang () = Haskell) + then str (string_of_ren l s) + else + if clash_in_contents mp s (decreasing_contents cur_mp) + then str (string_of_ren l s) + else str s + else + let nl = List.length l in + if n = nl && nl < List.length cur_l then (* strict prefix *) + if clash_in_contents mp s (decreasing_contents cur_mp) + then error_unqualified_name (string_of_ren l s) (string_of_modlist cur_l) + else str s + else (* [cur_mp] and [mp] are orthogonal *) + let l = remove_common cur_l l + in str (string_of_ren l s) + + let pp_long_module mp = + str (string_of_modlist (if !modular then mp_to_list mp else mp_to_list' mp)) + + let pp_short_module id = str (rename_module id) end module ToplevelPp = Ocaml.Make(ToplevelParams) @@ -166,11 +286,22 @@ module OcamlPp = Ocaml.Make(StdParams) module HaskellPp = Haskell.Make(StdParams) module SchemePp = Scheme.Make(StdParams) -let pp_decl () = match lang () with - | Ocaml -> OcamlPp.pp_decl - | Haskell -> HaskellPp.pp_decl - | Scheme -> SchemePp.pp_decl - | Toplevel -> ToplevelPp.pp_decl +let pp_decl mp d = match lang () with + | Ocaml -> OcamlPp.pp_decl mp d + | Haskell -> HaskellPp.pp_decl mp d + | Scheme -> SchemePp.pp_decl mp d + | Toplevel -> ToplevelPp.pp_decl mp d + +let pp_struct s = match lang () with + | Ocaml -> OcamlPp.pp_struct s + | Haskell -> HaskellPp.pp_struct s + | Scheme -> SchemePp.pp_struct s + | Toplevel -> ToplevelPp.pp_struct s + +let pp_signature s = match lang () with + | Ocaml -> OcamlPp.pp_signature s + | Haskell -> HaskellPp.pp_signature s + | _ -> assert false let set_keywords () = (match lang () with @@ -178,7 +309,8 @@ let set_keywords () = | Haskell -> keywords := Haskell.keywords | Scheme -> keywords := Scheme.keywords | Toplevel -> keywords := Idset.empty); - global_ids := !keywords + global_ids := !keywords; + must_qualify := Refset.empty let preamble prm = match lang () with | Ocaml -> Ocaml.preamble prm @@ -186,36 +318,59 @@ let preamble prm = match lang () with | Scheme -> Scheme.preamble prm | Toplevel -> (fun _ _ -> mt ()) +let preamble_sig prm = match lang () with + | Ocaml -> Ocaml.preamble_sig prm + | _ -> assert false + +(*S Extraction of one decl to stdout. *) + +let print_one_decl struc mp decl = + set_keywords (); + modular := false; + create_mono_renamings struc; + msgnl (pp_decl mp decl) + (*S Extraction to a file. *) -let extract_to_file f prm decls = +let print_structure_to_file f prm struc = cons_cofix := Refset.empty; Hashtbl.clear renamings; set_keywords (); - let used_modules = - if lang () = Toplevel then Idset.empty - else if prm.modular then - create_modular_renamings prm.mod_name decls - else begin create_mono_renamings decls; Idset.empty end + modular := prm.modular; + let used_modules = + if lang () = Toplevel then [] + else if prm.modular then create_modular_renamings struc + else (create_mono_renamings struc; []) in - let pp_decl = pp_decl () in - let cout = match f with - | None -> stdout - | Some f -> open_out f in + let print_dummys = + (struct_ast_search MLdummy struc, + struct_type_search Tdummy struc, + struct_type_search Tunknown struc) + in + (* print the implementation *) + let cout = match f with None -> stdout | Some (f,_) -> open_out f in let ft = Pp_control.with_output_to cout in - let print_dummys = - (decl_search MLdummy decls, - decl_type_search Tdummy decls, - decl_type_search Tunknown decls) in - pp_with ft (preamble prm used_modules print_dummys); - begin try - List.iter (fun d -> msgnl_with ft (pp_decl d)) decls - with e -> - pp_flush_with ft (); if f <> None then close_out cout; raise e + begin try + msg_with ft (preamble prm used_modules print_dummys); + msg_with ft (pp_struct struc); + if f <> None then close_out cout; + with e -> + if f <> None then close_out cout; raise e end; - pp_flush_with ft (); - if f <> None then close_out cout; - + (* print the signature *) + match f with + | Some (_,f) when lang () = Ocaml -> + let cout = open_out f in + let ft = Pp_control.with_output_to cout in + begin try + msg_with ft (preamble_sig prm used_modules print_dummys); + msg_with ft (pp_signature (signature_of_structure struc)); + close_out cout; + with e -> + close_out cout; raise e + end + | _ -> () + (*i (* DO NOT REMOVE: used when making names resolution *) let cout = open_out (f^".ren") in |
