(************************************************************************) (* * 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) *) (************************************************************************)
(*i*) open Pp open CErrors open Util open Names open Nameops open Termops open Libnames open Impargs open CAst open Notation open Constrexpr open Constrexpr_ops open Notation_ops open Glob_term open Glob_ops open Pattern open Detyping open Structures open Notationextern
(* This governs printing of implicit arguments. When [print_implicits]isonthen[print_implicits_explicit_args]tells howimplicitargsareprinted.Ifon,implicitargsareprinted withtheform(id:=arg)otherwiseargumentsareprintednormallyand
the function is prefixed by "@" *) let print_implicits = reffalse let print_implicits_explicit_args = reffalse
(* Tells if implicit arguments not known to be inferable from a rigid
position are systematically printed *) let print_implicits_defensive = reftrue
(* This forces printing of coercions *) let print_coercions = reffalse
(* This forces printing of parentheses even when
it is implied by associativity/precedence *) let print_parentheses = reffalse
(* This forces printing universe names of Type{.} *) let print_universes = Detyping.print_universes
(* This suppresses printing of notations *) let print_no_symbol = reffalse
(* This tells to skip types if a variable has this type by default *) let { Goptions.get = print_use_implicit_types } =
Goptions.declare_bool_option_and_ref
~key:["Printing";"Use";"Implicit";"Types"]
~value:true
()
(* Print primitive tokens, like strings *) let print_raw_literal = reffalse
let is_reserved_type na t = not !Flags.raw_print && print_use_implicit_types () && match na with
| Anonymous -> false
| Name id -> try let pat = Reserve.find_reserved_type id in let _ = match_notation_constr ~print_parentheses:true ~print_univ:false t ~vars:Id.Set.empty ([],pat) in true with Not_found | No_match -> false
(**********************************************************************) (* Turning notations and scopes on and off for printing *) (* This governs printing of projections using the dot notation symbols *) let print_projections = reffalse
let print_meta_as_hole = reffalse
let with_universes f = Flags.with_option print_universes f let with_meta_as_hole f = Flags.with_option print_meta_as_hole f let without_symbols f = Flags.with_option print_no_symbol f
(**********************************************************************) (* Control printing of records *)
(* Set Record Printing flag *) let { Goptions.get = get_record_print } =
Goptions.declare_bool_option_and_ref
~key:["Printing";"Records"]
~value:true
()
let is_record indsp = try let _ = Structure.find indsp in true with Not_found -> false
let encode_record r = let indsp = Nametab.global_inductive r in ifnot (is_record indsp) then
user_err ?loc:r.CAst.loc
(str "This type is not a structure type.");
indsp
module PrintingRecordRecord =
PrintingInductiveMake (struct let encode _env = encode_record let field = "Record" let title = "Types leading to pretty-printing using record notation: " let member_message s b =
str "Terms of " ++ s ++
str
(if b then" are printed using record notation" else" are not printed using record notation") end)
module PrintingRecordConstructor =
PrintingInductiveMake (struct let encode _env = encode_record let field = "Constructor" let title = "Types leading to pretty-printing using constructor form: " let member_message s b =
str "Terms of " ++ s ++
str
(if b then" are printed using constructor form" else" are not printed using constructor form") end)
(**********************************************************************) (* Various externalisation functions *)
let insert_delimiters e = function
| None -> e
| Some sc -> CAst.make @@ CDelimiters (DelimUnboundedScope,sc,e)
let insert_pat_delimiters ?loc p = function
| None -> p
| Some sc -> CAst.make ?loc @@ CPatDelimiters (DelimUnboundedScope,sc,p)
let insert_pat_alias ?loc p = function
| Anonymous -> p
| Name _ as na -> CAst.make ?loc @@ CPatAlias (p,(CAst.make ?loc na))
let rec insert_entry_coercion ?loc l c = match l with
| [] -> c
| (inscope,ntn)::l -> CAst.make ?loc @@ CNotation (Some inscope,ntn,([insert_entry_coercion ?loc l c],[],[],[]))
let rec insert_pat_coercion ?loc l c = match l with
| [] -> c
| (inscope,ntn)::l -> CAst.make ?loc @@ CPatNotation (Some inscope,ntn,([insert_pat_coercion ?loc l c],[],[]),[])
(**********************************************************************) (* conversion of references *)
let extern_evar n l = CEvar (n,l)
(** We allow customization of the global_reference printer. Forinstance,inthedebuggerthetablesofglobalreferences
may be inaccurate *)
let rec dirpath_of_modpath = function
| MPfile dp -> dp
| MPbound mbid -> let (_,id,_) = MBId.repr mbid in DirPath.make [id]
| MPdot (t, l) -> Libnames.add_dirpath_suffix (dirpath_of_modpath t) (Label.to_id l)
let qualid_of_global = function
| GlobRef.VarRef id -> Libnames.qualid_of_ident id (* We rely on the tacite invariant that the label of a constant is used to build its internal name *)
| GlobRef.ConstRef cst -> Libnames.make_qualid (dirpath_of_modpath (Constant.modpath cst)) (Label.to_id (Constant.label cst)) (* We rely on the tacite invariant that an inductive block inherits the name of its first type *)
| GlobRef.IndRef (ind,1) -> Libnames.make_qualid (dirpath_of_modpath (MutInd.modpath ind)) (Label.to_id (MutInd.label ind)) (* These are hacks *)
| GlobRef.IndRef (ind,n) -> Libnames.make_qualid (dirpath_of_modpath (MutInd.modpath ind)) (Id.of_string_soft ("<inductive:" ^ Label.to_string (MutInd.label ind) ^ ":" ^ string_of_int n ^ ">"))
| GlobRef.ConstructRef ((ind,1),p) -> Libnames.make_qualid (dirpath_of_modpath (MutInd.modpath ind)) (Id.of_string_soft ("<constructor:" ^ Label.to_string (MutInd.label ind) ^ ":" ^ string_of_int (p+1) ^ ">"))
| GlobRef.ConstructRef ((ind,n),p) -> Libnames.make_qualid (dirpath_of_modpath (MutInd.modpath ind)) (Id.of_string_soft ("<constructor:" ^ Label.to_string (MutInd.label ind) ^ ":" ^ string_of_int n ^ ":" ^ string_of_int (p+1) ^ ">"))
let default_extern_reference ?loc vars r = try Nametab.shortest_qualid_of_global ?loc vars r with Not_found -> qualid_of_global r
let my_extern_reference = ref default_extern_reference
let set_extern_reference f = my_extern_reference := f let get_extern_reference () = !my_extern_reference
let extern_reference ?loc vars l = !my_extern_reference vars l
let rec fill_arg_scopes args subscopes (_,scopes as all) = match args, subscopes with
| [], _ -> []
| a :: args, scopt :: subscopes ->
(a, ((constr_some_level,None), (scopt, scopes))) :: fill_arg_scopes args subscopes all
| a :: args, [] ->
(a, ((constr_some_level,None), ([], scopes))) :: fill_arg_scopes args [] all
let overlap_right_left {notation_entry = entry} lev_after ((typs,_):Notation_term.interpretation) = List.exists (fun (_id,(({notation_subentry = entry'; notation_relative_level = lev; notation_position = side},_),_,_)) -> match side with
| Some Right when notation_entry_eq entry entry' -> may_capture_cont_after lev_after lev
| _ -> false) typs
let update_with_subscope from_entry (entry,(scopt,scl)) lev_after closed scopes = let {notation_subentry = entry; notation_relative_level = lev; notation_position = side} = entry in let lev = if !print_parentheses && side <> None then LevelLe 0(* min level *) else lev in let lev_after = match side with
| Some Left -> Some from_entry.notation_level
| Some Right -> if closed then None else lev_after
| None -> None in let subentry' = {notation_subentry = entry; notation_relative_level = lev; notation_position = side} in
((subentry',lev_after),(scopt,scl@scopes))
let find_entry_coercion_with_application ?non_included custom entry is_empty_extra_args = if is_empty_extra_args then (* We need a direct coercion from custom to entry *) match availability_of_entry_coercion ?non_included custom entry with
| None -> raise No_match
| Some coercion -> coercion, [] else (* We need a coercion from custom to constr, then from constr to entry *) match availability_of_entry_coercion custom constr_lowest_level with
| None -> raise No_match
| Some appcoercion -> match availability_of_entry_coercion constr_some_level entry with
| None -> raise No_match
| Some coercion -> coercion, appcoercion
(**********************************************************************) (* mapping patterns to cases_pattern_expr *)
let add_patt_for_params ind l = if !Flags.in_debugger then l else
Util.List.addn (Inductiveops.inductive_nparamdecls (Global.env()) ind) (CAst.make @@ CPatAtom None) l
let add_cpatt_for_params ind l = if !Flags.in_debugger then l else
Util.List.addn (Inductiveops.inductive_nparamdecls (Global.env()) ind) (DAst.make @@ PatVar Anonymous) l
let drop_implicits_in_patt cst nb_expl args = let impl_st = implicits_of_global cst in let impl_data = extract_impargs_data impl_st in let rec impls_fit l = function
| [], t -> Some (List.rev_append l t)
| _, [] -> None
| h::t, { CAst.v = CPatAtom None }::tt when is_status_implicit h -> impls_fit l (t,tt)
| h::_, _ when is_status_implicit h -> None
| _::t, hh::tt -> impls_fit (hh::l) (t,tt) in let try_impls_fit (imps,args) = ifnot !Constrintern.parsing_explicit &&
((!Flags.raw_print || !print_implicits) && List.exists is_status_implicit imps) (* Note: !print_implicits_explicit_args=true not supported for patterns *) then None else impls_fit [] (imps,args) in let rec select = function
| [] -> None
| (_,imps)::imps_list -> match try_impls_fit (imps,args) with
| None -> select imps_list
| x -> x in if Int.equal nb_expl 0then select impl_data else let imps = List.skipn_at_best nb_expl (select_stronger_impargs impl_st) in
try_impls_fit (imps,args)
let destPrim = function { CAst.v = CPrim t } -> Some t | _ -> None let destPatPrim = function { CAst.v = CPatPrim t } -> Some t | _ -> None
let make_notation_gen loc ntn mknot mkprim destprim l bl = match snd ntn,List.map destprim l with (* Special case to avoid writing "- 3" for e.g. (Z.opp 3) *)
| "- _", [Some (Number p)] when not (NumTok.Signed.is_zero p) ->
assert (bl=[]);
mknot (loc,ntn,([mknot (loc,(InConstrEntry,"( _ )"),l,[])]),[])
| _ -> match decompose_notation_key ntn, l with
| (InConstrEntry,[Terminal x]), [] -> beginmatchString.unquote_coq_string x with
| Some s -> mkprim (loc, String s)
| None -> match NumTok.Unsigned.parse_string x with
| Some n -> mkprim (loc, Number (NumTok.SPlus,n))
| None -> mknot (loc,ntn,l,bl) end
| (InConstrEntry,[Terminal "-"; Terminal x]), [] -> beginmatch NumTok.Unsigned.parse_string x with
| Some n -> mkprim (loc, Number (NumTok.SMinus,n))
| None -> mknot (loc,ntn,l,bl) end
| _ -> mknot (loc,ntn,l,bl)
let make_notation loc (inscope,ntn) (terms,termlists,binders,binderlists as subst) = ifnot (List.is_empty termlists) || not (List.is_empty binderlists) then
CAst.make ?loc @@ CNotation (Some inscope,ntn,subst) else
make_notation_gen loc ntn
(fun (loc,ntn,l,bl) -> CAst.make ?loc @@ CNotation (Some inscope,ntn,(l,[],bl,[])))
(fun (loc,p) -> CAst.make ?loc @@ CPrim p)
destPrim terms binders
let apply_pat_notation (CAst.{v;loc} as c) args = ifList.is_empty args then c else match v with
| CPatNotation (sc,ntn,subst,[]) -> CAst.make ?loc @@ CPatNotation (sc,ntn,subst,args)
| CPatPrim _ -> raise No_match (* TODO: add support for applied primitive token, see also Constrexpr_ops.mkAppPattern *)
| CPatDelimiters _ -> raise No_match (* TODO: add support for applied delimited patterns *)
| _ -> assert false
let pattern_printable_in_both_syntax (ind,_ as c) = let impl_st = extract_impargs_data (implicits_of_global (GlobRef.ConstructRef c)) in let nb_params = Inductiveops.inductive_nparams (Global.env()) ind in List.exists (fun (_,impls) ->
(List.length impls >= nb_params) && let params,args = Util.List.chop nb_params impls in not !Flags.raw_print && not !print_implicits &&
(List.for_all is_status_implicit params)&&(List.for_all (fun x -> not (is_status_implicit x)) args)
) impl_st
let extern_record_pattern cstrsp args = try if !Flags.raw_print then raise_notrace Exit; let projs = Structure.find_projections (fst cstrsp) in if PrintingRecord.active (fst cstrsp) then
() elseif PrintingConstructor.active (fst cstrsp) then
raise_notrace Exit elseifnot (get_record_print ()) then
raise_notrace Exit; let rec ip projs args acc = match projs, args with
| [], [] -> acc
| proj :: q, pat :: tail -> let acc = match proj, pat with
| _, { CAst.v = CPatAtom None } -> (* we don't want to have 'x := _' in our patterns *)
acc
| Some c, _ -> let loc = pat.CAst.loc in
(extern_reference ?loc Id.Set.empty (GlobRef.ConstRef c), pat) :: acc
| _ -> raise No_match in
ip q tail acc
| _ -> assert false in
Some (List.rev (ip projs args [])) with
Not_found | No_match | Exit -> None
(* Better to use extern_glob_constr composed with injection/retraction ?? *) let rec extern_cases_pattern_in_scope ((custom,(lev_after:int option)),scopes as allscopes) vars pat = try if !Flags.in_debugger || !Flags.raw_print || !print_raw_literal thenraise No_match; let (na,p,key) = uninterp_prim_token_cases_pattern pat scopes in match availability_of_entry_coercion custom constr_lowest_level with
| None -> raise No_match
| Some coercion -> let loc = cases_pattern_loc pat in
insert_pat_coercion ?loc coercion
(insert_pat_alias ?loc (insert_pat_delimiters ?loc (CAst.make ?loc @@ CPatPrim p) key) na) with No_match -> try if !Flags.in_debugger || !Flags.raw_print || !print_no_symbol thenraise No_match;
extern_notation_pattern allscopes vars pat
(uninterp_cases_pattern_notations pat) with No_match -> let loc = pat.CAst.loc in match DAst.get pat with
| PatVar (Name id) when entry_has_global custom || entry_has_ident custom ->
CAst.make ?loc (CPatAtom (Some (qualid_of_ident ?loc id)))
| pat -> match availability_of_entry_coercion custom constr_lowest_level with
| None -> raise No_match
| Some coercion -> let allscopes = ((constr_some_level,None),scopes) in let pat = match pat with
| PatVar (Name id) -> CAst.make ?loc (CPatAtom (Some (qualid_of_ident ?loc id)))
| PatVar (Anonymous) -> CAst.make ?loc (CPatAtom None)
| PatCstr(cstrsp,args,na) -> let args = List.map (extern_cases_pattern_in_scope allscopes vars) args in let p = match extern_record_pattern cstrsp args with
| Some l -> CPatRecord l
| None -> let c = extern_reference vars (GlobRef.ConstructRef cstrsp) in if Constrintern.get_asymmetric_patterns () then if pattern_printable_in_both_syntax cstrsp then CPatCstr (c, None, args) else CPatCstr (c, Some (add_patt_for_params (fst cstrsp) args), []) else let full_args = add_patt_for_params (fst cstrsp) args in match drop_implicits_in_patt (GlobRef.ConstructRef cstrsp) 0 full_args with
| Some true_args -> CPatCstr (c, None, true_args)
| None -> CPatCstr (c, Some full_args, []) in
insert_pat_alias ?loc (CAst.make ?loc p) na in
insert_pat_coercion coercion pat
and apply_notation_to_pattern ?loc gr ((terms,termlists,binders),(no_implicit,nb_to_drop,more_args))
((custom, lev_after), (tmp_scope, scopes) as allscopes) vars pat rule = let lev_after = ifList.is_empty more_args then lev_after else Some Notation.app_level in let extra_args = let subscopes = find_arguments_scope gr in let more_args_scopes = tryList.skipn nb_to_drop subscopes with Failure _ -> [] in let more_args = fill_arg_scopes more_args more_args_scopes (snd allscopes) in let more_args = List.map (fun (c,allscopes) -> extern_cases_pattern_in_scope allscopes vars c) more_args in if Constrintern.get_asymmetric_patterns () || not (List.is_empty termlists) then more_args elseif no_implicit then more_args else match drop_implicits_in_patt gr nb_to_drop more_args with
| Some true_args -> true_args
| None -> raise No_match in match rule with
| NotationRule (_,ntn as specific_ntn) -> begin let entry = let entry = fst (Notation.level_of_notation ntn) in if overlap_right_left entry lev_after pat then {entry with notation_level = max_int} else entry in let coercion, appcoercion = find_entry_coercion_with_application custom entry (List.is_empty extra_args) in let closed = not (List.is_empty coercion) in match availability_of_notation specific_ntn (tmp_scope,scopes) with (* Uninterpretation is not allowed in current context *)
| None -> raise No_match (* Uninterpretation is allowed in current context *)
| Some (scopt,key) -> let scopes' = Option.List.cons scopt scopes in let l = List.map (fun (c,subscope) -> let scopes = update_with_subscope entry subscope lev_after closed scopes' in
extern_cases_pattern_in_scope scopes vars c)
terms in let ll = List.map (fun (c,subscope) -> let scopes = update_with_subscope entry subscope lev_after closed scopes' in List.map (extern_cases_pattern_in_scope scopes vars) c)
termlists in let bl = List.map (fun (c,subscope) -> let scopes = update_with_subscope entry subscope lev_after closed scopes' in
(extern_cases_pattern_in_scope scopes vars c, Explicit))
binders in
insert_pat_coercion appcoercion
(insert_pat_delimiters ?loc
(apply_pat_notation
(insert_pat_coercion coercion
(make_pat_notation ?loc specific_ntn (l,ll,bl)))
extra_args)
key) end
| AbbrevRule kn -> match availability_of_entry_coercion custom constr_lowest_level with
| None -> raise No_match
| Some coercion -> let qid = Nametab.shortest_qualid_of_abbreviation ?loc vars kn in let l1 = List.rev_map (fun (c,(subentry,(scopt,scl))) ->
extern_cases_pattern_in_scope ((subentry,lev_after),(scopt,scl@scopes)) vars c)
terms in
assert (List.is_empty termlists);
assert (List.is_empty binders);
insert_pat_coercion ?loc coercion (CAst.make ?loc @@ CPatCstr (qid,None,List.rev_append l1 extra_args))
and extern_notation_pattern allscopes vars t = function
| [] -> raise No_match
| { not_rule = keyrule; not_patt = pat; not_status = n } :: rules -> try if is_printing_inactive_rule keyrule pat thenraise No_match; let loc = t.loc in match DAst.get t with
| PatCstr (cstr,args,na) -> let t = if na = Anonymous then t else DAst.make ?loc (PatCstr (cstr,args,Anonymous)) in let p = apply_notation_to_pattern ?loc (GlobRef.ConstructRef cstr)
(match_notation_constr_cases_pattern t pat) allscopes vars pat keyrule in
insert_pat_alias ?loc p na
| PatVar Anonymous -> CAst.make ?loc @@ CPatAtom None
| PatVar (Name id) -> CAst.make ?loc @@ CPatAtom (Some (qualid_of_ident ?loc id)) with
No_match -> extern_notation_pattern allscopes vars t rules
let rec extern_notation_ind_pattern allscopes vars ind args = function
| [] -> raise No_match
| { not_rule = keyrule; not_patt = pat; not_status = n } :: rules -> try if is_printing_inactive_rule keyrule pat thenraise No_match;
apply_notation_to_pattern (GlobRef.IndRef ind)
(match_notation_constr_ind_pattern ind args pat) allscopes vars pat keyrule with
No_match -> extern_notation_ind_pattern allscopes vars ind args rules
let extern_ind_pattern_in_scope (custom,scopes as allscopes) vars ind args = (* pboutill: There are letins in pat which is incompatible with notations and
not explicit application. *) if !Flags.in_debugger||Inductiveops.inductive_has_local_defs (Global.env()) ind then let c = extern_reference vars (GlobRef.IndRef ind) in let args = List.map (extern_cases_pattern_in_scope allscopes vars) args in
CAst.make @@ CPatCstr (c, Some (add_patt_for_params ind args), []) else try if !Flags.raw_print || !print_no_symbol thenraise No_match;
extern_notation_ind_pattern allscopes vars ind args
(uninterp_ind_pattern_notations ind) with No_match -> let c = extern_reference vars (GlobRef.IndRef ind) in let args = List.map (extern_cases_pattern_in_scope allscopes vars) args in match drop_implicits_in_patt (GlobRef.IndRef ind) 0 args with
| Some true_args -> CAst.make @@ CPatCstr (c, None, true_args)
| None -> CAst.make @@ CPatCstr (c, Some args, [])
let extern_cases_pattern vars p =
extern_cases_pattern_in_scope ((constr_some_level,None),([],[])) vars p
let occur_name na aty = match na with
| Name id -> occur_var_constr_expr id aty
| Anonymous -> false
let is_gvar id c = match DAst.get c with
| GVar id' -> Id.equal id id'
| _ -> false
let is_projection nargs r = ifnot !Flags.in_debugger && not !Flags.raw_print && !print_projections then try match r with
| GlobRef.ConstRef c -> let n = Structure.projection_nparams c + 1in if n <= nargs then Some n else None
| _ -> None with Not_found -> None else None
let is_hole = function CHole _ | CEvar _ -> true | _ -> false
let isCRef_no_univ = function
| CRef (_,None) -> true
| _ -> false
let is_significant_implicit a = not (is_hole (a.CAst.v))
let is_needed_for_correct_partial_application tail imp = List.is_empty tail && not (maximal_insertion_of imp)
exception Expl
(* Take a list of arguments starting at position [q] and their implicit status *) (* Decide for each implicit argument if it skipped or made explicit *) (* If the removal of implicit arguments is not possible, raise [Expl] *) (* [inctx] tells if the term is in a context which will enforce the external type *) (* [n] is the total number of arguments block to which the [args] belong *) let adjust_implicit_arguments inctx n args impl = let rec exprec = function
| a::args, imp::impl when is_status_implicit imp -> let tail = exprec (args,impl) in let visible =
!Flags.raw_print ||
(!print_implicits && !print_implicits_explicit_args) ||
(is_needed_for_correct_partial_application tail imp) ||
(!print_implicits_defensive &&
(not (is_inferable_implicit inctx n imp) || !Flags.beautify) &&
is_significant_implicit (Lazy.force a)) in if visible then
(Lazy.force a,Some (make @@ explicitation imp)) :: tail else
tail
| a::args, _::impl -> (Lazy.force a,None) :: exprec (args,impl)
| args, [] -> List.map (fun a -> (Lazy.force a,None)) args (*In case of polymorphism*)
| [], (imp :: _) when is_status_implicit imp && maximal_insertion_of imp -> (* The non-explicit application cannot be parsed back with the same type *) raise Expl
| [], _ -> [] in exprec (args,impl)
let extern_projection inctx f nexpectedparams args impl = let (args1,args2) = List.chop (nexpectedparams + 1) args in let nextraargs = List.length args2 in let (impl1,impl2) = impargs_for_proj ~nexpectedparams ~nextraargs impl in let n = nexpectedparams + 1 + nextraargs in let args1 = adjust_implicit_arguments inctx n args1 impl1 in let args2 = adjust_implicit_arguments inctx n args2 impl2 in let (c1,expl), args1 = List.sep_last args1 in
assert (expl = None); let c = CProj (false,f,args1,c1) in if args2 = [] then c else CApp (CAst.make c, args2)
let is_start_implicit = function
| imp :: _ -> is_status_implicit imp && maximal_insertion_of imp
| [] -> false
let extern_record ref args = try if !Flags.raw_print then raise_notrace Exit; let cstrsp = matchrefwith GlobRef.ConstructRef c -> c | _ -> raise Not_found in let struc = Structure.find (fst cstrsp) in if PrintingRecord.active (fst cstrsp) then
() elseif PrintingConstructor.active (fst cstrsp) then
raise_notrace Exit elseifnot (get_record_print ()) then
raise_notrace Exit; let projs = struc.Structure.projections in let rec cut args n = if Int.equal n 0then args else match args with
| [] -> raise No_match
| _ :: t -> cut t (n - 1) in let args = cut args struc.Structure.nparams in let rec ip projs args acc = match projs with
| [] -> acc
| { Structure.proj_body = None } :: _ -> raise No_match
| { Structure.proj_body = Some c; proj_true = false } :: q -> (* we don't want to print locals *)
ip q args acc
| { Structure.proj_body = Some c; proj_true = true } :: q -> match args with
| [] -> raise No_match (* we give up since the constructor is not complete *)
| arg :: tail -> let arg = Lazy.force arg in let loc = arg.CAst.loc in letref = extern_reference ?loc Id.Set.empty (GlobRef.ConstRef c) in
ip q tail ((ref, arg) :: acc) in
Some (List.rev (ip projs args [])) with
| Not_found | No_match | Exit -> None
let extern_global impl f us = ifnot !Constrintern.parsing_explicit && is_start_implicit impl then
CAppExpl ((f, us), []) else
CRef (f,us)
(* Implicit args indexes are in ascending order *) (* inctx is useful only if there is a last argument to be deduced from ctxt *) let extern_applied_ref inctx impl (cf,f) us args = try ifnot !Constrintern.parsing_explicit &&
((!Flags.raw_print ||
(!print_implicits && not !print_implicits_explicit_args)) && List.exists is_status_implicit impl) thenraise Expl; let impl = if !Constrintern.parsing_explicit then [] else impl in let n = List.length args in letref = CRef (f,us) in let r = CAst.make refin let ip = is_projection n cf in match ip with
| Some i -> (* [t.(f args1) args2] projection-style notation *)
extern_projection inctx (f,us) (i-1) args impl
| None -> let args = adjust_implicit_arguments inctx n args impl in if args = [] thenrefelse CApp (r, args) with Expl -> (* A [@f args] node *) let args = List.map Lazy.force args in match is_projection (List.length args) cf with
| Some n when !print_projections -> let args = List.map (fun c -> (c,None)) args in let args1, args2 = List.chop n args in let (c1,_), args1 = List.sep_last args1 in let c = CProj (true, (f,us), args1, c1) in if args2 = [] then c else CApp (CAst.make c, args2)
| _ ->
CAppExpl ((f,us), args)
type application_style =
| UseCApp of (Constrexpr.constr_expr * Constrexpr.explicitation CAst.t option) list
| UseCAppExpl of constr_expr Lazy.t list
let is_empty_extra_args = function
| UseCApp extra_args -> List.is_empty extra_args
| UseCAppExpl extra_args -> List.is_empty extra_args
let extern_applied_abbreviation (cf,f) abbrevargs = function
| UseCApp extraargs -> let abbrevargs = List.map (fun a -> (a,None)) abbrevargs in let args = abbrevargs @ extraargs in if args = [] then cf else CApp (CAst.make cf, args)
| UseCAppExpl extraargs -> let args = abbrevargs @ List.map Lazy.force extraargs in
CAppExpl ((f,None), args)
let mkFlattenedCApp (head,args) = match head.CAst.v with
| CApp (g,args') -> (* may happen with notations for a prefix of an n-ary application *) (* or after removal of a coercion to funclass *)
CApp (g,args'@args)
| h -> ifList.is_empty args then h else CApp (head, args)
let extern_applied_notation f = function
| UseCApp args -> mkFlattenedCApp (f,args)
| UseCAppExpl _ -> raise No_match (* No @f for notations *)
let extern_args extern env args = letmap (arg, argscopes) = lazy (extern argscopes env arg) in List.mapmap args
let match_coercion_app c = match DAst.get c with
| GApp (r, args) -> beginmatch DAst.get r with
| GRef (r,_) -> Some (c.CAst.loc, r, args)
| _ -> None end
| _ -> None
let remove_one_coercion inctx c = trymatch match_coercion_app c with
| Some (loc,r,args) when not (!Flags.raw_print || !print_coercions) -> let nargs = List.length args in
(match Coercionops.hide_coercion r with
| Some nparams when let inctx = inctx || (* coercion to funclass implying being in context *) nparams+1 < nargs in
nparams < nargs && inctx -> (* We skip the coercion *) let l = List.skipn nparams args in let (a,l) = match l with a::l -> (a,l) | [] -> assert falsein (* Don't flatten App's in case of funclass so that (atomic)notationson[a]work;shouldbecompatible sinceprinterdoesnotcarewhetherApp'sare collapsedornotandnotationswithanimplicit coercionusingfunclasseitherwouldhavealready beenconfusedwithordinaryapplicationorwouldhaveneed asurroundingcontextandthecoerciontofunclasswould
have been made explicit to match *) let a' = if List.is_empty l then a else DAst.make ?loc @@ GApp (a,l) in let inctx = inctx || not (List.is_empty l) in
Some (nparams+1, inctx, a')
| _ -> None)
| _ -> None with Not_found ->
None
let rec flatten_application c = match DAst.get c with
| GApp (f, l) -> beginmatch DAst.get f with
| GApp(a,l') -> let loc = c.CAst.loc in
flatten_application (DAst.make ?loc @@ GApp (a,l'@l))
| _ -> c end
| a -> c
let same_binder_type ty nal c = match nal, DAst.get c with
| _::_, (GProd (_,_,_,ty',_) | GLambda (_,_,_,ty',_)) -> glob_constr_eq ty ty'
| [], _ -> true
| _ -> assert false
(**********************************************************************) (* mapping glob_constr to numerals (in presence of coercions, choose the *) (* one with no delimiter if possible) *)
let extern_possible_prim_token ((custom,_),scopes) r = if !print_raw_literal thenraise No_match; let (n,key) = uninterp_prim_token r scopes in match availability_of_entry_coercion custom constr_lowest_level with
| None -> raise No_match
| Some coercion ->
insert_entry_coercion coercion (insert_delimiters (CAst.make ?loc:(loc_of_glob_constr r) @@ CPrim n) key)
let filter_enough_applied nargs l = (* This is to ensure that notations for coercions are used only when thecoercionisfullyapplied;notexplicitlydoneyet,butwe couldalsoexpectthatthenotationisexactlytalkingaboutthe
coercion *) match nargs with
| None -> l
| Some nargs -> List.filter (fun rule -> match rule.not_status with
| AppBoundedNotation n -> n >= nargs
| AppUnboundedNotation | NotAppNotation -> false) l
(* Helper function for safe and optimal printing of primitive tokens *) (* such as those for Int63 *) let extern_prim_token_delimiter_if_required n key_n scope_n scopes = match availability_of_prim_token n scope_n scopes with
| Some None -> CPrim n
| None -> CDelimiters(DelimUnboundedScope, key_n, CAst.make (CPrim n))
| Some (Some key) -> CDelimiters(DelimUnboundedScope, key, CAst.make (CPrim n))
let extended_glob_local_binder_of_decl loc = function
| (p,r,bk,None,t) -> GLocalAssum (p,r,bk,t)
| (p,r,bk,Some x, t) ->
assert (bk = Explicit); match DAst.get t with
| GHole (GNamedHole _) -> GLocalDef (p,r,x,Some t)
| GHole _ -> GLocalDef (p,r,x,None)
| _ -> GLocalDef (p,r,x,Some t)
let extended_glob_local_binder_of_decl ?loc u = DAst.make ?loc (extended_glob_local_binder_of_decl loc u)
(**********************************************************************) (* mapping special floats *)
(* this helper function is copied from notation.ml as it's not exported *) let qualid_of_ref n =
n |> Rocqlib.lib_ref |> Nametab.shortest_qualid_of_global Id.Set.empty
let q_infinity () = qualid_of_ref "num.float.infinity" let q_neg_infinity () = qualid_of_ref "num.float.neg_infinity" let q_nan () = qualid_of_ref "num.float.nan"
let extern_float f scopes = if Float64.is_nan f then CRef(q_nan (), None) elseif Float64.is_infinity f then CRef(q_infinity (), None) elseif Float64.is_neg_infinity f then CRef(q_neg_infinity (), None) else let n = NumTok.Signed.of_string (Float64.to_hex_string f) in
extern_prim_token_delimiter_if_required (Number n) "float""float_scope" scopes
(**********************************************************************) (* mapping glob_constr to constr_expr *)
type extern_env = Id.Set.t * UnivNames.universe_binders let extern_env env sigma = vars_of_env env, Evd.universe_binders sigma let empty_extern_env = Id.Set.empty, UnivNames.empty_binders
let extern_glob_sort_name uvars = function
| GSProp -> CSProp
| GProp -> CProp
| GSet -> CSet
| GLocalUniv u -> CType (qualid_of_lident u)
| GRawUniv u -> CRawType u
| GUniv u -> beginmatch UnivNames.qualid_of_level uvars u with
| Some qid -> CType qid
| None -> CRawType u end
let extern_glob_qvar uvars = function
| GLocalQVar {v=Anonymous;loc} -> CQAnon loc
| GLocalQVar {v=Name id; loc} -> CQVar (qualid_of_ident ?loc id)
| GRawQVar q -> CRawQVar q
| GQVar q -> beginmatch UnivNames.qualid_of_quality uvars q with
| Some qid -> CQVar qid
| None -> CRawQVar q end
let extern_relevance_info uvars = Option.map (extern_relevance uvars)
let extern_glob_quality uvars = function
| GQConstant q -> CQConstant q
| GQualVar q -> CQualVar (extern_glob_qvar uvars q)
let extern_glob_sort uvars (q, l) = Option.map (extern_glob_qvar uvars) q,
map_glob_sort_gen (List.map (on_fst (extern_glob_sort_name uvars))) l
(** wrapper to handle print_universes: don't forget small univs *) let extern_glob_sort uvars (s:glob_sort) = let really_extern = !print_universes || Option.has_some (fst s) || match snd s with
| UNamed [s, 0] -> beginmatch s with
| GSet | GProp | GSProp -> true
| GUniv _ | GLocalUniv _ | GRawUniv _ -> false end
| _ -> false in if really_extern then extern_glob_sort uvars s else Constrexpr_ops.expr_Type_sort
let extern_instance uvars = function
| Some (ql,ul) when !print_universes -> let ql = List.map (extern_glob_quality uvars) ql in let ul = List.map (map_glob_sort_gen (extern_glob_sort_name uvars)) ul in
Some (ql,ul)
| _ -> None
let extern_ref (vars,uvars) ref us =
extern_global (select_stronger_impargs (implicits_of_global ref))
(extern_reference vars ref) (extern_instance uvars us)
let extern_var ?loc id = CRef (qualid_of_ident ?loc id,None)
let add_vname (vars,uvars) na = add_vname vars na, uvars
let rec insert_impargs impargs r = match impargs with
| [] -> r
| bk :: rest -> match DAst.get r with
| GProd (na,rinfo,_,t,c) ->
DAst.make ?loc:r.loc (GProd (na, rinfo, bk, t, insert_impargs rest c))
| GLetIn (na,rinfo,b,t,c) ->
DAst.make ?loc:r.loc (GLetIn (na, rinfo, b, t, insert_impargs impargs c))
| _ -> r
(* Max printing depth is handled by a combination of this and Format's max box depth.
Assuchexterndepthactsasanoptimizationtoavoidworkon
subterms which will anyway be ellipsis'd out. *) type depth = Unlimited | Until of { current : int; max : int }
let max_depth = ref None
let set_max_depth d = max_depth := d
let init_depth () = match !max_depth with
| None -> Unlimited
| Some max -> Until { current = 0; max }
let succ_depth = function
| Unlimited -> Some Unlimited
| Until { current; max } -> let current = succ current in if Int.equal current max then None else Some (Until { current; max })
let ellipsis = Constrexpr.CRef (Libnames.qualid_of_ident (Id.of_string_soft "..."), None)
let rec extern depth0 inctx scopes vars r = match succ_depth depth0 with
| None -> CAst.make ?loc:r.CAst.loc ellipsis
| Some depth -> match remove_one_coercion inctx (flatten_application r) with
| Some (nargs,inctx,r') ->
(try extern_notations depth inctx scopes vars (Some nargs) r with No_match -> extern depth0 inctx scopes vars r')
| None ->
let r' = match DAst.get r with
| GInt i when Rocqlib.has_ref "num.int63.wrap_int" -> let wrap = Rocqlib.lib_ref "num.int63.wrap_int"in
DAst.make (GApp (DAst.make (GRef (wrap, None)), [r]))
| GFloat f when Rocqlib.has_ref "num.float.wrap_float" -> let wrap = Rocqlib.lib_ref "num.float.wrap_float"in
DAst.make (GApp (DAst.make (GRef (wrap, None)), [r]))
| _ -> r in
try extern_notations depth inctx scopes vars None r' with No_match ->
let loc = r.CAst.loc in match DAst.get r with
| GRef (ref,us) when entry_has_global (fst (fst scopes)) -> CAst.make ?loc (extern_ref vars ref us)
| GVar id when entry_has_global (fst (fst scopes)) || entry_has_ident (fst (fst scopes)) ->
CAst.make ?loc (extern_var ?loc id)
| c ->
match availability_of_entry_coercion (fst (fst scopes)) constr_lowest_level with
| None -> raise No_match
| Some coercion ->
let scopes = ((constr_some_level, None), snd scopes) in let c = match c with
(* The remaining cases are only for the constr entry *)
| GRef (ref,us) -> extern_ref vars ref us
| GVar id -> extern_var ?loc id
| GEvar (n,[]) when !print_meta_as_hole -> CHole (None)
| GPatVar kind -> if !print_meta_as_hole then CHole (None) else
(match kind with
| Evar_kinds.SecondOrderPatVar n -> CPatVar n
| Evar_kinds.FirstOrderPatVar n -> CEvar (CAst.make n,[]))
| GApp (f,args) ->
(match DAst.get f with
| GRef (ref,us) -> let subscopes = find_arguments_scope refin let args = fill_arg_scopes args subscopes (snd scopes) in let args = extern_args (extern depth true) vars args in (* Try a "{|...|}" record notation *)
(match extern_record ref args with
| Some l -> CRecord l
| None -> (* Otherwise... *)
extern_applied_ref inctx
(select_stronger_impargs (implicits_of_global ref))
(ref,extern_reference ?loc (fst vars) ref) (extern_instance (snd vars) us) args)
| GProj (f,params,c) ->
extern_applied_proj depth inctx scopes vars f params c args
| _ -> let args = List.map (fun c -> (sub_extern depth true scopes vars c,None)) args in let head = sub_extern depth false scopes vars f in
mkFlattenedCApp (head,args))
| GProj (f,params,c) ->
extern_applied_proj depth inctx scopes vars f params c []
| GLetIn (na,_,b,t,c) ->
CLetIn (make ?loc na,
sub_extern depth (Option.has_some t) scopes vars b, Option.map (extern_typ depth scopes vars) t,
extern depth inctx scopes (add_vname vars na) c)
| GProd (na,r,bk,t,c) ->
factorize_prod depth scopes vars na r bk t c
| GLambda (na,r,bk,t,c) ->
factorize_lambda depth inctx scopes vars na r bk t c
| GCases (sty,rtntypopt,tml,eqns) -> let vars' = List.fold_right (Name.fold_right Id.Set.add)
(cases_predicate_names tml) (fst vars) in let vars' = vars', snd vars in let rtntypopt' = Option.map (extern_typ depth scopes vars') rtntypopt in let tml = List.map (fun (tm,(na,x)) -> let na' = match na, DAst.get tm with
| Anonymous, GVar id -> beginmatch rtntypopt with
| None -> None
| Some ntn -> if occur_glob_constr id ntn then
Some (CAst.make Anonymous) else None end
| Anonymous, _ -> None
| Name id, GVar id' when Id.equal id id' -> None
| Name _, _ -> Some (CAst.make na) in
(sub_extern depth false scopes vars tm,
na', Option.map (fun {CAst.loc;v=(ind,nal)} -> let args = List.map (fun x -> DAst.make @@ PatVar x) nal in let fullargs = add_cpatt_for_params ind args in
extern_ind_pattern_in_scope scopes (fst vars) ind fullargs
) x))
tml in let eqns = List.map (extern_eqn depth (inctx || rtntypopt <> None) scopes vars) (factorize_eqns eqns) in
CCases (sty,rtntypopt',tml,eqns)
| GLetTuple (nal,(na,typopt),tm,b) -> let inctx = inctx || typopt <> None in
CLetTuple (List.map CAst.make nal,
(Option.map (fun _ -> (make na)) typopt, Option.map (extern_typ depth scopes (add_vname vars na)) typopt),
sub_extern depth false scopes vars tm,
extern depth inctx scopes (List.fold_left add_vname vars nal) b)
| GIf (c,(na,typopt),b1,b2) -> let inctx = inctx || typopt <> None in
CIf (sub_extern depth false scopes vars c,
(Option.map (fun _ -> (CAst.make na)) typopt, Option.map (extern_typ depth scopes (add_vname vars na)) typopt),
sub_extern depth inctx scopes vars b1, sub_extern depth inctx scopes vars b2)
| GRec (fk,idv,blv,tyv,bv) -> let vars' = on_fst (Array.fold_right Id.Set.add idv) vars in
(match fk with
| GFix (nv,n) -> let listdecl =
Array.mapi (fun i fi -> let (bl,ty,def) = blv.(i), tyv.(i), bv.(i) in let bl = List.map (extended_glob_local_binder_of_decl ?loc) bl in let (assums,ids,bl) = extern_local_binder depth scopes vars bl in let vars0 = on_fst (List.fold_right (Name.fold_right Id.Set.add) ids) vars in let vars1 = on_fst (List.fold_right (Name.fold_right Id.Set.add) ids) vars' in let n = match nv.(i) with
| None -> None
| Some x -> Some (CAst.make @@ CStructRec (CAst.make @@ Name.get_id (List.nth assums x))) in
((CAst.make fi), None, n, bl, extern_typ depth scopes vars0 ty,
sub_extern depth true scopes vars1 def)) idv in
CFix (CAst.(make ?loc idv.(n)), Array.to_list listdecl)
| GCoFix n -> let listdecl =
Array.mapi (fun i fi -> let bl = List.map (extended_glob_local_binder_of_decl ?loc) blv.(i) in let (_,ids,bl) = extern_local_binder depth scopes vars bl in let vars0 = on_fst (List.fold_right (Name.fold_right Id.Set.add) ids) vars in let vars1 = on_fst (List.fold_right (Name.fold_right Id.Set.add) ids) vars' in
((CAst.make fi),None,bl,extern_typ depth scopes vars0 tyv.(i),
sub_extern depth true scopes vars1 bv.(i))) idv in
CCoFix (CAst.(make ?loc idv.(n)),Array.to_list listdecl))
| GSort s -> CSort (extern_glob_sort (snd vars) s)
| GHole e -> CHole (Some e)
| GGenarg arg -> CGenargGlob arg
| GCast (c, k, c') -> let scl = Notation.compute_glob_type_scope c' in let c' = extern_typ depth scopes vars c'in let c = extern depth true (fst scopes,(scl, snd (snd scopes))) vars c in
CCast (c, k, c')
| GArray(u,t,def,ty) ->
CArray(
extern_instance (snd vars) u,
Array.map (extern depth inctx scopes vars) t,
extern depth inctx scopes vars def,
extern_typ depth scopes vars ty)
in insert_entry_coercion coercion (CAst.make ?loc c)
and extern_typ depth (subentry,(_,scopes)) =
extern depth true (subentry,(Notation.current_type_scope_names (),scopes))
and sub_extern depth inctx (subentry,(_,scopes)) = extern depth inctx (subentry,([],scopes))
and factorize_prod depth scopes vars na r bk t c = let implicit_type = is_reserved_type na t in let r = extern_relevance_info (snd vars) r in let aty = extern_typ depth scopes vars t in let vars = add_vname vars na in let store, get = set_temporary_memory () in match na, DAst.get c with
| Name id, GCases (Constr.LetPatternStyle, None, [(e,(Anonymous,None))],(_::_ as eqns))
when is_gvar id e && List.length (store (factorize_eqns eqns)) = 1 ->
(match get () with
| [{CAst.v=(ids,disj_of_patl,b)}] -> let disjpat = List.map (function [pat] -> pat | _ -> assert false) disj_of_patl in let disjpat = if occur_glob_constr id b thenList.map (set_pat_alias id) disjpat else disjpat in let b = extern_typ depth scopes vars b in let p = mkCPatOr (List.map (extern_cases_pattern_in_scope scopes (fst vars)) disjpat) in let binder = CLocalPattern p in
(match b.v with
| CProdN (bl,b) -> CProdN (binder::bl,b)
| _ -> CProdN ([binder],b))
| _ -> assert false)
| _, _ -> let c' = extern_typ depth scopes vars c in match na, c'.v with
| Name id, CProdN (CLocalAssum(nal,r',Default bk',ty)::bl,b)
when relevance_info_expr_eq r r'
&& binding_kind_eq bk bk'
&& not (occur_var_constr_expr id ty) (* avoid na in ty escapes scope *)
&& (constr_expr_eq aty ty || (constr_expr_eq ty hole && same_binder_type t nal c)) -> let ty = if implicit_type then ty else aty in
CProdN (CLocalAssum(make na::nal,r,Default bk,ty)::bl,b)
| _, CProdN (bl,b) -> let ty = if implicit_type then hole else aty in
CProdN (CLocalAssum([make na],r,Default bk,ty)::bl,b)
| _, _ -> let ty = if implicit_type then hole else aty in
CProdN ([CLocalAssum([make na],r,Default bk,ty)],c')
and factorize_lambda depth inctx scopes vars na r bk t c = let implicit_type = is_reserved_type na t in let r = extern_relevance_info (snd vars) r in let aty = extern_typ depth scopes vars t in let vars = add_vname vars na in let store, get = set_temporary_memory () in match na, DAst.get c with
| Name id, GCases (Constr.LetPatternStyle, None, [(e,(Anonymous,None))],(_::_ as eqns))
when is_gvar id e && List.length (store (factorize_eqns eqns)) = 1 ->
(match get () with
| [{CAst.v=(ids,disj_of_patl,b)}] -> let disjpat = List.map (function [pat] -> pat | _ -> assert false) disj_of_patl in let disjpat = if occur_glob_constr id b thenList.map (set_pat_alias id) disjpat else disjpat in let b = sub_extern depth inctx scopes vars b in let p = mkCPatOr (List.map (extern_cases_pattern_in_scope scopes (fst vars)) disjpat) in let binder = CLocalPattern p in
(match b.v with
| CLambdaN (bl,b) -> CLambdaN (binder::bl,b)
| _ -> CLambdaN ([binder],b))
| _ -> assert false)
| _, _ -> let c' = sub_extern depth inctx scopes vars c in match c'.v with
| CLambdaN (CLocalAssum(nal,r',Default bk',ty)::bl,b)
when relevance_info_expr_eq r r'
&& binding_kind_eq bk bk'
&& not (occur_name na ty) (* avoid na in ty escapes scope *)
&& (constr_expr_eq aty ty || (constr_expr_eq ty hole && same_binder_type t nal c)) -> let aty = if implicit_type then ty else aty in
CLambdaN (CLocalAssum(make na::nal,r,Default bk,aty)::bl,b)
| CLambdaN (bl,b) -> let ty = if implicit_type then hole else aty in
CLambdaN (CLocalAssum([make na],r,Default bk,ty)::bl,b)
| _ -> let ty = if implicit_type then hole else aty in
CLambdaN ([CLocalAssum([make na],r,Default bk,ty)],c')
and extern_local_binder depth scopes vars = function
[] -> ([],[],[])
| b :: l -> match DAst.get b with
| GLocalDef (na,r,bd,ty) -> let (assums,ids,l) =
extern_local_binder depth scopes (on_fst (Name.fold_right Id.Set.add na) vars) l in
(assums,na::ids,
CLocalDef(CAst.make na, extern_relevance_info (snd vars) r, extern depth false scopes vars bd, Option.map (extern_typ depth scopes vars) ty) :: l)
| GLocalAssum (na,r,bk,ty) -> let implicit_type = is_reserved_type na ty in let ty = extern_typ depth scopes vars ty in
(match extern_local_binder depth scopes (on_fst (Name.fold_right Id.Set.add na) vars) l with
| (assums,ids,CLocalAssum(nal,r',k,ty')::l)
when (constr_expr_eq ty ty' || implicit_type && constr_expr_eq ty' hole) &&
binder_kind_eq k (Default bk) && match na with Name id -> not (occur_var_constr_expr id ty')
| _ -> true ->
(na::assums,na::ids,
CLocalAssum(CAst.make na::nal,r',k,ty')::l)
| (assums,ids,l) -> let ty = if implicit_type then hole else ty in
(na::assums,na::ids,
CLocalAssum([CAst.make na],extern_relevance_info (snd vars) r,Default bk,ty) :: l))
| GLocalPattern ((p,_),_,bk,ty) -> let ty = if !Flags.raw_print then Some (extern_typ depth scopes vars ty) else None in let p = mkCPatOr (List.map (extern_cases_pattern (fst vars)) p) in let (assums,ids,l) = extern_local_binder depth scopes vars l in let p = match ty with
| None -> p
| Some ty -> CAst.make @@ (CPatCast (p,ty)) in
(assums,ids, CLocalPattern p :: l)
and extern_eqn depth inctx scopes vars {CAst.loc;v=(ids,pll,c)} = let pll = List.map (List.map (extern_cases_pattern_in_scope scopes (fst vars))) pll in
make ?loc (pll,extern depth inctx scopes vars c)
and extern_notations depth inctx scopes vars nargs t = if !Flags.raw_print thenraise No_match; try extern_possible_prim_token scopes t with No_match -> if !print_no_symbol thenraise No_match; let t = flatten_application t in
extern_notation depth inctx scopes vars t (filter_enough_applied nargs (uninterp_notations t))
and extern_notation depth inctx ((custom,(lev_after: int option)),scopes as allscopes) vars t rules = match rules with
| [] -> raise No_match
| { not_rule = keyrule; not_patt = pat; not_status = n } :: rules -> let loc = Glob_ops.loc_of_glob_constr t in try if is_printing_inactive_rule keyrule pat thenraise No_match; let f,args = match DAst.get t with
| GApp (f,args) -> f,args
| _ -> t,[] in let nallargs = List.length args in let argsscopes,argsimpls = match DAst.get f with
| GRef (ref,_) -> let subscopes = find_arguments_scope refin let impls = select_stronger_impargs (implicits_of_global ref) in
subscopes, impls
| _ ->
[], [] in (* Adjust to the number of arguments expected by the notation *) let (t,args,argsscopes,argsimpls) = match n with
| AppBoundedNotation n when nallargs >= n -> let args1, args2 = List.chop n args in let args2scopes = tryList.skipn n argsscopes with Failure _ -> [] in let args2impls = if n = 0then (* Note: NApp(NRef f,[]), hence n=0, encodes @f and
conventionally deactivates implicit arguments *)
[] elsetryList.skipn n argsimpls with Failure _ -> [] in
DAst.make @@ GApp (f,args1), args2, args2scopes, args2impls
| AppUnboundedNotation -> t, [], [], []
| NotAppNotation -> beginmatch DAst.get f with
| GRef (ref,us) -> f, args, argsscopes, argsimpls
| _ -> t, [], [], [] end
| AppBoundedNotation _ -> raise No_match in (* Try matching ... *) let vars, uvars = vars in let terms,termlists,binders,binderlists =
match_notation_constr ~print_parentheses:!print_parentheses ~print_univ:(!print_universes)
t ~vars pat in let lev_after = ifList.is_empty args then lev_after else Some Notation.app_level in (* Try externing extra args... *) let extra_args = let args = fill_arg_scopes args argsscopes (snd allscopes) in let args = extern_args (extern depth true) (vars,uvars) args in try UseCApp (adjust_implicit_arguments inctx nallargs args argsimpls) with Expl -> UseCAppExpl args in (* Try availability of interpretation ... *) match keyrule with
| NotationRule (_,ntn as specific_ntn) -> let entry = fst (Notation.level_of_notation ntn) in let non_included = overlap_right_left entry lev_after pat in let coercion, appcoercion = find_entry_coercion_with_application ~non_included custom entry (is_empty_extra_args extra_args) in
(match availability_of_notation specific_ntn scopes with (* Uninterpretation is not allowed in current context *)
| None -> raise No_match (* Uninterpretation is allowed in current context *)
| Some (scopt,key) -> let closed = not (List.is_empty coercion) in let scopes' = Option.List.cons scopt (snd scopes) in let l = List.map (fun ((vars,c),subscope) -> let scopes = update_with_subscope entry subscope lev_after closed scopes' in
extern depth (* assuming no overloading: *) true scopes (vars,uvars) c)
terms in let ll = List.map (fun ((vars,l),subscope) -> let scopes = update_with_subscope entry subscope lev_after closed scopes' in List.map (extern depth true scopes (vars,uvars)) l)
termlists in let bl = List.map (fun ((vars,bl),subscope) -> let scopes = update_with_subscope entry subscope lev_after closed scopes' in
(mkCPatOr (List.map
(extern_cases_pattern_in_scope scopes vars) bl)),
Explicit)
binders in let bll = List.map (fun ((vars,bl),subscope) -> let scopes = update_with_subscope entry subscope lev_after closed scopes' in
pi3 (extern_local_binder depth scopes (vars,uvars) bl))
binderlists in let c = make_notation loc specific_ntn (l,ll,bl,bll) in let c = insert_entry_coercion coercion (insert_delimiters c key) in
insert_entry_coercion appcoercion (CAst.make ?loc @@ extern_applied_notation c extra_args))
| AbbrevRule kn -> let l = List.map (fun ((vars,c),(subentry,(scopt,scl))) ->
extern depth true ((subentry,lev_after),(scopt,scl@snd scopes)) (vars,uvars) c)
terms in let cf = Nametab.shortest_qualid_of_abbreviation ?loc vars kn in let a = CRef (cf,None) in let c = CAst.make ?loc @@ extern_applied_abbreviation (a,cf) l extra_args in if isCRef_no_univ c.CAst.v && entry_has_global custom then c elsematch availability_of_entry_coercion custom constr_lowest_level with
| None -> raise No_match
| Some coercion -> insert_entry_coercion coercion c with
No_match -> extern_notation depth inctx allscopes vars t rules
and extern_applied_proj depth inctx scopes vars (cst,us) params c extraargs = letref = GlobRef.ConstRef cst in let subscopes = find_arguments_scope refin let nparams = List.length params in let args = params @ c :: extraargs in let args = fill_arg_scopes args subscopes (snd scopes) in let args = extern_args (extern depth true) vars args in let imps = select_stronger_impargs (implicits_of_global ref) in let f = extern_reference (fst vars) refin let us = extern_instance (snd vars) us in
extern_projection inctx (f,us) nparams args imps
let extern inctx scopes vars c : constr_expr = extern (init_depth()) inctx scopes vars c
let extern_glob_constr vars c =
extern false ((constr_some_level,None),([],[])) vars c
let extern_glob_type ?impargs vars c = let c = Option.fold_right insert_impargs impargs c in
extern_typ (init_depth()) ((constr_some_level,None),([],[])) vars c
(******************************************************************) (* Main translation function from constr -> constr_expr *)
let extern_constr ?(inctx=false) ?scope env sigma t = let r = Detyping.detype Detyping.Later env sigma t in let vars = extern_env env sigma in let scope = Option.cata (fun x -> [x]) [] scope in
extern inctx ((constr_some_level,None),(scope,[])) vars r
let extern_constr_in_scope ?inctx scope env sigma t =
extern_constr ?inctx ~scope env sigma t
let make_avoid goal_concl_style env = if goal_concl_style then (Namegen.Generator.fresh, Fresh.of_set @@ vars_of_env env) (* TODO: this is linear in the size of the environment, maybe we can do better *) else (Namegen.Generator.fresh, Nameops.Fresh.empty)
let extern_type ?(goal_concl_style=false) env sigma ?impargs t = (* "goal_concl_style" means do alpha-conversion using the "goal" convention *) (* i.e.: avoid using the names of goal/section/rel variables and the short *) (* names of global definitions of current module when computing names for *) (* bound variables. *) (* Not "goal_concl_style" means do alpha-conversion avoiding only *) (* those goal/section/rel variables that occurs in the subterm under *) (* consideration; see namegen.ml for further details *) let avoid = make_avoid goal_concl_style env in let r = Detyping.detype Detyping.Later ~isgoal:goal_concl_style ~avoid env sigma t in
extern_glob_type ?impargs (extern_env env sigma) r
let extern_sort sigma s = extern_glob_sort (Evd.universe_binders sigma) (detype_sort sigma s)
let extern_closed_glob ?(goal_concl_style=false) ?(inctx=false) ?scope env sigma t = let avoid = make_avoid goal_concl_style env in let r =
Detyping.detype_closed_glob ~isgoal:goal_concl_style ~avoid env sigma t in let vars = extern_env env sigma in let scope = Option.cata (fun x -> [x]) [] scope in
extern inctx ((constr_some_level,None),(scope,[])) vars r
(******************************************************************) (* Main translation function from pattern -> constr_expr *)
let next_name_away na (gen, avoid) = let (id, avoid) = Namegen.Generator.next_name_away gen na avoid in
(id, (gen, avoid))
let compute_displayed_let_name_in env sigma flags (gen, avoid) na = letopen Namegen in let na, avoid = compute_displayed_let_name_in gen env sigma flags avoid na in
na, (gen, avoid)
let compute_displayed_name_in_pattern env sigma (gen, avoid) na c = letopen Namegen in let na, avoid = compute_displayed_name_in_gen gen (fun _ -> Patternops.noccurn_pattern) env sigma avoid na c in
na, (gen, avoid)
let glob_of_pat_under_context glob_of_pat avoid env sigma (nas, pat) = let fold (avoid, env, nas, epat) na = let na, avoid = compute_displayed_name_in_pattern (Global.env ()) sigma avoid na epat in let env = Termops.add_name na env in let epat = match epat with PLambda (_, _, p) -> p | _ -> assert falsein
(avoid, env, na :: nas, epat) in let epat = Array.fold_right (fun na p -> PLambda (na, PMeta None, p)) nas pat in let (avoid', env', nas, _) = Array.fold_left fold (avoid, env, [], epat) nas in let pat = glob_of_pat avoid' env' sigma pat in
(Array.rev_of_list nas, pat)
let rec glob_of_pat
: 'a 's. 's Namegen.Generator.input -> _ -> _ -> 'a constr_pattern_r -> _
= fun (type a s) (avoid : s Namegen.Generator.t * s) env sigma (pat: a constr_pattern_r) -> letopen Sorts.Quality in
DAst.make @@ match pat with
| PRef ref -> GRef (ref,None)
| PVar id -> GVar id
| PEvar (evk,l) -> letfilter (id, pat) = match pat with PVar id' -> Id.equal id id' | _ -> truein let EvarInfo evi = Evd.find sigma evk in let hyps = Evd.evar_filtered_context evi in letmap decl pat = NamedDecl.get_id decl, pat in let l = List.filterfilter @@ List.map2 map hyps l in let id = match Evd.evar_ident evk sigma with
| None -> Id.of_string "__"
| Some id -> id in
GEvar (CAst.make id,List.map (fun (id,c) -> (CAst.make id, glob_of_pat avoid env sigma c)) l)
| PRel n -> let id = trymatch lookup_name_of_rel n env with
| Name id -> id
| Anonymous ->
anomaly ~label:"glob_constr_of_pattern" (Pp.str "index to an anonymous variable.") with Not_found -> Id.of_string ("_UNBOUND_REL_"^(string_of_int n)) in
GVar id
| PMeta None -> GHole (GInternalHole)
| PMeta (Some n) -> GPatVar (Evar_kinds.FirstOrderPatVar n)
| PUninstantiated (PGenarg g) -> GGenarg g
| PProj (p,c) -> GApp (DAst.make @@ GRef (GlobRef.ConstRef (Projection.constant p),None),
[glob_of_pat avoid env sigma c])
| PApp (f,args) ->
GApp (glob_of_pat avoid env sigma f,Array.map_to_list (glob_of_pat avoid env sigma) args)
| PSoApp (n,args) ->
GApp (DAst.make @@ GPatVar (Evar_kinds.SecondOrderPatVar n), List.map (glob_of_pat avoid env sigma) args)
| PProd (na,t,c) -> let na',avoid' = compute_displayed_name_in_pattern (Global.env ()) sigma avoid na c in let env' = Termops.add_name na' env in
GProd (na',None,Explicit,glob_of_pat avoid env sigma t,glob_of_pat avoid' env' sigma c)
| PLetIn (na,b,t,c) -> let na',avoid' = compute_displayed_let_name_in (Global.env ()) sigma Namegen.RenamingForGoal avoid na in let env' = Termops.add_name na' env in
GLetIn (na',None,glob_of_pat avoid env sigma b, Option.map (glob_of_pat avoid env sigma) t,
glob_of_pat avoid' env' sigma c)
| PLambda (na,t,c) -> let na',avoid' = compute_displayed_name_in_pattern (Global.env ()) sigma avoid na c in let env' = Termops.add_name na' env in
GLambda (na',None,Explicit,glob_of_pat avoid env sigma t, glob_of_pat avoid' env' sigma c)
| PIf (c,b1,b2) ->
GIf (glob_of_pat avoid env sigma c, (Anonymous,None),
glob_of_pat avoid env sigma b1, glob_of_pat avoid env sigma b2)
| PCase ({cip_style=Constr.LetStyle},None,tm,[(0,n,b)]) -> let n, b = glob_of_pat_under_context glob_of_pat avoid env sigma (n, b) in let nal = Array.to_list n in
GLetTuple (nal,(Anonymous,None),glob_of_pat avoid env sigma tm,b)
| PCase (info,p,tm,bl) -> let mat = match bl, info.cip_ind with
| [], _ -> []
| _, Some ind -> letmap (i, n, c) = let n, c = glob_of_pat_under_context glob_of_pat avoid env sigma (n, c) in let nal = Array.to_list n in let mkPatVar na = DAst.make @@ PatVar na in let p = DAst.make @@ PatCstr ((ind,i+1),List.map mkPatVar nal,Anonymous) in let ids = List.map_filter Nameops.Name.to_option nal in
CAst.make @@ (ids,[p],c) in List.mapmap bl
| _, None -> anomaly (Pp.str "PCase with some branches but unknown inductive.") in let mat = if info.cip_extensible then mat @ [any_any_branch] else mat in let indnames,rtn = match p, info.cip_ind with
| None, _ -> (Anonymous,None),None
| Some p, Some ind -> let nas, p = glob_of_pat_under_context glob_of_pat avoid env sigma p in let nas = Array.rev_to_list nas in
((List.hd nas, Some (CAst.make (ind, List.tl nas))), Some p)
| _ -> anomaly (Pp.str "PCase with non-trivial predicate but unknown inductive.") in
GCases (Constr.RegularStyle,rtn,[glob_of_pat avoid env sigma tm,indnames],mat)
| PFix ((ln,i),(lna,tl,bl)) -> let def_avoid, def_env, lfi =
Array.fold_left
(fun (avoid, env, l) na -> let id, avoid = next_name_away na avoid in
(avoid, Name id :: env, id::l))
(avoid, env, []) lna in let n = Array.length tl in let v = Array.map3
(fun c t i -> Detyping.share_pattern_names glob_of_pat (i+1) [] def_avoid def_env sigma c (Patternops.lift_pattern n t))
bl tl ln in
GRec(GFix (Array.map (fun i -> Some i) ln,i),Array.of_list (List.rev lfi),
Array.map (fun (bl,_,_) -> bl) v,
Array.map (fun (_,_,ty) -> ty) v,
Array.map (fun (_,bd,_) -> bd) v)
| PCoFix (ln,(lna,tl,bl)) -> let def_avoid, def_env, lfi =
Array.fold_left
(fun (avoid, env, l) na -> let id, avoid = next_name_away na avoid in
(avoid, Name id :: env, id::l))
(avoid, env, []) lna in let ntys = Array.length tl in let v = Array.map2
(fun c t -> share_pattern_names glob_of_pat 0 [] def_avoid def_env sigma c (Patternops.lift_pattern ntys t))
bl tl in
GRec(GCoFix ln,Array.of_list (List.rev lfi),
Array.map (fun (bl,_,_) -> bl) v,
Array.map (fun (_,_,ty) -> ty) v,
Array.map (fun (_,bd,_) -> bd) v)
| PSort (Qual (QConstant QSProp)) -> GSort Glob_ops.glob_SProp_sort
| PSort (Qual (QConstant QProp)) -> GSort Glob_ops.glob_Prop_sort
| PSort (Qual (QConstant QType | QVar _)) -> GSort Glob_ops.glob_Type_sort
| PSort Set -> GSort Glob_ops.glob_Set_sort
| PInt i -> GInt i
| PFloat f -> GFloat f
| PString s -> GString s
| PArray(t,def,ty) -> let glob_of = glob_of_pat avoid env sigma in
GArray (None, Array.map glob_of t, glob_of def, glob_of ty)
let extern_constr_pattern env sigma pat =
extern true ((constr_some_level,None),([],[])) (* XXX no vars? *)
(Id.Set.empty, Evd.universe_binders sigma)
(glob_of_pat (genset, Id.Set.empty) env sigma pat)
let extern_rel_context where env sigma sign = let a = detype_rel_context Detyping.Later where ([],env) sigma sign in let vars = extern_env env sigma in let a = List.map (extended_glob_local_binder_of_decl) a in
pi3 (extern_local_binder (init_depth()) ((constr_some_level,None),([],[])) vars a)
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.42 Sekunden
(vorverarbeitet am 2026-09-28)
¤
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 und die Messung sind noch experimentell.