diff options
| author | herbelin | 2003-01-19 21:53:07 +0000 |
|---|---|---|
| committer | herbelin | 2003-01-19 21:53:07 +0000 |
| commit | 4767404bdc47e8148ab5ea171a0abb43795b01cf (patch) | |
| tree | aa6c294179827422d26889a1fbb12687a3a98e06 | |
| parent | 1a41ba2690897f69c602855a7ccb89b9241d0383 (diff) | |
Restructuration interpréteur de tactique: plus d'évaluation partielle à la définition; suppression TacFunRec, VClosure, VFTactic et VContext; davantage de globalisation statique (notamment pour les tactiques mutuellement récursives); débogueur plus informatif
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@3529 85f007b7-540e-0410-9357-904b9bb8a0f7
| -rw-r--r-- | interp/constrintern.ml | 59 | ||||
| -rw-r--r-- | interp/constrintern.mli | 19 | ||||
| -rw-r--r-- | proofs/tactic_debug.ml | 40 | ||||
| -rw-r--r-- | proofs/tactic_debug.mli | 5 | ||||
| -rw-r--r-- | tactics/tacinterp.ml | 1135 | ||||
| -rw-r--r-- | tactics/tacinterp.mli | 26 |
6 files changed, 599 insertions, 685 deletions
diff --git a/interp/constrintern.ml b/interp/constrintern.ml index cda51446e3..ef92ff3bc2 100644 --- a/interp/constrintern.ml +++ b/interp/constrintern.ml @@ -131,12 +131,19 @@ let set_var_scope loc id (_,_,scopes) (_,_,varscopes) = [vars2] is the set of global variables, env is the set of variables abstracted until this point *) -let intern_var (env,impls,scopes) (vars1,vars2,_) loc id = - (* Is [id] bound in *) +let intern_var (env,impls,scopes) ((vars1,unbndltacvars),vars2,_) loc id = + (* Is [id] bound in current env or ltac vars bound to constr *) if Idset.mem id env or List.mem id vars1 then RVar (loc,id), (try List.assoc id impls with Not_found -> []), [] else + (* Is [id] bound to a free name in ltac (this is an ltac error message) *) + try + match List.assoc id unbndltacvars with + | None -> user_err_loc (loc,"intern_var", + pr_id id ++ str " ist not bound to a term") + | Some id0 -> Pretype_errors.error_var_not_found_loc loc id0 + with Not_found -> (* Is [id] a section variable *) let _ = Sign.lookup_named id vars2 in (* Car Fixpoint met les fns définies temporairement comme vars de sect *) @@ -327,8 +334,8 @@ let check_capture loc ty = function | _ -> () -let locate_if_isevar loc id = function - | RHole _ -> RHole (loc, AbstractionType id) +let locate_if_isevar loc na = function + | RHole _ -> RHole (loc, AbstractionType na)) | x -> x (**********************************************************************) @@ -471,7 +478,8 @@ let internalise isarity sigma env allow_soapp lvar c = if nal <> [] then check_capture loc1 ty na; let ids' = name_fold Idset.add na ids in let body = iterate_prod loc2 (ids',impls,scopes) ty body nal in - RProd (join_loc loc1 loc2, na, intern true env ty, body) + let ty = locate_if_isevar loc1 na (intern true env ty) in + RProd (join_loc loc1 loc2, na, ty, body) | [] -> intern true env body and iterate_lam loc2 isarity (ids,impls,scopes as env) ty body = function @@ -540,18 +548,18 @@ let extract_ids env = (Termops.ids_of_rel_context (Environ.rel_context env)) Idset.empty -let interp_rawconstr_gen isarity sigma env impls allow_soapp lvar c = +let interp_rawconstr_gen isarity sigma env impls allow_soapp ltacvar c = internalise isarity sigma (extract_ids env, impls, []) - allow_soapp (lvar,Environ.named_context env, []) c + allow_soapp (ltacvar,Environ.named_context env, []) c let interp_rawconstr sigma env c = - interp_rawconstr_gen false sigma env [] false [] c + interp_rawconstr_gen false sigma env [] false ([],[]) c let interp_rawtype sigma env c = - interp_rawconstr_gen true sigma env [] false [] c + interp_rawconstr_gen true sigma env [] false ([],[]) c let interp_rawtype_with_implicits sigma env impls c = - interp_rawconstr_gen true sigma env impls false [] c + interp_rawconstr_gen true sigma env impls false ([],[]) c (* (* The same as interp_rawconstr but with a list of variables which must not be @@ -593,20 +601,28 @@ let retype_list sigma env lst = (* List.map (fun (x,csr) -> (x,Retyping.get_judgment_of env sigma csr)) lst*) +type ltac_sign = + identifier list * (identifier * identifier option) list + +type ltac_env = + (identifier * Term.constr) list * (identifier * identifier option) list + (* Interprets a constr according to two lists *) (* of instantiations (variables and metas) *) (* Note: typ is retyped *) -let interp_constr_gen sigma env lvar lmeta c exptyp = - let c = interp_rawconstr_gen false sigma env [] false (List.map fst lvar) c +let interp_constr_gen sigma env (ltacvar,unbndltacvar) lmeta c exptyp = + let c = interp_rawconstr_gen false sigma env [] false + (List.map fst ltacvar,unbndltacvar) c and rtype lst = retype_list sigma env lst in - understand_gen sigma env (rtype lvar) (rtype lmeta) exptyp c;; + understand_gen sigma env (rtype ltacvar) (rtype lmeta) exptyp c;; (*Interprets a casted constr according to two lists of instantiations (variables and metas)*) -let interp_openconstr_gen sigma env lvar lmeta c exptyp = - let c = interp_rawconstr_gen false sigma env [] false (List.map fst lvar) c +let interp_openconstr_gen sigma env (ltacvar,unbndltacvar) lmeta c exptyp = + let c = interp_rawconstr_gen false sigma env [] false + (List.map fst ltacvar,unbndltacvar) c and rtype lst = retype_list sigma env lst in - understand_gen_tcc sigma env (rtype lvar) (rtype lmeta) exptyp c;; + understand_gen_tcc sigma env (rtype ltacvar) (rtype lmeta) exptyp c;; let interp_casted_constr sigma env c typ = understand_gen sigma env [] [] (Some typ) (interp_rawconstr sigma env c) @@ -658,20 +674,21 @@ let pattern_of_rawconstr lvar c = let p = pat_of_raw metas [] lvar c in (!metas,p) -let interp_constrpattern_gen sigma env lvar c = - let c = interp_rawconstr_gen false sigma env [] true (List.map fst lvar) c in - let nlvar = List.map (fun (id,c) -> (id,pattern_of_constr c)) lvar in +let interp_constrpattern_gen sigma env (ltacvar,unbndltacvar) c = + let c = interp_rawconstr_gen false sigma env [] true + (List.map fst ltacvar,unbndltacvar) c in + let nlvar = List.map (fun (id,c) -> (id,pattern_of_constr c)) ltacvar in pattern_of_rawconstr nlvar c let interp_constrpattern sigma env c = - interp_constrpattern_gen sigma env [] c + interp_constrpattern_gen sigma env ([],[]) c let interp_aconstr vars a = let env = Global.env () in (* [vl] is intended to remember the scope of the free variables of [a] *) let vl = List.map (fun id -> (id,ref None)) vars in let c = for_grammar (internalise false Evd.empty (extract_ids env, [], []) - false ([],Environ.named_context env,vl)) a in + false (([],[]),Environ.named_context env,vl)) a in (* Translate and check that [c] has all its free variables bound in [vars] *) let a = aconstr_of_rawconstr vars c in (* Returns [a] and the ordered list of variables with their scopes *) diff --git a/interp/constrintern.mli b/interp/constrintern.mli index 4c185a788e..5478957b56 100644 --- a/interp/constrintern.mli +++ b/interp/constrintern.mli @@ -34,10 +34,16 @@ open Topconstr type implicits_env = (identifier * Impargs.implicits_list) list +type ltac_sign = + identifier list * (identifier * identifier option) list + +type ltac_env = + (identifier * constr) list * (identifier * identifier option) list + (* Interprets global names, including syntactic defs and section variables *) val interp_rawconstr : evar_map -> env -> constr_expr -> rawconstr val interp_rawconstr_gen : bool -> evar_map -> env -> implicits_env -> - bool -> identifier list -> constr_expr -> rawconstr + bool -> ltac_sign -> constr_expr -> rawconstr (*s Composing the translation with typing *) val interp_constr : evar_map -> env -> constr_expr -> constr @@ -62,25 +68,24 @@ val type_judgment_of_rawconstr : (* Interprets a constr according to two lists of instantiations (variables and metas), possibly casting it*) val interp_constr_gen : - evar_map -> env -> (identifier * constr) list -> - (int * constr) list -> constr_expr -> constr option -> constr + evar_map -> env -> ltac_env -> (int * constr) list -> constr_expr -> + constr option -> constr (* Interprets a constr according to two lists of instantiations (variables and metas), possibly casting it, and turning unresolved evar into metas*) val interp_openconstr_gen : - evar_map -> env -> (identifier * constr) list -> + evar_map -> env -> ltac_env -> (int * constr) list -> constr_expr -> constr option -> evar_map * constr (* Interprets constr patterns according to a list of instantiations (variables)*) val interp_constrpattern_gen : - evar_map -> env -> (identifier * constr) list -> constr_expr -> - int list * constr_pattern + evar_map -> env -> ltac_env -> constr_expr -> int list * constr_pattern val interp_constrpattern : evar_map -> env -> constr_expr -> int list * constr_pattern -val interp_reference : identifier list -> reference -> rawconstr +val interp_reference : ltac_sign -> reference -> rawconstr (* Interprets into a abbreviatable constr *) val interp_aconstr : identifier list -> constr_expr -> interpretation diff --git a/proofs/tactic_debug.ml b/proofs/tactic_debug.ml index 43162f05d4..68d1425aa0 100644 --- a/proofs/tactic_debug.ml +++ b/proofs/tactic_debug.ml @@ -16,7 +16,7 @@ open Printer (* Debug information *) type debug_info = - | DebugOn + | DebugOn of int | DebugOff | Exit @@ -31,20 +31,37 @@ let db_pr_goal = function let help () = msgnl (str "Commands: <Enter>=Continue, h=Help, s=Skip, x=Exit") +(* Prints raised exceptions *) +let rec db_print_error = function + | Type_errors.TypeError(ctx,te) -> + hov 0 (str "Type error:" ++ spc ()) + | Pretype_errors.PretypeError(ctx,te) -> + hov 0 (str "Pretype error:" ++ spc ()) + | Logic.RefinerError e -> + hov 0 (str "Refiner error:" ++ spc ()) + | Stdpp.Exc_located (loc,exc) -> + db_print_error exc + | Util.UserError(s,pps) -> + hov 1 (str"Error: " ++ pps) + | GlobalizationError q -> + hov 0 (str "Error: " ++ Libnames.pr_qualid q ++ str " not found") ++ + | _ -> + hov 0 (str "Uncaught exception ") + (* Prints the state and waits for an instruction *) -let debug_prompt goalopt tac_ast = +let debug_prompt level goalopt tac_ast f exit = db_pr_goal goalopt; msg (str "Going to execute:" ++ fnl () ++ (pr_raw_tactic tac_ast) ++ fnl ()); (* str "Commands: <Enter>=Continue, s=Skip, x=Exit" >];*) (* mSG (str "Going to execute:" ++ fnl () ++ (gentacpr tac_ast) ++ fnl () ++ fnl () ++ str "----<Enter>=Continue----s=Skip----x=Exit----");*) let rec prompt () = - msg (fnl () ++ str "TcDebug > "); + msg (fnl () ++ str "TcDebug (" ++ int level ++ str ") > "); flush stdout; let inst = read_line () in (* mSGNL (mt ());*) match inst with - | "" -> DebugOn + | "" -> DebugOn (level+1) | "s" -> DebugOff | "x" -> Exit | "h" -> @@ -53,20 +70,27 @@ let debug_prompt goalopt tac_ast = prompt () end | _ -> prompt () in - prompt () + match prompt () with + | Exit -> exit () + | d -> + try f d + with e when Logic.catchable_exception e -> + ppnl (str "Level " ++ int level ++ str ": " ++ db_print_error e); + raise e (* Prints a constr *) let db_constr debug env c = - if debug = DebugOn then + if debug <> DebugOff & debug <> Exit then msgnl (str "Evaluated term --> " ++ prterm_env env c) (* Prints a matched hypothesis *) let db_matched_hyp debug env (id,c) = - if debug = DebugOn then + if debug <> DebugOff & debug <> Exit then msgnl (str "Matched hypothesis --> " ++ str (Names.string_of_id id^": ") ++ prterm_env env c) (* Prints the matched conclusion *) let db_matched_concl debug env c = - if debug = DebugOn then + if debug <> DebugOff & debug <> Exit then msgnl (str "Matched goal --> " ++ prterm_env env c) + diff --git a/proofs/tactic_debug.mli b/proofs/tactic_debug.mli index b05a33fdfc..1bb8a7f42d 100644 --- a/proofs/tactic_debug.mli +++ b/proofs/tactic_debug.mli @@ -18,12 +18,13 @@ open Term (* Debug information *) type debug_info = - | DebugOn + | DebugOn of int | DebugOff | Exit (* Prints the state and waits *) -val debug_prompt : goal sigma option -> Tacexpr.raw_tactic_expr -> debug_info +val debug_prompt : int -> goal sigma option -> Tacexpr.raw_tactic_expr -> + (debug_info -> 'a) -> (unit -> 'a) -> 'a (* Prints a constr *) val db_constr : debug_info -> Environ.env -> constr -> unit diff --git a/tactics/tacinterp.ml b/tactics/tacinterp.ml index 64bf9371fd..5319b4fc08 100644 --- a/tactics/tacinterp.ml +++ b/tactics/tacinterp.ml @@ -42,10 +42,12 @@ open Hiddentac open Genarg open Decl_kinds +(* 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 @@ -56,39 +58,40 @@ let skip_metaid = function | AI x -> x | MetaId (loc,_) -> error_syntactic_metavariables_not_allowed loc +type ltac_type = + | LtacFun of ltac_type + | LtacBasic + | LtacTactic + (* 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_expr,raw_tactic_expr) match_rule list + | VRTactic of (goal list sigma * validation) (* For Match results *) + (* Not a true value *) | 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 + | VIdentifier of identifier (* idents which are not bound, as in "Intro H" *) + (* but which may be bound later, as in "tac" in*) + (* "Intro H; tac" *) + | VConstr of constr (* includes idents known bound and references *) | 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; + { lfun : (identifier * value) list; lmatch : (int * constr) list; - goalopt : goal sigma option; debug : debug_info } +let check_is_value = function + | VRTactic _ -> (* These are goals produced by Match *) + error "Immediate Match producing tactics not allowed in local definitions" + | _ -> () + (* 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 @@ -115,25 +118,14 @@ let pr_value env = function | 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>" + | (VTactic _ | VRTactic _ | VFun _ | VRec _) -> str "<fun>" (* Transforms a named_context into a (string * constr) list *) let make_hyps = List.map (fun (id,_,typ) -> (id, typ)) -(* Transforms an id into a constr if possible *) -let constr_of_id ist id = - match ist.goalopt with - | None -> construct_reference (Some (Environ.named_context 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) +(* Transforms an id into a constr if possible, or fails *) +let constr_of_id env id = + construct_reference (Some (Environ.named_context env)) id (* To embed several objects in Coqast.t *) let ((tactic_in : (interp_sign -> raw_tactic_expr) -> Dyn.t), @@ -203,20 +195,20 @@ let look_for_interp = Hashtbl.find interp_tab (* Globalizes the identifier *) -let find_reference ist qid = +let find_reference env qid = (* We first look for a variable of the current proof *) - match repr_qualid qid, ist.goalopt with - | (d,id),Some gl when repr_dirpath d = [] & List.mem id (pf_ids_of_hyps gl) + match repr_qualid qid with + | (d,id) when repr_dirpath d = [] & List.mem id (ids_of_context env) -> VarRef id | _ -> Nametab.locate qid -let coerce_to_reference ist = function +let coerce_to_reference env = 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 "The value" ++ spc () ++ pr_value env v ++ str "cannot be coerced to a reference") (* turns a value into an evaluable reference *) @@ -266,7 +258,7 @@ let _ = (* Interpretation of extra generic arguments *) type genarg_interp_type = - interp_sign -> raw_generic_argument -> closed_generic_argument + interp_sign -> goal sigma -> 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 = @@ -283,19 +275,31 @@ let unrec = function (* We have identifier <| global_reference <| constr *) +let find_ident id (lfun,_,_,env) = + List.mem id lfun or + List.mem id (ids_of_named_context (Environ.named_context env)) + (* Globalize a name which can be fresh *) -let glob_ident l ist x = +let glob_ident l ist id = (* 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 + if find_ident id ist then () else l:=id::!l; + id let glob_name l ist = function | Anonymous -> Anonymous | Name id -> Name (glob_ident l ist id) +let get_current_context () = + try Pfedit.get_current_goal_context () + with e when Logic.catchable_exception e -> + (Evd.empty, Global.env()) + +let weak = ref true + (* 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 +let glob_hyp ist (loc,id) = + let (_,env) = get_current_context () in + if !weak or find_ident id ist then id else (* try let _ = lookup (make_short_qualid id) in id @@ -309,8 +313,8 @@ 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_metanum (_,lmeta,_,_) loc n = + if List.mem n lmeta then n else error_unbound_metanum loc n let glob_hyp_or_metanum ist = function | AN id -> AN (glob_hyp ist (loc,id)) @@ -321,7 +325,7 @@ let glob_qualid_or_metanum ist = function | MetaNum (_loc,n) -> MetaNum (loc,glob_metanum ist loc n) let glob_reference ist = function - | Ident (loc,id) as r when List.mem id (fst ist) -> r + | Ident (loc,id) as r when find_ident id ist -> r | r -> Qualid (loc,qualid_of_sp (sp_of_global None (Nametab.global r))) let glob_ltac_qualid ist ref = @@ -330,7 +334,7 @@ let glob_ltac_qualid ist ref = with Not_found -> glob_reference ist ref let glob_ltac_reference ist = function - | Ident (_loc,id) when List.mem id (fst ist) -> Ident (loc,id) + | Ident (_loc,id) when !weak or find_ident id ist -> Ident (loc,id) | r -> glob_ltac_qualid ist r let rec glob_intro_pattern lf ist = function @@ -346,10 +350,10 @@ let glob_quantified_hypothesis ist x = statically check the existence of a quantified hyp); thus nothing to do *) x -let glob_constr ist c = +let glob_constr (lfun,_,sigma,env) c = let _ = - Constrintern.interp_rawconstr_gen false - Evd.empty (Global.env()) [] false (fst ist) c + Constrintern.for_grammar (Constrintern.interp_rawconstr_gen false + sigma env [] false (lfun,[])) c in c (* Globalize bindings *) @@ -412,11 +416,11 @@ let glob_hyp_location ist = function 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 + 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 + let (metas,_) = interp_constrpattern_gen evc env (lfun,[]) pc in metas, Term pc let glob_constr_may_eval ist = function @@ -463,7 +467,7 @@ let extract_let_names lrc = lrc [] (* Globalizes tactics *) -let rec glob_atomic lf ist = function +let rec glob_atomic lf (_,_,_,_ as ist) = function (* Basic tactics *) | TacIntroPattern l -> TacIntroPattern (List.map (glob_intro_pattern lf ist) l) | TacIntrosUntil hyp -> TacIntrosUntil (glob_quantified_hypothesis ist hyp) @@ -558,26 +562,26 @@ let rec glob_atomic lf ist = function | TacExtend (_loc,opn,l) -> let _ = lookup_tactic opn in TacExtend (loc,opn,List.map (glob_genarg ist) l) - | TacAlias (_,l,body) -> failwith "TacAlias globalisation: TODO" + | TacAlias (_,l,body) as t -> + (* failwith "TacAlias globalisation: TODO" *) + t and glob_tactic ist tac = snd (glob_tactic_seq ist tac) -and glob_tactic_seq (lfun,lmeta as ist) = function +and glob_tactic_seq (lfun,lmeta,sigma,env 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 ist = (names@lfun,lmeta,sigma,env) 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 + let ist' = ((extract_let_names l)@lfun,lmeta,sigma,env) 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 @@ -592,12 +596,12 @@ and glob_tactic_seq (lfun,lmeta as ist) = function | 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 + let lfun'', t2 = glob_tactic_seq (lfun',lmeta,sigma,env) 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) + lfun', TacThens (t, List.map (glob_tactic (lfun',lmeta,sigma,env)) 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) @@ -608,9 +612,9 @@ and glob_tactic_seq (lfun,lmeta as ist) = function | 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) = +and glob_tactic_fun (lfun,lmeta,sigma,env) (var,body) = let lfun' = List.rev_append (filter_some var) lfun in - (var,glob_tactic (lfun',lmeta) body) + (var,glob_tactic (lfun',lmeta,sigma,env) body) and glob_tacarg ist = function | TacVoid -> TacVoid @@ -629,15 +633,15 @@ and glob_tacarg ist = function 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 +and glob_match_rule (lfun,lmeta,sigma,env 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) + (Pat (hyps,pat,glob_tactic (lfun',metas,sigma,env) tc)) + ::(glob_match_rule ist tl) | [] -> [] and glob_genarg ist x = @@ -744,15 +748,10 @@ let is_match_catchable = function | e -> Logic.catchable_exception e (* Verifies if the matched list is coherent with respect to lcm *) -let rec verify_metas_coherence ist lcm = function +let rec verify_metas_coherence gl 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) + if (List.for_all (fun (a,b) -> a<>num or pf_conv_x gl b csr) lcm) then + (num,csr)::(verify_metas_coherence gl lcm tl) else raise Not_coherent_metas | [] -> [] @@ -765,12 +764,12 @@ let apply_matching pat csr = 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 apply_one_mhyp_context gl 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] + | Hyp((_,idpat),_) -> [idpat,VConstr (mkVar id)] | NoHypId _ -> [] in let rec apply_one_mhyp_context_rec mhyp lhyps_acc nocc = function | (id,hyp)::tl -> @@ -778,14 +777,14 @@ let apply_one_mhyp_context ist lmatch mhyp lhyps noccopt = | Term t -> (try let lmeta = - verify_metas_coherence ist lmatch (Pattern.matches t hyp) in + verify_metas_coherence gl 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 + let lmeta = verify_metas_coherence gl lmatch lm in (get_id_couple id mhyp,give_context ctxt ic,lmeta,tl,(id,hyp),Some nocc) with @@ -800,17 +799,6 @@ let apply_one_mhyp_context ist lmatch mhyp lhyps noccopt = | 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") @@ -820,21 +808,18 @@ let constr_to_qid loc 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" +let check_clause_pattern ist gl (l,occl) = + 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) (* Debug reference *) let debug = ref DebugOff @@ -845,196 +830,196 @@ let set_debug pos = debug := pos (* Gives the state of debug *) let get_debug () = !debug -(* Interprets an identifier *) +(* Interprets an identifier which must be fresh *) 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 - | VConstr c -> - (match kind_of_term c with - Var id -> id - | Const sp -> id_of_global None (ConstRef sp) - | Ind sp -> id_of_global None (IndRef sp) - | Construct sp -> id_of_global None (ConstructRef sp) - | _ -> - anomalylabstrm "id_of_Identifier" - (str "Not an IDENTIFIER tactic_arg")) + try match List.assoc id ist.lfun with | VIdentifier id -> id - | _ -> - anomalylabstrm "id_of_Identifier" (str "Not an IDENTIFIER tactic_arg") + | _ -> user_err_loc(loc,"eval_ident",str "should be bound to an identifier") + with Not_found -> id -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 eval_integer lfun (loc,id) = + try match List.assoc id lfun with + | VInteger n -> ArgArg n + | _ -> user_err_loc(loc,"eval_integer",str "should be bound to an integer") + with Not_found -> user_err_loc (loc,"eval_integer",str "Unbound variable") + +let constr_of_value env = function + | VConstr csr -> csr + | VIdentifier id -> constr_of_id env id + | _ -> raise Not_found -let ident_interp ist id = - id_of_Identifier (eval_ident ist id) +let is_variable env id = + List.mem id (ids_of_named_context (Environ.named_context env)) -let hyp_interp ist (loc,id) = - coerce_to_hypothesis ist (eval_ident ist id) +let variable_of_value env = function + | VConstr c as v when isVar c -> destVar c + | VIdentifier id' when is_variable env id' -> id' + | _ -> raise Not_found -let name_interp ist = function +(* Extract a variable from a value, if any *) +let id_of_Identifier = variable_of_value + +(* Extract a constr from a value, if any *) +let constr_of_VConstr = constr_of_value + +(* Interprets a variable *) +let eval_variable ist gl (loc,id) = + (* Look first in lfun for a value coercible to a variable *) + try + let v = List.assoc id ist.lfun in + try variable_of_value (pf_env gl) v + with Not_found -> + errorlabstrm "coerce_to_variable" + (str "Cannot coerce" ++ spc () ++ pr_value (pf_env gl) v ++ spc () ++ + str "to a variable") + with Not_found -> + (* Then look if bound in the proof context at calling time *) + if is_variable (pf_env gl) id then id + else + Pretype_errors.error_var_not_found_loc loc id + +let hyp_interp = eval_variable + +let eval_name ist = function | Anonymous -> Anonymous - | Name id -> Name (ident_interp ist id) + | Name id -> Name (eval_ident ist id) -let hyp_or_metanum_interp ist = function - | AN id -> ident_interp ist id +let hyp_or_metanum_interp ist gl = function + | AN id -> eval_variable ist gl (dummy_loc,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 is_applied ist (loc,qid) = - try VConstr (constr_of_reference (find_reference ist qid)) +let interp_pure_qualid is_applied env (loc,qid) = + try VConstr (constr_of_reference (find_reference env qid)) with Not_found -> let (dir,id) = repr_qualid qid in if not is_applied & dir = empty_dirpath then VIdentifier id else user_err_loc (loc,"interp_pure_qualid",str "Unknown reference") -let interp_ltac_qualid is_applied ist (loc,qid as lqid) = - try (!forward_vcontext_interp ist (lookup qid)) - with Not_found -> interp_pure_qualid is_applied ist lqid - -let interp_ltac_reference isapplied ist = function - | Ident (loc,id) -> - (try unrec (List.assoc id ist.lfun) - with | Not_found -> - interp_ltac_qualid isapplied ist (loc,make_short_qualid id)) - | Qualid qid -> interp_ltac_qualid isapplied ist qid - (* Interprets a qualified name *) -let eval_ref ist = function - | Qualid locqid -> interp_pure_qualid false ist locqid +let eval_ref ist env = function + | Qualid locqid -> interp_pure_qualid false env locqid | Ident (loc,id) -> try unrec (List.assoc id ist.lfun) - with Not_found -> interp_pure_qualid false ist (loc,make_short_qualid id) + with Not_found -> interp_pure_qualid false env (loc,make_short_qualid id) + +let reference_interp ist env qid = + let v = eval_ref ist env qid in + coerce_to_reference env v -let reference_interp ist qid = - let v = eval_ref ist qid in - coerce_to_reference ist v +let pf_reference_interp ist gl = reference_interp ist (pf_env gl) (* Interprets a qualified name. This can be a metavariable to be injected *) let qualid_or_metanum_interp ist = function | AN qid -> qid | MetaNum (loc,n) -> constr_to_qid loc (List.assoc n ist.lmatch) -let eval_ref_or_metanum ist = function - | AN qid -> eval_ref ist qid +let eval_ref_or_metanum ist gl = function + | AN qid -> eval_ref ist gl 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_evaluable_or_metanum ist env c = + let c = eval_ref_or_metanum ist env c in + coerce_to_evaluable_ref env c -let interp_inductive_or_metanum ist c = - let c = eval_ref_or_metanum ist c in +let interp_inductive_or_metanum ist gl c = + let c = eval_ref_or_metanum ist (pf_env gl) 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 interp_hyp_location ist gl = function + | InHyp id -> InHyp (hyp_interp ist gl (skip_metaid id)) + | InHypType id -> InHypType (hyp_interp ist gl (skip_metaid id)) -let id_opt_interp ist = option_app (ident_interp ist) +let eval_opt_ident ist = option_app (eval_ident 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 - | [] -> [] +(* Extracted the constr list from lfun *) +let rec constr_list_aux env = function + | (id,v)::tl -> + let (l1,l2) = constr_list_aux env tl in + (try ((id,constr_of_value env v)::l1,l2) + with Not_found -> + (l1,(id,match v with VIdentifier id0 -> Some id0 | _ -> None)::l2)) + | [] -> ([],[]) + +let constr_list ist env = constr_list_aux env ist.lfun + +let interp_constr ocl ist sigma env c = + interp_constr_gen sigma env (constr_list ist env) ist.lmatch c ocl -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 gl c ocl = + interp_openconstr_gen (project gl) (pf_env gl) + (constr_list ist (pf_env gl)) ist.lmatch c ocl -let interp_openconstr ist c ocl = - interp_openconstr_gen ist.evc ist.env (constr_list ist) ist.lmatch c ocl +let pf_interp_constr ist gl = + interp_constr None ist (project gl) (pf_env gl) (* Interprets a constr expression *) -let constr_interp ist c = - let csr = interp_constr None ist c in +let constr_interp ist sigma env c = + let csr = interp_constr None ist sigma env c in begin - db_constr ist.debug ist.env csr; + db_constr ist.debug env csr; csr end +let pf_constr_interp ist gl c = constr_interp ist (project gl) (pf_env gl) c + (* 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") +let cast_constr_interp ist gl c = + let csr = interp_constr (Some (pf_concl gl)) ist (project gl) (pf_env gl) c in + db_constr ist.debug (pf_env gl) csr; + csr (* 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") +let cast_openconstr_interp ist gl c = + interp_openconstr ist gl c (Some (pf_concl gl)) (* Interprets a reduction expression *) -let unfold_interp ist (l,qid) = (l,interp_evaluable_or_metanum ist qid) +let unfold_interp ist env (l,qid) = + (l,interp_evaluable_or_metanum ist env qid) + +let flag_interp ist env red = + { red + with rConst = List.map (interp_evaluable_or_metanum ist env) red.rConst } -let flag_interp ist red = - { red with rConst = List.map (interp_evaluable_or_metanum ist) red.rConst } +let pattern_interp ist sigma env (l,c) = (l,constr_interp ist sigma env c) -let pattern_interp ist (l,c) = (l,constr_interp ist c) +let pf_pattern_interp ist gl = pattern_interp ist (project gl) (pf_env gl) -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) - | Simpl o -> Simpl (option_app (pattern_interp ist) o) +let redexp_interp ist sigma env = function + | Unfold l -> Unfold (List.map (unfold_interp ist env) l) + | Fold l -> Fold (List.map (constr_interp ist sigma env) l) + | Cbv f -> Cbv (flag_interp ist env f) + | Lazy f -> Lazy (flag_interp ist env f) + | Pattern l -> Pattern (List.map (pattern_interp ist sigma env) l) + | Simpl o -> Simpl (option_app (pattern_interp ist sigma env) o) | (Red _ | Hnf as r) -> r - | ExtraRedExpr (s,c) -> ExtraRedExpr (s,constr_interp ist c) + | ExtraRedExpr (s,c) -> ExtraRedExpr (s,constr_interp ist sigma env c) + +let pf_redexp_interp ist gl = redexp_interp ist (project gl) (pf_env gl) -let interp_may_eval f ist = function +let interp_may_eval f ist gl = function | ConstrEval (r,c) -> - let redexp = redexp_interp ist r in - (reduction_of_redexp redexp) ist.env ist.evc (f ist c) + let redexp = pf_redexp_interp ist gl r in + pf_reduction_of_redexp gl redexp (f ist gl c) | ConstrContext ((loc,s),c) -> (try - let ic = f ist c + let ic = f ist gl 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 + | ConstrTypeOf c -> pf_type_of gl (f ist gl c) + | ConstrTerm c -> f ist gl 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 +let constr_interp_may_eval ist gl c = + let csr = interp_may_eval pf_interp_constr ist gl c in begin - db_constr ist.debug ist.env csr; + db_constr ist.debug (pf_env gl) csr; csr end @@ -1044,72 +1029,67 @@ let rec interp_intro_pattern ist = function | IntroWildcard -> IntroWildcard | IntroIdentifier id -> - IntroIdentifier (ident_interp ist id) + IntroIdentifier (eval_ident ist id) -let interp_quantified_hypothesis ist = function +(* Quantified named or numbered hypothesis or hypothesis in context *) +(* (as in Inversion) *) +let interp_quantified_hypothesis ist gl = function | AnonHyp n -> AnonHyp n - | NamedHyp id -> - match eval_ident ist id with + | NamedHyp id -> + try match List.assoc id ist.lfun with | VInteger n -> AnonHyp n - | v -> NamedHyp (coerce_to_hypothesis ist v) + | VIdentifier id -> NamedHyp id + | v -> NamedHyp (variable_of_value (pf_env gl) v) + with Not_found -> NamedHyp id -let interp_induction_arg ist = function - | ElimOnConstr c -> ElimOnConstr (constr_interp ist c) +let interp_induction_arg ist gl = function + | ElimOnConstr c -> ElimOnConstr (pf_constr_interp ist gl 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)))*) - (constr_interp ist (CRef (Ident (loc,id)))) - -let binding_interp ist (loc,b,c) = - (loc,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) + if Tactics.is_quantified_hypothesis id gl then ElimOnIdent (loc,id) + else ElimOnConstr (pf_constr_interp ist gl (CRef (Ident (loc,id)))) + +let binding_interp ist gl (loc,b,c) = + (loc,interp_quantified_hypothesis ist gl b,pf_constr_interp ist gl c) -let interp_constr_with_bindings ist (c,bl) = - (constr_interp ist c, bindings_interp ist bl) +let bindings_interp ist gl = function +| NoBindings -> NoBindings +| ImplicitBindings l -> ImplicitBindings (List.map (pf_constr_interp ist gl) l) +| ExplicitBindings l -> ExplicitBindings (List.map (binding_interp ist gl) l) -(* Interprets a tactic expression *) -let rec val_interp ist ast = +let interp_constr_with_bindings ist gl (c,bl) = + (pf_constr_interp ist gl c, bindings_interp ist gl bl) + +(* Interprets a l-tac expression into a value *) +let rec val_interp ist gl tac = let value_interp ist = - match ast with + match tac 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 + | TacLetRecIn (lrc,u) -> letrec_interp ist gl 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 + let addlfun = letin_interp ist gl l in + val_interp { ist with lfun=addlfun@ist.lfun } gl u + | TacMatchContext (lr,lmr) -> match_context_interp ist gl lr lmr + | TacMatch (c,lmr) -> match_interp ist gl c lmr + | TacArg a -> tacarg_interp ist gl a (* Delayed evaluation *) - | t -> VClosure (ist,t) + | t -> VTactic (eval_tactic 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 + match ist.debug with + | DebugOn n -> + debug_prompt n (Some gl) tac + (fun v -> value_interp {ist with debug=v}) + (fun () -> VTactic tclIDTAC) + | _ -> value_interp ist and eval_tactic ist = function | TacAtom (loc,t) -> fun gl -> - (try interp_atomic ist t gl + (try (interp_atomic ist gl t) gl 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 @@ -1130,19 +1110,24 @@ and eval_tactic ist = function 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 +and interp_ltac_qualid is_applied ist gl (loc,qid as lqid) = + try val_interp ist gl (lookup qid) + with Not_found -> interp_pure_qualid is_applied (pf_env gl) lqid + +and interp_ltac_reference isapplied ist gl = function + | Ident (loc,id) -> + (try unrec (List.assoc id ist.lfun) + with | Not_found -> + interp_ltac_qualid isapplied ist gl (loc,make_short_qualid id)) + | Qualid qid -> interp_ltac_qualid isapplied ist gl qid + +and tacarg_interp ist gl = function | TacVoid -> VVoid - | Reference r -> interp_ltac_reference false ist r + | Reference r -> interp_ltac_reference false ist gl r | Integer n -> VInteger n - | ConstrMayEval c -> VConstr (constr_interp_may_eval ist c) + | ConstrMayEval c -> VConstr (constr_interp_may_eval ist gl c) | MetaNumArg (_,n) -> VConstr (List.assoc n ist.lmatch) | MetaIdArg (loc,id) -> (try (* $id can occur in Grammar tactic... *) @@ -1150,17 +1135,15 @@ and tacarg_interp ist = function with | Not_found -> error_syntactic_metavariables_not_allowed loc) | TacCall (loc,f,l) -> - let fv = interp_ltac_reference true ist f - and largs = List.map (tacarg_interp ist) l in - app_interp ist fv largs loc - | Tacexp t -> val_interp ist t -(* - | Tacexp t -> VArg (Tacexp ((*tactic_interp ist t,*)t)) -*) + let fv = interp_ltac_reference true ist gl f + and largs = List.map (tacarg_interp ist gl) l in + List.iter check_is_value largs; + app_interp ist gl fv largs loc + | Tacexp t -> val_interp ist gl t | TacDynamic(_,t) -> let tg = (tag t) in if tg = "tactic" then - let f = (tactic_out t) in val_interp ist (f ist) + let f = (tactic_out t) in val_interp ist gl (f ist) else if tg = "value" then value_out t else if tg = "constr" then @@ -1170,17 +1153,13 @@ and tacarg_interp ist = function (str "Unknown dynamic: <" ++ str (Dyn.tag t) ++ str ">")) (* Interprets an application node *) -and app_interp ist fv largs loc = +and app_interp ist gl 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 + let v = val_interp { ist with lfun=newlfun@olfun } gl body in + if lval=[] then v else app_interp ist gl v lval loc else VFun(newlfun@olfun,lvar,body) | _ -> @@ -1190,19 +1169,15 @@ and app_interp ist fv largs loc = (* 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 | VFun _ -> error "A fully applied tactic is expected" | _ -> raise NotTactic (* Evaluation with FailError catching *) -and eval_with_fail interp ast goal = +and eval_with_fail interp tac goal = try - (match interp ast with - | VClosure (ist,tac) -> VRTactic (eval_tactic ist tac goal) - | VFTactic (largs,f) -> VRTactic (f largs goal) + (match interp goal tac with | VTactic tac -> VRTactic (tac goal) | a -> a) with | FailError lvl -> @@ -1212,241 +1187,179 @@ and eval_with_fail interp ast goal = 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) +and letrec_interp ist gl 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)) -> + 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 + begin + List.iter2 (fun vref (_,ve) -> vref:=ve) lref lve; + val_interp { ist with lfun=lve@ist.lfun } gl u + end -(* Interprets the clauses of a LetCutIn *) -and letin_interp ist = function +(* Interprets the clauses of a LetIn *) +and letin_interp ist gl = function | [] -> [] - | ((loc,id),None,t)::tl -> (id,tacarg_interp ist t):: (letin_interp ist tl) + | ((loc,id),None,t)::tl -> + let v = tacarg_interp ist gl t in + check_is_value v; + (id,v):: (letin_interp ist gl 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 IsLocal ndc typ (fun _ _ -> ()); - by t; - let (_,({const_entry_body = pft; const_entry_type = _},_,_)) = - cook_proof () in - delete_proof (dummy_loc,id); - (id,VConstr (mkCast (pft,typ)))::(letin_interp ist tl) - with | NotTactic -> - delete_proof (dummy_loc,id); - errorlabstrm "Tacinterp.letin_interp" - (str "Term or fully applied tactic expected in Let")) + let typ = interp_may_eval pf_interp_constr ist gl com + and v = tacarg_interp ist gl tce in + let csr = + try + constr_of_value (pf_env gl) v + with Not_found -> + try + let t = tactic_of_value v in + let ndc = Environ.named_context (pf_env gl) in + start_proof id IsLocal ndc typ (fun _ _ -> ()); + by t; + let (_,({const_entry_body = pft},_,_)) = cook_proof () in + delete_proof (dummy_loc,id); + pft + with | NotTactic -> + delete_proof (dummy_loc,id); + errorlabstrm "Tacinterp.letin_interp" + (str "Term or fully applied tactic expected in Let") + in (id,VConstr (mkCast (csr,typ)))::(letin_interp ist gl tl) (* Interprets the clauses of a LetCut *) -and letcut_interp ist = function +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|] + | (id,c,tce)::tl -> fun gl -> + let typ = constr_interp_may_eval ist gl c + and v = tacarg_interp ist gl tce in + let csr = + try + constr_of_value (pf_env gl) v + with Not_found -> + try + let t = tactic_of_value v in + start_proof id IsLocal (pf_hyps gl) typ (fun _ _ -> ()); + by t; + let (_,({const_entry_body = pft},_,_)) = cook_proof () in + delete_proof (dummy_loc,id); + pft + with | NotTactic -> + delete_proof (dummy_loc,id); + errorlabstrm "Tacinterp.letin_interp" + (str "Term or fully applied tactic expected in Let") + in + let cutt = h_cut typ + and exat = h_exact csr in + tclTHENSV cutt [|tclTHEN (introduction id) (letcut_interp ist tl);exat|] gl (* 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 IsLocal ndc typ (fun _ _ -> ()); - by t; - let (_,({const_entry_body = pft; const_entry_type = _},_,_)) = - cook_proof () in - delete_proof (dummy_loc,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 (dummy_loc,id); - errorlabstrm "Tacinterp.letcut_interp" - (str "Term or fully applied tactic expected in Let"))) - (* 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 = +and match_context_interp ist goal lr lmr = + let rec apply_goal_sub ist 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}) + (val_interp {ist with lfun=lctxt@ist.lfun; lmatch=lgoal@ist.lmatch}) mt goal else - apply_hyps_context {ist with goalopt=Some goal} mt lgoal mhyps hyps + apply_hyps_context ist 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 + apply_goal_sub ist (nocc + 1) (id,c) csr mt mhyps hyps in + let rec apply_match_context ist = 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) + eval_with_fail (val_interp ist) t goal + with No_match | FailError _ -> apply_match_context ist tl + | e when Logic.catchable_exception e -> apply_match_context ist 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 mhyps = List.rev mhyps (* Sens naturel *) 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; + db_matched_concl ist.debug (pf_env goal) concl; if mhyps = [] then - eval_with_fail (val_interp - {ist with lmatch=lgoal@ist.lmatch; goalopt=Some goal}) mt goal + eval_with_fail + (val_interp {ist with lmatch=lgoal@ist.lmatch}) mt goal else - apply_hyps_context { ist with goalopt=Some goal} mt lgoal mhyps - hyps + apply_hyps_context ist goal mt lgoal mhyps hyps end) - with e when is_match_catchable e -> apply_match_context ist goal tl) + with e when is_match_catchable e -> apply_match_context ist tl) | Subterm (id,mg) -> (try - apply_goal_sub ist goal 0 (id,mg) concl mt mhyps hyps + apply_goal_sub ist 0 (id,mg) concl mt mhyps hyps with e when is_match_catchable e -> - apply_match_context ist goal tl)) + apply_match_context ist 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 as go -> - let ist = { ist' with goalopt = go; env = pf_env g; evc = project g } - in match_context_interp ist lr lmr g) - | v -> v + let env = pf_env goal in + apply_match_context ist + (read_match_rule (project goal) env (constr_list ist env) lmr) (* 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 +and apply_hyps_context ist goal mt lgmatch mhyps hyps = + let rec apply_hyps_context_rec 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 + apply_one_mhyp_context goal lmatch hd lhyps_mhyp noccopt in begin - db_matched_hyp ist.debug ist.env hyp_match; + db_matched_hyp ist.debug (pf_env goal) 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}) + lmatch=lmatch@lm@ist.lmatch}) 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 + apply_hyps_context_rec 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 + apply_hyps_context_rec mt lfun lmatch mhyps newlhyps lhyps_rest None | Some nocc -> - apply_hyps_context_rec ist mt ist.lfun ist.lmatch mhyps + apply_hyps_context_rec 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 + apply_hyps_context_rec mt [] lgmatch mhyps hyps hyps None (* Interprets extended tactic generic arguments *) -and genarg_interp ist x = +and genarg_interp ist goal 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")) + | ArgVar locid -> eval_integer ist.lfun locid | ArgArg n as x -> x in in_gen wit_int_or_var (f (out_gen rawwit_int_or_var x)) | StringArgType -> @@ -1454,251 +1367,217 @@ and genarg_interp ist 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)) + in_gen wit_ident (out_gen rawwit_ident x) | RefArgType -> - in_gen wit_ref (reference_interp ist (out_gen rawwit_ref x)) + in_gen wit_ref (pf_reference_interp ist goal (out_gen rawwit_ref x)) | SortArgType -> in_gen wit_sort (destSort - (constr_interp ist (CSort (dummy_loc,out_gen rawwit_sort x)))) + (pf_constr_interp ist goal (CSort (dummy_loc,out_gen rawwit_sort x)))) | ConstrArgType -> - in_gen wit_constr (constr_interp ist (out_gen rawwit_constr x)) + in_gen wit_constr (pf_constr_interp ist goal (out_gen rawwit_constr x)) | ConstrMayEvalArgType -> - in_gen wit_constr_may_eval (constr_interp_may_eval ist (out_gen rawwit_constr_may_eval x)) + in_gen wit_constr_may_eval (constr_interp_may_eval ist goal (out_gen rawwit_constr_may_eval x)) | QuantHypArgType -> in_gen wit_quant_hyp - (interp_quantified_hypothesis ist (out_gen rawwit_quant_hyp x)) + (interp_quantified_hypothesis ist goal (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)) + in_gen wit_red_expr (pf_redexp_interp ist goal (out_gen rawwit_red_expr x)) + | TacticArgType -> in_gen wit_tactic (out_gen rawwit_tactic x) | CastedOpenConstrArgType -> in_gen wit_casted_open_constr - (cast_openconstr_interp ist (out_gen rawwit_casted_open_constr x)) + (cast_openconstr_interp ist goal (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 + (interp_constr_with_bindings ist goal (out_gen rawwit_constr_with_bindings x)) + | List0ArgType _ -> app_list0 (genarg_interp ist goal) x + | List1ArgType _ -> app_list1 (genarg_interp ist goal) x + | OptArgType _ -> app_opt (genarg_interp ist goal) x + | PairArgType _ -> app_pair (genarg_interp ist goal) (genarg_interp ist goal) x + | ExtraArgType s -> lookup_genarg_interp s ist goal 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) +and match_interp ist g constr lmr = + let rec apply_sub_match ist nocc (id,c) csr mt = + 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 + 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 ([],Term c,mt))::tl -> + (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) + | (Pat ([],Subterm (id,c),mt))::tl -> + (try + apply_sub_match ist 0 (id,c) csr mt with | No_match -> - apply_match ist csr tl)) + 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 + let csr = constr_interp_may_eval ist g constr in + let env = pf_env g in + let ilr = read_match_rule (project g) env (constr_list ist env) 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 +(* Interprets tactic expressions : returns a "tactic" *) +and tactic_interp ist tac g = + try tactic_of_value (val_interp ist g tac) 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 +and interp_atomic ist gl = 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) + | TacIntrosUntil hyp -> + h_intros_until (interp_quantified_hypothesis ist gl hyp) | TacIntroMove (ido,ido') -> - h_intro_move (option_app (ident_interp ist) ido) - (option_app (fun x -> ident_interp ist (snd x)) ido') + h_intro_move (option_app (eval_ident ist) ido) + (option_app (fun x -> eval_variable ist gl x) ido') | TacAssumption -> h_assumption - | TacExact c -> h_exact (cast_constr_interp ist c) - | TacApply cb -> h_apply (interp_constr_with_bindings ist cb) + | TacExact c -> h_exact (cast_constr_interp ist gl c) + | TacApply cb -> h_apply (interp_constr_with_bindings ist gl 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 + h_elim (interp_constr_with_bindings ist gl cb) + (option_app (interp_constr_with_bindings ist gl) cbo) + | TacElimType c -> h_elim_type (pf_constr_interp ist gl c) + | TacCase cb -> h_case (interp_constr_with_bindings ist gl cb) + | TacCaseType c -> h_case_type (pf_constr_interp ist gl c) + | TacFix (idopt,n) -> h_fix (eval_opt_ident 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) + let f (id,n,c) = (eval_ident ist id,n,pf_constr_interp ist gl c) in + h_mutual_fix (eval_ident ist id) n (List.map f l) + | TacCofix idopt -> h_cofix (eval_opt_ident 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) + let f (id,c) = (eval_ident ist id,pf_constr_interp ist gl c) in + h_mutual_cofix (eval_ident ist id) (List.map f l) + | TacCut c -> h_cut (pf_constr_interp ist gl c) + | TacTrueCut (ido,c) -> h_true_cut (eval_opt_ident ist ido) (pf_constr_interp ist gl c) + | TacForward (b,na,c) -> h_forward b (eval_name ist na) (pf_constr_interp ist gl c) + | TacGeneralize cl -> h_generalize (List.map (pf_constr_interp ist gl) cl) + | TacGeneralizeDep c -> h_generalize_dep (pf_constr_interp ist gl 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) + let clp = check_clause_pattern ist gl clp in + h_let_tac (eval_ident ist id) (pf_constr_interp ist gl c) clp + | TacInstantiate (n,c) -> h_instantiate n (pf_constr_interp ist gl 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) + | TacDestructHyp (b,id) -> Dhyp.h_destructHyp b (hyp_interp ist gl 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) + | TacOldInduction h -> h_old_induction (interp_quantified_hypothesis ist gl h) | TacNewInduction (c,cbo,ids) -> - h_new_induction (interp_induction_arg ist c) - (option_app (interp_constr_with_bindings ist) cbo) - (List.map (List.map (ident_interp ist)) ids) - | TacOldDestruct h -> h_old_destruct (interp_quantified_hypothesis ist h) + h_new_induction (interp_induction_arg ist gl c) + (option_app (interp_constr_with_bindings ist gl) cbo) + (List.map (List.map (eval_ident ist)) ids) + | TacOldDestruct h -> h_old_destruct (interp_quantified_hypothesis ist gl h) | TacNewDestruct (c,cbo,ids) -> - h_new_destruct (interp_induction_arg ist c) - (option_app (interp_constr_with_bindings ist) cbo) - (List.map (List.map (ident_interp ist)) ids) + h_new_destruct (interp_induction_arg ist gl c) + (option_app (interp_constr_with_bindings ist gl) cbo) + (List.map (List.map (eval_ident ist)) ids) | TacDoubleInduction (h1,h2) -> - let h1 = interp_quantified_hypothesis ist h1 in - let h2 = interp_quantified_hypothesis ist h2 in + let h1 = interp_quantified_hypothesis ist gl h1 in + let h2 = interp_quantified_hypothesis ist gl 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) + | TacDecomposeAnd c -> Elim.h_decompose_and (pf_constr_interp ist gl c) + | TacDecomposeOr c -> Elim.h_decompose_or (pf_constr_interp ist gl 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) + let l = List.map (interp_inductive_or_metanum ist gl) l in + Elim.h_decompose l (pf_constr_interp ist gl c) + | TacSpecialize (n,l) -> h_specialize n (interp_constr_with_bindings ist gl l) + | TacLApply c -> h_lapply (pf_constr_interp ist gl 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) + | TacClear l -> h_clear (List.map (hyp_or_metanum_interp ist gl) l) + | TacClearBody l -> h_clear_body (List.map (hyp_or_metanum_interp ist gl) l) | TacMove (dep,id1,id2) -> - h_move dep (hyp_interp ist id1) (hyp_interp ist id2) + h_move dep (hyp_interp ist gl id1) (hyp_interp ist gl id2) | TacRename (id1,id2) -> - h_rename (hyp_interp ist id1) (hyp_interp ist id2) + h_rename (hyp_interp ist gl id1) (eval_ident ist (snd 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) + | TacLeft bl -> h_left (bindings_interp ist gl bl) + | TacRight bl -> h_right (bindings_interp ist gl bl) + | TacSplit bl -> h_split (bindings_interp ist gl 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) + h_constructor (skip_metaid n) (bindings_interp ist gl bl) (* Conversion *) | TacReduce (r,cl) -> - h_reduce (redexp_interp ist r) (List.map (interp_hyp_location ist) cl) + h_reduce (pf_redexp_interp ist gl r) (List.map (interp_hyp_location ist gl) cl) | TacChange (occl,c,cl) -> - h_change (option_app (pattern_interp ist) occl) - (constr_interp ist c) (List.map (interp_hyp_location ist) cl) + h_change (option_app (pf_pattern_interp ist gl) occl) + (pf_constr_interp ist gl c) (List.map (interp_hyp_location ist gl) cl) (* Equivalence relations *) | TacReflexivity -> h_reflexivity | TacSymmetry -> h_symmetry - | TacTransitivity c -> h_transitivity (constr_interp ist c) + | TacTransitivity c -> h_transitivity (pf_constr_interp ist gl c) (* For extensions *) - | TacExtend (loc,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)) - | RefArgType -> VConstr (constr_of_reference (reference_interp ist (out_gen rawwit_ref 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) -> (x,f c)) l)@ist.lfun } body) + | TacExtend (loc,opn,l) -> + fun gl -> vernac_tactic (opn,List.map (genarg_interp ist gl) l) gl + | TacAlias (_,l,body) -> fun gl -> + let f x = match genarg_tag x with + | IdentArgType -> + let id = out_gen rawwit_ident x in + (try VConstr (mkVar (eval_variable ist gl (dummy_loc,id))) + with Not_found -> VIdentifier id) + | RefArgType -> VConstr (constr_of_reference (pf_reference_interp ist gl (out_gen rawwit_ref x))) + | ConstrArgType -> VConstr (pf_constr_interp ist gl (out_gen rawwit_constr x)) + | ConstrMayEvalArgType -> + VConstr (constr_interp_may_eval ist gl (out_gen rawwit_constr_may_eval x)) + | _ -> failwith "This generic type is not supported in alias" + in + let lfun = (List.map (fun (x,c) -> (x,f c)) l)@ist.lfun in + tactic_of_value (val_interp { ist with lfun=lfun } gl body) gl -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 +let tac_interp lfun lmatch debug t = + tactic_interp { lfun=lfun; lmatch=lmatch; debug=debug } t + +let interp = tac_interp [] [] (get_debug()) (* Hides interpretation for pretty-print *) -let hide_interp t ot = +let hide_interp t ot gl = + let te = glob_tactic ([],[],project gl,pf_env gl) t in match ot with - | None -> abstract_tactic_expr (TacArg (Tacexp t)) (interp t) - | Some t' -> abstract_tactic_expr (TacArg (Tacexp t)) (tclTHEN (interp t) t') + | None -> abstract_tactic_expr (TacArg (Tacexp t)) (interp t) gl + | Some t' -> + abstract_tactic_expr (TacArg (Tacexp t)) (tclTHEN (interp t) t') gl (* For bad tactic calls *) let bad_tactic_args s = @@ -1708,12 +1587,7 @@ let bad_tactic_args s = (* 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 register_tacdef (sp,td) = sp,td let cache_md (_,defs) = (* Needs a rollback if something goes wrong *) @@ -1735,19 +1609,18 @@ let make_absolute_name (loc,id) = ++ pr_sp sp); sp -let add_tacdef tacl = +let add_tacdef isrec tacl = let lfun = List.map (fun ((loc,id),_) -> id) tacl in + let ist = ((if isrec then lfun else []), [], Evd.empty, Global.env()) 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 tacl = List.map (fun (id,def) -> (id,glob_tactic ist def)) tacl in 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 interp_redexp env evc r = + let ist = { lfun=[]; lmatch=[]; debug=get_debug () } in + redexp_interp ist evc env r let _ = Auto.set_extern_interp (fun l -> tac_interp [] l (get_debug())) let _ = Dhyp.set_extern_interp interp diff --git a/tactics/tacinterp.mli b/tactics/tacinterp.mli index c22ce9829c..9d63f33ef4 100644 --- a/tactics/tacinterp.mli +++ b/tactics/tacinterp.mli @@ -23,12 +23,8 @@ open Topconstr (* 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_expr,raw_tactic_expr) match_rule list | VFun of (identifier * value) list * identifier option list *raw_tactic_expr | VVoid | VInteger of int @@ -39,21 +35,18 @@ type value = (* Signature for interpretation: val\_interp and interpretation functions *) and interp_sign = - { evc : Evd.evar_map; - env : Environ.env; - lfun : (identifier * value) list; + { lfun : (identifier * value) list; lmatch : (int * constr) list; - goalopt : goal sigma option; debug : debug_info } (* Gives the identifier corresponding to an Identifier [tactic_arg] *) -val id_of_Identifier : value -> identifier +val id_of_Identifier : Environ.env -> value -> identifier (* Gives the constr corresponding to a Constr [value] *) -val constr_of_VConstr : value -> constr +val constr_of_VConstr : Environ.env -> value -> constr (* Transforms an id into a constr if possible *) -val constr_of_id : interp_sign -> identifier -> constr +val constr_of_id : Environ.env -> identifier -> constr (* To embed several objects in Coqast.t *) val tacticIn : (interp_sign -> raw_tactic_expr) -> raw_tactic_expr @@ -70,18 +63,19 @@ val set_debug : debug_info -> unit val get_debug : unit -> debug_info (* Adds a definition for tactics in the table *) -val add_tacdef : (identifier Util.located * raw_tactic_expr) list -> unit +val add_tacdef : + bool -> (identifier Util.located * raw_tactic_expr) list -> unit (* Adds an interpretation function for extra generic arguments *) val add_genarg_interp : string -> - (interp_sign -> raw_generic_argument -> closed_generic_argument) -> unit + (interp_sign -> goal sigma -> raw_generic_argument -> closed_generic_argument) -> unit val genarg_interp : - interp_sign -> raw_generic_argument -> closed_generic_argument + interp_sign -> goal sigma -> raw_generic_argument -> closed_generic_argument (* Interprets any expression *) -val val_interp : interp_sign -> raw_tactic_expr -> value +val val_interp : interp_sign -> goal sigma -> raw_tactic_expr -> value (* (* Interprets tactic arguments *) @@ -97,7 +91,7 @@ val tac_interp : (identifier * value) list -> (int * constr) list -> debug_info -> raw_tactic_expr -> tactic (* Interprets constr expressions *) -val constr_interp : interp_sign -> constr_expr -> constr +val constr_interp : interp_sign -> Evd.evar_map -> Environ.env -> constr_expr -> constr (* Initial call for interpretation *) val interp : raw_tactic_expr -> tactic |
