(* ||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$ *) module C = NCic module Ref = NReference exception CircularDependency of string Lazy.t;; exception ObjectNotFound of string Lazy.t;; exception BadDependency of string Lazy.t * exn;; exception BadConstraint of string Lazy.t;; exception AlreadyDefined of string Lazy.t;; let cache = NUri.UriHash.create 313;; let history = ref [];; let frozen_list = ref [];; let get_obj = ref (fun _ -> assert false);; let set_get_obj f = get_obj := f;; let type0 = [] let max l1 l2 = HExtlib.list_uniq ~eq:(fun (b1,u1) (b2,u2) -> b1=b2 && NUri.eq u1 u2) (List.sort (fun (b1,u1) (b2,u2) -> let res = compare b1 b2 in if res = 0 then NUri.compare u1 u2 else res) (l1 @ l2)) let le_constraints = ref [] (* strict,a,b *) let rec le_path_uri avoid strict a b = (not strict && NUri.eq a b) || List.exists (fun (strict',x,y) -> NUri.eq y b && not (List.exists (NUri.eq x) avoid) && le_path_uri (x::avoid) (strict && not strict') a x ) !le_constraints ;; let leq_path a b = le_path_uri [b] (fst a) (snd a) b;; let universe_leq a b = match a, b with | a,[(false,b)] -> List.for_all (fun a -> leq_path a b) a | _,_ -> raise (BadConstraint (lazy "trying to check if a universe is less or equal than an inferred universe")) let universe_eq a b = match a,b with | [(false,_)], [(false,_)] -> universe_leq b a && universe_leq a b | _, [(false,_)] | [(false,_)],_ -> false | _ -> raise (BadConstraint (lazy "trying to check if two inferred universes are equal")) ;; let pp_constraint b x y = NUri.name_of_uri x ^ (if b then " < " else " <= ") ^ NUri.name_of_uri y ;; let pp_constraints () = String.concat "\n" (List.map (fun (b,x,y) -> pp_constraint b x y) !le_constraints) ;; let universes = ref [];; let get_universes () = List.map (fun x -> [false,x]) !universes;; let is_declared u = match u with [false,x] -> List.exists (fun y -> NUri.eq x y) !universes | _ -> assert false ;; let add_constraint strict a b = match a,b with | [false,a2],[false,b2] -> if not (le_path_uri [] strict a2 b2) then ( if le_path_uri [] (not strict) b2 a2 then (raise(BadConstraint(lazy("universe inconsistency adding "^pp_constraint strict a2 b2 ^ " to:\n" ^ pp_constraints ())))); universes := a2 :: b2 :: List.filter (fun x -> not (NUri.eq x a2 || NUri.eq x b2)) !universes; le_constraints := (strict,a2,b2) :: !le_constraints); history := (`Constr (strict,a,b))::!history; | _ -> raise (BadConstraint (lazy "trying to add a constraint on an inferred universe")) ;; let sup l = match l with | [false,_] -> Some l | l -> let bigger_than acc (s1,n1) = List.filter (le_path_uri [] s1 n1) acc in let solutions = List.fold_left bigger_than !universes l in let rec aux = function | [] -> None | u :: tl -> if List.exists (fun x -> le_path_uri [] true x u) solutions then aux tl else Some [false,u] in aux solutions ;; let typecheck_obj,already_set = ref (fun _ -> assert false), ref false;; let set_typecheck_obj f = if !already_set then assert false else begin typecheck_obj := f; already_set := true end ;; let invalidate_item item = let item_eq a b = match a, b with | `Obj (u1,_), `Obj (u2,_) -> NUri.eq u1 u2 | `Constr _, `Constr _ -> a=b (* MAKE EFFICIENT *) | _ -> false in let rec aux to_be_deleted = function [] -> assert false | item'::tl when item_eq item item' -> item'::to_be_deleted,tl | item'::tl -> aux (item'::to_be_deleted) tl in let to_be_deleted,h = aux [] !history in history := h; List.iter (function | `Obj (uri,_) -> NUri.UriHash.remove cache uri | `Constr (strict,[_,u1],[_,u2]) as c -> let w = strict,u1,u2 in if not(List.mem c !history) then le_constraints := List.filter ((<>) w) !le_constraints; | `Constr _ -> assert false ) to_be_deleted ;; exception Propagate of NUri.uri * exn;; let to_exn f x = match f x with `WellTyped o -> o | `Exn e -> raise e ;; let check_and_add_obj ((u,_,_,_,_) as obj) = let saved_frozen_list = !frozen_list in try frozen_list := (u,obj)::saved_frozen_list; !typecheck_obj obj; frozen_list := saved_frozen_list; let obj' = `WellTyped obj in NUri.UriHash.add cache u obj'; history := (`Obj (u,obj))::!history; obj' with Sys.Break as e -> frozen_list := saved_frozen_list; raise e | Propagate (u',old_exn) as e' -> frozen_list := saved_frozen_list; let exn = `Exn (BadDependency (lazy (NUri.string_of_uri u ^ " depends (recursively) on " ^ NUri.string_of_uri u' ^ " which is not well-typed"), match old_exn with BadDependency (_,e) -> e | _ -> old_exn)) in NUri.UriHash.add cache u exn; history := (`Obj (u,obj))::!history; if saved_frozen_list = [] then exn else raise e' | e -> frozen_list := saved_frozen_list; let exn = `Exn e in NUri.UriHash.add cache u exn; history := (`Obj (u,obj))::!history; if saved_frozen_list = [] then exn else raise (Propagate (u,e)) ;; let get_checked_obj u = if List.exists (fun (k,_) -> NUri.eq u k) !frozen_list then raise (CircularDependency (lazy (NUri.string_of_uri u))) else try NUri.UriHash.find cache u with Not_found -> check_and_add_obj (!get_obj u) ;; let get_checked_obj u = to_exn get_checked_obj u;; let check_and_add_obj ((u,_,_,_,_) as obj) = if NUri.UriHash.mem cache u then raise (AlreadyDefined (lazy (NUri.string_of_uri u))) else ignore (to_exn check_and_add_obj obj) ;; let get_checked_decl = function | Ref.Ref (uri, Ref.Decl) -> (match get_checked_obj uri with | _,height,_,_, C.Constant (rlv,name,None,ty,att) -> rlv,name,ty,att,height | _,_,_,_, C.Constant (_,_,Some _,_,_) -> prerr_endline "get_checked_decl on a definition"; assert false | _ -> prerr_endline "get_checked_decl on a non decl 2"; assert false) | _ -> prerr_endline "get_checked_decl on a non decl"; assert false ;; let get_checked_def = function | Ref.Ref (uri, Ref.Def _) -> (match get_checked_obj uri with | _,height,_,_, C.Constant (rlv,name,Some bo,ty,att) -> rlv,name,bo,ty,att,height | _,_,_,_, C.Constant (_,_,None,_,_) -> prerr_endline "get_checked_def on an axiom"; assert false | _ -> prerr_endline "get_checked_def on a non def 2"; assert false) | _ -> prerr_endline "get_checked_def on a non def"; assert false ;; let get_checked_indtys = function | Ref.Ref (uri, (Ref.Ind (_,n,_)|Ref.Con (n,_,_))) -> (match get_checked_obj uri with | _,_,_,_, C.Inductive (inductive,leftno,tys,att) -> inductive,leftno,tys,att,n | _ -> prerr_endline "get_checked_indtys on a non ind 2"; assert false) | _ -> prerr_endline "get_checked_indtys on a non ind"; assert false ;; let get_checked_fixes_or_cofixes = function | Ref.Ref (uri, (Ref.Fix _|Ref.CoFix _))-> (match get_checked_obj uri with | _,height,_,_, C.Fixpoint (_,funcs,att) -> funcs, att, height | _ ->prerr_endline "get_checked_(co)fix on a non (co)fix 2";assert false) | _ -> prerr_endline "get_checked_(co)fix on a non (co)fix"; assert false ;; let get_relevance (Ref.Ref (_, infos) as r) = match infos with Ref.Def _ -> let res,_,_,_,_,_ = get_checked_def r in res | Ref.Decl -> let res,_,_,_,_ = get_checked_decl r in res | Ref.Ind _ -> let _,_,tl,_,n = get_checked_indtys r in let res,_,_,_ = List.nth tl n in res | Ref.Con (_,i,_) -> let _,_,tl,_,n = get_checked_indtys r in let _,_,_,cl = List.nth tl n in let res,_,_ = List.nth cl (i - 1) in res | Ref.Fix (fixno,_,_) | Ref.CoFix fixno -> let fl,_,_ = get_checked_fixes_or_cofixes r in let res,_,_,_,_ = List.nth fl fixno in res ;; let invalidate _ = assert (!frozen_list = []); NUri.UriHash.clear cache ;;