(************************************************************************) (* * 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] is on then [print_implicits_explicit_args] tells how implicit args are printed. If on, implicit args are printed with the form (id:=arg) otherwise arguments are printed normally and
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. For instance, in the debugger the tables of global references
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 (" ^ 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 (" ^ 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 (" ^ 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 0 then 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 + 1 in 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 0 then 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) notations on [a] work; should be compatible since printer does not care whether App's are collapsed or not and notations with an implicit coercion using funclass either would have already been confused with ordinary application or would have need a surrounding context and the coercion to funclass would
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 the coercion is fully applied; not explicitly done yet, but we could also expect that the notation is exactly talking about the
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.
Strictly speaking we will print an ellipsis for everything which has bigger extern depth and everything which has bigger Pp box depth than the limit, but in practice extern depth is always smaller than box depth.
As such extern depth acts as an optimization to avoid work on
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 = 0 then (* 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)
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.35 Sekunden
(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.