]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_kernel/nCicEnvironment.ml
freescale porting, work in progress
[helm.git] / helm / software / components / ng_kernel / nCicEnvironment.ml
1 (*
2     ||M||  This file is part of HELM, an Hypertextual, Electronic        
3     ||A||  Library of Mathematics, developed at the Computer Science     
4     ||T||  Department, University of Bologna, Italy.                     
5     ||I||                                                                
6     ||T||  HELM is free software; you can redistribute it and/or         
7     ||A||  modify it under the terms of the GNU General Public License   
8     \   /  version 2 or (at your option) any later version.      
9      \ /   This software is distributed as is, NO WARRANTY.     
10       V_______________________________________________________________ *)
11
12 (* $Id$ *)
13
14 module C = NCic
15 module Ref = NReference
16
17 exception CircularDependency of string Lazy.t;;
18 exception ObjectNotFound of string Lazy.t;;
19 exception BadDependency of string Lazy.t * exn;;
20 exception BadConstraint of string Lazy.t;;
21 exception AlreadyDefined of string Lazy.t;;
22
23 let cache = NUri.UriHash.create 313;;
24 let history = ref [];;
25 let frozen_list = ref [];;
26
27 let get_obj = ref (fun _ -> assert false);;
28 let set_get_obj f = get_obj := f;;
29
30 let type0 = []
31
32 module F = Format 
33
34 let rec ppsort f = function
35   | C.Prop -> F.fprintf f "Prop"
36   | (C.Type []) -> F.fprintf f "Type0"
37   | (C.Type [`Type, u]) -> F.fprintf f "%s" (NUri.name_of_uri u)
38   | (C.Type [`Succ, u]) -> F.fprintf f "S(%s)" (NUri.name_of_uri u)
39   | (C.Type [`CProp, u]) -> F.fprintf f "P(%s)" (NUri.name_of_uri u)
40   | (C.Type l) -> 
41       F.fprintf f "Max(";
42       ppsort f ((C.Type [List.hd l]));
43       List.iter (fun x -> F.fprintf f ",";ppsort f ((C.Type [x]))) (List.tl l);
44       F.fprintf f ")"
45 ;;
46
47 let string_of_univ u =
48   let b = Buffer.create 100 in
49   let f = Format.formatter_of_buffer b in
50   ppsort f (NCic.Type u);
51   Format.fprintf f "@?";
52   Buffer.contents b
53 ;;
54
55 let eq_univ (b1,u1) (b2,u2) = b1=b2 && NUri.eq u1 u2;;
56
57 let max (l1:NCic.universe) (l2:NCic.universe) =
58  match l2 with
59  | x::tl -> 
60     let rest = List.filter (fun y -> not (eq_univ x y)) (l1@tl) in
61     x :: HExtlib.list_uniq ~eq:eq_univ
62       (List.sort (fun (b1,u1) (b2,u2) ->
63          let res = compare b1 b2 in 
64          if res = 0 then NUri.compare u1 u2 else res)
65       rest)
66  | [] -> 
67      match l1 with
68      | [] -> []
69      | ((`Type|`Succ), _)::_ -> l1
70      | (`CProp, u)::tl -> (`Type, u)::tl
71 ;;
72
73 let lt_constraints = ref [] (* a,b := a < b *)
74
75 let rec lt_path_uri avoid a b = 
76  List.exists
77   (fun (x,y) ->
78       NUri.eq y b && 
79      (NUri.eq a x ||
80         (not (List.exists (NUri.eq x) avoid) &&
81         lt_path_uri (x::avoid) a x))
82   ) !lt_constraints
83 ;;
84
85 let lt_path a b = lt_path_uri [b] a b;;
86
87 let universe_eq a b = 
88   match a,b with 
89   | [(`Type|`CProp) as b1, u1], [(`Type|`CProp) as b2, u2] -> 
90          b1 = b2 && NUri.eq u1 u2
91   | _, [(`Type|`CProp),_]
92   | [(`Type|`CProp),_],_ -> false
93   | _ ->
94      raise (BadConstraint
95       (lazy "trying to check if two inferred universes are equal"))
96 ;;
97
98 let universe_leq a b = 
99   match a, b with
100   | (((`Type|`Succ),_)::_ | []) , [`CProp,_] -> false
101   | l, [((`Type|`CProp),b)] -> 
102        List.for_all 
103          (function 
104          | `Succ,a -> lt_path a b 
105          | _, a -> NUri.eq a b || lt_path a b) l
106   | _, ([] | [`Succ,_] | _::_::_) -> 
107      raise (BadConstraint (lazy (
108        "trying to check if "^string_of_univ a^
109        " is leq than the inferred universe " ^ string_of_univ b)))
110 ;;
111
112 let are_sorts_convertible ~test_eq_only s1 s2 =
113    match s1,s2 with
114    | C.Type a, C.Type b when not test_eq_only -> universe_leq a b
115    | C.Type a, C.Type b -> universe_eq a b
116    | C.Prop,C.Type _ -> (not test_eq_only)
117    | C.Prop, C.Prop -> true
118    | _ -> false
119 ;;
120
121 let pp_constraint x y =  
122   NUri.name_of_uri x ^ " < " ^ NUri.name_of_uri y
123 ;;
124
125 let pp_constraints () =
126   String.concat "\n" (List.map (fun (x,y) -> pp_constraint x y) !lt_constraints)
127 ;;
128
129 let universes = ref [];;
130
131 let get_universes () = 
132   List.map (fun x -> [`Type,x]) !universes @
133   List.map (fun x -> [`CProp,x]) !universes
134 ;;
135
136 let is_declared u =
137  match u with
138  | [(`CProp|`Type),x] -> List.exists (fun y -> NUri.eq x y) !universes
139  | _ -> assert false
140 ;;
141
142 exception UntypableSort of string Lazy.t
143 exception AssertFailure of string Lazy.t
144
145 let typeof_sort = function
146   | C.Type ([(`Type|`CProp),u] as univ) ->
147      if is_declared univ then (C.Type [`Succ, u])
148      else 
149        raise (UntypableSort (lazy ("undeclared universe " ^
150          NUri.string_of_uri u ^ "\ndeclared ones are: " ^ 
151          String.concat ", " (List.map NUri.string_of_uri !universes)
152      )))
153   | C.Type t -> 
154       raise (AssertFailure (lazy (
155               "Cannot type an inferred type: "^ string_of_univ t)))
156   | C.Prop -> (C.Type type0)
157 ;;
158
159 let add_lt_constraint a b = 
160   match a,b with
161   | [`Type,a2],[`Type,b2] -> 
162       if not (lt_path_uri [] a2 b2) then (
163         if lt_path_uri [] b2 a2 || NUri.eq a2 b2 then
164          (raise(BadConstraint(lazy("universe inconsistency adding "^
165                     pp_constraint a2 b2
166            ^ " to:\n" ^ pp_constraints ()))));
167         universes := a2 :: b2 :: 
168           List.filter (fun x -> not (NUri.eq x a2 || NUri.eq x b2)) !universes;
169         lt_constraints := (a2,b2) :: !lt_constraints);
170       history := (`Constr (a,b))::!history;
171   | _ -> raise (BadConstraint
172           (lazy "trying to add a constraint on an inferred universe"))
173 ;;
174
175 let sup l =
176   match l with
177   | [(`Type|`CProp),_] -> Some l
178   | l ->
179    let bigger_than acc (_s1,n1) = 
180      List.filter (fun x -> lt_path_uri [] n1 x || NUri.eq n1 x) acc 
181    in
182    let solutions = List.fold_left bigger_than !universes l in
183    let fam = match l with (`CProp,_)::_ -> `CProp | _ -> `Type in
184    let rec aux = function
185      | [] -> None
186      | u :: tl ->
187          if List.exists (fun x -> lt_path_uri [] x u) solutions then aux tl
188          else Some [fam,u]
189    in
190     aux solutions
191 ;;
192
193 let allowed_sort_elimination s1 s2 =
194   match s1, s2 with
195   | C.Type (((`Type|`Succ),_)::_ | []), C.Type (((`Type|`Succ),_)::_ | []) 
196   | C.Type _, C.Type ((`CProp,_)::_) 
197   | C.Type _, C.Prop
198   | C.Prop, C.Prop -> `Yes
199
200   | C.Type ((`CProp,_)::_), C.Type (((`Type|`Succ),_)::_ | [])
201   | C.Prop, C.Type _ -> `UnitOnly
202 ;;
203
204 let typecheck_obj,already_set = ref (fun _ -> assert false), ref false;;
205 let set_typecheck_obj f =
206  if !already_set then
207   assert false
208  else
209   begin
210    typecheck_obj := f;
211    already_set := true
212   end
213 ;;
214
215 let invalidate_item item =
216  let item_eq a b = 
217    match a, b with
218    | `Obj (u1,_), `Obj (u2,_) -> NUri.eq u1 u2
219    | `Constr _, `Constr _ -> a=b (* MAKE EFFICIENT *)
220    | _ -> false
221  in
222  let rec aux to_be_deleted =
223   function
224      [] -> assert false
225    | item'::tl when item_eq item item' -> item'::to_be_deleted,tl
226    | item'::tl -> aux (item'::to_be_deleted) tl
227  in
228   let to_be_deleted,h = aux [] !history in
229    history := h;
230    List.iter 
231      (function 
232      | `Obj (uri,_) -> NUri.UriHash.remove cache uri
233      | `Constr ([_,u1],[_,u2]) as c -> 
234           let w = u1,u2 in
235           if not(List.mem c !history) then 
236            lt_constraints := List.filter ((<>) w) !lt_constraints;
237      | `Constr _ -> assert false
238      ) to_be_deleted
239 ;;
240
241 exception Propagate of NUri.uri * exn;;
242
243 let to_exn f x =
244  match f x with
245     `WellTyped o -> o
246   | `Exn e -> raise e
247 ;;
248
249 let check_and_add_obj ((u,_,_,_,_) as obj) =
250  let saved_frozen_list = !frozen_list in
251  try
252    frozen_list := (u,obj)::saved_frozen_list;
253    !typecheck_obj obj;
254    frozen_list := saved_frozen_list;
255    let obj' = `WellTyped obj in
256    NUri.UriHash.add cache u obj';
257    history := (`Obj (u,obj))::!history;
258    obj'
259  with
260     Sys.Break as e ->
261      frozen_list := saved_frozen_list;
262      raise e
263   | Propagate (u',old_exn) as e' ->
264      frozen_list := saved_frozen_list;
265      let exn = `Exn (BadDependency (lazy (NUri.string_of_uri u ^
266        " depends (recursively) on " ^ NUri.string_of_uri u' ^
267        " which is not well-typed"), 
268        match old_exn with BadDependency (_,e) -> e | _ -> old_exn)) in
269      NUri.UriHash.add cache u exn;
270      history := (`Obj (u,obj))::!history;
271      if saved_frozen_list = [] then
272       exn
273      else
274       raise e'
275   | e ->
276      frozen_list := saved_frozen_list;
277      let exn = `Exn e in
278      NUri.UriHash.add cache u exn;
279      history := (`Obj (u,obj))::!history;
280      if saved_frozen_list = [] then
281       exn
282      else
283       raise (Propagate (u,e))
284 ;;
285
286 let get_checked_obj u =
287  if List.exists (fun (k,_) -> NUri.eq u k) !frozen_list
288  then
289   raise (CircularDependency (lazy (NUri.string_of_uri u)))
290  else
291   try NUri.UriHash.find cache u
292   with Not_found -> check_and_add_obj (!get_obj u)
293 ;;
294
295 let get_checked_obj u = to_exn get_checked_obj u;;
296
297 let check_and_add_obj ((u,_,_,_,_) as obj) =
298  if NUri.UriHash.mem cache u then
299   raise (AlreadyDefined (lazy (NUri.string_of_uri u)))
300  else
301   ignore (to_exn check_and_add_obj obj)
302 ;;
303
304 let get_checked_decl = function
305   | Ref.Ref (uri, Ref.Decl) ->
306       (match get_checked_obj uri with
307       | _,height,_,_, C.Constant (rlv,name,None,ty,att) ->
308           rlv,name,ty,att,height
309       | _,_,_,_, C.Constant (_,_,Some _,_,_) ->
310           prerr_endline "get_checked_decl on a definition"; assert false
311       | _ -> prerr_endline "get_checked_decl on a non decl 2"; assert false)
312   | _ -> prerr_endline "get_checked_decl on a non decl"; assert false
313 ;;
314
315 let get_checked_def = function
316   | Ref.Ref (uri, Ref.Def _) ->
317       (match get_checked_obj uri with
318       | _,height,_,_, C.Constant (rlv,name,Some bo,ty,att) ->
319           rlv,name,bo,ty,att,height
320       | _,_,_,_, C.Constant (_,_,None,_,_) ->
321           prerr_endline "get_checked_def on an axiom"; assert false
322       | _ -> prerr_endline "get_checked_def on a non def 2"; assert false)
323   | _ -> prerr_endline "get_checked_def on a non def"; assert false
324 ;;
325
326 let get_checked_indtys = function
327   | Ref.Ref (uri, (Ref.Ind (_,n,_)|Ref.Con (n,_,_))) ->
328       (match get_checked_obj uri with
329       | _,_,_,_, C.Inductive (inductive,leftno,tys,att) ->
330         inductive,leftno,tys,att,n
331       | _ -> prerr_endline "get_checked_indtys on a non ind 2"; assert false)
332   | _ -> prerr_endline "get_checked_indtys on a non ind"; assert false
333 ;;
334
335 let get_checked_fixes_or_cofixes = function
336   | Ref.Ref (uri, (Ref.Fix _|Ref.CoFix _))->
337       (match get_checked_obj uri with
338       | _,height,_,_, C.Fixpoint (_,funcs,att) ->
339          funcs, att, height
340       | _ ->prerr_endline "get_checked_(co)fix on a non (co)fix 2";assert false)
341   | _ -> prerr_endline "get_checked_(co)fix on a non (co)fix"; assert false
342 ;;
343
344 let get_relevance (Ref.Ref (_, infos) as r) =
345   match infos with
346      Ref.Def _ -> let res,_,_,_,_,_ = get_checked_def r in res
347    | Ref.Decl -> let res,_,_,_,_ = get_checked_decl r in res
348    | Ref.Ind _ ->
349        let _,_,tl,_,n = get_checked_indtys r in
350        let res,_,_,_ = List.nth tl n in
351          res
352     | Ref.Con (_,i,_) ->
353        let _,_,tl,_,n = get_checked_indtys r in
354        let _,_,_,cl = List.nth tl n in
355        let res,_,_ = List.nth cl (i - 1) in
356          res
357     | Ref.Fix (fixno,_,_)
358     | Ref.CoFix fixno ->
359         let fl,_,_ = get_checked_fixes_or_cofixes r in
360         let res,_,_,_,_ = List.nth fl fixno in
361           res
362 ;;
363
364
365 let invalidate _ = 
366   assert (!frozen_list = []);
367   NUri.UriHash.clear cache
368 ;;