aboutsummaryrefslogtreecommitdiffhomepage
path: root/tactics/tacinterp.ml
diff options
context:
space:
mode:
Diffstat (limited to 'tactics/tacinterp.ml')
-rw-r--r--tactics/tacinterp.ml1738
1 files changed, 1738 insertions, 0 deletions
diff --git a/tactics/tacinterp.ml b/tactics/tacinterp.ml
new file mode 100644
index 000000000..2d8f7c904
--- /dev/null
+++ b/tactics/tacinterp.ml
@@ -0,0 +1,1738 @@
+(***********************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
+(* \VV/ *************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(***********************************************************************)
+
+(* $Id$ *)
+
+open Astterm
+open Closure
+open RedFlags
+open Declarations
+open Dyn
+open Libobject
+open Pattern
+open Pp
+open Rawterm
+open Sign
+open Tacred
+open Util
+open Names
+open Nameops
+open Nametab
+open Pfedit
+open Proof_type
+open Refiner
+open Tacmach
+open Tactic_debug
+open Coqast
+open Ast
+open Term
+open Termops
+open Declare
+open Tacexpr
+open Safe_typing
+open Typing
+open Hiddentac
+open Genarg
+
+let err_msg_tactic_not_found macro_loc macro =
+ user_err_loc
+ (macro_loc,"macro_expand",
+ (str "Tactic macro " ++ str macro ++ spc () ++ str "not found"))
+
+let error_syntactic_metavariables_not_allowed loc =
+ user_err_loc
+ (loc,"out_ident",
+ str "Syntactic metavariables allowed only in quotations")
+
+let skip_metaid = function
+ | AI x -> x
+ | MetaId (loc,_) -> error_syntactic_metavariables_not_allowed loc
+
+(* Values for interpretation *)
+type value =
+ | VClosure of interp_sign * raw_tactic_expr
+ | VTactic of tactic (* For mixed ML/Ltac tactics (e.g. Tauto) *)
+ | VFTactic of value list * (value list->tactic)
+ | VRTactic of (goal list sigma * validation)
+ | VContext of interp_sign * direction_flag
+ * (pattern_ast,raw_tactic_expr) match_rule list
+ | VFun of (identifier * value) list * identifier option list *raw_tactic_expr
+ | VVoid
+ | VInteger of int
+ | VIdentifier of identifier (* idents which are not refs, as in "Intro H" *)
+ | VConstr of constr
+ | VConstr_context of constr
+ | VRec of value ref
+
+(* Signature for interpretation: val_interp and interpretation functions *)
+and interp_sign =
+ { evc : Evd.evar_map;
+ env : Environ.env;
+ lfun : (identifier * value) list;
+ lmatch : (int * constr) list;
+ goalopt : goal sigma option;
+ debug : debug_info }
+
+(* For tactic_of_value *)
+exception NotTactic
+
+(* Gives the constr corresponding to a Constr tactic_arg *)
+let constr_of_VConstr = function
+ | VConstr c -> c
+ | _ -> anomalylabstrm "constr_of_VConstr" (str "Not a Constr tactic_arg")
+
+(* Gives the constr corresponding to a Constr_context tactic_arg *)
+let constr_of_VConstr_context = function
+ | VConstr_context c -> c
+ | _ ->
+ anomalylabstrm "constr_of_VConstr_context" (str
+ "Not a Constr_context tactic_arg")
+
+(*
+(* Gives identifiers and makes the possible injection constr -> ident *)
+let make_ids ast = function
+ | Identifier id -> id
+ | Constr c ->
+ (try destVar c with
+ | Invalid_argument "destVar" ->
+ anomalylabstrm "make_ids"
+ (str "This term cannot be reduced to an identifier" ++ fnl () ++
+ print_ast ast))
+ | _ -> anomalylabstrm "make_ids" (str "Not an identifier")
+*)
+
+let pr_value env = function
+ | VVoid -> str "()"
+ | VInteger n -> int n
+ | VIdentifier id -> pr_id id
+ | VConstr c -> Printer.prterm_env env c
+ | VConstr_context c -> Printer.prterm_env env c
+ | (VClosure _ | VTactic _ | VFTactic _ | VRTactic _ |
+ VContext _ | VFun _ | VRec _) -> str "<fun>"
+
+(* Transforms a named_context into a (string * constr) list *)
+let make_hyps = List.map (fun (id,_,typ) -> (id,body_of_type typ))
+
+(* Transforms an id into a constr if possible *)
+let constr_of_id ist id =
+ match ist.goalopt with
+ | None -> construct_reference ist.env id
+ | Some goal ->
+ let hyps = pf_hyps goal in
+ if mem_named_context id hyps then
+ mkVar id
+ else
+ let csr = global_qualified_reference (make_short_qualid id) in
+ (match kind_of_term csr with
+ | Var _ -> raise Not_found
+ | _ -> csr)
+
+(* To embed several objects in Coqast.t *)
+let ((tactic_in : (interp_sign -> raw_tactic_expr) -> Dyn.t),
+ (tactic_out : Dyn.t -> (interp_sign -> raw_tactic_expr))) =
+ create "tactic"
+
+let ((value_in : value -> Dyn.t),
+ (value_out : Dyn.t -> value)) = create "value"
+
+let tacticIn t = TacArg (TacDynamic (dummy_loc,tactic_in t))
+let tacticOut = function
+ | TacArg (TacDynamic (_,d)) ->
+ if (tag d) = "tactic" then
+ tactic_out d
+ else
+ anomalylabstrm "tacticOut" (str "Dynamic tag should be tactic")
+ | ast ->
+ anomalylabstrm "tacticOut"
+ (str "Not a Dynamic ast: " (* ++ print_ast ast*) )
+
+let valueIn t = TacDynamic (dummy_loc,value_in t)
+let valueOut = function
+ | TacDynamic (_,d) ->
+ if (tag d) = "value" then
+ value_out d
+ else
+ anomalylabstrm "valueOut" (str "Dynamic tag should be value")
+ | ast ->
+ anomalylabstrm "valueOut"
+ (str "Not a Dynamic ast: " (* ++ print_ast ast*) )
+
+let constrIn c = constrIn c
+let constrOut = constrOut
+
+let loc = dummy_loc
+
+(* Table of interpretation functions *)
+let interp_tab =
+ (Hashtbl.create 17 : (string , interp_sign -> Coqast.t -> value) Hashtbl.t)
+
+(* Adds an interpretation function *)
+let interp_add (ast_typ,interp_fun) =
+ try
+ Hashtbl.add interp_tab ast_typ interp_fun
+ with
+ Failure _ ->
+ errorlabstrm "interp_add"
+ (str "Cannot add the interpretation function for " ++ str ast_typ ++ str " twice")
+
+(* Adds a possible existing interpretation function *)
+let overwriting_interp_add (ast_typ,interp_fun) =
+ if Hashtbl.mem interp_tab ast_typ then
+ begin
+ Hashtbl.remove interp_tab ast_typ;
+ warning ("Overwriting definition of tactic interpreter command " ^ ast_typ)
+ end;
+ Hashtbl.add interp_tab ast_typ interp_fun
+
+(* Finds the interpretation function corresponding to a given ast type *)
+let look_for_interp = Hashtbl.find interp_tab
+
+(* Globalizes the identifier *)
+
+let find_reference ist qid =
+ (* We first look for a variable of the current proof *)
+ match Nametab.repr_qualid qid, ist.goalopt with
+ | (d,id),Some gl when repr_dirpath d = [] & List.mem id (pf_ids_of_hyps gl)
+ -> VarRef id
+ | _ -> Nametab.locate qid
+
+let coerce_to_reference ist = function
+ | VConstr c ->
+ (try reference_of_constr c
+ with Not_found -> invalid_arg_loc (loc, "Not a reference"))
+(* | VIdentifier id -> VarRef id*)
+ | v -> errorlabstrm "coerce_to_reference"
+ (str "The value" ++ spc () ++ pr_value ist.env v ++
+ str "cannot be coerced to a reference")
+
+(* turns a value into an evaluable reference *)
+let error_not_evaluable s =
+ errorlabstrm "evalref_of_ref"
+ (str "Cannot coerce" ++ spc () ++ s ++ spc () ++
+ str "to an evaluable reference")
+
+let coerce_to_evaluable_ref env c =
+ let ev = match c with
+ | VConstr c when isConst c -> EvalConstRef (destConst c)
+ | VConstr c when isVar c -> EvalVarRef (destVar c)
+(* | VIdentifier id -> EvalVarRef id*)
+ | _ -> error_not_evaluable (pr_value env c)
+ in
+ if not (Tacred.is_evaluable env ev) then
+ error_not_evaluable (pr_value env c);
+ ev
+
+let coerce_to_inductive = function
+ | VConstr c when isInd c -> destInd c
+ | x ->
+ try
+ let r = match x with
+ | VConstr c -> reference_of_constr c
+ | _ -> failwith "" in
+ errorlabstrm "coerce_to_inductive"
+ (Printer.pr_global r ++ str " is not an inductive type")
+ with _ ->
+ errorlabstrm "coerce_to_inductive"
+ (str "Found an argument which should be an inductive type")
+
+(* Summary and Object declaration *)
+let mactab = ref Gmap.empty
+
+let lookup qid = Gmap.find (locate_tactic qid) !mactab
+
+let _ =
+ let init () = mactab := Gmap.empty in
+ let freeze () = !mactab in
+ let unfreeze fs = mactab := fs in
+ Summary.declare_summary "tactic-definition"
+ { Summary.freeze_function = freeze;
+ Summary.unfreeze_function = unfreeze;
+ Summary.init_function = init;
+ Summary.survive_section = false }
+
+(* Interpretation of extra generic arguments *)
+type genarg_interp_type =
+ interp_sign -> raw_generic_argument -> closed_generic_argument
+let extragenargtab = ref (Gmap.empty : (string,genarg_interp_type) Gmap.t)
+let add_genarg_interp id f = extragenargtab := Gmap.add id f !extragenargtab
+let lookup_genarg_interp id =
+ try Gmap.find id !extragenargtab
+ with Not_found -> failwith ("No interpretation function found for entry "^id)
+
+
+(* Unboxes VRec *)
+let unrec = function
+ | VRec v -> !v
+ | a -> a
+
+(************* GLOBALIZE ************)
+
+(* We have identifier <| global_reference <| constr *)
+
+(* Globalize a name which can be fresh *)
+let glob_ident l ist x =
+ (* We use identifier both for variables and new names; thus nothing to do *)
+ if List.mem x (fst ist) then () else l:=x::!l;
+ x
+
+let glob_name l ist = function
+ | Anonymous -> Anonymous
+ | Name id -> Name (glob_ident l ist id)
+
+(* Globalize a name which must be bound -- actually just check it is bound *)
+let glob_hyp (lfun,_) (loc,id) =
+ if List.mem id lfun then id
+ else
+(*
+ try let _ = lookup (make_short_qualid id) in id
+ with Not_found ->
+*)
+ Pretype_errors.error_var_not_found_loc loc id
+
+let glob_lochyp ist (loc,_ as locid) = (loc,glob_hyp ist locid)
+
+let error_unbound_metanum loc n =
+ user_err_loc
+ (loc,"glob_qualid_or_metanum", str "?" ++ int n ++ str " is unbound")
+
+let glob_metanum ist loc n =
+ if List.mem n (snd ist) then n else error_unbound_metanum loc n
+
+let glob_hyp_or_metanum ist = function
+ | AN (loc,id) -> AN (loc,glob_hyp ist (loc,id))
+ | MetaNum (loc,n) -> MetaNum (loc,glob_metanum ist loc n)
+
+let glob_qualid_or_metanum ist = function
+ | AN (loc,qid) -> AN (loc,qualid_of_sp (sp_of_global (Global.env())(Nametab.global (loc,qid))))
+ | MetaNum (loc,n) -> MetaNum (loc,glob_metanum ist loc n)
+
+let glob_reference ist (_,qid as locqid) =
+ let dir, id = repr_qualid qid in
+ try
+ if dir = empty_dirpath && List.mem id (fst ist) then qid
+ else raise Not_found
+ with Not_found ->
+ qualid_of_sp (sp_of_global (Global.env()) (Nametab.global locqid))
+
+let glob_ltac_qualid ist (loc,qid as locqid) =
+ try qualid_of_sp (locate_tactic qid)
+ with Not_found -> glob_reference ist locqid
+
+let glob_ltac_reference ist = function
+ | RIdent (loc,id) ->
+ if List.mem id (fst ist) then RIdent (loc,id)
+ else RQualid (loc,glob_ltac_qualid ist (loc,make_short_qualid id))
+ | RQualid qid -> RQualid (loc,glob_ltac_qualid ist qid)
+
+let rec glob_intro_pattern lf ist = function
+ | IntroOrAndPattern l ->
+ IntroOrAndPattern (List.map (List.map (glob_intro_pattern lf ist)) l)
+ | IntroWildcard ->
+ IntroWildcard
+ | IntroIdentifier id ->
+ IntroIdentifier (glob_ident lf ist id)
+
+let glob_quantified_hypothesis ist x =
+ (* We use identifier both for variables and quantified hyps (no way to
+ statically check the existence of a quantified hyp); thus nothing to do *)
+ x
+
+let glob_constr ist c =
+ let _ = Astterm.interp_rawconstr_gen Evd.empty (Global.env()) [] false (fst ist) c in
+ c
+
+(* Globalize bindings *)
+let glob_binding ist (b,c) =
+ (glob_quantified_hypothesis ist b,glob_constr ist c)
+
+let glob_bindings ist = function
+ | NoBindings -> NoBindings
+ | ImplicitBindings l -> ImplicitBindings (List.map (glob_constr ist) l)
+ | ExplicitBindings l -> ExplicitBindings (List.map (glob_binding ist) l)
+
+let glob_constr_with_bindings ist (c,bl) =
+ (glob_constr ist c, glob_bindings ist bl)
+
+let glob_clause_pattern ist (l,occl) =
+ let rec check = function
+ | (hyp,l) :: rest ->
+ let (loc,_ as id) = skip_metaid hyp in
+ (AI(loc,glob_hyp ist id),l)::(check rest)
+ | [] -> []
+ in (l,check occl)
+
+let glob_induction_arg ist = function
+ | ElimOnConstr c -> ElimOnConstr (glob_constr ist c)
+ | ElimOnAnonHyp n as x -> x
+ | ElimOnIdent (loc,id) as x -> x
+
+(* Globalize a reduction expression *)
+let glob_evaluable_or_metanum ist = function
+ | AN (loc,qid) -> AN (loc,glob_reference ist (loc,qid))
+ | MetaNum (loc,n) -> MetaNum (loc,glob_metanum ist loc n)
+
+let glob_unfold ist (l,qid) = (l,glob_evaluable_or_metanum ist qid)
+
+let glob_flag ist red =
+ { red with rConst = List.map (glob_evaluable_or_metanum ist) red.rConst }
+
+let glob_pattern ist (l,c) = (l,glob_constr ist c)
+
+let glob_redexp ist = function
+ | Unfold l -> Unfold (List.map (glob_unfold ist) l)
+ | Fold l -> Fold (List.map (glob_constr ist) l)
+ | Cbv f -> Cbv (glob_flag ist f)
+ | Lazy f -> Lazy (glob_flag ist f)
+ | Pattern l -> Pattern (List.map (glob_pattern ist) l)
+ | (Red _ | Simpl | Hnf as r) -> r
+ | ExtraRedExpr (s,l) -> ExtraRedExpr (s, List.map (glob_constr ist) l)
+
+(* Interprets an hypothesis name *)
+let glob_hyp_location ist = function
+ | InHyp id ->
+ let (loc,_ as id) = skip_metaid id in
+ InHyp (AI(loc,glob_hyp ist id))
+ | InHypType id ->
+ let (loc,_ as id) = skip_metaid id in
+ InHypType (AI(loc,glob_hyp ist id))
+
+(* Reads a pattern *)
+let glob_pattern evc env lfun = function
+ | Subterm (ido,pc) ->
+ let lfun = List.map (fun id -> (id, mkVar id)) lfun in
+ let (metas,_) = interp_constrpattern_gen evc env lfun pc in
+ metas, Subterm (ido,pc)
+ | Term pc ->
+ let lfun = List.map (fun id -> (id, mkVar id)) lfun in
+ let (metas,_) = interp_constrpattern_gen evc env lfun pc in
+ metas, Term pc
+
+let glob_constr_may_eval ist = function
+ | ConstrEval (r,c) -> ConstrEval (glob_redexp ist r,glob_constr ist c)
+ | ConstrContext (locid,c) ->
+ ConstrContext ((loc,glob_hyp ist locid),glob_constr ist c)
+ | ConstrTypeOf c -> ConstrTypeOf (glob_constr ist c)
+ | ConstrTerm c -> ConstrTerm (glob_constr ist c)
+
+(* Reads the hypotheses of a Match Context rule *)
+let rec glob_match_context_hyps evc env lfun = function
+ | (NoHypId mp)::tl ->
+ let metas1, pat = glob_pattern evc env lfun mp in
+ let lfun, metas2, hyps = glob_match_context_hyps evc env lfun tl in
+ lfun, metas1@metas2, (NoHypId pat)::hyps
+ | (Hyp ((_,s) as locs,mp))::tl ->
+ let metas1, pat = glob_pattern evc env lfun mp in
+ let lfun, metas2, hyps = glob_match_context_hyps evc env lfun tl in
+ s::lfun, metas1@metas2, Hyp (locs,pat)::hyps
+ | [] -> lfun, [], []
+
+(* Utilities *)
+let rec filter_some = function
+ | None :: l -> filter_some l
+ | Some a :: l -> a :: filter_some l
+ | [] -> []
+
+let extract_names lrc =
+ List.fold_right
+ (fun ((loc,name),_) l ->
+ if List.mem name l then
+ user_err_loc
+ (loc, "glob_tactic", str "This variable is bound several times");
+ name::l)
+ lrc []
+
+let extract_let_names lrc =
+ List.fold_right
+ (fun ((loc,name),_,_) l ->
+ if List.mem name l then
+ user_err_loc
+ (loc, "glob_tactic", str "This variable is bound several times");
+ name::l)
+ lrc []
+
+(* Globalizes tactics *)
+let rec glob_atomic lf ist = function
+ (* Basic tactics *)
+ | TacIntroPattern l -> TacIntroPattern (List.map (glob_intro_pattern lf ist) l)
+ | TacIntrosUntil hyp -> TacIntrosUntil (glob_quantified_hypothesis ist hyp)
+ | TacIntroMove (ido,ido') ->
+ TacIntroMove (option_app (glob_ident lf ist) ido,
+ option_app (fun (loc,_ as x) -> (loc,glob_hyp ist x)) ido')
+ | TacAssumption -> TacAssumption
+ | TacExact c -> TacExact (glob_constr ist c)
+ | TacApply cb -> TacApply (glob_constr_with_bindings ist cb)
+ | TacElim (cb,cbo) ->
+ TacElim (glob_constr_with_bindings ist cb,
+ option_app (glob_constr_with_bindings ist) cbo)
+ | TacElimType c -> TacElimType (glob_constr ist c)
+ | TacCase cb -> TacCase (glob_constr_with_bindings ist cb)
+ | TacCaseType c -> TacCaseType (glob_constr ist c)
+ | TacFix (idopt,n) -> TacFix (option_app (glob_ident lf ist) idopt,n)
+ | TacMutualFix (id,n,l) ->
+ let f (id,n,c) = (glob_ident lf ist id,n,glob_constr ist c) in
+ TacMutualFix (glob_ident lf ist id, n, List.map f l)
+ | TacCofix idopt -> TacCofix (option_app (glob_ident lf ist) idopt)
+ | TacMutualCofix (id,l) ->
+ let f (id,c) = (glob_ident lf ist id,glob_constr ist c) in
+ TacMutualCofix (glob_ident lf ist id, List.map f l)
+ | TacCut c -> TacCut (glob_constr ist c)
+ | TacTrueCut (ido,c) ->
+ TacTrueCut (option_app (glob_ident lf ist) ido, glob_constr ist c)
+ | TacForward (b,na,c) -> TacForward (b,glob_name lf ist na,glob_constr ist c)
+ | TacGeneralize cl -> TacGeneralize (List.map (glob_constr ist) cl)
+ | TacGeneralizeDep c -> TacGeneralizeDep (glob_constr ist c)
+ | TacLetTac (id,c,clp) ->
+ TacLetTac (id,glob_constr ist c,glob_clause_pattern ist clp)
+ | TacInstantiate (n,c) -> TacInstantiate (n,glob_constr ist c)
+
+ (* Automation tactics *)
+ | TacTrivial l -> TacTrivial l
+ | TacAuto (n,l) -> TacAuto (n,l)
+ | TacAutoTDB n -> TacAutoTDB n
+ | TacDestructHyp (b,(loc,_ as id)) -> TacDestructHyp(b,(loc,glob_hyp ist id))
+ | TacDestructConcl -> TacDestructConcl
+ | TacSuperAuto (n,l,b1,b2) -> TacSuperAuto (n,l,b1,b2)
+ | TacDAuto (n,p) -> TacDAuto (n,p)
+
+ (* Derived basic tactics *)
+ | TacOldInduction h -> TacOldInduction (glob_quantified_hypothesis ist h)
+ | TacNewInduction c -> TacNewInduction (glob_induction_arg ist c)
+ | TacOldDestruct h -> TacOldDestruct (glob_quantified_hypothesis ist h)
+ | TacNewDestruct c -> TacNewDestruct (glob_induction_arg ist c)
+ | TacDoubleInduction (h1,h2) ->
+ let h1 = glob_quantified_hypothesis ist h1 in
+ let h2 = glob_quantified_hypothesis ist h2 in
+ TacDoubleInduction (h1,h2)
+ | TacDecomposeAnd c -> TacDecomposeAnd (glob_constr ist c)
+ | TacDecomposeOr c -> TacDecomposeOr (glob_constr ist c)
+ | TacDecompose (l,c) ->
+ let l = List.map (glob_qualid_or_metanum ist) l in
+ TacDecompose (l,glob_constr ist c)
+ | TacSpecialize (n,l) -> TacSpecialize (n,glob_constr_with_bindings ist l)
+ | TacLApply c -> TacLApply (glob_constr ist c)
+
+ (* Context management *)
+ | TacClear l -> TacClear (List.map (glob_hyp_or_metanum ist) l)
+ | TacClearBody l -> TacClearBody (List.map (glob_hyp_or_metanum ist) l)
+ | TacMove (dep,id1,id2) -> TacMove (dep,glob_lochyp ist id1,glob_lochyp ist id2)
+ | TacRename (id1,id2) -> TacRename (glob_lochyp ist id1, glob_lochyp ist id2)
+
+ (* Constructors *)
+ | TacLeft bl -> TacLeft (glob_bindings ist bl)
+ | TacRight bl -> TacRight (glob_bindings ist bl)
+ | TacSplit bl -> TacSplit (glob_bindings ist bl)
+ | TacAnyConstructor t -> TacAnyConstructor (option_app (glob_tactic ist) t)
+ | TacConstructor (n,bl) -> TacConstructor (n, glob_bindings ist bl)
+
+ (* Conversion *)
+ | TacReduce (r,cl) ->
+ TacReduce (glob_redexp ist r, List.map (glob_hyp_location ist) cl)
+ | TacChange (c,cl) ->
+ TacChange (glob_constr ist c, List.map (glob_hyp_location ist) cl)
+
+ (* Equivalence relations *)
+ | TacReflexivity -> TacReflexivity
+ | TacSymmetry -> TacSymmetry
+ | TacTransitivity c -> TacTransitivity (glob_constr ist c)
+
+ (* For extensions *)
+ | TacExtend (opn,l) ->
+ let _ = lookup_tactic opn in
+ TacExtend (opn,List.map (glob_genarg ist) l)
+ | TacAlias (_,l,body) -> failwith "TODO"
+
+and glob_tactic ist tac = snd (glob_tactic_seq ist tac)
+
+and glob_tactic_seq (lfun,lmeta as ist) = function
+ | TacAtom (loc,t) ->
+ let lf = ref lfun in
+ let t = glob_atomic lf ist t in
+ !lf, TacAtom (loc, t)
+ | TacFun tacfun -> lfun, TacFun (glob_tactic_fun ist tacfun)
+ | TacFunRec (name,tacfun) ->
+ lfun, TacFunRec (name,glob_tactic_fun ((snd name)::lfun,lmeta) tacfun)
+ | TacLetRecIn (lrc,u) ->
+ let names = extract_names lrc in
+ let ist = (names@lfun,lmeta) in
+ let lrc = List.map (fun (n,b) -> (n,glob_tactic_fun ist b)) lrc in
+ lfun, TacLetRecIn (lrc,glob_tactic ist u)
+ | TacLetIn (l,u) ->
+ let l = List.map (fun (n,c,b) -> (n,option_app (glob_constr_may_eval ist) c,glob_tacarg ist b)) l in
+ let ist' = ((extract_let_names l)@lfun,lmeta) in
+ lfun, TacLetIn (l,glob_tactic ist' u)
+ | TacLetCut l ->
+ let f (n,c,t) = (n,glob_constr_may_eval ist c,glob_tacarg ist t) in
+ lfun, TacLetCut (List.map f l)
+ | TacMatchContext (lr,lmr) ->
+ lfun, TacMatchContext(lr, glob_match_rule ist lmr)
+ | TacMatch (c,lmr) ->
+ lfun, TacMatch (glob_constr_may_eval ist c,glob_match_rule ist lmr)
+ | TacId -> lfun, TacId
+ | TacFail n as x -> lfun, x
+ | TacProgress tac -> lfun, TacProgress (glob_tactic ist tac)
+ | TacAbstract (tac,s) -> lfun, TacAbstract (glob_tactic ist tac,s)
+ | TacThen (t1,t2) ->
+ let lfun', t1 = glob_tactic_seq ist t1 in
+ let lfun'', t2 = glob_tactic_seq (lfun',lmeta) t2 in
+ lfun'', TacThen (t1,t2)
+ | TacThens (t,tl) ->
+ let lfun', t = glob_tactic_seq ist t in
+ (* Que faire en cas de (tac complexe avec Match et Thens; tac2) ?? *)
+ lfun', TacThens (t, List.map (glob_tactic (lfun',lmeta)) tl)
+ | TacDo (n,tac) -> lfun, TacDo (n,glob_tactic ist tac)
+ | TacTry tac -> lfun, TacTry (glob_tactic ist tac)
+ | TacInfo tac -> lfun, TacInfo (glob_tactic ist tac)
+ | TacRepeat tac -> lfun, TacRepeat (glob_tactic ist tac)
+ | TacOrelse (tac1,tac2) ->
+ lfun, TacOrelse (glob_tactic ist tac1,glob_tactic ist tac2)
+ | TacFirst l -> lfun, TacFirst (List.map (glob_tactic ist) l)
+ | TacSolve l -> lfun, TacSolve (List.map (glob_tactic ist) l)
+ | TacArg a -> lfun, TacArg (glob_tacarg ist a)
+
+and glob_tactic_fun (lfun,lmeta) (var,body) =
+ let lfun' = List.rev_append (filter_some var) lfun in
+ (var,glob_tactic (lfun',lmeta) body)
+
+and glob_tacarg ist = function
+ | TacVoid -> TacVoid
+ | Reference r -> Reference (glob_ltac_reference ist r)
+ | Integer n -> Integer n
+ | ConstrMayEval c -> ConstrMayEval (glob_constr_may_eval ist c)
+ | MetaNumArg (loc,n) -> MetaNumArg (loc,glob_metanum ist loc n)
+ | MetaIdArg (loc,_) -> error_syntactic_metavariables_not_allowed loc
+ | TacCall (loc,f,l) ->
+ TacCall (loc,glob_tacarg ist f,List.map (glob_tacarg ist) l)
+ | Tacexp t -> Tacexp (glob_tactic ist t)
+ | TacDynamic(_,t) as x ->
+ (match tag t with
+ | "tactic"|"value"|"constr" -> x
+ | s -> anomaly_loc (loc, "Tacinterp.val_interp",
+ str "Unknown dynamic: <" ++ str s ++ str ">"))
+
+(* Reads the rules of a Match Context or a Match *)
+and glob_match_rule (lfun,lmeta as ist) = function
+ | (All tc)::tl ->
+ (All (glob_tactic ist tc))::(glob_match_rule ist tl)
+ | (Pat (rl,mp,tc))::tl ->
+ let env = Global.env() in
+ let lfun',metas1,hyps = glob_match_context_hyps Evd.empty env lfun rl in
+ let metas2,pat = glob_pattern Evd.empty env lfun mp in
+ let metas = list_uniquize (metas1@metas2@lmeta) in
+ (Pat (hyps,pat,glob_tactic (lfun',metas) tc))::(glob_match_rule ist tl)
+ | [] -> []
+
+and glob_genarg ist x =
+ match genarg_tag x with
+ | BoolArgType -> in_gen rawwit_bool (out_gen rawwit_bool x)
+ | IntArgType -> in_gen rawwit_int (out_gen rawwit_int x)
+ | IntOrVarArgType ->
+ let f = function
+ | ArgVar (loc,id) -> ArgVar (loc,glob_hyp ist (loc,id))
+ | ArgArg n as x -> x in
+ in_gen rawwit_int_or_var (f (out_gen rawwit_int_or_var x))
+ | StringArgType ->
+ in_gen rawwit_string (out_gen rawwit_string x)
+ | PreIdentArgType ->
+ in_gen rawwit_pre_ident (out_gen rawwit_pre_ident x)
+ | IdentArgType ->
+ in_gen rawwit_ident (glob_hyp ist (dummy_loc,out_gen rawwit_ident x))
+ | QualidArgType ->
+ let (loc,qid) = out_gen rawwit_qualid x in
+ in_gen rawwit_qualid (loc,glob_ltac_qualid ist (loc,qid))
+ | ConstrArgType ->
+ in_gen rawwit_constr (glob_constr ist (out_gen rawwit_constr x))
+ | ConstrMayEvalArgType ->
+ in_gen rawwit_constr_may_eval (glob_constr_may_eval ist (out_gen rawwit_constr_may_eval x))
+ | QuantHypArgType ->
+ in_gen rawwit_quant_hyp
+ (glob_quantified_hypothesis ist (out_gen rawwit_quant_hyp x))
+ | RedExprArgType ->
+ in_gen rawwit_red_expr (glob_redexp ist (out_gen rawwit_red_expr x))
+ | TacticArgType ->
+ in_gen rawwit_tactic (glob_tactic ist (out_gen rawwit_tactic x))
+ | CastedOpenConstrArgType ->
+ in_gen rawwit_casted_open_constr
+ (glob_constr ist (out_gen rawwit_casted_open_constr x))
+ | ConstrWithBindingsArgType ->
+ in_gen rawwit_constr_with_bindings
+ (glob_constr_with_bindings ist (out_gen rawwit_constr_with_bindings x))
+ | List0ArgType _ -> app_list0 (glob_genarg ist) x
+ | List1ArgType _ -> app_list1 (glob_genarg ist) x
+ | OptArgType _ -> app_opt (glob_genarg ist) x
+ | PairArgType _ -> app_pair (glob_genarg ist) (glob_genarg ist) x
+ | ExtraArgType s -> x
+
+
+(************* END GLOBALIZE ************)
+
+(* Reads the head of Fun *)
+let read_fun ast =
+ let rec read_fun_rec = function
+ | Node(_,"VOID",[])::tl -> None::(read_fun_rec tl)
+ | Nvar(_,s)::tl -> (Some s)::(read_fun_rec tl)
+ | [] -> []
+ | _ ->
+ anomalylabstrm "Tacinterp.read_fun_rec" (str "Fun not well formed")
+ in
+ match ast with
+ | Node(_,"FUNVAR",l) -> read_fun_rec l
+ | _ ->
+ anomalylabstrm "Tacinterp.read_fun" (str "Fun not well formed")
+
+(* Reads the clauses of a Rec *)
+let rec read_rec_clauses = function
+ | [] -> []
+ | Node(_,"RECCLAUSE",[Nvar(_,name);it;body])::tl ->
+ (name,it,body)::(read_rec_clauses tl)
+ |_ ->
+ anomalylabstrm "Tacinterp.read_rec_clauses"
+ (str "Rec not well formed")
+
+(* Associates variables with values and gives the remaining variables and
+ values *)
+let head_with_value (lvar,lval) =
+ let rec head_with_value_rec lacc = function
+ | ([],[]) -> (lacc,[],[])
+ | (vr::tvr,ve::tve) ->
+ (match vr with
+ | None -> head_with_value_rec lacc (tvr,tve)
+ | Some v -> head_with_value_rec ((v,ve)::lacc) (tvr,tve))
+ | (vr,[]) -> (lacc,vr,[])
+ | ([],ve) -> (lacc,[],ve)
+ in
+ head_with_value_rec [] (lvar,lval)
+
+(* Gives a context couple if there is a context identifier *)
+let give_context ctxt = function
+ | None -> []
+ | Some id -> [id,VConstr_context ctxt]
+
+(* Reads a pattern *)
+let read_pattern evc env lfun = function
+ | Subterm (ido,pc) ->
+ Subterm (ido,snd (interp_constrpattern_gen evc env lfun pc))
+ | Term pc ->
+ Term (snd (interp_constrpattern_gen evc env lfun pc))
+
+(* Reads the hypotheses of a Match Context rule *)
+let rec read_match_context_hyps evc env lfun lidh = function
+ | (NoHypId mp)::tl ->
+ (NoHypId (read_pattern evc env lfun mp))::
+ (read_match_context_hyps evc env lfun lidh tl)
+ | (Hyp ((loc,id) as locid,mp))::tl ->
+ if List.mem id lidh then
+ user_err_loc (loc,"Tacinterp.read_match_context_hyps",
+ str ("Hypothesis pattern-matching variable "^(string_of_id id)^
+ " used twice in the same pattern"))
+ else
+ (Hyp (locid,read_pattern evc env lfun mp))::
+ (read_match_context_hyps evc env lfun (id::lidh) tl)
+ | [] -> []
+
+(* Reads the rules of a Match Context or a Match *)
+let rec read_match_rule evc env lfun = function
+ | (All tc)::tl -> (All tc)::(read_match_rule evc env lfun tl)
+ | (Pat (rl,mp,tc))::tl ->
+ (Pat (read_match_context_hyps evc env lfun [] rl,
+ read_pattern evc env lfun mp,tc))
+ ::(read_match_rule evc env lfun tl)
+ | [] -> []
+
+(* For Match Context and Match *)
+exception No_match
+exception Not_coherent_metas
+
+let is_match_catchable = function
+ | No_match | FailError _ -> true
+ | e -> Logic.catchable_exception e
+
+(* Verifies if the matched list is coherent with respect to lcm *)
+let rec verify_metas_coherence ist lcm = function
+ | (num,csr)::tl ->
+ if (List.for_all
+ (fun (a,b) ->
+ if a=num then
+ Reductionops.is_conv ist.env ist.evc b csr
+ else
+ true) lcm) then
+ (num,csr)::(verify_metas_coherence ist lcm tl)
+ else
+ raise Not_coherent_metas
+ | [] -> []
+
+(* Tries to match a pattern and a constr *)
+let apply_matching pat csr =
+ try
+ (Pattern.matches pat csr)
+ with
+ PatternMatchingFailure -> raise No_match
+
+(* Tries to match one hypothesis pattern with a list of hypotheses *)
+let apply_one_mhyp_context ist lmatch mhyp lhyps noccopt =
+ let get_pattern = function
+ | Hyp (_,pat) -> pat
+ | NoHypId pat -> pat
+ and get_id_couple id = function
+ | Hyp((_,idpat),_) -> [idpat,VIdentifier id]
+ | NoHypId _ -> [] in
+ let rec apply_one_mhyp_context_rec mhyp lhyps_acc nocc = function
+ | (id,hyp)::tl ->
+ (match (get_pattern mhyp) with
+ | Term t ->
+ (try
+ let lmeta =
+ verify_metas_coherence ist lmatch (Pattern.matches t hyp) in
+ (get_id_couple id mhyp,[],lmeta,tl,(id,hyp),None)
+ with | PatternMatchingFailure | Not_coherent_metas ->
+ apply_one_mhyp_context_rec mhyp (lhyps_acc@[id,hyp]) 0 tl)
+ | Subterm (ic,t) ->
+ (try
+ let (lm,ctxt) = sub_match nocc t hyp in
+ let lmeta = verify_metas_coherence ist lmatch lm in
+ (get_id_couple id mhyp,give_context ctxt
+ ic,lmeta,tl,(id,hyp),Some nocc)
+ with
+ | NextOccurrence _ ->
+ apply_one_mhyp_context_rec mhyp (lhyps_acc@[id,hyp]) 0 tl
+ | Not_coherent_metas ->
+ apply_one_mhyp_context_rec mhyp lhyps_acc (nocc + 1) ((id,hyp)::tl)))
+ | [] -> raise No_match in
+ let nocc =
+ match noccopt with
+ | None -> 0
+ | Some n -> n in
+ apply_one_mhyp_context_rec mhyp [] nocc lhyps
+
+(*
+let coerce_to_qualid loc = function
+ | Constr c when isVar c -> make_short_qualid (destVar c)
+ | Constr c ->
+ (try qualid_of_sp (sp_of_global (Global.env()) (reference_of_constr c))
+ with Not_found -> invalid_arg_loc (loc, "Not a reference"))
+ | Identifier id -> make_short_qualid id
+ | Qualid qid -> qid
+ | _ -> invalid_arg_loc (loc, "Not a reference")
+*)
+
+let constr_to_id loc c =
+ if isVar c then destVar c
+ else invalid_arg_loc (loc, "Not an identifier")
+
+let constr_to_qid loc c =
+ try qualid_of_sp (sp_of_global (Global.env ()) (reference_of_constr c))
+ with _ -> invalid_arg_loc (loc, "Not a global reference")
+
+(* Check for LetTac *)
+let check_clause_pattern ist (l,occl) =
+ match ist.goalopt with
+ | Some gl ->
+ let sign = pf_hyps gl in
+ let rec check acc = function
+ | (hyp,l) :: rest ->
+ let _,hyp = skip_metaid hyp in
+ if List.mem hyp acc then
+ error ("Hypothesis "^(string_of_id hyp)^" occurs twice");
+ if not (mem_named_context hyp sign) then
+ error ("No such hypothesis: " ^ (string_of_id hyp));
+ (hyp,l)::(check (hyp::acc) rest)
+ | [] -> []
+ in (l,check [] occl)
+ | None -> error "No goal"
+
+(* Debug reference *)
+let debug = ref DebugOff
+
+(* Sets the debugger mode *)
+let set_debug pos = debug := pos
+
+(* Gives the state of debug *)
+let get_debug () = !debug
+
+(* Interprets an identifier *)
+let eval_ident ist id =
+ try (unrec (List.assoc id ist.lfun))
+ with | Not_found ->
+(*
+ try (vcontext_interp ist (lookup (make_short_qualid id)))
+ with | Not_found ->
+*)
+VIdentifier id
+
+(* Gives the identifier corresponding to an Identifier tactic_arg *)
+let id_of_Identifier = function
+ | VConstr c when isVar c -> destVar c
+ | VIdentifier id -> id
+ | _ ->
+ anomalylabstrm "id_of_Identifier" (str "Not an IDENTIFIER tactic_arg")
+
+let coerce_to_hypothesis ist = function
+ | VConstr c when isVar c -> destVar c
+ | VIdentifier id -> id
+ | v -> errorlabstrm "coerce_to_hypothesis"
+ (str "Cannot coerce" ++ spc () ++ pr_value ist.env v ++ spc () ++
+ str "to an existing hypothesis")
+
+let ident_interp ist id =
+ id_of_Identifier (eval_ident ist id)
+
+let hyp_interp ist (loc,id) =
+ coerce_to_hypothesis ist (eval_ident ist id)
+
+let name_interp ist = function
+ | Anonymous -> Anonymous
+ | Name id -> Name (ident_interp ist id)
+
+let hyp_or_metanum_interp ist = function
+ | AN (loc,id) -> ident_interp ist id
+ | MetaNum (loc,n) -> constr_to_id loc (List.assoc n ist.lmatch)
+
+(* To avoid to move to much simple functions in the big recursive block *)
+let forward_vcontext_interp = ref (fun ist v -> failwith "not implemented")
+
+let interp_pure_qualid ist (loc,qid) =
+ try (!forward_vcontext_interp ist (lookup qid))
+ with | Not_found ->
+ try VConstr (constr_of_reference (find_reference ist qid))
+ with Not_found ->
+ let (dir,id) = repr_qualid qid in
+ if dir = empty_dirpath then VIdentifier id
+ else user_err_loc (loc,"interp_pure_qualid",str "Unknown reference")
+
+let interp_ltac_reference ist = function
+ | RIdent (loc,id) ->
+ (try unrec (List.assoc id ist.lfun)
+ with | Not_found -> interp_pure_qualid ist (loc,make_short_qualid id))
+ | RQualid qid -> interp_pure_qualid ist qid
+
+(* Interprets a qualified name *)
+let eval_qualid ist (loc,qid as locqid) =
+ let dir, id = repr_qualid qid in
+ try
+ if dir = empty_dirpath then unrec (List.assoc id ist.lfun)
+ else raise Not_found
+ with | Not_found ->
+ interp_pure_qualid ist locqid
+
+let qualid_interp ist qid =
+ let v = eval_qualid ist qid in
+ coerce_to_reference ist v
+
+(* Interprets a qualified name. This can be a metavariable to be injected *)
+let qualid_or_metanum_interp ist = function
+ | AN (loc,qid) -> qid
+ | MetaNum (loc,n) -> constr_to_qid loc (List.assoc n ist.lmatch)
+
+let eval_ref_or_metanum ist = function
+ | AN (loc,qid) -> eval_qualid ist (loc,qid)
+ | MetaNum (loc,n) -> VConstr (List.assoc n ist.lmatch)
+
+let interp_evaluable_or_metanum ist c =
+ let c = eval_ref_or_metanum ist c in
+ coerce_to_evaluable_ref ist.env c
+
+let interp_inductive_or_metanum ist c =
+ let c = eval_ref_or_metanum ist c in
+ coerce_to_inductive c
+
+(* Interprets an hypothesis name *)
+let interp_hyp_location ist = function
+ | InHyp id -> InHyp (hyp_interp ist (skip_metaid id))
+ | InHypType id -> InHypType (hyp_interp ist (skip_metaid id))
+
+let id_opt_interp ist = option_app (ident_interp ist)
+
+(* Interpretation of constructions *)
+
+ (* Extracted the constr list from lfun *)
+let rec constr_list_aux ist = function
+ | (id,VConstr c)::tl -> (id,c)::(constr_list_aux ist tl)
+ | (id0,VIdentifier id)::tl ->
+ (try (id0,(constr_of_id ist id))::(constr_list_aux ist tl)
+ with | Not_found -> (constr_list_aux ist tl))
+ | _::tl -> constr_list_aux ist tl
+ | [] -> []
+
+let constr_list ist = constr_list_aux ist ist.lfun
+let interp_constr ocl ist c =
+ interp_constr_gen ist.evc ist.env (constr_list ist) ist.lmatch c ocl
+
+let interp_openconstr ist c ocl =
+ interp_openconstr_gen ist.evc ist.env (constr_list ist) ist.lmatch c ocl
+
+(* Interprets a constr expression *)
+let constr_interp ist c =
+ let csr = interp_constr None ist c in
+ begin
+ db_constr ist.debug ist.env csr;
+ csr
+ end
+
+(* Interprets a constr expression casted by the current goal *)
+let cast_constr_interp ist c =
+ match ist.goalopt with
+ | Some gl ->
+ let csr = interp_constr (Some (pf_concl gl)) ist c in
+ begin
+ db_constr ist.debug ist.env csr;
+ csr
+ end
+
+ | None ->
+ errorlabstrm "cast_constr_interp"
+ (str "Cannot cast a constr without goal")
+
+(* Interprets an open constr expression casted by the current goal *)
+let cast_openconstr_interp ist c =
+ match ist.goalopt with
+ | Some gl -> interp_openconstr ist c (Some (pf_concl gl))
+ | None ->
+ errorlabstrm "cast_openconstr_interp"
+ (str "Cannot cast a constr without goal")
+
+(* Interprets a reduction expression *)
+let unfold_interp ist (l,qid) = (l,interp_evaluable_or_metanum ist qid)
+
+let flag_interp ist red =
+ { red with rConst = List.map (interp_evaluable_or_metanum ist) red.rConst }
+
+let pattern_interp ist (l,c) = (l,constr_interp ist c)
+
+let redexp_interp ist = function
+ | Unfold l -> Unfold (List.map (unfold_interp ist) l)
+ | Fold l -> Fold (List.map (constr_interp ist) l)
+ | Cbv f -> Cbv (flag_interp ist f)
+ | Lazy f -> Lazy (flag_interp ist f)
+ | Pattern l -> Pattern (List.map (pattern_interp ist) l)
+ | (Red _ | Simpl | Hnf as r) -> r
+ | ExtraRedExpr (s,l) -> ExtraRedExpr (s,List.map (constr_interp ist) l)
+
+let interp_may_eval f ist = function
+ | ConstrEval (r,c) ->
+ let redexp = redexp_interp ist r in
+ (reduction_of_redexp redexp) ist.env ist.evc (f ist c)
+ | ConstrContext ((loc,s),c) ->
+ (try
+ let ic = f ist c
+ and ctxt = constr_of_VConstr_context (List.assoc s ist.lfun) in
+ subst_meta [-1,ic] ctxt
+ with
+ | Not_found ->
+ user_err_loc (loc, "constr_interp",
+ str "Unbound context identifier" ++ pr_id s))
+ | ConstrTypeOf c -> type_of ist.env ist.evc (f ist c)
+ | ConstrTerm c -> f ist c
+
+(* Interprets a constr expression possibly to first evaluate *)
+let constr_interp_may_eval ist c =
+ let csr = interp_may_eval (interp_constr None) ist c in
+ begin
+ db_constr ist.debug ist.env csr;
+ csr
+ end
+
+let rec interp_intro_pattern ist = function
+ | IntroOrAndPattern l ->
+ IntroOrAndPattern (List.map (List.map (interp_intro_pattern ist)) l)
+ | IntroWildcard ->
+ IntroWildcard
+ | IntroIdentifier id ->
+ IntroIdentifier (ident_interp ist id)
+
+let interp_quantified_hypothesis ist = function
+ | AnonHyp n -> AnonHyp n
+ | NamedHyp id ->
+ match eval_ident ist id with
+ | VIdentifier id -> NamedHyp id
+ | VInteger n -> AnonHyp n
+ | _ -> invalid_arg_loc
+ (loc, "Not a reference to an hypothesis: "^(string_of_id id))
+
+
+let interp_induction_arg ist = function
+ | ElimOnConstr c -> ElimOnConstr (constr_interp ist c)
+ | ElimOnAnonHyp n as x -> x
+ | ElimOnIdent (loc,id) ->
+ match ist.goalopt with
+ | None -> error "No goal"
+ | Some gl ->
+ if Tactics.is_quantified_hypothesis id gl then ElimOnIdent (loc,id)
+ else ElimOnConstr
+ (constr_interp ist (Termast.ast_of_qualid (make_short_qualid id)))
+
+let binding_interp ist (b,c) =
+ (interp_quantified_hypothesis ist b,constr_interp ist c)
+
+let bindings_interp ist = function
+ | NoBindings -> NoBindings
+ | ImplicitBindings l -> ImplicitBindings (List.map (constr_interp ist) l)
+ | ExplicitBindings l -> ExplicitBindings (List.map (binding_interp ist) l)
+
+let interp_constr_with_bindings ist (c,bl) =
+ (constr_interp ist c, bindings_interp ist bl)
+
+(* Interprets a tactic expression *)
+let rec val_interp ist ast =
+
+ let value_interp ist =
+ match ast with
+ (* Immediate evaluation *)
+ | TacFun (it,body) -> VFun (ist.lfun,it,body)
+ | TacFunRec rc -> funrec_interp ist rc
+ | TacLetRecIn (lrc,u) -> letrec_interp ist lrc u
+ | TacLetIn (l,u) ->
+ let addlfun=letin_interp ist l in
+ val_interp { ist with lfun=addlfun@ist.lfun } u
+ | TacMatchContext (lr,lmr) ->
+ (match ist.goalopt with
+ | None -> VContext (ist,lr,lmr)
+ | Some g -> match_context_interp ist lr lmr g)
+ | TacMatch (c,lmr) -> match_interp ist c lmr
+ | TacArg a -> tacarg_interp ist a
+ (* Delayed evaluation *)
+ | t -> VClosure (ist,t)
+ in
+ if ist.debug = DebugOn then
+ match debug_prompt ist.goalopt ast with
+ | Exit -> VClosure (ist,TacId)
+ | v -> value_interp {ist with debug=v}
+ else
+ value_interp ist
+
+and eval_tactic ist = function
+ | TacAtom (loc,t) ->
+ (try interp_atomic ist t
+ with e -> Stdpp.raise_with_loc loc e)
+ | TacFun (it,body) -> assert false
+ | TacFunRec rc -> assert false
+ | TacLetRecIn (lrc,u) -> assert false
+ | TacLetIn (l,u) -> assert false
+ | TacLetCut l -> letcut_interp ist l
+ | TacMatchContext _ -> assert false
+ | TacMatch (c,lmr) -> assert false
+ | TacId -> tclIDTAC
+ | TacFail n -> tclFAIL n
+ | TacProgress tac -> tclPROGRESS (tactic_interp ist tac)
+ | TacAbstract (tac,s) -> Tactics.tclABSTRACT s (tactic_interp ist tac)
+ | TacThen (t1,t2) -> tclTHEN (tactic_interp ist t1) (tactic_interp ist t2)
+ | TacThens (t,tl) ->
+ tclTHENS (tactic_interp ist t) (List.map (tactic_interp ist) tl)
+ | TacDo (n,tac) -> tclDO n (tactic_interp ist tac)
+ | TacTry tac -> tclTRY (tactic_interp ist tac)
+ | TacInfo tac -> tclINFO (tactic_interp ist tac)
+ | TacRepeat tac -> tclREPEAT (tactic_interp ist tac)
+ | TacOrelse (tac1,tac2) ->
+ tclORELSE (tactic_interp ist tac1) (tactic_interp ist tac2)
+ | TacFirst l -> tclFIRST (List.map (tactic_interp ist) l)
+ | TacSolve l -> tclSOLVE (List.map (tactic_interp ist) l)
+(* Obsolete ??
+ | Node(loc0,"APPTACTIC",[Node(loc1,s,l)]) ->
+ (Node(loc0,"APP",[Node(loc1,"PRIM-TACTIC",[Node(loc1,s,[])])]@l))
+ | Node(_,"PRIMTACTIC",[Node(loc,opn,[])]) ->
+ VFTactic ([],(interp_atomic opn))
+*)
+ | TacArg a -> assert false
+
+and tacarg_interp ist = function
+ | TacVoid -> VVoid
+ | Reference r -> interp_ltac_reference ist r
+ | Integer n -> VInteger n
+ | ConstrMayEval c -> VConstr (constr_interp_may_eval ist c)
+ | MetaNumArg (_,n) -> VConstr (List.assoc n ist.lmatch)
+ | MetaIdArg (loc,_) -> error_syntactic_metavariables_not_allowed loc
+(*
+ | Tacexp t -> VArg (Tacexp ((*tactic_interp ist t,*)t))
+*)
+ | TacCall (loc,f,l) ->
+ let fv = tacarg_interp ist f
+ and largs = List.map (tacarg_interp ist) l in
+ app_interp ist fv largs loc
+ | Tacexp t -> val_interp ist t
+(*
+ | Node(loc,s,l) ->
+ let fv = val_interp ist (Node(loc,"PRIMTACTIC",[Node(loc,s,[])]))
+ and largs = List.map (val_interp ist) l in
+ app_interp ist fv largs ast
+*)
+ | TacDynamic(_,t) ->
+ let tg = (tag t) in
+ if tg = "tactic" then
+ let f = (tactic_out t) in val_interp ist (f ist)
+ else if tg = "value" then
+ value_out t
+ else if tg = "constr" then
+ VConstr (Pretyping.constr_out t)
+ else
+ anomaly_loc (loc, "Tacinterp.val_interp",
+ (str "Unknown dynamic: <" ++ str (Dyn.tag t) ++ str ">"))
+
+(* Interprets an application node *)
+and app_interp ist fv largs loc =
+ match fv with
+ | VFTactic(l,f) -> VFTactic(l@largs,f)
+ | VFun(olfun,var,body) ->
+ let (newlfun,lvar,lval)=head_with_value (var,largs) in
+ if lvar=[] then
+ if lval=[] then
+ val_interp { ist with lfun=newlfun@olfun } body
+ else
+ app_interp ist
+ (val_interp {ist with lfun=newlfun@olfun } body) lval loc
+ else
+ VFun(newlfun@olfun,lvar,body)
+ | _ ->
+ user_err_loc (loc, "Tacinterp.app_interp",
+ (str"Illegal tactic application"))
+
+(* Gives the tactic corresponding to the tactic value *)
+and tactic_of_value vle g =
+ match vle with
+ | VClosure (ist,tac) -> eval_tactic ist tac g
+ | VFTactic (largs,f) -> (f largs g)
+ | VRTactic res -> res
+ | VTactic tac -> tac g
+ | _ -> raise NotTactic
+
+(* Evaluation with FailError catching *)
+and eval_with_fail interp ast goal =
+ try
+ (match interp ast with
+ | VClosure (ist,tac) -> VRTactic (eval_tactic ist tac goal)
+ | VFTactic (largs,f) -> VRTactic (f largs goal)
+ | VTactic tac -> VRTactic (tac goal)
+ | a -> a)
+ with | FailError lvl ->
+ if lvl = 0 then
+ raise No_match
+ else
+ raise (FailError (lvl - 1))
+
+(* Interprets recursive expressions *)
+and funrec_interp ist ((loc,name),(var,body)) =
+ let ve = ref VVoid in
+ let newve = VFun((name,VRec ve)::ist.lfun,var,body) in
+ begin
+ ve:=newve;
+ !ve
+ end
+
+and letrec_interp ist lrc u =
+ let lref = Array.to_list (Array.make (List.length lrc) (ref VVoid)) in
+ let lenv = List.fold_right2 (fun ((loc,name),_) vref l -> (name,VRec vref)::l)
+ lrc lref [] in
+ let lve = List.map (fun ((loc,name),(var,body)) ->
+ (name,VFun(lenv@ist.lfun,var,body))) lrc in
+ begin
+ List.iter2 (fun vref (_,ve) -> vref:=ve) lref lve;
+ val_interp { ist with lfun=lve@ist.lfun } u
+ end
+
+(* Interprets the clauses of a LetCutIn *)
+and letin_interp ist = function
+ | [] -> []
+ | ((loc,id),None,t)::tl -> (id,tacarg_interp ist t):: (letin_interp ist tl)
+ | ((loc,id),Some com,tce)::tl ->
+ let typ = interp_may_eval (interp_constr None) ist com
+ and tac = tacarg_interp ist tce in
+ match tac with
+ | VConstr csr ->
+ (id,VConstr (mkCast (csr,typ)))::(letin_interp ist tl)
+ | VIdentifier id ->
+ (try
+ (id,VConstr (mkCast (constr_of_id ist id,typ)))::
+ (letin_interp ist tl)
+ with | Not_found ->
+ errorlabstrm "Tacinterp.letin_interp"
+ (str "Term or tactic expected"))
+ | _ ->
+ (try
+ let t = tactic_of_value tac in
+ let ndc =
+ (match ist.goalopt with
+ | None -> Global.named_context ()
+ | Some g -> pf_hyps g) in
+ start_proof id (true,NeverDischarge) ndc typ (fun _ _ -> ());
+ by t;
+ let (_,({const_entry_body = pft; const_entry_type = _},_,_)) =
+ cook_proof () in
+ delete_proof id;
+ (id,VConstr (mkCast (pft,typ)))::(letin_interp ist tl)
+ with | NotTactic ->
+ delete_proof id;
+ errorlabstrm "Tacinterp.letin_interp"
+ (str "Term or tactic expected"))
+
+(* Interprets the clauses of a LetCut *)
+and letcut_interp ist = function
+ | [] -> tclIDTAC
+ | (id,com,tce)::tl ->
+ let typ = constr_interp_may_eval ist com
+ and tac = tacarg_interp ist tce
+ and (ndc,ccl) =
+ match ist.goalopt with
+ | None ->
+ errorlabstrm "Tacinterp.letcut_interp" (str
+ "Do not use Let for toplevel definitions, use Lemma, ... instead")
+ | Some g -> (pf_hyps g,pf_concl g) in
+ (match tac with
+ | VConstr csr ->
+ let cutt = h_cut typ
+ and exat = h_exact csr in
+ tclTHENSV cutt [|tclTHEN (introduction id)
+ (letcut_interp ist tl);exat|]
+
+(* let lic = mkLetIn (Name id,csr,typ,ccl) in
+ let ntac = refine (mkCast (mkMeta (Logic.new_meta ()),lic)) in
+ tclTHEN ntac (tclTHEN (introduction id)
+ (letcut_interp ist tl))*)
+
+ | VIdentifier ir ->
+ (try
+ let cutt = h_cut typ
+ and exat = h_exact (constr_of_id ist ir) in
+ tclTHENSV cutt [| tclTHEN (introduction id)
+ (letcut_interp ist tl); exat |]
+ with | Not_found ->
+ errorlabstrm "Tacinterp.letin_interp"
+ (str "Term or tactic expected"))
+ | _ ->
+ (try
+ let t = tactic_of_value tac in
+ start_proof id (false,NeverDischarge) ndc typ (fun _ _ -> ());
+ by t;
+ let (_,({const_entry_body = pft; const_entry_type = _},_,_)) =
+ cook_proof () in
+ delete_proof id;
+ let cutt = h_cut typ
+ and exat = h_exact pft in
+ tclTHENSV cutt [|tclTHEN (introduction id)
+ (letcut_interp ist tl);exat|]
+
+(* let lic = mkLetIn (Name id,pft,typ,ccl) in
+ let ntac = refine (mkCast (mkMeta (Logic.new_meta ()),lic)) in
+ tclTHEN ntac (tclTHEN (introduction id)
+ (letcut_interp ist tl))*)
+ with | NotTactic ->
+ delete_proof id;
+ errorlabstrm "Tacinterp.letcut_interp"
+ (str "Term or tactic expected")))
+
+(* Interprets the Match Context expressions *)
+and match_context_interp ist lr lmr g =
+(* let goal =
+ (match goalopt with
+ | None ->
+ errorlabstrm "Tacinterp.apply_match_context" (str
+ "No goal available")
+ | Some g -> g) in*)
+ let rec apply_goal_sub ist goal nocc (id,c) csr mt mhyps hyps =
+ try
+ let (lgoal,ctxt) = sub_match nocc c csr in
+ let lctxt = give_context ctxt id in
+ if mhyps = [] then
+ eval_with_fail
+ (val_interp
+ { ist with lfun=lctxt@ist.lfun; lmatch=lgoal@ist.lmatch;
+ goalopt=Some goal})
+ mt goal
+ else
+ apply_hyps_context {ist with goalopt=Some goal} mt lgoal mhyps hyps
+ with
+ | (FailError _) as e -> raise e
+ | NextOccurrence _ -> raise No_match
+ | No_match | _ ->
+ apply_goal_sub ist goal (nocc + 1) (id,c) csr mt mhyps hyps in
+ let rec apply_match_context ist goal = function
+ | (All t)::tl ->
+ (try
+ eval_with_fail (val_interp {ist with goalopt=Some goal }) t
+ goal
+ with No_match | FailError _ -> apply_match_context ist goal tl
+ | e when Logic.catchable_exception e -> apply_match_context ist goal tl)
+ | (Pat (mhyps,mgoal,mt))::tl ->
+ let hyps = make_hyps (pf_hyps goal) in
+ let hyps = if lr then List.rev hyps else hyps in
+ let concl = pf_concl goal in
+ (match mgoal with
+ | Term mg ->
+ (try
+ (let lgoal = apply_matching mg concl in
+ begin
+ db_matched_concl ist.debug ist.env concl;
+ if mhyps = [] then
+ eval_with_fail (val_interp
+ {ist with lmatch=lgoal@ist.lmatch; goalopt=Some goal}) mt goal
+ else
+ apply_hyps_context { ist with goalopt=Some goal} mt lgoal mhyps
+ hyps
+ end)
+ with e when is_match_catchable e -> apply_match_context ist goal tl)
+ | Subterm (id,mg) ->
+ (try
+ apply_goal_sub ist goal 0 (id,mg) concl mt mhyps hyps
+ with e when is_match_catchable e ->
+ apply_match_context ist goal tl))
+ | _ ->
+ errorlabstrm "Tacinterp.apply_match_context" (str
+ "No matching clauses for Match Context")
+
+ in
+ apply_match_context ist g
+ (read_match_rule ist.evc ist.env (constr_list ist) lmr)
+
+(* Interprets a VContext value *)
+and vcontext_interp ist = function
+ | (VContext (ist',lr,lmr)) as v ->
+ (match ist.goalopt with
+ | None -> v
+ | Some g -> (* Relaunch *) match_context_interp ist' lr lmr g)
+ | v -> v
+
+(* Tries to match the hypotheses in a Match Context *)
+and apply_hyps_context ist mt lgmatch mhyps hyps =
+ let rec apply_hyps_context_rec ist mt lfun lmatch mhyps lhyps_mhyp
+ lhyps_rest noccopt =
+ let goal = match ist.goalopt with Some g -> g | _ -> assert false in
+ match mhyps with
+ | hd::tl ->
+ let (lid,lc,lm,newlhyps,hyp_match,noccopt) =
+ apply_one_mhyp_context ist lmatch hd lhyps_mhyp noccopt in
+ begin
+ db_matched_hyp ist.debug ist.env hyp_match;
+ (try
+ if tl = [] then
+ eval_with_fail
+ (val_interp {ist with lfun=lfun@lid@lc@ist.lfun;
+ lmatch=lmatch@lm@ist.lmatch;
+ goalopt=Some goal})
+ mt goal
+ else
+ let nextlhyps =
+ List.fold_left (fun l e -> if e = hyp_match then l else l@[e]) []
+ lhyps_rest in
+ apply_hyps_context_rec ist mt
+ (lfun@lid@lc) (lmatch@lm) tl nextlhyps nextlhyps None
+ with
+ | (FailError _) as e -> raise e
+ | e when is_match_catchable e ->
+ (match noccopt with
+ | None ->
+ apply_hyps_context_rec ist mt lfun
+ lmatch mhyps newlhyps lhyps_rest None
+ | Some nocc ->
+ apply_hyps_context_rec ist mt ist.lfun ist.lmatch mhyps
+ (hyp_match::newlhyps) lhyps_rest (Some (nocc + 1))))
+ end
+ | [] ->
+ anomalylabstrm "apply_hyps_context_rec" (str
+ "Empty list should not occur") in
+ apply_hyps_context_rec ist mt [] lgmatch mhyps hyps hyps None
+
+ (* Interprets extended tactic generic arguments *)
+and genarg_interp ist x =
+ match genarg_tag x with
+ | BoolArgType -> in_gen wit_bool (out_gen rawwit_bool x)
+ | IntArgType -> in_gen wit_int (out_gen rawwit_int x)
+ | IntOrVarArgType ->
+ let f = function
+ | ArgVar (loc,id) ->
+ (match eval_ident ist id with
+ | VInteger n -> ArgArg n
+ | _ ->
+ user_err_loc
+ (loc,"genarg_interp",str "should be bound to an integer"))
+ | ArgArg n as x -> x in
+ in_gen wit_int_or_var (f (out_gen rawwit_int_or_var x))
+ | StringArgType ->
+ in_gen wit_string (out_gen rawwit_string x)
+ | PreIdentArgType ->
+ in_gen wit_pre_ident (out_gen rawwit_pre_ident x)
+ | IdentArgType ->
+ in_gen wit_ident (ident_interp ist (out_gen rawwit_ident x))
+ | QualidArgType ->
+ in_gen wit_qualid (qualid_interp ist (out_gen rawwit_qualid x))
+ | ConstrArgType ->
+ in_gen wit_constr (constr_interp ist (out_gen rawwit_constr x))
+ | ConstrMayEvalArgType ->
+ in_gen wit_constr_may_eval (constr_interp_may_eval ist (out_gen rawwit_constr_may_eval x))
+ | QuantHypArgType ->
+ in_gen wit_quant_hyp
+ (interp_quantified_hypothesis ist (out_gen rawwit_quant_hyp x))
+ | RedExprArgType ->
+ in_gen wit_red_expr (redexp_interp ist (out_gen rawwit_red_expr x))
+ | TacticArgType ->
+ in_gen wit_tactic ((*tactic_interp ist*) (out_gen rawwit_tactic x))
+ | CastedOpenConstrArgType ->
+ in_gen wit_casted_open_constr
+ (cast_openconstr_interp ist (out_gen rawwit_casted_open_constr x))
+ | ConstrWithBindingsArgType ->
+ in_gen wit_constr_with_bindings
+ (interp_constr_with_bindings ist (out_gen rawwit_constr_with_bindings x))
+ | List0ArgType _ -> app_list0 (genarg_interp ist) x
+ | List1ArgType _ -> app_list1 (genarg_interp ist) x
+ | OptArgType _ -> app_opt (genarg_interp ist) x
+ | PairArgType _ -> app_pair (genarg_interp ist) (genarg_interp ist) x
+ | ExtraArgType s -> lookup_genarg_interp s ist x
+
+(* Interprets the Match expressions *)
+and match_interp ist constr lmr =
+ let rec apply_sub_match ist nocc (id,c) csr
+ mt =
+ match ist.goalopt with
+ | None ->
+ (try
+ let (lm,ctxt) = sub_match nocc c csr in
+ let lctxt = give_context ctxt id in
+ val_interp {ist with lfun=lctxt@ist.lfun; lmatch=lm@ist.lmatch} mt
+ with | NextOccurrence _ -> raise No_match)
+ | Some g ->
+ (try
+ let (lm,ctxt) = sub_match nocc c csr in
+ let lctxt = give_context ctxt id in
+ eval_with_fail (val_interp { ist with lfun=lctxt@ist.lfun;
+ lmatch=lm@ist.lmatch})
+ mt g
+ with
+ | NextOccurrence n -> raise No_match
+ | (FailError _) as e -> raise e
+ | e when is_match_catchable e ->
+ apply_sub_match ist (nocc + 1) (id,c) csr mt)
+ in
+ let rec apply_match ist csr = function
+ | (All t)::_ ->
+ (match ist.goalopt with
+ | None ->
+ (try val_interp ist t
+ with e when is_match_catchable e -> apply_match ist csr [])
+ | Some g ->
+ (try
+ eval_with_fail (val_interp ist) t g
+ with
+ | (FailError _) as e -> raise e
+ | e when is_match_catchable e ->
+ apply_match ist csr []))
+ | (Pat ([],mp,mt))::tl ->
+ (match mp with
+ | Term c ->
+ (match ist.goalopt with
+ | None ->
+ (try
+ val_interp
+ { ist with lmatch=(apply_matching c csr)@ist.lmatch } mt
+ with e when is_match_catchable e -> apply_match ist csr tl)
+ | Some g ->
+ (try
+ eval_with_fail (val_interp
+ { ist with lmatch=(apply_matching c csr)@ist.lmatch }) mt g
+ with
+ | (FailError _) as e -> raise e
+ | e when is_match_catchable e ->
+ apply_match ist csr tl))
+ | Subterm (id,c) ->
+ (try
+ apply_sub_match ist 0 (id,c) csr mt
+ with | No_match ->
+ apply_match ist csr tl))
+ | _ ->
+ errorlabstrm "Tacinterp.apply_match" (str
+ "No matching clauses for Match") in
+ let csr = constr_interp_may_eval ist constr
+ and ilr = read_match_rule ist.evc ist.env (constr_list ist) lmr in
+ apply_match ist csr ilr
+
+and tactic_interp ist (ast:raw_tactic_expr) g =
+ tac_interp ist.lfun ist.lmatch ist.debug ast g
+
+(* Interprets tactic expressions *)
+and tac_interp lfun lmatch debug ast g =
+ let evc = project g
+ and env = pf_env g in
+ let ist = { evc=evc; env=env; lfun=lfun; lmatch=lmatch;
+ goalopt=Some g; debug=debug } in
+ try tactic_of_value (val_interp ist ast) g
+ with | NotTactic ->
+ errorlabstrm "Tacinterp.tac_interp" (str
+ "Must be a command or must give a tactic value")
+
+(* errorlabstrm "Tacinterp.tac_interp" (str
+ "Interpretation gives a non-tactic value") *)
+
+(* match (val_interp (evc,env,lfun,lmatch,(Some g),debug) ast) with
+ | VClosure tac -> (tac g)
+ | VFTactic (largs,f) -> (f largs g)
+ | VRTactic res -> res
+ | _ ->
+ errorlabstrm "Tacinterp.tac_interp" (str
+ "Interpretation gives a non-tactic value")*)
+
+(* Interprets a primitive tactic *)
+and interp_atomic ist = function
+ (* Basic tactics *)
+ | TacIntroPattern l ->
+ Elim.h_intro_patterns (List.map (interp_intro_pattern ist) l)
+ | TacIntrosUntil hyp -> h_intros_until (interp_quantified_hypothesis ist hyp)
+ | TacIntroMove (ido,ido') ->
+ h_intro_move (option_app (ident_interp ist) ido)
+ (option_app (fun x -> ident_interp ist (snd x)) ido')
+ | TacAssumption -> h_assumption
+ | TacExact c -> h_exact (cast_constr_interp ist c)
+ | TacApply cb -> h_apply (interp_constr_with_bindings ist cb)
+ | TacElim (cb,cbo) ->
+ h_elim (interp_constr_with_bindings ist cb)
+ (option_app (interp_constr_with_bindings ist) cbo)
+ | TacElimType c -> h_elim_type (constr_interp ist c)
+ | TacCase cb -> h_case (interp_constr_with_bindings ist cb)
+ | TacCaseType c -> h_case_type (constr_interp ist c)
+ | TacFix (idopt,n) -> h_fix (id_opt_interp ist idopt) n
+ | TacMutualFix (id,n,l) ->
+ let f (id,n,c) = (ident_interp ist id,n,constr_interp ist c) in
+ h_mutual_fix (ident_interp ist id) n (List.map f l)
+ | TacCofix idopt -> h_cofix (id_opt_interp ist idopt)
+ | TacMutualCofix (id,l) ->
+ let f (id,c) = (ident_interp ist id,constr_interp ist c) in
+ h_mutual_cofix (ident_interp ist id) (List.map f l)
+ | TacCut c -> h_cut (constr_interp ist c)
+ | TacTrueCut (ido,c) -> h_true_cut (id_opt_interp ist ido) (constr_interp ist c)
+ | TacForward (b,na,c) -> h_forward b (name_interp ist na) (constr_interp ist c)
+ | TacGeneralize cl -> h_generalize (List.map (constr_interp ist) cl)
+ | TacGeneralizeDep c -> h_generalize_dep (constr_interp ist c)
+ | TacLetTac (id,c,clp) ->
+ let clp = check_clause_pattern ist clp in
+ h_let_tac (ident_interp ist id) (constr_interp ist c) clp
+ | TacInstantiate (n,c) -> h_instantiate n (constr_interp ist c)
+
+ (* Automation tactics *)
+ | TacTrivial l -> Auto.h_trivial l
+ | TacAuto (n, l) -> Auto.h_auto n l
+ | TacAutoTDB n -> Dhyp.h_auto_tdb n
+ | TacDestructHyp (b,id) -> Dhyp.h_destructHyp b (hyp_interp ist id)
+ | TacDestructConcl -> Dhyp.h_destructConcl
+ | TacSuperAuto (n,l,b1,b2) -> Auto.h_superauto n l b1 b2
+ | TacDAuto (n,p) -> Auto.h_dauto (n,p)
+
+ (* Derived basic tactics *)
+ | TacOldInduction h -> h_old_induction (interp_quantified_hypothesis ist h)
+ | TacNewInduction c -> h_new_induction (interp_induction_arg ist c)
+ | TacOldDestruct h -> h_old_destruct (interp_quantified_hypothesis ist h)
+ | TacNewDestruct c -> h_new_destruct (interp_induction_arg ist c)
+ | TacDoubleInduction (h1,h2) ->
+ let h1 = interp_quantified_hypothesis ist h1 in
+ let h2 = interp_quantified_hypothesis ist h2 in
+ Elim.h_double_induction h1 h2
+ | TacDecomposeAnd c -> Elim.h_decompose_and (constr_interp ist c)
+ | TacDecomposeOr c -> Elim.h_decompose_or (constr_interp ist c)
+ | TacDecompose (l,c) ->
+ let l = List.map (interp_inductive_or_metanum ist) l in
+ Elim.h_decompose l (constr_interp ist c)
+ | TacSpecialize (n,l) -> h_specialize n (interp_constr_with_bindings ist l)
+ | TacLApply c -> h_lapply (constr_interp ist c)
+
+ (* Context management *)
+ | TacClear l -> h_clear (List.map (hyp_or_metanum_interp ist) l)
+ | TacClearBody l -> h_clear_body (List.map (hyp_or_metanum_interp ist) l)
+ | TacMove (dep,id1,id2) ->
+ h_move dep (hyp_interp ist id1) (hyp_interp ist id2)
+ | TacRename (id1,id2) ->
+ h_rename (hyp_interp ist id1) (hyp_interp ist id2)
+
+ (* Constructors *)
+ | TacLeft bl -> h_left (bindings_interp ist bl)
+ | TacRight bl -> h_right (bindings_interp ist bl)
+ | TacSplit bl -> h_split (bindings_interp ist bl)
+ | TacAnyConstructor t ->
+ abstract_tactic (TacAnyConstructor t)
+ (Tactics.any_constructor (option_app (tactic_interp ist) t))
+ | TacConstructor (n,bl) ->
+ h_constructor (skip_metaid n) (bindings_interp ist bl)
+
+ (* Conversion *)
+ | TacReduce (r,cl) ->
+ h_reduce (redexp_interp ist r) (List.map (interp_hyp_location ist) cl)
+ | TacChange (c,cl) ->
+ h_change (constr_interp ist c) (List.map (interp_hyp_location ist) cl)
+
+ (* Equivalence relations *)
+ | TacReflexivity -> h_reflexivity
+ | TacSymmetry -> h_symmetry
+ | TacTransitivity c -> h_transitivity (constr_interp ist c)
+
+ (* For extensions *)
+ | TacExtend (opn,l) -> vernac_tactic (opn,List.map (genarg_interp ist) l)
+ | TacAlias (_,l,body) ->
+ let f x = match genarg_tag x with
+ | IdentArgType -> VIdentifier (ident_interp ist (out_gen rawwit_ident x))
+ | QualidArgType -> VConstr (constr_of_reference (qualid_interp ist (out_gen rawwit_qualid x)))
+ | ConstrArgType -> VConstr (constr_interp ist (out_gen rawwit_constr x))
+ | ConstrMayEvalArgType ->
+ VConstr (constr_interp_may_eval ist (out_gen rawwit_constr_may_eval x))
+ | _ -> failwith "This generic type is not supported in alias" in
+
+ tactic_of_value (val_interp { ist with lfun=(List.map (fun (x,c) -> (id_of_string x,f c)) l)@ist.lfun } body)
+
+let _ = forward_vcontext_interp := vcontext_interp
+
+(* Interprets tactic arguments *)
+let interp_tacarg sign ast = (*unvarg*) (val_interp sign ast)
+
+(* Initial call for interpretation *)
+let interp = fun ast -> tac_interp [] [] !debug ast
+
+(* Hides interpretation for pretty-print *)
+let hide_interp t = abstract_tactic_expr (TacArg (Tacexp t)) (interp t)
+
+(* For bad tactic calls *)
+let bad_tactic_args s =
+ anomalylabstrm s
+ (str "Tactic " ++ str s ++ str " called with bad arguments")
+
+(* Declaration of the TAC-DEFINITION object *)
+let add (sp,td) = mactab := Gmap.add sp td !mactab
+
+let register_tacdef (sp,td) =
+ let ve = val_interp
+ {evc=Evd.empty;env=Global.env ();lfun=[];
+ lmatch=[]; goalopt=None; debug=get_debug ()}
+ td in
+ sp,ve
+
+let cache_md (_,defs) =
+ (* Needs a rollback if something goes wrong *)
+ List.iter (fun (sp,_) -> Nametab.push_tactic_path sp) defs;
+ List.iter add (List.map register_tacdef defs)
+
+let (inMD,outMD) =
+ declare_object ("TAC-DEFINITION",
+ {cache_function = cache_md;
+ load_function = (fun _ -> ());
+ open_function = cache_md;
+ export_function = (fun x -> Some x)})
+
+(* Adds a definition for tactics in the table *)
+let make_absolute_name (loc,id) =
+ let sp = Lib.make_path id in
+ if Gmap.mem sp !mactab then
+ errorlabstrm "Tacinterp.add_tacdef"
+ (str "There is already a Meta Definition or a Tactic Definition named "
+ ++ pr_sp sp);
+ sp
+
+let add_tacdef tacl =
+ let lfun = List.map (fun ((loc,id),_) -> id) tacl in
+ let tacl = List.map (fun (id,tac) -> (make_absolute_name id,tac)) tacl in
+ List.iter (fun (_,def) -> let _ = glob_tactic (lfun,[]) def in ()) tacl;
+ let _ = Lib.add_leaf (List.hd lfun) (inMD tacl) in
+ List.iter
+ (fun id -> Options.if_verbose msgnl (pr_id id ++ str " is defined")) lfun
+
+let interp_redexp env evc r =
+ let ist =
+ { evc=evc; env=env; lfun=[]; lmatch=[]; goalopt=None; debug=get_debug ()}
+ in
+ redexp_interp ist r
+
+let _ = Auto.set_extern_interp (fun l -> tac_interp [] l (get_debug()))
+let _ = Dhyp.set_extern_interp interp