(* ||M|| This file is part of HELM, an Hypertextual, Electronic ||A|| Library of Mathematics, developed at the Computer Science ||T|| Department, University of Bologna, Italy. ||I|| ||T|| HELM is free software; you can redistribute it and/or ||A|| modify it under the terms of the GNU General Public License \ / version 2 or (at your option) any later version. \ / This software is distributed as is, NO WARRANTY. V_______________________________________________________________ *) (* $Id$ *) exception LibraryOutOfSync of string Lazy.t type timestamp = (NUri.uri * NCic.obj) list * (NUri.uri * string * NReference.reference) list * NCic.obj NUri.UriMap.t;; let time0 = [],[],NUri.UriMap.empty;; let storage = ref [];; let local_aliases = ref [];; let global_aliases = ref [];; let cache = ref NUri.UriMap.empty;; class status = object val timestamp = (time0 : timestamp) method timestamp = timestamp method set_timestamp v = {< timestamp = v >} method set_library_status : 'status. < timestamp : timestamp; .. > as 'status -> 'self = fun o -> {< timestamp = o#timestamp >} end let time_travel status = let sto,ali,cac = status#timestamp in storage := sto; local_aliases := ali; cache := cac ;; let path_of_baseuri ?(no_suffix=false) baseuri = let uri = NUri.string_of_uri baseuri in let path = String.sub uri 4 (String.length uri - 4) in let path = Helm_registry.get "matita.basedir" ^ path in let dirname = Filename.dirname path in HExtlib.mkdir dirname; if no_suffix then path else path ^ ".ng" ;; let magic = 0;; let require_path path = let ch = open_in path in let mmagic,dump = Marshal.from_channel ch in close_in ch; if mmagic <> magic then raise (LibraryOutOfSync (lazy "The library is out of sync with the implementation. Please recompile the library.")) else dump ;; let require0 ~baseuri = require_path (path_of_baseuri baseuri);; let db_path () = Helm_registry.get "matita.basedir" ^ "/ng_db.ng";; let init () = try global_aliases := require_path (db_path ()) with Sys_error _ -> () ;; let serialize ~baseuri dump = let ch = open_out (path_of_baseuri baseuri) in Marshal.to_channel ch (magic,dump) []; close_out ch; List.iter (fun (uri,obj) -> let ch = open_out (path_of_baseuri uri) in Marshal.to_channel ch (magic,obj) []; close_out ch ) !storage; global_aliases := !local_aliases @ !global_aliases; let ch = open_out (db_path ()) in Marshal.to_channel ch (magic,!global_aliases) []; close_out ch; time_travel (new status) ;; let refresh_uri uri = NUri.uri_of_string (NUri.string_of_uri uri);; let rec refresh_uri_in_term = function NCic.Const (NReference.Ref (u,spec)) -> NCic.Const (NReference.reference_of_spec (refresh_uri u) spec) | t -> NCicUtils.map (fun _ _ -> ()) () (fun _ -> refresh_uri_in_term) t ;; let refresh_uri_in_obj (uri,height,metasenv,subst,obj_kind) = assert (metasenv = []); assert (subst = []); uri,height,metasenv,subst, NCicUntrusted.map_obj_kind refresh_uri_in_term obj_kind ;; module type Serializer = sig type status type obj val register: string -> ('a -> refresh_uri_in_term:(NCic.term -> NCic.term) -> status -> status) -> ('a -> obj) val serialize: baseuri:NUri.uri -> obj list -> unit val require: baseuri:NUri.uri -> status -> status end module Serializer(S: sig type status end) = struct type status = S.status type obj = string * Obj.t let require1 = ref (fun _ -> assert false (* unknown data*)) let already_registered = ref [] let register tag require = assert (not (List.mem tag !already_registered)); already_registered := tag :: !already_registered; require1 := (fun (tag',data) as x -> if tag=tag' then require (Obj.magic data) ~refresh_uri_in_term else !require1 x); (fun x -> tag,Obj.repr x) let serialize = serialize let require ~baseuri status = let dump = require0 ~baseuri in List.fold_right !require1 dump status end let decompile ~baseuri = HExtlib.safe_remove (path_of_baseuri baseuri); let basepath = path_of_baseuri ~no_suffix:true baseuri in try let od = Unix.opendir basepath in let rec aux names = try let name = Unix.readdir od in if name <> "." && name <> ".." then aux (name::names) else aux names with End_of_file -> names in let names = List.map (fun name -> basepath ^ "/" ^ name) (aux []) in Unix.closedir od; List.iter Unix.unlink names; HExtlib.rmdir_descend basepath with Unix.Unix_error _ -> () (* raised by Unix.opendir, we hope :-) *) ;; LibraryClean.set_decompile_cb (fun ~baseuri -> decompile ~baseuri:(NUri.uri_of_string baseuri));; let fetch_obj uri = let obj = require0 ~baseuri:uri in refresh_uri_in_obj obj ;; let resolve name = try HExtlib.filter_map (fun (_,name',nref) -> if name'=name then Some nref else None) (!local_aliases @ !global_aliases) with Not_found -> raise (NCicEnvironment.ObjectNotFound (lazy name)) ;; let aliases_of uri = try HExtlib.filter_map (fun (uri',_,nref) -> if NUri.eq uri' uri then Some nref else None) !local_aliases with Not_found -> raise (NCicEnvironment.ObjectNotFound (lazy (NUri.string_of_uri uri))) ;; let add_obj status u obj = storage := (u,obj)::!storage; let _,height,_,_,obj = obj in let references = match obj with NCic.Constant (_,name,None,_,_) -> [u,name,NReference.reference_of_spec u NReference.Decl] | NCic.Constant (_,name,Some _,_,_) -> [u,name,NReference.reference_of_spec u (NReference.Def height)] | NCic.Fixpoint (is_ind,fl,_) -> HExtlib.list_mapi (fun (_,name,recno,_,_) i -> if is_ind then u,name,NReference.reference_of_spec u(NReference.Fix(i,recno,height)) else u,name,NReference.reference_of_spec u (NReference.CoFix i)) fl | NCic.Inductive (inductive,leftno,il,_) -> List.flatten (HExtlib.list_mapi (fun (_,iname,_,cl) i -> HExtlib.list_mapi (fun (_,cname,_) j-> u,cname, NReference.reference_of_spec u (NReference.Con (i,j+1,leftno)) ) cl @ [u,iname, NReference.reference_of_spec u (NReference.Ind (inductive,i,leftno))] ) il) in local_aliases := references @ !local_aliases; status#set_timestamp (!storage,!local_aliases,!cache) ;; let get_obj u = try List.assq u !storage with Not_found -> try fetch_obj u with Sys_error _ -> try NUri.UriMap.find u !cache with Not_found -> let ouri = NCic2OCic.ouri_of_nuri u in try let o,_ = CicEnvironment.get_obj CicUniv.oblivion_ugraph ouri in let l = OCic2NCic.convert_obj ouri o in List.iter (fun (u,_,_,_,_ as o) -> cache:= NUri.UriMap.add u o !cache) l; HExtlib.list_last l with CicEnvironment.Object_not_found u -> raise (NCicEnvironment.ObjectNotFound (lazy (NUri.string_of_uri (OCic2NCic.nuri_of_ouri u)))) ;; let clear_cache () = cache := NUri.UriMap.empty;; NCicEnvironment.set_get_obj get_obj;; NCicPp.set_get_obj get_obj;;