(************************************************************************) (* * 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."))
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.