aboutsummaryrefslogtreecommitdiffhomepage
path: root/library/nametab.ml
blob: 25348379168f65eaf050a5c806e4ad1a3fad429c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259

(* $Id$ *)

open Util
open Pp
open Names
open Libobject
open Declarations
open Term

(*s qualified names *)
type qualid = string list * identifier

let make_qualid p id = (p,id)
let repr_qualid q = q

let string_of_qualid (l,id) = String.concat "." (l@[string_of_id id])
let pr_qualid (l,id) =
  prlist_with_sep (fun () -> pr_str ".") pr_str (l@[string_of_id id])

let qualid_of_sp sp = make_qualid (dirpath sp) (basename sp)

exception GlobalizationError of qualid

let error_global_not_found_loc loc q =
  Stdpp.raise_with_loc loc (GlobalizationError q)

(*s Roots of the space of absolute names *)

let roots = ref []
let push_library_root s = roots := list_add_set s !roots

let coq_root = "Coq"
let default_root = "Scratch"

(* Names tables *)
type cci_table = global_reference Idmap.t
type obj_table = (section_path * obj) Idmap.t
type mod_table = (section_path * module_contents) Stringmap.t
and module_contents = Closed of cci_table * obj_table * mod_table

let empty =
  Closed (Idmap.empty, Idmap.empty, Stringmap.empty)
 
let persistent_nametab = ref (empty : module_contents)
let local_nametab = ref (empty : module_contents)

let push_cci (Closed (ccitab, objtab, modtab)) s ref =
  Closed (Idmap.add s ref ccitab, objtab, modtab)

let push_obj (Closed (ccitab, objtab, modtab)) s obj =
  Closed (ccitab, Idmap.add s obj objtab, modtab)

let push_mod (Closed (ccitab, objtab, modtab)) s mc =
  (* devrait pas mais ca plante en décommentant la ligne ci-dessous *)
 (* assert (not (Stringmap.mem s modtab)); *)
  Closed (ccitab, objtab, Stringmap.add s mc modtab)

