(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
open Pp open Util open Names open Nameops open Libnames open Glob_term open Notationextern open Constrexpr
(***********) (* Universes *)
let expr_Type_sort = None, UAnonymous {rigid=UnivRigid} let expr_SProp_sort = None, UNamed [CSProp, 0] let expr_Prop_sort = None, UNamed [CProp, 0] let expr_Set_sort = None, UNamed [CSet, 0]
let sort_name_expr_eq c1 c2 = match c1, c2 with
| CSProp, CSProp
| CProp, CProp
| CSet, CSet -> true
| CType q1, CType q2 -> Libnames.qualid_eq q1 q2
| CRawType u1, CRawType u2 -> Univ.Level.equal u1 u2
| (CSProp|CProp|CSet|CType _|CRawType _), _ -> false
(* We use a functor to avoid passing the recursion all over the place *)
module EqGen (A:sigval constr_expr_eq : constr_expr -> constr_expr -> boolend) = struct
open A let args_eq (a1,e1) (a2,e2) = Option.equal (CAst.eq explicitation_eq) e1 e2 &&
constr_expr_eq a1 a2
let constr_expr_eq_gen eq = let module Eq = EqGen(structlet constr_expr_eq = eq end) in
Eq.constr_expr_eq
module Eq = EqGen(struct let rec constr_expr_eq c1 c2 = constr_expr_eq_gen constr_expr_eq c1 c2 end)
include Eq
let constr_loc c = CAst.(c.loc) let cases_pattern_expr_loc cp = CAst.(cp.loc)
let local_binder_loc = letopen CAst in function
| CLocalAssum ({ loc } ::_,_,_,t)
| CLocalDef ( { loc },_,t,None) -> Loc.merge_opt loc (constr_loc t)
| CLocalDef ( { loc },_,b,Some t) -> Loc.merge_opt loc (Loc.merge_opt (constr_loc b) (constr_loc t))
| CLocalAssum ([],_,_,_) -> assert false
| CLocalPattern { loc } -> loc
let local_binders_loc bll = match bll with
| [] -> None
| h :: l -> Loc.merge_opt (local_binder_loc h) (local_binder_loc (List.last bll))
(** Folds and maps *) let is_constructor id = match
Smartlocate.global_of_extended_global
(Nametab.locate_extended (qualid_of_ident id)) with
| exception Not_found -> false
| None -> false
| Some gref -> Globnames.isConstructRef gref
let rec cases_pattern_fold_names f h nacc pt = match CAst.(pt.v) with
| CPatRecord l -> List.fold_left (fun nacc (r, cp) -> cases_pattern_fold_names f h nacc cp) nacc l
| CPatAlias (pat,{CAst.v=na}) -> Name.fold_right (fun na (n,acc) -> (f na n,acc)) na (cases_pattern_fold_names f h nacc pat)
| CPatOr (patl) -> List.fold_left (cases_pattern_fold_names f h) nacc patl
| CPatCstr (_,patl1,patl2) -> List.fold_left (cases_pattern_fold_names f h)
(Option.fold_left (List.fold_left (cases_pattern_fold_names f h)) nacc patl1) patl2
| CPatNotation (_,_,(patl,patll,binderl),patl') -> List.fold_left (cases_pattern_fold_names f h)
(List.fold_left (cases_pattern_fold_names f h) nacc
(patl@List.flatten patll@List.map fst binderl)) patl'
| CPatDelimiters (_,_,pat) -> cases_pattern_fold_names f h nacc pat
| CPatAtom (Some qid)
when qualid_is_ident qid && not (is_constructor @@ qualid_basename qid) -> let (n, acc) = nacc in
(f (qualid_basename qid) n, acc)
| CPatPrim _ | CPatAtom _ -> nacc
| CPatCast (p,t) -> let (n, acc) = nacc in
cases_pattern_fold_names f h (n, h acc t) p
let ids_of_pattern_list p =
fst (List.fold_left
(List.fold_left (cases_pattern_fold_names Id.Set.add (fun () _ -> ())))
(Id.Set.empty,()) p)
let ids_of_cases_tomatch tms = List.fold_right
(fun (_, ona, indnal) l -> Option.fold_right (fun t ids -> fst (cases_pattern_fold_names Id.Set.add (fun () _ -> ()) (ids,()) t))
indnal
(Option.fold_right (CAst.with_val (Name.fold_right Id.Set.add)) ona l))
tms Id.Set.empty
let rec fold_local_binders g f n acc b = letopen CAst in function
| CLocalAssum (nal,_,bk,t)::l -> let nal = List.(map (fun {v} -> v) nal) in let n' = List.fold_right (Name.fold_right g) nal n in
f n (fold_local_binders g f n' acc b l) t
| CLocalDef ( { v = na },_,c,t)::l -> Option.fold_left (f n) (f n (fold_local_binders g f (Name.fold_right g na n) acc b l) c) t
| CLocalPattern pat :: l -> let n, acc = cases_pattern_fold_names g (f n) (n,acc) pat in
fold_local_binders g f n acc b l
| [] ->
f n acc b
let fold_constr_expr_with_binders g f n acc = CAst.with_val (function
| CAppExpl ((_,_),l) -> List.fold_left (f n) acc l
| CApp (t,l) -> List.fold_left (f n) (f n acc t) (List.map fst l)
| CProj (e,_,l,t) -> f n (List.fold_left (f n) acc (List.map fst l)) t
| CProdN (l,b) | CLambdaN (l,b) -> fold_local_binders g f n acc b l
| CLetIn (na,a,t,b) ->
f (Name.fold_right g (na.CAst.v) n) (Option.fold_left (f n) (f n acc a) t) b
| CCast (a,_,b) -> f n (f n acc a) b
| CNotation (_,_,(l,ll,bl,bll)) -> (* The following is an approximation: we don't know exactly if
an ident is binding nor to which subterms bindings apply *) let acc = List.fold_left (f n) acc (l@List.flatten ll) in List.fold_left (fun acc bl -> fold_local_binders g f n acc (CAst.make @@ CHole (None)) bl) acc bll
| CGeneralization (_,c) -> f n acc c
| CDelimiters (_,_,a) -> f n acc a
| CRecord l -> List.fold_left (fun acc (id, c) -> f n acc c) acc l
| CCases (sty,rtnpo,al,bl) -> let ids = ids_of_cases_tomatch al in let acc = Option.fold_left (f (Id.Set.fold g ids n)) acc rtnpo in let acc = List.fold_left (f n) acc (List.map (fun (fst,_,_) -> fst) al) in List.fold_right (fun {CAst.v=(patl,rhs)} acc -> let ids = ids_of_pattern_list patl in
f (Id.Set.fold g ids n) acc rhs) bl acc
| CLetTuple (nal,(ona,po),b,c) -> let n' = List.fold_right (CAst.with_val (Name.fold_right g)) nal n in
f (Option.fold_right (CAst.with_val (Name.fold_right g)) ona n') (f n acc b) c
| CIf (c,(ona,po),b1,b2) -> let acc = f n (f n (f n acc b1) b2) c in Option.fold_left
(f (Option.fold_right (CAst.with_val (Name.fold_right g)) ona n)) acc po
| CFix (_,l) -> let n' = List.fold_right (fun ( { CAst.v = id },_,_,_,_,_) -> g id) l n in List.fold_right (fun (_,_,ro,lb,t,c) acc ->
fold_local_binders g f n'
(fold_local_binders g f n acc t lb) c lb) l acc
| CCoFix (_,_) ->
Feedback.msg_warning (strbrk "Capture check in multiple binders not done"); acc
| CArray (_u,t,def,ty) -> f n (f n (Array.fold_left (f n) acc t) def) ty
| CHole _ | CGenarg _ | CGenargGlob _ | CEvar _ | CPatVar _ | CSort _ | CPrim _ | CRef _ ->
acc
)
let free_vars_of_constr_expr c = let rec aux bdvars l = function
| { CAst.v = CRef (qid, _) } when qualid_is_ident qid -> let id = qualid_basename qid in if Id.List.mem id bdvars then l else Id.Set.add id l
| c -> fold_constr_expr_with_binders (fun a l -> a::l) aux bdvars l c in aux [] Id.Set.empty c
let names_of_constr_expr c = let vars = ref Id.Set.empty in let rec aux () () = function
| { CAst.v = CRef (qid, _) } when qualid_is_ident qid -> let id = qualid_basename qid in vars := Id.Set.add id !vars
| c -> fold_constr_expr_with_binders (fun a () -> vars := Id.Set.add a !vars) aux () () c in aux () () c; !vars
let occur_var_constr_expr id c = Id.Set.mem id (free_vars_of_constr_expr c)
let rec fold_map_cases_pattern f h acc (CAst.{v=pt;loc} as p) = match pt with
| CPatRecord l -> let acc, l = List.fold_left_map (fun acc (r, cp) -> let acc, cp = fold_map_cases_pattern f h acc cp in acc, (r, cp)) acc l in
acc, CAst.make ?loc (CPatRecord l)
| CPatAlias (pat,({CAst.v=na} as lna)) -> let acc, p = fold_map_cases_pattern f h acc pat in let acc = Name.fold_right f na acc in
acc, CAst.make ?loc (CPatAlias (pat,lna))
| CPatOr patl -> let acc, patl = List.fold_left_map (fold_map_cases_pattern f h) acc patl in
acc, CAst.make ?loc (CPatOr patl)
| CPatCstr (c,patl1,patl2) -> let acc, patl1 = Option.fold_left_map (List.fold_left_map (fold_map_cases_pattern f h)) acc patl1 in let acc, patl2 = List.fold_left_map (fold_map_cases_pattern f h) acc patl2 in
acc, CAst.make ?loc (CPatCstr (c,patl1,patl2))
| CPatNotation (sc,ntn,(patl,patll,binderl),patl') -> let acc, patl = List.fold_left_map (fold_map_cases_pattern f h) acc patl in let acc, patll = List.fold_left_map (List.fold_left_map (fold_map_cases_pattern f h)) acc patll in let acc, binderl' = List.fold_left_map (fold_fst (fold_map_cases_pattern f h)) acc binderl in let acc, patl' = List.fold_left_map (fold_map_cases_pattern f h) acc patl'in
acc, CAst.make ?loc (CPatNotation (sc,ntn,(patl,patll,binderl'),patl'))
| CPatDelimiters (depth,d,pat) -> let acc, p = fold_map_cases_pattern f h acc pat in
acc, CAst.make ?loc (CPatDelimiters (depth,d,pat))
| CPatAtom (Some qid)
when qualid_is_ident qid && not (is_constructor @@ qualid_basename qid) ->
f (qualid_basename qid) acc, p
| CPatPrim _ | CPatAtom _ -> (acc,p)
| CPatCast (pat,t) -> let acc, pat = fold_map_cases_pattern f h acc pat in let t = h acc t in
acc, CAst.make ?loc (CPatCast (pat,t))
(* Used in correctness and interface *) let map_binder g e nal = List.fold_right (CAst.with_val (Name.fold_right g)) nal e
let fold_map_local_binders f g e bl = (* TODO: avoid variable capture in [t] by some [na] in [List.tl nal] *) letopen CAst in let h (e,bl) = function
CLocalAssum(nal,r,k,ty) ->
(map_binder g e nal, CLocalAssum(nal,r,k,f e ty)::bl)
| CLocalDef( { loc ; v = na } as cna ,r,c,ty) ->
(Name.fold_right g na e, CLocalDef(cna,r,f e c,Option.map (f e) ty)::bl)
| CLocalPattern pat -> let e, pat = fold_map_cases_pattern g f e pat in
(e, CLocalPattern pat::bl) in let (e,rbl) = List.fold_left h (e,[]) bl in
(e, List.rev rbl)
let map_constr_expr_with_binders g f e = CAst.map (function
| CAppExpl (r,l) -> CAppExpl (r,List.map (f e) l)
| CApp (a,l) ->
CApp (f e a,List.map (fun (a,i) -> (f e a,i)) l)
| CProj (expl,p,l,a) ->
CProj (expl,p,List.map (fun (a,i) -> (f e a,i)) l,f e a)
| CProdN (bl,b) -> let (e,bl) = fold_map_local_binders f g e bl in CProdN (bl,f e b)
| CLambdaN (bl,b) -> let (e,bl) = fold_map_local_binders f g e bl in CLambdaN (bl,f e b)
| CLetIn (na,a,t,b) ->
CLetIn (na,f e a,Option.map (f e) t,f (Name.fold_right g (na.CAst.v) e) b)
| CCast (a,k,c) -> CCast (f e a, k, f e c)
| CNotation (inscope,n,(l,ll,bl,bll)) -> (* This is an approximation because we don't know what binds what *)
CNotation (inscope,n,(List.map (f e) l,List.map (List.map (f e)) ll, bl, List.map (fun bl -> snd (fold_map_local_binders f g e bl)) bll))
| CGeneralization (b,c) -> CGeneralization (b,f e c)
| CDelimiters (depth,s,a) -> CDelimiters (depth,s,f e a)
| CRecord l -> CRecord (List.map (fun (id, c) -> (id, f e c)) l)
| CCases (sty,rtnpo,a,bl) -> let bl = List.map (fun {CAst.v=(patl,rhs);loc} -> let ids = ids_of_pattern_list patl in
CAst.make ?loc (patl,f (Id.Set.fold g ids e) rhs)) bl in let ids = ids_of_cases_tomatch a in let po = Option.map (f (Id.Set.fold g ids e)) rtnpo in
CCases (sty, po, List.map (fun (tm,x,y) -> f e tm,x,y) a,bl)
| CLetTuple (nal,(ona,po),b,c) -> let e' = List.fold_right (CAst.with_val (Name.fold_right g)) nal e in let e'' = Option.fold_right (CAst.with_val (Name.fold_right g)) ona e in
CLetTuple (nal,(ona,Option.map (f e'') po),f e b,f e' c)
| CIf (c,(ona,po),b1,b2) -> let e' = Option.fold_right (CAst.with_val (Name.fold_right g)) ona e in
CIf (f e c,(ona,Option.map (f e') po),f e b1,f e b2)
| CFix (id,dl) ->
CFix (id,List.map (fun (id,r,n,bl,t,d) -> let (e',bl') = fold_map_local_binders f g e bl in let t' = f e' t in (* Note: fix names should be inserted before the arguments... *) let e'' = List.fold_left (fun e ({ CAst.v = id },_,_,_,_,_) -> g id e) e' dl in let d' = f e'' d in
(id,r,n,bl',t',d')) dl)
| CCoFix (id,dl) ->
CCoFix (id,List.map (fun (id,r,bl,t,d) -> let (e',bl') = fold_map_local_binders f g e bl in let t' = f e' t in let e'' = List.fold_left (fun e ({ CAst.v = id },_,_,_,_) -> g id e) e' dl in let d' = f e'' d in
(id,r,bl',t',d')) dl)
| CArray (u, t, def, ty) ->
CArray (u, Array.map (f e) t, f e def, f e ty)
| CHole _ | CGenarg _ | CGenargGlob _ | CEvar _ | CPatVar _ | CSort _
| CPrim _ | CRef _ as x -> x
)
(* Used in constrintern *) let rec replace_vars_constr_expr l r = match r with
| { CAst.loc; v = CRef (qid,us) } as x when qualid_is_ident qid -> let id = qualid_basename qid in
(try CAst.make ?loc @@ CRef (qualid_of_ident ?loc (Id.Map.find id l),us) with Not_found -> x)
| cn -> map_constr_expr_with_binders Id.Map.remove replace_vars_constr_expr l cn
(* Returns the ranges of locs of the notation that are not occupied by args *) (* and which are then occupied by proper symbols of the notation (or spaces) *)
let locs_of_notation ?loc locs ntn = let unloc loc = Option.cata Loc.unloc (0,0) loc in let (bl, el) = unloc loc in let locs = List.map unloc locs in let rec aux pos = function
| [] -> if Int.equal pos el then [] else [(pos,el)]
| (ba,ea)::l -> if Int.equal pos ba then aux ea l else (pos,ba)::aux ea l in aux bl (List.sort (fun l1 l2 -> fst l1 - fst l2) locs)
let error_invalid_pattern_notation ?loc () =
CErrors.user_err ?loc (str "Invalid notation for pattern.")
(** Pseudo-constructors *)
let mkIdentC id = CAst.make @@ CRef (qualid_of_ident id,None) let mkRefC r = CAst.make @@ CRef (r,None) let mkCastC (a,k,t) = CAst.make @@ CCast (a,k,t) let mkLambdaC (idl,bk,a,b) = CAst.make @@ CLambdaN ([CLocalAssum (idl,None,bk,a)],b) let mkLetInC (id,a,t,b) = CAst.make @@ CLetIn (id,a,t,b) let mkProdC (idl,bk,a,b) = CAst.make @@ CProdN ([CLocalAssum (idl,None,bk,a)],b)
let mkAppC (f,l) = let l = List.map (fun x -> (x,None)) l in match CAst.(f.v) with
| CApp (g,l') -> CAst.make @@ CApp (g, l' @ l)
| _ -> CAst.make @@ CApp (f, l)
let mkProdCN ?loc bll c = if bll = [] then c else
CAst.make ?loc @@ CProdN (bll,c)
let mkLambdaCN ?loc bll c = if bll = [] then c else
CAst.make ?loc @@ CLambdaN (bll,c)
let mkCProdN ?loc bll c =
CAst.make ?loc @@ CProdN (bll,c)
let mkCLambdaN ?loc bll c =
CAst.make ?loc @@ CLambdaN (bll,c)
let coerce_reference_to_id qid = if qualid_is_ident qid then qualid_basename qid else
CErrors.user_err ?loc:qid.CAst.loc
(str "This expression should be a simple identifier.")
let coerce_to_id = function
| { CAst.loc; v = CRef (qid,None) } when qualid_is_ident qid ->
CAst.make ?loc @@ qualid_basename qid
| { CAst.loc; _ } -> CErrors.user_err ?loc
(str "This expression should be a simple identifier.")
let coerce_to_name = function
| { CAst.loc; v = CRef (qid,None) } when qualid_is_ident qid ->
CAst.make ?loc @@ Name (qualid_basename qid)
| { CAst.loc; v = CHole (None) } -> CAst.make ?loc Anonymous
| { CAst.loc; _ } -> CErrors.user_err ?loc
(str "This expression should be a name.")
let mkCPatOr ?loc = function
| [pat] -> pat
| disjpat -> CAst.make ?loc @@ (CPatOr disjpat)
let mkAppPattern ?loc p lp = ifList.is_empty lp then p else letopen CAst in
make ?loc @@ (match p.v with
| CPatAtom (Some r) -> CPatCstr (r, None, lp)
| CPatCstr (r, None, l2) ->
CErrors.user_err ?loc:p.loc
(Pp.str "Nested applications not supported.")
| CPatCstr (r, l1, l2) -> CPatCstr (r, l1 , l2@lp)
| CPatNotation (inscope, n, s, l) -> CPatNotation (inscope, n , s, l@lp)
| _ -> CErrors.user_err ?loc:p.loc (Pp.str "Such pattern cannot have arguments."))
let isCSort a = match a.CAst.v with Constrexpr.CSort _ -> true | _ -> false
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.24Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.