text \Command to print names of a theorem statement\ theory Names_Of_Thm imports Main keywords "print_names_of_thm" :: diag and "print_dup_thms" :: diag begin ML \ signature NAMES_OF_THM = sig (* dynamic \ _ \ _: get all facts from context. *) val all_facts_of : bool -> Proof.context -> (Facts.ref * thm) list (* Find nicest name in list. Returns empty or singleton list. *) val nicest_name_of: Proof.context -> Facts.ref list -> Facts.ref list (* Beta-Eta normalize term, and standardize variable names *) val norm_term: term -> term type configT = {dynamic: bool, rdups: bool} (* Obtain names for given theorem *) val names_of: configT -> Proof.context -> term -> Facts.ref list val names_of_thm: configT -> Proof.context -> thm -> Facts.ref list (* Pretty print theorem name *) val pretty_ref: Proof.context -> Facts.ref -> Pretty.T val pretty_refs: Proof.context -> Facts.ref list -> Pretty.T val analyze_dup_names: Proof.context -> string -> (term * Facts.ref list) list val pretty_dup_name: Proof.context -> (term * Facts.ref list) -> Pretty.T val pretty_dup_names: Proof.context -> (term * Facts.ref list) list -> Pretty.T end structure Names_Of_Thm : NAMES_OF_THM = struct fun all_facts_of dynamic ctxt = let val dest = if dynamic then Facts.dest_all (Context.Proof ctxt) false else Facts.dest_static false val thy = Proof_Context.theory_of ctxt; val transfer = Global_Theory.transfer_theories thy; val local_facts = Proof_Context.facts_of ctxt val global_facts = Global_Theory.facts_of thy; in (dest [global_facts] local_facts @ dest [] global_facts) |> maps Facts.selections |> map (apsnd transfer) end; local val index_ord = option_ord (K EQUAL); val hidden_ord = bool_ord o apply2 Long_Name.is_hidden; val qual_ord = int_ord o apply2 Long_Name.qualification; val txt_ord = int_ord o apply2 size; fun nicer_name ((a, x), i) ((b, y), j) = (case bool_ord (a, b) of EQUAL => (case hidden_ord (x, y) of EQUAL => (case index_ord (i, j) of EQUAL => (case qual_ord (x, y) of EQUAL => txt_ord (x, y) | ord => ord) | ord => ord) | ord => ord) | ord => ord) <> GREATER; in fun nicer_shortest ctxt = let fun extern_shortest name = let val facts = Proof_Context.facts_of_fact ctxt name; val space = Facts.space_of facts; in (Facts.is_dynamic facts name, Name_Space.extern_shortest ctxt space name) end; fun nicer (Facts.Named ((x, _), i)) (Facts.Named ((y, _), j)) = nicer_name (extern_shortest x, i) (extern_shortest y, j) | nicer (Facts.Fact _) (Facts.Named _) = true | nicer (Facts.Named _) (Facts.Fact _) = false | nicer (Facts.Fact _) (Facts.Fact _) = true; in nicer end; fun nicest_name_of _ [] = [] | nicest_name_of ctxt (x::xs) = let fun rem x [] = x | rem x (y::ys) = rem (if nicer_shortest ctxt x y then x else y) ys in [rem x xs] end end; fun norm_term t = let val t = Envir.beta_eta_contract t val tfs = Term.add_tvars t [] val tfs = tfs ~~ (1 upto length tfs) |> map (fn ((n,s),i) => (TVar (n,s), TVar (("T"^Int.toString i,0),s))) |> Typtab.make fun mapT T = the_default T (Typtab.lookup tfs T) val fs = Term.add_vars t [] val fs = fs ~~ (1 upto length fs) |> map (fn ((n,T),i) => (Var (n,T), Var ( ("x"^Int.toString i,0) ,T ))) |> Termtab.make fun mapV V = the_default V (Termtab.lookup fs V) val t = t |> map_aterms mapV |> map_types (map_atyps mapT) in t end type configT = { dynamic : bool, rdups : bool } fun names_of { dynamic, rdups } ctxt : term -> Facts.ref list = let val tab = all_facts_of dynamic ctxt |> map (swap #>> Thm.prop_of #>> norm_term) |> Termtab.make_list in norm_term #> Termtab.lookup_list tab #> rdups? nicest_name_of ctxt end fun names_of_thm cfg ctxt = names_of cfg ctxt o Thm.prop_of fun pretty_ref ctxt thmref = let val (name, sel) = (case thmref of Facts.Named ((name, _), sel) => (name, sel) | Facts.Fact _ => raise Fail "Illegal literal fact"); in Pretty.block [Pretty.marks_str (#1 (Proof_Context.markup_extern_fact ctxt name), name), Pretty.str (Facts.string_of_selection sel)] end; fun pretty_refs ctxt refs = map (pretty_ref ctxt) refs |> Pretty.fbreaks |> Pretty.block fun analyze_dup_names ctxt pat = let val match = match_string pat o Facts.name_of_ref fun sort xs = filter match xs @ filter_out match xs val res = all_facts_of false ctxt |> map (swap #>> Thm.prop_of #>> norm_term) |> Termtab.make_list |> Termtab.dest |> filter (fn (_,xs) => length xs > 1) |> filter (exists match o snd) |> map (apsnd sort) in res end fun pretty_dup_name ctxt (t,names) = Pretty.block [ Pretty.cartouche (Syntax.pretty_term ctxt t), Pretty.str ":", Pretty.brk 1, map (pretty_ref ctxt) names |> Pretty.breaks |> Pretty.block ] fun pretty_dup_names ctxt dups = Pretty.fbreaks (map (pretty_dup_name ctxt) dups) |> Pretty.block val _ = Outer_Syntax.command \<^command_keyword>\print_names_of_thm\ "print theorem names under which given statement is available" (Args.mode "dynamic" -- Parse.prop >> (fn (dynamic,t) => Toplevel.keep (fn st => let val ctxt = Toplevel.context_of st val t = Syntax.read_prop ctxt t val t = singleton (Variable.export_terms (Variable.auto_fixes t ctxt) ctxt) t val names = names_of {dynamic=dynamic, rdups=false} ctxt t val pretty_t = Pretty.cartouche (Syntax.pretty_term ctxt t) val res = case names of [] => Pretty.block [Pretty.str "No named theorem for statement ",pretty_t] | _ => Pretty.block [Pretty.str "Names of",Pretty.brk 1,pretty_t,Pretty.str ":", Pretty.fbrk, pretty_refs ctxt names] in Pretty.string_of res |> writeln end))); val _ = Outer_Syntax.command \<^command_keyword>\print_dup_thms\ "print duplicate theorems" (Scan.option Parse.name >> (fn pat => Toplevel.keep (fn st => let val ctxt = Toplevel.context_of st val pat = the_default (Context.theory_name (Proof_Context.theory_of ctxt) ^ ".*") pat val dups = analyze_dup_names ctxt pat val pretty_pat = Pretty.cartouche (Pretty.str pat) val res = case dups of [] => Pretty.block [Pretty.str "No duplicate theorems matching",Pretty.brk 1,pretty_pat] | _ => Pretty.block [Pretty.str "Duplicate theorems matching ",Pretty.brk 1,pretty_pat,Pretty.str ":", Pretty.fbrk, pretty_dup_names ctxt dups] in Pretty.string_of res |> writeln end))); end \ end