let push_tree push dir id o =
  let rec search (Closed (ccitab, objtab, modtab) as tabs) pref = function
    | id :: dir' ->
	let sp, mc = 
	  try Stringmap.find id modtab
	  with Not_found ->
	    let pref = List.rev pref in
	    (make_path dir (id_of_string id) CCI, empty)
	in
	Closed (ccitab, objtab,
		Stringmap.add id (sp,search mc (id::pref) dir') modtab)
    | [] ->
	push tabs id o in
  persistent_nametab := search !persistent_nametab [] dir

(* This pushes a name at the current level (for relative qualified use) *)
let push_cci_current = push_tree push_cci []
let push_obj_current = push_tree push_obj []
let push_mod_current = push_tree push_mod []

(* This pushes a name at the root level (for absolute access) *)
let push_cci_absolute = push_tree push_cci
let push_obj_absolute = push_tree push_obj
let push_mod_absolute = push_tree push_mod

(* These are entry points for new declarations at toplevel *)
(* Do not use with "open" since it pushes an absolute name too *)
let push sp ref =
  let dir, s = repr_qualid (qualid_of_sp sp) in
  push_cci_absolute dir s ref;
  push_cci_current s ref

let push_object sp obj =
  let dir, s = repr_qualid (qualid_of_sp sp) in
  push_obj_absolute dir s (sp,obj);
  push_obj_current s (sp,obj)

let push_module sp mc =
  let dir, s = repr_qualid (qualid_of_sp sp) in
  let s = string_of_id s in
  push_mod_absolute dir s (sp,mc);
  if List.mem s !roots then 
    warning ("Cannot allow access to "^s^" by relative paths: it is already registered as a root of the Coq library")
  else push_mod_current s (sp,mc)

(* Sections are not accessible by basename *)
let push_section sp mc =
  let dir, s = repr_qualid (qualid_of_sp sp) in
  push_mod_absolute dir (string_of_id s) (sp,mc)

(* This is an entry point for local declarations at toplevel *)
(* Do not use with "open" since it pushes an absolute name too *)

let push_cci_local s ref =
  local_nametab := push_cci !local_nametab s ref

let push_obj_local s o =
  local_nametab := push_obj !local_nametab s o

let push_local sp ref =
  let dir, s = repr_qualid (qualid_of_sp sp) in
  push_cci_absolute dir s ref;
  push_cci_local s ref

let push_local_object sp obj =
  let dir, s = repr_qualid (qualid_of_sp sp) in
  push_obj_absolute dir s (sp,obj);
  push_obj_local s (sp,obj)

(* These are entry points to locate names *)
(* If the name starts with the coq_root name, then it is an absolute name *)
let locate qid =
  let (dir,id) = repr_qualid qid in
  let rec search (Closed (ccitab,_,modtab)) = function
    | id :: dir' -> search (snd (Stringmap.find id modtab)) dir'
    | [] -> Idmap.find id ccitab
  in
  try search !local_nametab dir
  with Not_found -> search !persistent_nametab dir

let locate_obj qid =
  let (dir,id) = repr_qualid qid in
  let rec search (Closed (_,objtab,modtab)) = function
    | id :: dir' -> search (snd (Stringmap.find id modtab)) dir'
    | [] -> Idmap.find id objtab
  in
  try search !local_nametab dir
  with Not_found -> search !persistent_nametab dir

let locate_module qid =
  let (dir,id) = repr_qualid qid in
  let s = string_of_id id in
  let rec search (Closed (_,_,modtab)) = function
    | id :: dir' -> search (snd (Stringmap.find id modtab)) dir'
    | [] -> Stringmap.find s modtab
  in
  try search !local_nametab dir
  with Not_found -> search !persistent_nametab dir

let locate_constant qid =
  match locate qid with
    | ConstRef sp -> sp
    | _ -> raise Not_found

let sp_of_id _ id = locate (make_qualid [] id)

let constant_sp_of_id id =
  match locate (make_qualid [] id) with
    | ConstRef sp -> sp
    | _ -> raise Not_found

let check_absoluteness dir =
  match dir with
    | a::_ when List.mem a !roots -> ()
    | _ -> anomaly ("Not an absolute dirpath: "^(string_of_dirpath dir))

let absolute_reference sp =
  check_absoluteness (dirpath sp);
  locate (qualid_of_sp sp)

exception Found of global_reference
let locate_in_module dir id =
  let rec exists_in id (Closed (ccitab,_,modtab)) =
    try raise (Found (Idmap.find id ccitab))
    with Not_found -> 
      Stringmap.iter (fun _ (sp,mc) -> exists_in id mc) modtab
  in
  let rec search (Closed (ccitab,_,modtab) as mc) = function
    | modid :: dir' -> search (snd (Stringmap.find modid modtab)) dir'
    | [] -> 
	try exists_in id mc; raise Not_found
	with Found ref -> ref
  in
  search !persistent_nametab dir

let locate_in_absolute_module dir id =
  check_absoluteness dir;
  locate_in_module dir id

(* These are entry points to make the contents of a module/section visible *)
(* in the current env (does not affect the absolute name space `coq_root') *)
let open_module_contents qid =
  let _, (Closed (ccitab,objtab,modtab)) = locate_module qid in
  Idmap.iter push_cci_current ccitab;
(*  Idmap.iter (fun _ -> Libobject.open_object) objtab;*)
  Stringmap.iter push_mod_current modtab

let conditional_push ref = push_cci_current ref (* TODO *)

let open_section_contents qid =
  let _, (Closed (ccitab,objtab,modtab)) = locate_module qid in
  Idmap.iter push_cci_current ccitab;
(*  Idmap.iter (fun _ -> Libobject.open_object) objtab;*)
  Stringmap.iter push_mod_current modtab

let rec rec_open_module_contents qid =
  let _, (Closed (ccitab,objtab,modtab)) = locate_module qid in
  Idmap.iter push_cci_current ccitab;
(*  Idmap.iter (fun _ -> Libobject.open_object) objtab;*)
  Stringmap.iter 
    (fun m (sp,_ as mt) -> 
       push_mod_current m mt;
       rec_open_module_contents (qualid_of_sp sp))
    modtab

let exists_cci sp =
  try let _ = locate (qualid_of_sp sp) in true with Not_found -> false

let exists_module sp =
  try let _ = locate_module (qualid_of_sp sp) in true with Not_found -> false

(********************************************************************)
(* Registration of persistent tables as a global table and rollback *)

type frozen = module_contents

let init () = persistent_nametab := empty; roots := []
let freeze () = !persistent_nametab, !roots
let unfreeze (mc,r) = persistent_nametab := mc; roots := r

let _ = 
  Summary.declare_summary "persistent-names"
    { Summary.freeze_function = freeze;
      Summary.unfreeze_function = unfreeze;
      Summary.init_function = init;
      Summary.survive_section = true }

(********************************************************************)
(* Registration of persistent tables as a global table and rollback *)

let init () = local_nametab := empty
let freeze () = !local_nametab
let unfreeze mc = local_nametab := mc

let _ = 
  Summary.declare_summary "local-names"
    { Summary.freeze_function = freeze;
      Summary.unfreeze_function = unfreeze;
      Summary.init_function = init;
      Summary.survive_section = false }