1 (* ========================================================================== *)
\r
2 (* FLYSPECK - BOOK FORMALIZATION *)
\r
4 (* Update theorem search *)
\r
5 (* Date: 2010-07-16 *)
\r
7 (* 2012-09-06: JRH fixed up for OCaml 4.0 and added alphabetic sorting. *)
\r
8 (* ========================================================================== *)
\r
10 (* ========================================================================= *)
\r
11 (* Create search database from OCaml / modify search database dynamically. *)
\r
13 (* This file assigns to "theorems", which is a list of name-theorem pairs. *)
\r
14 (* The core system already has such a database set up. Use this file if you *)
\r
15 (* want to update the database beyond the core, so you can search it. *)
\r
17 (* The trickery to get at the OCaml environment is due to Roland Zumkeller. *)
\r
18 (* It works by copying some internal data structures and casting into the *)
\r
19 (* copy using Obj.magic. *)
\r
20 (* ========================================================================= *)
\r
23 (* module Update_database_310 = struct *)
\r
25 (* Execute any OCaml expression given as a string. *)
\r
27 let exec = ignore o Toploop.execute_phrase false Format.std_formatter
\r
28 o !Toploop.parse_toplevel_phrase o Lexing.from_string;;
\r
32 (* ------------------------------------------------------------------------- *)
\r
33 (* Basic data structures copied from OCaml. May be version-dependent. *)
\r
34 (* ------------------------------------------------------------------------- *)
\r
38 (*** from ./typing/ident.ml: ***)
\r
40 type ident_t = { stamp: int; name: string; mutable flags: int };;
\r
44 | Node of 'a tbl * 'a data * 'a tbl * int
\r
49 previous: 'a data option };;
\r
51 (*** from ./typing/path.ml: ***)
\r
55 | Pdot of path_t * string * int
\r
56 | Papply of path_t * path_t;;
\r
58 (*** from typing/types.ml: ***)
\r
62 { mutable desc: type_desc;
\r
68 (if String.sub Sys.ocaml_version 0 1 = "4"
\r
69 then "Tvar of string option\n"
\r
71 " | Tarrow of label * type_expr * type_expr * commutable
\r
72 | Ttuple of type_expr list
\r
73 | Tconstr of path_t * type_expr list * abbrev_memo ref
\r
74 | Tobject of type_expr * (path_t * type_expr list) option ref
\r
75 | Tfield of string * field_kind * type_expr * type_expr
\r
77 | Tlink of type_expr
\r
78 | Tsubst of type_expr
\r
79 | Tvariant of row_desc
\r
81 | Tpoly of type_expr * type_expr list
\r
84 { row_fields: (label * row_field) list;
\r
85 row_more: type_expr;
\r
86 row_bound: type_expr list;
\r
89 row_name: (path_t * type_expr list) option }
\r
92 Rpresent of type_expr option
\r
93 | Reither of bool * type_expr list * bool * row_field option ref
\r
98 | Mcons of path_t * type_expr * type_expr * abbrev_memo
\r
99 | Mlink of abbrev_memo ref
\r
102 Fvar of field_kind option ref
\r
109 | Clink of commutable ref;;
\r
112 type value_description =
\r
113 { val_type: type_expr;
\r
114 val_kind: dummy };;
\r
117 Tmty_ident of path_t
\r
118 | Tmty_signature of signature
\r
119 | Tmty_functor of ident_t * module_type * module_type
\r
121 and signature = signature_item list
\r
123 and signature_item =
\r
124 Tsig_value of ident_t * value_description
\r
125 | Tsig_type of ident_t * dummy * dummy
\r
126 | Tsig_exception of ident_t * dummy
\r
127 | Tsig_module of ident_t * module_type * dummy
\r
128 | Tsig_modtype of ident_t * dummy
\r
129 | Tsig_class of ident_t * dummy * dummy
\r
130 | Tsig_cltype of ident_t * dummy * dummy;;
\r
132 (*** from ./typing/env.ml: ***)
\r
135 "type env_t = {\n" ^
\r
136 (if String.sub Sys.ocaml_version 0 1 = "4"
\r
137 then "values: ((path_t * value_description) * bool ref) tbl;\n"
\r
138 else "values: (path_t * value_description) tbl;\n") ^
\r
139 (if (let v = String.sub Sys.ocaml_version 0 4 in v = "3.09" or v = "3.10")
\r
141 else "annotations: dummy;\n") ^
\r
143 labels: dummy;\n" ^
\r
144 (if String.sub Sys.ocaml_version 0 1 = "4"
\r
145 then "constrs_by_path: dummy;\n"
\r
147 " types: dummy;\n" ^
\r
148 (if String.sub Sys.ocaml_version 0 1 = "4"
\r
149 then "modules: ((path_t * module_type) * bool ref) tbl;\n"
\r
150 else "modules: (path_t * module_type) tbl;\n") ^
\r
155 summary: dummy;\n" ^
\r
156 (if String.sub Sys.ocaml_version 0 1 = "4"
\r
157 then "local_constraints: dummy;
\r
158 gadt_instances: dummy;
\r
159 in_signature: dummy;
\r
163 (* ------------------------------------------------------------------------- *)
\r
164 (* End of basic data structures copied from OCaml. *)
\r
165 (* ------------------------------------------------------------------------- *)
\r
167 (* Iterate over the entries of a table. *)
\r
169 let rec iterTbl (f : ident_t -> 'a -> unit) = function
\r
171 | Node (t1,d,t2,_) ->
\r
176 (* If the given type is simple return its name, otherwise None. *)
\r
178 let rec get_simple_type = function
\r
179 | Tlink { desc = Tconstr (Pident p,[],_) } -> Some p.name
\r
180 | Tlink { desc = d } -> get_simple_type d
\r
183 (* Evaluate any OCaml expression given as a string. *)
\r
186 exec ("let buf__ = ( " ^ n ^ " );;");
\r
187 Obj.magic (Toploop.getvalue "buf__");;
\r
189 (* Register all theorems added since the last update. *)
\r
191 let thm_hashtable = Hashtbl.create 5000;;
\r
194 "let update_database =
\r
195 let lastStamp = ref 0
\r
196 and currentStamp = ref 0
\r
197 and thms = thm_hashtable in
\r
200 if i.stamp > !lastStamp then
\r
201 ((if i.stamp > !currentStamp then currentStamp := i.stamp);
\r
204 let rec regVal pfx = ifNew (fun i vd ->
\r
205 let n = pfx ^ i.name in
\r
206 if n <> \"buf__\" then
\r
207 (if get_simple_type vd.val_type.desc = Some \"thm\"
\r
208 then Hashtbl.replace thms n (eval n)
\r
209 else Hashtbl.remove thms n))
\r
211 and regMod pfx = ifNew (fun i mt ->
\r
213 | Tmty_signature sg ->
\r
214 let pfx' = pfx ^ i.name ^ \".\" in
\r
215 List.iter (function
\r
216 | Tsig_value (i',vd) -> regVal pfx' i' vd
\r
217 | Tsig_module (i',mt',_) -> regMod pfx' i' mt'
\r
222 let env = Obj.magic !Toploop.toplevel_env in
\r
224 (if String.sub Sys.ocaml_version 0 1 = "4"
\r
225 then "iterTbl (fun i ((_,vd),_) -> regVal \"\" i vd) env.values;
\r
226 iterTbl (fun i ((_,mt),_) -> regMod \"\" i mt) env.modules;
\r
229 "iterTbl (fun i (_,vd) -> regVal \"\" i vd) env.values;
\r
230 iterTbl (fun i (_,mt) -> regMod \"\" i mt) env.modules;
\r
232 " lastStamp := !currentStamp;
\r
233 theorems := Hashtbl.fold (fun s t l -> (s,t)::l) thms [];;
\r
236 (* ------------------------------------------------------------------------- *)
\r
237 (* Search (automatically updates) *)
\r
238 (* ------------------------------------------------------------------------- *)
\r
240 let omit t = mk_comb(mk_var("<omit this pattern>",W mk_fun_ty (type_of t)),t);;
\r
242 let exactly t = mk_comb(mk_var("<match aconv>",W mk_fun_ty (type_of t)),t);;
\r
244 let name s = mk_comb(mk_var("<match theorem name>",W mk_fun_ty aty),
\r
247 let full t = mk_comb(mk_var("<full term>",W mk_fun_ty (type_of t)),t);;
\r
249 let rewrite t = mk_comb(mk_var("<rewrite>",W mk_fun_ty (type_of t)),t);;
\r
251 let regexp s = mk_comb(mk_var("<regexp>",W mk_fun_ty aty),
\r
255 let u = mk_pair pr in
\r
256 let ty = type_of u in
\r
257 let h = mk_var ("<search_or>",(mk_type("fun",[ty;aty]))) in
\r
261 (* very rough measure of the size of a printed term *)
\r
262 let rec term_length =
\r
263 let n = `NUMERAL` in
\r
264 let d = `DECIMAL` in
\r
266 | Abs(s,x) -> 1 + term_length x
\r
267 | Comb(s,x) -> if ((s = n) or (s = d)) then 2
\r
268 else ( term_length s + term_length x)
\r
271 let sortlength_thml thml =
\r
273 (function (s,t) as r -> (term_length (concl t),r)) thml in
\r
274 let stml = sort (fun (a,_) (b,_) -> (a < b)) ltml in
\r
278 (* main search function *)
\r
280 let search_thml term_matcher =
\r
281 let rec immediatesublist l1 l2 =
\r
285 | (h1::t1,h2::t2) -> h1 = h2 & immediatesublist t1 t2 in
\r
286 let rec sublist l1 l2 =
\r
290 | (h1::t1,h2::t2) -> immediatesublist l1 l2 or sublist l1 t2 in
\r
292 let rec conjuncts t =
\r
293 let t' = snd (strip_forall t) in
\r
294 if (is_conj t') then (let (a,b) = dest_conj t' in conjuncts a @ conjuncts b) else [t'] in
\r
297 let c = map (fst o dest_eq) (filter (is_eq) (conjuncts t)) in
\r
298 let h = map (fst o strip_comb) c in
\r
299 let hc = filter (is_const) h in
\r
300 map (fst o dest_const) hc in
\r
302 let is_rewrite t (n,th) =
\r
303 mem (fst(dest_const t)) (heads(snd( dest_thm th))) in
\r
305 let name_matches_regexp s (n,th) =
\r
306 let pat = Str.regexp (".*"^s) in
\r
307 Str.string_match pat n 0 in
\r
309 let exists_subterm_satisfying p (n,th) = can (find_term p) (concl th) in
\r
310 let exists_fullterm_satisfying p (n,th) = p (concl th) in
\r
311 let name_contains s (n,th) = sublist (explode s) (explode n) in
\r
312 let rec filterpred tm =
\r
314 Comb(Var("<omit this pattern>",_),t) -> not o filterpred t
\r
315 | Comb(Var("<match theorem name>",_),Var(pat,_)) -> name_contains pat
\r
316 | Comb(Var("<regexp>",_),Var(pat,_)) -> name_matches_regexp pat
\r
317 | Comb(Var("<search_or>",_),t) ->
\r
318 let (pat1,pat2) = dest_pair t in
\r
319 (fun (n,th) -> exists_subterm_satisfying (can (term_matcher pat1)) (n,th) or
\r
320 exists_subterm_satisfying (can (term_matcher pat2)) (n,th))
\r
321 | Comb(Var("<rewrite>",_),t) -> is_rewrite t
\r
322 | Comb(Var("<match aconv>",_),pat) -> exists_subterm_satisfying (aconv pat)
\r
323 | Comb(Var("<full term>",_),pat) -> exists_fullterm_satisfying (can (term_matcher pat))
\r
324 | pat -> exists_subterm_satisfying (can (term_matcher pat)) in
\r
325 fun pats thml -> update_database ();
\r
326 if (pats = []) then failwith ("keywords: omit (term), name (string),"^
\r
327 " disjunct (term,term), "^
\r
328 " regexp (string), exactly (term), full (term), rewrite (term constant)") else
\r
329 (itlist (filter o filterpred) pats thml);;
\r
332 let search pat = sort (increasing fst) (search_thml (term_match []) pat (!theorems));;
\r
334 (* ------------------------------------------------------------------------- *)
\r
335 (* Update to bring to current state. *)
\r
336 (* ------------------------------------------------------------------------- *)
\r
338 update_database ();;
\r