1structure ThmSetData :> ThmSetData = 2struct 3 4open DB Lib HolKernel 5 6val ERR = mk_HOL_ERR "ThmSetData" 7 8type data = LoadableThyData.t 9type thname = KernelSig.kernelname 10val name_toString = KernelSig.name_toString 11datatype setdelta = 12 ADD of thname * thm 13 | REMOVE of string (* could be anything *) 14datatype raw_delta = rADD of thname | rREMOVE of string 15 16val added_thms = List.mapPartial (fn ADD (_, th) => SOME th | _ => NONE) 17 18fun splitnm nm = let 19 val comps = String.fields (equal #".") nm 20in 21 case comps of 22 [thy,nm] => (thy, nm) 23 | _ => raise Fail ("ThmSetData.splitnm applied to " ^ nm) 24end 25 26fun mk_store_name_safe s = 27 case String.fields (equal #".") s of 28 [s0] => {Thy = current_theory(), Name = s} 29 | [s1,s2] => {Thy = s1, Name = s2} 30 | _ => raise mk_HOL_ERR "ThmSetData" "mk_store_name_safe" 31 ("Malformed name: " ^ s) 32 33fun lookup_exn {Thy,Name} = DB.fetch Thy Name 34fun mk_radd s = rADD (mk_store_name_safe s) 35fun mk_add s = 36 let val nm = mk_store_name_safe s in ADD(nm, lookup_exn nm) end 37 38 39fun lookup ty nm = 40 SOME (lookup_exn nm) 41 handle HOL_ERR _ => ( 42 Feedback.HOL_WARNING 43 "ThmSetData" "lookup" 44 ("Bad theorem name: \"" ^ name_toString nm ^ "\" for set-type \"" ^ 45 ty ^ "\""); 46 NONE 47 ) 48 49local 50 open ThyDataSexp 51in 52val pp_sexp = pp_sexp Parse.pp_type Parse.pp_term Parse.pp_thm 53fun sexp2string sexp = PP.pp_to_string (!Globals.linewidth) pp_sexp sexp 54end; 55 56datatype read_result = OK of setdelta | BAD_ADD of thname 57 58fun raw_read1 ty sexp = 59 let 60 open ThyDataSexp 61 in 62 case sexp of 63 KName nm => SOME (rADD nm) 64 | String nm => SOME (rREMOVE nm) 65 | _ => NONE 66 end 67 68fun raw_write1 d = 69 let 70 open ThyDataSexp 71 in 72 case d of 73 rADD knm => KName knm 74 | rREMOVE s => String s 75 end 76 77fun cook (rADD nm) = ADD(nm, lookup_exn nm) 78 | cook (rREMOVE s) = REMOVE s 79 80fun read ty sexp = 81 let 82 open ThyDataSexp 83 fun decode1 sexp = 84 case sexp of 85 KName nm => 86 (OK (ADD (nm,lookup_exn nm)) handle HOL_ERR _ => BAD_ADD nm) 87 | String nm => OK (REMOVE nm) 88 | _ => raise ERR "read" ("Bad sexp for 1 update: "^sexp2string sexp) 89 in 90 case sexp of 91 List deltas => map decode1 deltas 92 | _ => raise ERR "read" ("Bad sexp for type "^ty^": "^sexp2string sexp) 93 end 94 95fun write10 d = 96 case d of 97 ADD(knm,th) => ThyDataSexp.KName knm 98 | REMOVE s => ThyDataSexp.String s 99 100fun write_deltas ds = ThyDataSexp.List (map write10 ds) 101 102fun write1 d = write_deltas [d] 103 104 105 106(* ---------------------------------------------------------------------- 107 destfn: takes polymorphic theory data and turns it into the 108 structured theorem data we want to use 109 storefn: takes a theorem name and stores the associated theorem into 110 the theory data. Doesn't perform any associated update in 111 the run-time memory 112 exportfn: takes a string and a list of names and theorems and does 113 something with them at runtime (adds them to a simpset, 114 say). The string is expected to be the name of the 115 theory with which these theorems are associated. 116 ---------------------------------------------------------------------- *) 117 118type exportfns = 119 { add : {thy : string, named_thm : (thname * thm)} -> unit, 120 remove : {thy : string, remove : string} -> unit} 121 122type tabledata = ({thyname:string}->setdelta list) * exportfns 123 124val data_map = ref (Symtab.empty : tabledata Symtab.table) 125 126fun data_exportfns {settype = s} = Option.map #2 (Symtab.lookup (!data_map) s) 127 128fun all_set_types () = Symtab.keys (!data_map) 129 130fun theory_data {settype = key, thy} = 131 case Symtab.lookup (!data_map) key of 132 NONE => raise mk_HOL_ERR "ThmSetData" "theory_data" 133 ("No ThmSetData with name "^Lib.quote key) 134 | SOME (sdf,_) => sdf {thyname=thy} 135 136fun current_data {settype = s} = 137 theory_data { settype = s, thy = current_theory() } 138 139fun all_data {settype = s} = 140 map (fn thy => (thy, theory_data {settype = s, thy = thy})) 141 (current_theory() :: ancestry "-") 142 143 144fun new_exporter {settype = name, efns = efns as {add, remove}} = let 145 open TheoryDelta 146 val dropBads = 147 List.mapPartial 148 (fn OK sd => SOME sd 149 | BAD_ADD s => ( 150 HOL_WARNING "ThmSetData" "apply_delta" 151 ("Bad add command, with name: "^name_toString s); NONE)) 152 fun apply_deltas thyname ds = 153 let 154 fun appthis (ADD (s,th)) = add {thy = thyname, named_thm = (s, th)} 155 | appthis (REMOVE s) = remove {thy = thyname, remove = s} 156 in 157 List.app appthis ds 158 end 159 fun loadfn {thyname, data = data_opt} = 160 case data_opt of 161 NONE => () 162 | SOME data => apply_deltas thyname (dropBads (read name data)) 163 fun uptodate_thmdelta (ADD (s,th)) = uptodate_thm th 164 | uptodate_thmdelta _ = true 165 fun neqbinding s1 (ADD ({Thy,Name},_)) = 166 s1 <> Name orelse current_theory () <> Thy 167 | neqbinding _ _ = true 168 fun toString (ADD (s,_)) = "ADD<" ^ name_toString s ^ ">" 169 | toString (REMOVE s) = "REMOVE<" ^ s ^ ">" 170 fun read_result_toString (OK sd) = toString sd 171 | read_result_toString (BAD_ADD s) = "ADD<" ^ name_toString s ^ ">" 172 fun check_result P (OK d) = P d 173 | check_result _ (BAD_ADD s) = false 174 fun revise_data P (deltas_sexp,td) = 175 let 176 val deltas = read name deltas_sexp 177 val (ok,notok) = Lib.partition (check_result P) deltas 178 in 179 case notok of 180 [] => NONE 181 | _ => (HOL_WARNING 182 "ThmSetData" "revise_data" 183 ("\n Theorems in set " ^ Lib.quote name ^ 184 ":\n " ^ 185 String.concatWith ", " (map read_result_toString notok) ^ 186 "\n invalidated by " ^ TheoryDelta.toString td); 187 SOME (write_deltas (dropBads ok))) 188 end 189 190 fun hook (DelConstant _) = uptodate_thmdelta 191 | hook (DelTypeOp _) = uptodate_thmdelta 192 | hook (NewConstant _) = uptodate_thmdelta 193 | hook (NewTypeOp _) = uptodate_thmdelta 194 | hook (DelBinding s) = neqbinding s 195 | hook (NewBinding(s,_)) = neqbinding s 196 | hook _ = fn _ => true 197 fun check_thydelta (arg as (sexp,td)) = revise_data (hook td) arg 198 199 200 val {export = export_deltasexp, segment_data, ...} = 201 ThyDataSexp.new {merge = ThyDataSexp.append_merge, load = loadfn, 202 other_tds = check_thydelta, thydataty = name} 203 fun opt2list (SOME x) = x | opt2list NONE = [] 204 fun segdata {thyname} = 205 segment_data {thyname=thyname} 206 |> Option.map (dropBads o read name) 207 |> opt2list 208 fun export p (* name * thm *) = 209 let 210 in 211 add {thy = current_theory(), named_thm = p}; 212 export_deltasexp (write1 (ADD p)) 213 end 214 215 fun onload thy = apply_deltas thy (segdata {thyname = thy}) 216 217 fun export_nameonly s = 218 let val thnm = mk_store_name_safe s 219 in 220 export(thnm, lookup_exn thnm) 221 end 222 fun delete s = let 223 val data = write1 (REMOVE s) 224 in 225 remove {thy = current_theory(), remove = s}; 226 export_deltasexp data 227 end 228 229 fun store_attrfun {attrname,name,thm} = export (mk_store_name_safe name,thm) 230 fun local_attrfun {attrname,name,thm} = 231 add {named_thm = ({Thy = current_theory(), Name = name},thm), 232 thy = current_theory()} 233in 234 data_map := Symtab.update(name,(segdata, efns)) (!data_map); 235 ThmAttribute.register_attribute ( 236 name, {storedf = store_attrfun, localf = local_attrfun} 237 ); 238 List.app onload (ancestry "-"); 239 {export = export_nameonly, delete = delete} 240end 241 242fun lift nm = {Thy = current_theory(), Name = nm} 243 244fun mk_raw (ADD(nm,_)) = rADD nm 245 | mk_raw (REMOVE s) = rREMOVE s 246 247type 'value ops = {apply_to_global : setdelta -> 'value -> 'value, 248 thy_finaliser : ({thyname:string} -> setdelta list -> 249 'value -> 'value) option, 250 uptodate_delta : setdelta -> bool, initial_value : 'value, 251 apply_delta : setdelta -> 'value -> 'value} 252fun raw_uptodate (rADD{Thy,Name}) = can (DB.fetch Thy) Name 253 | raw_uptodate _ = true 254 255fun export_with_ancestry 256 {settype,delta_ops:'value ops}:(setdelta,'value)AncestryData.fullresult = 257 let 258 val {apply_to_global, uptodate_delta, initial_value, apply_delta, 259 thy_finaliser} = 260 delta_ops 261 fun raw_apply_delta d = apply_delta (cook d) 262 fun raw_apply_global d = apply_to_global (cook d) 263 fun mk_raw_finaliser f thy ds = f thy (map cook ds) 264 val raw_finaliser = Option.map mk_raw_finaliser thy_finaliser 265 val adinfo = {tag = settype, initial_values = [("min", initial_value)], 266 apply_delta = raw_apply_delta} 267 val sexps = {dec = raw_read1 settype, enc = raw_write1} 268 val globinfo = {apply_to_global = raw_apply_global, 269 thy_finaliser = raw_finaliser, 270 initial_value = initial_value} 271 fun uptodate rd = raw_uptodate rd andalso uptodate_delta (cook rd) 272 val fullresult = 273 AncestryData.fullmake { adinfo = adinfo, 274 uptodate_delta = uptodate, 275 sexps = sexps, globinfo = globinfo} 276 fun store_attrfun {attrname,name,thm} = 277 let val d = rADD(lift name) 278 in 279 #record_delta fullresult d; 280 #update_global_value fullresult (raw_apply_global d) 281 end 282 fun local_attrfun {attrname,name,thm} = 283 (* as this is local, the name is not going to be a valid binding, 284 and "cooking" a raw ADD delta will just throw an exception *) 285 #update_global_value fullresult(apply_to_global (ADD(lift name, thm))) 286 fun efn_add {thy,named_thm} = 287 #update_global_value fullresult(raw_apply_global(rADD (#1 named_thm))) 288 fun efn_remove {thy,remove} = 289 #update_global_value fullresult (raw_apply_global (rREMOVE remove)) 290 val efns = {add = efn_add, remove = efn_remove} 291 val get_fulldeltas = map cook o #get_deltas fullresult 292 in 293 data_map := Symtab.update(settype, (get_fulldeltas, efns)) (!data_map); 294 ThmAttribute.register_attribute ( 295 settype, {storedf = store_attrfun, localf = local_attrfun} 296 ); 297 {merge = #merge fullresult, DB = #DB fullresult, 298 get_deltas = get_fulldeltas, 299 record_delta = #record_delta fullresult o mk_raw, 300 parents = #parents fullresult, set_parents = #set_parents fullresult, 301 get_global_value = #get_global_value fullresult, 302 update_global_value = #update_global_value fullresult 303 } 304 end 305 306 307end (* struct *) 308