aboutsummaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/coqlib.ml323
-rw-r--r--library/coqlib.mli300
-rw-r--r--library/decl_kinds.ml75
-rw-r--r--library/declaremods.ml1015
-rw-r--r--library/declaremods.mli144
-rw-r--r--library/decls.ml46
-rw-r--r--library/decls.mli36
-rw-r--r--library/doc.tex16
-rw-r--r--library/dune9
-rw-r--r--library/global.ml191
-rw-r--r--library/global.mli169
-rw-r--r--library/globnames.ml139
-rw-r--r--library/globnames.mli84
-rw-r--r--library/goptions.ml436
-rw-r--r--library/goptions.mli185
-rw-r--r--library/keys.ml159
-rw-r--r--library/keys.mli23
-rw-r--r--library/kindops.ml37
-rw-r--r--library/kindops.mli17
-rw-r--r--library/lib.ml668
-rw-r--r--library/lib.mli199
-rw-r--r--library/libnames.ml171
-rw-r--r--library/libnames.mli102
-rw-r--r--library/libobject.ml174
-rw-r--r--library/libobject.mli169
-rw-r--r--library/library.ml750
-rw-r--r--library/library.mli82
-rw-r--r--library/library.mllib17
-rw-r--r--library/loadpath.ml119
-rw-r--r--library/loadpath.mli57
-rw-r--r--library/nametab.ml594
-rw-r--r--library/nametab.mli262
-rw-r--r--library/states.ml43
-rw-r--r--library/states.mli36
-rw-r--r--library/summary.ml165
-rw-r--r--library/summary.mli90
36 files changed, 7102 insertions, 0 deletions
diff --git a/library/coqlib.ml b/library/coqlib.ml
new file mode 100644
index 0000000000..784360dc8a
--- /dev/null
+++ b/library/coqlib.ml
@@ -0,0 +1,323 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open CErrors
+open Util
+open Pp
+open Names
+open Libnames
+open Globnames
+
+let make_dir l = DirPath.make (List.rev_map Id.of_string l)
+
+(************************************************************************)
+(* Coq reference API *)
+(************************************************************************)
+let coq = Libnames.coq_string (* "Coq" *)
+
+let init_dir = [ coq; "Init"]
+
+let jmeq_module_name = [coq;"Logic";"JMeq"]
+let jmeq_library_path = make_dir jmeq_module_name
+let jmeq_module = MPfile jmeq_library_path
+
+let find_reference locstr dir s =
+ let dp = make_dir dir in
+ let sp = Libnames.make_path dp (Id.of_string s) in
+ Nametab.global_of_path sp
+
+let coq_reference locstr dir s = find_reference locstr (coq::dir) s
+
+let table : GlobRef.t CString.Map.t ref =
+ let name = "coqlib_registered" in
+ Summary.ref ~name CString.Map.empty
+
+let get_lib_refs () =
+ CString.Map.bindings !table
+
+let has_ref s = CString.Map.mem s !table
+
+let check_ind_ref s ind =
+ match CString.Map.find s !table with
+ | IndRef r -> eq_ind r ind
+ | _ -> false
+ | exception Not_found -> false
+
+let lib_ref s =
+ try CString.Map.find s !table
+ with Not_found ->
+ user_err Pp.(str "not found in table: " ++ str s)
+
+let add_ref s c =
+ table := CString.Map.add s c !table
+
+let cache_ref (_,(s,c)) =
+ add_ref s c
+
+let (inCoqlibRef : string * GlobRef.t -> Libobject.obj) =
+ let open Libobject in
+ declare_object { (default_object "COQLIBREF") with
+ cache_function = cache_ref;
+ load_function = (fun _ x -> cache_ref x);
+ classify_function = (fun o -> Substitute o);
+ subst_function = ident_subst_function;
+ discharge_function = fun (_, sc) -> Some sc }
+
+(** Replaces a binding ! *)
+let register_ref s c =
+ Lib.add_anonymous_leaf @@ inCoqlibRef (s,c)
+
+(************************************************************************)
+(* Generic functions to find Coq objects *)
+
+let has_suffix_in_dirs dirs ref =
+ let dir = dirpath (Nametab.path_of_global ref) in
+ List.exists (fun d -> is_dirpath_prefix_of d dir) dirs
+
+let gen_reference_in_modules locstr dirs s =
+ let dirs = List.map make_dir dirs in
+ let qualid = qualid_of_string s in
+ let all = Nametab.locate_all qualid in
+ let all = List.sort_uniquize GlobRef.Ordered_env.compare all in
+ let these = List.filter (has_suffix_in_dirs dirs) all in
+ match these with
+ | [x] -> x
+ | [] ->
+ anomaly ~label:locstr (str "cannot find " ++ str s ++
+ str " in module" ++ str (if List.length dirs > 1 then "s " else " ") ++
+ prlist_with_sep pr_comma DirPath.print dirs ++ str ".")
+ | l ->
+ anomaly ~label:locstr
+ (str "ambiguous name " ++ str s ++ str " can represent " ++
+ prlist_with_sep pr_comma
+ (fun x -> Libnames.pr_path (Nametab.path_of_global x)) l ++
+ str " in module" ++ str (if List.length dirs > 1 then "s " else " ") ++
+ prlist_with_sep pr_comma DirPath.print dirs ++ str ".")
+
+(* For tactics/commands requiring vernacular libraries *)
+
+let check_required_library d =
+ let dir = make_dir d in
+ if Library.library_is_loaded dir then ()
+ else
+ let in_current_dir = match Lib.current_mp () with
+ | MPfile dp -> DirPath.equal dir dp
+ | _ -> false
+ in
+ if not in_current_dir then
+ user_err ~hdr:"Coqlib.check_required_library"
+ (str "Library " ++ DirPath.print dir ++ str " has to be required first.")
+
+(************************************************************************)
+(* Specific Coq objects *)
+(************************************************************************)
+
+let arith_dir = [coq;"Arith"]
+let arith_modules = [arith_dir]
+
+let numbers_dir = [coq;"Numbers"]
+let parith_dir = [coq;"PArith"]
+let narith_dir = [coq;"NArith"]
+let zarith_dir = [coq;"ZArith"]
+
+let zarith_base_modules = [numbers_dir;parith_dir;narith_dir;zarith_dir]
+
+let init_modules = [
+ init_dir@["Datatypes"];
+ init_dir@["Logic"];
+ init_dir@["Specif"];
+ init_dir@["Logic_Type"];
+ init_dir@["Nat"];
+ init_dir@["Peano"];
+ init_dir@["Wf"]
+]
+
+let logic_module_name = init_dir@["Logic"]
+let logic_module = MPfile (make_dir logic_module_name)
+
+let logic_type_module_name = init_dir@["Logic_Type"]
+let logic_type_module = make_dir logic_type_module_name
+
+let datatypes_module_name = init_dir@["Datatypes"]
+let datatypes_module = MPfile (make_dir datatypes_module_name)
+
+(** Identity *)
+
+let id = Constant.make2 datatypes_module @@ Label.make "idProp"
+let type_of_id = Constant.make2 datatypes_module @@ Label.make "IDProp"
+
+(** Natural numbers *)
+let nat_kn = MutInd.make2 datatypes_module @@ Label.make "nat"
+let nat_path = Libnames.make_path (make_dir datatypes_module_name) (Id.of_string "nat")
+
+let glob_nat = IndRef (nat_kn,0)
+
+let path_of_O = ((nat_kn,0),1)
+let path_of_S = ((nat_kn,0),2)
+let glob_O = ConstructRef path_of_O
+let glob_S = ConstructRef path_of_S
+
+(** Booleans *)
+let bool_kn = MutInd.make2 datatypes_module @@ Label.make "bool"
+
+let glob_bool = IndRef (bool_kn,0)
+
+let path_of_true = ((bool_kn,0),1)
+let path_of_false = ((bool_kn,0),2)
+let glob_true = ConstructRef path_of_true
+let glob_false = ConstructRef path_of_false
+
+(** Equality *)
+let eq_kn = MutInd.make2 logic_module @@ Label.make "eq"
+let glob_eq = IndRef (eq_kn,0)
+
+let identity_kn = MutInd.make2 datatypes_module @@ Label.make "identity"
+let glob_identity = IndRef (identity_kn,0)
+
+let jmeq_kn = MutInd.make2 jmeq_module @@ Label.make "JMeq"
+let glob_jmeq = IndRef (jmeq_kn,0)
+
+(* Sigma data *)
+type coq_sigma_data = {
+ proj1 : GlobRef.t;
+ proj2 : GlobRef.t;
+ elim : GlobRef.t;
+ intro : GlobRef.t;
+ typ : GlobRef.t }
+
+let build_sigma_gen str =
+ { typ = lib_ref ("core." ^ str ^ ".type");
+ elim = lib_ref ("core." ^ str ^ ".rect");
+ intro = lib_ref ("core." ^ str ^ ".intro");
+ proj1 = lib_ref ("core." ^ str ^ ".proj1");
+ proj2 = lib_ref ("core." ^ str ^ ".proj2");
+ }
+
+let build_prod () = build_sigma_gen "prod"
+let build_sigma () = build_sigma_gen "sig"
+let build_sigma_type () = build_sigma_gen "sigT"
+
+(* Booleans *)
+
+type coq_bool_data = {
+ andb : GlobRef.t;
+ andb_prop : GlobRef.t;
+ andb_true_intro : GlobRef.t}
+
+let build_bool_type () =
+ { andb = lib_ref "core.bool.andb";
+ andb_prop = lib_ref "core.bool.andb_prop";
+ andb_true_intro = lib_ref "core.bool.andb_true_intro"; }
+
+(* Equalities *)
+type coq_eq_data = {
+ eq : GlobRef.t;
+ ind : GlobRef.t;
+ refl : GlobRef.t;
+ sym : GlobRef.t;
+ trans: GlobRef.t;
+ congr: GlobRef.t }
+
+(* Leibniz equality on Type *)
+
+let build_eqdata_gen str = {
+ eq = lib_ref ("core." ^ str ^ ".type");
+ ind = lib_ref ("core." ^ str ^ ".ind");
+ refl = lib_ref ("core." ^ str ^ ".refl");
+ sym = lib_ref ("core." ^ str ^ ".sym");
+ trans = lib_ref ("core." ^ str ^ ".trans");
+ congr = lib_ref ("core." ^ str ^ ".congr");
+ }
+
+let build_coq_eq_data () = build_eqdata_gen "eq"
+let build_coq_jmeq_data () = build_eqdata_gen "JMeq"
+let build_coq_identity_data () = build_eqdata_gen "identity"
+
+(* Inversion data... *)
+
+(* Data needed for discriminate and injection *)
+type coq_inversion_data = {
+ inv_eq : GlobRef.t; (* : forall params, t -> Prop *)
+ inv_ind : GlobRef.t; (* : forall params P y, eq params y -> P y *)
+ inv_congr: GlobRef.t (* : forall params B (f:t->B) y, eq params y -> f c=f y *)
+}
+
+let build_coq_inversion_gen l str =
+ List.iter check_required_library l; {
+ inv_eq = lib_ref ("core." ^ str ^ ".type");
+ inv_ind = lib_ref ("core." ^ str ^ ".ind");
+ inv_congr = lib_ref ("core." ^ str ^ ".congr_canonical");
+ }
+
+let build_coq_inversion_eq_data () =
+ build_coq_inversion_gen [logic_module_name] "eq"
+
+let build_coq_inversion_eq_true_data () =
+ build_coq_inversion_gen [logic_module_name] "True"
+
+let build_coq_inversion_identity_data () =
+ build_coq_inversion_gen [logic_module_name] "identity"
+
+(* This needs a special case *)
+let build_coq_inversion_jmeq_data () = {
+ inv_eq = lib_ref "core.JMeq.hom";
+ inv_ind = lib_ref "core.JMeq.ind";
+ inv_congr = lib_ref "core.JMeq.congr_canonical";
+}
+
+(* Specif *)
+let build_coq_sumbool () = lib_ref "core.sumbool.type"
+
+let build_coq_eq () = lib_ref "core.eq.type"
+let build_coq_eq_refl () = lib_ref "core.eq.refl"
+let build_coq_eq_sym () = lib_ref "core.eq.sym"
+let build_coq_f_equal2 () = lib_ref "core.eq.congr2"
+
+(* Runtime part *)
+let build_coq_True () = lib_ref "core.True.type"
+let build_coq_I () = lib_ref "core.True.I"
+let build_coq_identity () = lib_ref "core.identity.type"
+
+let build_coq_eq_true () = lib_ref "core.eq_true.type"
+let build_coq_jmeq () = lib_ref "core.JMeq.type"
+
+let build_coq_prod () = lib_ref "core.prod.type"
+let build_coq_pair () = lib_ref "core.prod.intro"
+
+let build_coq_False () = lib_ref "core.False.type"
+let build_coq_not () = lib_ref "core.not.type"
+let build_coq_and () = lib_ref "core.and.type"
+let build_coq_conj () = lib_ref "core.and.conj"
+let build_coq_or () = lib_ref "core.or.type"
+let build_coq_ex () = lib_ref "core.ex.type"
+let build_coq_sig () = lib_ref "core.sig.type"
+let build_coq_existT () = lib_ref "core.sigT.existT"
+let build_coq_iff () = lib_ref "core.iff.type"
+
+let build_coq_iff_left_proj () = lib_ref "core.iff.proj1"
+let build_coq_iff_right_proj () = lib_ref "core.iff.proj2"
+
+(* The following is less readable but does not depend on parsing *)
+let coq_eq_ref = Lazy.from_fun build_coq_eq
+let coq_identity_ref = Lazy.from_fun build_coq_identity
+let coq_jmeq_ref = Lazy.from_fun build_coq_jmeq
+let coq_eq_true_ref = Lazy.from_fun build_coq_eq_true
+let coq_existS_ref = Lazy.from_fun build_coq_existT
+let coq_existT_ref = Lazy.from_fun build_coq_existT
+let coq_exist_ref = Lazy.from_fun build_coq_ex
+let coq_not_ref = Lazy.from_fun build_coq_not
+let coq_False_ref = Lazy.from_fun build_coq_False
+let coq_sumbool_ref = Lazy.from_fun build_coq_sumbool
+let coq_sig_ref = Lazy.from_fun build_coq_sig
+let coq_or_ref = Lazy.from_fun build_coq_or
+let coq_iff_ref = Lazy.from_fun build_coq_iff
+
+(** Deprecated functions that search by library name. *)
+let build_sigma_set () = anomaly (Pp.str "Use build_sigma_type.")
diff --git a/library/coqlib.mli b/library/coqlib.mli
new file mode 100644
index 0000000000..f6779dbbde
--- /dev/null
+++ b/library/coqlib.mli
@@ -0,0 +1,300 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Util
+open Names
+
+(** Indirection between logical names and global references.
+
+ This module provides a mechanism to bind “names” to constants and to look up
+ these constants using their names.
+
+ The two main functions are [register_ref n r] which binds the name [n] to
+ the reference [r] and [lib_ref n] which returns the previously registered
+ reference under name [n].
+
+ The first function is meant to be available through the vernacular command
+ [Register r as n], so that plug-ins can refer to a constant without knowing
+ its user-facing name, the precise module path in which it is defined, etc.
+
+ For instance, [lib_ref "core.eq.type"] returns the proper [GlobRef.t] for
+ the type of the core equality type.
+*)
+
+(** Registers a global reference under the given name. *)
+val register_ref : string -> GlobRef.t -> unit
+
+(** Retrieves the reference bound to the given name (by a previous call to {!register_ref}).
+ Raises an error if no reference is bound to this name. *)
+val lib_ref : string -> GlobRef.t
+
+(** Checks whether a name refers to a registered constant.
+ For any name [n], if [has_ref n] returns [true], [lib_ref n] will succeed. *)
+val has_ref : string -> bool
+
+(** Checks whether a name is bound to a known inductive. *)
+val check_ind_ref : string -> inductive -> bool
+
+(** List of all currently bound names. *)
+val get_lib_refs : unit -> (string * GlobRef.t) list
+
+(* Exceptions to deprecation *)
+
+(** {2 For Equality tactics} *)
+
+type coq_sigma_data = {
+ proj1 : GlobRef.t;
+ proj2 : GlobRef.t;
+ elim : GlobRef.t;
+ intro : GlobRef.t;
+ typ : GlobRef.t }
+
+val build_sigma_set : coq_sigma_data delayed
+val build_sigma_type : coq_sigma_data delayed
+val build_sigma : coq_sigma_data delayed
+
+type coq_eq_data = {
+ eq : GlobRef.t;
+ ind : GlobRef.t;
+ refl : GlobRef.t;
+ sym : GlobRef.t;
+ trans: GlobRef.t;
+ congr: GlobRef.t }
+
+val build_coq_eq_data : coq_eq_data delayed
+val build_coq_identity_data : coq_eq_data delayed
+val build_coq_jmeq_data : coq_eq_data delayed
+
+(* XXX: Some tactics special case JMeq, they should instead check for
+ the constant, not the module *)
+(** For tactics/commands requiring vernacular libraries *)
+val check_required_library : string list -> unit
+
+(* Used by obligations *)
+val datatypes_module_name : string list
+
+(* Used by ind_schemes *)
+val logic_module_name : string list
+
+(* Used by tactics *)
+val jmeq_module_name : string list
+
+
+(*************************************************************************)
+(** {2 DEPRECATED} *)
+(*************************************************************************)
+
+(** All the functions below are deprecated and should go away in the
+ next coq version ... *)
+
+(** [find_reference caller_message [dir;subdir;...] s] returns a global
+ reference to the name dir.subdir.(...).s; the corresponding module
+ must have been required or in the process of being compiled so that
+ it must be used lazily; it raises an anomaly with the given message
+ if not found *)
+val find_reference : string -> string list -> string -> GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** This just prefixes find_reference with Coq... *)
+val coq_reference : string -> string list -> string -> GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Search in several modules (not prefixed by "Coq") *)
+val gen_reference_in_modules : string->string list list-> string -> GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val arith_modules : string list list
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val zarith_base_modules : string list list
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val init_modules : string list list
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** {6 Global references } *)
+
+(** Modules *)
+val logic_module : ModPath.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val logic_type_module : DirPath.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Identity *)
+val id : Constant.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val type_of_id : Constant.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Natural numbers *)
+
+val nat_path : Libnames.full_path
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val glob_nat : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val path_of_O : constructor
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val path_of_S : constructor
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val glob_O : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val glob_S : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Booleans *)
+val glob_bool : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val path_of_true : constructor
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val path_of_false : constructor
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val glob_true : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val glob_false : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Equality *)
+val glob_eq : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val glob_identity : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val glob_jmeq : GlobRef.t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** {6 ... } *)
+(** Constructions and patterns related to Coq initial state are unknown
+ at compile time. Therefore, we can only provide methods to build
+ them at runtime. This is the purpose of the [constr delayed] and
+ [constr_pattern delayed] types. Objects of this time needs to be
+ forced with [delayed_force] to get the actual constr or pattern
+ at runtime. *)
+
+type coq_bool_data = {
+ andb : GlobRef.t;
+ andb_prop : GlobRef.t;
+ andb_true_intro : GlobRef.t
+}
+
+val build_bool_type : coq_bool_data delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Non-dependent pairs in Set from Datatypes *)
+val build_prod : coq_sigma_data delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val build_coq_eq : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+(** = [(build_coq_eq_data()).eq] *)
+
+val build_coq_eq_refl : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+(** = [(build_coq_eq_data()).refl] *)
+
+val build_coq_eq_sym : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+(** = [(build_coq_eq_data()).sym] *)
+
+val build_coq_f_equal2 : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Data needed for discriminate and injection *)
+
+type coq_inversion_data = {
+ inv_eq : GlobRef.t; (** : forall params, args -> Prop *)
+ inv_ind : GlobRef.t; (** : forall params P (H : P params) args, eq params args
+ -> P args *)
+ inv_congr: GlobRef.t (** : forall params B (f:t->B) args, eq params args ->
+ f params = f args *)
+}
+
+val build_coq_inversion_eq_data : coq_inversion_data delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_inversion_identity_data : coq_inversion_data delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_inversion_jmeq_data : coq_inversion_data delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_inversion_eq_true_data : coq_inversion_data delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Specif *)
+val build_coq_sumbool : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** {6 ... }
+ Connectives
+ The False proposition *)
+val build_coq_False : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** The True proposition and its unique proof *)
+val build_coq_True : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_I : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Negation *)
+val build_coq_not : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Conjunction *)
+val build_coq_and : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_conj : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_iff : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val build_coq_iff_left_proj : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_iff_right_proj : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Pairs *)
+val build_coq_prod : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val build_coq_pair : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Disjunction *)
+val build_coq_or : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+(** Existential quantifier *)
+val build_coq_ex : GlobRef.t delayed
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val coq_eq_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_identity_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_jmeq_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_eq_true_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_existS_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_existT_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_exist_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_not_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_False_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_sumbool_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_sig_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+
+val coq_or_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
+val coq_iff_ref : GlobRef.t lazy_t
+[@@ocaml.deprecated "Please use Coqlib.lib_ref"]
diff --git a/library/decl_kinds.ml b/library/decl_kinds.ml
new file mode 100644
index 0000000000..171d51800e
--- /dev/null
+++ b/library/decl_kinds.ml
@@ -0,0 +1,75 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** Informal mathematical status of declarations *)
+
+type discharge = DoDischarge | NoDischarge
+
+type locality = Discharge | Local | Global
+
+type binding_kind = Explicit | Implicit
+
+type polymorphic = bool
+
+type private_flag = bool
+
+type cumulative_inductive_flag = bool
+
+type theorem_kind =
+ | Theorem
+ | Lemma
+ | Fact
+ | Remark
+ | Property
+ | Proposition
+ | Corollary
+
+type definition_object_kind =
+ | Definition
+ | Coercion
+ | SubClass
+ | CanonicalStructure
+ | Example
+ | Fixpoint
+ | CoFixpoint
+ | Scheme
+ | StructureComponent
+ | IdentityCoercion
+ | Instance
+ | Method
+ | Let
+
+type assumption_object_kind = Definitional | Logical | Conjectural
+
+(* [assumption_kind]
+
+ | Local | Global
+ ------------------------------------
+ Definitional | Variable | Parameter
+ Logical | Hypothesis | Axiom
+
+*)
+type assumption_kind = locality * polymorphic * assumption_object_kind
+type definition_kind = locality * polymorphic * definition_object_kind
+
+(** Kinds used in proofs *)
+
+type goal_object_kind =
+ | DefinitionBody of definition_object_kind
+ | Proof of theorem_kind
+
+type goal_kind = locality * polymorphic * goal_object_kind
+
+(** Kinds used in library *)
+
+type logical_kind =
+ | IsAssumption of assumption_object_kind
+ | IsDefinition of definition_object_kind
+ | IsProof of theorem_kind
diff --git a/library/declaremods.ml b/library/declaremods.ml
new file mode 100644
index 0000000000..8699583cdf
--- /dev/null
+++ b/library/declaremods.ml
@@ -0,0 +1,1015 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+open CErrors
+open Util
+open Names
+open Declarations
+open Entries
+open Libnames
+open Libobject
+open Mod_subst
+
+(** {6 Inlining levels} *)
+
+(** Rigid / flexible module signature *)
+
+type 'a module_signature =
+ | Enforce of 'a (** ... : T *)
+ | Check of 'a list (** ... <: T1 <: T2, possibly empty *)
+
+(** Which module inline annotations should we honor,
+ either None or the ones whose level is less or equal
+ to the given integer *)
+
+type inline =
+ | NoInline
+ | DefaultInline
+ | InlineAt of int
+
+type module_kind = Module | ModType | ModAny
+
+let default_inline () = Some (Flags.get_inline_level ())
+
+let inl2intopt = function
+ | NoInline -> None
+ | InlineAt i -> Some i
+ | DefaultInline -> default_inline ()
+
+(** {6 Substitutive objects}
+
+ - The list of bound identifiers is nonempty only if the objects
+ are owned by a functor
+
+ - Then comes either the object segment itself (for interactive
+ modules), or a compact way to store derived objects (path to
+ a earlier module + subtitution).
+*)
+
+type algebraic_objects =
+ | Objs of Lib.lib_objects
+ | Ref of ModPath.t * substitution
+
+type substitutive_objects = MBId.t list * algebraic_objects
+
+(** ModSubstObjs : a cache of module substitutive objects
+
+ This table is common to modules and module types.
+ - For a Module M:=N, the objects of N will be reloaded
+ with M after substitution.
+ - For a Module M:SIG:=..., the module M gets its objects from SIG
+
+ Invariants:
+ - A alias (i.e. a module path inside a Ref constructor) should
+ never lead to another alias, but rather to a concrete Objs
+ constructor.
+
+ We will plug later a handler dealing with missing entries in the
+ cache. Such missing entries may come from inner parts of module
+ types, which aren't registered by the standard libobject machinery.
+*)
+
+module ModSubstObjs :
+ sig
+ val set : ModPath.t -> substitutive_objects -> unit
+ val get : ModPath.t -> substitutive_objects
+ val set_missing_handler : (ModPath.t -> substitutive_objects) -> unit
+ end =
+ struct
+ let table =
+ Summary.ref (MPmap.empty : substitutive_objects MPmap.t)
+ ~name:"MODULE-SUBSTOBJS"
+ let missing_handler = ref (fun mp -> assert false)
+ let set_missing_handler f = (missing_handler := f)
+ let set mp objs = (table := MPmap.add mp objs !table)
+ let get mp =
+ try MPmap.find mp !table with Not_found -> !missing_handler mp
+ end
+
+(** Some utilities about substitutive objects :
+ substitution, expansion *)
+
+let sobjs_no_functor (mbids,_) = List.is_empty mbids
+
+let subst_aobjs sub = function
+ | Objs o -> Objs (Lib.subst_objects sub o)
+ | Ref (mp, sub0) -> Ref (mp, join sub0 sub)
+
+let subst_sobjs sub (mbids,aobjs) = (mbids, subst_aobjs sub aobjs)
+
+let expand_aobjs = function
+ | Objs o -> o
+ | Ref (mp, sub) ->
+ match ModSubstObjs.get mp with
+ | (_,Objs o) -> Lib.subst_objects sub o
+ | _ -> assert false (* Invariant : any alias points to concrete objs *)
+
+let expand_sobjs (_,aobjs) = expand_aobjs aobjs
+
+
+(** {6 ModObjs : a cache of module objects}
+
+ For each module, we also store a cache of
+ "prefix", "substituted objects", "keep objects".
+ This is used for instance to implement the "Import" command.
+
+ substituted objects :
+ roughly the objects above after the substitution - we need to
+ keep them to call open_object when the module is opened (imported)
+
+ keep objects :
+ The list of non-substitutive objects - as above, for each of
+ them we will call open_object when the module is opened
+
+ (Some) Invariants:
+ * If the module is a functor, it won't appear in this cache.
+
+ * Module objects in substitutive_objects part have empty substituted
+ objects.
+
+ * Modules which where created with Module M:=mexpr or with
+ Module M:SIG. ... End M. have the keep list empty.
+*)
+
+type module_objects = Nametab.object_prefix * Lib.lib_objects * Lib.lib_objects
+
+module ModObjs :
+ sig
+ val set : ModPath.t -> module_objects -> unit
+ val get : ModPath.t -> module_objects (* may raise Not_found *)
+ val all : unit -> module_objects MPmap.t
+ end =
+ struct
+ let table =
+ Summary.ref (MPmap.empty : module_objects MPmap.t)
+ ~name:"MODULE-OBJS"
+ let set mp objs = (table := MPmap.add mp objs !table)
+ let get mp = MPmap.find mp !table
+ let all () = !table
+ end
+
+
+(** {6 Name management}
+
+ Auxiliary functions to transform full_path and kernel_name given
+ by Lib into ModPath.t and DirPath.t needed for modules
+*)
+
+let mp_of_kn kn =
+ let mp,l = KerName.repr kn in
+ MPdot (mp,l)
+
+let dir_of_sp sp =
+ let dir,id = repr_path sp in
+ add_dirpath_suffix dir id
+
+
+(** {6 Declaration of module substitutive objects} *)
+
+(** These functions register the visibility of the module and iterates
+ through its components. They are called by plenty of module functions *)
+
+let consistency_checks exists dir dirinfo =
+ if exists then
+ let globref =
+ try Nametab.locate_dir (qualid_of_dirpath dir)
+ with Not_found ->
+ user_err ~hdr:"consistency_checks"
+ (DirPath.print dir ++ str " should already exist!")
+ in
+ assert (Nametab.GlobDirRef.equal globref dirinfo)
+ else
+ if Nametab.exists_dir dir then
+ user_err ~hdr:"consistency_checks"
+ (DirPath.print dir ++ str " already exists")
+
+let compute_visibility exists i =
+ if exists then Nametab.Exactly i else Nametab.Until i
+
+(** Iterate some function [iter_objects] on all components of a module *)
+
+let do_module exists iter_objects i obj_dir obj_mp sobjs kobjs =
+ let prefix = Nametab.{ obj_dir ; obj_mp; obj_sec = DirPath.empty } in
+ let dirinfo = Nametab.GlobDirRef.DirModule prefix in
+ consistency_checks exists obj_dir dirinfo;
+ Nametab.push_dir (compute_visibility exists i) obj_dir dirinfo;
+ ModSubstObjs.set obj_mp sobjs;
+ (* If we're not a functor, let's iter on the internal components *)
+ if sobjs_no_functor sobjs then begin
+ let objs = expand_sobjs sobjs in
+ ModObjs.set obj_mp (prefix,objs,kobjs);
+ iter_objects (i+1) prefix objs;
+ iter_objects (i+1) prefix kobjs
+ end
+
+let do_module' exists iter_objects i ((sp,kn),sobjs) =
+ do_module exists iter_objects i (dir_of_sp sp) (mp_of_kn kn) sobjs []
+
+(** Nota: Interactive modules and module types cannot be recached!
+ This used to be checked here via a flag along the substobjs. *)
+
+let cache_module = do_module' false Lib.load_objects 1
+let load_module = do_module' false Lib.load_objects
+let open_module = do_module' true Lib.open_objects
+let subst_module (subst,sobjs) = subst_sobjs subst sobjs
+let classify_module sobjs = Substitute sobjs
+
+let (in_module : substitutive_objects -> obj),
+ (out_module : obj -> substitutive_objects) =
+ declare_object_full {(default_object "MODULE") with
+ cache_function = cache_module;
+ load_function = load_module;
+ open_function = open_module;
+ subst_function = subst_module;
+ classify_function = classify_module }
+
+
+(** {6 Declaration of module keep objects} *)
+
+let cache_keep _ = anomaly (Pp.str "This module should not be cached!")
+
+let load_keep i ((sp,kn),kobjs) =
+ (* Invariant : seg isn't empty *)
+ let obj_dir = dir_of_sp sp and obj_mp = mp_of_kn kn in
+ let prefix = Nametab.{ obj_dir ; obj_mp; obj_sec = DirPath.empty } in
+ let prefix',sobjs,kobjs0 =
+ try ModObjs.get obj_mp
+ with Not_found -> assert false (* a substobjs should already be loaded *)
+ in
+ assert Nametab.(eq_op prefix' prefix);
+ assert (List.is_empty kobjs0);
+ ModObjs.set obj_mp (prefix,sobjs,kobjs);
+ Lib.load_objects i prefix kobjs
+
+let open_keep i ((sp,kn),kobjs) =
+ let obj_dir = dir_of_sp sp and obj_mp = mp_of_kn kn in
+ let prefix = Nametab.{ obj_dir; obj_mp; obj_sec = DirPath.empty } in
+ Lib.open_objects i prefix kobjs
+
+let in_modkeep : Lib.lib_objects -> obj =
+ declare_object {(default_object "MODULE KEEP") with
+ cache_function = cache_keep;
+ load_function = load_keep;
+ open_function = open_keep }
+
+
+(** {6 Declaration of module type substitutive objects} *)
+
+(** Nota: Interactive modules and module types cannot be recached!
+ This used to be checked more properly here. *)
+
+let do_modtype i sp mp sobjs =
+ if Nametab.exists_modtype sp then
+ anomaly (pr_path sp ++ str " already exists.");
+ Nametab.push_modtype (Nametab.Until i) sp mp;
+ ModSubstObjs.set mp sobjs
+
+let cache_modtype ((sp,kn),sobjs) = do_modtype 1 sp (mp_of_kn kn) sobjs
+let load_modtype i ((sp,kn),sobjs) = do_modtype i sp (mp_of_kn kn) sobjs
+let subst_modtype (subst,sobjs) = subst_sobjs subst sobjs
+let classify_modtype sobjs = Substitute sobjs
+
+let open_modtype i ((sp,kn),_) =
+ let mp = mp_of_kn kn in
+ let mp' =
+ try Nametab.locate_modtype (qualid_of_path sp)
+ with Not_found ->
+ anomaly (pr_path sp ++ str " should already exist!");
+ in
+ assert (ModPath.equal mp mp');
+ Nametab.push_modtype (Nametab.Exactly i) sp mp
+
+let (in_modtype : substitutive_objects -> obj),
+ (out_modtype : obj -> substitutive_objects) =
+ declare_object_full {(default_object "MODULE TYPE") with
+ cache_function = cache_modtype;
+ open_function = open_modtype;
+ load_function = load_modtype;
+ subst_function = subst_modtype;
+ classify_function = classify_modtype }
+
+
+(** {6 Declaration of substitutive objects for Include} *)
+
+let do_include do_load do_open i ((sp,kn),aobjs) =
+ let obj_dir = Libnames.dirpath sp in
+ let obj_mp = KerName.modpath kn in
+ let prefix = Nametab.{ obj_dir; obj_mp; obj_sec = DirPath.empty } in
+ let o = expand_aobjs aobjs in
+ if do_load then Lib.load_objects i prefix o;
+ if do_open then Lib.open_objects i prefix o
+
+let cache_include = do_include true true 1
+let load_include = do_include true false
+let open_include = do_include false true
+let subst_include (subst,aobjs) = subst_aobjs subst aobjs
+let classify_include aobjs = Substitute aobjs
+
+let (in_include : algebraic_objects -> obj),
+ (out_include : obj -> algebraic_objects) =
+ declare_object_full {(default_object "INCLUDE") with
+ cache_function = cache_include;
+ load_function = load_include;
+ open_function = open_include;
+ subst_function = subst_include;
+ classify_function = classify_include }
+
+
+(** {6 Handler for missing entries in ModSubstObjs} *)
+
+(** Since the inner of Module Types are not added by default to
+ the ModSubstObjs table, we compensate this by explicit traversal
+ of Module Types inner objects when needed. Quite a hack... *)
+
+let mp_id mp id = MPdot (mp, Label.of_id id)
+
+let rec register_mod_objs mp (id,obj) = match object_tag obj with
+ | "MODULE" -> ModSubstObjs.set (mp_id mp id) (out_module obj)
+ | "MODULE TYPE" -> ModSubstObjs.set (mp_id mp id) (out_modtype obj)
+ | "INCLUDE" ->
+ List.iter (register_mod_objs mp) (expand_aobjs (out_include obj))
+ | _ -> ()
+
+let handle_missing_substobjs mp = match mp with
+ | MPdot (mp',l) ->
+ let objs = expand_sobjs (ModSubstObjs.get mp') in
+ List.iter (register_mod_objs mp') objs;
+ ModSubstObjs.get mp
+ | _ ->
+ assert false (* Only inner parts of module types should be missing *)
+
+let () = ModSubstObjs.set_missing_handler handle_missing_substobjs
+
+
+
+(** {6 From module expression to substitutive objects} *)
+
+(** Turn a chain of [MSEapply] into the head ModPath.t and the
+ list of ModPath.t parameters (deepest param coming first).
+ The left part of a [MSEapply] must be either [MSEident] or
+ another [MSEapply]. *)
+
+let get_applications mexpr =
+ let rec get params = function
+ | MEident mp -> mp, params
+ | MEapply (fexpr, mp) -> get (mp::params) fexpr
+ | MEwith _ -> user_err Pp.(str "Non-atomic functor application.")
+ in get [] mexpr
+
+(** Create the substitution corresponding to some functor applications *)
+
+let rec compute_subst env mbids sign mp_l inl =
+ match mbids,mp_l with
+ | _,[] -> mbids,empty_subst
+ | [],r -> user_err Pp.(str "Application of a functor with too few arguments.")
+ | mbid::mbids,mp::mp_l ->
+ let farg_id, farg_b, fbody_b = Modops.destr_functor sign in
+ let mb = Environ.lookup_module mp env in
+ let mbid_left,subst = compute_subst env mbids fbody_b mp_l inl in
+ let resolver =
+ if Modops.is_functor mb.mod_type then empty_delta_resolver
+ else
+ Modops.inline_delta_resolver env inl mp farg_id farg_b mb.mod_delta
+ in
+ mbid_left,join (map_mbid mbid mp resolver) subst
+
+(** Create the objects of a "with Module" structure. *)
+
+let rec replace_module_object idl mp0 objs0 mp1 objs1 =
+ match idl, objs0 with
+ | _,[] -> []
+ | id::idl,(id',obj)::tail when Id.equal id id' ->
+ assert (String.equal (object_tag obj) "MODULE");
+ let mp_id = MPdot(mp0, Label.of_id id) in
+ let objs = match idl with
+ | [] -> Lib.subst_objects (map_mp mp1 mp_id empty_delta_resolver) objs1
+ | _ ->
+ let objs_id = expand_sobjs (out_module obj) in
+ replace_module_object idl mp_id objs_id mp1 objs1
+ in
+ (id, in_module ([], Objs objs))::tail
+ | idl,lobj::tail -> lobj::replace_module_object idl mp0 tail mp1 objs1
+
+let type_of_mod mp env = function
+ |true -> (Environ.lookup_module mp env).mod_type
+ |false -> (Environ.lookup_modtype mp env).mod_type
+
+let rec get_module_path = function
+ |MEident mp -> mp
+ |MEwith (me,_) -> get_module_path me
+ |MEapply (me,_) -> get_module_path me
+
+(** Substitutive objects of a module expression (or module type) *)
+
+let rec get_module_sobjs is_mod env inl = function
+ |MEident mp ->
+ begin match ModSubstObjs.get mp with
+ |(mbids,Objs _) when not (ModPath.is_bound mp) ->
+ (mbids,Ref (mp, empty_subst)) (* we create an alias *)
+ |sobjs -> sobjs
+ end
+ |MEwith (mty, WithDef _) -> get_module_sobjs is_mod env inl mty
+ |MEwith (mty, WithMod (idl,mp1)) ->
+ assert (not is_mod);
+ let sobjs0 = get_module_sobjs is_mod env inl mty in
+ assert (sobjs_no_functor sobjs0);
+ (* For now, we expanse everything, to be safe *)
+ let mp0 = get_module_path mty in
+ let objs0 = expand_sobjs sobjs0 in
+ let objs1 = expand_sobjs (ModSubstObjs.get mp1) in
+ ([], Objs (replace_module_object idl mp0 objs0 mp1 objs1))
+ |MEapply _ as me ->
+ let mp1, mp_l = get_applications me in
+ let mbids, aobjs = get_module_sobjs is_mod env inl (MEident mp1) in
+ let typ = type_of_mod mp1 env is_mod in
+ let mbids_left,subst = compute_subst env mbids typ mp_l inl in
+ (mbids_left, subst_aobjs subst aobjs)
+
+let get_functor_sobjs is_mod env inl (params,mexpr) =
+ let (mbids, aobjs) = get_module_sobjs is_mod env inl mexpr in
+ (List.map fst params @ mbids, aobjs)
+
+
+(** {6 Handling of module parameters} *)
+
+(** For printing modules, [process_module_binding] adds names of
+ bound module (and its components) to Nametab. It also loads
+ objects associated to it. *)
+
+let process_module_binding mbid me =
+ let dir = DirPath.make [MBId.to_id mbid] in
+ let mp = MPbound mbid in
+ let sobjs = get_module_sobjs false (Global.env()) (default_inline ()) me in
+ let subst = map_mp (get_module_path me) mp empty_delta_resolver in
+ let sobjs = subst_sobjs subst sobjs in
+ do_module false Lib.load_objects 1 dir mp sobjs []
+
+(** Process a declaration of functor parameter(s) (Id1 .. Idn : Typ)
+ i.e. possibly multiple names with the same module type.
+ Global environment is updated on the fly.
+ Objects in these parameters are also loaded.
+ Output is accumulated on top of [acc] (in reverse order). *)
+
+let intern_arg interp_modast (acc, cst) (idl,(typ,ann)) =
+ let inl = inl2intopt ann in
+ let lib_dir = Lib.library_dp() in
+ let env = Global.env() in
+ let (mty, _, cst') = interp_modast env ModType typ in
+ let () = Global.push_context_set true cst' in
+ let env = Global.env () in
+ let sobjs = get_module_sobjs false env inl mty in
+ let mp0 = get_module_path mty in
+ let fold acc {CAst.v=id} =
+ let dir = DirPath.make [id] in
+ let mbid = MBId.make lib_dir id in
+ let mp = MPbound mbid in
+ let resolver = Global.add_module_parameter mbid mty inl in
+ let sobjs = subst_sobjs (map_mp mp0 mp resolver) sobjs in
+ do_module false Lib.load_objects 1 dir mp sobjs [];
+ (mbid,mty,inl)::acc
+ in
+ let acc = List.fold_left fold acc idl in
+ (acc, Univ.ContextSet.union cst cst')
+
+(** Process a list of declarations of functor parameters
+ (Id11 .. Id1n : Typ1)..(Idk1 .. Idkm : Typk)
+ Global environment is updated on the fly.
+ The calls to [interp_modast] should be interleaved with these
+ env updates, otherwise some "with Definition" could be rejected.
+ Returns a list of mbids and entries (in reversed order).
+
+ This used to be a [List.concat (List.map ...)], but this should
+ be more efficient and independent of [List.map] eval order.
+*)
+
+let intern_args interp_modast params =
+ List.fold_left (intern_arg interp_modast) ([], Univ.ContextSet.empty) params
+
+
+(** {6 Auxiliary functions concerning subtyping checks} *)
+
+let check_sub mtb sub_mtb_l =
+ (* The constraints are checked and forgot immediately : *)
+ ignore (List.fold_right
+ (fun sub_mtb env ->
+ Environ.add_constraints
+ (Subtyping.check_subtypes env mtb sub_mtb) env)
+ sub_mtb_l (Global.env()))
+
+(** This function checks if the type calculated for the module [mp] is
+ a subtype of all signatures in [sub_mtb_l]. Uses only the global
+ environment. *)
+
+let check_subtypes mp sub_mtb_l =
+ let mb =
+ try Global.lookup_module mp with Not_found -> assert false
+ in
+ let mtb = Modops.module_type_of_module mb in
+ check_sub mtb sub_mtb_l
+
+(** Same for module type [mp] *)
+
+let check_subtypes_mt mp sub_mtb_l =
+ let mtb =
+ try Global.lookup_modtype mp with Not_found -> assert false
+ in
+ check_sub mtb sub_mtb_l
+
+(** Create a params entry.
+ In [args], the youngest module param now comes first. *)
+
+let mk_params_entry args =
+ List.rev_map (fun (mbid,arg_t,_) -> (mbid,arg_t)) args
+
+(** Create a functor type struct.
+ In [args], the youngest module param now comes first. *)
+
+let mk_funct_type env args seb0 =
+ List.fold_left
+ (fun seb (arg_id,arg_t,arg_inl) ->
+ let mp = MPbound arg_id in
+ let arg_t = Mod_typing.translate_modtype env mp arg_inl ([],arg_t) in
+ MoreFunctor(arg_id,arg_t,seb))
+ seb0 args
+
+(** Prepare the module type list for check of subtypes *)
+
+let build_subtypes interp_modast env mp args mtys =
+ let (cst, ans) = List.fold_left_map
+ (fun cst (m,ann) ->
+ let inl = inl2intopt ann in
+ let mte, _, cst' = interp_modast env ModType m in
+ let env = Environ.push_context_set ~strict:true cst' env in
+ let cst = Univ.ContextSet.union cst cst' in
+ let mtb = Mod_typing.translate_modtype env mp inl ([],mte) in
+ cst, { mtb with mod_type = mk_funct_type env args mtb.mod_type })
+ Univ.ContextSet.empty mtys
+ in
+ (ans, cst)
+
+
+(** {6 Current module information}
+
+ This information is stored by each [start_module] for use
+ in a later [end_module]. *)
+
+type current_module_info = {
+ cur_typ : (module_struct_entry * int option) option; (** type via ":" *)
+ cur_typs : module_type_body list (** types via "<:" *)
+}
+
+let default_module_info = { cur_typ = None; cur_typs = [] }
+
+let openmod_info = Summary.ref default_module_info ~name:"MODULE-INFO"
+
+
+(** {6 Current module type information}
+
+ This information is stored by each [start_modtype] for use
+ in a later [end_modtype]. *)
+
+let openmodtype_info =
+ Summary.ref ([] : module_type_body list) ~name:"MODTYPE-INFO"
+
+
+(** {6 Modules : start, end, declare} *)
+
+module RawModOps = struct
+
+let start_module interp_modast export id args res fs =
+ let mp = Global.start_module id in
+ let arg_entries_r, cst = intern_args interp_modast args in
+ let () = Global.push_context_set true cst in
+ let env = Global.env () in
+ let res_entry_o, subtyps, cst = match res with
+ | Enforce (res,ann) ->
+ let inl = inl2intopt ann in
+ let (mte, _, cst) = interp_modast env ModType res in
+ let env = Environ.push_context_set ~strict:true cst env in
+ (* We check immediately that mte is well-formed *)
+ let _, _, _, cst' = Mod_typing.translate_mse env None inl mte in
+ let cst = Univ.ContextSet.union cst cst' in
+ Some (mte, inl), [], cst
+ | Check resl ->
+ let typs, cst = build_subtypes interp_modast env mp arg_entries_r resl in
+ None, typs, cst
+ in
+ let () = Global.push_context_set true cst in
+ openmod_info := { cur_typ = res_entry_o; cur_typs = subtyps };
+ let prefix = Lib.start_module export id mp fs in
+ Nametab.(push_dir (Until 1) (prefix.obj_dir) (GlobDirRef.DirOpenModule prefix));
+ mp
+
+let end_module () =
+ let oldoname,oldprefix,fs,lib_stack = Lib.end_module () in
+ let substitute, keep, special = Lib.classify_segment lib_stack in
+ let m_info = !openmod_info in
+
+ (* For sealed modules, we use the substitutive objects of their signatures *)
+ let sobjs0, keep, special = match m_info.cur_typ with
+ | None -> ([], Objs substitute), keep, special
+ | Some (mty, inline) ->
+ get_module_sobjs false (Global.env()) inline mty, [], []
+ in
+ let id = basename (fst oldoname) in
+ let mp,mbids,resolver = Global.end_module fs id m_info.cur_typ in
+ let sobjs = let (ms,objs) = sobjs0 in (mbids@ms,objs) in
+
+ check_subtypes mp m_info.cur_typs;
+
+ (* We substitute objects if the module is sealed by a signature *)
+ let sobjs =
+ match m_info.cur_typ with
+ | None -> sobjs
+ | Some (mty, _) ->
+ subst_sobjs (map_mp (get_module_path mty) mp resolver) sobjs
+ in
+ let node = in_module sobjs in
+ (* We add the keep objects, if any, and if this isn't a functor *)
+ let objects = match keep, mbids with
+ | [], _ | _, _ :: _ -> special@[node]
+ | _ -> special@[node;in_modkeep keep]
+ in
+ let newoname = Lib.add_leaves id objects in
+
+ (* Name consistency check : start_ vs. end_module, kernel vs. library *)
+ assert (eq_full_path (fst newoname) (fst oldoname));
+ assert (ModPath.equal (mp_of_kn (snd newoname)) mp);
+
+ mp
+
+let declare_module interp_modast id args res mexpr_o fs =
+ (* We simulate the beginning of an interactive module,
+ then we adds the module parameters to the global env. *)
+ let mp = Global.start_module id in
+ let arg_entries_r, cst = intern_args interp_modast args in
+ let params = mk_params_entry arg_entries_r in
+ let env = Global.env () in
+ let env = Environ.push_context_set ~strict:true cst env in
+ let mty_entry_o, subs, inl_res, cst' = match res with
+ | Enforce (mty,ann) ->
+ let inl = inl2intopt ann in
+ let (mte, _, cst) = interp_modast env ModType mty in
+ let env = Environ.push_context_set ~strict:true cst env in
+ (* We check immediately that mte is well-formed *)
+ let _, _, _, cst' = Mod_typing.translate_mse env None inl mte in
+ let cst = Univ.ContextSet.union cst cst' in
+ Some mte, [], inl, cst
+ | Check mtys ->
+ let typs, cst = build_subtypes interp_modast env mp arg_entries_r mtys in
+ None, typs, default_inline (), cst
+ in
+ let env = Environ.push_context_set ~strict:true cst' env in
+ let cst = Univ.ContextSet.union cst cst' in
+ let mexpr_entry_o, inl_expr, cst' = match mexpr_o with
+ | None -> None, default_inline (), Univ.ContextSet.empty
+ | Some (mexpr,ann) ->
+ let (mte, _, cst) = interp_modast env Module mexpr in
+ Some mte, inl2intopt ann, cst
+ in
+ let env = Environ.push_context_set ~strict:true cst' env in
+ let cst = Univ.ContextSet.union cst cst' in
+ let entry = match mexpr_entry_o, mty_entry_o with
+ | None, None -> assert false (* No body, no type ... *)
+ | None, Some typ -> MType (params, typ)
+ | Some body, otyp -> MExpr (params, body, otyp)
+ in
+ let sobjs, mp0 = match entry with
+ | MType (_,mte) | MExpr (_,_,Some mte) ->
+ get_functor_sobjs false env inl_res (params,mte), get_module_path mte
+ | MExpr (_,me,None) ->
+ get_functor_sobjs true env inl_expr (params,me), get_module_path me
+ in
+ (* Undo the simulated interactive building of the module
+ and declare the module as a whole *)
+ Summary.unfreeze_summaries fs;
+ let inl = match inl_expr with
+ | None -> None
+ | _ -> inl_res
+ in
+ let () = Global.push_context_set true cst in
+ let mp_env,resolver = Global.add_module id entry inl in
+
+ (* Name consistency check : kernel vs. library *)
+ assert (ModPath.equal mp (mp_of_kn (Lib.make_kn id)));
+ assert (ModPath.equal mp mp_env);
+
+ check_subtypes mp subs;
+
+ let sobjs = subst_sobjs (map_mp mp0 mp resolver) sobjs in
+ ignore (Lib.add_leaf id (in_module sobjs));
+ mp
+
+end
+
+(** {6 Module types : start, end, declare} *)
+
+module RawModTypeOps = struct
+
+let start_modtype interp_modast id args mtys fs =
+ let mp = Global.start_modtype id in
+ let arg_entries_r, cst = intern_args interp_modast args in
+ let () = Global.push_context_set true cst in
+ let env = Global.env () in
+ let sub_mty_l, cst = build_subtypes interp_modast env mp arg_entries_r mtys in
+ let () = Global.push_context_set true cst in
+ openmodtype_info := sub_mty_l;
+ let prefix = Lib.start_modtype id mp fs in
+ Nametab.(push_dir (Until 1) (prefix.obj_dir) (GlobDirRef.DirOpenModtype prefix));
+ mp
+
+let end_modtype () =
+ let oldoname,prefix,fs,lib_stack = Lib.end_modtype () in
+ let id = basename (fst oldoname) in
+ let substitute, _, special = Lib.classify_segment lib_stack in
+ let sub_mty_l = !openmodtype_info in
+ let mp, mbids = Global.end_modtype fs id in
+ let modtypeobjs = (mbids, Objs substitute) in
+ check_subtypes_mt mp sub_mty_l;
+ let oname = Lib.add_leaves id (special@[in_modtype modtypeobjs])
+ in
+ (* Check name consistence : start_ vs. end_modtype, kernel vs. library *)
+ assert (eq_full_path (fst oname) (fst oldoname));
+ assert (ModPath.equal (mp_of_kn (snd oname)) mp);
+
+ mp
+
+let declare_modtype interp_modast id args mtys (mty,ann) fs =
+ let inl = inl2intopt ann in
+ (* We simulate the beginning of an interactive module,
+ then we adds the module parameters to the global env. *)
+ let mp = Global.start_modtype id in
+ let arg_entries_r, cst = intern_args interp_modast args in
+ let () = Global.push_context_set true cst in
+ let params = mk_params_entry arg_entries_r in
+ let env = Global.env () in
+ let mte, _, cst = interp_modast env ModType mty in
+ let () = Global.push_context_set true cst in
+ let env = Global.env () in
+ (* We check immediately that mte is well-formed *)
+ let _, _, _, cst = Mod_typing.translate_mse env None inl mte in
+ let () = Global.push_context_set true cst in
+ let env = Global.env () in
+ let entry = params, mte in
+ let sub_mty_l, cst = build_subtypes interp_modast env mp arg_entries_r mtys in
+ let () = Global.push_context_set true cst in
+ let env = Global.env () in
+ let sobjs = get_functor_sobjs false env inl entry in
+ let subst = map_mp (get_module_path (snd entry)) mp empty_delta_resolver in
+ let sobjs = subst_sobjs subst sobjs in
+
+ (* Undo the simulated interactive building of the module type
+ and declare the module type as a whole *)
+ Summary.unfreeze_summaries fs;
+
+ (* We enrich the global environment *)
+ let mp_env = Global.add_modtype id entry inl in
+
+ (* Name consistency check : kernel vs. library *)
+ assert (ModPath.equal mp_env mp);
+
+ (* Subtyping checks *)
+ check_subtypes_mt mp sub_mty_l;
+
+ ignore (Lib.add_leaf id (in_modtype sobjs));
+ mp
+
+end
+
+(** {6 Include} *)
+
+module RawIncludeOps = struct
+
+let rec include_subst env mp reso mbids sign inline = match mbids with
+ | [] -> empty_subst
+ | mbid::mbids ->
+ let farg_id, farg_b, fbody_b = Modops.destr_functor sign in
+ let subst = include_subst env mp reso mbids fbody_b inline in
+ let mp_delta =
+ Modops.inline_delta_resolver env inline mp farg_id farg_b reso
+ in
+ join (map_mbid mbid mp mp_delta) subst
+
+let rec decompose_functor mpl typ =
+ match mpl, typ with
+ | [], _ -> typ
+ | _::mpl, MoreFunctor(_,_,str) -> decompose_functor mpl str
+ | _ -> user_err Pp.(str "Application of a functor with too much arguments.")
+
+exception NoIncludeSelf
+
+let type_of_incl env is_mod = function
+ |MEident mp -> type_of_mod mp env is_mod
+ |MEapply _ as me ->
+ let mp0, mp_l = get_applications me in
+ decompose_functor mp_l (type_of_mod mp0 env is_mod)
+ |MEwith _ -> raise NoIncludeSelf
+
+let declare_one_include interp_modast (me_ast,annot) =
+ let env = Global.env() in
+ let me, kind, cst = interp_modast env ModAny me_ast in
+ let () = Global.push_context_set true cst in
+ let env = Global.env () in
+ let is_mod = (kind == Module) in
+ let cur_mp = Lib.current_mp () in
+ let inl = inl2intopt annot in
+ let mbids,aobjs = get_module_sobjs is_mod env inl me in
+ let subst_self =
+ try
+ if List.is_empty mbids then raise NoIncludeSelf;
+ let typ = type_of_incl env is_mod me in
+ let reso,_ = Safe_typing.delta_of_senv (Global.safe_env ()) in
+ include_subst env cur_mp reso mbids typ inl
+ with NoIncludeSelf -> empty_subst
+ in
+ let base_mp = get_module_path me in
+ let resolver = Global.add_include me is_mod inl in
+ let subst = join subst_self (map_mp base_mp cur_mp resolver) in
+ let aobjs = subst_aobjs subst aobjs in
+ ignore (Lib.add_leaf (Lib.current_mod_id ()) (in_include aobjs))
+
+let declare_include interp me_asts =
+ List.iter (declare_one_include interp) me_asts
+
+end
+
+
+(** {6 Module operations handling summary freeze/unfreeze} *)
+
+let protect_summaries f =
+ let fs = Summary.freeze_summaries ~marshallable:false in
+ try f fs
+ with reraise ->
+ (* Something wrong: undo the whole process *)
+ let reraise = CErrors.push reraise in
+ let () = Summary.unfreeze_summaries fs in
+ iraise reraise
+
+let start_module interp export id args res =
+ protect_summaries (RawModOps.start_module interp export id args res)
+
+let end_module = RawModOps.end_module
+
+let declare_module interp id args mtys me_l =
+ let declare_me fs = match me_l with
+ | [] -> RawModOps.declare_module interp id args mtys None fs
+ | [me] -> RawModOps.declare_module interp id args mtys (Some me) fs
+ | me_l ->
+ ignore (RawModOps.start_module interp None id args mtys fs);
+ RawIncludeOps.declare_include interp me_l;
+ RawModOps.end_module ()
+ in
+ protect_summaries declare_me
+
+let start_modtype interp id args mtys =
+ protect_summaries (RawModTypeOps.start_modtype interp id args mtys)
+
+let end_modtype = RawModTypeOps.end_modtype
+
+let declare_modtype interp id args mtys mty_l =
+ let declare_mt fs = match mty_l with
+ | [] -> assert false
+ | [mty] -> RawModTypeOps.declare_modtype interp id args mtys mty fs
+ | mty_l ->
+ ignore (RawModTypeOps.start_modtype interp id args mtys fs);
+ RawIncludeOps.declare_include interp mty_l;
+ RawModTypeOps.end_modtype ()
+ in
+ protect_summaries declare_mt
+
+let declare_include interp me_asts =
+ protect_summaries (fun _ -> RawIncludeOps.declare_include interp me_asts)
+
+
+(** {6 Libraries} *)
+
+type library_name = DirPath.t
+
+(** A library object is made of some substitutive objects
+ and some "keep" objects. *)
+
+type library_objects = Lib.lib_objects * Lib.lib_objects
+
+(** For the native compiler, we cache the library values *)
+
+let register_library dir cenv (objs:library_objects) digest univ =
+ let mp = MPfile dir in
+ let () =
+ try
+ (* Is this library already loaded ? *)
+ ignore(Global.lookup_module mp);
+ with Not_found ->
+ (* If not, let's do it now ... *)
+ let mp' = Global.import cenv univ digest in
+ if not (ModPath.equal mp mp') then
+ anomaly (Pp.str "Unexpected disk module name.");
+ in
+ let sobjs,keepobjs = objs in
+ do_module false Lib.load_objects 1 dir mp ([],Objs sobjs) keepobjs
+
+let get_library_native_symbols dir =
+ Safe_typing.get_library_native_symbols (Global.safe_env ()) dir
+
+let start_library dir =
+ let mp = Global.start_library dir in
+ openmod_info := default_module_info;
+ Lib.start_compilation dir mp
+
+let end_library_hook = ref ignore
+let append_end_library_hook f =
+ let old_f = !end_library_hook in
+ end_library_hook := fun () -> old_f(); f ()
+
+let end_library ?except dir =
+ !end_library_hook();
+ let oname = Lib.end_compilation_checks dir in
+ let mp,cenv,ast = Global.export ?except dir in
+ let prefix, lib_stack = Lib.end_compilation oname in
+ assert (ModPath.equal mp (MPfile dir));
+ let substitute, keep, _ = Lib.classify_segment lib_stack in
+ cenv,(substitute,keep),ast
+
+
+
+(** {6 Implementation of Import and Export commands} *)
+
+let really_import_module mp =
+ (* May raise Not_found for unknown module and for functors *)
+ let prefix,sobjs,keepobjs = ModObjs.get mp in
+ Lib.open_objects 1 prefix sobjs;
+ Lib.open_objects 1 prefix keepobjs
+
+let cache_import (_,(_,mp)) = really_import_module mp
+
+let open_import i obj =
+ if Int.equal i 1 then cache_import obj
+
+let classify_import (export,_ as obj) =
+ if export then Substitute obj else Dispose
+
+let subst_import (subst,(export,mp as obj)) =
+ let mp' = subst_mp subst mp in
+ if mp'==mp then obj else (export,mp')
+
+let in_import : bool * ModPath.t -> obj =
+ declare_object {(default_object "IMPORT MODULE") with
+ cache_function = cache_import;
+ open_function = open_import;
+ subst_function = subst_import;
+ classify_function = classify_import }
+
+let import_module export mp =
+ Lib.add_anonymous_leaf (in_import (export,mp))
+
+
+(** {6 Iterators} *)
+
+let iter_all_segments f =
+ let rec apply_obj prefix (id,obj) = match object_tag obj with
+ | "INCLUDE" ->
+ let objs = expand_aobjs (out_include obj) in
+ List.iter (apply_obj prefix) objs
+ | _ -> f (Lib.make_oname prefix id) obj
+ in
+ let apply_mod_obj _ (prefix,substobjs,keepobjs) =
+ List.iter (apply_obj prefix) substobjs;
+ List.iter (apply_obj prefix) keepobjs
+ in
+ let apply_node = function
+ | sp, Lib.Leaf o -> f sp o
+ | _ -> ()
+ in
+ MPmap.iter apply_mod_obj (ModObjs.all ());
+ List.iter apply_node (Lib.contents ())
+
+
+(** {6 Some types used to shorten declaremods.mli} *)
+
+type 'modast module_interpretor =
+ Environ.env -> module_kind -> 'modast ->
+ Entries.module_struct_entry * module_kind * Univ.ContextSet.t
+
+type 'modast module_params =
+ (lident list * ('modast * inline)) list
+
+(** {6 Debug} *)
+
+let debug_print_modtab _ =
+ let pr_seg = function
+ | [] -> str "[]"
+ | l -> str "[." ++ int (List.length l) ++ str ".]"
+ in
+ let pr_modinfo mp (prefix,substobjs,keepobjs) s =
+ s ++ str (ModPath.to_string mp) ++ (spc ())
+ ++ (pr_seg (Lib.segment_of_objects prefix (substobjs@keepobjs)))
+ in
+ let modules = MPmap.fold pr_modinfo (ModObjs.all ()) (mt ()) in
+ hov 0 modules
diff --git a/library/declaremods.mli b/library/declaremods.mli
new file mode 100644
index 0000000000..7aa4bc30ce
--- /dev/null
+++ b/library/declaremods.mli
@@ -0,0 +1,144 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+
+(** {6 Modules } *)
+
+(** Rigid / flexible module signature *)
+
+type 'a module_signature =
+ | Enforce of 'a (** ... : T *)
+ | Check of 'a list (** ... <: T1 <: T2, possibly empty *)
+
+(** Which module inline annotations should we honor,
+ either None or the ones whose level is less or equal
+ to the given integer *)
+
+type inline =
+ | NoInline
+ | DefaultInline
+ | InlineAt of int
+
+(** Kinds of modules *)
+
+type module_kind = Module | ModType | ModAny
+
+type 'modast module_interpretor =
+ Environ.env -> module_kind -> 'modast ->
+ Entries.module_struct_entry * module_kind * Univ.ContextSet.t
+
+type 'modast module_params =
+ (lident list * ('modast * inline)) list
+
+(** [declare_module interp_modast id fargs typ exprs]
+ declares module [id], with structure constructed by [interp_modast]
+ from functor arguments [fargs], with final type [typ].
+ [exprs] is usually of length 1 (Module definition with a concrete
+ body), but it could also be empty ("Declare Module", with non-empty [typ]),
+ or multiple (body of the shape M <+ N <+ ...). *)
+
+val declare_module :
+ 'modast module_interpretor ->
+ Id.t ->
+ 'modast module_params ->
+ ('modast * inline) module_signature ->
+ ('modast * inline) list -> ModPath.t
+
+val start_module :
+ 'modast module_interpretor ->
+ bool option -> Id.t ->
+ 'modast module_params ->
+ ('modast * inline) module_signature -> ModPath.t
+
+val end_module : unit -> ModPath.t
+
+
+
+(** {6 Module types } *)
+
+(** [declare_modtype interp_modast id fargs typs exprs]
+ Similar to [declare_module], except that the types could be multiple *)
+
+val declare_modtype :
+ 'modast module_interpretor ->
+ Id.t ->
+ 'modast module_params ->
+ ('modast * inline) list ->
+ ('modast * inline) list ->
+ ModPath.t
+
+val start_modtype :
+ 'modast module_interpretor ->
+ Id.t ->
+ 'modast module_params ->
+ ('modast * inline) list -> ModPath.t
+
+val end_modtype : unit -> ModPath.t
+
+(** {6 Libraries i.e. modules on disk } *)
+
+type library_name = DirPath.t
+
+type library_objects
+
+val register_library :
+ library_name ->
+ Safe_typing.compiled_library -> library_objects -> Safe_typing.vodigest ->
+ Univ.ContextSet.t -> unit
+
+val get_library_native_symbols : library_name -> Nativecode.symbols
+
+val start_library : library_name -> unit
+
+val end_library :
+ ?except:Future.UUIDSet.t -> library_name ->
+ Safe_typing.compiled_library * library_objects * Safe_typing.native_library
+
+(** append a function to be executed at end_library *)
+val append_end_library_hook : (unit -> unit) -> unit
+
+(** [really_import_module mp] opens the module [mp] (in a Caml sense).
+ It modifies Nametab and performs the [open_object] function for
+ every object of the module. Raises [Not_found] when [mp] is unknown
+ or when [mp] corresponds to a functor. *)
+
+val really_import_module : ModPath.t -> unit
+
+(** [import_module export mp] is a synchronous version of
+ [really_import_module]. If [export] is [true], the module is also
+ opened every time the module containing it is. *)
+
+val import_module : bool -> ModPath.t -> unit
+
+(** Include *)
+
+val declare_include :
+ 'modast module_interpretor -> ('modast * inline) list -> unit
+
+(** {6 ... } *)
+(** [iter_all_segments] iterate over all segments, the modules'
+ segments first and then the current segment. Modules are presented
+ in an arbitrary order. The given function is applied to all leaves
+ (together with their section path). *)
+
+val iter_all_segments :
+ (Libobject.object_name -> Libobject.obj -> unit) -> unit
+
+
+val debug_print_modtab : unit -> Pp.t
+
+(** For printing modules, [process_module_binding] adds names of
+ bound module (and its components) to Nametab. It also loads
+ objects associated to it. It may raise a [Failure] when the
+ bound module hasn't an atomic type. *)
+
+val process_module_binding :
+ MBId.t -> Declarations.module_alg_expr -> unit
diff --git a/library/decls.ml b/library/decls.ml
new file mode 100644
index 0000000000..b766b6e2cb
--- /dev/null
+++ b/library/decls.ml
@@ -0,0 +1,46 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** This module registers tables for some non-logical informations
+ associated declarations *)
+
+open Names
+open Decl_kinds
+open Libnames
+
+(** Datas associated to section variables and local definitions *)
+
+type variable_data =
+ DirPath.t * bool (* opacity *) * Univ.ContextSet.t * polymorphic * logical_kind
+
+let vartab =
+ Summary.ref (Id.Map.empty : variable_data Id.Map.t) ~name:"VARIABLE"
+
+let add_variable_data id o = vartab := Id.Map.add id o !vartab
+
+let variable_path id = let (p,_,_,_,_) = Id.Map.find id !vartab in p
+let variable_opacity id = let (_,opaq,_,_,_) = Id.Map.find id !vartab in opaq
+let variable_kind id = let (_,_,_,_,k) = Id.Map.find id !vartab in k
+let variable_context id = let (_,_,ctx,_,_) = Id.Map.find id !vartab in ctx
+let variable_polymorphic id = let (_,_,_,p,_) = Id.Map.find id !vartab in p
+
+let variable_secpath id =
+ let dir = drop_dirpath_prefix (Lib.library_dp()) (variable_path id) in
+ make_qualid dir id
+
+let variable_exists id = Id.Map.mem id !vartab
+
+(** Datas associated to global parameters and constants *)
+
+let csttab = Summary.ref (Cmap.empty : logical_kind Cmap.t) ~name:"CONSTANT"
+
+let add_constant_kind kn k = csttab := Cmap.add kn k !csttab
+
+let constant_kind kn = Cmap.find kn !csttab
diff --git a/library/decls.mli b/library/decls.mli
new file mode 100644
index 0000000000..c0db537427
--- /dev/null
+++ b/library/decls.mli
@@ -0,0 +1,36 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+open Libnames
+open Decl_kinds
+
+(** This module manages non-kernel informations about declarations. It
+ is either non-logical informations or logical informations that
+ have no place to be (yet) in the kernel *)
+
+(** Registration and access to the table of variable *)
+
+type variable_data =
+ DirPath.t * bool (* opacity *) * Univ.ContextSet.t * polymorphic * logical_kind
+
+val add_variable_data : variable -> variable_data -> unit
+val variable_path : variable -> DirPath.t
+val variable_secpath : variable -> qualid
+val variable_kind : variable -> logical_kind
+val variable_opacity : variable -> bool
+val variable_context : variable -> Univ.ContextSet.t
+val variable_polymorphic : variable -> polymorphic
+val variable_exists : variable -> bool
+
+(** Registration and access to the table of constants *)
+
+val add_constant_kind : Constant.t -> logical_kind -> unit
+val constant_kind : Constant.t -> logical_kind
diff --git a/library/doc.tex b/library/doc.tex
new file mode 100644
index 0000000000..33af59336c
--- /dev/null
+++ b/library/doc.tex
@@ -0,0 +1,16 @@
+
+\newpage
+\section*{The Coq library}
+
+\ocwsection \label{library}
+This chapter describes the \Coq\ library, which is made of two parts:
+\begin{itemize}
+ \item a general mechanism to keep a trace of all operations and of
+ the state of the system, with backtrack capabilities;
+ \item a global environment for the CCI, with functions to export and
+ import compiled modules.
+\end{itemize}
+The modules of the library are organized as follows.
+
+\bigskip
+\begin{center}\epsfig{file=library.dep.ps}\end{center}
diff --git a/library/dune b/library/dune
new file mode 100644
index 0000000000..344fad5a75
--- /dev/null
+++ b/library/dune
@@ -0,0 +1,9 @@
+(library
+ (name library)
+ (synopsis "Coq's Loadable Libraries (vo) Support")
+ (public_name coq.library)
+ (wrapped false)
+ (libraries kernel))
+
+(documentation
+ (package coq))
diff --git a/library/global.ml b/library/global.ml
new file mode 100644
index 0000000000..84d2a37170
--- /dev/null
+++ b/library/global.ml
@@ -0,0 +1,191 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+open Environ
+
+(** We introduce here the global environment of the system,
+ and we declare it as a synchronized table. *)
+
+let global_env_summary_name = "Global environment"
+
+module GlobalSafeEnv : sig
+
+ val safe_env : unit -> Safe_typing.safe_environment
+ val set_safe_env : Safe_typing.safe_environment -> unit
+ val join_safe_environment : ?except:Future.UUIDSet.t -> unit -> unit
+ val is_joined_environment : unit -> bool
+ val global_env_summary_tag : Safe_typing.safe_environment Summary.Dyn.tag
+
+end = struct
+
+let global_env = ref Safe_typing.empty_environment
+
+let join_safe_environment ?except () =
+ global_env := Safe_typing.join_safe_environment ?except !global_env
+
+let is_joined_environment () =
+ Safe_typing.is_joined_environment !global_env
+
+let global_env_summary_tag =
+ Summary.declare_summary_tag global_env_summary_name
+ { Summary.freeze_function = (fun ~marshallable -> if marshallable then
+ (join_safe_environment (); !global_env)
+ else !global_env);
+ unfreeze_function = (fun fr -> global_env := fr);
+ init_function = (fun () -> global_env := Safe_typing.empty_environment) }
+
+let assert_not_parsing () =
+ if !Flags.we_are_parsing then
+ CErrors.anomaly (
+ Pp.strbrk"The global environment cannot be accessed during parsing.")
+
+let safe_env () = assert_not_parsing(); !global_env
+
+let set_safe_env e = global_env := e
+
+end
+
+let global_env_summary_tag = GlobalSafeEnv.global_env_summary_tag
+
+let safe_env = GlobalSafeEnv.safe_env
+let join_safe_environment ?except () =
+ GlobalSafeEnv.join_safe_environment ?except ()
+let is_joined_environment = GlobalSafeEnv.is_joined_environment
+
+let env () = Safe_typing.env_of_safe_env (safe_env ())
+
+let env_is_initial () = Safe_typing.is_initial (safe_env ())
+
+(** Turn ops over the safe_environment state monad to ops on the global env *)
+
+let globalize0 f = GlobalSafeEnv.set_safe_env (f (safe_env ()))
+
+let globalize f =
+ let res,env = f (safe_env ()) in GlobalSafeEnv.set_safe_env env; res
+
+let globalize_with_summary fs f =
+ let res,env = f (safe_env ()) in
+ Summary.unfreeze_summaries fs;
+ GlobalSafeEnv.set_safe_env env;
+ res
+
+(** [Safe_typing] operations, now operating on the global environment *)
+
+let i2l = Label.of_id
+
+let push_named_assum a = globalize0 (Safe_typing.push_named_assum a)
+let push_named_def d = globalize0 (Safe_typing.push_named_def d)
+let add_constraints c = globalize0 (Safe_typing.add_constraints c)
+let push_context_set b c = globalize0 (Safe_typing.push_context_set b c)
+
+let set_engagement c = globalize0 (Safe_typing.set_engagement c)
+let set_indices_matter b = globalize0 (Safe_typing.set_indices_matter b)
+let set_typing_flags c = globalize0 (Safe_typing.set_typing_flags c)
+let typing_flags () = Environ.typing_flags (env ())
+let export_private_constants ~in_section cd = globalize (Safe_typing.export_private_constants ~in_section cd)
+let add_constant ~in_section id d = globalize (Safe_typing.add_constant ~in_section (i2l id) d)
+let add_mind id mie = globalize (Safe_typing.add_mind (i2l id) mie)
+let add_modtype id me inl = globalize (Safe_typing.add_modtype (i2l id) me inl)
+let add_module id me inl = globalize (Safe_typing.add_module (i2l id) me inl)
+let add_include me ismod inl = globalize (Safe_typing.add_include me ismod inl)
+
+let start_module id = globalize (Safe_typing.start_module (i2l id))
+let start_modtype id = globalize (Safe_typing.start_modtype (i2l id))
+
+let end_module fs id mtyo =
+ globalize_with_summary fs (Safe_typing.end_module (i2l id) mtyo)
+
+let end_modtype fs id =
+ globalize_with_summary fs (Safe_typing.end_modtype (i2l id))
+
+let add_module_parameter mbid mte inl =
+ globalize (Safe_typing.add_module_parameter mbid mte inl)
+
+(** Queries on the global environment *)
+
+let universes () = universes (env())
+let named_context () = named_context (env())
+let named_context_val () = named_context_val (env())
+
+let lookup_named id = lookup_named id (env())
+let lookup_constant kn = lookup_constant kn (env())
+let lookup_inductive ind = Inductive.lookup_mind_specif (env()) ind
+let lookup_pinductive (ind,_) = Inductive.lookup_mind_specif (env()) ind
+let lookup_mind kn = lookup_mind kn (env())
+
+let lookup_module mp = lookup_module mp (env())
+let lookup_modtype kn = lookup_modtype kn (env())
+
+let exists_objlabel id = Safe_typing.exists_objlabel id (safe_env ())
+
+let opaque_tables () = Environ.opaque_tables (env ())
+
+let body_of_constant_body ce = body_of_constant_body (env ()) ce
+
+let body_of_constant cst = body_of_constant_body (lookup_constant cst)
+
+(** Operations on kernel names *)
+
+let constant_of_delta_kn kn =
+ Safe_typing.constant_of_delta_kn_senv (safe_env ()) kn
+
+let mind_of_delta_kn kn =
+ Safe_typing.mind_of_delta_kn_senv (safe_env ()) kn
+
+(** Operations on libraries *)
+
+let start_library dir = globalize (Safe_typing.start_library dir)
+let export ?except s = Safe_typing.export ?except (safe_env ()) s
+let import c u d = globalize (Safe_typing.import c u d)
+
+
+(** Function to get an environment from the constants part of the global
+ environment and a given context. *)
+
+let env_of_context hyps =
+ reset_with_named_context hyps (env())
+
+let constr_of_global_in_context = Typeops.constr_of_global_in_context
+let type_of_global_in_context = Typeops.type_of_global_in_context
+
+let universes_of_global gr =
+ universes_of_global (env ()) gr
+
+let is_polymorphic r = Environ.is_polymorphic (env()) r
+
+let is_template_polymorphic r = is_template_polymorphic (env ()) r
+
+let is_type_in_type r = is_type_in_type (env ()) r
+
+let current_modpath () =
+ Safe_typing.current_modpath (safe_env ())
+
+let current_dirpath () =
+ Safe_typing.current_dirpath (safe_env ())
+
+let with_global f =
+ let (a, ctx) = f (env ()) (current_dirpath ()) in
+ push_context_set false ctx; a
+
+(* spiwack: register/unregister functions for retroknowledge *)
+let register field value =
+ globalize0 (Safe_typing.register field value)
+
+let register_inline c = globalize0 (Safe_typing.register_inline c)
+
+let set_strategy k l =
+ globalize0 (Safe_typing.set_strategy k l)
+
+let set_share_reduction b =
+ globalize0 (Safe_typing.set_share_reduction b)
+
+let set_VM b = globalize0 (Safe_typing.set_VM b)
+let set_native_compiler b = globalize0 (Safe_typing.set_native_compiler b)
diff --git a/library/global.mli b/library/global.mli
new file mode 100644
index 0000000000..40962e21af
--- /dev/null
+++ b/library/global.mli
@@ -0,0 +1,169 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+
+(** This module defines the global environment of Coq. The functions
+ below are exactly the same as the ones in [Safe_typing], operating on
+ that global environment. [add_*] functions perform name verification,
+ i.e. check that the name given as argument match those provided by
+ [Safe_typing]. *)
+
+val safe_env : unit -> Safe_typing.safe_environment
+val env : unit -> Environ.env
+
+val env_is_initial : unit -> bool
+
+val universes : unit -> UGraph.t
+val named_context_val : unit -> Environ.named_context_val
+val named_context : unit -> Constr.named_context
+
+(** {6 Enriching the global environment } *)
+
+(** Changing the (im)predicativity of the system *)
+val set_engagement : Declarations.engagement -> unit
+val set_indices_matter : bool -> unit
+val set_typing_flags : Declarations.typing_flags -> unit
+val typing_flags : unit -> Declarations.typing_flags
+
+(** Variables, Local definitions, constants, inductive types *)
+
+val push_named_assum : (Id.t * Constr.types * bool) Univ.in_universe_context_set -> unit
+val push_named_def : (Id.t * Entries.section_def_entry) -> unit
+
+val export_private_constants : in_section:bool ->
+ Safe_typing.private_constants Entries.definition_entry ->
+ unit Entries.definition_entry * Safe_typing.exported_private_constant list
+
+val add_constant :
+ in_section:bool -> Id.t -> Safe_typing.global_declaration -> Constant.t
+val add_mind :
+ Id.t -> Entries.mutual_inductive_entry -> MutInd.t
+
+(** Extra universe constraints *)
+val add_constraints : Univ.Constraint.t -> unit
+
+val push_context_set : bool -> Univ.ContextSet.t -> unit
+
+(** Non-interactive modules and module types *)
+
+val add_module :
+ Id.t -> Entries.module_entry -> Declarations.inline ->
+ ModPath.t * Mod_subst.delta_resolver
+val add_modtype :
+ Id.t -> Entries.module_type_entry -> Declarations.inline -> ModPath.t
+val add_include :
+ Entries.module_struct_entry -> bool -> Declarations.inline ->
+ Mod_subst.delta_resolver
+
+(** Interactive modules and module types *)
+
+val start_module : Id.t -> ModPath.t
+val start_modtype : Id.t -> ModPath.t
+
+val end_module : Summary.frozen -> Id.t ->
+ (Entries.module_struct_entry * Declarations.inline) option ->
+ ModPath.t * MBId.t list * Mod_subst.delta_resolver
+
+val end_modtype : Summary.frozen -> Id.t -> ModPath.t * MBId.t list
+
+val add_module_parameter :
+ MBId.t -> Entries.module_struct_entry -> Declarations.inline ->
+ Mod_subst.delta_resolver
+
+(** {6 Queries in the global environment } *)
+
+val lookup_named : variable -> Constr.named_declaration
+val lookup_constant : Constant.t -> Declarations.constant_body
+val lookup_inductive : inductive ->
+ Declarations.mutual_inductive_body * Declarations.one_inductive_body
+val lookup_pinductive : Constr.pinductive ->
+ Declarations.mutual_inductive_body * Declarations.one_inductive_body
+val lookup_mind : MutInd.t -> Declarations.mutual_inductive_body
+val lookup_module : ModPath.t -> Declarations.module_body
+val lookup_modtype : ModPath.t -> Declarations.module_type_body
+val exists_objlabel : Label.t -> bool
+
+val constant_of_delta_kn : KerName.t -> Constant.t
+val mind_of_delta_kn : KerName.t -> MutInd.t
+
+val opaque_tables : unit -> Opaqueproof.opaquetab
+
+val body_of_constant : Constant.t -> (Constr.constr * Univ.AUContext.t) option
+(** Returns the body of the constant if it has any, and the polymorphic context
+ it lives in. For monomorphic constant, the latter is empty, and for
+ polymorphic constants, the term contains De Bruijn universe variables that
+ need to be instantiated. *)
+
+val body_of_constant_body : Declarations.constant_body -> (Constr.constr * Univ.AUContext.t) option
+(** Same as {!body_of_constant} but on {!Declarations.constant_body}. *)
+
+(** {6 Compiled libraries } *)
+
+val start_library : DirPath.t -> ModPath.t
+val export : ?except:Future.UUIDSet.t -> DirPath.t ->
+ ModPath.t * Safe_typing.compiled_library * Safe_typing.native_library
+val import :
+ Safe_typing.compiled_library -> Univ.ContextSet.t -> Safe_typing.vodigest ->
+ ModPath.t
+
+(** {6 Misc } *)
+
+(** Function to get an environment from the constants part of the global
+ * environment and a given context. *)
+
+val env_of_context : Environ.named_context_val -> Environ.env
+
+val join_safe_environment : ?except:Future.UUIDSet.t -> unit -> unit
+val is_joined_environment : unit -> bool
+
+val is_polymorphic : GlobRef.t -> bool
+val is_template_polymorphic : GlobRef.t -> bool
+val is_type_in_type : GlobRef.t -> bool
+
+val constr_of_global_in_context : Environ.env ->
+ GlobRef.t -> Constr.types * Univ.AUContext.t
+ [@@ocaml.deprecated "alias of [Typeops.constr_of_global_in_context]"]
+
+val type_of_global_in_context : Environ.env ->
+ GlobRef.t -> Constr.types * Univ.AUContext.t
+ [@@ocaml.deprecated "alias of [Typeops.type_of_global]"]
+
+(** Returns the universe context of the global reference (whatever its polymorphic status is). *)
+val universes_of_global : GlobRef.t -> Univ.AUContext.t
+[@@ocaml.deprecated "Use [Environ.universes_of_global]"]
+
+(** {6 Retroknowledge } *)
+
+val register :
+ Retroknowledge.field -> GlobRef.t -> unit
+
+val register_inline : Constant.t -> unit
+
+(** {6 Oracle } *)
+
+val set_strategy : Constant.t Names.tableKey -> Conv_oracle.level -> unit
+
+(** {6 Conversion settings } *)
+
+val set_share_reduction : bool -> unit
+
+val set_VM : bool -> unit
+val set_native_compiler : bool -> unit
+
+(* Modifies the global state, registering new universes *)
+
+val current_modpath : unit -> ModPath.t
+
+val current_dirpath : unit -> DirPath.t
+
+val with_global : (Environ.env -> DirPath.t -> 'a Univ.in_universe_context_set) -> 'a
+
+val global_env_summary_tag : Safe_typing.safe_environment Summary.Dyn.tag
diff --git a/library/globnames.ml b/library/globnames.ml
new file mode 100644
index 0000000000..db2e8bfaed
--- /dev/null
+++ b/library/globnames.ml
@@ -0,0 +1,139 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+open Constr
+open Mod_subst
+
+(*s Global reference is a kernel side type for all references together *)
+type global_reference = GlobRef.t =
+ | VarRef of variable (** A reference to the section-context. *)
+ | ConstRef of Constant.t (** A reference to the environment. *)
+ | IndRef of inductive (** A reference to an inductive type. *)
+ | ConstructRef of constructor (** A reference to a constructor of an inductive type. *)
+
+let isVarRef = function VarRef _ -> true | _ -> false
+let isConstRef = function ConstRef _ -> true | _ -> false
+let isIndRef = function IndRef _ -> true | _ -> false
+let isConstructRef = function ConstructRef _ -> true | _ -> false
+
+let destVarRef = function VarRef ind -> ind | _ -> failwith "destVarRef"
+let destConstRef = function ConstRef ind -> ind | _ -> failwith "destConstRef"
+let destIndRef = function IndRef ind -> ind | _ -> failwith "destIndRef"
+let destConstructRef = function ConstructRef ind -> ind | _ -> failwith "destConstructRef"
+
+let subst_constructor subst (ind,j as ref) =
+ let ind' = subst_ind subst ind in
+ if ind==ind' then ref
+ else (ind',j)
+
+let subst_global_reference subst ref = match ref with
+ | VarRef var -> ref
+ | ConstRef kn ->
+ let kn' = subst_constant subst kn in
+ if kn==kn' then ref else ConstRef kn'
+ | IndRef ind ->
+ let ind' = subst_ind subst ind in
+ if ind==ind' then ref else IndRef ind'
+ | ConstructRef ((kn,i),j as c) ->
+ let c' = subst_constructor subst c in
+ if c'==c then ref else ConstructRef c'
+
+let subst_global subst ref = match ref with
+ | VarRef var -> ref, None
+ | ConstRef kn ->
+ let kn',t = subst_con subst kn in
+ if kn==kn' then ref, None else ConstRef kn', t
+ | IndRef ind ->
+ let ind' = subst_ind subst ind in
+ if ind==ind' then ref, None else IndRef ind', None
+ | ConstructRef ((kn,i),j as c) ->
+ let c' = subst_constructor subst c in
+ if c'==c then ref,None else ConstructRef c', None
+
+let canonical_gr = function
+ | ConstRef con -> ConstRef(Constant.make1 (Constant.canonical con))
+ | IndRef (kn,i) -> IndRef(MutInd.make1(MutInd.canonical kn),i)
+ | ConstructRef ((kn,i),j )-> ConstructRef((MutInd.make1(MutInd.canonical kn),i),j)
+ | VarRef id -> VarRef id
+
+let global_of_constr c = match kind c with
+ | Const (sp,u) -> ConstRef sp
+ | Ind (ind_sp,u) -> IndRef ind_sp
+ | Construct (cstr_cp,u) -> ConstructRef cstr_cp
+ | Var id -> VarRef id
+ | _ -> raise Not_found
+
+let is_global c t =
+ match c, kind t with
+ | ConstRef c, Const (c', _) -> Constant.equal c c'
+ | IndRef i, Ind (i', _) -> eq_ind i i'
+ | ConstructRef i, Construct (i', _) -> eq_constructor i i'
+ | VarRef id, Var id' -> Id.equal id id'
+ | _ -> false
+
+let printable_constr_of_global = function
+ | VarRef id -> mkVar id
+ | ConstRef sp -> mkConst sp
+ | ConstructRef sp -> mkConstruct sp
+ | IndRef sp -> mkInd sp
+
+module RefOrdered = Names.GlobRef.Ordered
+module RefOrdered_env = Names.GlobRef.Ordered_env
+
+module Refmap = Names.GlobRef.Map
+module Refset = Names.GlobRef.Set
+
+module Refmap_env = Names.GlobRef.Map_env
+module Refset_env = Names.GlobRef.Set_env
+
+(* Extended global references *)
+
+type syndef_name = KerName.t
+
+type extended_global_reference =
+ | TrueGlobal of global_reference
+ | SynDef of syndef_name
+
+(* We order [extended_global_reference] via their user part
+ (cf. pretty printer) *)
+
+module ExtRefOrdered = struct
+ type t = extended_global_reference
+
+ let equal x y =
+ x == y ||
+ match x, y with
+ | TrueGlobal rx, TrueGlobal ry -> GlobRef.Ordered_env.equal rx ry
+ | SynDef knx, SynDef kny -> KerName.equal knx kny
+ | (TrueGlobal _ | SynDef _), _ -> false
+
+ let compare x y =
+ if x == y then 0
+ else match x, y with
+ | TrueGlobal rx, TrueGlobal ry -> GlobRef.Ordered_env.compare rx ry
+ | SynDef knx, SynDef kny -> KerName.compare knx kny
+ | TrueGlobal _, SynDef _ -> -1
+ | SynDef _, TrueGlobal _ -> 1
+
+ open Hashset.Combine
+
+ let hash = function
+ | TrueGlobal gr -> combinesmall 1 (GlobRef.Ordered_env.hash gr)
+ | SynDef kn -> combinesmall 2 (KerName.hash kn)
+
+end
+
+type global_reference_or_constr =
+ | IsGlobal of global_reference
+ | IsConstr of constr
+
+(* Deprecated *)
+let eq_gr = GlobRef.equal
diff --git a/library/globnames.mli b/library/globnames.mli
new file mode 100644
index 0000000000..d49ed453f5
--- /dev/null
+++ b/library/globnames.mli
@@ -0,0 +1,84 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+open Constr
+open Mod_subst
+
+(** {6 Global reference is a kernel side type for all references together } *)
+type global_reference = GlobRef.t =
+ | VarRef of variable (** A reference to the section-context. *)
+ | ConstRef of Constant.t (** A reference to the environment. *)
+ | IndRef of inductive (** A reference to an inductive type. *)
+ | ConstructRef of constructor (** A reference to a constructor of an inductive type. *)
+[@@ocaml.deprecated "Use Names.GlobRef.t"]
+
+val isVarRef : GlobRef.t -> bool
+val isConstRef : GlobRef.t -> bool
+val isIndRef : GlobRef.t -> bool
+val isConstructRef : GlobRef.t -> bool
+
+val eq_gr : GlobRef.t -> GlobRef.t -> bool
+[@@ocaml.deprecated "Use Names.GlobRef.equal"]
+val canonical_gr : GlobRef.t -> GlobRef.t
+
+val destVarRef : GlobRef.t -> variable
+val destConstRef : GlobRef.t -> Constant.t
+val destIndRef : GlobRef.t -> inductive
+val destConstructRef : GlobRef.t -> constructor
+
+val is_global : GlobRef.t -> constr -> bool
+
+val subst_constructor : substitution -> constructor -> constructor
+val subst_global : substitution -> GlobRef.t -> GlobRef.t * constr Univ.univ_abstracted option
+val subst_global_reference : substitution -> GlobRef.t -> GlobRef.t
+
+(** This constr is not safe to be typechecked, universe polymorphism is not
+ handled here: just use for printing *)
+val printable_constr_of_global : GlobRef.t -> constr
+
+(** Turn a construction denoting a global reference into a global reference;
+ raise [Not_found] if not a global reference *)
+val global_of_constr : constr -> GlobRef.t
+
+module RefOrdered = Names.GlobRef.Ordered
+[@@ocaml.deprecated "Use Names.GlobRef.Ordered"]
+
+module RefOrdered_env = Names.GlobRef.Ordered_env
+[@@ocaml.deprecated "Use Names.GlobRef.Ordered_env"]
+
+module Refset = Names.GlobRef.Set
+[@@ocaml.deprecated "Use Names.GlobRef.Set"]
+module Refmap = Names.GlobRef.Map
+[@@ocaml.deprecated "Use Names.GlobRef.Map"]
+
+module Refset_env = GlobRef.Set_env
+[@@ocaml.deprecated "Use Names.GlobRef.Set_env"]
+module Refmap_env = GlobRef.Map_env
+[@@ocaml.deprecated "Use Names.GlobRef.Map_env"]
+
+(** {6 Extended global references } *)
+
+type syndef_name = KerName.t
+
+type extended_global_reference =
+ | TrueGlobal of GlobRef.t
+ | SynDef of syndef_name
+
+module ExtRefOrdered : sig
+ type t = extended_global_reference
+ val compare : t -> t -> int
+ val equal : t -> t -> bool
+ val hash : t -> int
+end
+
+type global_reference_or_constr =
+ | IsGlobal of GlobRef.t
+ | IsConstr of constr
diff --git a/library/goptions.ml b/library/goptions.ml
new file mode 100644
index 0000000000..1b907fd966
--- /dev/null
+++ b/library/goptions.ml
@@ -0,0 +1,436 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(* This module manages customization parameters at the vernacular level *)
+
+open Pp
+open CErrors
+open Util
+open Libobject
+open Libnames
+open Mod_subst
+
+type option_name = string list
+type option_value =
+ | BoolValue of bool
+ | IntValue of int option
+ | StringValue of string
+ | StringOptValue of string option
+
+(** Summary of an option status *)
+type option_state = {
+ opt_depr : bool;
+ opt_name : string;
+ opt_value : option_value;
+}
+
+(****************************************************************************)
+(* 0- Common things *)
+
+let nickname table = String.concat " " table
+
+let error_undeclared_key key =
+ user_err ~hdr:"Goptions" (str (nickname key) ++ str ": no table or option of this type")
+
+(****************************************************************************)
+(* 1- Tables *)
+
+class type ['a] table_of_A =
+object
+ method add : 'a -> unit
+ method remove : 'a -> unit
+ method mem : 'a -> unit
+ method print : unit
+end
+
+module MakeTable =
+ functor
+ (A : sig
+ type t
+ type key
+ val compare : t -> t -> int
+ val table : (string * key table_of_A) list ref
+ val encode : key -> t
+ val subst : substitution -> t -> t
+ val printer : t -> Pp.t
+ val key : option_name
+ val title : string
+ val member_message : t -> bool -> Pp.t
+ end) ->
+ struct
+ type option_mark =
+ | GOadd
+ | GOrmv
+
+ let nick = nickname A.key
+
+ let _ =
+ if String.List.mem_assoc nick !A.table then
+ user_err Pp.(str "Sorry, this table name (" ++ str nick ++ str ") is already used.")
+
+ module MySet = Set.Make (struct type t = A.t let compare = A.compare end)
+
+ let t = Summary.ref MySet.empty ~name:nick
+
+ let (add_option,remove_option) =
+ let cache_options (_,(f,p)) = match f with
+ | GOadd -> t := MySet.add p !t
+ | GOrmv -> t := MySet.remove p !t in
+ let load_options i o = if Int.equal i 1 then cache_options o in
+ let subst_options (subst,(f,p as obj)) =
+ let p' = A.subst subst p in
+ if p' == p then obj else
+ (f,p')
+ in
+ let inGo : option_mark * A.t -> obj =
+ Libobject.declare_object {(Libobject.default_object nick) with
+ Libobject.load_function = load_options;
+ Libobject.open_function = load_options;
+ Libobject.cache_function = cache_options;
+ Libobject.subst_function = subst_options;
+ Libobject.classify_function = (fun x -> Substitute x)}
+ in
+ ((fun c -> Lib.add_anonymous_leaf (inGo (GOadd, c))),
+ (fun c -> Lib.add_anonymous_leaf (inGo (GOrmv, c))))
+
+ let print_table table_name printer table =
+ Feedback.msg_notice
+ (str table_name ++
+ (hov 0
+ (if MySet.is_empty table then str " None" ++ fnl ()
+ else MySet.fold
+ (fun a b -> spc () ++ printer a ++ b)
+ table (mt ()) ++ str "." ++ fnl ())))
+
+ class table_of_A () =
+ object
+ method add x = add_option (A.encode x)
+ method remove x = remove_option (A.encode x)
+ method mem x =
+ let y = A.encode x in
+ let answer = MySet.mem y !t in
+ Feedback.msg_info (A.member_message y answer)
+ method print = print_table A.title A.printer !t
+ end
+
+ let _ = A.table := (nick,new table_of_A ())::!A.table
+ let active c = MySet.mem c !t
+ let elements () = MySet.elements !t
+ end
+
+let string_table = ref []
+
+let get_string_table k = String.List.assoc (nickname k) !string_table
+
+module type StringConvertArg =
+sig
+ val key : option_name
+ val title : string
+ val member_message : string -> bool -> Pp.t
+end
+
+module StringConvert = functor (A : StringConvertArg) ->
+struct
+ type t = string
+ type key = string
+ let compare = String.compare
+ let table = string_table
+ let encode x = x
+ let subst _ x = x
+ let printer = str
+ let key = A.key
+ let title = A.title
+ let member_message = A.member_message
+end
+
+module MakeStringTable =
+ functor (A : StringConvertArg) -> MakeTable (StringConvert(A))
+
+let ref_table = ref []
+
+let get_ref_table k = String.List.assoc (nickname k) !ref_table
+
+module type RefConvertArg =
+sig
+ type t
+ val compare : t -> t -> int
+ val encode : qualid -> t
+ val subst : substitution -> t -> t
+ val printer : t -> Pp.t
+ val key : option_name
+ val title : string
+ val member_message : t -> bool -> Pp.t
+end
+
+module RefConvert = functor (A : RefConvertArg) ->
+struct
+ type t = A.t
+ type key = qualid
+ let compare = A.compare
+ let table = ref_table
+ let encode = A.encode
+ let subst = A.subst
+ let printer = A.printer
+ let key = A.key
+ let title = A.title
+ let member_message = A.member_message
+end
+
+module MakeRefTable =
+ functor (A : RefConvertArg) -> MakeTable (RefConvert(A))
+
+(****************************************************************************)
+(* 2- Flags. *)
+
+type 'a option_sig = {
+ optdepr : bool;
+ optname : string;
+ optkey : option_name;
+ optread : unit -> 'a;
+ optwrite : 'a -> unit }
+
+type option_locality = OptDefault | OptLocal | OptExport | OptGlobal
+
+type option_mod = OptSet | OptAppend
+
+module OptionOrd =
+struct
+ type t = option_name
+ let compare opt1 opt2 = List.compare String.compare opt1 opt2
+end
+
+module OptionMap = Map.Make(OptionOrd)
+
+let value_tab = ref OptionMap.empty
+
+(* This raises Not_found if option of key [key] is unknown *)
+
+let get_option key = OptionMap.find key !value_tab
+
+let check_key key = try
+ let _ = get_option key in
+ user_err Pp.(str "Sorry, this option name ("++ str (nickname key) ++ str ") is already used.")
+with Not_found ->
+ if String.List.mem_assoc (nickname key) !string_table
+ || String.List.mem_assoc (nickname key) !ref_table
+ then user_err Pp.(str "Sorry, this option name (" ++ str (nickname key) ++ str ") is already used.")
+
+open Libobject
+
+let warn_deprecated_option =
+ CWarnings.create ~name:"deprecated-option" ~category:"deprecated"
+ (fun key -> str "Option" ++ spc () ++ str (nickname key) ++
+ strbrk " is deprecated")
+
+let declare_option cast uncast append ?(preprocess = fun x -> x)
+ { optdepr=depr; optname=name; optkey=key; optread=read; optwrite=write } =
+ check_key key;
+ let default = read() in
+ let change =
+ let _ = Summary.declare_summary (nickname key)
+ { Summary.freeze_function = (fun ~marshallable -> read ());
+ Summary.unfreeze_function = write;
+ Summary.init_function = (fun () -> write default) } in
+ let cache_options (_,(l,m,v)) =
+ match m with
+ | OptSet -> write v
+ | OptAppend -> write (append (read ()) v) in
+ let load_options i (_, (l, _, _) as o) = match l with
+ | OptGlobal -> cache_options o
+ | OptExport -> ()
+ | OptLocal | OptDefault ->
+ (* Ruled out by classify_function *)
+ assert false
+ in
+ let open_options i (_, (l, _, _) as o) = match l with
+ | OptExport -> if Int.equal i 1 then cache_options o
+ | OptGlobal -> ()
+ | OptLocal | OptDefault ->
+ (* Ruled out by classify_function *)
+ assert false
+ in
+ let subst_options (subst,obj) = obj in
+ let discharge_options (_,(l,_,_ as o)) =
+ match l with OptLocal -> None | (OptExport | OptGlobal | OptDefault) -> Some o in
+ let classify_options (l,_,_ as o) =
+ match l with (OptExport | OptGlobal) -> Substitute o | (OptLocal | OptDefault) -> Dispose in
+ let options : option_locality * option_mod * _ -> obj =
+ declare_object
+ { (default_object (nickname key)) with
+ load_function = load_options;
+ open_function = open_options;
+ cache_function = cache_options;
+ subst_function = subst_options;
+ discharge_function = discharge_options;
+ classify_function = classify_options } in
+ (fun l m v -> let v = preprocess v in Lib.add_anonymous_leaf (options (l, m, v)))
+ in
+ let warn () = if depr then warn_deprecated_option key in
+ let cread () = cast (read ()) in
+ let cwrite l v = warn (); change l OptSet (uncast v) in
+ let cappend l v = warn (); change l OptAppend (uncast v) in
+ value_tab := OptionMap.add key (name, depr, (cread,cwrite,cappend)) !value_tab
+
+let declare_int_option =
+ declare_option
+ (fun v -> IntValue v)
+ (function IntValue v -> v | _ -> anomaly (Pp.str "async_option."))
+ (fun _ _ -> anomaly (Pp.str "async_option."))
+let declare_bool_option =
+ declare_option
+ (fun v -> BoolValue v)
+ (function BoolValue v -> v | _ -> anomaly (Pp.str "async_option."))
+ (fun _ _ -> anomaly (Pp.str "async_option."))
+let declare_string_option =
+ declare_option
+ (fun v -> StringValue v)
+ (function StringValue v -> v | _ -> anomaly (Pp.str "async_option."))
+ (fun x y -> x^","^y)
+let declare_stringopt_option =
+ declare_option
+ (fun v -> StringOptValue v)
+ (function StringOptValue v -> v | _ -> anomaly (Pp.str "async_option."))
+ (fun _ _ -> anomaly (Pp.str "async_option."))
+
+let declare_bool_option_and_ref ~depr ~name ~key ~(value:bool) =
+ let r_opt = ref value in
+ let optwrite v = r_opt := v in
+ let optread () = !r_opt in
+ let _ = declare_bool_option {
+ optdepr = depr;
+ optname = name;
+ optkey = key;
+ optread; optwrite
+ } in
+ optread
+
+(* 3- User accessible commands *)
+
+(* Setting values of options *)
+
+let warn_unknown_option =
+ CWarnings.create ~name:"unknown-option" ~category:"option"
+ (fun key -> strbrk "There is no option " ++
+ str (nickname key) ++ str ".")
+
+let set_option_value ?(locality = OptDefault) check_and_cast key v =
+ let opt = try Some (get_option key) with Not_found -> None in
+ match opt with
+ | None -> warn_unknown_option key
+ | Some (name, depr, (read,write,append)) ->
+ write locality (check_and_cast v (read ()))
+
+let show_value_type = function
+ | BoolValue _ -> "bool"
+ | IntValue _ -> "int"
+ | StringValue _ -> "string"
+ | StringOptValue _ -> "string"
+
+let bad_type_error opt_value actual_type =
+ user_err Pp.(str "Bad type of value for this option:" ++ spc() ++
+ str "expected " ++ str (show_value_type opt_value) ++
+ str ", got " ++ str actual_type ++ str ".")
+
+let check_int_value v = function
+ | IntValue _ -> IntValue v
+ | optv -> bad_type_error optv "int"
+
+let check_bool_value v = function
+ | BoolValue _ -> BoolValue v
+ | optv -> bad_type_error optv "bool"
+
+let check_string_value v = function
+ | StringValue _ -> StringValue v
+ | StringOptValue _ -> StringOptValue (Some v)
+ | optv -> bad_type_error optv "string"
+
+let check_unset_value v = function
+ | BoolValue _ -> BoolValue false
+ | IntValue _ -> IntValue None
+ | StringOptValue _ -> StringOptValue None
+ | optv -> bad_type_error optv "nothing"
+
+(* Nota: For compatibility reasons, some errors are treated as
+ warning. This allows a script to refer to an option that doesn't
+ exist anymore *)
+
+let set_int_option_value_gen ?locality =
+ set_option_value ?locality check_int_value
+let set_bool_option_value_gen ?locality key v =
+ set_option_value ?locality check_bool_value key v
+let set_string_option_value_gen ?locality =
+ set_option_value ?locality check_string_value
+let unset_option_value_gen ?locality key =
+ set_option_value ?locality check_unset_value key ()
+
+let set_string_option_append_value_gen ?(locality = OptDefault) key v =
+ let opt = try Some (get_option key) with Not_found -> None in
+ match opt with
+ | None -> warn_unknown_option key
+ | Some (name, depr, (read,write,append)) ->
+ append locality (check_string_value v (read ()))
+
+let set_int_option_value opt v = set_int_option_value_gen opt v
+let set_bool_option_value opt v = set_bool_option_value_gen opt v
+let set_string_option_value opt v = set_string_option_value_gen opt v
+
+(* Printing options/tables *)
+
+let msg_option_value (name,v) =
+ match v with
+ | BoolValue true -> str "on"
+ | BoolValue false -> str "off"
+ | IntValue (Some n) -> int n
+ | IntValue None -> str "undefined"
+ | StringValue s -> quote (str s)
+ | StringOptValue None -> str"undefined"
+ | StringOptValue (Some s) -> quote (str s)
+(* | IdentValue r -> pr_global_env Id.Set.empty r *)
+
+let print_option_value key =
+ let (name, depr, (read,_,_)) = get_option key in
+ let s = read () in
+ match s with
+ | BoolValue b ->
+ Feedback.msg_info (str "The " ++ str name ++ str " mode is " ++ str (if b then "on" else "off"))
+ | _ ->
+ Feedback.msg_info (str "Current value of " ++ str name ++ str " is " ++ msg_option_value (name, s))
+
+let get_tables () =
+ let tables = !value_tab in
+ let fold key (name, depr, (read,_,_)) accu =
+ let state = {
+ opt_name = name;
+ opt_depr = depr;
+ opt_value = read ();
+ } in
+ OptionMap.add key state accu
+ in
+ OptionMap.fold fold tables OptionMap.empty
+
+let print_tables () =
+ let print_option key name value depr =
+ let msg = str " " ++ str (nickname key) ++ str ": " ++ msg_option_value (name, value) in
+ if depr then msg ++ str " [DEPRECATED]" ++ fnl ()
+ else msg ++ fnl ()
+ in
+ str "Options:" ++ fnl () ++
+ OptionMap.fold
+ (fun key (name, depr, (read,_,_)) p ->
+ p ++ print_option key name (read ()) depr)
+ !value_tab (mt ()) ++
+ str "Tables:" ++ fnl () ++
+ List.fold_right
+ (fun (nickkey,_) p -> p ++ str " " ++ str nickkey ++ fnl ())
+ !string_table (mt ()) ++
+ List.fold_right
+ (fun (nickkey,_) p -> p ++ str " " ++ str nickkey ++ fnl ())
+ !ref_table (mt ()) ++
+ fnl ()
diff --git a/library/goptions.mli b/library/goptions.mli
new file mode 100644
index 0000000000..b91553bf3c
--- /dev/null
+++ b/library/goptions.mli
@@ -0,0 +1,185 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** This module manages customization parameters at the vernacular level *)
+
+(** Two kinds of things are managed : tables and options value
+ - Tables are created by applying the [MakeTable] functor.
+ - Variables storing options value are created by applying one of the
+ [declare_int_option], [declare_bool_option], ... functions.
+
+ Each table/option is uniquely identified by a key of type [option_name]
+ which consists in a list of strings. Note that for parsing constraints,
+ table names must not be made of more than 2 strings while option names
+ can be of arbitrary length.
+
+ The declaration of a table, say of name [["Toto";"Titi"]]
+ automatically makes available the following vernacular commands:
+
+ Add Toto Titi foo.
+ Remove Toto Titi foo.
+ Print Toto Titi.
+ Test Toto Titi.
+
+ The declaration of a non boolean option value, say of name
+ [["Tata";"Tutu";"Titi"]], automatically makes available the
+ following vernacular commands:
+
+ Set Tata Tutu Titi val.
+ Print Table Tata Tutu Titi.
+
+ If it is the declaration of a boolean value, the following
+ vernacular commands are made available:
+
+ Set Tata Tutu Titi.
+ Unset Tata Tutu Titi.
+ Print Table Tata Tutu Titi. (** synonym: Test Table Tata Tutu Titi. *)
+
+ All options are synchronized with the document.
+*)
+
+open Libnames
+open Mod_subst
+
+type option_name = string list
+
+type option_locality = OptDefault | OptLocal | OptExport | OptGlobal
+
+(** {6 Tables. } *)
+
+(** The functor [MakeStringTable] declares a table containing objects
+ of type [string]; the function [member_message] say what to print
+ when invoking the "Test Toto Titi foo." command; at the end [title]
+ is the table name printed when invoking the "Print Toto Titi."
+ command; [active] is roughly the internal version of the vernacular
+ "Test ...": it tells if a given object is in the table; [elements]
+ returns the list of elements of the table *)
+
+module MakeStringTable :
+ functor
+ (A : sig
+ val key : option_name
+ val title : string
+ val member_message : string -> bool -> Pp.t
+ end) ->
+sig
+ val active : string -> bool
+ val elements : unit -> string list
+end
+
+(** The functor [MakeRefTable] declares a new table of objects of type
+ [A.t] practically denoted by [reference]; the encoding function
+ [encode : reference -> A.t] is typically a globalization function,
+ possibly with some restriction checks; the function
+ [member_message] say what to print when invoking the "Test Toto
+ Titi foo." command; at the end [title] is the table name printed
+ when invoking the "Print Toto Titi." command; [active] is roughly
+ the internal version of the vernacular "Test ...": it tells if a
+ given object is in the table. *)
+
+module MakeRefTable :
+ functor
+ (A : sig
+ type t
+ val compare : t -> t -> int
+ val encode : qualid -> t
+ val subst : substitution -> t -> t
+ val printer : t -> Pp.t
+ val key : option_name
+ val title : string
+ val member_message : t -> bool -> Pp.t
+ end) ->
+ sig
+ val active : A.t -> bool
+ val elements : unit -> A.t list
+ end
+
+
+(** {6 Options. } *)
+
+(** These types and function are for declaring a new option of name [key]
+ and access functions [read] and [write]; the parameter [name] is the option name
+ used when printing the option value (command "Print Toto Titi." *)
+
+type 'a option_sig = {
+ optdepr : bool;
+ (** whether the option is DEPRECATED *)
+ optname : string;
+ (** a short string describing the option *)
+ optkey : option_name;
+ (** the low-level name of this option *)
+ optread : unit -> 'a;
+ optwrite : 'a -> unit
+}
+
+(** The [preprocess] function is triggered before setting the option. It can be
+ used to emit a warning on certain values, and clean-up the final value. *)
+
+val declare_int_option : ?preprocess:(int option -> int option) ->
+ int option option_sig -> unit
+val declare_bool_option : ?preprocess:(bool -> bool) ->
+ bool option_sig -> unit
+val declare_string_option: ?preprocess:(string -> string) ->
+ string option_sig -> unit
+val declare_stringopt_option: ?preprocess:(string option -> string option) ->
+ string option option_sig -> unit
+
+(** Helper to declare a reference controlled by an option. Read-only
+ as to avoid races. *)
+val declare_bool_option_and_ref : depr:bool -> name:string -> key:option_name -> value:bool -> (unit -> bool)
+
+(** {6 Special functions supposed to be used only in vernacentries.ml } *)
+
+module OptionMap : CSig.MapS with type key = option_name
+
+val get_string_table :
+ option_name ->
+ < add : string -> unit;
+ remove : string -> unit;
+ mem : string -> unit;
+ print : unit >
+
+val get_ref_table :
+ option_name ->
+ < add : qualid -> unit;
+ remove : qualid -> unit;
+ mem : qualid -> unit;
+ print : unit >
+
+(** The first argument is a locality flag. *)
+val set_int_option_value_gen : ?locality:option_locality -> option_name -> int option -> unit
+val set_bool_option_value_gen : ?locality:option_locality -> option_name -> bool -> unit
+val set_string_option_value_gen : ?locality:option_locality -> option_name -> string -> unit
+val set_string_option_append_value_gen : ?locality:option_locality -> option_name -> string -> unit
+val unset_option_value_gen : ?locality:option_locality -> option_name -> unit
+
+val set_int_option_value : option_name -> int option -> unit
+val set_bool_option_value : option_name -> bool -> unit
+val set_string_option_value : option_name -> string -> unit
+
+val print_option_value : option_name -> unit
+
+type option_value =
+ | BoolValue of bool
+ | IntValue of int option
+ | StringValue of string
+ | StringOptValue of string option
+
+(** Summary of an option status *)
+type option_state = {
+ opt_depr : bool;
+ opt_name : string;
+ opt_value : option_value;
+}
+
+val get_tables : unit -> option_state OptionMap.t
+val print_tables : unit -> Pp.t
+
+val error_undeclared_key : option_name -> 'a
diff --git a/library/keys.ml b/library/keys.ml
new file mode 100644
index 0000000000..58883ccc88
--- /dev/null
+++ b/library/keys.ml
@@ -0,0 +1,159 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** Keys for unification and indexing *)
+
+open Names
+open Constr
+open Libobject
+open Globnames
+
+type key =
+ | KGlob of GlobRef.t
+ | KLam
+ | KLet
+ | KProd
+ | KSort
+ | KCase
+ | KFix
+ | KCoFix
+ | KRel
+
+module KeyOrdered = struct
+ type t = key
+
+ let hash gr =
+ match gr with
+ | KGlob gr -> 8 + GlobRef.Ordered.hash gr
+ | KLam -> 0
+ | KLet -> 1
+ | KProd -> 2
+ | KSort -> 3
+ | KCase -> 4
+ | KFix -> 5
+ | KCoFix -> 6
+ | KRel -> 7
+
+ let compare gr1 gr2 =
+ match gr1, gr2 with
+ | KGlob gr1, KGlob gr2 -> GlobRef.Ordered.compare gr1 gr2
+ | _, KGlob _ -> -1
+ | KGlob _, _ -> 1
+ | k, k' -> Int.compare (hash k) (hash k')
+
+ let equal k1 k2 =
+ match k1, k2 with
+ | KGlob gr1, KGlob gr2 -> GlobRef.Ordered.equal gr1 gr2
+ | _, KGlob _ -> false
+ | KGlob _, _ -> false
+ | k, k' -> k == k'
+end
+
+module Keymap = HMap.Make(KeyOrdered)
+module Keyset = Keymap.Set
+
+(* Mapping structure for references to be considered equivalent *)
+
+let keys = Summary.ref Keymap.empty ~name:"Keys_decl"
+
+let add_kv k v m =
+ try Keymap.modify k (fun k' vs -> Keyset.add v vs) m
+ with Not_found -> Keymap.add k (Keyset.singleton v) m
+
+let add_keys k v =
+ keys := add_kv k v (add_kv v k !keys)
+
+let equiv_keys k k' =
+ k == k' || KeyOrdered.equal k k' ||
+ try Keyset.mem k' (Keymap.find k !keys)
+ with Not_found -> false
+
+(** Registration of keys as an object *)
+
+let load_keys _ (_,(ref,ref')) =
+ add_keys ref ref'
+
+let cache_keys o =
+ load_keys 1 o
+
+let subst_key subst k =
+ match k with
+ | KGlob gr -> KGlob (subst_global_reference subst gr)
+ | _ -> k
+
+let subst_keys (subst,(k,k')) =
+ (subst_key subst k, subst_key subst k')
+
+let discharge_key = function
+ | KGlob (VarRef _ as g) when Lib.is_in_section g -> None
+ | x -> Some x
+
+let discharge_keys (_,(k,k')) =
+ match discharge_key k, discharge_key k' with
+ | Some x, Some y -> Some (x, y)
+ | _ -> None
+
+type key_obj = key * key
+
+let inKeys : key_obj -> obj =
+ declare_object @@ superglobal_object "KEYS"
+ ~cache:cache_keys
+ ~subst:(Some subst_keys)
+ ~discharge:discharge_keys
+
+let declare_equiv_keys ref ref' =
+ Lib.add_anonymous_leaf (inKeys (ref,ref'))
+
+let constr_key kind c =
+ let open Globnames in
+ try
+ let rec aux k =
+ match kind k with
+ | Const (c, _) -> KGlob (ConstRef c)
+ | Ind (i, u) -> KGlob (IndRef i)
+ | Construct (c,u) -> KGlob (ConstructRef c)
+ | Var id -> KGlob (VarRef id)
+ | App (f, _) -> aux f
+ | Proj (p, _) -> KGlob (ConstRef (Projection.constant p))
+ | Cast (p, _, _) -> aux p
+ | Lambda _ -> KLam
+ | Prod _ -> KProd
+ | Case _ -> KCase
+ | Fix _ -> KFix
+ | CoFix _ -> KCoFix
+ | Rel _ -> KRel
+ | Meta _ -> raise Not_found
+ | Evar _ -> raise Not_found
+ | Sort _ -> KSort
+ | LetIn _ -> KLet
+ in Some (aux c)
+ with Not_found -> None
+
+open Pp
+
+let pr_key pr_global = function
+ | KGlob gr -> pr_global gr
+ | KLam -> str"Lambda"
+ | KLet -> str"Let"
+ | KProd -> str"Product"
+ | KSort -> str"Sort"
+ | KCase -> str"Case"
+ | KFix -> str"Fix"
+ | KCoFix -> str"CoFix"
+ | KRel -> str"Rel"
+
+let pr_keyset pr_global v =
+ prlist_with_sep spc (pr_key pr_global) (Keyset.elements v)
+
+let pr_mapping pr_global k v =
+ pr_key pr_global k ++ str" <-> " ++ pr_keyset pr_global v
+
+let pr_keys pr_global =
+ Keymap.fold (fun k v acc -> pr_mapping pr_global k v ++ fnl () ++ acc) !keys (mt())
diff --git a/library/keys.mli b/library/keys.mli
new file mode 100644
index 0000000000..198383650a
--- /dev/null
+++ b/library/keys.mli
@@ -0,0 +1,23 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+type key
+
+val declare_equiv_keys : key -> key -> unit
+(** Declare two keys as being equivalent. *)
+
+val equiv_keys : key -> key -> bool
+(** Check equivalence of keys. *)
+
+val constr_key : ('a -> ('a, 't, 'u, 'i) Constr.kind_of_term) -> 'a -> key option
+(** Compute the head key of a term. *)
+
+val pr_keys : (Names.GlobRef.t -> Pp.t) -> Pp.t
+(** Pretty-print the mapping *)
diff --git a/library/kindops.ml b/library/kindops.ml
new file mode 100644
index 0000000000..247319fa2f
--- /dev/null
+++ b/library/kindops.ml
@@ -0,0 +1,37 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Decl_kinds
+
+(** Operations about types defined in [Decl_kinds] *)
+
+let logical_kind_of_goal_kind = function
+ | DefinitionBody d -> IsDefinition d
+ | Proof s -> IsProof s
+
+let string_of_theorem_kind = function
+ | Theorem -> "Theorem"
+ | Lemma -> "Lemma"
+ | Fact -> "Fact"
+ | Remark -> "Remark"
+ | Property -> "Property"
+ | Proposition -> "Proposition"
+ | Corollary -> "Corollary"
+
+let string_of_definition_object_kind = function
+ | Definition -> "Definition"
+ | Example -> "Example"
+ | Coercion -> "Coercion"
+ | SubClass -> "SubClass"
+ | CanonicalStructure -> "Canonical Structure"
+ | Instance -> "Instance"
+ | Let -> "Let"
+ | (StructureComponent|Scheme|CoFixpoint|Fixpoint|IdentityCoercion|Method) ->
+ CErrors.anomaly (Pp.str "Internal definition kind.")
diff --git a/library/kindops.mli b/library/kindops.mli
new file mode 100644
index 0000000000..df39019da4
--- /dev/null
+++ b/library/kindops.mli
@@ -0,0 +1,17 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Decl_kinds
+
+(** Operations about types defined in [Decl_kinds] *)
+
+val logical_kind_of_goal_kind : goal_object_kind -> logical_kind
+val string_of_theorem_kind : theorem_kind -> string
+val string_of_definition_object_kind : definition_object_kind -> string
diff --git a/library/lib.ml b/library/lib.ml
new file mode 100644
index 0000000000..d4381a6923
--- /dev/null
+++ b/library/lib.ml
@@ -0,0 +1,668 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+open CErrors
+open Util
+open Names
+open Libnames
+open Globnames
+open Libobject
+open Context.Named.Declaration
+
+module NamedDecl = Context.Named.Declaration
+
+type is_type = bool (* Module Type or just Module *)
+type export = bool option (* None for a Module Type *)
+
+(* let make_oname (dirpath,(mp,dir)) id = *)
+let make_oname Nametab.{ obj_dir; obj_mp } id =
+ Names.(make_path obj_dir id, KerName.make obj_mp (Label.of_id id))
+
+(* let make_oname (dirpath,(mp,dir)) id = *)
+type node =
+ | Leaf of obj
+ | CompilingLibrary of Nametab.object_prefix
+ | OpenedModule of is_type * export * Nametab.object_prefix * Summary.frozen
+ | OpenedSection of Nametab.object_prefix * Summary.frozen
+
+type library_entry = object_name * node
+
+type library_segment = library_entry list
+
+type lib_objects = (Names.Id.t * obj) list
+
+let module_kind is_type =
+ if is_type then "module type" else "module"
+
+let iter_objects f i prefix =
+ List.iter (fun (id,obj) -> f i (make_oname prefix id, obj))
+
+let load_objects i pr = iter_objects load_object i pr
+let open_objects i pr = iter_objects open_object i pr
+
+let subst_objects subst seg =
+ let subst_one = fun (id,obj as node) ->
+ let obj' = subst_object (subst,obj) in
+ if obj' == obj then node else
+ (id, obj')
+ in
+ List.Smart.map subst_one seg
+
+(*let load_and_subst_objects i prefix subst seg =
+ List.rev (List.fold_left (fun seg (id,obj as node) ->
+ let obj' = subst_object (make_oname prefix id, subst, obj) in
+ let node = if obj == obj' then node else (id, obj') in
+ load_object i (make_oname prefix id, obj');
+ node :: seg) [] seg)
+*)
+let classify_segment seg =
+ let rec clean ((substl,keepl,anticipl) as acc) = function
+ | (_,CompilingLibrary _) :: _ | [] -> acc
+ | ((sp,kn),Leaf o) :: stk ->
+ let id = Names.Label.to_id (Names.KerName.label kn) in
+ (match classify_object o with
+ | Dispose -> clean acc stk
+ | Keep o' ->
+ clean (substl, (id,o')::keepl, anticipl) stk
+ | Substitute o' ->
+ clean ((id,o')::substl, keepl, anticipl) stk
+ | Anticipate o' ->
+ clean (substl, keepl, o'::anticipl) stk)
+ | (_,OpenedSection _) :: _ -> user_err Pp.(str "there are still opened sections")
+ | (_,OpenedModule (ty,_,_,_)) :: _ ->
+ user_err ~hdr:"Lib.classify_segment"
+ (str "there are still opened " ++ str (module_kind ty) ++ str "s")
+ in
+ clean ([],[],[]) (List.rev seg)
+
+
+let segment_of_objects prefix =
+ List.map (fun (id,obj) -> (make_oname prefix id, Leaf obj))
+
+(* We keep trace of operations in the stack [lib_stk].
+ [path_prefix] is the current path of sections, where sections are stored in
+ ``correct'' order, the oldest coming first in the list. It may seems
+ costly, but in practice there is not so many openings and closings of
+ sections, but on the contrary there are many constructions of section
+ paths based on the library path. *)
+
+let initial_prefix = Nametab.{
+ obj_dir = default_library;
+ obj_mp = ModPath.initial;
+ obj_sec = DirPath.empty;
+}
+
+type lib_state = {
+ comp_name : DirPath.t option;
+ lib_stk : library_segment;
+ path_prefix : Nametab.object_prefix;
+}
+
+let initial_lib_state = {
+ comp_name = None;
+ lib_stk = [];
+ path_prefix = initial_prefix;
+}
+
+let lib_state = ref initial_lib_state
+
+let library_dp () =
+ match !lib_state.comp_name with Some m -> m | None -> default_library
+
+(* [path_prefix] is a pair of absolute dirpath and a pair of current
+ module path and relative section path *)
+
+let cwd () = !lib_state.path_prefix.Nametab.obj_dir
+let current_mp () = !lib_state.path_prefix.Nametab.obj_mp
+let current_sections () = !lib_state.path_prefix.Nametab.obj_sec
+
+let sections_depth () = List.length (Names.DirPath.repr (current_sections ()))
+let sections_are_opened () = not (Names.DirPath.is_empty (current_sections ()))
+
+let cwd_except_section () =
+ Libnames.pop_dirpath_n (sections_depth ()) (cwd ())
+
+let current_dirpath sec =
+ Libnames.drop_dirpath_prefix (library_dp ())
+ (if sec then cwd () else cwd_except_section ())
+
+let make_path id = Libnames.make_path (cwd ()) id
+
+let make_path_except_section id =
+ Libnames.make_path (cwd_except_section ()) id
+
+let make_kn id =
+ let mp = current_mp () in
+ Names.KerName.make mp (Names.Label.of_id id)
+
+let make_foname id = make_oname !lib_state.path_prefix id
+
+let recalc_path_prefix () =
+ let rec recalc = function
+ | (sp, OpenedSection (dir,_)) :: _ -> dir
+ | (sp, OpenedModule (_,_,dir,_)) :: _ -> dir
+ | (sp, CompilingLibrary dir) :: _ -> dir
+ | _::l -> recalc l
+ | [] -> initial_prefix
+ in
+ lib_state := { !lib_state with path_prefix = recalc !lib_state.lib_stk }
+
+let pop_path_prefix () =
+ let op = !lib_state.path_prefix in
+ lib_state := { !lib_state
+ with path_prefix = Nametab.{ op with obj_dir = pop_dirpath op.obj_dir;
+ obj_sec = pop_dirpath op.obj_sec;
+ } }
+
+let find_entry_p p =
+ let rec find = function
+ | [] -> raise Not_found
+ | ent::l -> if p ent then ent else find l
+ in
+ find !lib_state.lib_stk
+
+let find_entries_p p =
+ let rec find = function
+ | [] -> []
+ | ent::l -> if p ent then ent::find l else find l
+ in
+ find !lib_state.lib_stk
+
+let split_lib_gen test =
+ let rec collect after equal = function
+ | hd::before when test hd -> collect after (hd::equal) before
+ | before -> after,equal,before
+ in
+ let rec findeq after = function
+ | hd :: before when test hd -> collect after [hd] before
+ | hd :: before -> findeq (hd::after) before
+ | [] -> user_err Pp.(str "no such entry")
+ in
+ findeq [] !lib_state.lib_stk
+
+let eq_object_name (fp1, kn1) (fp2, kn2) =
+ eq_full_path fp1 fp2 && Names.KerName.equal kn1 kn2
+
+let split_lib sp =
+ let is_sp (nsp, _) = eq_object_name sp nsp in
+ split_lib_gen is_sp
+
+let split_lib_at_opening sp =
+ let is_sp (nsp, obj) = match obj with
+ | OpenedSection _ | OpenedModule _ | CompilingLibrary _ ->
+ eq_object_name nsp sp
+ | _ -> false
+ in
+ let a, s, b = split_lib_gen is_sp in
+ match s with
+ | [obj] -> (a, obj, b)
+ | _ -> assert false
+
+(* Adding operations. *)
+
+let add_entry sp node =
+ lib_state := { !lib_state with lib_stk = (sp,node) :: !lib_state.lib_stk }
+
+let pull_to_head oname =
+ lib_state := { !lib_state with lib_stk = (oname,List.assoc oname !lib_state.lib_stk) :: List.remove_assoc oname !lib_state.lib_stk }
+
+let anonymous_id =
+ let n = ref 0 in
+ fun () -> incr n; Names.Id.of_string ("_" ^ (string_of_int !n))
+
+let add_anonymous_entry node =
+ add_entry (make_foname (anonymous_id ())) node
+
+let add_leaf id obj =
+ if ModPath.equal (current_mp ()) ModPath.initial then
+ user_err Pp.(str "No session module started (use -top dir)");
+ let oname = make_foname id in
+ cache_object (oname,obj);
+ add_entry oname (Leaf obj);
+ oname
+
+let add_discharged_leaf id obj =
+ let oname = make_foname id in
+ let newobj = rebuild_object obj in
+ cache_object (oname,newobj);
+ add_entry oname (Leaf newobj)
+
+let add_leaves id objs =
+ let oname = make_foname id in
+ let add_obj obj =
+ add_entry oname (Leaf obj);
+ load_object 1 (oname,obj)
+ in
+ List.iter add_obj objs;
+ oname
+
+let add_anonymous_leaf ?(cache_first = true) obj =
+ let id = anonymous_id () in
+ let oname = make_foname id in
+ if cache_first then begin
+ cache_object (oname,obj);
+ add_entry oname (Leaf obj)
+ end else begin
+ add_entry oname (Leaf obj);
+ cache_object (oname,obj)
+ end
+
+(* Modules. *)
+
+let is_opening_node = function
+ | _,(OpenedSection _ | OpenedModule _) -> true
+ | _ -> false
+
+let is_opening_node_or_lib = function
+ | _,(CompilingLibrary _ | OpenedSection _ | OpenedModule _) -> true
+ | _ -> false
+
+let current_mod_id () =
+ try match find_entry_p is_opening_node_or_lib with
+ | oname,OpenedModule (_,_,_,fs) -> basename (fst oname)
+ | oname,CompilingLibrary _ -> basename (fst oname)
+ | _ -> user_err Pp.(str "you are not in a module")
+ with Not_found -> user_err Pp.(str "no opened modules")
+
+
+let start_mod is_type export id mp fs =
+ let dir = add_dirpath_suffix (!lib_state.path_prefix.Nametab.obj_dir) id in
+ let prefix = Nametab.{ obj_dir = dir; obj_mp = mp; obj_sec = Names.DirPath.empty } in
+ let exists =
+ if is_type then Nametab.exists_cci (make_path id)
+ else Nametab.exists_module dir
+ in
+ if exists then
+ user_err ~hdr:"open_module" (Id.print id ++ str " already exists");
+ add_entry (make_foname id) (OpenedModule (is_type,export,prefix,fs));
+ lib_state := { !lib_state with path_prefix = prefix} ;
+ prefix
+
+let start_module = start_mod false
+let start_modtype = start_mod true None
+
+let error_still_opened string oname =
+ let id = basename (fst oname) in
+ user_err
+ (str "The " ++ str string ++ str " " ++ Id.print id ++ str " is still opened.")
+
+let end_mod is_type =
+ let oname,fs =
+ try match find_entry_p is_opening_node with
+ | oname,OpenedModule (ty,_,_,fs) ->
+ if ty == is_type then oname, fs
+ else error_still_opened (module_kind ty) oname
+ | oname,OpenedSection _ -> error_still_opened "section" oname
+ | _ -> assert false
+ with Not_found -> user_err (Pp.str "No opened modules.")
+ in
+ let (after,mark,before) = split_lib_at_opening oname in
+ lib_state := { !lib_state with lib_stk = before };
+ let prefix = !lib_state.path_prefix in
+ recalc_path_prefix ();
+ (oname, prefix, fs, after)
+
+let end_module () = end_mod false
+let end_modtype () = end_mod true
+
+let contents () = !lib_state.lib_stk
+
+let contents_after sp = let (after,_,_) = split_lib sp in after
+
+(* Modules. *)
+
+(* TODO: use check_for_module ? *)
+let start_compilation s mp =
+ if !lib_state.comp_name != None then
+ user_err Pp.(str "compilation unit is already started");
+ if not (Names.DirPath.is_empty (!lib_state.path_prefix.Nametab.obj_sec)) then
+ user_err Pp.(str "some sections are already opened");
+ let prefix = Nametab.{ obj_dir = s; obj_mp = mp; obj_sec = DirPath.empty } in
+ add_anonymous_entry (CompilingLibrary prefix);
+ lib_state := { !lib_state with comp_name = Some s;
+ path_prefix = prefix }
+
+let open_blocks_message es =
+ let open_block_name = function
+ | oname, OpenedSection _ -> str "section " ++ Id.print (basename (fst oname))
+ | oname, OpenedModule (ty,_,_,_) -> str (module_kind ty) ++ spc () ++ Id.print (basename (fst oname))
+ | _ -> assert false in
+ str "The " ++ pr_enum open_block_name es ++ spc () ++
+ str "need" ++ str (if List.length es == 1 then "s" else "") ++ str " to be closed."
+
+let end_compilation_checks dir =
+ let _ = match find_entries_p is_opening_node with
+ | [] -> ()
+ | es -> user_err ~hdr:"Lib.end_compilation_checks" (open_blocks_message es) in
+ let is_opening_lib = function _,CompilingLibrary _ -> true | _ -> false
+ in
+ let oname =
+ try match find_entry_p is_opening_lib with
+ | (oname, CompilingLibrary prefix) -> oname
+ | _ -> assert false
+ with Not_found -> anomaly (Pp.str "No module declared.")
+ in
+ let _ =
+ match !lib_state.comp_name with
+ | None -> anomaly (Pp.str "There should be a module name...")
+ | Some m ->
+ if not (Names.DirPath.equal m dir) then anomaly
+ (str "The current open module has name" ++ spc () ++ DirPath.print m ++
+ spc () ++ str "and not" ++ spc () ++ DirPath.print m ++ str ".");
+ in
+ oname
+
+let end_compilation oname =
+ let (after,mark,before) = split_lib_at_opening oname in
+ lib_state := { !lib_state with comp_name = None };
+ !lib_state.path_prefix,after
+
+(* Returns true if we are inside an opened module or module type *)
+
+let is_module_gen which check =
+ let test = function
+ | _, OpenedModule (ty,_,_,_) -> which ty
+ | _ -> false
+ in
+ try
+ match find_entry_p test with
+ | _, OpenedModule (ty,_,_,_) -> check ty
+ | _ -> assert false
+ with Not_found -> false
+
+let is_module_or_modtype () = is_module_gen (fun _ -> true) (fun _ -> true)
+let is_modtype () = is_module_gen (fun b -> b) (fun _ -> true)
+let is_modtype_strict () = is_module_gen (fun _ -> true) (fun b -> b)
+let is_module () = is_module_gen (fun b -> not b) (fun _ -> true)
+
+(* Returns the opening node of a given name *)
+let find_opening_node id =
+ try
+ let oname,entry = find_entry_p is_opening_node in
+ let id' = basename (fst oname) in
+ if not (Names.Id.equal id id') then
+ user_err ~hdr:"Lib.find_opening_node"
+ (str "Last block to end has name " ++ Id.print id' ++ str ".");
+ entry
+ with Not_found -> user_err Pp.(str "There is nothing to end.")
+
+(* Discharge tables *)
+
+(* At each level of section, we remember
+ - the list of variables in this section
+ - the list of variables on which each constant depends in this section
+ - the list of variables on which each inductive depends in this section
+ - the list of substitution to do at section closing
+*)
+
+type variable_info = Constr.named_declaration * Decl_kinds.binding_kind
+
+type variable_context = variable_info list
+type abstr_info = {
+ abstr_ctx : variable_context;
+ abstr_subst : Univ.Instance.t;
+ abstr_uctx : Univ.AUContext.t;
+}
+type abstr_list = abstr_info Names.Cmap.t * abstr_info Names.Mindmap.t
+
+type secentry =
+ | Variable of (Names.Id.t * Decl_kinds.binding_kind *
+ Decl_kinds.polymorphic * Univ.ContextSet.t)
+ | Context of Univ.ContextSet.t
+
+let sectab =
+ Summary.ref ([] : (secentry list * Opaqueproof.work_list * abstr_list) list)
+ ~name:"section-context"
+
+let add_section () =
+ sectab := ([],(Names.Cmap.empty,Names.Mindmap.empty),
+ (Names.Cmap.empty,Names.Mindmap.empty)) :: !sectab
+
+let check_same_poly p vars =
+ let pred = function Context _ -> p = false | Variable (_, _, poly, _) -> p != poly in
+ if List.exists pred vars then
+ user_err Pp.(str "Cannot mix universe polymorphic and monomorphic declarations in sections.")
+
+let add_section_variable id impl poly ctx =
+ match !sectab with
+ | [] -> () (* because (Co-)Fixpoint temporarily uses local vars *)
+ | (vars,repl,abs)::sl ->
+ List.iter (fun tab -> check_same_poly poly (pi1 tab)) !sectab;
+ sectab := (Variable (id,impl,poly,ctx)::vars,repl,abs)::sl
+
+let add_section_context ctx =
+ match !sectab with
+ | [] -> () (* because (Co-)Fixpoint temporarily uses local vars *)
+ | (vars,repl,abs)::sl ->
+ check_same_poly true vars;
+ sectab := (Context ctx :: vars,repl,abs)::sl
+
+exception PolyFound of bool (* make this a let exception once possible *)
+let is_polymorphic_univ u =
+ try
+ let open Univ in
+ List.iter (fun (vars,_,_) ->
+ List.iter (function
+ | Variable (_,_,poly,(univs,_)) ->
+ if LSet.mem u univs then raise (PolyFound poly)
+ | Context (univs,_) ->
+ if LSet.mem u univs then raise (PolyFound true)
+ ) vars
+ ) !sectab;
+ false
+ with PolyFound b -> b
+
+let extract_hyps (secs,ohyps) =
+ let rec aux = function
+ | (Variable (id,impl,poly,ctx)::idl, decl::hyps) when Names.Id.equal id (NamedDecl.get_id decl) ->
+ let l, r = aux (idl,hyps) in
+ (decl,impl) :: l, if poly then Univ.ContextSet.union r ctx else r
+ | (Variable (_,_,poly,ctx)::idl,hyps) ->
+ let l, r = aux (idl,hyps) in
+ l, if poly then Univ.ContextSet.union r ctx else r
+ | (Context ctx :: idl, hyps) ->
+ let l, r = aux (idl, hyps) in
+ l, Univ.ContextSet.union r ctx
+ | [], _ -> [],Univ.ContextSet.empty
+ in aux (secs,ohyps)
+
+let instance_from_variable_context =
+ List.map fst %> List.filter is_local_assum %> List.map NamedDecl.get_id %> Array.of_list
+
+let named_of_variable_context =
+ List.map fst
+
+let name_instance inst =
+ (* FIXME: this should probably be done at an upper level, by storing the
+ name information in the section data structure. *)
+ let map lvl = match Univ.Level.name lvl with
+ | None -> (* Having Prop/Set/Var as section universes makes no sense *)
+ assert false
+ | Some na ->
+ try
+ let qid = Nametab.shortest_qualid_of_universe na in
+ Name (Libnames.qualid_basename qid)
+ with Not_found ->
+ (* Best-effort naming from the string representation of the level.
+ See univNames.ml for a similar hack. *)
+ Name (Id.of_string_soft (Univ.Level.to_string lvl))
+ in
+ Array.map map (Univ.Instance.to_array inst)
+
+let add_section_replacement f g poly hyps =
+ match !sectab with
+ | [] -> ()
+ | (vars,exps,abs)::sl ->
+ let () = check_same_poly poly vars in
+ let sechyps,ctx = extract_hyps (vars,hyps) in
+ let ctx = Univ.ContextSet.to_context ctx in
+ let inst = Univ.UContext.instance ctx in
+ let nas = name_instance inst in
+ let subst, ctx = Univ.abstract_universes nas ctx in
+ let args = instance_from_variable_context (List.rev sechyps) in
+ let info = {
+ abstr_ctx = sechyps;
+ abstr_subst = subst;
+ abstr_uctx = ctx;
+ } in
+ sectab := (vars,f (inst,args) exps, g info abs) :: sl
+
+let add_section_kn poly kn =
+ let f x (l1,l2) = (l1,Names.Mindmap.add kn x l2) in
+ add_section_replacement f f poly
+
+let add_section_constant poly kn =
+ let f x (l1,l2) = (Names.Cmap.add kn x l1,l2) in
+ add_section_replacement f f poly
+
+let replacement_context () = pi2 (List.hd !sectab)
+
+let section_segment_of_constant con =
+ Names.Cmap.find con (fst (pi3 (List.hd !sectab)))
+
+let section_segment_of_mutual_inductive kn =
+ Names.Mindmap.find kn (snd (pi3 (List.hd !sectab)))
+
+let empty_segment = {
+ abstr_ctx = [];
+ abstr_subst = Univ.Instance.empty;
+ abstr_uctx = Univ.AUContext.empty;
+}
+
+let section_segment_of_reference = function
+| ConstRef c -> section_segment_of_constant c
+| IndRef (kn,_) | ConstructRef ((kn,_),_) ->
+ section_segment_of_mutual_inductive kn
+| VarRef _ -> empty_segment
+
+let variable_section_segment_of_reference gr =
+ (section_segment_of_reference gr).abstr_ctx
+
+let section_instance = function
+ | VarRef id ->
+ let eq = function
+ | Variable (id',_,_,_) -> Names.Id.equal id id'
+ | Context _ -> false
+ in
+ if List.exists eq (pi1 (List.hd !sectab))
+ then Univ.Instance.empty, [||]
+ else raise Not_found
+ | ConstRef con ->
+ Names.Cmap.find con (fst (pi2 (List.hd !sectab)))
+ | IndRef (kn,_) | ConstructRef ((kn,_),_) ->
+ Names.Mindmap.find kn (snd (pi2 (List.hd !sectab)))
+
+let is_in_section ref =
+ try ignore (section_instance ref); true with Not_found -> false
+
+(*************)
+(* Sections. *)
+let open_section id =
+ let opp = !lib_state.path_prefix in
+ let obj_dir = add_dirpath_suffix opp.Nametab.obj_dir id in
+ let prefix = Nametab.{ obj_dir; obj_mp = opp.obj_mp; obj_sec = add_dirpath_suffix opp.obj_sec id } in
+ if Nametab.exists_section obj_dir then
+ user_err ~hdr:"open_section" (Id.print id ++ str " already exists.");
+ let fs = Summary.freeze_summaries ~marshallable:false in
+ add_entry (make_foname id) (OpenedSection (prefix, fs));
+ (*Pushed for the lifetime of the section: removed by unfrozing the summary*)
+ Nametab.(push_dir (Until 1) obj_dir (GlobDirRef.DirOpenSection prefix));
+ lib_state := { !lib_state with path_prefix = prefix };
+ add_section ()
+
+
+(* Restore lib_stk and summaries as before the section opening, and
+ add a ClosedSection object. *)
+
+let discharge_item ((sp,_ as oname),e) =
+ match e with
+ | Leaf lobj ->
+ Option.map (fun o -> (basename sp,o)) (discharge_object (oname,lobj))
+ | OpenedSection _ | OpenedModule _ | CompilingLibrary _ ->
+ anomaly (Pp.str "discharge_item.")
+
+let close_section () =
+ let oname,fs =
+ try match find_entry_p is_opening_node with
+ | oname,OpenedSection (_,fs) -> oname,fs
+ | _ -> assert false
+ with Not_found ->
+ user_err Pp.(str "No opened section.")
+ in
+ let (secdecls,mark,before) = split_lib_at_opening oname in
+ lib_state := { !lib_state with lib_stk = before };
+ pop_path_prefix ();
+ let newdecls = List.map discharge_item secdecls in
+ Summary.unfreeze_summaries fs;
+ List.iter (Option.iter (fun (id,o) -> add_discharged_leaf id o)) newdecls
+
+(* State and initialization. *)
+
+type frozen = lib_state
+
+let freeze ~marshallable = !lib_state
+
+let unfreeze st = lib_state := st
+
+let drop_objects st =
+ let lib_stk =
+ CList.map_filter (function
+ | _, Leaf _ -> None
+ | n, (CompilingLibrary _ as x) -> Some (n,x)
+ | n, OpenedModule (it,e,op,_) ->
+ Some(n,OpenedModule(it,e,op,Summary.empty_frozen))
+ | n, OpenedSection (op, _) ->
+ Some(n,OpenedSection(op,Summary.empty_frozen)))
+ st.lib_stk in
+ { st with lib_stk }
+
+let init () =
+ unfreeze initial_lib_state;
+ Summary.init_summaries ()
+
+(* Misc *)
+
+let mp_of_global = function
+ | VarRef id -> !lib_state.path_prefix.Nametab.obj_mp
+ | ConstRef cst -> Names.Constant.modpath cst
+ | IndRef ind -> Names.ind_modpath ind
+ | ConstructRef constr -> Names.constr_modpath constr
+
+let rec dp_of_mp = function
+ |Names.MPfile dp -> dp
+ |Names.MPbound _ -> library_dp ()
+ |Names.MPdot (mp,_) -> dp_of_mp mp
+
+let rec split_modpath = function
+ |Names.MPfile dp -> dp, []
+ |Names.MPbound mbid -> library_dp (), [Names.MBId.to_id mbid]
+ |Names.MPdot (mp,l) ->
+ let (dp,ids) = split_modpath mp in
+ (dp, Names.Label.to_id l :: ids)
+
+let library_part = function
+ |VarRef id -> library_dp ()
+ |ref -> dp_of_mp (mp_of_global ref)
+
+let discharge_proj_repr =
+ Projection.Repr.map_npars (fun mind npars ->
+ if not (is_in_section (IndRef (mind,0))) then mind, npars
+ else let modlist = replacement_context () in
+ let _, newpars = Mindmap.find mind (snd modlist) in
+ mind, npars + Array.length newpars)
+
+let discharge_abstract_universe_context { abstr_subst = subst; abstr_uctx = abs_ctx } auctx =
+ let open Univ in
+ let ainst = make_abstract_instance auctx in
+ let subst = Instance.append subst ainst in
+ let subst = make_instance_subst subst in
+ let auctx = Univ.subst_univs_level_abstract_universe_context subst auctx in
+ subst, AUContext.union abs_ctx auctx
diff --git a/library/lib.mli b/library/lib.mli
new file mode 100644
index 0000000000..30569197bc
--- /dev/null
+++ b/library/lib.mli
@@ -0,0 +1,199 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+
+(** Lib: record of operations, backtrack, low-level sections *)
+
+(** This module provides a general mechanism to keep a trace of all operations
+ and to backtrack (undo) those operations. It provides also the section
+ mechanism (at a low level; discharge is not known at this step). *)
+
+type is_type = bool (* Module Type or just Module *)
+type export = bool option (* None for a Module Type *)
+
+val make_oname : Nametab.object_prefix -> Names.Id.t -> Libobject.object_name
+
+type node =
+ | Leaf of Libobject.obj
+ | CompilingLibrary of Nametab.object_prefix
+ | OpenedModule of is_type * export * Nametab.object_prefix * Summary.frozen
+ | OpenedSection of Nametab.object_prefix * Summary.frozen
+
+type library_segment = (Libobject.object_name * node) list
+
+type lib_objects = (Id.t * Libobject.obj) list
+
+(** {6 Object iteration functions. } *)
+
+val open_objects : int -> Nametab.object_prefix -> lib_objects -> unit
+val load_objects : int -> Nametab.object_prefix -> lib_objects -> unit
+val subst_objects : Mod_subst.substitution -> lib_objects -> lib_objects
+(*val load_and_subst_objects : int -> Libnames.Nametab.object_prefix -> Mod_subst.substitution -> lib_objects -> lib_objects*)
+
+(** [classify_segment seg] verifies that there are no OpenedThings,
+ clears ClosedSections and FrozenStates and divides Leafs according
+ to their answers to the [classify_object] function in three groups:
+ [Substitute], [Keep], [Anticipate] respectively. The order of each
+ returned list is the same as in the input list. *)
+val classify_segment :
+ library_segment -> lib_objects * lib_objects * Libobject.obj list
+
+(** [segment_of_objects prefix objs] forms a list of Leafs *)
+val segment_of_objects :
+ Nametab.object_prefix -> lib_objects -> library_segment
+
+
+(** {6 ... } *)
+(** Adding operations (which call the [cache] method, and getting the
+ current list of operations (most recent ones coming first). *)
+
+val add_leaf : Id.t -> Libobject.obj -> Libobject.object_name
+val add_anonymous_leaf : ?cache_first:bool -> Libobject.obj -> unit
+val pull_to_head : Libobject.object_name -> unit
+
+(** this operation adds all objects with the same name and calls [load_object]
+ for each of them *)
+val add_leaves : Id.t -> Libobject.obj list -> Libobject.object_name
+
+(** {6 ... } *)
+
+(** The function [contents] gives access to the current entire segment *)
+
+val contents : unit -> library_segment
+
+(** The function [contents_after] returns the current library segment,
+ starting from a given section path. *)
+
+val contents_after : Libobject.object_name -> library_segment
+
+(** {6 Functions relative to current path } *)
+
+(** User-side names *)
+val cwd : unit -> DirPath.t
+val cwd_except_section : unit -> DirPath.t
+val current_dirpath : bool -> DirPath.t (* false = except sections *)
+val make_path : Id.t -> Libnames.full_path
+val make_path_except_section : Id.t -> Libnames.full_path
+
+(** Kernel-side names *)
+val current_mp : unit -> ModPath.t
+val make_kn : Id.t -> KerName.t
+
+(** Are we inside an opened section *)
+val sections_are_opened : unit -> bool
+val sections_depth : unit -> int
+
+(** Are we inside an opened module type *)
+val is_module_or_modtype : unit -> bool
+val is_modtype : unit -> bool
+(* [is_modtype_strict] checks not only if we are in a module type, but
+ if the latest module started is a module type. *)
+val is_modtype_strict : unit -> bool
+val is_module : unit -> bool
+val current_mod_id : unit -> module_ident
+
+(** Returns the opening node of a given name *)
+val find_opening_node : Id.t -> node
+
+(** {6 Modules and module types } *)
+
+val start_module :
+ export -> module_ident -> ModPath.t ->
+ Summary.frozen -> Nametab.object_prefix
+
+val start_modtype :
+ module_ident -> ModPath.t ->
+ Summary.frozen -> Nametab.object_prefix
+
+val end_module :
+ unit ->
+ Libobject.object_name * Nametab.object_prefix *
+ Summary.frozen * library_segment
+
+val end_modtype :
+ unit ->
+ Libobject.object_name * Nametab.object_prefix *
+ Summary.frozen * library_segment
+
+(** {6 Compilation units } *)
+
+val start_compilation : DirPath.t -> ModPath.t -> unit
+val end_compilation_checks : DirPath.t -> Libobject.object_name
+val end_compilation :
+ Libobject.object_name-> Nametab.object_prefix * library_segment
+
+(** The function [library_dp] returns the [DirPath.t] of the current
+ compiling library (or [default_library]) *)
+val library_dp : unit -> DirPath.t
+
+(** Extract the library part of a name even if in a section *)
+val dp_of_mp : ModPath.t -> DirPath.t
+val split_modpath : ModPath.t -> DirPath.t * Id.t list
+val library_part : GlobRef.t -> DirPath.t
+
+(** {6 Sections } *)
+
+val open_section : Id.t -> unit
+val close_section : unit -> unit
+
+(** {6 We can get and set the state of the operations (used in [States]). } *)
+
+type frozen
+
+val freeze : marshallable:bool -> frozen
+val unfreeze : frozen -> unit
+
+(** Keep only the libobject structure, not the objects themselves *)
+val drop_objects : frozen -> frozen
+
+val init : unit -> unit
+
+(** {6 Section management for discharge } *)
+type variable_info = Constr.named_declaration * Decl_kinds.binding_kind
+type variable_context = variable_info list
+type abstr_info = private {
+ abstr_ctx : variable_context;
+ (** Section variables of this prefix *)
+ abstr_subst : Univ.Instance.t;
+ (** Actual names of the abstracted variables *)
+ abstr_uctx : Univ.AUContext.t;
+ (** Universe quantification, same length as the substitution *)
+}
+
+val instance_from_variable_context : variable_context -> Id.t array
+val named_of_variable_context : variable_context -> Constr.named_context
+
+val section_segment_of_constant : Constant.t -> abstr_info
+val section_segment_of_mutual_inductive: MutInd.t -> abstr_info
+val section_segment_of_reference : GlobRef.t -> abstr_info
+
+val variable_section_segment_of_reference : GlobRef.t -> variable_context
+
+val section_instance : GlobRef.t -> Univ.Instance.t * Id.t array
+val is_in_section : GlobRef.t -> bool
+
+val add_section_variable : Id.t -> Decl_kinds.binding_kind -> Decl_kinds.polymorphic -> Univ.ContextSet.t -> unit
+val add_section_context : Univ.ContextSet.t -> unit
+val add_section_constant : Decl_kinds.polymorphic ->
+ Constant.t -> Constr.named_context -> unit
+val add_section_kn : Decl_kinds.polymorphic ->
+ MutInd.t -> Constr.named_context -> unit
+val replacement_context : unit -> Opaqueproof.work_list
+
+val is_polymorphic_univ : Univ.Level.t -> bool
+
+(** {6 Discharge: decrease the section level if in the current section } *)
+
+(* XXX Why can't we use the kernel functions ? *)
+
+val discharge_proj_repr : Projection.Repr.t -> Projection.Repr.t
+val discharge_abstract_universe_context :
+ abstr_info -> Univ.AUContext.t -> Univ.universe_level_subst * Univ.AUContext.t
diff --git a/library/libnames.ml b/library/libnames.ml
new file mode 100644
index 0000000000..87c4de42e8
--- /dev/null
+++ b/library/libnames.ml
@@ -0,0 +1,171 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+open CErrors
+open Util
+open Names
+
+(**********************************************)
+
+(*s Operations on dirpaths *)
+
+let split_dirpath d = match DirPath.repr d with
+ | id :: l -> DirPath.make l, id
+ | _ -> failwith "split_dirpath"
+
+let pop_dirpath p = match DirPath.repr p with
+ | _::l -> DirPath.make l
+ | [] -> failwith "pop_dirpath"
+
+(* Pop the last n module idents *)
+let pop_dirpath_n n dir = DirPath.make (List.skipn n (DirPath.repr dir))
+
+let is_dirpath_prefix_of d1 d2 =
+ List.prefix_of Id.equal
+ (List.rev (DirPath.repr d1)) (List.rev (DirPath.repr d2))
+
+let is_dirpath_suffix_of dir1 dir2 =
+ let dir1 = DirPath.repr dir1 in
+ let dir2 = DirPath.repr dir2 in
+ List.prefix_of Id.equal dir1 dir2
+
+let chop_dirpath n d =
+ let d1,d2 = List.chop n (List.rev (DirPath.repr d)) in
+ DirPath.make (List.rev d1), DirPath.make (List.rev d2)
+
+let drop_dirpath_prefix d1 d2 =
+ let d =
+ List.drop_prefix Id.equal
+ (List.rev (DirPath.repr d1)) (List.rev (DirPath.repr d2))
+ in
+ DirPath.make (List.rev d)
+
+let append_dirpath d1 d2 = DirPath.make (DirPath.repr d2 @ DirPath.repr d1)
+
+let add_dirpath_prefix id d = DirPath.make (DirPath.repr d @ [id])
+
+let add_dirpath_suffix p id = DirPath.make (id :: DirPath.repr p)
+
+(* parsing *)
+let parse_dir s =
+ let len = String.length s in
+ let rec decoupe_dirs dirs n =
+ if Int.equal n len && n > 0 then user_err Pp.(str @@ s ^ " is an invalid path.");
+ if n >= len then dirs else
+ let pos =
+ try
+ String.index_from s n '.'
+ with Not_found -> len
+ in
+ if Int.equal pos n then user_err Pp.(str @@ s ^ " is an invalid path.");
+ let dir = String.sub s n (pos-n) in
+ decoupe_dirs ((Id.of_string dir)::dirs) (pos+1)
+ in
+ decoupe_dirs [] 0
+
+let dirpath_of_string s =
+ let path = match s with
+ | "" -> []
+ | _ -> parse_dir s
+ in
+ DirPath.make path
+
+module Dirset = Set.Make(DirPath)
+module Dirmap = Map.Make(DirPath)
+
+(*s Section paths are absolute names *)
+
+type full_path = {
+ dirpath : DirPath.t ;
+ basename : Id.t }
+
+let dirpath sp = sp.dirpath
+let basename sp = sp.basename
+
+let make_path pa id = { dirpath = pa; basename = id }
+
+let repr_path { dirpath = pa; basename = id } = (pa,id)
+
+let eq_full_path p1 p2 =
+ Id.equal p1.basename p2.basename &&
+ DirPath.equal p1.dirpath p2.dirpath
+
+(* parsing and printing of section paths *)
+let string_of_path sp =
+ let (sl,id) = repr_path sp in
+ match DirPath.repr sl with
+ | [] -> Id.to_string id
+ | _ -> (DirPath.to_string sl) ^ "." ^ (Id.to_string id)
+
+let sp_ord sp1 sp2 =
+ let (p1,id1) = repr_path sp1
+ and (p2,id2) = repr_path sp2 in
+ let p_bit = DirPath.compare p1 p2 in
+ if Int.equal p_bit 0 then Id.compare id1 id2 else p_bit
+
+module SpOrdered =
+ struct
+ type t = full_path
+ let compare = sp_ord
+ end
+
+module Spmap = Map.Make(SpOrdered)
+
+let path_of_string s =
+ try
+ let dir, id = split_dirpath (dirpath_of_string s) in
+ make_path dir id
+ with
+ | Invalid_argument _ -> invalid_arg "path_of_string"
+
+let pr_path sp = str (string_of_path sp)
+
+let restrict_path n sp =
+ let dir, s = repr_path sp in
+ let dir' = List.firstn n (DirPath.repr dir) in
+ make_path (DirPath.make dir') s
+
+(*s qualified names *)
+type qualid_r = full_path
+type qualid = qualid_r CAst.t
+
+let make_qualid ?loc pa id = CAst.make ?loc (make_path pa id)
+let repr_qualid {CAst.v=qid} = repr_path qid
+
+let qualid_eq qid1 qid2 = eq_full_path qid1.CAst.v qid2.CAst.v
+
+let string_of_qualid qid = string_of_path qid.CAst.v
+let pr_qualid qid = pr_path qid.CAst.v
+
+let qualid_of_string ?loc s = CAst.make ?loc @@ path_of_string s
+
+let qualid_of_path ?loc sp = CAst.make ?loc sp
+let qualid_of_ident ?loc id = make_qualid ?loc DirPath.empty id
+let qualid_of_dirpath ?loc dir =
+ let (l,a) = split_dirpath dir in
+ make_qualid ?loc l a
+
+let qualid_is_ident qid =
+ DirPath.is_empty qid.CAst.v.dirpath
+
+let qualid_basename qid =
+ qid.CAst.v.basename
+
+let qualid_path qid =
+ qid.CAst.v.dirpath
+
+(* Default paths *)
+let default_library = Names.DirPath.initial (* = ["Top"] *)
+
+(*s Roots of the space of absolute names *)
+let coq_string = "Coq"
+let coq_root = Id.of_string coq_string
+let default_root_prefix = DirPath.empty
diff --git a/library/libnames.mli b/library/libnames.mli
new file mode 100644
index 0000000000..bbb4d2a058
--- /dev/null
+++ b/library/libnames.mli
@@ -0,0 +1,102 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Util
+open Names
+
+(** {6 Dirpaths } *)
+val dirpath_of_string : string -> DirPath.t
+
+(** Pop the suffix of a [DirPath.t]. Raises a [Failure] for an empty path *)
+val pop_dirpath : DirPath.t -> DirPath.t
+
+(** Pop the suffix n times *)
+val pop_dirpath_n : int -> DirPath.t -> DirPath.t
+
+(** Immediate prefix and basename of a [DirPath.t]. May raise [Failure] *)
+val split_dirpath : DirPath.t -> DirPath.t * Id.t
+
+val add_dirpath_suffix : DirPath.t -> module_ident -> DirPath.t
+val add_dirpath_prefix : module_ident -> DirPath.t -> DirPath.t
+
+val chop_dirpath : int -> DirPath.t -> DirPath.t * DirPath.t
+val append_dirpath : DirPath.t -> DirPath.t -> DirPath.t
+
+val drop_dirpath_prefix : DirPath.t -> DirPath.t -> DirPath.t
+val is_dirpath_prefix_of : DirPath.t -> DirPath.t -> bool
+
+val is_dirpath_suffix_of : DirPath.t -> DirPath.t -> bool
+
+module Dirset : Set.S with type elt = DirPath.t
+module Dirmap : Map.ExtS with type key = DirPath.t and module Set := Dirset
+
+(** {6 Full paths are {e absolute} paths of declarations } *)
+type full_path
+
+val eq_full_path : full_path -> full_path -> bool
+
+(** Constructors of [full_path] *)
+val make_path : DirPath.t -> Id.t -> full_path
+
+(** Destructors of [full_path] *)
+val repr_path : full_path -> DirPath.t * Id.t
+val dirpath : full_path -> DirPath.t
+val basename : full_path -> Id.t
+
+(** Parsing and printing of section path as ["coq_root.module.id"] *)
+val path_of_string : string -> full_path
+val string_of_path : full_path -> string
+val pr_path : full_path -> Pp.t
+
+module Spmap : CSig.MapS with type key = full_path
+
+val restrict_path : int -> full_path -> full_path
+
+(** {6 ... } *)
+(** A [qualid] is a partially qualified ident; it includes fully
+ qualified names (= absolute names) and all intermediate partial
+ qualifications of absolute names, including single identifiers.
+ The [qualid] are used to access the name table. *)
+
+type qualid_r
+type qualid = qualid_r CAst.t
+
+val make_qualid : ?loc:Loc.t -> DirPath.t -> Id.t -> qualid
+val repr_qualid : qualid -> DirPath.t * Id.t
+
+val qualid_eq : qualid -> qualid -> bool
+
+val pr_qualid : qualid -> Pp.t
+val string_of_qualid : qualid -> string
+val qualid_of_string : ?loc:Loc.t -> string -> qualid
+
+(** Turns an absolute name, a dirpath, or an Id.t into a
+ qualified name denoting the same name *)
+
+val qualid_of_path : ?loc:Loc.t -> full_path -> qualid
+val qualid_of_dirpath : ?loc:Loc.t -> DirPath.t -> qualid
+val qualid_of_ident : ?loc:Loc.t -> Id.t -> qualid
+
+val qualid_is_ident : qualid -> bool
+val qualid_path : qualid -> DirPath.t
+val qualid_basename : qualid -> Id.t
+
+(** {6 ... } *)
+
+(** some preset paths *)
+val default_library : DirPath.t
+
+(** This is the root of the standard library of Coq *)
+val coq_root : module_ident (* "Coq" *)
+val coq_string : string (* "Coq" *)
+
+(** This is the default root prefix for developments which doesn't
+ mention a root *)
+val default_root_prefix : DirPath.t
diff --git a/library/libobject.ml b/library/libobject.ml
new file mode 100644
index 0000000000..3d17b4a605
--- /dev/null
+++ b/library/libobject.ml
@@ -0,0 +1,174 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+
+module Dyn = Dyn.Make ()
+
+type 'a substitutivity =
+ Dispose | Substitute of 'a | Keep of 'a | Anticipate of 'a
+
+type object_name = Libnames.full_path * Names.KerName.t
+
+type 'a object_declaration = {
+ object_name : string;
+ cache_function : object_name * 'a -> unit;
+ load_function : int -> object_name * 'a -> unit;
+ open_function : int -> object_name * 'a -> unit;
+ classify_function : 'a -> 'a substitutivity;
+ subst_function : Mod_subst.substitution * 'a -> 'a;
+ discharge_function : object_name * 'a -> 'a option;
+ rebuild_function : 'a -> 'a }
+
+let default_object s = {
+ object_name = s;
+ cache_function = (fun _ -> ());
+ load_function = (fun _ _ -> ());
+ open_function = (fun _ _ -> ());
+ subst_function = (fun _ ->
+ CErrors.anomaly (str "The object " ++ str s ++ str " does not know how to substitute!"));
+ classify_function = (fun obj -> Keep obj);
+ discharge_function = (fun _ -> None);
+ rebuild_function = (fun x -> x)}
+
+
+(* The suggested object declaration is the following:
+
+ declare_object { (default_object "MY OBJECT") with
+ cache_function = fun (sp,a) -> Mytbl.add sp a}
+
+ and the listed functions are only those which definitions actually
+ differ from the default.
+
+ This helps introducing new functions in objects.
+*)
+
+let ident_subst_function (_,a) = a
+
+type obj = Dyn.t (* persistent dynamic objects *)
+
+type dynamic_object_declaration = {
+ dyn_cache_function : object_name * obj -> unit;
+ dyn_load_function : int -> object_name * obj -> unit;
+ dyn_open_function : int -> object_name * obj -> unit;
+ dyn_subst_function : Mod_subst.substitution * obj -> obj;
+ dyn_classify_function : obj -> obj substitutivity;
+ dyn_discharge_function : object_name * obj -> obj option;
+ dyn_rebuild_function : obj -> obj }
+
+let object_tag (Dyn.Dyn (t, _)) = Dyn.repr t
+
+let cache_tab =
+ (Hashtbl.create 223 : (string,dynamic_object_declaration) Hashtbl.t)
+
+let declare_object_full odecl =
+ let na = odecl.object_name in
+ let (infun, outfun) = Dyn.Easy.make_dyn na in
+ let cacher (oname,lobj) = odecl.cache_function (oname,outfun lobj)
+ and loader i (oname,lobj) = odecl.load_function i (oname,outfun lobj)
+ and opener i (oname,lobj) = odecl.open_function i (oname,outfun lobj)
+ and substituter (sub,lobj) = infun (odecl.subst_function (sub,outfun lobj))
+ and classifier lobj = match odecl.classify_function (outfun lobj) with
+ | Dispose -> Dispose
+ | Substitute obj -> Substitute (infun obj)
+ | Keep obj -> Keep (infun obj)
+ | Anticipate (obj) -> Anticipate (infun obj)
+ and discharge (oname,lobj) =
+ Option.map infun (odecl.discharge_function (oname,outfun lobj))
+ and rebuild lobj = infun (odecl.rebuild_function (outfun lobj))
+ in
+ Hashtbl.add cache_tab na { dyn_cache_function = cacher;
+ dyn_load_function = loader;
+ dyn_open_function = opener;
+ dyn_subst_function = substituter;
+ dyn_classify_function = classifier;
+ dyn_discharge_function = discharge;
+ dyn_rebuild_function = rebuild };
+ (infun,outfun)
+
+let declare_object odecl = fst (declare_object_full odecl)
+let declare_object_full odecl = declare_object_full odecl
+
+(* this function describes how the cache, load, open, and export functions
+ are triggered. *)
+
+let apply_dyn_fun f lobj =
+ let tag = object_tag lobj in
+ let dodecl =
+ try Hashtbl.find cache_tab tag
+ with Not_found -> assert false
+ in
+ f dodecl
+
+let cache_object ((_,lobj) as node) =
+ apply_dyn_fun (fun d -> d.dyn_cache_function node) lobj
+
+let load_object i ((_,lobj) as node) =
+ apply_dyn_fun (fun d -> d.dyn_load_function i node) lobj
+
+let open_object i ((_,lobj) as node) =
+ apply_dyn_fun (fun d -> d.dyn_open_function i node) lobj
+
+let subst_object ((_,lobj) as node) =
+ apply_dyn_fun (fun d -> d.dyn_subst_function node) lobj
+
+let classify_object lobj =
+ apply_dyn_fun (fun d -> d.dyn_classify_function lobj) lobj
+
+let discharge_object ((_,lobj) as node) =
+ apply_dyn_fun (fun d -> d.dyn_discharge_function node) lobj
+
+let rebuild_object lobj =
+ apply_dyn_fun (fun d -> d.dyn_rebuild_function lobj) lobj
+
+let dump = Dyn.dump
+
+let local_object_nodischarge s ~cache =
+ { (default_object s) with
+ cache_function = cache;
+ classify_function = (fun _ -> Dispose);
+ }
+
+let local_object s ~cache ~discharge =
+ { (local_object_nodischarge s ~cache) with
+ discharge_function = discharge }
+
+let global_object_nodischarge s ~cache ~subst =
+ let import i o = if Int.equal i 1 then cache o in
+ { (default_object s) with
+ cache_function = cache;
+ open_function = import;
+ subst_function = (match subst with
+ | None -> fun _ -> CErrors.anomaly (str "The object " ++ str s ++ str " does not know how to substitute!")
+ | Some subst -> subst;
+ );
+ classify_function =
+ if Option.has_some subst then (fun o -> Substitute o) else (fun o -> Keep o);
+ }
+
+let global_object s ~cache ~subst ~discharge =
+ { (global_object_nodischarge s ~cache ~subst) with
+ discharge_function = discharge }
+
+let superglobal_object_nodischarge s ~cache ~subst =
+ { (default_object s) with
+ load_function = (fun _ x -> cache x);
+ cache_function = cache;
+ subst_function = (match subst with
+ | None -> fun _ -> CErrors.anomaly (str "The object " ++ str s ++ str " does not know how to substitute!")
+ | Some subst -> subst;
+ );
+ classify_function =
+ if Option.has_some subst then (fun o -> Substitute o) else (fun o -> Keep o);
+ }
+
+let superglobal_object s ~cache ~subst ~discharge =
+ { (superglobal_object_nodischarge s ~cache ~subst) with
+ discharge_function = discharge }
diff --git a/library/libobject.mli b/library/libobject.mli
new file mode 100644
index 0000000000..00515bd273
--- /dev/null
+++ b/library/libobject.mli
@@ -0,0 +1,169 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Libnames
+open Mod_subst
+
+(** [Libobject] declares persistent objects, given with methods:
+
+ * a caching function specifying how to add the object in the current
+ scope;
+ If the object wishes to register its visibility in the Nametab,
+ it should do so for all possible suffixes.
+
+ * a loading function, specifying what to do when the module
+ containing the object is loaded;
+ If the object wishes to register its visibility in the Nametab,
+ it should do so for all suffixes no shorter than the "int" argument
+
+ * an opening function, specifying what to do when the module
+ containing the object is opened (imported);
+ If the object wishes to register its visibility in the Nametab,
+ it should do so for the suffix of the length the "int" argument
+
+ * a classification function, specifying what to do with the object,
+ when the current module (containing the object) is ended;
+ The possibilities are:
+ Dispose - the object dies at the end of the module
+ Substitute - meaning the object is substitutive and
+ the module name must be updated
+ Keep - the object is not substitutive, but survives module
+ closing
+ Anticipate - this is for objects that have to be explicitly
+ managed by the [end_module] function (like Require
+ and Read markers)
+
+ The classification function is also an occasion for a cleanup
+ (if this function returns Keep or Substitute of some object, the
+ cache method is never called for it)
+
+ * a substitution function, performing the substitution;
+ this function should be declared for substitutive objects
+ only (see above). NB: the substitution might now be delayed
+ instead of happening at module creation, so this function
+ should _not_ depend on the current environment
+
+ * a discharge function, that is applied at section closing time to
+ collect the data necessary to rebuild the discharged form of the
+ non volatile objects
+
+ * a rebuild function, that is applied after section closing to
+ rebuild the non volatile content of a section from the data
+ collected by the discharge function
+
+ Any type defined as a persistent object must be pure (e.g. no references) and
+ marshallable by the OCaml Marshal module (e.g. no closures).
+
+*)
+
+type 'a substitutivity =
+ Dispose | Substitute of 'a | Keep of 'a | Anticipate of 'a
+
+(** Both names are passed to objects: a "semantic" [kernel_name], which
+ can be substituted and a "syntactic" [full_path] which can be printed
+*)
+
+type object_name = full_path * Names.KerName.t
+
+type 'a object_declaration = {
+ object_name : string;
+ cache_function : object_name * 'a -> unit;
+ load_function : int -> object_name * 'a -> unit;
+ open_function : int -> object_name * 'a -> unit;
+ classify_function : 'a -> 'a substitutivity;
+ subst_function : substitution * 'a -> 'a;
+ discharge_function : object_name * 'a -> 'a option;
+ rebuild_function : 'a -> 'a }
+
+(** The default object is a "Keep" object with empty methods.
+ Object creators are advised to use the construction
+ [{(default_object "MY_OBJECT") with
+ cache_function = ...
+ }]
+ and specify only these functions which are not empty/meaningless
+
+*)
+
+val default_object : string -> 'a object_declaration
+
+(** the identity substitution function *)
+val ident_subst_function : substitution * 'a -> 'a
+
+(** {6 ... } *)
+(** Given an object declaration, the function [declare_object_full]
+ will hand back two functions, the "injection" and "projection"
+ functions for dynamically typed library-objects. *)
+
+type obj
+
+val declare_object_full :
+ 'a object_declaration -> ('a -> obj) * (obj -> 'a)
+
+val declare_object :
+ 'a object_declaration -> ('a -> obj)
+
+val object_tag : obj -> string
+
+val cache_object : object_name * obj -> unit
+val load_object : int -> object_name * obj -> unit
+val open_object : int -> object_name * obj -> unit
+val subst_object : substitution * obj -> obj
+val classify_object : obj -> obj substitutivity
+val discharge_object : object_name * obj -> obj option
+val rebuild_object : obj -> obj
+
+(** Higher-level API for objects with fixed scope.
+
+- Local means that the object cannot be imported from outside.
+- Global means that it can be imported (by importing the module that contains the
+object).
+- Superglobal means that the object survives to closing a module, and is imported
+when the file which contains it is Required (even without Import).
+- With the nodischarge variants, the object does not survive section closing.
+ With the normal variants, it does.
+
+We recommend to avoid declaring superglobal objects and using the nodischarge
+variants.
+*)
+
+val local_object : string ->
+ cache:(object_name * 'a -> unit) ->
+ discharge:(object_name * 'a -> 'a option) ->
+ 'a object_declaration
+
+val local_object_nodischarge : string ->
+ cache:(object_name * 'a -> unit) ->
+ 'a object_declaration
+
+val global_object : string ->
+ cache:(object_name * 'a -> unit) ->
+ subst:(Mod_subst.substitution * 'a -> 'a) option ->
+ discharge:(object_name * 'a -> 'a option) ->
+ 'a object_declaration
+
+val global_object_nodischarge : string ->
+ cache:(object_name * 'a -> unit) ->
+ subst:(Mod_subst.substitution * 'a -> 'a) option ->
+ 'a object_declaration
+
+val superglobal_object : string ->
+ cache:(object_name * 'a -> unit) ->
+ subst:(Mod_subst.substitution * 'a -> 'a) option ->
+ discharge:(object_name * 'a -> 'a option) ->
+ 'a object_declaration
+
+val superglobal_object_nodischarge : string ->
+ cache:(object_name * 'a -> unit) ->
+ subst:(Mod_subst.substitution * 'a -> 'a) option ->
+ 'a object_declaration
+
+(** {6 Debug} *)
+
+val dump : unit -> (int * string) list
diff --git a/library/library.ml b/library/library.ml
new file mode 100644
index 0000000000..9b9bd07c93
--- /dev/null
+++ b/library/library.ml
@@ -0,0 +1,750 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+open CErrors
+open Util
+
+open Names
+open Libnames
+open Lib
+open Libobject
+
+(************************************************************************)
+(*s Low-level interning/externing of libraries to files *)
+
+let raw_extern_library f =
+ System.raw_extern_state Coq_config.vo_magic_number f
+
+let raw_intern_library f =
+ System.with_magic_number_check
+ (System.raw_intern_state Coq_config.vo_magic_number) f
+
+(************************************************************************)
+(** Serialized objects loaded on-the-fly *)
+
+exception Faulty of string
+
+module Delayed :
+sig
+
+type 'a delayed
+val in_delayed : string -> in_channel -> 'a delayed * Digest.t
+val fetch_delayed : 'a delayed -> 'a
+
+end =
+struct
+
+type 'a delayed = {
+ del_file : string;
+ del_off : int;
+ del_digest : Digest.t;
+}
+
+let in_delayed f ch =
+ let pos = pos_in ch in
+ let _, digest = System.skip_in_segment f ch in
+ ({ del_file = f; del_digest = digest; del_off = pos; }, digest)
+
+(** Fetching a table of opaque terms at position [pos] in file [f],
+ expecting to find first a copy of [digest]. *)
+
+let fetch_delayed del =
+ let { del_digest = digest; del_file = f; del_off = pos; } = del in
+ try
+ let ch = raw_intern_library f in
+ let () = seek_in ch pos in
+ let obj, _, digest' = System.marshal_in_segment f ch in
+ let () = close_in ch in
+ if not (String.equal digest digest') then raise (Faulty f);
+ obj
+ with e when CErrors.noncritical e -> raise (Faulty f)
+
+end
+
+open Delayed
+
+
+(************************************************************************)
+(*s Modules on disk contain the following informations (after the magic
+ number, and before the digest). *)
+
+type compilation_unit_name = DirPath.t
+
+type library_disk = {
+ md_compiled : Safe_typing.compiled_library;
+ md_objects : Declaremods.library_objects;
+}
+
+type summary_disk = {
+ md_name : compilation_unit_name;
+ md_imports : compilation_unit_name array;
+ md_deps : (compilation_unit_name * Safe_typing.vodigest) array;
+}
+
+(*s Modules loaded in memory contain the following informations. They are
+ kept in the global table [libraries_table]. *)
+
+type library_t = {
+ library_name : compilation_unit_name;
+ library_data : library_disk delayed;
+ library_deps : (compilation_unit_name * Safe_typing.vodigest) array;
+ library_imports : compilation_unit_name array;
+ library_digests : Safe_typing.vodigest;
+ library_extra_univs : Univ.ContextSet.t;
+}
+
+type library_summary = {
+ libsum_name : compilation_unit_name;
+ libsum_digests : Safe_typing.vodigest;
+ libsum_imports : compilation_unit_name array;
+}
+
+module LibraryOrdered = DirPath
+module LibraryMap = Map.Make(LibraryOrdered)
+module LibraryFilenameMap = Map.Make(LibraryOrdered)
+
+(* This is a map from names to loaded libraries *)
+let libraries_table : library_summary LibraryMap.t ref =
+ Summary.ref LibraryMap.empty ~name:"LIBRARY"
+
+(* This is the map of loaded libraries filename *)
+(* (not synchronized so as not to be caught in the states on disk) *)
+let libraries_filename_table = ref LibraryFilenameMap.empty
+
+(* These are the _ordered_ sets of loaded, imported and exported libraries *)
+let libraries_loaded_list = Summary.ref [] ~name:"LIBRARY-LOAD"
+let libraries_imports_list = Summary.ref [] ~name:"LIBRARY-IMPORT"
+let libraries_exports_list = Summary.ref [] ~name:"LIBRARY-EXPORT"
+
+(* various requests to the tables *)
+
+let find_library dir =
+ LibraryMap.find dir !libraries_table
+
+let try_find_library dir =
+ try find_library dir
+ with Not_found ->
+ user_err ~hdr:"Library.find_library"
+ (str "Unknown library " ++ DirPath.print dir)
+
+let register_library_filename dir f =
+ (* Not synchronized: overwrite the previous binding if one existed *)
+ (* from a previous play of the session *)
+ libraries_filename_table :=
+ LibraryFilenameMap.add dir f !libraries_filename_table
+
+let library_full_filename dir =
+ try LibraryFilenameMap.find dir !libraries_filename_table
+ with Not_found -> "<unavailable filename>"
+
+let overwrite_library_filenames f =
+ let f =
+ if Filename.is_relative f then Filename.concat (Sys.getcwd ()) f else f in
+ LibraryMap.iter (fun dir _ -> register_library_filename dir f)
+ !libraries_table
+
+let library_is_loaded dir =
+ try let _ = find_library dir in true
+ with Not_found -> false
+
+let library_is_opened dir =
+ List.exists (fun name -> DirPath.equal name dir) !libraries_imports_list
+
+let loaded_libraries () = !libraries_loaded_list
+
+let opened_libraries () = !libraries_imports_list
+
+ (* If a library is loaded several time, then the first occurrence must
+ be performed first, thus the libraries_loaded_list ... *)
+
+let register_loaded_library m =
+ let libname = m.libsum_name in
+ let link () =
+ let dirname = Filename.dirname (library_full_filename libname) in
+ let prefix = Nativecode.mod_uid_of_dirpath libname ^ "." in
+ let f = prefix ^ "cmo" in
+ let f = Dynlink.adapt_filename f in
+ if Coq_config.native_compiler then
+ Nativelib.link_library ~prefix ~dirname ~basename:f
+ in
+ let rec aux = function
+ | [] -> link (); [libname]
+ | m'::_ as l when DirPath.equal m' libname -> l
+ | m'::l' -> m' :: aux l' in
+ libraries_loaded_list := aux !libraries_loaded_list;
+ libraries_table := LibraryMap.add libname m !libraries_table
+
+ (* ... while if a library is imported/exported several time, then
+ only the last occurrence is really needed - though the imported
+ list may differ from the exported list (consider the sequence
+ Export A; Export B; Import A which results in A;B for exports but
+ in B;A for imports) *)
+
+let rec remember_last_of_each l m =
+ match l with
+ | [] -> [m]
+ | m'::l' when DirPath.equal m' m -> remember_last_of_each l' m
+ | m'::l' -> m' :: remember_last_of_each l' m
+
+let register_open_library export m =
+ libraries_imports_list := remember_last_of_each !libraries_imports_list m;
+ if export then
+ libraries_exports_list := remember_last_of_each !libraries_exports_list m
+
+(************************************************************************)
+(*s Opening libraries *)
+
+(* [open_library export explicit m] opens library [m] if not already
+ opened _or_ if explicitly asked to be (re)opened *)
+
+let open_library export explicit_libs m =
+ if
+ (* Only libraries indirectly to open are not reopen *)
+ (* Libraries explicitly mentionned by the user are always reopen *)
+ List.exists (fun m' -> DirPath.equal m m') explicit_libs
+ || not (library_is_opened m)
+ then begin
+ register_open_library export m;
+ Declaremods.really_import_module (MPfile m)
+ end
+ else
+ if export then
+ libraries_exports_list := remember_last_of_each !libraries_exports_list m
+
+(* open_libraries recursively open a list of libraries but opens only once
+ a library that is re-exported many times *)
+
+let open_libraries export modl =
+ let to_open_list =
+ List.fold_left
+ (fun l m ->
+ let subimport =
+ Array.fold_left
+ (fun l m -> remember_last_of_each l m)
+ l m.libsum_imports
+ in remember_last_of_each subimport m.libsum_name)
+ [] modl in
+ let explicit = List.map (fun m -> m.libsum_name) modl in
+ List.iter (open_library export explicit) to_open_list
+
+
+(**********************************************************************)
+(* import and export of libraries - synchronous operations *)
+(* at the end similar to import and export of modules except that it *)
+(* is optimized: when importing several libraries at the same time *)
+(* which themselves indirectly imports the very same modules, these *)
+(* ones are imported only ones *)
+
+let open_import_library i (_,(modl,export)) =
+ if Int.equal i 1 then
+ (* even if the library is already imported, we re-import it *)
+ (* if not (library_is_opened dir) then *)
+ open_libraries export (List.map try_find_library modl)
+
+let cache_import_library obj =
+ open_import_library 1 obj
+
+let subst_import_library (_,o) = o
+
+let classify_import_library (_,export as obj) =
+ if export then Substitute obj else Dispose
+
+let in_import_library : DirPath.t list * bool -> obj =
+ declare_object {(default_object "IMPORT LIBRARY") with
+ cache_function = cache_import_library;
+ open_function = open_import_library;
+ subst_function = subst_import_library;
+ classify_function = classify_import_library }
+
+
+(************************************************************************)
+(*s Locate absolute or partially qualified library names in the path *)
+
+exception LibUnmappedDir
+exception LibNotFound
+type library_location = LibLoaded | LibInPath
+
+let warn_several_object_files =
+ CWarnings.create ~name:"several-object-files" ~category:"require"
+ (fun (vi, vo) -> str"Loading" ++ spc () ++ str vi ++
+ strbrk " instead of " ++ str vo ++
+ strbrk " because it is more recent")
+
+let locate_absolute_library dir =
+ (* Search in loadpath *)
+ let pref, base = split_dirpath dir in
+ let loadpath = Loadpath.filter_path (fun dir -> DirPath.equal dir pref) in
+ let () = match loadpath with [] -> raise LibUnmappedDir | _ -> () in
+ let loadpath = List.map fst loadpath in
+ let find ext =
+ try
+ let name = Id.to_string base ^ ext in
+ let _, file = System.where_in_path ~warn:false loadpath name in
+ Some file
+ with Not_found -> None in
+ match find ".vo", find ".vio" with
+ | None, None -> raise LibNotFound
+ | Some file, None | None, Some file -> file
+ | Some vo, Some vi when Unix.((stat vo).st_mtime < (stat vi).st_mtime) ->
+ warn_several_object_files (vi, vo);
+ vi
+ | Some vo, Some _ -> vo
+
+let locate_qualified_library ?root ?(warn = true) qid =
+ (* Search library in loadpath *)
+ let dir, base = repr_qualid qid in
+ let loadpath = Loadpath.expand_path ?root dir in
+ let () = match loadpath with [] -> raise LibUnmappedDir | _ -> () in
+ let find ext =
+ try
+ let name = Id.to_string base ^ ext in
+ let lpath, file =
+ System.where_in_path ~warn (List.map fst loadpath) name in
+ Some (lpath, file)
+ with Not_found -> None in
+ let lpath, file =
+ match find ".vo", find ".vio" with
+ | None, None -> raise LibNotFound
+ | Some res, None | None, Some res -> res
+ | Some (_, vo), Some (_, vi as resvi)
+ when Unix.((stat vo).st_mtime < (stat vi).st_mtime) ->
+ warn_several_object_files (vi, vo);
+ resvi
+ | Some resvo, Some _ -> resvo
+ in
+ let dir = add_dirpath_suffix (String.List.assoc lpath loadpath) base in
+ (* Look if loaded *)
+ if library_is_loaded dir then (LibLoaded, dir,library_full_filename dir)
+ (* Otherwise, look for it in the file system *)
+ else (LibInPath, dir, file)
+
+let error_unmapped_dir qid =
+ let prefix, _ = repr_qualid qid in
+ user_err ~hdr:"load_absolute_library_from"
+ (str "Cannot load " ++ pr_qualid qid ++ str ":" ++ spc () ++
+ str "no physical path bound to" ++ spc () ++ DirPath.print prefix ++ fnl ())
+
+let error_lib_not_found qid =
+ user_err ~hdr:"load_absolute_library_from"
+ (str"Cannot find library " ++ pr_qualid qid ++ str" in loadpath")
+
+let try_locate_absolute_library dir =
+ try
+ locate_absolute_library dir
+ with
+ | LibUnmappedDir -> error_unmapped_dir (qualid_of_dirpath dir)
+ | LibNotFound -> error_lib_not_found (qualid_of_dirpath dir)
+
+(************************************************************************)
+(** {6 Tables of opaque proof terms} *)
+
+(** We now store opaque proof terms apart from the rest of the environment.
+ See the [Indirect] contructor in [Lazyconstr.lazy_constr]. This way,
+ we can quickly load a first half of a .vo file without these opaque
+ terms, and access them only when a specific command (e.g. Print or
+ Print Assumptions) needs it. *)
+
+(** Delayed / available tables of opaque terms *)
+
+type 'a table_status =
+ | ToFetch of 'a Future.computation array delayed
+ | Fetched of 'a Future.computation array
+
+let opaque_tables =
+ ref (LibraryMap.empty : (Constr.constr table_status) LibraryMap.t)
+let univ_tables =
+ ref (LibraryMap.empty : (Univ.ContextSet.t table_status) LibraryMap.t)
+
+let add_opaque_table dp st =
+ opaque_tables := LibraryMap.add dp st !opaque_tables
+let add_univ_table dp st =
+ univ_tables := LibraryMap.add dp st !univ_tables
+
+let access_table what tables dp i =
+ let t = match LibraryMap.find dp !tables with
+ | Fetched t -> t
+ | ToFetch f ->
+ let dir_path = Names.DirPath.to_string dp in
+ Flags.if_verbose Feedback.msg_info (str"Fetching " ++ str what++str" from disk for " ++ str dir_path);
+ let t =
+ try fetch_delayed f
+ with Faulty f ->
+ user_err ~hdr:"Library.access_table"
+ (str "The file " ++ str f ++ str " (bound to " ++ str dir_path ++
+ str ") is inaccessible or corrupted,\ncannot load some " ++
+ str what ++ str " in it.\n")
+ in
+ tables := LibraryMap.add dp (Fetched t) !tables;
+ t
+ in
+ assert (i < Array.length t); t.(i)
+
+let access_opaque_table dp i =
+ let what = "opaque proofs" in
+ access_table what opaque_tables dp i
+
+let access_univ_table dp i =
+ try
+ let what = "universe contexts of opaque proofs" in
+ Some (access_table what univ_tables dp i)
+ with Not_found -> None
+
+let () =
+ Opaqueproof.set_indirect_opaque_accessor access_opaque_table;
+ Opaqueproof.set_indirect_univ_accessor access_univ_table
+
+(************************************************************************)
+(* Internalise libraries *)
+
+type seg_sum = summary_disk
+type seg_lib = library_disk
+type seg_univ = (* true = vivo, false = vi *)
+ Univ.ContextSet.t Future.computation array * Univ.ContextSet.t * bool
+type seg_discharge = Opaqueproof.cooking_info list array
+type seg_proofs = Constr.constr Future.computation array
+
+let mk_library sd md digests univs =
+ {
+ library_name = sd.md_name;
+ library_data = md;
+ library_deps = sd.md_deps;
+ library_imports = sd.md_imports;
+ library_digests = digests;
+ library_extra_univs = univs;
+ }
+
+let mk_summary m = {
+ libsum_name = m.library_name;
+ libsum_imports = m.library_imports;
+ libsum_digests = m.library_digests;
+}
+
+let intern_from_file f =
+ let ch = raw_intern_library f in
+ let (lsd : seg_sum), _, digest_lsd = System.marshal_in_segment f ch in
+ let ((lmd : seg_lib delayed), digest_lmd) = in_delayed f ch in
+ let (univs : seg_univ option), _, digest_u = System.marshal_in_segment f ch in
+ let _ = System.skip_in_segment f ch in
+ let _ = System.skip_in_segment f ch in
+ let ((del_opaque : seg_proofs delayed),_) = in_delayed f ch in
+ close_in ch;
+ register_library_filename lsd.md_name f;
+ add_opaque_table lsd.md_name (ToFetch del_opaque);
+ let open Safe_typing in
+ match univs with
+ | None -> mk_library lsd lmd (Dvo_or_vi digest_lmd) Univ.ContextSet.empty
+ | Some (utab,uall,true) ->
+ add_univ_table lsd.md_name (Fetched utab);
+ mk_library lsd lmd (Dvivo (digest_lmd,digest_u)) uall
+ | Some (utab,_,false) ->
+ add_univ_table lsd.md_name (Fetched utab);
+ mk_library lsd lmd (Dvo_or_vi digest_lmd) Univ.ContextSet.empty
+
+module DPMap = Map.Make(DirPath)
+
+let rec intern_library (needed, contents) (dir, f) from =
+ (* Look if in the current logical environment *)
+ try (find_library dir).libsum_digests, (needed, contents)
+ with Not_found ->
+ (* Look if already listed and consequently its dependencies too *)
+ try (DPMap.find dir contents).library_digests, (needed, contents)
+ with Not_found ->
+ Feedback.feedback(Feedback.FileDependency (from, DirPath.to_string dir));
+ (* [dir] is an absolute name which matches [f] which must be in loadpath *)
+ let f = match f with Some f -> f | None -> try_locate_absolute_library dir in
+ let m = intern_from_file f in
+ if not (DirPath.equal dir m.library_name) then
+ user_err ~hdr:"load_physical_library"
+ (str "The file " ++ str f ++ str " contains library" ++ spc () ++
+ DirPath.print m.library_name ++ spc () ++ str "and not library" ++
+ spc() ++ DirPath.print dir);
+ Feedback.feedback (Feedback.FileLoaded(DirPath.to_string dir, f));
+ m.library_digests, intern_library_deps (needed, contents) dir m f
+
+and intern_library_deps libs dir m from =
+ let needed, contents = Array.fold_left (intern_mandatory_library dir from) libs m.library_deps in
+ (dir :: needed, DPMap.add dir m contents )
+
+and intern_mandatory_library caller from libs (dir,d) =
+ let digest, libs = intern_library libs (dir, None) (Some from) in
+ if not (Safe_typing.digest_match ~actual:digest ~required:d) then
+ user_err (str "Compiled library " ++ DirPath.print caller ++
+ str " (in file " ++ str from ++ str ") makes inconsistent assumptions \
+ over library " ++ DirPath.print dir);
+ libs
+
+let rec_intern_library libs (dir, f) =
+ let _, libs = intern_library libs (dir, Some f) None in
+ libs
+
+let native_name_from_filename f =
+ let ch = raw_intern_library f in
+ let (lmd : seg_sum), pos, digest_lmd = System.marshal_in_segment f ch in
+ Nativecode.mod_uid_of_dirpath lmd.md_name
+
+(**********************************************************************)
+(*s [require_library] loads and possibly opens a library. This is a
+ synchronized operation. It is performed as follows:
+
+ preparation phase: (functions require_library* ) the library and its
+ dependencies are read from to disk (using intern_* )
+ [they are read from disk to ensure that at section/module
+ discharging time, the physical library referred to outside the
+ section/module is the one that was used at type-checking time in
+ the section/module]
+
+ execution phase: (through add_leaf and cache_require)
+ the library is loaded in the environment and Nametab, the objects are
+ registered etc, using functions from Declaremods (via load_library,
+ which recursively loads its dependencies)
+*)
+
+let register_library m =
+ let l = fetch_delayed m.library_data in
+ Declaremods.register_library
+ m.library_name
+ l.md_compiled
+ l.md_objects
+ m.library_digests
+ m.library_extra_univs;
+ register_loaded_library (mk_summary m)
+
+(* Follow the semantics of Anticipate object:
+ - called at module or module type closing when a Require occurs in
+ the module or module type
+ - not called from a library (i.e. a module identified with a file) *)
+let load_require _ (_,(needed,modl,_)) =
+ List.iter register_library needed
+
+let open_require i (_,(_,modl,export)) =
+ Option.iter (fun exp -> open_libraries exp (List.map find_library modl))
+ export
+
+ (* [needed] is the ordered list of libraries not already loaded *)
+let cache_require o =
+ load_require 1 o;
+ open_require 1 o
+
+let discharge_require (_,o) = Some o
+
+(* open_function is never called from here because an Anticipate object *)
+
+type require_obj = library_t list * DirPath.t list * bool option
+
+let in_require : require_obj -> obj =
+ declare_object {(default_object "REQUIRE") with
+ cache_function = cache_require;
+ load_function = load_require;
+ open_function = (fun _ _ -> assert false);
+ discharge_function = discharge_require;
+ classify_function = (fun o -> Anticipate o) }
+
+(* Require libraries, import them if [export <> None], mark them for export
+ if [export = Some true] *)
+
+let warn_require_in_module =
+ CWarnings.create ~name:"require-in-module" ~category:"deprecated"
+ (fun () -> strbrk "Require inside a module is" ++
+ strbrk " deprecated and strongly discouraged. " ++
+ strbrk "You can Require a module at toplevel " ++
+ strbrk "and optionally Import it inside another one.")
+
+let require_library_from_dirpath modrefl export =
+ let needed, contents = List.fold_left rec_intern_library ([], DPMap.empty) modrefl in
+ let needed = List.rev_map (fun dir -> DPMap.find dir contents) needed in
+ let modrefl = List.map fst modrefl in
+ if Lib.is_module_or_modtype () then
+ begin
+ warn_require_in_module ();
+ add_anonymous_leaf (in_require (needed,modrefl,None));
+ Option.iter (fun exp ->
+ add_anonymous_leaf (in_import_library (modrefl,exp)))
+ export
+ end
+ else
+ add_anonymous_leaf (in_require (needed,modrefl,export));
+ ()
+
+(* the function called by Vernacentries.vernac_import *)
+
+let safe_locate_module qid =
+ try Nametab.locate_module qid
+ with Not_found ->
+ user_err ?loc:qid.CAst.loc ~hdr:"import_library"
+ (pr_qualid qid ++ str " is not a module")
+
+let import_module export modl =
+ (* Optimization: libraries in a raw in the list are imported
+ "globally". If there is non-library in the list; it breaks the
+ optimization For instance: "Import Arith MyModule Zarith" will
+ not be optimized (possibly resulting in redefinitions, but
+ "Import MyModule Arith Zarith" and "Import Arith Zarith MyModule"
+ will have the submodules imported by both Arith and ZArith
+ imported only once *)
+ let flush = function
+ | [] -> ()
+ | modl -> add_anonymous_leaf (in_import_library (List.rev modl, export)) in
+ let rec aux acc = function
+ | qid :: l ->
+ let m,acc =
+ try Nametab.locate_module qid, acc
+ with Not_found-> flush acc; safe_locate_module qid, [] in
+ (match m with
+ | MPfile dir -> aux (dir::acc) l
+ | mp ->
+ flush acc;
+ try Declaremods.import_module export mp; aux [] l
+ with Not_found ->
+ user_err ?loc:qid.CAst.loc ~hdr:"import_library"
+ (pr_qualid qid ++ str " is not a module"))
+ | [] -> flush acc
+ in aux [] modl
+
+(************************************************************************)
+(*s Initializing the compilation of a library. *)
+
+let load_library_todo f =
+ let longf = Loadpath.locate_file (f^".v") in
+ let f = longf^"io" in
+ let ch = raw_intern_library f in
+ let (s0 : seg_sum), _, _ = System.marshal_in_segment f ch in
+ let (s1 : seg_lib), _, _ = System.marshal_in_segment f ch in
+ let (s2 : seg_univ option), _, _ = System.marshal_in_segment f ch in
+ let (s3 : seg_discharge option), _, _ = System.marshal_in_segment f ch in
+ let tasks, _, _ = System.marshal_in_segment f ch in
+ let (s5 : seg_proofs), _, _ = System.marshal_in_segment f ch in
+ close_in ch;
+ if tasks = None then user_err ~hdr:"restart" (str"not a .vio file");
+ if s2 = None then user_err ~hdr:"restart" (str"not a .vio file");
+ if s3 = None then user_err ~hdr:"restart" (str"not a .vio file");
+ if pi3 (Option.get s2) then user_err ~hdr:"restart" (str"not a .vio file");
+ longf, s0, s1, Option.get s2, Option.get s3, Option.get tasks, s5
+
+(************************************************************************)
+(*s [save_library dir] ends library [dir] and save it to the disk. *)
+
+let current_deps () =
+ let map name =
+ let m = try_find_library name in
+ (name, m.libsum_digests)
+ in
+ List.map map !libraries_loaded_list
+
+let current_reexports () = !libraries_exports_list
+
+let error_recursively_dependent_library dir =
+ user_err
+ (strbrk "Unable to use logical name " ++ DirPath.print dir ++
+ strbrk " to save current library because" ++
+ strbrk " it already depends on a library of this name.")
+
+(* We now use two different digests in a .vo file. The first one
+ only covers half of the file, without the opaque table. It is
+ used for identifying this version of this library : this digest
+ is the one leading to "inconsistent assumptions" messages.
+ The other digest comes at the very end, and covers everything
+ before it. This one is used for integrity check of the whole
+ file when loading the opaque table. *)
+
+(* Security weakness: file might have been changed on disk between
+ writing the content and computing the checksum... *)
+
+let save_library_to ?todo dir f otab =
+ let except = match todo with
+ | None ->
+ (* XXX *)
+ (* assert(!Flags.compilation_mode = Flags.BuildVo); *)
+ assert(Filename.check_suffix f ".vo");
+ Future.UUIDSet.empty
+ | Some (l,_) ->
+ assert(Filename.check_suffix f ".vio");
+ List.fold_left (fun e (r,_) -> Future.UUIDSet.add r.Stateid.uuid e)
+ Future.UUIDSet.empty l in
+ let cenv, seg, ast = Declaremods.end_library ~except dir in
+ let opaque_table, univ_table, disch_table, f2t_map = Opaqueproof.dump otab in
+ let tasks, utab, dtab =
+ match todo with
+ | None -> None, None, None
+ | Some (tasks, rcbackup) ->
+ let tasks =
+ List.map Stateid.(fun (r,b) ->
+ try { r with uuid = Future.UUIDMap.find r.uuid f2t_map }, b
+ with Not_found -> assert b; { r with uuid = -1 }, b)
+ tasks in
+ Some (tasks,rcbackup),
+ Some (univ_table,Univ.ContextSet.empty,false),
+ Some disch_table in
+ let except =
+ Future.UUIDSet.fold (fun uuid acc ->
+ try Int.Set.add (Future.UUIDMap.find uuid f2t_map) acc
+ with Not_found -> acc)
+ except Int.Set.empty in
+ let is_done_or_todo i x = Future.is_val x || Int.Set.mem i except in
+ Array.iteri (fun i x ->
+ if not(is_done_or_todo i x) then CErrors.user_err ~hdr:"library"
+ Pp.(str"Proof object "++int i++str" is not checked nor to be checked"))
+ opaque_table;
+ let sd = {
+ md_name = dir;
+ md_deps = Array.of_list (current_deps ());
+ md_imports = Array.of_list (current_reexports ());
+ } in
+ let md = {
+ md_compiled = cenv;
+ md_objects = seg;
+ } in
+ if Array.exists (fun (d,_) -> DirPath.equal d dir) sd.md_deps then
+ error_recursively_dependent_library dir;
+ (* Open the vo file and write the magic number *)
+ let f' = f in
+ let ch = raw_extern_library f' in
+ try
+ (* Writing vo payload *)
+ System.marshal_out_segment f' ch (sd : seg_sum);
+ System.marshal_out_segment f' ch (md : seg_lib);
+ System.marshal_out_segment f' ch (utab : seg_univ option);
+ System.marshal_out_segment f' ch (dtab : seg_discharge option);
+ System.marshal_out_segment f' ch (tasks : 'tasks option);
+ System.marshal_out_segment f' ch (opaque_table : seg_proofs);
+ close_out ch;
+ (* Writing native code files *)
+ if !Flags.output_native_objects then
+ let fn = Filename.dirname f'^"/"^Nativecode.mod_uid_of_dirpath dir in
+ if not (Nativelib.compile_library dir ast fn) then
+ user_err Pp.(str "Could not compile the library to native code.")
+ with reraise ->
+ let reraise = CErrors.push reraise in
+ let () = Feedback.msg_warning (str "Removed file " ++ str f') in
+ let () = close_out ch in
+ let () = Sys.remove f' in
+ iraise reraise
+
+let save_library_raw f sum lib univs proofs =
+ let f' = f^"o" in
+ let ch = raw_extern_library f' in
+ System.marshal_out_segment f' ch (sum : seg_sum);
+ System.marshal_out_segment f' ch (lib : seg_lib);
+ System.marshal_out_segment f' ch (Some univs : seg_univ option);
+ System.marshal_out_segment f' ch (None : seg_discharge option);
+ System.marshal_out_segment f' ch (None : 'tasks option);
+ System.marshal_out_segment f' ch (proofs : seg_proofs);
+ close_out ch
+
+module StringOrd = struct type t = string let compare = String.compare end
+module StringSet = Set.Make(StringOrd)
+
+let get_used_load_paths () =
+ StringSet.elements
+ (List.fold_left (fun acc m -> StringSet.add
+ (Filename.dirname (library_full_filename m)) acc)
+ StringSet.empty !libraries_loaded_list)
+
+let _ = Nativelib.get_load_paths := get_used_load_paths
diff --git a/library/library.mli b/library/library.mli
new file mode 100644
index 0000000000..c016352808
--- /dev/null
+++ b/library/library.mli
@@ -0,0 +1,82 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+open Libnames
+
+(** This module provides functions to load, open and save
+ libraries. Libraries correspond to the subclass of modules that
+ coincide with a file on disk (the ".vo" files). Libraries on the
+ disk comes with checksums (obtained with the [Digest] module), which
+ are checked at loading time to prevent inconsistencies between files
+ written at various dates.
+*)
+
+(** {6 ... }
+ Require = load in the environment + open (if the optional boolean
+ is not [None]); mark also for export if the boolean is [Some true] *)
+val require_library_from_dirpath : (DirPath.t * string) list -> bool option -> unit
+
+(** {6 Start the compilation of a library } *)
+
+(** Segments of a library *)
+type seg_sum
+type seg_lib
+type seg_univ = (* cst, all_cst, finished? *)
+ Univ.ContextSet.t Future.computation array * Univ.ContextSet.t * bool
+type seg_discharge = Opaqueproof.cooking_info list array
+type seg_proofs = Constr.constr Future.computation array
+
+(** Open a module (or a library); if the boolean is true then it's also
+ an export otherwise just a simple import *)
+val import_module : bool -> qualid list -> unit
+
+(** End the compilation of a library and save it to a ".vo" file *)
+val save_library_to :
+ ?todo:(((Future.UUID.t,'document) Stateid.request * bool) list * 'counters) ->
+ DirPath.t -> string -> Opaqueproof.opaquetab -> unit
+
+val load_library_todo :
+ string -> string * seg_sum * seg_lib * seg_univ * seg_discharge * 'tasks * seg_proofs
+val save_library_raw : string -> seg_sum -> seg_lib -> seg_univ -> seg_proofs -> unit
+
+(** {6 Interrogate the status of libraries } *)
+
+ (** - Tell if a library is loaded or opened *)
+val library_is_loaded : DirPath.t -> bool
+val library_is_opened : DirPath.t -> bool
+
+ (** - Tell which libraries are loaded or imported *)
+val loaded_libraries : unit -> DirPath.t list
+val opened_libraries : unit -> DirPath.t list
+
+ (** - Return the full filename of a loaded library. *)
+val library_full_filename : DirPath.t -> string
+
+ (** - Overwrite the filename of all libraries (used when restoring a state) *)
+val overwrite_library_filenames : string -> unit
+
+(** {6 Locate a library in the load paths } *)
+exception LibUnmappedDir
+exception LibNotFound
+type library_location = LibLoaded | LibInPath
+
+val locate_qualified_library :
+ ?root:DirPath.t -> ?warn:bool -> qualid ->
+ library_location * DirPath.t * CUnix.physical_path
+(** Locates a library by implicit name.
+
+ @raise LibUnmappedDir if the library is not in the path
+ @raise LibNotFound if there is no corresponding file in the path
+
+*)
+
+(** {6 Native compiler. } *)
+val native_name_from_filename : string -> string
diff --git a/library/library.mllib b/library/library.mllib
new file mode 100644
index 0000000000..8f694f4a31
--- /dev/null
+++ b/library/library.mllib
@@ -0,0 +1,17 @@
+Libnames
+Globnames
+Libobject
+Summary
+Nametab
+Global
+Decl_kinds
+Lib
+Declaremods
+Loadpath
+Library
+States
+Kindops
+Goptions
+Decls
+Keys
+Coqlib
diff --git a/library/loadpath.ml b/library/loadpath.ml
new file mode 100644
index 0000000000..fc13c864d0
--- /dev/null
+++ b/library/loadpath.ml
@@ -0,0 +1,119 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+open Util
+open CErrors
+open Names
+open Libnames
+
+(** Load paths. Mapping from physical to logical paths. *)
+
+type t = {
+ path_physical : CUnix.physical_path;
+ path_logical : DirPath.t;
+ path_implicit : bool;
+}
+
+let load_paths = Summary.ref ([] : t list) ~name:"LOADPATHS"
+
+let logical p = p.path_logical
+
+let physical p = p.path_physical
+
+let get_load_paths () = !load_paths
+
+let anomaly_too_many_paths path =
+ anomaly (str "Several logical paths are associated to" ++ spc () ++ str path ++ str ".")
+
+let find_load_path phys_dir =
+ let phys_dir = CUnix.canonical_path_name phys_dir in
+ let filter p = String.equal p.path_physical phys_dir in
+ let paths = List.filter filter !load_paths in
+ match paths with
+ | [] -> raise Not_found
+ | [p] -> p
+ | _ -> anomaly_too_many_paths phys_dir
+
+let is_in_load_paths phys_dir =
+ let dir = CUnix.canonical_path_name phys_dir in
+ let lp = get_load_paths () in
+ let check_p p = String.equal dir p.path_physical in
+ List.exists check_p lp
+
+let remove_load_path dir =
+ let filter p = not (String.equal p.path_physical dir) in
+ load_paths := List.filter filter !load_paths
+
+let warn_overriding_logical_loadpath =
+ CWarnings.create ~name:"overriding-logical-loadpath" ~category:"loadpath"
+ (fun (phys_path, old_path, coq_path) ->
+ str phys_path ++ strbrk " was previously bound to " ++
+ DirPath.print old_path ++ strbrk "; it is remapped to " ++
+ DirPath.print coq_path)
+
+let add_load_path phys_path coq_path ~implicit =
+ let phys_path = CUnix.canonical_path_name phys_path in
+ let filter p = String.equal p.path_physical phys_path in
+ let binding = {
+ path_logical = coq_path;
+ path_physical = phys_path;
+ path_implicit = implicit;
+ } in
+ match List.filter filter !load_paths with
+ | [] ->
+ load_paths := binding :: !load_paths
+ | [{ path_logical = old_path; path_implicit = old_implicit }] ->
+ let replace =
+ if DirPath.equal coq_path old_path then
+ implicit <> old_implicit
+ else
+ let () =
+ (* Do not warn when overriding the default "-I ." path *)
+ if not (DirPath.equal old_path Libnames.default_root_prefix) then
+ warn_overriding_logical_loadpath (phys_path, old_path, coq_path)
+ in
+ true in
+ if replace then
+ begin
+ remove_load_path phys_path;
+ load_paths := binding :: !load_paths;
+ end
+ | _ -> anomaly_too_many_paths phys_path
+
+let filter_path f =
+ let rec aux = function
+ | [] -> []
+ | p :: l ->
+ if f p.path_logical then (p.path_physical, p.path_logical) :: aux l
+ else aux l
+ in
+ aux !load_paths
+
+let expand_path ?root dir =
+ let rec aux = function
+ | [] -> []
+ | { path_physical = ph; path_logical = lg; path_implicit = implicit } :: l ->
+ let success =
+ match root with
+ | None ->
+ if implicit then is_dirpath_suffix_of dir lg
+ else DirPath.equal dir lg
+ | Some root ->
+ is_dirpath_prefix_of root lg &&
+ is_dirpath_suffix_of dir (drop_dirpath_prefix root lg) in
+ if success then (ph, lg) :: aux l else aux l in
+ aux !load_paths
+
+let locate_file fname =
+ let paths = List.map physical !load_paths in
+ let _,longfname =
+ System.find_file_in_path ~warn:(not !Flags.quiet) paths fname in
+ longfname
diff --git a/library/loadpath.mli b/library/loadpath.mli
new file mode 100644
index 0000000000..4044ca1127
--- /dev/null
+++ b/library/loadpath.mli
@@ -0,0 +1,57 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+
+(** * Load paths.
+
+ A load path is a physical path in the file system; to each load path is
+ associated a Coq [DirPath.t] (the "logical" path of the physical path).
+
+*)
+
+type t
+(** Type of loadpath bindings. *)
+
+val physical : t -> CUnix.physical_path
+(** Get the physical path (filesystem location) of a loadpath. *)
+
+val logical : t -> DirPath.t
+(** Get the logical path (Coq module hierarchy) of a loadpath. *)
+
+val get_load_paths : unit -> t list
+(** Get the current loadpath association. *)
+
+val add_load_path : CUnix.physical_path -> DirPath.t -> implicit:bool -> unit
+(** [add_load_path phys log type] adds the binding [phys := log] to the current
+ loadpaths. *)
+
+val remove_load_path : CUnix.physical_path -> unit
+(** Remove the current logical path binding associated to a given physical path,
+ if any. *)
+
+val find_load_path : CUnix.physical_path -> t
+(** Get the binding associated to a physical path. Raises [Not_found] if there
+ is none. *)
+
+val is_in_load_paths : CUnix.physical_path -> bool
+(** Whether a physical path is currently bound. *)
+
+val expand_path : ?root:DirPath.t -> DirPath.t -> (CUnix.physical_path * DirPath.t) list
+(** Given a relative logical path, associate the list of absolute physical and
+ logical paths which are possible matches of it. *)
+
+val filter_path : (DirPath.t -> bool) -> (CUnix.physical_path * DirPath.t) list
+(** As {!expand_path} but uses a filter function instead, and ignores the
+ implicit status of loadpaths. *)
+
+val locate_file : string -> string
+(** Locate a file among the registered paths. Do not use this function, as
+ it does not respect the visibility of paths. *)
diff --git a/library/nametab.ml b/library/nametab.ml
new file mode 100644
index 0000000000..95890b2edf
--- /dev/null
+++ b/library/nametab.ml
@@ -0,0 +1,594 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open CErrors
+open Util
+open Pp
+open Names
+open Libnames
+open Globnames
+
+type object_prefix = {
+ obj_dir : DirPath.t;
+ obj_mp : ModPath.t;
+ obj_sec : DirPath.t;
+}
+
+let eq_op op1 op2 =
+ DirPath.equal op1.obj_dir op2.obj_dir &&
+ DirPath.equal op1.obj_sec op2.obj_sec &&
+ ModPath.equal op1.obj_mp op2.obj_mp
+
+(* to this type are mapped DirPath.t's in the nametab *)
+module GlobDirRef = struct
+ type t =
+ | DirOpenModule of object_prefix
+ | DirOpenModtype of object_prefix
+ | DirOpenSection of object_prefix
+ | DirModule of object_prefix
+
+ let equal r1 r2 = match r1, r2 with
+ | DirOpenModule op1, DirOpenModule op2 -> eq_op op1 op2
+ | DirOpenModtype op1, DirOpenModtype op2 -> eq_op op1 op2
+ | DirOpenSection op1, DirOpenSection op2 -> eq_op op1 op2
+ | DirModule op1, DirModule op2 -> eq_op op1 op2
+ | _ -> false
+
+end
+
+type global_dir_reference = GlobDirRef.t
+[@@ocaml.deprecated "Use [GlobDirRef.t]"]
+
+let eq_global_dir_reference = GlobDirRef.equal
+[@@ocaml.deprecated "Use [GlobDirRef.equal]"]
+
+exception GlobalizationError of qualid
+
+let error_global_not_found qid =
+ Loc.raise ?loc:qid.CAst.loc (GlobalizationError qid)
+
+(* The visibility can be registered either
+ - for all suffixes not shorter then a given int - when the object
+ is loaded inside a module
+ or
+ - for a precise suffix, when the module containing (the module
+ containing ...) the object is open (imported)
+*)
+type visibility = Until of int | Exactly of int
+
+let map_visibility f = function
+ | Until i -> Until (f i)
+ | Exactly i -> Exactly (f i)
+
+(* Data structure for nametabs *******************************************)
+
+
+(* This module type will be instantiated by [full_path] of [DirPath.t] *)
+(* The [repr] function is assumed to return the reversed list of idents. *)
+module type UserName = sig
+ type t
+ val equal : t -> t -> bool
+ val to_string : t -> string
+ val repr : t -> Id.t * module_ident list
+end
+
+module type EqualityType =
+sig
+ type t
+ val equal : t -> t -> bool
+end
+
+(* A ['a t] is a map from [user_name] to ['a], with possible lookup by
+ partially qualified names of type [qualid]. The mapping of
+ partially qualified names to ['a] is determined by the [visibility]
+ parameter of [push].
+
+ The [shortest_qualid] function given a user_name Coq.A.B.x, tries
+ to find the shortest among x, B.x, A.B.x and Coq.A.B.x that denotes
+ the same object.
+*)
+module type NAMETREE = sig
+ type elt
+ type t
+ type user_name
+
+ val empty : t
+ val push : visibility -> user_name -> elt -> t -> t
+ val locate : qualid -> t -> elt
+ val find : user_name -> t -> elt
+ val exists : user_name -> t -> bool
+ val user_name : qualid -> t -> user_name
+ val shortest_qualid : ?loc:Loc.t -> Id.Set.t -> user_name -> t -> qualid
+ val find_prefixes : qualid -> t -> elt list
+
+ (** Matches a prefix of [qualid], useful for completion *)
+ val match_prefixes : qualid -> t -> elt list
+end
+
+module Make (U : UserName) (E : EqualityType) : NAMETREE
+ with type user_name = U.t and type elt = E.t =
+struct
+ type elt = E.t
+
+ (* A name became inaccessible, even with absolute qualification.
+ Example:
+ Module F (X : S). Module X.
+ The argument X of the functor F is masked by the inner module X.
+ *)
+ let warn_masking_absolute =
+ CWarnings.create ~name:"masking-absolute-name" ~category:"deprecated"
+ (fun n -> str ("Trying to mask the absolute name \"" ^ U.to_string n ^ "\"!"))
+
+ type user_name = U.t
+
+ type path_status =
+ Nothing
+ | Relative of user_name * elt
+ | Absolute of user_name * elt
+
+ (* Dictionaries of short names *)
+ type nametree =
+ { path : path_status;
+ map : nametree ModIdmap.t }
+
+ let mktree p m = { path=p; map=m }
+ let empty_tree = mktree Nothing ModIdmap.empty
+
+ type t = nametree Id.Map.t
+
+ let empty = Id.Map.empty
+
+ (* [push_until] is used to register [Until vis] visibility and
+ [push_exactly] to [Exactly vis] and [push_tree] chooses the right one*)
+
+ let rec push_until uname o level tree = function
+ | modid :: path ->
+ let modify _ mc = push_until uname o (level-1) mc path in
+ let map =
+ try ModIdmap.modify modid modify tree.map
+ with Not_found ->
+ let ptab = modify () empty_tree in
+ ModIdmap.add modid ptab tree.map
+ in
+ let this =
+ if level <= 0 then
+ match tree.path with
+ | Absolute (n,_) ->
+ (* This is an absolute name, we must keep it
+ otherwise it may become unaccessible forever *)
+ warn_masking_absolute n; tree.path
+ | Nothing
+ | Relative _ -> Relative (uname,o)
+ else tree.path
+ in
+ mktree this map
+ | [] ->
+ match tree.path with
+ | Absolute (uname',o') ->
+ if E.equal o' o then begin
+ assert (U.equal uname uname');
+ tree
+ (* we are putting the same thing for the second time :) *)
+ end
+ else
+ (* This is an absolute name, we must keep it otherwise it may
+ become unaccessible forever *)
+ (* But ours is also absolute! This is an error! *)
+ user_err Pp.(str @@ "Cannot mask the absolute name \""
+ ^ U.to_string uname' ^ "\"!")
+ | Nothing
+ | Relative _ -> mktree (Absolute (uname,o)) tree.map
+
+let rec push_exactly uname o level tree = function
+| [] ->
+ anomaly (Pp.str "Prefix longer than path! Impossible!")
+| modid :: path ->
+ if Int.equal level 0 then
+ let this =
+ match tree.path with
+ | Absolute (n,_) ->
+ (* This is an absolute name, we must keep it
+ otherwise it may become unaccessible forever *)
+ warn_masking_absolute n; tree.path
+ | Nothing
+ | Relative _ -> Relative (uname,o)
+ in
+ mktree this tree.map
+ else (* not right level *)
+ let modify _ mc = push_exactly uname o (level-1) mc path in
+ let map =
+ try ModIdmap.modify modid modify tree.map
+ with Not_found ->
+ let ptab = modify () empty_tree in
+ ModIdmap.add modid ptab tree.map
+ in
+ mktree tree.path map
+
+
+let push visibility uname o tab =
+ let id,dir = U.repr uname in
+ let modify _ ptab = match visibility with
+ | Until i -> push_until uname o (i-1) ptab dir
+ | Exactly i -> push_exactly uname o (i-1) ptab dir
+ in
+ try Id.Map.modify id modify tab
+ with Not_found ->
+ let ptab = modify () empty_tree in
+ Id.Map.add id ptab tab
+
+
+let rec search tree = function
+ | modid :: path -> search (ModIdmap.find modid tree.map) path
+ | [] -> tree.path
+
+let find_node qid tab =
+ let (dir,id) = repr_qualid qid in
+ search (Id.Map.find id tab) (DirPath.repr dir)
+
+let locate qid tab =
+ let o = match find_node qid tab with
+ | Absolute (uname,o) | Relative (uname,o) -> o
+ | Nothing -> raise Not_found
+ in
+ o
+
+let user_name qid tab =
+ let uname = match find_node qid tab with
+ | Absolute (uname,o) | Relative (uname,o) -> uname
+ | Nothing -> raise Not_found
+ in
+ uname
+
+let find uname tab =
+ let id,l = U.repr uname in
+ match search (Id.Map.find id tab) l with
+ Absolute (_,o) -> o
+ | _ -> raise Not_found
+
+let exists uname tab =
+ try
+ let _ = find uname tab in
+ true
+ with
+ Not_found -> false
+
+let shortest_qualid ?loc ctx uname tab =
+ let id,dir = U.repr uname in
+ let hidden = Id.Set.mem id ctx in
+ let rec find_uname pos dir tree =
+ let is_empty = match pos with [] -> true | _ -> false in
+ match tree.path with
+ | Absolute (u,_) | Relative (u,_)
+ when U.equal u uname && not (is_empty && hidden) -> List.rev pos
+ | _ ->
+ match dir with
+ [] -> raise Not_found
+ | id::dir -> find_uname (id::pos) dir (ModIdmap.find id tree.map)
+ in
+ let ptab = Id.Map.find id tab in
+ let found_dir = find_uname [] dir ptab in
+ make_qualid ?loc (DirPath.make found_dir) id
+
+let push_node node l =
+ match node with
+ | Absolute (_,o) | Relative (_,o) when not (List.mem_f E.equal o l) -> o::l
+ | _ -> l
+
+let rec flatten_idmap tab l =
+ let f _ tree l = flatten_idmap tree.map (push_node tree.path l) in
+ ModIdmap.fold f tab l
+
+let rec search_prefixes tree = function
+ | modid :: path -> search_prefixes (ModIdmap.find modid tree.map) path
+ | [] -> List.rev (flatten_idmap tree.map (push_node tree.path []))
+
+let find_prefixes qid tab =
+ try
+ let (dir,id) = repr_qualid qid in
+ search_prefixes (Id.Map.find id tab) (DirPath.repr dir)
+ with Not_found -> []
+
+let match_prefixes =
+ let cprefix x y = CString.(compare x (sub y 0 (min (length x) (length y)))) in
+ fun qid tab ->
+ try
+ let (dir,id) = repr_qualid qid in
+ let id_prefix = cprefix Id.(to_string id) in
+ let matches = Id.Map.filter_range (fun x -> id_prefix Id.(to_string x)) tab in
+ let matches = Id.Map.mapi (fun _key tab -> search_prefixes tab (DirPath.repr dir)) matches in
+ (* Coq's flatten is "magical", so this is not so bad perf-wise *)
+ CList.flatten @@ Id.Map.(fold (fun _ r l -> r :: l) matches [])
+ with Not_found -> []
+
+end
+
+(* Global name tables *************************************************)
+
+module FullPath =
+struct
+ type t = full_path
+ let equal = eq_full_path
+ let to_string = string_of_path
+ let repr sp =
+ let dir,id = repr_path sp in
+ id, (DirPath.repr dir)
+end
+
+module ExtRefEqual = ExtRefOrdered
+module MPEqual = Names.ModPath
+
+module ExtRefTab = Make(FullPath)(ExtRefEqual)
+module MPTab = Make(FullPath)(MPEqual)
+
+type ccitab = ExtRefTab.t
+let the_ccitab = Summary.ref ~name:"ccitab" (ExtRefTab.empty : ccitab)
+
+type mptab = MPTab.t
+let the_modtypetab = Summary.ref ~name:"modtypetab" (MPTab.empty : mptab)
+
+module DirPath' =
+struct
+ include DirPath
+ let repr dir = match DirPath.repr dir with
+ | [] -> anomaly (Pp.str "Empty dirpath.")
+ | id :: l -> (id, l)
+end
+
+module DirTab = Make(DirPath')(GlobDirRef)
+
+(* If we have a (closed) module M having a submodule N, than N does not
+ have the entry in [the_dirtab]. *)
+type dirtab = DirTab.t
+let the_dirtab = Summary.ref ~name:"dirtab" (DirTab.empty : dirtab)
+
+module UnivIdEqual =
+struct
+ type t = Univ.Level.UGlobal.t
+ let equal = Univ.Level.UGlobal.equal
+end
+module UnivTab = Make(FullPath)(UnivIdEqual)
+type univtab = UnivTab.t
+let the_univtab = Summary.ref ~name:"univtab" (UnivTab.empty : univtab)
+
+(* Reversed name tables ***************************************************)
+
+(* This table translates extended_global_references back to section paths *)
+module Globrevtab = HMap.Make(ExtRefOrdered)
+
+type globrevtab = full_path Globrevtab.t
+let the_globrevtab = Summary.ref ~name:"globrevtab" (Globrevtab.empty : globrevtab)
+
+
+type mprevtab = DirPath.t MPmap.t
+let the_modrevtab = Summary.ref ~name:"modrevtab" (MPmap.empty : mprevtab)
+
+type mptrevtab = full_path MPmap.t
+let the_modtyperevtab = Summary.ref ~name:"modtyperevtab" (MPmap.empty : mptrevtab)
+
+module UnivIdOrdered =
+struct
+ type t = Univ.Level.UGlobal.t
+ let hash = Univ.Level.UGlobal.hash
+ let compare = Univ.Level.UGlobal.compare
+end
+
+module UnivIdMap = HMap.Make(UnivIdOrdered)
+
+type univrevtab = full_path UnivIdMap.t
+let the_univrevtab = Summary.ref ~name:"univrevtab" (UnivIdMap.empty : univrevtab)
+
+(* Push functions *********************************************************)
+
+(* This is for permanent constructions (never discharged -- but with
+ possibly limited visibility, i.e. Theorem, Lemma, Definition, Axiom,
+ Parameter but also Remark and Fact) *)
+
+let push_xref visibility sp xref =
+ match visibility with
+ | Until _ ->
+ the_ccitab := ExtRefTab.push visibility sp xref !the_ccitab;
+ the_globrevtab := Globrevtab.add xref sp !the_globrevtab
+ | _ ->
+ begin
+ if ExtRefTab.exists sp !the_ccitab then
+ match ExtRefTab.find sp !the_ccitab with
+ | TrueGlobal( ConstRef _) | TrueGlobal( IndRef _) |
+ TrueGlobal( ConstructRef _) as xref ->
+ the_ccitab := ExtRefTab.push visibility sp xref !the_ccitab;
+ | _ ->
+ the_ccitab := ExtRefTab.push visibility sp xref !the_ccitab;
+ else
+ the_ccitab := ExtRefTab.push visibility sp xref !the_ccitab;
+ end
+
+let push_cci visibility sp ref =
+ push_xref visibility sp (TrueGlobal ref)
+
+(* This is for Syntactic Definitions *)
+let push_syndef visibility sp kn =
+ push_xref visibility sp (SynDef kn)
+
+let push = push_cci
+
+let push_modtype vis sp kn =
+ the_modtypetab := MPTab.push vis sp kn !the_modtypetab;
+ the_modtyperevtab := MPmap.add kn sp !the_modtyperevtab
+
+(* This is to remember absolute Section/Module names and to avoid redundancy *)
+let push_dir vis dir dir_ref =
+ the_dirtab := DirTab.push vis dir dir_ref !the_dirtab;
+ match dir_ref with
+ | GlobDirRef.DirModule { obj_mp; _ } -> the_modrevtab := MPmap.add obj_mp dir !the_modrevtab
+ | _ -> ()
+
+(* This is for global universe names *)
+
+let push_universe vis sp univ =
+ the_univtab := UnivTab.push vis sp univ !the_univtab;
+ the_univrevtab := UnivIdMap.add univ sp !the_univrevtab
+
+(* Locate functions *******************************************************)
+
+
+(* This should be used when syntactic definitions are allowed *)
+let locate_extended qid = ExtRefTab.locate qid !the_ccitab
+
+(* This should be used when no syntactic definitions is expected *)
+let locate qid = match locate_extended qid with
+ | TrueGlobal ref -> ref
+ | SynDef _ -> raise Not_found
+let full_name_cci qid = ExtRefTab.user_name qid !the_ccitab
+
+let locate_syndef qid = match locate_extended qid with
+ | TrueGlobal _ -> raise Not_found
+ | SynDef kn -> kn
+
+let locate_modtype qid = MPTab.locate qid !the_modtypetab
+let full_name_modtype qid = MPTab.user_name qid !the_modtypetab
+
+let locate_universe qid = UnivTab.locate qid !the_univtab
+
+let locate_dir qid = DirTab.locate qid !the_dirtab
+
+let locate_module qid =
+ match locate_dir qid with
+ | GlobDirRef.DirModule { obj_mp ; _} -> obj_mp
+ | _ -> raise Not_found
+
+let full_name_module qid =
+ match locate_dir qid with
+ | GlobDirRef.DirModule { obj_dir ; _} -> obj_dir
+ | _ -> raise Not_found
+
+let locate_section qid =
+ match locate_dir qid with
+ | GlobDirRef.DirOpenSection { obj_dir; _ } -> obj_dir
+ | _ -> raise Not_found
+
+let locate_all qid =
+ List.fold_right (fun a l -> match a with TrueGlobal a -> a::l | _ -> l)
+ (ExtRefTab.find_prefixes qid !the_ccitab) []
+
+let locate_extended_all qid = ExtRefTab.find_prefixes qid !the_ccitab
+
+let locate_extended_all_dir qid = DirTab.find_prefixes qid !the_dirtab
+
+let locate_extended_all_modtype qid = MPTab.find_prefixes qid !the_modtypetab
+
+(* Completion *)
+let completion_canditates qualid =
+ ExtRefTab.match_prefixes qualid !the_ccitab
+
+(* Derived functions *)
+
+let locate_constant qid =
+ match locate_extended qid with
+ | TrueGlobal (ConstRef kn) -> kn
+ | _ -> raise Not_found
+
+let global_of_path sp =
+ match ExtRefTab.find sp !the_ccitab with
+ | TrueGlobal ref -> ref
+ | _ -> raise Not_found
+
+let extended_global_of_path sp = ExtRefTab.find sp !the_ccitab
+
+let global qid =
+ try match locate_extended qid with
+ | TrueGlobal ref -> ref
+ | SynDef _ ->
+ user_err ?loc:qid.CAst.loc ~hdr:"global"
+ (str "Unexpected reference to a notation: " ++
+ pr_qualid qid)
+ with Not_found ->
+ error_global_not_found qid
+
+(* Exists functions ********************************************************)
+
+let exists_cci sp = ExtRefTab.exists sp !the_ccitab
+
+let exists_dir dir = DirTab.exists dir !the_dirtab
+
+let exists_section = exists_dir
+
+let exists_module = exists_dir
+
+let exists_modtype sp = MPTab.exists sp !the_modtypetab
+
+let exists_universe kn = UnivTab.exists kn !the_univtab
+
+(* Reverse locate functions ***********************************************)
+
+let path_of_global ref =
+ match ref with
+ | VarRef id -> make_path DirPath.empty id
+ | _ -> Globrevtab.find (TrueGlobal ref) !the_globrevtab
+
+let dirpath_of_global ref =
+ fst (repr_path (path_of_global ref))
+
+let basename_of_global ref =
+ snd (repr_path (path_of_global ref))
+
+let path_of_syndef kn =
+ Globrevtab.find (SynDef kn) !the_globrevtab
+
+let dirpath_of_module mp =
+ MPmap.find mp !the_modrevtab
+
+let path_of_modtype mp =
+ MPmap.find mp !the_modtyperevtab
+
+let path_of_universe mp =
+ UnivIdMap.find mp !the_univrevtab
+
+(* Shortest qualid functions **********************************************)
+
+let shortest_qualid_of_global ?loc ctx ref =
+ match ref with
+ | VarRef id -> make_qualid ?loc DirPath.empty id
+ | _ ->
+ let sp = Globrevtab.find (TrueGlobal ref) !the_globrevtab in
+ ExtRefTab.shortest_qualid ?loc ctx sp !the_ccitab
+
+let shortest_qualid_of_syndef ?loc ctx kn =
+ let sp = path_of_syndef kn in
+ ExtRefTab.shortest_qualid ?loc ctx sp !the_ccitab
+
+let shortest_qualid_of_module ?loc mp =
+ let dir = MPmap.find mp !the_modrevtab in
+ DirTab.shortest_qualid ?loc Id.Set.empty dir !the_dirtab
+
+let shortest_qualid_of_modtype ?loc kn =
+ let sp = MPmap.find kn !the_modtyperevtab in
+ MPTab.shortest_qualid ?loc Id.Set.empty sp !the_modtypetab
+
+let shortest_qualid_of_universe ?loc kn =
+ let sp = UnivIdMap.find kn !the_univrevtab in
+ UnivTab.shortest_qualid ?loc Id.Set.empty sp !the_univtab
+
+let pr_global_env env ref =
+ try pr_qualid (shortest_qualid_of_global env ref)
+ with Not_found as e ->
+ if !Flags.debug then Feedback.msg_debug (Pp.str "pr_global_env not found"); raise e
+
+let global_inductive qid =
+ match global qid with
+ | IndRef ind -> ind
+ | ref ->
+ user_err ?loc:qid.CAst.loc ~hdr:"global_inductive"
+ (pr_qualid qid ++ spc () ++ str "is not an inductive type")
+
+(********************************************************************)
+
+(* Deprecated synonyms *)
+
+let extended_locate = locate_extended
+let absolute_reference = global_of_path
diff --git a/library/nametab.mli b/library/nametab.mli
new file mode 100644
index 0000000000..fccb8fd918
--- /dev/null
+++ b/library/nametab.mli
@@ -0,0 +1,262 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Names
+open Libnames
+open Globnames
+
+(** This module contains the tables for globalization. *)
+
+(** These globalization tables associate internal object references to
+ qualified names (qualid). There are three classes of names:
+
+ - 1a) internal kernel names: [kernel_name], [constant], [inductive],
+ [module_path], [DirPath.t]
+
+ - 1b) other internal names: [global_reference], [syndef_name],
+ [extended_global_reference], [global_dir_reference], ...
+
+ - 2) full, non ambiguous user names: [full_path]
+
+ - 3) non necessarily full, possibly ambiguous user names: [reference]
+ and [qualid]
+*)
+
+(** Most functions in this module fall into one of the following categories:
+{ul {- [push : visibility -> full_user_name -> object_reference -> unit]
+
+ Registers the [object_reference] to be referred to by the
+ [full_user_name] (and its suffixes according to [visibility]).
+ [full_user_name] can either be a [full_path] or a [DirPath.t].
+ }
+ {- [exists : full_user_name -> bool]
+
+ Is the [full_user_name] already atributed as an absolute user name
+ of some object?
+ }
+ {- [locate : qualid -> object_reference]
+
+ Finds the object referred to by [qualid] or raises [Not_found]
+ }
+ {- [full_name : qualid -> full_user_name]
+
+ Finds the full user name referred to by [qualid] or raises [Not_found]
+ }
+ {- [shortest_qualid_of : object_reference -> user_name]
+
+ The [user_name] can be for example the shortest non ambiguous [qualid] or
+ the [full_user_name] or [Id.t]. Such a function can also have a
+ local context argument.}}
+
+*)
+
+(** Object prefix morally contains the "prefix" naming of an object to
+ be stored by [library], where [obj_dir] is the "absolute" path,
+ [obj_mp] is the current "module" prefix and [obj_sec] is the
+ "section" prefix.
+
+ Thus, for an object living inside [Module A. Section B.] the
+ prefix would be:
+
+ [ { obj_dir = "A.B"; obj_mp = "A"; obj_sec = "B" } ]
+
+ Note that both [obj_dir] and [obj_sec] are "paths" that is to say,
+ as opposed to [obj_mp] which is a single module name.
+
+ *)
+type object_prefix = {
+ obj_dir : DirPath.t;
+ obj_mp : ModPath.t;
+ obj_sec : DirPath.t;
+}
+
+val eq_op : object_prefix -> object_prefix -> bool
+
+(** to this type are mapped [DirPath.t]'s in the nametab *)
+module GlobDirRef : sig
+ type t =
+ | DirOpenModule of object_prefix
+ | DirOpenModtype of object_prefix
+ | DirOpenSection of object_prefix
+ | DirModule of object_prefix
+ val equal : t -> t -> bool
+end
+
+type global_dir_reference = GlobDirRef.t
+[@@ocaml.deprecated "Use [GlobDirRef.t]"]
+
+val eq_global_dir_reference :
+ GlobDirRef.t -> GlobDirRef.t -> bool
+[@@ocaml.deprecated "Use [GlobDirRef.equal]"]
+
+exception GlobalizationError of qualid
+
+(** Raises a globalization error *)
+val error_global_not_found : qualid -> 'a
+
+(** {6 Register visibility of things } *)
+
+(** The visibility can be registered either
+ - for all suffixes not shorter then a given int -- when the
+ object is loaded inside a module -- or
+ - for a precise suffix, when the module containing (the module
+ containing ...) the object is opened (imported)
+
+*)
+
+type visibility = Until of int | Exactly of int
+
+val map_visibility : (int -> int) -> visibility -> visibility
+
+val push : visibility -> full_path -> GlobRef.t -> unit
+val push_modtype : visibility -> full_path -> ModPath.t -> unit
+val push_dir : visibility -> DirPath.t -> GlobDirRef.t -> unit
+val push_syndef : visibility -> full_path -> syndef_name -> unit
+
+module UnivIdMap : CMap.ExtS with type key = Univ.Level.UGlobal.t
+
+val push_universe : visibility -> full_path -> Univ.Level.UGlobal.t -> unit
+
+(** {6 The following functions perform globalization of qualified names } *)
+
+(** These functions globalize a (partially) qualified name or fail with
+ [Not_found] *)
+
+val locate : qualid -> GlobRef.t
+val locate_extended : qualid -> extended_global_reference
+val locate_constant : qualid -> Constant.t
+val locate_syndef : qualid -> syndef_name
+val locate_modtype : qualid -> ModPath.t
+val locate_dir : qualid -> GlobDirRef.t
+val locate_module : qualid -> ModPath.t
+val locate_section : qualid -> DirPath.t
+val locate_universe : qualid -> Univ.Level.UGlobal.t
+
+(** These functions globalize user-level references into global
+ references, like [locate] and co, but raise a nice error message
+ in case of failure *)
+
+val global : qualid -> GlobRef.t
+val global_inductive : qualid -> inductive
+
+(** These functions locate all global references with a given suffix;
+ if [qualid] is valid as such, it comes first in the list *)
+
+val locate_all : qualid -> GlobRef.t list
+val locate_extended_all : qualid -> extended_global_reference list
+val locate_extended_all_dir : qualid -> GlobDirRef.t list
+val locate_extended_all_modtype : qualid -> ModPath.t list
+
+(** Experimental completion support, API is _unstable_ *)
+val completion_canditates : qualid -> extended_global_reference list
+(** [completion_canditates qualid] will return the list of global
+ references that have [qualid] as a prefix. UI usually will want to
+ compose this with [shortest_qualid_of_global] *)
+
+(** Mapping a full path to a global reference *)
+
+val global_of_path : full_path -> GlobRef.t
+val extended_global_of_path : full_path -> extended_global_reference
+
+(** {6 These functions tell if the given absolute name is already taken } *)
+
+val exists_cci : full_path -> bool
+val exists_modtype : full_path -> bool
+val exists_dir : DirPath.t -> bool
+val exists_section : DirPath.t -> bool (** deprecated synonym of [exists_dir] *)
+
+val exists_module : DirPath.t -> bool (** deprecated synonym of [exists_dir] *)
+
+val exists_universe : full_path -> bool
+
+(** {6 These functions locate qualids into full user names } *)
+
+val full_name_cci : qualid -> full_path
+val full_name_modtype : qualid -> full_path
+val full_name_module : qualid -> DirPath.t
+
+(** {6 Reverse lookup }
+ Finding user names corresponding to the given
+ internal name *)
+
+(** Returns the full path bound to a global reference or syntactic
+ definition, and the (full) dirpath associated to a module path *)
+
+val path_of_syndef : syndef_name -> full_path
+val path_of_global : GlobRef.t -> full_path
+val dirpath_of_module : ModPath.t -> DirPath.t
+val path_of_modtype : ModPath.t -> full_path
+
+(** A universe_id might not be registered with a corresponding user name.
+ @raise Not_found if the universe was not introduced by the user. *)
+val path_of_universe : Univ.Level.UGlobal.t -> full_path
+
+(** Returns in particular the dirpath or the basename of the full path
+ associated to global reference *)
+
+val dirpath_of_global : GlobRef.t -> DirPath.t
+val basename_of_global : GlobRef.t -> Id.t
+
+(** Printing of global references using names as short as possible.
+ @raise Not_found when the reference is not in the global tables. *)
+val pr_global_env : Id.Set.t -> GlobRef.t -> Pp.t
+
+
+(** The [shortest_qualid] functions given an object with [user_name]
+ Coq.A.B.x, try to find the shortest among x, B.x, A.B.x and
+ Coq.A.B.x that denotes the same object.
+ @raise Not_found for unknown objects. *)
+
+val shortest_qualid_of_global : ?loc:Loc.t -> Id.Set.t -> GlobRef.t -> qualid
+val shortest_qualid_of_syndef : ?loc:Loc.t -> Id.Set.t -> syndef_name -> qualid
+val shortest_qualid_of_modtype : ?loc:Loc.t -> ModPath.t -> qualid
+val shortest_qualid_of_module : ?loc:Loc.t -> ModPath.t -> qualid
+val shortest_qualid_of_universe : ?loc:Loc.t -> Univ.Level.UGlobal.t -> qualid
+
+(** Deprecated synonyms *)
+
+val extended_locate : qualid -> extended_global_reference (*= locate_extended *)
+val absolute_reference : full_path -> GlobRef.t (** = global_of_path *)
+
+(** {5 Generic name handling} *)
+
+(** NOT FOR PUBLIC USE YET. Plugin writers, please do not rely on this API. *)
+
+module type UserName = sig
+ type t
+ val equal : t -> t -> bool
+ val to_string : t -> string
+ val repr : t -> Id.t * module_ident list
+end
+
+module type EqualityType =
+sig
+ type t
+ val equal : t -> t -> bool
+end
+
+module type NAMETREE = sig
+ type elt
+ type t
+ type user_name
+
+ val empty : t
+ val push : visibility -> user_name -> elt -> t -> t
+ val locate : qualid -> t -> elt
+ val find : user_name -> t -> elt
+ val exists : user_name -> t -> bool
+ val user_name : qualid -> t -> user_name
+ val shortest_qualid : ?loc:Loc.t -> Id.Set.t -> user_name -> t -> qualid
+ val find_prefixes : qualid -> t -> elt list
+ val match_prefixes : qualid -> t -> elt list
+end
+
+module Make (U : UserName) (E : EqualityType) :
+ NAMETREE with type user_name = U.t and type elt = E.t
diff --git a/library/states.ml b/library/states.ml
new file mode 100644
index 0000000000..92bdc410a3
--- /dev/null
+++ b/library/states.ml
@@ -0,0 +1,43 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Util
+open System
+
+type state = Lib.frozen * Summary.frozen
+
+let lib_of_state = fst
+let summary_of_state = snd
+let replace_summary (lib,_) st = lib, st
+let replace_lib (_,st) lib = lib, st
+
+let freeze ~marshallable =
+ (Lib.freeze ~marshallable, Summary.freeze_summaries ~marshallable)
+
+let unfreeze (fl,fs) =
+ Lib.unfreeze fl;
+ Summary.unfreeze_summaries fs
+
+let extern_state s =
+ System.extern_state Coq_config.state_magic_number s (freeze ~marshallable:true)
+
+let intern_state s =
+ unfreeze (with_magic_number_check (System.intern_state Coq_config.state_magic_number) s);
+ Library.overwrite_library_filenames s
+
+(* Rollback. *)
+
+let with_state_protection f x =
+ let st = freeze ~marshallable:false in
+ try
+ let a = f x in unfreeze st; a
+ with reraise ->
+ let reraise = CErrors.push reraise in
+ (unfreeze st; iraise reraise)
diff --git a/library/states.mli b/library/states.mli
new file mode 100644
index 0000000000..52feb95222
--- /dev/null
+++ b/library/states.mli
@@ -0,0 +1,36 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** {6 States of the system} *)
+
+(** In that module, we provide functions to get
+ and set the state of the whole system. Internally, it is done by
+ freezing the states of both [Lib] and [Summary]. We provide functions
+ to write and restore state to and from a given file. *)
+
+val intern_state : string -> unit
+val extern_state : string -> unit
+
+type state
+val freeze : marshallable:bool -> state
+val unfreeze : state -> unit
+
+val summary_of_state : state -> Summary.frozen
+val lib_of_state : state -> Lib.frozen
+val replace_summary : state -> Summary.frozen -> state
+val replace_lib : state -> Lib.frozen -> state
+
+(** {6 Rollback } *)
+
+(** [with_state_protection f x] applies [f] to [x] and restores the
+ state of the whole system as it was before applying [f] *)
+
+val with_state_protection : ('a -> 'b) -> 'a -> 'b
+
diff --git a/library/summary.ml b/library/summary.ml
new file mode 100644
index 0000000000..8fbca44353
--- /dev/null
+++ b/library/summary.ml
@@ -0,0 +1,165 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+open CErrors
+open Util
+
+module Dyn = Dyn.Make ()
+
+type 'a summary_declaration = {
+ freeze_function : marshallable:bool -> 'a;
+ unfreeze_function : 'a -> unit;
+ init_function : unit -> unit }
+
+let sum_mod = ref None
+let sum_map = ref String.Map.empty
+
+let mangle id = id ^ "-SUMMARY"
+let unmangle id = String.(sub id 0 (length id - 8))
+
+let ml_modules = "ML-MODULES"
+
+let internal_declare_summary fadd sumname sdecl =
+ let infun, outfun, tag = Dyn.Easy.make_dyn_tag (mangle sumname) in
+ let dyn_freeze ~marshallable = infun (sdecl.freeze_function ~marshallable)
+ and dyn_unfreeze sum = sdecl.unfreeze_function (outfun sum)
+ and dyn_init = sdecl.init_function in
+ let ddecl = {
+ freeze_function = dyn_freeze;
+ unfreeze_function = dyn_unfreeze;
+ init_function = dyn_init }
+ in
+ fadd sumname ddecl;
+ tag
+
+let declare_ml_modules_summary decl =
+ let ml_add _ ddecl = sum_mod := Some ddecl in
+ internal_declare_summary ml_add ml_modules decl
+
+let declare_ml_modules_summary decl =
+ ignore(declare_ml_modules_summary decl)
+
+let declare_summary_tag sumname decl =
+ let fadd name ddecl = sum_map := String.Map.add name ddecl !sum_map in
+ let () = if String.Map.mem sumname !sum_map then
+ anomaly ~label:"Summary.declare_summary"
+ (str "Colliding summary names: " ++ str sumname ++ str " vs. " ++ str sumname ++ str ".")
+ in
+ internal_declare_summary fadd sumname decl
+
+let declare_summary sumname decl =
+ ignore(declare_summary_tag sumname decl)
+
+type frozen = {
+ summaries : Dyn.t String.Map.t;
+ (** Ordered list w.r.t. the first component. *)
+ ml_module : Dyn.t option;
+ (** Special handling of the ml_module summary. *)
+}
+
+let empty_frozen = { summaries = String.Map.empty; ml_module = None }
+
+let freeze_summaries ~marshallable : frozen =
+ let smap decl = decl.freeze_function ~marshallable in
+ { summaries = String.Map.map smap !sum_map;
+ ml_module = Option.map (fun decl -> decl.freeze_function ~marshallable) !sum_mod;
+ }
+
+let warn_summary_out_of_scope =
+ let name = "summary-out-of-scope" in
+ let category = "dev" in
+ let default = CWarnings.Disabled in
+ CWarnings.create ~name ~category ~default (fun name ->
+ Pp.str (Printf.sprintf
+ "A Coq plugin was loaded inside a local scope (such as a Section). It is recommended to load plugins at the start of the file. Summary entry: %s"
+ name)
+ )
+
+let unfreeze_summaries ?(partial=false) { summaries; ml_module } =
+ (* The unfreezing of [ml_modules_summary] has to be anticipated since it
+ * may modify the content of [summaries] by loading new ML modules *)
+ begin match !sum_mod with
+ | None -> anomaly (str "Undeclared summary " ++ str ml_modules ++ str ".")
+ | Some decl -> Option.iter (fun state -> decl.unfreeze_function state) ml_module
+ end;
+ (* We must be independent on the order of the map! *)
+ let ufz name decl =
+ try decl.unfreeze_function String.Map.(find name summaries)
+ with Not_found ->
+ if not partial then begin
+ warn_summary_out_of_scope name;
+ decl.init_function ()
+ end;
+ in
+ (* String.Map.iter unfreeze_single !sum_map *)
+ String.Map.iter ufz !sum_map
+
+let init_summaries () =
+ String.Map.iter (fun _ decl -> decl.init_function ()) !sum_map
+
+(** For global tables registered statically before the end of coqtop
+ launch, the following empty [init_function] could be used. *)
+
+let nop () = ()
+
+(** Summary projection *)
+let project_from_summary { summaries } tag =
+ let id = unmangle (Dyn.repr tag) in
+ let state = String.Map.find id summaries in
+ Option.get (Dyn.Easy.prj state tag)
+
+let modify_summary st tag v =
+ let id = unmangle (Dyn.repr tag) in
+ let summaries = String.Map.set id (Dyn.Easy.inj v tag) st.summaries in
+ {st with summaries}
+
+let remove_from_summary st tag =
+ let id = unmangle (Dyn.repr tag) in
+ let summaries = String.Map.remove id st.summaries in
+ {st with summaries}
+
+(** All-in-one reference declaration + registration *)
+
+let ref_tag ?(freeze=fun ~marshallable r -> r) ~name x =
+ let r = ref x in
+ let tag = declare_summary_tag name
+ { freeze_function = (fun ~marshallable -> freeze ~marshallable !r);
+ unfreeze_function = ((:=) r);
+ init_function = (fun () -> r := x) } in
+ r, tag
+
+let ref ?freeze ~name x = fst @@ ref_tag ?freeze ~name x
+
+module Local = struct
+
+type 'a local_ref = ('a CEphemeron.key * string) ref
+
+let (:=) r v = r := (CEphemeron.create v, snd !r)
+
+let (!) r =
+ let key, name = !r in
+ try CEphemeron.get key
+ with CEphemeron.InvalidKey ->
+ let { init_function } = String.Map.find name !sum_map in
+ init_function ();
+ CEphemeron.get (fst !r)
+
+let ref ?(freeze=fun x -> x) ~name init =
+ let r = Pervasives.ref (CEphemeron.create init, name) in
+ declare_summary name
+ { freeze_function = (fun ~marshallable -> freeze !r);
+ unfreeze_function = ((:=) r);
+ init_function = (fun () -> r := init) };
+ r
+
+end
+
+let dump = Dyn.dump
diff --git a/library/summary.mli b/library/summary.mli
new file mode 100644
index 0000000000..0d77d725ac
--- /dev/null
+++ b/library/summary.mli
@@ -0,0 +1,90 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
+(* <O___,, * (see CREDITS file for the list of authors) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** This module registers the declaration of global tables, which will be kept
+ in synchronization during the various backtracks of the system. *)
+
+(** Types of global Coq states. The ['a] type should be pure and marshallable by
+ the standard OCaml marshalling function. *)
+type 'a summary_declaration = {
+ freeze_function : marshallable:bool -> 'a;
+ (** freeze_function [true] is for marshalling to disk.
+ * e.g. lazy must be forced *)
+ unfreeze_function : 'a -> unit;
+ init_function : unit -> unit }
+
+(** For tables registered during the launch of coqtop, the [init_function]
+ will be run only once, during an [init_summaries] done at the end of
+ coqtop initialization. For tables registered later (for instance
+ during a plugin dynlink), [init_function] is used when unfreezing
+ an earlier frozen state that doesn't contain any value for this table.
+
+ Beware: for tables registered dynamically after the initialization
+ of Coq, their init functions may not be run immediately. It is hence
+ the responsability of plugins to initialize themselves properly.
+*)
+
+val declare_summary : string -> 'a summary_declaration -> unit
+
+(** We provide safe projection from the summary to the types stored in
+ it.*)
+module Dyn : Dyn.S
+
+val declare_summary_tag : string -> 'a summary_declaration -> 'a Dyn.tag
+
+(** All-in-one reference declaration + summary registration.
+ It behaves just as OCaml's standard [ref] function, except
+ that a [declare_summary] is done, with [name] as string.
+ The [init_function] restores the reference to its initial value.
+ The [freeze_function] can be overridden *)
+
+val ref : ?freeze:(marshallable:bool -> 'a -> 'a) -> name:string -> 'a -> 'a ref
+val ref_tag : ?freeze:(marshallable:bool -> 'a -> 'a) -> name:string -> 'a -> 'a ref * 'a Dyn.tag
+
+(* As [ref] but the value is local to a process, i.e. not sent to, say, proof
+ * workers. It is useful to implement a local cache for example. *)
+module Local : sig
+
+ type 'a local_ref
+ val ref : ?freeze:('a -> 'a) -> name:string -> 'a -> 'a local_ref
+ val (:=) : 'a local_ref -> 'a -> unit
+ val (!) : 'a local_ref -> 'a
+
+end
+
+(** Special summary for ML modules. This summary entry is special
+ because its unfreeze may load ML code and hence add summary
+ entries. Thus is has to be recognizable, and handled properly.
+ *)
+val declare_ml_modules_summary : 'a summary_declaration -> unit
+
+(** For global tables registered statically before the end of coqtop
+ launch, the following empty [init_function] could be used. *)
+
+val nop : unit -> unit
+
+(** The type [frozen] is a snapshot of the states of all the registered
+ tables of the system. *)
+
+type frozen
+
+val empty_frozen : frozen
+val freeze_summaries : marshallable:bool -> frozen
+val unfreeze_summaries : ?partial:bool -> frozen -> unit
+val init_summaries : unit -> unit
+
+(** Typed projection of the summary. Experimental API, use with CARE *)
+
+val modify_summary : frozen -> 'a Dyn.tag -> 'a -> frozen
+val project_from_summary : frozen -> 'a Dyn.tag -> 'a
+val remove_from_summary : frozen -> 'a Dyn.tag -> frozen
+
+(** {6 Debug} *)
+val dump : unit -> (int * string) list