aboutsummaryrefslogtreecommitdiffhomepage
path: root/contrib/extraction/common.ml
diff options
context:
space:
mode:
authorGravatar letouzey <letouzey@85f007b7-540e-0410-9357-904b9bb8a0f7>2007-10-17 12:32:10 +0000
committerGravatar letouzey <letouzey@85f007b7-540e-0410-9357-904b9bb8a0f7>2007-10-17 12:32:10 +0000
commit350398eaea679b2bf66c93e9ac5e0308349bc959 (patch)
treeb44f7974e648a816e036616abd5fff9ecbc3fd17 /contrib/extraction/common.ml
parenta7f22f83ffd59bdd7ecf84dcefda6552f8be7c4a (diff)
Major reorganisation of the extraction "backend".
Initial Idea: getting rid of nasty renaming issues in modules, in particular bugs #820 (part d) #1340 #1526 #1654 Final effect: lots of changes, simplifications, cleanups, unrelated fixes and ehancements, and also probably some regressions (time will tell). A few details: * no more experimental "Toplevel" language. * no more functors Make in Ocaml/Haskell/Scheme. The spirit of these functors and Mlpp_params was already not followed much, and this framework was more a nuisance that anything else. * instead, some records language_descr regrouping the specific features of the different output languages. * Common now comes before Ocaml/Haskell/Scheme, these ones are now independant from each others. print_structure_to_file is now in Extract_env. * A nice detail: no more duplications of warnings concerning axioms. * In modular extraction, the clashes due to the opened modules are now computed once and for all thanks to record_contents_fstlev, instead of re-asking Coq each time about these opened modules and using Extraction.constant_kind * some utilities about modules_path added and/or moved from Modutil to Table. * using a .v file as a module, e.g. in a functor application should now works in modular extraction. Now concerning renaming issues themselves: * printing is done twice, the first time toward /dev/null, in order to encounter the naming issues unsolvable by a simple qualification. On the second run, we create artificial modules Coq__123 for allowing qualification of these hidden objects. * names are now fully separated into their syntaxic categories: terms/types/constructors/modules * Only one last unsupported situation (but at least detected and signaled by an error): an object M.t from an external file-module M.v can't be printed when a local module M is in the way. This situation is really unlikely (in Coq you must use _long_ file-module name, e.g. Init.Datatypes.nat). It could be solved by inserting "module Coq_123 = M" at the beginning of the file, but then the signature of Coq_123 (that is, the one of M) should be written explicitely in the .mli, which is _really_ not nice. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@10232 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'contrib/extraction/common.ml')
-rw-r--r--contrib/extraction/common.ml754
1 files changed, 389 insertions, 365 deletions
diff --git a/contrib/extraction/common.ml b/contrib/extraction/common.ml
index 6db146b1e..855990d25 100644
--- a/contrib/extraction/common.ml
+++ b/contrib/extraction/common.ml
@@ -17,42 +17,218 @@ open Nameops
open Libnames
open Table
open Miniml
+open Mlutil
open Modutil
-open Ocaml
+open Mod_subst
-(*S Renamings. *)
+(*s Some pretty-print utility functions. *)
+
+let pp_par par st = if par then str "(" ++ st ++ str ")" else st
+
+let pp_apply st par args = match args with
+ | [] -> st
+ | _ -> hov 2 (pp_par par (st ++ spc () ++ prlist_with_sep spc identity args))
+
+let pr_binding = function
+ | [] -> mt ()
+ | l -> str " " ++ prlist_with_sep (fun () -> str " ") pr_id l
+
+let fnl2 () = fnl () ++ fnl ()
+
+let space_if = function true -> str " " | false -> mt ()
+
+let sec_space_if = function true -> spc () | false -> mt ()
+
+let is_digit = function
+ | '0'..'9' -> true
+ | _ -> false
+
+let begins_with_CoqXX s =
+ let n = String.length s in
+ n >= 4 && s.[0] = 'C' && s.[1] = 'o' && s.[2] = 'q' &&
+ let i = ref 3 in
+ try while !i < n do
+ if s.[!i] = '_' then i:=n (*Stop*)
+ else if is_digit s.[!i] then incr i
+ else raise Not_found
+ done; true
+ with Not_found -> false
+
+let unquote s =
+ if lang () <> Scheme then s
+ else
+ let s = String.copy s in
+ for i=0 to String.length s - 1 do if s.[i] = '\'' then s.[i] <- '~' done;
+ s
+
+let rec dottify = function
+ | [] -> assert false
+ | [s] -> unquote s
+ | s::[""] -> unquote s
+ | s::l -> (dottify l)^"."^(unquote s)
+
+(*s Uppercase/lowercase renamings. *)
+
+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 lowercase_id id = id_of_string (String.uncapitalize (string_of_id id))
+let uppercase_id id = id_of_string (String.capitalize (string_of_id id))
+
+(* [pr_upper_id id] makes 2 String.copy lesser than [pr_id (uppercase_id id)] *)
+let pr_upper_id id = str (String.capitalize (string_of_id id))
+
+
+(*s de Bruijn environments for programs *)
+
+type env = identifier list * Idset.t
+
+(*s Generic renaming issues for local variable names. *)
+
+let rec rename_id id avoid =
+ if Idset.mem id avoid then rename_id (lift_ident id) avoid else id
+
+let rec rename_vars avoid = function
+ | [] ->
+ [], avoid
+ | id :: idl when id == dummy_name ->
+ (* we don't rename dummy binders *)
+ let (idl', avoid') = rename_vars avoid idl in
+ (id :: idl', avoid')
+ | id :: idl ->
+ let (idl, avoid) = rename_vars avoid idl in
+ let id = rename_id (lowercase_id id) avoid in
+ (id :: idl, Idset.add id avoid)
+
+let rename_tvars avoid l =
+ let rec rename avoid = function
+ | [] -> [],avoid
+ | id :: idl ->
+ let id = rename_id (lowercase_id id) avoid in
+ let idl, avoid = rename (Idset.add id avoid) idl in
+ (id :: idl, avoid) in
+ fst (rename avoid l)
+
+let push_vars ids (db,avoid) =
+ let ids',avoid' = rename_vars avoid ids in
+ ids', (ids' @ db, avoid')
+
+let get_db_name n (db,_) =
+ let id = List.nth db (pred n) in
+ if id = dummy_name then id_of_string "__" else id
+
+
+(*S Renamings of global objects. *)
(*s Tables of global renamings *)
let keywords = ref Idset.empty
+let set_keywords kws = keywords := kws
+
let global_ids = ref Idset.empty
-let modular = ref false
+let add_global_ids s = global_ids := Idset.add s !global_ids
+let global_ids_list () = Idset.elements !global_ids
+
+let empty_env () = [], !global_ids
+
+let mktable () =
+ let h = Hashtbl.create 97 in
+ (Hashtbl.add h, Hashtbl.find h, fun () -> Hashtbl.clear h)
+
+let mkset () =
+ let h = Hashtbl.create 97 in
+ (fun x -> Hashtbl.add h x ()), (Hashtbl.mem h), (fun () -> Hashtbl.clear h)
+
+let mktriset () =
+ let h = Hashtbl.create 97 in
+ (fun x y z -> Hashtbl.add h (x,y,z) ()),
+ (fun x y z -> Hashtbl.mem h (x,y,z)),
+ (fun () -> Hashtbl.clear h)
(* For each [global_reference], this table will contain the different parts
- of its renamings, in [string list] form. *)
-let renamings = Hashtbl.create 97
-let rename r l = Hashtbl.add renamings r l
-let get_renamings r = Hashtbl.find renamings r
+ of its renaming, in [string list] form. *)
+let add_renaming, get_renaming, clear_renaming = mktable ()
(* Idem for [module_path]. *)
-let mp_renamings = Hashtbl.create 97
-let mp_rename mp l = Hashtbl.add mp_renamings mp l
-let mp_get_renamings mp = Hashtbl.find mp_renamings mp
+let add_mp_renaming, get_mp_renaming, clear_mp_renaming = mktable ()
-let modvisited = ref MPset.empty
-let modcontents = ref Gset.empty
-let add_module_contents mp s = modcontents := Gset.add (mp,s) !modcontents
-let module_contents mp s = Gset.mem (mp,s) !modcontents
+(* A table for function modfstlev_rename *)
+let add_modfstlev, get_modfstlev, clear_modfstlev = mktable ()
-let to_qualify = ref Refset.empty
+(* A set of all external objects that will have to be fully qualified *)
+let add_static_clash, static_clash, clear_static_clash = mkset ()
-let mod_1st_level = ref Idmap.empty
+(* Two tables of triplets [kind * module_path * string]. The first one
+ will record the first level of all MPfile, not only the current one.
+ The second table will contains local renamings. *)
-(*s Uppercase/lowercase renamings. *)
+type kind = Term | Type | Cons | Mod
-let is_upper s = match s.[0] with 'A' .. 'Z' -> true | _ -> false
+let add_ext_mpmem, ext_mpmem, clear_ext_mpmem = mktriset ()
+let add_loc_mpmem, loc_mpmem, clear_loc_mpmem = mktriset ()
-let is_lower s = match s.[0] with 'a' .. 'z' | '_' -> true | _ -> false
+(* The list of external modules that will be opened initially *)
+let add_mpfiles, mem_mpfiles, list_mpfiles, clear_mpfiles =
+ let m = ref MPset.empty in
+ (fun mp -> m:= MPset.add mp !m),
+ (fun mp -> MPset.mem mp !m),
+ (fun () -> MPset.elements !m),
+ (fun () -> m:= MPset.empty)
+
+(*s table containing the visible horizon at a precise moment *)
+
+let visible = ref ([] : module_path list)
+let pop_visible () = visible := List.tl !visible
+let push_visible mp = visible := mp :: !visible
+let top_visible_mp () = List.hd !visible
+
+(*s substitutions for printing signatures *)
+
+let substs = ref empty_subst
+let add_subst msid mp = substs := add_msid msid mp !substs
+let subst_mp mp = subst_mp !substs mp
+let subst_kn kn = subst_kn !substs kn
+let subst_con c = fst (subst_con !substs c)
+let subst_ref = function
+ | ConstRef con -> ConstRef (subst_con con)
+ | IndRef (kn,i) -> IndRef (subst_kn kn,i)
+ | ConstructRef ((kn,i),j) -> ConstructRef ((subst_kn kn,i),j)
+ | _ -> assert false
+
+
+let duplicate_index = ref 0
+let to_duplicate = ref Gmap.empty
+let add_duplicate mp l =
+ incr duplicate_index;
+ let ren = "Coq__" ^ string_of_int (!duplicate_index) in
+ to_duplicate := Gmap.add (mp,l) ren !to_duplicate
+let check_duplicate mp l =
+ let mp' = subst_mp mp in
+ Gmap.find (mp',l) !to_duplicate
+
+type reset_kind = OnlyLocal | AllButExternal | Everything
+
+let reset_allbutext () =
+ clear_loc_mpmem ();
+ global_ids := !keywords;
+ clear_renaming ();
+ clear_mp_renaming ();
+ clear_modfstlev ();
+ clear_static_clash ();
+ clear_mpfiles ();
+ duplicate_index := 0;
+ to_duplicate := Gmap.empty;
+ visible := [];
+ substs := empty_subst
+
+let reset_everything () = reset_allbutext (); clear_ext_mpmem ()
+
+let reset_renaming_tables = function
+ | OnlyLocal -> clear_loc_mpmem ()
+ | AllButExternal -> reset_allbutext ()
+ | Everything -> reset_everything ()
+
+(*S Renaming functions *)
(* This function creates from [id] a correct uppercase/lowercase identifier.
This is done by adding a [Coq_] or [coq_] prefix. To avoid potential clashes
@@ -69,389 +245,237 @@ let modular_rename up id =
then prefix ^ s
else s
-let rename_module = modular_rename true
-
-(* [clash mp0 l s mpl] checks if [mp0-l-s] can be printed as [l-s] when
- [mpl] is the context of visible modules. More precisely, we check if
- there exists a mp1, module (sub-)path of an element of [mpl], such as
- module [mp1-l] contains [s].
- The verification stops if we encounter [mp1=mp0]. *)
-
-exception Stop
-
-let clash mp0 l s mpl =
- let rec clash_one mp = match mp with
- | _ when mp = mp0 -> raise Stop
- | MPdot (mp',_) ->
- (module_contents (add_labels_mp mp l) s) || (clash_one mp')
- | mp when is_toplevel mp -> false
- | _ -> module_contents (add_labels_mp mp l) s
+(*s [record_contents_fstlev] finds the names of the first-level objects
+ exported by the ground-level modules in [struc]. *)
+
+let rec record_contents_fstlev struc =
+ let upper_type = (lang () = Haskell) in
+ let addtyp mp id = add_ext_mpmem Type mp (modular_rename upper_type id) in
+ let addcons mp id = add_ext_mpmem Cons mp (modular_rename true id) in
+ let addterm mp id = add_ext_mpmem Term mp (modular_rename false id) in
+ let addmod mp id = add_ext_mpmem Mod mp (modular_rename true id) in
+ let addfix mp r =
+ add_ext_mpmem Term mp (modular_rename false (id_of_global r))
in
- let rec clash_list = function
- | [] -> false
- | mp :: mpl -> (clash_one mp) || (clash_list mpl)
- in try clash_list mpl with Stop -> false
-
-(*s [contents_first_level mp] finds the names of the first-level objects
- exported by module [mp]. Nota: it might fail if [mp] isn't a directly
- visible module. Ex: [MPself] under functor, [MPbound], etc ... *)
-
-let contents_first_level mp =
- if not (MPset.mem mp !modvisited) then begin
- modvisited := MPset.add mp !modvisited;
- match (Global.lookup_module mp).mod_type with
- | MTBsig (msid,msb) ->
- let add b id = add_module_contents mp (modular_rename b id) in
- let upper_type = (lang () = Haskell) in
- List.iter
- (function
- | (l, SPBconst cb) ->
- (match Extraction.constant_kind (Global.env ()) cb with
- | Extraction.Logical -> ()
- | Extraction.Type -> add upper_type (id_of_label l)
- | Extraction.Term -> add false (id_of_label l))
- | (_, SPBmind mib) ->
- Array.iter
- (fun mip -> if snd (Inductive.mind_arity mip) <> InProp
- then begin
- add upper_type mip.mind_typename;
- Array.iter (add true) mip.mind_consnames
- end)
- mib.mind_packets
- | _ -> ())
- (Modops.subst_signature_msid msid mp msb)
- | _ -> ()
- end
+ let f mp = function
+ | (l,SEdecl (Dind (_,ind))) ->
+ Array.iter
+ (fun ip ->
+ addtyp mp ip.ip_typename; Array.iter (addcons mp) ip.ip_consnames)
+ ind.ind_packets
+ | (l,SEdecl (Dtype _)) -> addtyp mp (id_of_label l)
+ | (l,SEdecl (Dterm _)) -> addterm mp (id_of_label l)
+ | (l,SEdecl (Dfix (rv,_,_))) -> Array.iter (addfix mp) rv
+ | (l,SEmodule _) -> addmod mp (id_of_label l)
+ | (l,SEmodtype _) -> addmod mp (id_of_label l)
+ in
+ List.iter (fun (mp,sel) -> List.iter (f mp) sel) struc
-(*s Initial renamings creation, for modular extraction. *)
+(*s For monolithic extraction, first-level modules might have to be renamed
+ with unique numbers *)
+
+let modfstlev_rename l =
+ let coqid = id_of_string "Coq" in
+ let id = id_of_label l in
+ try
+ let coqset = get_modfstlev id in
+ let nextcoq = next_ident_away coqid coqset in
+ add_modfstlev id (nextcoq::coqset);
+ (string_of_id nextcoq)^"_"^(string_of_id id)
+ with Not_found ->
+ let s = string_of_id id in
+ if is_lower s || begins_with_CoqXX s then
+ (add_modfstlev id [coqid]; "Coq_"^s)
+ else
+ (add_modfstlev id []; s)
+
+(*s Creating renaming for a [module_path] *)
-let rec mp_create_modular_renamings mp =
- try mp_get_renamings mp
+let rec mp_create_renaming mp =
+ try get_mp_renaming mp
with Not_found ->
let ren = match mp with
+ | _ when not (modular ()) && at_toplevel mp -> [""]
| MPdot (mp,l) ->
- (rename_module (id_of_label l)) :: (mp_create_modular_renamings mp)
- | MPself msid -> [rename_module (id_of_msid msid)]
- | MPbound mbid -> [rename_module (id_of_mbid mbid)]
- | MPfile f -> [String.capitalize (string_of_id (List.hd (repr_dirpath f)))]
- in mp_rename mp ren; ren
+ let lmp = mp_create_renaming mp in
+ if lmp = [""] then (modfstlev_rename l)::lmp
+ else (modular_rename true (id_of_label l))::lmp
+ | MPself msid -> [modular_rename true (id_of_msid msid)]
+ | MPbound mbid -> [modular_rename true (id_of_mbid mbid)]
+ | MPfile _ when not (modular ()) -> assert false
+ | MPfile _ -> [string_of_modfile mp]
+ in add_mp_renaming mp ren; ren
+
+(* [clash mp0 s mpl] checks if [mp0-s] can be printed as [s] when
+ [mpl] is the context of visible modules. More precisely, we check if
+ there exists a [mp] in [mpl] that contains [s].
+ The verification stops if we encounter [mp=mp0]. *)
+let rec clash mem mp0 s = function
+ | [] -> false
+ | mp :: _ when mp = mp0 -> false
+ | mp :: mpl -> mem mp s || clash mem mp0 s mpl
+
+(*s Initial renamings creation, for modular extraction. *)
let create_modular_renamings struc =
let current_module = fst (List.hd struc) in
- let modfiles = ref MPset.empty in
- let { up = u ; down = d } = struct_get_references_set struc
+ let { typ = ty ; trm = tr ; cons = co } = struct_get_references_set struc
in
(* 1) creates renamings of objects *)
let add upper r =
let mp = modpath_of_r r in
- let l = mp_create_modular_renamings mp in
+ let l = mp_create_renaming mp in
let s = modular_rename upper (id_of_global r) in
- global_ids := Idset.add (id_of_string s) !global_ids;
- rename r (s::l);
+ add_global_ids (id_of_string s);
+ add_renaming r (s::l);
begin try
- let mp = modfile_of_mp mp in
- if mp <> current_module then modfiles := MPset.add mp !modfiles
+ let mp = modfile_of_mp mp in if mp <> current_module then add_mpfiles mp
with Not_found -> ()
end;
in
- Refset.iter (add true) u;
- Refset.iter (add false) d;
+ Refset.iter (add (lang () = Haskell)) ty;
+ Refset.iter (add true) co;
+ Refset.iter (add false) tr;
(* 2) determines the opened libraries. *)
- let used_modules = MPset.elements !modfiles in
-
- (* [s] will contain all first-level sub-modules of [cur_mp] *)
- let s = ref Stringset.empty in
- begin
- let add l = s := Stringset.add (rename_module (id_of_label l)) !s in
- match (Global.lookup_module current_module).mod_type with
- | MTBsig (_,msb) ->
- List.iter (function (l,SPBmodule _) -> add l | _ -> ()) msb
- | _ -> ()
- end;
- (* We now compare [s] with the modules coming from [used_modules]. *)
- 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 used_modules = list_mpfiles () in
+ let used_modules' = List.rev used_modules in
+ let str_list = List.map string_of_modfile used_modules'
+ in
+ let rec check_elsewhere mpl sl = match mpl, sl with
+ | [], [] -> []
+ | mp::mpl, _::sl ->
+ if List.exists (ext_mpmem Mod mp) sl then
+ check_elsewhere mpl sl
+ else mp :: (check_elsewhere mpl sl)
+ | _ -> assert false
+ in
+ let opened_modules = check_elsewhere used_modules' str_list in
+ clear_mpfiles ();
+ List.iter add_mpfiles opened_modules;
(* 3) determines the potential clashes *)
- List.iter contents_first_level used_modules;
- let used_modules' = List.rev used_modules in
- let needs_qualify r =
+ let needs_qualify k r =
let mp = modpath_of_r r in
if (is_modfile mp) && mp <> current_module &&
- (clash mp [] (List.hd (get_renamings r)) used_modules')
- then to_qualify := Refset.add r !to_qualify
+ (clash (ext_mpmem k) mp (List.hd (get_renaming r)) opened_modules)
+ then add_static_clash r
in
- Refset.iter needs_qualify u;
- Refset.iter needs_qualify d;
- used_modules
+ Refset.iter (needs_qualify Type) ty;
+ Refset.iter (needs_qualify Term) tr;
+ Refset.iter (needs_qualify Cons) co;
+ List.rev opened_modules
(*s Initial renamings creation, for monolithic extraction. *)
-let begins_with_CoqXX s =
- (String.length s >= 4) &&
- (String.sub s 0 3 = "Coq") &&
- (try
- for i = 4 to (String.index s '_')-1 do
- match s.[i] with
- | '0'..'9' -> ()
- | _ -> raise Not_found
- done;
- true
- with Not_found -> false)
-
-let mod_1st_level_rename l =
- let coqid = id_of_string "Coq" in
- let id = id_of_label l in
- try
- let coqset = Idmap.find id !mod_1st_level in
- let nextcoq = next_ident_away coqid coqset in
- mod_1st_level := Idmap.add id (nextcoq::coqset) !mod_1st_level;
- (string_of_id nextcoq)^"_"^(string_of_id id)
- with Not_found ->
- let s = string_of_id id in
- if is_lower s || begins_with_CoqXX s then
- (mod_1st_level := Idmap.add id [coqid] !mod_1st_level; "Coq_"^s)
- else
- (mod_1st_level := Idmap.add id [] !mod_1st_level; s)
-
-let rec mp_create_mono_renamings mp =
- try mp_get_renamings mp
- with Not_found ->
- let ren = match mp with
- | _ when (at_toplevel mp) -> [""]
- | MPdot (mp,l) ->
- let lmp = mp_create_mono_renamings mp in
- if lmp = [""] then (mod_1st_level_rename l)::lmp
- else (rename_module (id_of_label l))::lmp
- | MPself msid -> [rename_module (id_of_msid msid)]
- | MPbound mbid -> [rename_module (id_of_mbid mbid)]
- | _ -> assert false
- in mp_rename mp ren; ren
-
let create_mono_renamings struc =
- let { up = u ; down = d } = struct_get_references_list struc in
+ let { typ = ty ; trm = tr ; cons = co } = struct_get_references_list struc in
let add upper r =
let mp = modpath_of_r r in
- let l = mp_create_mono_renamings mp in
+ let l = mp_create_renaming mp in
let mycase = if upper then uppercase_id else lowercase_id in
let id =
if l = [""] then
- next_ident_away (mycase (id_of_global r)) (Idset.elements !global_ids)
+ next_ident_away (mycase (id_of_global r)) (global_ids_list ())
else id_of_string (modular_rename upper (id_of_global r))
in
- global_ids := Idset.add id !global_ids;
- rename r ((string_of_id id)::l)
+ add_global_ids id;
+ add_renaming r ((string_of_id id)::l)
in
- List.iter (add true) (List.rev u);
- List.iter (add false) (List.rev d)
-
-(*s Renaming issues at toplevel *)
-
-module TopParams = struct
- let globals () = Idset.empty
- let pp_global _ r = pr_id (id_of_global r)
- let pp_module _ mp = str (string_of_mp mp)
-end
-
-(*s Renaming issues for a monolithic or modular extraction. *)
-
-module StdParams = struct
-
- let globals () = !global_ids
-
- let unquote s =
- if lang () <> Scheme then s
- else
- let s = String.copy s in
- for i=0 to String.length s - 1 do if s.[i] = '\'' then s.[i] <- '~' done;
- s
-
- let rec dottify = function
- | [] -> assert false
- | [s] -> unquote s
- | s::[""] -> unquote s
- | s::l -> (dottify l)^"."^(unquote s)
-
- let pp_global mpl r =
- let ls = get_renamings r in
- let s = List.hd ls in
- let mp = modpath_of_r r in
- let ls =
- if mp = List.hd mpl then [s] (* simpliest situation *)
- else match lang () with
- | Scheme -> [s] (* no modular Scheme extraction... *)
- | Toplevel -> [s] (* idem *)
- | Haskell ->
- if !modular then
- ls (* for the moment we always qualify in modular Haskell *)
- else [s]
- | Ocaml ->
- try (* has [mp] something in common with one of those in [mpl] ? *)
- let pref = common_prefix_from_list mp mpl in
- (*i TODO: possibilité de clash i*)
- list_firstn ((mp_length mp)-(mp_length pref)+1) ls
- with Not_found -> (* [mp] is othogonal with every element of [mp]. *)
- let base = base_mp mp in
- if !modular &&
- (at_toplevel mp) &&
- not (Refset.mem r !to_qualify) &&
- not (clash base [] s mpl)
- then snd (list_sep_last ls)
- else ls
- in
- add_module_contents mp s; (* update the visible environment *)
- str (dottify ls)
-
- (* The next function is used only in Ocaml extraction...*)
- let pp_module mpl mp =
- let ls =
- if !modular
- then mp_create_modular_renamings mp
- else mp_create_mono_renamings mp
- in
- let ls =
- try (* has [mp] something in common with one of those in [mpl] ? *)
- let pref = common_prefix_from_list mp mpl in
- (*i TODO: clash possible i*)
- list_firstn ((mp_length mp)-(mp_length pref)) ls
- with Not_found -> (* [mp] is othogonal with every element of [mp]. *)
- if !modular && (at_toplevel mp)
- then snd (list_sep_last ls)
- else ls
- in str (dottify ls)
-
-end
-
-module ToplevelPp = Ocaml.Make(TopParams)
-module OcamlPp = Ocaml.Make(StdParams)
-module HaskellPp = Haskell.Make(StdParams)
-module SchemePp = Scheme.Make(StdParams)
-
-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
- | Ocaml -> keywords := Ocaml.keywords
- | Haskell -> keywords := Haskell.keywords
- | Scheme -> keywords := Scheme.keywords
- | Toplevel -> keywords := Idset.empty);
- global_ids := !keywords;
- to_qualify := Refset.empty
+ List.iter (add (lang () = Haskell)) (List.rev ty);
+ List.iter (add false) (List.rev tr);
+ List.iter (add true) (List.rev co);
+ []
+
+let create_renamings struc =
+ if modular () then create_modular_renamings struc
+ else create_mono_renamings struc
-let preamble prm = match lang () with
- | Ocaml -> Ocaml.preamble prm
- | Haskell -> Haskell.preamble prm
- | 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 info f =
- Options.if_verbose msgnl
- (str ("The file "^f^" has been created by extraction."))
-
-let print_structure_to_file f prm struc =
- Hashtbl.clear renamings;
- mod_1st_level := Idmap.empty;
- modcontents := Gset.empty;
- modvisited := MPset.empty;
- set_keywords ();
- 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 print_dummys =
- (struct_ast_search ((=) MLdummy) struc,
- struct_type_search Mlutil.isDummy struc,
- struct_type_search ((=) Tunknown) struc)
- in
- let print_magic =
- if lang () <> Haskell then false
- else struct_ast_search (function MLmagic _ -> true | _ -> false) struc
- in
- (* print the implementation *)
- let cout = option_map (fun (f,_) -> open_out f) f in
- let ft = match cout with
- | None -> !Pp_control.std_ft
- | Some cout -> Pp_control.with_output_to cout in
- begin try
- msg_with ft (preamble prm used_modules print_dummys print_magic);
- msg_with ft (pp_struct struc);
- option_iter close_out cout;
- with e ->
- option_iter close_out cout; raise e
- end;
- option_iter (fun (f,_) -> info f) f;
- (* 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;
- info f
- | _ -> ()
-
-
-(*i
- (* DO NOT REMOVE: used when making names resolution *)
- let cout = open_out (f^".ren") in
- let ft = Pp_control.with_output_to cout in
- Hashtbl.iter
- (fun r id ->
- if short_module r = !current_module then
- msgnl_with ft (pr_id id ++ str " " ++ pr_sp (sp_of_r r)))
- renamings;
- pp_flush_with ft ();
- close_out cout;
-i*)
-
-
-
-
-
-
+
+(*s On-the-fly qualification issues for both monolithic or modular extraction. *)
+
+let pp_global k r =
+ let ls = get_renaming r in
+ assert (List.length ls > 1);
+ let s = List.hd ls in
+ let mp = modpath_of_r r in
+ if mp = top_visible_mp () then
+ (* simpliest situation: definition of r (or use in the same context) *)
+ (* we update the visible environment *)
+ (add_loc_mpmem k mp s; unquote s)
+ else match lang () with
+ | Scheme -> unquote s (* no modular Scheme extraction... *)
+ | Haskell ->
+ (* for the moment we always qualify in modular Haskell *)
+ if modular () then dottify ls else s
+ | Ocaml ->
+ try (* has [mp] something in common with one of [!visible] ? *)
+ let prefix = common_prefix_from_list mp !visible in
+ let delta = mp_length mp - mp_length prefix in
+ let ls = list_firstn (delta+1) ls in
+ (* Difficulty: in ocaml we cannot qualify more than [ls],
+ but this (not-so-long) name can in fact be hidden. Solution:
+ duplication of the _definition_ of r in a Coq__XXX module *)
+ let s,ls' = list_sep_last ls in
+ let k' = if ls' = [] then k else Mod in
+ if clash (loc_mpmem k') prefix s !visible then
+ let front = if ls' = [] then [s] else ls' in
+ let l = get_nth_label delta r in
+ try dottify (front @ [check_duplicate prefix l])
+ with Not_found -> add_duplicate prefix l; dottify ls
+ else dottify ls
+ with Not_found ->
+ (* [mp] belongs to a closed module, not one of [!visible]. *)
+ let base = base_mp mp in
+ let base_s,ls1 = list_sep_last ls in
+ let s,ls2 = list_sep_last ls1 in
+ let k' = if ls2 = [] then k else Mod in
+ if modular () && (mem_mpfiles base) &&
+ not (static_clash r) &&
+ (* k' = Mod can't clash in an opened module, see earlier check *)
+ not (clash (loc_mpmem k') base s !visible)
+ then (* Standard situation of an object in another file: *)
+ (* Thanks to the "open" of this file we remove its name *)
+ dottify ls1
+ else if clash (loc_mpmem Mod) base base_s !visible then
+ error_module_clash base_s
+ else dottify ls
+
+(* The next function is used only in Ocaml extraction...*)
+let pp_module mp =
+ let ls = mp_create_renaming mp in
+ if List.length ls = 1 then dottify ls
+ else match mp with
+ | MPdot (mp0,_) when mp0 = top_visible_mp () ->
+ (* simpliest situation: definition of mp (or use in the same context) *)
+ (* we update the visible environment *)
+ let s = List.hd ls in
+ add_loc_mpmem Mod mp0 s; s
+ | _ ->
+ try (* has [mp] something in common with one of those in [!visible] ? *)
+ let prefix = common_prefix_from_list mp !visible in
+ assert (mp <> prefix); (* no use of mp as whole module from itself *)
+ let delta = mp_length mp - mp_length prefix in
+ let ls = list_firstn delta ls in
+ (* Difficulty: in ocaml we cannot qualify more than [ls],
+ but this (not-so-long) name can in fact be hidden. Solution:
+ duplication of the _definition_ of mp via a Coq__XXX module *)
+ let s,ls' = list_sep_last ls in
+ if clash (loc_mpmem Mod) prefix s !visible then
+ let l = get_nth_label_mp delta mp in
+ try dottify (ls' @ [check_duplicate prefix l])
+ with Not_found -> add_duplicate prefix l; dottify ls
+ else dottify ls
+ with Not_found ->
+ (* [mp] belongs to a closed module, not one of [!visible]. *)
+ let base = base_mp mp in
+ let base_s,ls' = list_sep_last ls in
+ let s = fst (list_sep_last ls) in
+ if modular () && (mem_mpfiles base) &&
+ not (clash (loc_mpmem Mod) base s !visible)
+ then dottify ls'
+ else if clash (loc_mpmem Mod) base base_s !visible then
+ error_module_clash base_s
+ else dottify ls