|
| 1 | +(* ========================================================================= *) |
| 2 | +(* Create search database from OCaml / modify search database dynamically. *) |
| 3 | +(* *) |
| 4 | +(* This file assigns to "theorems", which is a list of name-theorem pairs. *) |
| 5 | +(* The core system already has such a database set up. Use this file if you *) |
| 6 | +(* want to update the database beyond the core, so you can search it. *) |
| 7 | +(* *) |
| 8 | +(* The trickery to get at the OCaml environment is due to Roland Zumkeller *) |
| 9 | +(* and Michael Farber. It works by copying some internal data structures and *) |
| 10 | +(* casting into the copy using Obj.magic. *) |
| 11 | +(* ========================================================================= *) |
| 12 | + |
| 13 | +module Ocaml_typing = struct |
| 14 | + |
| 15 | +open Types |
| 16 | + |
| 17 | +(* If the given type is simple return its name, otherwise None. *) |
| 18 | + |
| 19 | +let rec get_simple_type = function |
| 20 | + | Tlink texpr -> |
| 21 | + (match get_desc texpr with |
| 22 | + | Tconstr (Pident p,[],_) -> Some (Ident.name p) |
| 23 | + | d -> get_simple_type d) |
| 24 | + | Tconstr (Path.Pident p, [], _) -> Some (Ident.name p) |
| 25 | + | _ -> None;; |
| 26 | + |
| 27 | +(* Execute any OCaml expression given as a string. *) |
| 28 | + |
| 29 | +let exec s = (ignore o Toploop.execute_phrase false Format.std_formatter |
| 30 | + o !Toploop.parse_toplevel_phrase o Lexing.from_string) s |
| 31 | + |
| 32 | +(* Evaluate any OCaml expression given as a string. *) |
| 33 | + |
| 34 | +let eval n = |
| 35 | + if String.contains n '.' then begin |
| 36 | + exec ("let buf__ = ( " ^ n ^ " );;"); |
| 37 | + Obj.magic (Toploop.getvalue "buf__") |
| 38 | + end else Obj.magic (Toploop.getvalue n) |
| 39 | + |
| 40 | +(* Register all theorems added since the last update. *) |
| 41 | +end |
| 42 | + |
| 43 | +module Lookuptheorems = struct |
| 44 | +open Types |
| 45 | + |
| 46 | +let lid_cons lidopt id = |
| 47 | + match lidopt with |
| 48 | + None -> Longident.Lident id |
| 49 | + | Some li -> Longident.Ldot(li, id) |
| 50 | + |
| 51 | +let it_val_1 lidopt s p vd acc = |
| 52 | + if (Some "thm") = Ocaml_typing.get_simple_type (get_desc vd.Types.val_type) then |
| 53 | + (lid_cons lidopt s)::acc else acc |
| 54 | + |
| 55 | +let it_mod_1 lidopt s p md acc = (lid_cons lidopt s)::acc |
| 56 | + |
| 57 | +let enum0 lidopt = |
| 58 | + try |
| 59 | + let vl = Env.fold_values (it_val_1 lidopt) lidopt !Toploop.toplevel_env [] in |
| 60 | + let ml = Env.fold_modules (it_mod_1 lidopt) lidopt !Toploop.toplevel_env [] in |
| 61 | + (vl, ml) |
| 62 | + with Not_found -> |
| 63 | + (* Looking for (Longident.Lident "Stream") raises Not_found. |
| 64 | + Stream is a deprecated alias module of "Stdlib.Stream", and the camlp-streams |
| 65 | + package that is used by pa_hol_syntax redefines Stream, which seems to |
| 66 | + confuse Env.fold_values and Env.fold_modules. *) |
| 67 | + ([], []) |
| 68 | + |
| 69 | +let rec enum1 lidopt acc = |
| 70 | + match enum0 lidopt with |
| 71 | + (vl, []) -> vl@acc |
| 72 | + | (vl, ml) -> |
| 73 | + List.fold_left (fun acc mlid -> |
| 74 | + enum1 (Some mlid) acc) (vl@acc) ml |
| 75 | + |
| 76 | +let string_of_longident lid = |
| 77 | + String.concat "." (Longident.flatten lid) |
| 78 | + |
| 79 | +let all_theorems () = |
| 80 | + let _ = Ocaml_typing.exec ("unset_jrh_lexer;;") in |
| 81 | + let res = enum1 None [] |
| 82 | + |> List.map (fun lid -> |
| 83 | + let s = string_of_longident lid in |
| 84 | + (s, (Ocaml_typing.eval s : thm))) in |
| 85 | + let _ = Ocaml_typing.exec ("set_jrh_lexer;;") in |
| 86 | + res |
| 87 | +end |
| 88 | + |
| 89 | + |
| 90 | +let update_database () = |
| 91 | + theorems := Lookuptheorems.all_theorems() |
| 92 | + |
| 93 | +(* ------------------------------------------------------------------------- *) |
| 94 | +(* Put an assignment of a theorem database in the named file. *) |
| 95 | +(* ------------------------------------------------------------------------- *) |
| 96 | + |
| 97 | +let make_database_assignment filename = |
| 98 | + update_database(); |
| 99 | + (let allnames = uniq(sort (<) (map fst (!theorems))) in |
| 100 | + let names = subtract allnames ["it"] in |
| 101 | + let entries = map (fun n -> "\""^n^"\","^n) names in |
| 102 | + let text = "needs \"help.ml\";;\n\n"^ |
| 103 | + "theorems :=\n[\n"^ |
| 104 | + end_itlist (fun a b -> a^";\n"^b) entries^"\n];;\n" in |
| 105 | + file_of_string filename text);; |
| 106 | + |
| 107 | +(* ------------------------------------------------------------------------- *) |
| 108 | +(* Search (automatically updates) *) |
| 109 | +(* ------------------------------------------------------------------------- *) |
| 110 | + |
| 111 | +let search = |
| 112 | + let rec immediatesublist l1 l2 = |
| 113 | + match (l1,l2) with |
| 114 | + [],_ -> true |
| 115 | + | _,[] -> false |
| 116 | + | (h1::t1,h2::t2) -> h1 = h2 && immediatesublist t1 t2 in |
| 117 | + let rec sublist l1 l2 = |
| 118 | + match (l1,l2) with |
| 119 | + [],_ -> true |
| 120 | + | _,[] -> false |
| 121 | + | (h1::t1,h2::t2) -> immediatesublist l1 l2 || sublist l1 t2 in |
| 122 | + let exists_subterm_satisfying p (n,th) = can (find_term p) (concl th) |
| 123 | + and name_contains s (n,th) = sublist (explode s) (explode n) in |
| 124 | + let rec filterpred tm = |
| 125 | + match tm with |
| 126 | + Comb(Var("<omit this pattern>",_),t) -> not o filterpred t |
| 127 | + | Comb(Var("<match theorem name>",_),Var(pat,_)) -> name_contains pat |
| 128 | + | Comb(Var("<match aconv>",_),pat) -> exists_subterm_satisfying (aconv pat) |
| 129 | + | pat -> exists_subterm_satisfying (can (term_match [] pat)) in |
| 130 | + fun pats -> |
| 131 | + update_database(); |
| 132 | + let triv,nontriv = partition is_var pats in |
| 133 | + (if triv <> [] then |
| 134 | + warn true |
| 135 | + ("Ignoring plain variables in search: "^ |
| 136 | + end_itlist (fun s t -> s^", "^t) (map (fst o dest_var) triv)) |
| 137 | + else ()); |
| 138 | + (if nontriv = [] && triv <> [] then [] |
| 139 | + else sort (increasing fst) |
| 140 | + (itlist (filter o filterpred) pats (!theorems)));; |
| 141 | + |
| 142 | +(* ------------------------------------------------------------------------- *) |
| 143 | +(* Update to bring things back to current state. *) |
| 144 | +(* ------------------------------------------------------------------------- *) |
| 145 | + |
| 146 | +update_database();; |
| 147 | + |
| 148 | +(* This printf checks whether standard modules like Printf are still alive |
| 149 | + after update_database. |
| 150 | + See also: https://github.com/ocaml/ocaml/issues/12271 *) |
| 151 | +Printf.printf "update_database.ml loaded! # theorems: %d\n" |
| 152 | + (List.length !theorems);; |
0 commit comments