summaryrefslogtreecommitdiff
path: root/pretyping/glob_ops.ml
diff options
context:
space:
mode:
Diffstat (limited to 'pretyping/glob_ops.ml')
-rw-r--r--pretyping/glob_ops.ml434
1 files changed, 434 insertions, 0 deletions
diff --git a/pretyping/glob_ops.ml b/pretyping/glob_ops.ml
new file mode 100644
index 00000000..454d64f0
--- /dev/null
+++ b/pretyping/glob_ops.ml
@@ -0,0 +1,434 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+open Util
+open Names
+open Globnames
+open Misctypes
+open Glob_term
+
+(* Untyped intermediate terms, after ASTs and before constr. *)
+
+let cases_pattern_loc = function
+ PatVar(loc,_) -> loc
+ | PatCstr(loc,_,_,_) -> loc
+
+let cases_predicate_names tml =
+ List.flatten (List.map (function
+ | (tm,(na,None)) -> [na]
+ | (tm,(na,Some (_,_,nal))) -> na::nal) tml)
+
+let mkGApp loc p t =
+ match p with
+ | GApp (loc,f,l) -> GApp (loc,f,l@[t])
+ | _ -> GApp (loc,p,[t])
+
+let map_glob_decl_left_to_right f (na,k,obd,ty) =
+ let comp1 = Option.map f obd in
+ let comp2 = f ty in
+ (na,k,comp1,comp2)
+
+let binding_kind_eq bk1 bk2 = match bk1, bk2 with
+| Decl_kinds.Explicit, Decl_kinds.Explicit -> true
+| Decl_kinds.Implicit, Decl_kinds.Implicit -> true
+| _ -> false
+
+let case_style_eq s1 s2 = match s1, s2 with
+| LetStyle, LetStyle -> true
+| IfStyle, IfStyle -> true
+| LetPatternStyle, LetPatternStyle -> true
+| MatchStyle, MatchStyle -> true
+| RegularStyle, RegularStyle -> true
+| _ -> false
+
+let rec cases_pattern_eq p1 p2 = match p1, p2 with
+| PatVar (_, na1), PatVar (_, na2) -> Name.equal na1 na2
+| PatCstr (_, c1, pl1, na1), PatCstr (_, c2, pl2, na2) ->
+ eq_constructor c1 c2 && List.equal cases_pattern_eq pl1 pl2 &&
+ Name.equal na1 na2
+| _ -> false
+
+let cast_type_eq eq t1 t2 = match t1, t2 with
+| CastConv t1, CastConv t2 -> eq t1 t2
+| CastVM t1, CastVM t2 -> eq t1 t2
+| CastCoerce, CastCoerce -> true
+| CastNative t1, CastNative t2 -> eq t1 t2
+| _ -> false
+
+let rec glob_constr_eq c1 c2 = match c1, c2 with
+| GRef (_, gr1, _), GRef (_, gr2, _) -> eq_gr gr1 gr2
+| GVar (_, id1), GVar (_, id2) -> Id.equal id1 id2
+| GEvar (_, id1, arg1), GEvar (_, id2, arg2) ->
+ Id.equal id1 id2 &&
+ List.equal instance_eq arg1 arg2
+| GPatVar (_, (b1, pat1)), GPatVar (_, (b2, pat2)) ->
+ (b1 : bool) == b2 && Id.equal pat1 pat2
+| GApp (_, f1, arg1), GApp (_, f2, arg2) ->
+ glob_constr_eq f1 f2 && List.equal glob_constr_eq arg1 arg2
+| GLambda (_, na1, bk1, t1, c1), GLambda (_, na2, bk2, t2, c2) ->
+ Name.equal na1 na2 && binding_kind_eq bk1 bk2 &&
+ glob_constr_eq t1 t2 && glob_constr_eq c1 c2
+| GProd (_, na1, bk1, t1, c1), GProd (_, na2, bk2, t2, c2) ->
+ Name.equal na1 na2 && binding_kind_eq bk1 bk2 &&
+ glob_constr_eq t1 t2 && glob_constr_eq c1 c2
+| GLetIn (_, na1, t1, c1), GLetIn (_, na2, t2, c2) ->
+ Name.equal na1 na2 && glob_constr_eq t1 t2 && glob_constr_eq c1 c2
+| GCases (_, st1, c1, tp1, cl1), GCases (_, st2, c2, tp2, cl2) ->
+ case_style_eq st1 st2 && Option.equal glob_constr_eq c1 c2 &&
+ List.equal tomatch_tuple_eq tp1 tp2 &&
+ List.equal cases_clause_eq cl1 cl2
+| GLetTuple (_, na1, (n1, p1), c1, t1), GLetTuple (_, na2, (n2, p2), c2, t2) ->
+ List.equal Name.equal na1 na2 && Name.equal n1 n2 &&
+ Option.equal glob_constr_eq p1 p2 && glob_constr_eq c1 c2 &&
+ glob_constr_eq t1 t2
+| GIf (_, m1, (pat1, p1), c1, t1), GIf (_, m2, (pat2, p2), c2, t2) ->
+ glob_constr_eq m1 m2 && Name.equal pat1 pat2 &&
+ Option.equal glob_constr_eq p1 p2 && glob_constr_eq c1 c2 &&
+ glob_constr_eq t1 t2
+| GRec (_, kn1, id1, decl1, c1, t1), GRec (_, kn2, id2, decl2, c2, t2) ->
+ fix_kind_eq kn1 kn2 && Array.equal Id.equal id1 id2 &&
+ Array.equal (fun l1 l2 -> List.equal glob_decl_eq l1 l2) decl1 decl2 &&
+ Array.equal glob_constr_eq c1 c2 &&
+ Array.equal glob_constr_eq t1 t2
+| GSort (_, s1), GSort (_, s2) -> Miscops.glob_sort_eq s1 s2
+| GHole (_, kn1, nam1, gn1), GHole (_, kn2, nam2, gn2) ->
+ Option.equal (==) gn1 gn2 (** Only thing sensible *) &&
+ Miscops.intro_pattern_naming_eq nam1 nam2
+| GCast (_, c1, t1), GCast (_, c2, t2) ->
+ glob_constr_eq c1 c2 && cast_type_eq glob_constr_eq t1 t2
+| _ -> false
+
+and tomatch_tuple_eq (c1, p1) (c2, p2) =
+ let eqp (_, i1, na1) (_, i2, na2) =
+ eq_ind i1 i2 && List.equal Name.equal na1 na2
+ in
+ let eq_pred (n1, o1) (n2, o2) = Name.equal n1 n2 && Option.equal eqp o1 o2 in
+ glob_constr_eq c1 c2 && eq_pred p1 p2
+
+and cases_clause_eq (_, id1, p1, c1) (_, id2, p2, c2) =
+ List.equal Id.equal id1 id2 && List.equal cases_pattern_eq p1 p2 &&
+ glob_constr_eq c1 c2
+
+and glob_decl_eq (na1, bk1, c1, t1) (na2, bk2, c2, t2) =
+ Name.equal na1 na2 && binding_kind_eq bk1 bk2 &&
+ Option.equal glob_constr_eq c1 c2 &&
+ glob_constr_eq t1 t2
+
+and fix_kind_eq k1 k2 = match k1, k2 with
+| GFix (a1, i1), GFix (a2, i2) ->
+ let eq (i1, o1) (i2, o2) =
+ Option.equal Int.equal i1 i2 && fix_recursion_order_eq o1 o2
+ in
+ Int.equal i1 i2 && Array.equal eq a1 a1
+| GCoFix i1, GCoFix i2 -> Int.equal i1 i2
+| _ -> false
+
+and fix_recursion_order_eq o1 o2 = match o1, o2 with
+| GStructRec, GStructRec -> true
+| GWfRec c1, GWfRec c2 -> glob_constr_eq c1 c2
+| GMeasureRec (c1, o1), GMeasureRec (c2, o2) ->
+ glob_constr_eq c1 c2 && Option.equal glob_constr_eq o1 o2
+| _ -> false
+
+and instance_eq (x1,c1) (x2,c2) =
+ Id.equal x1 x2 && glob_constr_eq c1 c2
+
+let map_glob_constr_left_to_right f = function
+ | GApp (loc,g,args) ->
+ let comp1 = f g in
+ let comp2 = Util.List.map_left f args in
+ GApp (loc,comp1,comp2)
+ | GLambda (loc,na,bk,ty,c) ->
+ let comp1 = f ty in
+ let comp2 = f c in
+ GLambda (loc,na,bk,comp1,comp2)
+ | GProd (loc,na,bk,ty,c) ->
+ let comp1 = f ty in
+ let comp2 = f c in
+ GProd (loc,na,bk,comp1,comp2)
+ | GLetIn (loc,na,b,c) ->
+ let comp1 = f b in
+ let comp2 = f c in
+ GLetIn (loc,na,comp1,comp2)
+ | GCases (loc,sty,rtntypopt,tml,pl) ->
+ let comp1 = Option.map f rtntypopt in
+ let comp2 = Util.List.map_left (fun (tm,x) -> (f tm,x)) tml in
+ let comp3 = Util.List.map_left (fun (loc,idl,p,c) -> (loc,idl,p,f c)) pl in
+ GCases (loc,sty,comp1,comp2,comp3)
+ | GLetTuple (loc,nal,(na,po),b,c) ->
+ let comp1 = Option.map f po in
+ let comp2 = f b in
+ let comp3 = f c in
+ GLetTuple (loc,nal,(na,comp1),comp2,comp3)
+ | GIf (loc,c,(na,po),b1,b2) ->
+ let comp1 = Option.map f po in
+ let comp2 = f b1 in
+ let comp3 = f b2 in
+ GIf (loc,f c,(na,comp1),comp2,comp3)
+ | GRec (loc,fk,idl,bl,tyl,bv) ->
+ let comp1 = Array.map (Util.List.map_left (map_glob_decl_left_to_right f)) bl in
+ let comp2 = Array.map f tyl in
+ let comp3 = Array.map f bv in
+ GRec (loc,fk,idl,comp1,comp2,comp3)
+ | GCast (loc,c,k) ->
+ let comp1 = f c in
+ let comp2 = Miscops.map_cast_type f k in
+ GCast (loc,comp1,comp2)
+ | (GVar _ | GSort _ | GHole _ | GRef _ | GEvar _ | GPatVar _) as x -> x
+
+let map_glob_constr = map_glob_constr_left_to_right
+
+let fold_glob_constr f acc =
+ let rec fold acc = function
+ | GVar _ -> acc
+ | GApp (_,c,args) -> List.fold_left fold (fold acc c) args
+ | GLambda (_,_,_,b,c) | GProd (_,_,_,b,c) | GLetIn (_,_,b,c) ->
+ fold (fold acc b) c
+ | GCases (_,_,rtntypopt,tml,pl) ->
+ List.fold_left fold_pattern
+ (List.fold_left fold (Option.fold_left fold acc rtntypopt) (List.map fst tml))
+ pl
+ | GLetTuple (_,_,rtntyp,b,c) ->
+ fold (fold (fold_return_type acc rtntyp) b) c
+ | GIf (_,c,rtntyp,b1,b2) ->
+ fold (fold (fold (fold_return_type acc rtntyp) c) b1) b2
+ | GRec (_,_,_,bl,tyl,bv) ->
+ let acc = Array.fold_left
+ (List.fold_left (fun acc (na,k,bbd,bty) ->
+ fold (Option.fold_left fold acc bbd) bty)) acc bl in
+ Array.fold_left fold (Array.fold_left fold acc tyl) bv
+ | GCast (_,c,k) ->
+ let r = match k with
+ | CastConv t | CastVM t | CastNative t -> fold acc t | CastCoerce -> acc
+ in
+ fold r c
+ | (GSort _ | GHole _ | GRef _ | GEvar _ | GPatVar _) -> acc
+
+ and fold_pattern acc (_,idl,p,c) = fold acc c
+
+ and fold_return_type acc (na,tyopt) = Option.fold_left fold acc tyopt
+
+ in fold acc
+
+let iter_glob_constr f = fold_glob_constr (fun () -> f) ()
+
+let same_id na id = match na with
+| Anonymous -> false
+| Name id' -> Id.equal id id'
+
+let occur_glob_constr id =
+ let rec occur = function
+ | GVar (loc,id') -> Id.equal id id'
+ | GApp (loc,f,args) -> (occur f) || (List.exists occur args)
+ | GLambda (loc,na,bk,ty,c) ->
+ (occur ty) || (not (same_id na id) && (occur c))
+ | GProd (loc,na,bk,ty,c) ->
+ (occur ty) || (not (same_id na id) && (occur c))
+ | GLetIn (loc,na,b,c) ->
+ (occur b) || (not (same_id na id) && (occur c))
+ | GCases (loc,sty,rtntypopt,tml,pl) ->
+ (occur_option rtntypopt)
+ || (List.exists (fun (tm,_) -> occur tm) tml)
+ || (List.exists occur_pattern pl)
+ | GLetTuple (loc,nal,rtntyp,b,c) ->
+ occur_return_type rtntyp id
+ || (occur b) || (not (List.mem_f Name.equal (Name id) nal) && (occur c))
+ | GIf (loc,c,rtntyp,b1,b2) ->
+ occur_return_type rtntyp id || (occur c) || (occur b1) || (occur b2)
+ | GRec (loc,fk,idl,bl,tyl,bv) ->
+ not (Array.for_all4 (fun fid bl ty bd ->
+ let rec occur_fix = function
+ [] -> not (occur ty) && (Id.equal fid id || not(occur bd))
+ | (na,k,bbd,bty)::bl ->
+ not (occur bty) &&
+ (match bbd with
+ Some bd -> not (occur bd)
+ | _ -> true) &&
+ (match na with Name id' -> Id.equal id id' | _ -> not (occur_fix bl)) in
+ occur_fix bl)
+ idl bl tyl bv)
+ | GCast (loc,c,k) -> (occur c) || (match k with CastConv t
+ | CastVM t | CastNative t -> occur t | CastCoerce -> false)
+ | (GSort _ | GHole _ | GRef _ | GEvar _ | GPatVar _) -> false
+
+ and occur_pattern (loc,idl,p,c) = not (Id.List.mem id idl) && (occur c)
+
+ and occur_option = function None -> false | Some p -> occur p
+
+ and occur_return_type (na,tyopt) id = not (same_id na id) && occur_option tyopt
+
+ in occur
+
+
+let add_name_to_ids set na =
+ match na with
+ | Anonymous -> set
+ | Name id -> Id.Set.add id set
+
+let free_glob_vars =
+ let rec vars bounded vs = function
+ | GVar (loc,id') -> if Id.Set.mem id' bounded then vs else Id.Set.add id' vs
+ | GApp (loc,f,args) -> List.fold_left (vars bounded) vs (f::args)
+ | GLambda (loc,na,_,ty,c) | GProd (loc,na,_,ty,c) | GLetIn (loc,na,ty,c) ->
+ let vs' = vars bounded vs ty in
+ let bounded' = add_name_to_ids bounded na in
+ vars bounded' vs' c
+ | GCases (loc,sty,rtntypopt,tml,pl) ->
+ let vs1 = vars_option bounded vs rtntypopt in
+ let vs2 = List.fold_left (fun vs (tm,_) -> vars bounded vs tm) vs1 tml in
+ List.fold_left (vars_pattern bounded) vs2 pl
+ | GLetTuple (loc,nal,rtntyp,b,c) ->
+ let vs1 = vars_return_type bounded vs rtntyp in
+ let vs2 = vars bounded vs1 b in
+ let bounded' = List.fold_left add_name_to_ids bounded nal in
+ vars bounded' vs2 c
+ | GIf (loc,c,rtntyp,b1,b2) ->
+ let vs1 = vars_return_type bounded vs rtntyp in
+ let vs2 = vars bounded vs1 c in
+ let vs3 = vars bounded vs2 b1 in
+ vars bounded vs3 b2
+ | GRec (loc,fk,idl,bl,tyl,bv) ->
+ let bounded' = Array.fold_right Id.Set.add idl bounded in
+ let vars_fix i vs fid =
+ let vs1,bounded1 =
+ List.fold_left
+ (fun (vs,bounded) (na,k,bbd,bty) ->
+ let vs' = vars_option bounded vs bbd in
+ let vs'' = vars bounded vs' bty in
+ let bounded' = add_name_to_ids bounded na in
+ (vs'',bounded')
+ )
+ (vs,bounded')
+ bl.(i)
+ in
+ let vs2 = vars bounded1 vs1 tyl.(i) in
+ vars bounded1 vs2 bv.(i)
+ in
+ Array.fold_left_i vars_fix vs idl
+ | GCast (loc,c,k) -> let v = vars bounded vs c in
+ (match k with CastConv t | CastVM t | CastNative t -> vars bounded v t | _ -> v)
+ | (GSort _ | GHole _ | GRef _ | GEvar _ | GPatVar _) -> vs
+
+ and vars_pattern bounded vs (loc,idl,p,c) =
+ let bounded' = List.fold_right Id.Set.add idl bounded in
+ vars bounded' vs c
+
+ and vars_option bounded vs = function None -> vs | Some p -> vars bounded vs p
+
+ and vars_return_type bounded vs (na,tyopt) =
+ let bounded' = add_name_to_ids bounded na in
+ vars_option bounded' vs tyopt
+ in
+ fun rt ->
+ let vs = vars Id.Set.empty Id.Set.empty rt in
+ Id.Set.elements vs
+
+(** Mapping of names in binders *)
+
+(* spiwack: I used a smartmap-style kind of mapping here, because the
+ operation will be the identity almost all of the time (with any
+ term outside of Ltac to begin with). But to be honest, there would
+ probably be no significant penalty in doing reallocation as
+ pattern-matching expressions are usually rather small. *)
+
+let map_inpattern_binders f ((loc,id,nal) as x) =
+ let r = CList.smartmap f nal in
+ if r == nal then x
+ else loc,id,r
+
+let map_tomatch_binders f ((c,(na,inp)) as x) : tomatch_tuple =
+ let r = Option.smartmap (fun p -> map_inpattern_binders f p) inp in
+ if r == inp then x
+ else c,(f na, r)
+
+let rec map_case_pattern_binders f = function
+ | PatVar (loc,na) as x ->
+ let r = f na in
+ if r == na then x
+ else PatVar (loc,r)
+ | PatCstr (loc,c,ps,na) as x ->
+ let rna = f na in
+ let rps =
+ CList.smartmap (fun p -> map_case_pattern_binders f p) ps
+ in
+ if rna == na && rps == ps then x
+ else PatCstr(loc,c,rps,rna)
+
+let map_cases_branch_binders f ((loc,il,cll,rhs) as x) : cases_clause =
+ (* spiwack: not sure if I must do something with the list of idents.
+ It is intended to be a superset of the free variable of the
+ right-hand side, if I understand correctly. But I'm not sure when
+ or how they are used. *)
+ let r = List.smartmap (fun cl -> map_case_pattern_binders f cl) cll in
+ if r == cll then x
+ else loc,il,r,rhs
+
+let map_pattern_binders f tomatch branches =
+ CList.smartmap (fun tm -> map_tomatch_binders f tm) tomatch,
+ CList.smartmap (fun br -> map_cases_branch_binders f br) branches
+
+(** /mapping of names in binders *)
+
+let map_tomatch f (c,pp) : tomatch_tuple = f c , pp
+
+let map_cases_branch f (loc,il,cll,rhs) : cases_clause =
+ loc , il , cll , f rhs
+
+let map_pattern f tomatch branches =
+ List.map (fun tm -> map_tomatch f tm) tomatch,
+ List.map (fun br -> map_cases_branch f br) branches
+
+let loc_of_glob_constr = function
+ | GRef (loc,_,_) -> loc
+ | GVar (loc,_) -> loc
+ | GEvar (loc,_,_) -> loc
+ | GPatVar (loc,_) -> loc
+ | GApp (loc,_,_) -> loc
+ | GLambda (loc,_,_,_,_) -> loc
+ | GProd (loc,_,_,_,_) -> loc
+ | GLetIn (loc,_,_,_) -> loc
+ | GCases (loc,_,_,_,_) -> loc
+ | GLetTuple (loc,_,_,_,_) -> loc
+ | GIf (loc,_,_,_,_) -> loc
+ | GRec (loc,_,_,_,_,_) -> loc
+ | GSort (loc,_) -> loc
+ | GHole (loc,_,_,_) -> loc
+ | GCast (loc,_,_) -> loc
+
+(**********************************************************************)
+(* Conversion from glob_constr to cases pattern, if possible *)
+
+let rec cases_pattern_of_glob_constr na = function
+ | GVar (loc,id) ->
+ begin match na with
+ | Name _ ->
+ (* Unable to manage the presence of both an alias and a variable *)
+ raise Not_found
+ | Anonymous -> PatVar (loc,Name id)
+ end
+ | GHole (loc,_,_,_) -> PatVar (loc,na)
+ | GRef (loc,ConstructRef cstr,_) ->
+ PatCstr (loc,cstr,[],na)
+ | GApp (loc,GRef (_,ConstructRef cstr,_),l) ->
+ PatCstr (loc,cstr,List.map (cases_pattern_of_glob_constr Anonymous) l,na)
+ | _ -> raise Not_found
+
+(* Turn a closed cases pattern into a glob_constr *)
+let rec glob_constr_of_closed_cases_pattern_aux = function
+ | PatCstr (loc,cstr,[],Anonymous) ->
+ GRef (loc,ConstructRef cstr,None)
+ | PatCstr (loc,cstr,l,Anonymous) ->
+ let ref = GRef (loc,ConstructRef cstr,None) in
+ GApp (loc,ref, List.map glob_constr_of_closed_cases_pattern_aux l)
+ | _ -> raise Not_found
+
+let glob_constr_of_closed_cases_pattern = function
+ | PatCstr (loc,cstr,l,na) ->
+ na,glob_constr_of_closed_cases_pattern_aux (PatCstr (loc,cstr,l,Anonymous))
+ | _ ->
+ raise Not_found