(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
open Util open Names open Constr open EConstr open Namegen open Tactypes open Genarg open Stdarg open Tacarg open Geninterp open Pp
exception CannotCoerceTo ofstring
let pr_argument_type arg = letVal.Dyn (tag, _) = arg in Val.pr tag
(** TODO: unify printing of generic Ltac values in case of coercion failure. *)
(* Displays a value *) let pr_value env v = let ppty = spc() ++ str "of type" ++ spc () ++ pr_argument_type v in let pr_with_env pr = match env with
| Some (env,sigma) -> pr env sigma ++ ppty
| None -> str "a value" ++ ppty in letopen Genprint in match generic_val_print v with
| TopPrinterBasic pr -> pr () ++ ppty
| TopPrinterNeedsContext pr -> pr_with_env pr
| TopPrinterNeedsContextAndLevel { default_already_surrounded; printer } ->
pr_with_env (fun env sigma -> printer env sigma default_already_surrounded)
(** Abstract application, to print ltac functions *) type appl =
| UnnamedAppl (** For generic applications: nothing is printed *)
| GlbAppl of (Names.KerName.t * Val.t list) list (** For calls to global constants, some may alias other. *)
(* Values for interpretation *) type tacvalue =
| VFun of
appl *
Tacexpr.ltac_trace *
Loc.t option * (* when executing a global Ltac function: the location where this function was called *) Val.t Id.Map.t * (* closure *)
Name.t list * (* binders *)
Tacexpr.glob_tactic_expr (* body *)
| VRec ofVal.t Id.Map.t ref * Tacexpr.glob_tactic_expr
let tacvalue_tag : tacvalue Val.typ = let tag = Val.create "tacvalue"in let pr = function
| VFun (a,_,loc,ids,l,tac) -> let tac = ifList.is_empty l then tac else CAst.make ?loc @@ Tacexpr.TacFun (l,tac) in let pr_env env sigma = if Id.Map.is_empty ids then mt () else cut () ++ str "where" ++ Id.Map.fold (fun id c pp -> cut () ++ Id.print id ++ str " := " ++ pr_value (Some (env,sigma)) c ++ pp) ids (mt ()) in
Genprint.TopPrinterNeedsContext (fun env sigma -> v 0 (hov 0 (Pptactic.pr_glob_tactic env tac) ++ pr_env env sigma))
| _ -> Genprint.TopPrinterBasic (fun _ -> str "") in let () = Genprint.register_val_print0 tag pr in
tag
let constr_context_tag : Constr_matching.context Val.typ = let tag = Val.create "constr_context"in let pr env sigma lev c : Pp.t = Printer.pr_econstr_n_env env sigma lev (Constr_matching.repr_context c) in let () = Genprint.register_val_print0 tag (Pptactic.make_constr_printer pr) in
tag
(* includes idents known to be bound and references *) let constr_under_binders_tag : Ltac_pretype.constr_under_binders Val.typ = let tag = Val.create "constr_under_binders"in let () = Genprint.register_val_print0 tag (fun c ->
Genprint.TopPrinterNeedsContext (fun env sigma -> Printer.pr_constr_under_binders_env env sigma c)) in
tag
(** All the types considered here are base types *) let val_tag wit = match val_tag wit with
| Val.Base t -> t
| _ -> assert false
let has_type : type a. Val.t -> a typed_abstract_argument_type -> bool = fun v wit -> letVal.Dyn (t, _) = v in matchVal.eq t (val_tag wit) with
| None -> false
| Some Refl -> true
let prj : type a. a Val.typ -> Val.t -> a option = fun t v -> letVal.Dyn (t', x) = v in matchVal.eq t t' with
| None -> None
| Some Refl -> Some x
let in_gen wit v = Val.Dyn (val_tag wit, v) let out_gen wit v = match prj (val_tag wit) v with None -> assert false | Some x -> x
module Value = struct
type t = Val.t
let of_tacvalue v = Val.Dyn (tacvalue_tag, v)
let to_tacvalue v = prj tacvalue_tag v
let of_constr c = in_gen (topwit wit_constr) c
let to_constr v = if has_type v (topwit wit_constr) then let c = out_gen (topwit wit_constr) v in
Some c elsematch prj constr_under_binders_tag v with
| Some (vars, c) -> beginmatch vars with [] -> Some c | _ -> None end
| None -> None
let of_uconstr c = in_gen (topwit wit_uconstr) c
let to_uconstr v = if has_type v (topwit wit_uconstr) then
Some (out_gen (topwit wit_uconstr) v) else None
let of_constr_context v = Val.Dyn (constr_context_tag, v)
let to_constr_context v = prj constr_context_tag v
(* XXX should we do [of_constr] when the vars are empty? *) let of_constr_under_binders v = Val.Dyn (constr_under_binders_tag, v)
let of_int i = in_gen (topwit wit_int) i
let to_int v = if has_type v (topwit wit_int) then
Some (out_gen (topwit wit_int) v) else None
let of_ident id = in_gen (topwit wit_ident) id
let to_ident v = if has_type v (topwit wit_ident) then
Some (out_gen (topwit wit_ident) v) else None
let to_list v = prj Val.typ_list v
let to_option v = prj Val.typ_opt v
let to_pair v = prj Val.typ_pair v
let cast_error wit v = let pr_v = Pptactic.pr_value Pptactic.ltop v in letVal.Dyn (tag, _) = v in let tag = Val.pr tag in
CErrors.user_err (str "Type error: value " ++ pr_v ++ str " is a " ++ tag
++ str " while type " ++ Val.pr wit ++ str " was expected.")
let unbox wit v ans = match ans with
| None -> cast_error wit v
| Some x -> x
let rec prj : type a. a Val.tag -> Val.t -> a = fun tag v -> match tag with
| Val.List tag -> List.map (fun v -> prj tag v) (unbox Val.typ_list v (to_list v))
| Val.Opt tag -> Option.map (fun v -> prj tag v) (unbox Val.typ_opt v (to_option v))
| Val.Pair (tag1, tag2) -> let (x, y) = unbox Val.typ_pair v (to_pair v) in
(prj tag1 x, prj tag2 y)
| Val.Base t -> letVal.Dyn (t', x) = v in matchVal.eq t t' with
| None -> cast_error t v
| Some Refl -> x let rec tag_of_arg : type a b c. (a, b, c) genarg_type -> c Val.tag = fun wit -> match wit with
| ExtraArg _ -> Geninterp.val_tag (topwit wit)
| ListArg t -> Val.List (tag_of_arg t)
| OptArg t -> Val.Opt (tag_of_arg t)
| PairArg (t1, t2) -> Val.Pair (tag_of_arg t1, tag_of_arg t2)
let val_cast arg v = prj (tag_of_arg arg) v
let cast (Topwit wit) v = val_cast wit v
end
let is_variable env id =
Id.List.mem id (Termops.ids_of_named_context (Environ.named_context env))
(* Transforms an id into a constr if possible, or fails with Not_found *) let constr_of_id env id =
EConstr.mkVar (let _ = Environ.lookup_named id env in id)
(* Gives the Value.t corresponding to a Constr_context tactic_arg *) let coerce_to_constr_context v = match Value.to_constr_context v with
| Some v -> v
| None -> raise (CannotCoerceTo "a term context")
let is_intro_pattern v = if has_type v (topwit wit_intro_pattern) then
Some (out_gen (topwit wit_intro_pattern) v).CAst.v else
None
(* Interprets an identifier which must be fresh *) let coerce_var_to_ident fresh env sigma v = let fail () = raise (CannotCoerceTo "a fresh identifier") in match is_intro_pattern v with
| Some (IntroNaming (IntroIdentifier id)) -> id
| Some _ -> fail ()
| None -> if has_type v (topwit wit_intro_pattern) then match out_gen (topwit wit_intro_pattern) v with
| { CAst.v=IntroNaming (IntroIdentifier id)} -> id
| _ -> fail () elseif has_type v (topwit wit_hyp) then
out_gen (topwit wit_hyp) v elsematch Value.to_constr v with
| None -> fail ()
| Some c -> (* We need it fresh for intro e.g. in "Tac H = clear H; intro H" *) if isVar sigma c && not (fresh && is_variable env (destVar sigma c)) then
destVar sigma c else fail ()
(* Interprets, if possible, a constr to an identifier which may not be fresh but suitable to be given to the fresh tactic. Works for
vars, constants, inductive, constructors and sorts. *) let coerce_to_ident_not_fresh sigma v = let fail () = raise (CannotCoerceTo "an identifier") in match is_intro_pattern v with
| Some (IntroNaming (IntroIdentifier id)) -> id
| Some _ -> fail ()
| None -> if has_type v (topwit wit_hyp) then
out_gen (topwit wit_hyp) v else match Value.to_constr v with
| None -> fail ()
| Some c -> match EConstr.kind sigma c with
| Var id -> id
| Meta m -> Id.of_string "x"
| Evar (kn,_) -> beginmatch Evd.evar_ident kn sigma with
| None -> fail ()
| Some id -> id end
| Const (cst,_) -> Label.to_id (Constant.label cst)
| Construct (cstr,_) -> letref = GlobRef.ConstructRef cstr in let basename = Nametab.basename_of_global refin
basename
| Ind (ind,_) -> letref = GlobRef.IndRef ind in let basename = Nametab.basename_of_global refin
basename
| Sort s -> begin match ESorts.kind sigma s with
| Sorts.SProp -> Label.to_id (Label.make "SProp")
| Sorts.Prop -> Label.to_id (Label.make "Prop")
| Sorts.Set -> Label.to_id (Label.make "Set")
| Sorts.Type _ | Sorts.QSort _ -> Label.to_id (Label.make "Type") end
| _ -> fail()
let coerce_to_intro_pattern sigma v = match is_intro_pattern v with
| Some pat -> pat
| None -> if has_type v (topwit wit_hyp) then let id = out_gen (topwit wit_hyp) v in
IntroNaming (IntroIdentifier id) elsematch Value.to_constr v with
| Some c when isVar sigma c -> (* This happens e.g. in definitions like "Tac H = clear H; intro H" *) (* but also in "destruct H as (H,H')" *)
IntroNaming (IntroIdentifier (destVar sigma c))
| _ -> raise (CannotCoerceTo "an introduction pattern")
let coerce_to_intro_pattern_naming sigma v = match coerce_to_intro_pattern sigma v with
| IntroNaming pat -> pat
| _ -> raise (CannotCoerceTo "a naming introduction pattern")
let coerce_to_hint_base v = match is_intro_pattern v with
| Some (IntroNaming (IntroIdentifier id)) -> Id.to_string id
| Some _ | None -> raise (CannotCoerceTo "a hint base name")
let coerce_to_int v = if has_type v (topwit wit_int) then
out_gen (topwit wit_int) v elseraise (CannotCoerceTo "an integer")
let coerce_to_constr env v = let fail () = raise (CannotCoerceTo "a term") in match is_intro_pattern v with
| Some (IntroNaming (IntroIdentifier id)) ->
(try ([], constr_of_id env id) with Not_found -> fail ())
| Some _ -> fail ()
| None -> if has_type v (topwit wit_constr) then let c = out_gen (topwit wit_constr) v in
([], c) elsematch prj constr_under_binders_tag v with
| Some v -> v
| None -> if has_type v (topwit wit_hyp) then let id = out_gen (topwit wit_hyp) v in
(try [], constr_of_id env id with Not_found -> fail ()) else fail ()
let coerce_to_uconstr v = if has_type v (topwit wit_uconstr) then
out_gen (topwit wit_uconstr) v else raise (CannotCoerceTo "an untyped term")
let coerce_to_closed_constr env v = let ids,c = coerce_to_constr env v in let () = ifnot (List.is_empty ids) thenraise (CannotCoerceTo "a term") in
c
let coerce_to_evaluable_ref env sigma v = letopen Evaluable in let fail () = raise (CannotCoerceTo "an evaluable reference") in let ev = match is_intro_pattern v with
| Some (IntroNaming (IntroIdentifier id)) when is_variable env id -> EvalVarRef id
| Some _ -> fail ()
| None -> if has_type v (topwit wit_hyp) then let id = out_gen (topwit wit_hyp) v in if Id.List.mem id (Termops.ids_of_context env) then EvalVarRef id else fail () elseif has_type v (topwit wit_ref) then letopen GlobRef in let r = out_gen (topwit wit_ref) v in match r with
| VarRef var -> EvalVarRef var
| ConstRef c -> EvalConstRef c
| IndRef _ | ConstructRef _ -> fail () elseif has_type v (topwit wit_smart_global) then letopen GlobRef in let r = out_gen (topwit wit_smart_global) v in match r with
| VarRef var -> EvalVarRef var
| ConstRef c -> EvalConstRef c
| IndRef _ | ConstructRef _ -> fail () else match Value.to_constr v with
| Some c when isConst sigma c -> EvalConstRef (fst (destConst sigma c))
| Some c when isVar sigma c -> EvalVarRef (destVar sigma c)
| _ -> fail () inif Tacred.is_evaluable env ev then ev else fail ()
let coerce_to_constr_list env v = let v = Value.to_list v in match v with
| Some l -> letmap v = coerce_to_closed_constr env v in List.mapmap l
| None -> raise (CannotCoerceTo "a term list")
let coerce_to_intro_pattern_list ?loc sigma v = match Value.to_list v with
| None -> raise (CannotCoerceTo "an intro pattern list")
| Some l -> letmap v = CAst.make ?loc @@ coerce_to_intro_pattern sigma v in List.mapmap l
let coerce_to_hyp env sigma v = let fail () = raise (CannotCoerceTo "a variable") in match is_intro_pattern v with
| Some (IntroNaming (IntroIdentifier id)) when is_variable env id -> id
| Some _ -> fail ()
| None -> if has_type v (topwit wit_hyp) then let id = out_gen (topwit wit_hyp) v in if is_variable env id then id else fail () elsematch Value.to_constr v with
| Some c when isVar sigma c -> destVar sigma c
| _ -> fail ()
let coerce_to_hyp_list env sigma v = let v = Value.to_list v in match v with
| Some l -> letmap n = coerce_to_hyp env sigma n in List.mapmap l
| None -> raise (CannotCoerceTo "a variable list")
(* Interprets a qualified name *) let coerce_to_reference sigma v = match Value.to_constr v with
| Some c -> begin try fst (EConstr.destRef sigma c) with DestKO -> raise (CannotCoerceTo "a reference") end
| None -> raise (CannotCoerceTo "a reference")
(* Quantified named or numbered hypothesis or hypothesis in context *) (* (as in Inversion) *) let coerce_to_quantified_hypothesis sigma v = match is_intro_pattern v with
| Some (IntroNaming (IntroIdentifier id)) -> NamedHyp (CAst.make id)
| Some _ -> raise (CannotCoerceTo "a quantified hypothesis")
| None -> if has_type v (topwit wit_hyp) then let id = out_gen (topwit wit_hyp) v in
NamedHyp (CAst.make id) elseif has_type v (topwit wit_int) then
AnonHyp (out_gen (topwit wit_int) v) elsematch Value.to_constr v with
| Some c when isVar sigma c -> NamedHyp (CAst.make @@ destVar sigma c)
| _ -> raise (CannotCoerceTo "a quantified hypothesis")
(* Quantified named or numbered hypothesis or hypothesis in context *) (* (as in Inversion) *) let coerce_to_decl_or_quant_hyp sigma v = if has_type v (topwit wit_int) then
AnonHyp (out_gen (topwit wit_int) v) else try coerce_to_quantified_hypothesis sigma v with CannotCoerceTo _ -> raise (CannotCoerceTo "a declared or quantified hypothesis")
let coerce_to_int_list v = match Value.to_list v with
| None -> raise (CannotCoerceTo "an int list")
| Some l -> List.map coerce_to_int l
let () = CErrors.register_handler begin function
| CoercionError (id, env, v, s) ->
Some (str "Ltac variable " ++ Id.print id ++
strbrk " is bound to" ++ spc () ++ pr_value env v ++ spc () ++
strbrk "which cannot be coerced to " ++ str s ++ str".")
| _ -> None end
let error_ltac_variable ?loc id env v s =
Loc.raise ?loc (CoercionError (id, env, v, s))
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 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 und die Messung sind noch experimentell.