(* * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) * * SPDX-License-Identifier: BSD-2-Clause *) structure CrunchTheoryData = Theory_Data (struct type T = ((Token.src list -> string -> string -> (string * ((Facts.ref * Token.src list), xstring) sum) list -> string list -> local_theory -> local_theory) * (string list -> string list -> local_theory -> local_theory)) Symtab.table val empty = Symtab.empty val merge = Symtab.merge (fn _ => true); end); fun get_crunch_instance name lthy = CrunchTheoryData.get lthy |> (fn tab => Symtab.lookup tab name) fun add_crunch_instance name instance lthy = CrunchTheoryData.map (Symtab.update_new (name, instance)) lthy structure CallCrunch = struct local structure P = Parse and K = Keyword in (* Read a list of names, up to the next section identifier *) fun read_thm_list section sections = let val match_section_name = Scan.first (map (P.reserved o #1) sections) in Scan.repeat (Scan.unless match_section_name (#2 section)) end fun read_section all_sections section = (P.reserved (#1 section) -- P.$$$ ":") |-- read_thm_list section all_sections >> map (fn n => (#1 section, n)) fun read_sections sections = Scan.repeat (Scan.first (map (read_section sections) sections)) >> List.concat val crunch_parser = (((Scan.optional (P.$$$ "(" |-- P.name --| P.$$$ ")") "" -- P.name -- Parse.opt_attribs --| P.$$$ ":") -- P.list1 P.const -- Scan.optional P.term "" -- Scan.optional (P.$$$ "(" |-- read_sections [wp_sect,wp_del_sect,wps_sect,ignore_sect,simp_sect, simp_del_sect,rule_sect,rule_del_sect,ignore_del_sect] --| P.$$$ ")") [] ) >> (fn (((((crunch_instance, prp_name), att_srcs), consts), extra), wpigs) => (fn lthy => (case get_crunch_instance crunch_instance (Proof_Context.theory_of lthy) of NONE => error ("Crunch has not been defined for " ^ crunch_instance) | SOME (crunch_x, _) => crunch_x att_srcs extra prp_name wpigs consts lthy)))); val crunches_parser = (((P.list1 P.const --| P.$$$ "for") -- P.and_list1 ((Scan.optional (P.$$$ "(" |-- P.name --| P.$$$ ")") "" -- P.name -- Parse.opt_attribs) -- Scan.optional (P.$$$ ":" |-- P.term) "") -- Scan.optional (P.$$$ "(" |-- read_sections [wp_sect,wp_del_sect,wps_sect,ignore_sect,simp_sect, simp_del_sect,rule_sect,rule_del_sect,ignore_del_sect] --| P.$$$ ")") [] ) >> (fn ((consts, confs), wpigs) => fold (fn (((crunch_instance, prp_name), att_srcs), extra) => fn lthy => (case get_crunch_instance crunch_instance (Proof_Context.theory_of lthy) of NONE => error ("Crunch has not been defined for " ^ crunch_instance) | SOME (crunch_x, _) => crunch_x att_srcs extra prp_name wpigs consts lthy)) confs)); (* example: crunch(kind) inv[wp]: f,g P (wp: h_P simp: .. ignore: ..) or: crunches f,g for (kind)inv: P and (kind2)inv2: Q (wp: etc) where: crunch = command keyword kind = instance of crunch, e.g. valid, no_fail inv = lemma name pattern [wp] = optional list of attributes for all proved thms f,g = constants under investigation P,Q = property to be shown (not required for no_fail/empty_fail instance) h_P = wp lemma to use (h will not be unfolded) simp: .. = simp lemmas to use ignore: .. = constants to ignore for unfolding will prove lemmas for f and for any constituents required. for the default crunch instance "valid", lemmas of the form "{P and X} f {%_. P}" will be proven. the additional preconditions X are propagated upwards from similar preconditions in preexisting lemmas. There is a longer description of what each crunch does in crunch-cmd.ML *) val crunchP = Outer_Syntax.local_theory @{command_keyword "crunch"} "crunch through monadic definitions with a given property" crunch_parser val crunchesP = Outer_Syntax.local_theory @{command_keyword "crunches"} "crunch through monadic definitions with multiple properties" crunches_parser val add_sect = ("add", Parse.const >> Constant); val del_sect = ("del", Parse.const >> Constant); val crunch_ignoreP = Outer_Syntax.local_theory @{command_keyword "crunch_ignore"} "add to and delete from list of things that crunch should ignore in finding prerequisites" ((Scan.optional (P.$$$ "(" |-- P.list1 P.name --| P.$$$ ")") [""] -- Scan.optional (P.$$$ "(" |-- read_sections [add_sect, del_sect] --| P.$$$ ")") []) >> (fn (crunch_instances, wpigs) => fn lthy => let fun const_name const = dest_Const (read_const lthy const) |> #1; val add = wpigs |> filter (fn (s,_) => s = #1 add_sect) |> map #2 |> constants |> map const_name; val del = wpigs |> filter (fn (s,_) => s = #1 del_sect) |> map #2 |> constants |> map const_name; fun crunch_ignore_add_del inst = (case get_crunch_instance inst (Proof_Context.theory_of lthy) of NONE => error ("Crunch has not been defined for " ^ inst) | SOME x => snd x); val crunch_ignore_add_dels = map (fn inst => crunch_ignore_add_del inst add del) crunch_instances in fold (curry (op #>)) crunch_ignore_add_dels I lthy end)); end; fun setup thy = thy end;