diff options
Diffstat (limited to 'tactics/tacinterp.ml')
-rw-r--r-- | tactics/tacinterp.ml | 1363 |
1 files changed, 796 insertions, 567 deletions
diff --git a/tactics/tacinterp.ml b/tactics/tacinterp.ml index 0e0ccac2e..04624e1a1 100644 --- a/tactics/tacinterp.ml +++ b/tactics/tacinterp.ml @@ -43,6 +43,7 @@ open Miscops open Locus open Tacintern open Taccoerce +open Proofview.Notations let safe_msgnl s = let _ = @@ -55,8 +56,7 @@ type value = tlevel generic_argument (* Values for interpretation *) type tacvalue = - | VRTactic of (goal list sigma) (* For Match results *) - (* Not a true tacvalue *) + | VRTactic (* variant of unit returned by match. For historical reasons. *) | VFun of ltac_trace * value Id.Map.t * Id.t option list * glob_tactic_expr | VRec of value Id.Map.t ref * glob_tactic_expr @@ -71,19 +71,18 @@ module Value = Taccoerce.Value let dloc = Loc.ghost -let catch_error call_trace tac g = - try tac g with e when Errors.noncritical e -> +let catching_error call_trace fail e = let e = Errors.push e in let inner_trace, e = match Exninfo.get e ltac_trace_info with | Some inner_trace -> inner_trace, e | None -> [], e in - if List.is_empty call_trace && List.is_empty inner_trace then raise e + if List.is_empty call_trace & List.is_empty inner_trace then fail e else begin assert (Errors.noncritical e); (* preserved invariant *) let new_trace = inner_trace @ call_trace in let located_exc = Exninfo.add e ltac_trace_info new_trace in - raise located_exc + fail located_exc end module TacStore = Geninterp.TacStore @@ -93,6 +92,13 @@ let f_avoid_ids : Id.t list TacStore.field = TacStore.field () let f_debug : debug_info TacStore.field = TacStore.field () let f_trace : ltac_trace TacStore.field = TacStore.field () +let catch_error call_trace f x = + try f x with e when Errors.noncritical e -> catching_error call_trace raise e +let catch_error_tac call_trace tac = + Proofview.tclORELSE + tac + (catching_error call_trace Proofview.tclZERO) + (* Signature for interpretation: val_interp and interpretation functions *) type interp_sign = Geninterp.interp_sign = { lfun : value Id.Map.t; @@ -107,7 +113,7 @@ let check_is_value v = if has_type v (topwit wit_tacvalue) then let v = to_tacvalue v in match v with - | VRTactic _ -> (* These are goals produced by Match *) + | VRTactic -> (* These are goals produced by Match *) error "Immediate match producing tactics not allowed in local definitions." | _ -> () else () @@ -248,7 +254,7 @@ let coerce_to_tactic loc id v = if has_type v (topwit wit_tacvalue) then let tacv = to_tacvalue v in match tacv with - | VFun _ | VRTactic _ -> v + | VFun _ | VRTactic -> v | _ -> fail () else fail () @@ -966,7 +972,17 @@ let verify_metas_coherence gl (ln1,lcm) (ln,lm) = let adjust (l, lc) = (l, Id.Map.map (fun c -> [], c) lc) -type 'a extended_matching_result = + +(* spiwack: a small wrapper around the [Matching] module *) + +type 'a _matching_result = + { s_sub : bound_ident_map * patvar_map ; + s_ctx : 'a ; + s_nxt : 'a matching_result } +and 'a matching_result = 'a _matching_result Goal.sensitive Proofview.tactic + + +type 'a _extended_matching_result = { e_ctx : 'a; e_sub : bound_ident_map * extended_patvar_map; } @@ -1051,168 +1067,156 @@ let extend_gl_hyps { it=gl ; sigma=sigma } sign = Goal.V82.new_goal_with sigma gl sign (* Interprets an l-tac expression into a value *) -let rec val_interp ist gl (tac:glob_tactic_expr) : Evd.evar_map * typed_generic_argument = +let rec val_interp ist (tac:glob_tactic_expr) : typed_generic_argument Goal.sensitive Proofview.tactic = let value_interp ist = match tac with (* Immediate evaluation *) | TacFun (it,body) -> let v = VFun (extract_trace ist,ist.lfun,it,body) in - project gl, of_tacvalue v - | TacLetIn (true,l,u) -> interp_letrec ist gl l u - | TacLetIn (false,l,u) -> interp_letin ist gl l u - | TacMatchGoal (lz,lr,lmr) -> interp_match_goal ist gl lz lr lmr - | TacMatch (lz,c,lmr) -> interp_match ist gl lz c lmr - | TacArg (loc,a) -> interp_tacarg ist gl a + Proofview.tclUNIT (Goal.return (of_tacvalue v)) + | TacLetIn (true,l,u) -> interp_letrec ist l u + | TacLetIn (false,l,u) -> interp_letin ist l u + | TacMatchGoal (lz,lr,lmr) -> interp_match_goal ist lz lr lmr + | TacMatch (lz,c,lmr) -> interp_match ist lz c lmr + | TacArg (loc,a) -> interp_tacarg ist a (* Delayed evaluation *) | t -> let v = VFun (extract_trace ist,ist.lfun,[],t) in - project gl, of_tacvalue v - + Proofview.tclUNIT (Goal.return (of_tacvalue v)) in check_for_interrupt (); - match curr_debug ist with - | DebugOn lev -> - let eval v = - let ist = { ist with extra = TacStore.set ist.extra f_debug v } in - value_interp ist - in - debug_prompt lev gl tac eval - | _ -> value_interp ist + match curr_debug ist with + (* arnaud: todo: debug + | DebugOn lev -> + debug_prompt lev gl tac (fun v -> value_interp {ist with debug=v}) + *) + | _ -> value_interp ist + and eval_tactic ist = function | TacAtom (loc,t) -> - fun gl -> - let call = LtacAtomCall t in - let tac = (* catch error in the interpretation *) - catch_error (push_trace(dloc,call)ist) - (interp_atomic ist gl) t in - (* catch error in the evaluation *) - catch_error (push_trace(loc,call)ist) tac gl + let call = LtacAtomCall t in + catch_error_tac (push_trace(loc,call) ist) (interp_atomic ist t) | TacFun _ | TacLetIn _ -> assert false | TacMatchGoal _ | TacMatch _ -> assert false - | TacId s -> fun gl -> - let res = tclIDTAC_MESSAGE (interp_message_nl ist gl s) gl in - db_breakpoint (curr_debug ist) s; res - | TacFail (n,s) -> fun gl -> tclFAIL (interp_int_or_var ist n) (interp_message ist gl s) gl - | TacProgress tac -> tclPROGRESS (interp_tactic ist tac) - | TacShowHyps tac -> tclSHOWHYPS (interp_tactic ist tac) + | TacId s -> Proofview.V82.tactic begin fun gl -> + let res = tclIDTAC_MESSAGE (interp_message_nl ist gl s) gl in + db_breakpoint (curr_debug ist) s; res + end + | TacFail (n,s) -> + Proofview.V82.tactic begin fun gl -> + tclFAIL (interp_int_or_var ist n) (interp_message ist gl s) gl + end + | TacProgress tac -> Proofview.tclPROGRESS (interp_tactic ist tac) + | TacShowHyps tac -> + (* arnaud: todo: + tclSHOWHYPS (interp_tactic ist tac)*) + assert false | TacAbstract (tac,ido) -> - fun gl -> Tactics.tclABSTRACT + Proofview.V82.tactic begin fun gl -> Tactics.tclABSTRACT (Option.map (pf_interp_ident ist gl) ido) (interp_tactic ist tac) gl + end | TacThen (t1,tf,t,tl) -> - tclTHENS3PARTS (interp_tactic ist t1) + Tacticals.New.tclTHENS3PARTS (interp_tactic ist t1) (Array.map (interp_tactic ist) tf) (interp_tactic ist t) (Array.map (interp_tactic ist) tl) - | TacThens (t1,tl) -> tclTHENS (interp_tactic ist t1) (List.map (interp_tactic ist) tl) - | TacDo (n,tac) -> tclDO (interp_int_or_var ist n) (interp_tactic ist tac) - | TacTimeout (n,tac) -> tclTIMEOUT (interp_int_or_var ist n) (interp_tactic ist tac) - | TacTry tac -> tclTRY (interp_tactic ist tac) - | TacRepeat tac -> tclREPEAT (interp_tactic ist tac) + | TacThens (t1,tl) -> Tacticals.New.tclTHENS (interp_tactic ist t1) (List.map (interp_tactic ist) tl) + | TacDo (n,tac) -> Tacticals.New.tclDO (interp_int_or_var ist n) (interp_tactic ist tac) + | TacTimeout (n,tac) -> Proofview.tclTIMEOUT (interp_int_or_var ist n) (interp_tactic ist tac) + | TacTry tac -> Tacticals.New.tclTRY (interp_tactic ist tac) + | TacRepeat tac -> Tacticals.New.tclREPEAT (interp_tactic ist tac) | TacOrelse (tac1,tac2) -> - tclORELSE (interp_tactic ist tac1) (interp_tactic ist tac2) - | TacFirst l -> tclFIRST (List.map (interp_tactic ist) l) - | TacSolve l -> tclSOLVE (List.map (interp_tactic ist) l) - | TacComplete tac -> tclCOMPLETE (interp_tactic ist tac) + Tacticals.New.tclORELSE (interp_tactic ist tac1) (interp_tactic ist tac2) + | TacFirst l -> Tacticals.New.tclFIRST (List.map (interp_tactic ist) l) + | TacSolve l -> Tacticals.New.tclSOLVE (List.map (interp_tactic ist) l) + | TacComplete tac -> Tacticals.New.tclCOMPLETE (interp_tactic ist tac) | TacArg a -> interp_tactic ist (TacArg a) | TacInfo tac -> msg_warning (strbrk "The general \"info\" tactic is currently not working." ++ fnl () ++ - strbrk "Some specific verbose tactics may exist instead, such as info_trivial, info_auto, info_eauto."); + strbrk "Some specific verbose tactics may exist instead, such as info_trivial, info_auto, info_eauto."); eval_tactic ist tac -and force_vrec ist gl v = +and force_vrec ist v = let v = Value.normalize v in if has_type v (topwit wit_tacvalue) then let v = to_tacvalue v in match v with - | VRec (lfun,body) -> val_interp {ist with lfun = !lfun} gl body - | v -> project gl , of_tacvalue v - else project gl, v + | VRec (lfun,body) -> val_interp {ist with lfun = !lfun} body + | v -> Proofview.tclUNIT (Goal.return (of_tacvalue v)) + else Proofview.tclUNIT (Goal.return v) -and interp_ltac_reference loc' mustbetac ist gl = function +and interp_ltac_reference loc' mustbetac ist = function | ArgVar (loc,id) -> let v = try Id.Map.find id ist.lfun with Not_found -> in_gen (topwit wit_var) id in - let (sigma,v) = force_vrec ist gl v in + force_vrec ist v >>== fun v -> let v = propagate_trace ist loc id v in - sigma , if mustbetac then coerce_to_tactic loc id v else v + if mustbetac then Proofview.tclUNIT (Goal.return (coerce_to_tactic loc id v)) else Proofview.tclUNIT (Goal.return v) | ArgArg (loc,r) -> let ids = extract_ids [] ist.lfun in let loc_info = ((if Loc.is_ghost loc' then loc else loc'),LtacNameCall r) in let extra = TacStore.set ist.extra f_avoid_ids ids in let extra = TacStore.set extra f_trace (push_trace loc_info ist) in let ist = { lfun = Id.Map.empty; extra = extra; } in - val_interp ist gl (lookup_ltacref r) + val_interp ist (lookup_ltacref r) -and interp_tacarg ist gl arg = - let evdref = ref (project gl) in - let v = match arg with - | TacGeneric arg -> - let gl = { gl with sigma = !evdref } in - let (sigma, v) = Geninterp.generic_interp ist gl arg in - evdref := sigma; - v - | Reference r -> - let (sigma,v) = interp_ltac_reference dloc false ist gl r in - evdref := sigma; - v - | ConstrMayEval c -> - let (sigma,c_interp) = interp_constr_may_eval ist gl c in - evdref := sigma; - Value.of_constr c_interp - | MetaIdArg (loc,_,id) -> assert false - | TacCall (loc,r,[]) -> - let (sigma,v) = interp_ltac_reference loc true ist gl r in - evdref := sigma; - v - | TacCall (loc,f,l) -> - let (sigma,fv) = interp_ltac_reference loc true ist gl f in - let (sigma,largs) = - List.fold_right begin fun a (sigma',acc) -> - let (sigma', a_interp) = interp_tacarg ist gl a in - sigma' , a_interp::acc - end l (sigma,[]) - in - List.iter check_is_value largs; - let (sigma,v) = interp_app loc ist { gl with sigma=sigma } fv largs in - evdref:= sigma; - v - | TacExternal (loc,com,req,la) -> - let (sigma,la_interp) = - List.fold_right begin fun a (sigma,acc) -> - let (sigma,a_interp) = interp_tacarg ist {gl with sigma=sigma} a in - sigma , a_interp::acc - end la (project gl,[]) - in - let (sigma,v) = interp_external loc ist { gl with sigma=sigma } com req la_interp in - evdref := sigma; - v - | TacFreshId l -> - let id = pf_interp_fresh_id ist gl l in - in_gen (topwit wit_intro_pattern) (dloc, IntroIdentifier id) - | Tacexp t -> - let (sigma,v) = val_interp ist gl t in - evdref := sigma; - v - | TacDynamic(_,t) -> - let tg = (Dyn.tag t) in - if String.equal tg "tactic" then - let (sigma,v) = val_interp ist gl (tactic_out t ist) in - evdref := sigma; - v - else if String.equal tg "value" then - value_out t - else if String.equal tg "constr" then - Value.of_constr (constr_out t) - else - anomaly ~loc:dloc ~label:"Tacinterp.val_interp" - (str "Unknown dynamic: <" ++ str (Dyn.tag t) ++ str ">") +and interp_tacarg ist arg = + let tac_of_old f = + Tacmach.New.of_old f >>-- fun (sigma,v) -> + Proofview.V82.tactic (tclEVARS sigma) <*> + Proofview.tclUNIT (Goal.return v) in - !evdref , v + match arg with + | TacGeneric arg -> + Goal.defs >>-- fun sigma -> + tac_of_old (fun gl -> + Geninterp.generic_interp ist { gl with sigma = sigma } arg) + | Reference r -> interp_ltac_reference dloc false ist r + | ConstrMayEval c -> + tac_of_old (fun gl -> interp_constr_may_eval ist gl c) >>== fun c_interp -> + Proofview.tclUNIT (Goal.return (Value.of_constr c_interp)) + | MetaIdArg (loc,_,id) -> assert false + | TacCall (loc,r,[]) -> + interp_ltac_reference loc true ist r + | TacCall (loc,f,l) -> + interp_ltac_reference loc true ist f >>== fun fv -> + Proofview.tclEVARMAP >= fun sigma -> + List.fold_right begin fun a acc -> + interp_tacarg ist a >>== fun a_interp -> + acc >>== fun acc -> Proofview.tclUNIT (Goal.return (a_interp::acc)) + end l (Proofview.tclUNIT (Goal.return [])) >>== fun largs -> + interp_app loc ist fv largs + | TacExternal (loc,com,req,la) -> + List.fold_right begin fun a acc -> + interp_tacarg ist a >>== fun a_interp -> + acc >>== fun acc -> Proofview.tclUNIT (Goal.return (a_interp::acc)) + end la (Proofview.tclUNIT (Goal.return [])) >>== fun la_interp -> + tac_of_old (fun gl -> interp_external loc ist { gl with sigma=project gl } com req la_interp) + | TacFreshId l -> + Tacmach.New.of_old (fun gl -> pf_interp_fresh_id ist gl l) >>-- fun id -> + Proofview.tclUNIT (Goal.return (in_gen (topwit wit_intro_pattern) (dloc, IntroIdentifier id))) + | Tacexp t -> val_interp ist t + | TacDynamic(_,t) -> + let tg = (Dyn.tag t) in + if String.equal tg "tactic" then + val_interp ist (tactic_out t ist) + else if String.equal tg "value" then + Proofview.tclUNIT (Goal.return (value_out t)) + else if String.equal tg "constr" then + Proofview.tclUNIT (Goal.return (Value.of_constr (constr_out t))) + else + Errors.anomaly ~loc:dloc ~label:"Tacinterp.val_interp" + (str "Unknown dynamic: <" ++ str (Dyn.tag t) ++ str ">") (* Interprets an application node *) -and interp_app loc ist gl fv largs = - let fail () = user_err_loc (loc, "Tacinterp.interp_app", - (str"Illegal tactic application.")) in +and interp_app loc ist fv largs = + let fail = + (* spiwack: quick hack, can be inlined. *) + try + user_err_loc (loc, "Tacinterp.interp_app", + (str"Illegal tactic application.")) + with e -> Proofview.tclZERO e + in let fv = Value.normalize fv in if has_type fv (topwit wit_tacvalue) then match to_tacvalue fv with @@ -1226,72 +1230,78 @@ and interp_app loc ist gl fv largs = let (extfun,lvar,lval)=head_with_value (var,largs) in let fold accu (id, v) = Id.Map.add id v accu in let newlfun = List.fold_left fold olfun extfun in - if List.is_empty lvar then - (* Check evaluation and report problems with current trace *) - let (sigma,v) = - try + if List.is_empty lvar then + begin Proofview.tclORELSE + begin let ist = { lfun = newlfun; extra = TacStore.set ist.extra f_trace []; } in - catch_error trace (val_interp ist gl) body - with reraise -> - let reraise = Errors.push reraise in - debugging_exception_step ist false reraise - (fun () -> str "evaluation"); - raise reraise - in + catch_error_tac trace (val_interp ist body) + end + begin fun e -> + (* spiwack: [Errors.push] here is unlikely to do what + it's intended to, or anything meaningful for that + matter. *) + let e = Errors.push e in + (* arnaud: todo: debugging: debugging_exception_step ist false e (fun () -> str "evaluation"); *) + Proofview.tclZERO e + end + end >>== fun v -> + (* arnaud: todo: debugging: (* No errors happened, we propagate the trace *) let v = append_trace trace v in - - let gl = { gl with sigma=sigma } in - debugging_step ist - (fun () -> - str"evaluation returns"++fnl()++pr_value (Some (pf_env gl)) v); - if List.is_empty lval then sigma,v else interp_app loc ist gl v lval - else - project gl , of_tacvalue (VFun(trace,newlfun,lvar,body)) - | _ -> fail () - else fail () + debugging_step ist + (fun () -> + str"evaluation returns"++fnl()++pr_value (Some (pf_env gl)) v); + *) + if List.is_empty lval then Proofview.tclUNIT (Goal.return v) else interp_app loc ist v lval + else + Proofview.tclUNIT (Goal.return (of_tacvalue (VFun(trace,newlfun,lvar,body)))) + | _ -> fail + else fail (* Gives the tactic corresponding to the tactic value *) -and tactic_of_value ist vle g = +and tactic_of_value ist vle = let vle = Value.normalize vle in if has_type vle (topwit wit_tacvalue) then match to_tacvalue vle with - | VRTactic res -> res + | VRTactic -> Proofview.tclUNIT () | VFun (trace,lfun,[],t) -> let ist = { lfun = lfun; extra = TacStore.set ist.extra f_trace []; } in let tac = eval_tactic ist t in - catch_error trace tac g - | (VFun _|VRec _) -> error "A fully applied tactic is expected." - else errorlabstrm "" (str"Expression does not evaluate to a tactic.") + catch_error_tac trace tac + | (VFun _|VRec _) -> Proofview.tclZERO (UserError ("" , str "A fully applied tactic is expected.")) + else Proofview.tclZERO (UserError ("" , str"Expression does not evaluate to a tactic.")) (* Evaluation with FailError catching *) -and eval_with_fail ist is_lazy goal tac = - try - let (sigma,v) = val_interp ist goal tac in - let v = Value.normalize v in - sigma , - (if has_type v (topwit wit_tacvalue) then match to_tacvalue v with - | VFun (trace,lfun,[],t) when not is_lazy -> - let ist = { - lfun = lfun; - extra = TacStore.set ist.extra f_trace trace; } in - let tac = eval_tactic ist t in - of_tacvalue (VRTactic (catch_error trace tac { goal with sigma=sigma })) - | _ -> v - else v) - with - (** FIXME: Should we add [Errors.push]? *) - | FailError (0,s) -> - raise (Eval_fail (Lazy.force s)) - | FailError (lvl,s) as e -> - raise (Exninfo.copy e (FailError (lvl - 1, s))) +and eval_with_fail ist is_lazy tac = + Proofview.tclORELSE + begin + val_interp ist tac >>== fun v -> + (if has_type v (topwit wit_tacvalue) then match to_tacvalue v with + | VFun (trace,lfun,[],t) when not is_lazy -> + let ist = { + lfun = lfun; + extra = TacStore.set ist.extra f_trace trace; } in + let tac = eval_tactic ist t in + catch_error_tac trace (tac <*> Proofview.tclUNIT (Goal.return (of_tacvalue VRTactic))) + | _ -> Proofview.tclUNIT (Goal.return v) + else Proofview.tclUNIT (Goal.return v)) + end + begin function + (** FIXME: Should we add [Errors.push]? *) + | FailError (0,s) -> + Proofview.tclZERO (Eval_fail (Lazy.force s)) + | FailError (lvl,s) as e -> + Proofview.tclZERO (Exninfo.copy e (FailError (lvl - 1, s))) + | e -> Proofview.tclZERO e + end (* Interprets the clauses of a recursive LetIn *) -and interp_letrec ist gl llc u = +and interp_letrec ist llc u = + Proofview.tclUNIT () >= fun () -> (* delay for the effects of [lref], just in case. *) let lref = ref ist.lfun in let fold accu ((_, id), b) = let v = of_tacvalue (VRec (lref, TacArg (dloc, b))) in @@ -1300,83 +1310,115 @@ and interp_letrec ist gl llc u = let lfun = List.fold_left fold ist.lfun llc in let () = lref := lfun in let ist = { ist with lfun } in - val_interp ist gl u + val_interp ist u (* Interprets the clauses of a LetIn *) -and interp_letin ist gl llc u = - let fold ((_, id), body) (sigma, acc) = - let (sigma, v) = interp_tacarg ist { gl with sigma } body in +and interp_letin ist llc u = + let fold ((_, id), body) acc = + interp_tacarg ist body >>== fun v -> + acc >>== fun acc -> let () = check_is_value v in - sigma, Id.Map.add id v acc + Proofview.tclUNIT (Goal.return (Id.Map.add id v acc)) in - let (sigma, lfun) = List.fold_right fold llc (project gl, ist.lfun) in + List.fold_right fold llc (Proofview.tclUNIT (Goal.return ist.lfun)) >>== fun lfun -> let ist = { ist with lfun } in - val_interp ist { gl with sigma } u + val_interp ist u (* Interprets the Match Context expressions *) -and interp_match_goal ist goal lz lr lmr = +and interp_match_goal ist lz lr lmr = + (* arnaud: on va prier pour que je n'ai pas besoin de faire ça, + sinon, je fais un truc ad-hoc let (gl,sigma) = Goal.V82.nf_evar (project goal) (sig_it goal) in let goal = { it = gl ; sigma = sigma; } in - let hyps = pf_hyps goal in + *) + Goal.hyps >>-- fun hyps -> + let hyps = Environ.named_context_of_val hyps in let hyps = if lr then List.rev hyps else hyps in - let concl = pf_concl goal in - let env = pf_env goal in - let apply_goal_sub app ist (id,c) csr mt mhyps hyps = - let matches = match_subterm_gen app c csr in + Goal.concl >>-- fun concl -> + Goal.env >>-- fun env -> + let rec apply_goal_sub app ist (id,c) csr mt mhyps hyps = let rec match_next_pattern next = match IStream.peek next with - | None -> raise PatternMatchingFailure + | None -> Proofview.tclZERO PatternMatchingFailure | Some ({ m_sub=lgoal; m_ctx=ctxt }, next) -> let lctxt = give_context ctxt id in - try apply_hyps_context ist env lz goal mt lctxt (adjust lgoal) mhyps hyps - with e when is_match_catchable e -> match_next_pattern next in - match_next_pattern matches - in - let rec apply_match_goal ist env goal nrs lex lpt = + Proofview.tclORELSE + (apply_hyps_context ist env lz mt lctxt (adjust lgoal) mhyps hyps) + begin function + | e when is_match_catchable e -> match_next_pattern next + | e -> Proofview.tclZERO e + end + in + match_next_pattern (match_subterm_gen app c csr) in + let rec apply_match_goal ist env nrs lex lpt = begin let () = match lex with | r :: _ -> db_pattern_rule (curr_debug ist) nrs r | _ -> () in match lpt with - | (All t)::tl -> - begin - db_mc_pattern_success (curr_debug ist); - try eval_with_fail ist lz goal t - with e when is_match_catchable e -> - apply_match_goal ist env goal (nrs+1) (List.tl lex) tl - end - | (Pat (mhyps,mgoal,mt))::tl -> - let mhyps = List.rev mhyps (* Sens naturel *) in - (match mgoal with - | Term mg -> - (try - let lmatch = extended_matches mg concl in - db_matched_concl (curr_debug ist) env concl; - apply_hyps_context ist env lz goal mt Id.Map.empty lmatch mhyps hyps - with e when is_match_catchable e -> - (match e with - | PatternMatchingFailure -> db_matching_failure (curr_debug ist) - | Eval_fail s -> db_eval_failure (curr_debug ist) s - | _ -> db_logic_failure (curr_debug ist) e); - apply_match_goal ist env goal (nrs+1) (List.tl lex) tl) - | Subterm (b,id,mg) -> - (try apply_goal_sub b ist (id,mg) concl mt mhyps hyps - with - | PatternMatchingFailure -> - apply_match_goal ist env goal (nrs+1) (List.tl lex) tl)) - | _ -> - errorlabstrm "Tacinterp.apply_match_goal" - (v 0 (str "No matching clauses for match goal" ++ - (if (curr_debug ist) == DebugOff then - fnl() ++ str "(use \"Set Ltac Debug\" for more info)" - else mt()) ++ str".")) + | (All t)::tl -> + begin + db_mc_pattern_success (curr_debug ist); + Proofview.tclORELSE (eval_with_fail ist lz t) + begin function + | e when is_match_catchable e -> + apply_match_goal ist env (nrs+1) (List.tl lex) tl + | e -> Proofview.tclZERO e + end + end + | (Pat (mhyps,mgoal,mt))::tl -> + let mhyps = List.rev mhyps (* Sens naturel *) in + begin match mgoal with + | Term mg -> + let matches = + try Some (extended_matches mg concl) + with PatternMatchingFailure -> None + in + begin match matches with + | None -> + db_matching_failure (curr_debug ist); + apply_match_goal ist env (nrs+1) (List.tl lex) tl + | Some lmatch -> + Proofview.tclORELSE + begin + db_matched_concl (curr_debug ist) env concl; + apply_hyps_context ist env lz mt Id.Map.empty lmatch mhyps hyps + end + begin function + | e when is_match_catchable e -> + ((match e with + | PatternMatchingFailure -> db_matching_failure (curr_debug ist) + | Eval_fail s -> db_eval_failure (curr_debug ist) s + | _ -> db_logic_failure (curr_debug ist) e); + apply_match_goal ist env (nrs+1) (List.tl lex) tl) + | e -> Proofview.tclZERO e + end + end + | Subterm (b,id,mg) -> + Proofview.tclORELSE (apply_goal_sub b ist (id,mg) concl mt mhyps hyps) + begin function + | PatternMatchingFailure -> + apply_match_goal ist env (nrs+1) (List.tl lex) tl + | e -> Proofview.tclZERO e + end + end + | _ -> + Proofview.tclZERO (UserError ( + "Tacinterp.apply_match_goal" , + (v 0 (str "No matching clauses for match goal" ++ + (if curr_debug ist==DebugOff then + fnl() ++ str "(use \"Set Ltac Debug\" for more info)" + else mt()) ++ str".")) + )) end in - apply_match_goal ist env goal 0 lmr - (read_match_rule (extract_ltac_constr_values ist env) - ist env (project goal) lmr) + Proofview.tclEVARMAP >= fun sigma -> + apply_match_goal ist env 0 lmr + (read_match_rule (extract_ltac_constr_values ist env) + ist env sigma lmr) (* Tries to match the hypotheses in a Match Context *) -and apply_hyps_context ist env lz goal mt lctxt lgmatch mhyps hyps = +and apply_hyps_context ist env lz mt lctxt lgmatch mhyps hyps = + Goal.env >>-- fun env -> let rec apply_hyps_context_rec lfun lmatch lhyps_rest = function | hyp_pat::tl -> let (hypname, _, pat as hyp_pat) = @@ -1387,34 +1429,43 @@ and apply_hyps_context ist env lz goal mt lctxt lgmatch mhyps hyps = let rec match_next_pattern next = match IStream.peek next with | None -> db_hyp_pattern_failure (curr_debug ist) env (hypname, pat); - raise PatternMatchingFailure + Proofview.tclZERO PatternMatchingFailure | Some (s, next) -> - let lids,hyp_match = s.e_ctx in - db_matched_hyp (curr_debug ist) (pf_env goal) hyp_match hypname; - try - let id_match = pi1 hyp_match in - let select_match (id,_,_) = Id.equal id id_match in - let nextlhyps = List.remove_first select_match lhyps_rest in - let lfun = lfun +++ lids in - apply_hyps_context_rec lfun s.e_sub nextlhyps tl - with e when is_match_catchable e -> - match_next_pattern next in - let init_match_pattern = apply_one_mhyp_context goal lmatch hyp_pat lhyps_rest in - match_next_pattern init_match_pattern + let lids, hyp_match = s.e_ctx in + db_matched_hyp (curr_debug ist) env hyp_match hypname; + Proofview.tclORELSE + begin + let id_match = pi1 hyp_match in + let select_match (id,_,_) = Id.equal id id_match in + let nextlhyps = List.remove_first select_match lhyps_rest in + let lfun = lfun +++ lids in + apply_hyps_context_rec lfun s.e_sub nextlhyps tl + end + begin function + | e when is_match_catchable e -> + match_next_pattern next + | e -> Proofview.tclZERO e + end + in + let init_match_pattern = Tacmach.New.of_old (fun gl -> + apply_one_mhyp_context gl lmatch hyp_pat lhyps_rest) in + init_match_pattern >>-- match_next_pattern | [] -> let lfun = lfun +++ ist.lfun in let lfun = extend_values_with_bindings lmatch lfun in db_mc_pattern_success (curr_debug ist); - eval_with_fail { ist with lfun } lz goal mt + eval_with_fail {ist with lfun } lz mt in apply_hyps_context_rec lctxt lgmatch hyps mhyps -and interp_external loc ist gl com req la = +and interp_external loc ist gl com req la = assert false +(* arnaud: todo let f ch = extern_request ch req gl la in let g ch = internalise_tacarg ch in - interp_tacarg ist gl (System.connect f g com) + interp_tacarg ist (System.connect f g com) +*) - (* Interprets extended tactic generic arguments *) +(* Interprets extended tactic generic arguments *) and interp_genarg ist gl x = let evdref = ref (project gl) in let rec interp_genarg ist gl x = @@ -1489,206 +1540,293 @@ and interp_genarg_var_list ist gl x = in_gen (topwit (wit_list wit_var)) lc (* Interprets the Match expressions *) -and interp_match ist g lz constr lmr = +and interp_match ist lz constr lmr = let apply_match_subterm app ist (id,c) csr mt = let rec match_next_pattern next = match IStream.peek next with - | None -> raise PatternMatchingFailure + | None -> Proofview.tclZERO PatternMatchingFailure | Some ({ m_sub=lmatch; m_ctx=ctxt; }, next) -> let lctxt = give_context ctxt id in let lfun = extend_values_with_bindings (adjust lmatch) (lctxt +++ ist.lfun) in - try eval_with_fail {ist with lfun=lfun} lz g mt - with e when is_match_catchable e -> match_next_pattern next in + Proofview.tclORELSE + (eval_with_fail {ist with lfun=lfun} lz mt) + begin function + | e when is_match_catchable e -> + match_next_pattern next + | e -> Proofview.tclZERO e + end + in match_next_pattern (match_subterm_gen app c csr) in - let rec apply_match ist sigma csr = let g = { g with sigma=sigma } in function + + let rec apply_match ist csr = function | (All t)::tl -> - (try eval_with_fail ist lz g t - with e when is_match_catchable e -> apply_match ist sigma csr tl) + Proofview.tclORELSE + (eval_with_fail ist lz t) + begin function + | e when is_match_catchable e -> apply_match ist csr tl + | e -> Proofview.tclZERO e + end | (Pat ([],Term c,mt))::tl -> - (try - let lmatch = - try extended_matches c csr - with reraise -> - let reraise = Errors.push reraise in - debugging_exception_step ist false reraise (fun () -> - str "matching with pattern" ++ fnl () ++ - pr_constr_pattern_env (pf_env g) c); - raise reraise - in - try - let lfun = extend_values_with_bindings lmatch ist.lfun in - eval_with_fail { ist with lfun=lfun } lz g mt - with reraise -> - let reraise = Errors.push reraise in - debugging_exception_step ist false reraise (fun () -> - str "rule body for pattern" ++ - pr_constr_pattern_env (pf_env g) c); - raise reraise - with e when is_match_catchable e -> - debugging_step ist (fun () -> str "switching to the next rule"); - apply_match ist sigma csr tl) + let matches = + try Some (extended_matches c csr) + with PatternMatchingFailure -> None + in + Proofview.tclORELSE begin match matches with + | None -> Proofview.tclZERO PatternMatchingFailure + | Some lmatch -> + Proofview.tclORELSE + begin + let lfun = extend_values_with_bindings lmatch ist.lfun in + eval_with_fail { ist with lfun=lfun } lz mt + end + begin function + | e -> + (* arnaud: todo: debugging + debugging_exception_step ist false e (fun () -> + str "rule body for pattern" ++ + pr_constr_pattern_env (pf_env g) c);*) + Proofview.tclZERO e + end + end + begin function + | e when is_match_catchable e -> + debugging_step ist (fun () -> str "switching to the next rule"); + apply_match ist csr tl + | e -> Proofview.tclZERO e + end | (Pat ([],Subterm (b,id,c),mt))::tl -> - (try apply_match_subterm b ist (id,c) csr mt - with PatternMatchingFailure -> apply_match ist sigma csr tl) + Proofview.tclORELSE + (apply_match_subterm b ist (id,c) csr mt) + begin function + | PatternMatchingFailure -> apply_match ist csr tl + | e -> Proofview.tclZERO e + end | _ -> - errorlabstrm "Tacinterp.apply_match" (str - "No matching clauses for match.") in - let (sigma,csr) = - try interp_ltac_constr ist g constr - with reraise -> - let reraise = Errors.push reraise in - debugging_exception_step ist true reraise - (fun () -> str "evaluation of the matched expression"); - raise reraise - in - let ilr = read_match_rule (extract_ltac_constr_values ist (pf_env g)) ist (pf_env g) sigma lmr in - let res = - try apply_match ist sigma csr ilr - with reraise -> - let reraise = Errors.push reraise in - debugging_exception_step ist true reraise - (fun () -> str "match expression"); - raise reraise - in + Proofview.tclZERO (UserError ("Tacinterp.apply_match" , str + "No matching clauses for match.")) in + begin Proofview.tclORELSE + (interp_ltac_constr ist constr) + begin function + | e -> + (* spiwack: [Errors.push] here is unlikely to do what + it's intended to, or anything meaningful for that + matter. *) + let e = Errors.push e in + debugging_exception_step ist true e + (fun () -> str "evaluation of the matched expression"); + Proofview.tclZERO e + end + end >>== fun csr -> + Goal.env >>-- fun env -> + Proofview.tclEVARMAP >= fun sigma -> + let ilr = read_match_rule (extract_ltac_constr_values ist env) ist env sigma lmr in + Proofview.tclORELSE + (apply_match ist csr ilr) + begin function + | e -> + debugging_exception_step ist true e (fun () -> str "match expression"); + Proofview.tclZERO e + end >>== fun res -> debugging_step ist (fun () -> - str "match expression returns " ++ pr_value (Some (pf_env g)) (snd res)); - res + str "match expression returns " ++ pr_value (Some env) res); + Proofview.tclUNIT (Goal.return res) (* Interprets tactic expressions : returns a "constr" *) -and interp_ltac_constr ist gl e = - let (sigma, result) = - try val_interp ist gl e with Not_found -> - debugging_step ist (fun () -> - str "evaluation failed for" ++ fnl() ++ - Pptactic.pr_glob_tactic (pf_env gl) e); - raise Not_found in +and interp_ltac_constr ist e = + begin Proofview.tclORELSE + (val_interp ist e) + begin function + | Not_found -> + (* arnaud: todo: debugging + debugging_step ist (fun () -> + str "evaluation failed for" ++ fnl() ++ + Pptactic.pr_glob_tactic (pf_env gl) e); + *) + Proofview.tclZERO Not_found + | e -> Proofview.tclZERO e + end + end >>== fun result -> + Goal.env >>-- fun env -> let result = Value.normalize result in try - let cresult = coerce_to_closed_constr (pf_env gl) result in + let cresult = coerce_to_closed_constr env result in debugging_step ist (fun () -> - Pptactic.pr_glob_tactic (pf_env gl) e ++ fnl() ++ - str " has value " ++ fnl() ++ - pr_constr_env (pf_env gl) cresult); - sigma, cresult + Pptactic.pr_glob_tactic env e ++ fnl() ++ + str " has value " ++ fnl() ++ + pr_constr_env env cresult); + Proofview.tclUNIT (Goal.return cresult) with CannotCoerceTo _ -> - errorlabstrm "" + Goal.env >>-- fun env -> + Proofview.tclZERO (UserError ( "", + errorlabstrm "" (str "Must evaluate to a closed term" ++ fnl() ++ - str "offending expression: " ++ fnl() ++ pr_inspect (pf_env gl) e result) + str "offending expression: " ++ fnl() ++ pr_inspect env e result))) (* Interprets tactic expressions : returns a "tactic" *) -and interp_tactic ist tac gl = - let (sigma,v) = val_interp ist gl tac in - tactic_of_value ist v { gl with sigma=sigma } +and interp_tactic ist tac = + val_interp ist tac >>= fun v -> + tactic_of_value ist v (* Interprets a primitive tactic *) -and interp_atomic ist gl tac = - let env = pf_env gl and sigma = project gl in +and interp_atomic ist tac = match tac with (* Basic tactics *) | TacIntroPattern l -> - h_intro_patterns (interp_intro_pattern_list_as_list ist gl l) + Tacmach.New.of_old (fun gl -> interp_intro_pattern_list_as_list ist gl l) >>- fun patterns -> + h_intro_patterns patterns | TacIntrosUntil hyp -> h_intros_until (interp_quantified_hypothesis ist hyp) | TacIntroMove (ido,hto) -> - h_intro_move (Option.map (interp_fresh_ident ist env) ido) - (interp_move_location ist gl hto) - | TacAssumption -> h_assumption + Goal.env >>- fun env -> + Tacmach.New.of_old (fun gl -> interp_move_location ist gl hto) >>- fun mloc -> + h_intro_move (Option.map (interp_fresh_ident ist env) ido) mloc + | TacAssumption -> Proofview.V82.tactic h_assumption | TacExact c -> - let (sigma,c_interp) = pf_interp_casted_constr ist gl c in - tclTHEN - (tclEVARS sigma) - (h_exact c_interp) + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_casted_constr ist gl c in + tclTHEN + (tclEVARS sigma) + (h_exact c_interp) + gl + end | TacExactNoCheck c -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) - (h_exact_no_check c_interp) + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_constr ist gl c in + tclTHEN + (tclEVARS sigma) + (h_exact_no_check c_interp) + gl + end | TacVmCastNoCheck c -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) - (h_vm_cast_no_check c_interp) + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_constr ist gl c in + tclTHEN + (tclEVARS sigma) + (h_vm_cast_no_check c_interp) + gl + end | TacApply (a,ev,cb,cl) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let sigma, l = List.fold_map (interp_open_constr_with_bindings_loc ist env) sigma cb in let tac = match cl with - | None -> h_apply a ev + | None -> fun l -> Proofview.V82.tactic (h_apply a ev l) | Some cl -> - (fun l -> h_apply_in a ev l (interp_in_hyp_as ist gl cl)) in - tclWITHHOLES ev tac sigma l + (fun l -> + Tacmach.New.of_old (fun gl -> interp_in_hyp_as ist gl cl) >>- fun cl -> + h_apply_in a ev l cl) in + Tacticals.New.tclWITHHOLES ev tac sigma l | TacElim (ev,cb,cbo) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let sigma, cb = interp_constr_with_bindings ist env sigma cb in let sigma, cbo = Option.fold_map (interp_constr_with_bindings ist env) sigma cbo in - tclWITHHOLES ev (h_elim ev cb) sigma cbo + Tacticals.New.tclWITHHOLES ev (h_elim ev cb) sigma cbo | TacElimType c -> - let (sigma,c_interp) = pf_interp_type ist gl c in - tclTHEN - (tclEVARS sigma) - (h_elim_type c_interp) + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_type ist gl c in + tclTHEN + (tclEVARS sigma) + (h_elim_type c_interp) + gl + end | TacCase (ev,cb) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let sigma, cb = interp_constr_with_bindings ist env sigma cb in - tclWITHHOLES ev (h_case ev) sigma cb + Tacticals.New.tclWITHHOLES ev (h_case ev) sigma cb | TacCaseType c -> - let (sigma,c_interp) = pf_interp_type ist gl c in - tclTHEN - (tclEVARS sigma) - (h_case_type c_interp) - | TacFix (idopt,n) -> h_fix (Option.map (interp_fresh_ident ist env) idopt) n + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_type ist gl c in + tclTHEN + (tclEVARS sigma) + (h_case_type c_interp) + gl + end + | TacFix (idopt,n) -> + Goal.env >>- fun env -> + Proofview.V82.tactic (h_fix (Option.map (interp_fresh_ident ist env) idopt) n) | TacMutualFix (id,n,l) -> - let f sigma (id,n,c) = - let (sigma,c_interp) = pf_interp_type ist { gl with sigma=sigma } c in - sigma , (interp_fresh_ident ist env id,n,c_interp) in - let (sigma,l_interp) = - List.fold_right begin fun c (sigma,acc) -> - let (sigma,c_interp) = f sigma c in - sigma , c_interp::acc - end l (project gl,[]) - in - tclTHEN - (tclEVARS sigma) - (h_mutual_fix (interp_fresh_ident ist env id) n l_interp) - | TacCofix idopt -> h_cofix (Option.map (interp_fresh_ident ist env) idopt) + Goal.env >>- fun env -> + Proofview.V82.tactic begin fun gl -> + let f sigma (id,n,c) = + let (sigma,c_interp) = pf_interp_type ist { gl with sigma=sigma } c in + sigma , (interp_fresh_ident ist env id,n,c_interp) in + let (sigma,l_interp) = + List.fold_right begin fun c (sigma,acc) -> + let (sigma,c_interp) = f sigma c in + sigma , c_interp::acc + end l (project gl,[]) + in + tclTHEN + (tclEVARS sigma) + (h_mutual_fix (interp_fresh_ident ist env id) n l_interp) + gl + end + | TacCofix idopt -> + Goal.env >>- fun env -> + Proofview.V82.tactic (h_cofix (Option.map (interp_fresh_ident ist env) idopt)) | TacMutualCofix (id,l) -> - let f sigma (id,c) = - let (sigma,c_interp) = pf_interp_type ist { gl with sigma=sigma } c in - sigma , (interp_fresh_ident ist env id,c_interp) in - let (sigma,l_interp) = - List.fold_right begin fun c (sigma,acc) -> - let (sigma,c_interp) = f sigma c in - sigma , c_interp::acc - end l (project gl,[]) - in - tclTHEN - (tclEVARS sigma) - (h_mutual_cofix (interp_fresh_ident ist env id) l_interp) + Goal.env >>- fun env -> + Proofview.V82.tactic begin fun gl -> + let f sigma (id,c) = + let (sigma,c_interp) = pf_interp_type ist { gl with sigma=sigma } c in + sigma , (interp_fresh_ident ist env id,c_interp) in + let (sigma,l_interp) = + List.fold_right begin fun c (sigma,acc) -> + let (sigma,c_interp) = f sigma c in + sigma , c_interp::acc + end l (project gl,[]) + in + tclTHEN + (tclEVARS sigma) + (h_mutual_cofix (interp_fresh_ident ist env id) l_interp) + gl + end | TacCut c -> - let (sigma,c_interp) = pf_interp_type ist gl c in - tclTHEN - (tclEVARS sigma) - (h_cut c_interp) + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_type ist gl c in + tclTHEN + (tclEVARS sigma) + (h_cut c_interp) + gl + end | TacAssert (t,ipat,c) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let (sigma,c) = (if Option.is_empty t then interp_constr else interp_type) ist env sigma c in - tclTHEN - (tclEVARS sigma) + Tacmach.New.of_old (fun gl -> interp_intro_pattern ist gl) >>- fun patt -> + Tacticals.New.tclTHEN + (Proofview.V82.tactic (tclEVARS sigma)) (Tactics.forward (Option.map (interp_tactic ist) t) - (Option.map (interp_intro_pattern ist gl) ipat) c) + (Option.map patt ipat) c) | TacGeneralize cl -> - let sigma, cl = interp_constr_with_occurrences_and_name_as_list ist env sigma cl in - tclWITHHOLES false (h_generalize_gen) sigma cl + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> + Proofview.V82.tactic begin fun gl -> + let sigma, cl = interp_constr_with_occurrences_and_name_as_list ist env sigma cl in + tclWITHHOLES false (h_generalize_gen) sigma cl gl + end | TacGeneralizeDep c -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) - (h_generalize_dep c_interp) + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_constr ist gl c in + tclTHEN + (tclEVARS sigma) + (h_generalize_dep c_interp) + gl + end | TacLetTac (na,c,clp,b,eqpat) -> - let clp = interp_clause ist gl clp in - let eqpat = Option.map (interp_intro_pattern ist gl) eqpat in + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> + Tacmach.New.of_old (fun gl -> interp_clause ist gl clp) >>- fun clp -> + Tacmach.New.of_old (fun gl -> Option.map (interp_intro_pattern ist gl) eqpat) >>- fun eqpat -> if Locusops.is_nowhere clp then (* We try to fully-typecheck the term *) - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) + Tacmach.New.of_old (fun gl -> pf_interp_constr ist gl c) >>- fun (sigma,c_interp) -> + Tacticals.New.tclTHEN + (Proofview.V82.tactic (tclEVARS sigma)) (h_let_tac b (interp_fresh_name ist env na) c_interp clp eqpat) else (* We try to keep the pattern structure as much as possible *) @@ -1697,10 +1835,14 @@ and interp_atomic ist gl tac = (* Automation tactics *) | TacTrivial (debug,lems,l) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> Auto.h_trivial ~debug (interp_auto_lemmas ist env sigma lems) (Option.map (List.map (interp_hint_base ist)) l) | TacAuto (debug,n,lems,l) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> Auto.h_auto ~debug (Option.map (interp_int_or_var ist) n) (interp_auto_lemmas ist env sigma lems) (Option.map (List.map (interp_hint_base ist)) l) @@ -1709,241 +1851,321 @@ and interp_atomic ist gl tac = | TacSimpleInductionDestruct (isrec,h) -> h_simple_induction_destruct isrec (interp_quantified_hypothesis ist h) | TacInductionDestruct (isrec,ev,(l,el,cls)) -> - let sigma, l = - List.fold_map (fun sigma (c,(ipato,ipats)) -> - let c = interp_induction_arg ist gl c in - (sigma,(c, - (Option.map (interp_intro_pattern ist gl) ipato, - Option.map (interp_intro_pattern ist gl) ipats)))) sigma l in + Goal.env >>- fun env -> + let l = + Goal.sensitive_list_map begin fun (c,(ipato,ipats)) -> + Tacmach.New.of_old (fun gl -> interp_induction_arg ist gl c) >- fun c -> + Tacmach.New.of_old (fun gl -> interp_intro_pattern ist gl) >- fun interp_intro_pattern -> + Goal.return begin + c, + (Option.map interp_intro_pattern ipato, + Option.map interp_intro_pattern ipats) + end + end l + in + l >>- fun l -> + Goal.defs >>- fun sigma -> let sigma,el = Option.fold_map (interp_constr_with_bindings ist env) sigma el in - let cls = Option.map (interp_clause ist gl) cls in - tclWITHHOLES ev (h_induction_destruct isrec ev) sigma (l,el,cls) + Tacmach.New.of_old (fun gl -> interp_clause ist gl) >>- fun interp_clause -> + let cls = Option.map interp_clause cls in + Tacticals.New.tclWITHHOLES ev (h_induction_destruct isrec ev) sigma (l,el,cls) | 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 -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) + Tacmach.New.of_old (fun gl -> pf_interp_constr ist gl c) >>- fun (sigma,c_interp) -> + Tacticals.New.tclTHEN + (Proofview.V82.tactic (tclEVARS sigma)) (Elim.h_decompose_and c_interp) | TacDecomposeOr c -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) + Tacmach.New.of_old (fun gl -> pf_interp_constr ist gl c) >>- fun (sigma,c_interp) -> + Tacticals.New.tclTHEN + (Proofview.V82.tactic (tclEVARS sigma)) (Elim.h_decompose_or c_interp) | TacDecompose (l,c) -> let l = List.map (interp_inductive ist) l in - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) + Tacmach.New.of_old (fun gl -> pf_interp_constr ist gl c) >>- fun (sigma,c_interp) -> + Tacticals.New.tclTHEN + (Proofview.V82.tactic (tclEVARS sigma)) (Elim.h_decompose l c_interp) | TacSpecialize (n,cb) -> - let sigma, cb = interp_constr_with_bindings ist env sigma cb in - tclWITHHOLES false (h_specialize n) sigma cb + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> + Proofview.V82.tactic begin fun gl -> + let sigma, cb = interp_constr_with_bindings ist env sigma cb in + tclWITHHOLES false (h_specialize n) sigma cb gl + end | TacLApply c -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) - (h_lapply c_interp) + Proofview.V82.tactic begin fun gl -> + let (sigma,c_interp) = pf_interp_constr ist gl c in + tclTHEN + (tclEVARS sigma) + (h_lapply c_interp) + gl + end (* Context management *) - | TacClear (b,l) -> h_clear b (interp_hyp_list ist gl l) - | TacClearBody l -> h_clear_body (interp_hyp_list ist gl l) + | TacClear (b,l) -> + Proofview.V82.tactic begin fun gl -> + h_clear b (interp_hyp_list ist gl l) gl + end + | TacClearBody l -> + Proofview.V82.tactic begin fun gl -> + h_clear_body (interp_hyp_list ist gl l) gl + end | TacMove (dep,id1,id2) -> - h_move dep (interp_hyp ist gl id1) (interp_move_location ist gl id2) + Proofview.V82.tactic begin fun gl -> + h_move dep (interp_hyp ist gl id1) (interp_move_location ist gl id2) gl + end | TacRename l -> - h_rename (List.map (fun (id1,id2) -> - interp_hyp ist gl id1, - interp_fresh_ident ist env (snd id2)) l) - | TacRevert l -> h_revert (interp_hyp_list ist gl l) + Goal.env >>- fun env -> + Proofview.V82.tactic begin fun gl -> + h_rename (List.map (fun (id1,id2) -> + interp_hyp ist gl id1, + interp_fresh_ident ist env (snd id2)) l) + gl + end + | TacRevert l -> + Proofview.V82.tactic begin fun gl -> + h_revert (interp_hyp_list ist gl l) gl + end (* Constructors *) | TacLeft (ev,bl) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let sigma, bl = interp_bindings ist env sigma bl in - tclWITHHOLES ev (h_left ev) sigma bl + Tacticals.New.tclWITHHOLES ev (h_left ev) sigma bl | TacRight (ev,bl) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let sigma, bl = interp_bindings ist env sigma bl in - tclWITHHOLES ev (h_right ev) sigma bl + Tacticals.New.tclWITHHOLES ev (h_right ev) sigma bl | TacSplit (ev,_,bll) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let sigma, bll = List.fold_map (interp_bindings ist env) sigma bll in - tclWITHHOLES ev (h_split ev) sigma bll + Tacticals.New.tclWITHHOLES ev (h_split ev) sigma bll | TacAnyConstructor (ev,t) -> Tactics.any_constructor ev (Option.map (interp_tactic ist) t) | TacConstructor (ev,n,bl) -> + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let sigma, bl = interp_bindings ist env sigma bl in - tclWITHHOLES ev (h_constructor ev (interp_int_or_var ist n)) sigma bl + Tacticals.New.tclWITHHOLES ev (h_constructor ev (interp_int_or_var ist n)) sigma bl (* Conversion *) | TacReduce (r,cl) -> - let (sigma,r_interp) = pf_interp_red_expr ist gl r in - tclTHEN - (tclEVARS sigma) - (h_reduce r_interp (interp_clause ist gl cl)) + Proofview.V82.tactic begin fun gl -> + let (sigma,r_interp) = pf_interp_red_expr ist gl r in + tclTHEN + (tclEVARS sigma) + (h_reduce r_interp (interp_clause ist gl cl)) + gl + end | TacChange (None,c,cl) -> - let is_onhyps = match cl.onhyps with - | None | Some [] -> true - | _ -> false - in - let is_onconcl = match cl.concl_occs with - | AllOccurrences | NoOccurrences -> true - | _ -> false - in - let (sigma,c_interp) = - if is_onhyps && is_onconcl - then pf_interp_type ist gl c - else pf_interp_constr ist gl c - in - tclTHEN - (tclEVARS sigma) - (h_change None c_interp (interp_clause ist gl cl)) + Proofview.V82.tactic begin fun gl -> + let is_onhyps = match cl.onhyps with + | None | Some [] -> true + | _ -> false + in + let is_onconcl = match cl.concl_occs with + | AllOccurrences | NoOccurrences -> true + | _ -> false + in + let (sigma,c_interp) = + if is_onhyps && is_onconcl + then pf_interp_type ist gl c + else pf_interp_constr ist gl c + in + tclTHEN + (tclEVARS sigma) + (h_change None c_interp (interp_clause ist gl cl)) + gl + end | TacChange (Some op,c,cl) -> - let sign,op = interp_typed_pattern ist env sigma op in + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> + Proofview.V82.tactic begin fun gl -> + let sign,op = interp_typed_pattern ist env sigma op in (* spiwack: (2012/04/18) the evar_map output by pf_interp_constr is dropped as the evar_map taken as input (from extend_gl_hyps) is incorrect. This means that evar instantiated by pf_interp_constr may be lost, there. *) let to_catch = function Not_found -> true | e -> Errors.is_anomaly e in let (_,c_interp) = - try pf_interp_constr ist (extend_gl_hyps gl sign) c - with e when to_catch e (* Hack *) -> - errorlabstrm "" (strbrk "Failed to get enough information from the left-hand side to type the right-hand side.") - in - tclTHEN - (tclEVARS sigma) - (h_change (Some op) c_interp (interp_clause ist { gl with sigma=sigma } cl)) + try pf_interp_constr ist (extend_gl_hyps gl sign) c + with e when to_catch e (* Hack *) -> + errorlabstrm "" (strbrk "Failed to get enough information from the left-hand side to type the right-hand side.") + in + tclTHEN + (tclEVARS sigma) + (h_change (Some op) c_interp (interp_clause ist { gl with sigma=sigma } cl)) + gl + end (* Equivalence relations *) | TacReflexivity -> h_reflexivity - | TacSymmetry c -> h_symmetry (interp_clause ist gl c) + | TacSymmetry c -> + Tacmach.New.of_old (fun gl -> interp_clause ist gl c) >>- fun cl -> + h_symmetry cl | TacTransitivity c -> - begin match c with - | None -> h_transitivity None - | Some c -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - tclTHEN - (tclEVARS sigma) - (h_transitivity (Some c_interp)) - end + begin match c with + | None -> h_transitivity None + | Some c -> + Tacmach.New.of_old (fun gl -> pf_interp_constr ist gl c) >>- fun (sigma,c_interp) -> + Tacticals.New.tclTHEN + (Proofview.V82.tactic (tclEVARS sigma)) + (h_transitivity (Some c_interp)) + end (* Equality and inversion *) | TacRewrite (ev,l,cl,by) -> let l = List.map (fun (b,m,c) -> let f env sigma = interp_open_constr_with_bindings ist env sigma c in (b,m,f)) l in - let cl = interp_clause ist gl cl in + Tacmach.New.of_old (fun gl -> interp_clause ist gl cl) >>- fun cl -> Equality.general_multi_multi_rewrite ev l cl - (Option.map (fun by -> tclCOMPLETE (interp_tactic ist by), Equality.Naive) by) + (Option.map (fun by -> Tacticals.New.tclCOMPLETE (interp_tactic ist by), Equality.Naive) by) | TacInversion (DepInversion (k,c,ids),hyp) -> - let (sigma,c_interp) = - match c with - | None -> sigma , None - | Some c -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - sigma , Some c_interp - in + Goal.defs >>- fun sigma -> + begin match c with + | None -> Goal.return (sigma , None) + | Some c -> + Tacmach.New.of_old (fun gl -> pf_interp_constr ist gl c) >- fun (sigma,c_interp) -> + Goal.return (sigma , Some c_interp) + end >>- fun (sigma,c_interp) -> + Tacmach.New.of_old (interp_intro_pattern ist) >>- fun interp_intro_pattern -> + Tacmach.New.of_old (fun gl -> interp_declared_or_quantified_hypothesis ist gl hyp) >>- fun dqhyps -> Inv.dinv k c_interp - (Option.map (interp_intro_pattern ist gl) ids) - (interp_declared_or_quantified_hypothesis ist gl hyp) + (Option.map interp_intro_pattern ids) + dqhyps | TacInversion (NonDepInversion (k,idl,ids),hyp) -> + Tacmach.New.of_old (interp_intro_pattern ist) >>- fun interp_intro_pattern -> + Tacmach.New.of_old (fun gl -> interp_hyp_list ist gl idl) >>- fun hyps -> + Tacmach.New.of_old (fun gl -> interp_declared_or_quantified_hypothesis ist gl hyp) >>- fun dqhyps -> Inv.inv_clause k - (Option.map (interp_intro_pattern ist gl) ids) - (interp_hyp_list ist gl idl) - (interp_declared_or_quantified_hypothesis ist gl hyp) + (Option.map interp_intro_pattern ids) + hyps + dqhyps | TacInversion (InversionUsing (c,idl),hyp) -> - let (sigma,c_interp) = pf_interp_constr ist gl c in - Leminv.lemInv_clause (interp_declared_or_quantified_hypothesis ist gl hyp) + Tacmach.New.of_old (fun gl -> pf_interp_constr ist gl c) >>- fun (sigma,c_interp) -> + Tacmach.New.of_old (fun gl -> interp_declared_or_quantified_hypothesis ist gl hyp) >>- fun dqhyps -> + Tacmach.New.of_old (fun gl -> interp_hyp_list ist gl idl) >>- fun hyps -> + Leminv.lemInv_clause dqhyps c_interp - (interp_hyp_list ist gl idl) + hyps (* For extensions *) | TacExtend (loc,opn,l) -> + Goal.defs >>- fun goal_sigma -> let tac = lookup_tactic opn in - let (sigma,args) = + Tacmach.New.of_old begin fun gl -> List.fold_right begin fun a (sigma,acc) -> let (sigma,a_interp) = interp_genarg ist { gl with sigma=sigma } a in sigma , a_interp::acc - end l (project gl,[]) - in + end l (goal_sigma,[]) + end >>- fun (sigma,args) -> + Proofview.V82.tactic (tclEVARS sigma) <*> tac args ist - | TacAlias (loc,s,l,(_,body)) -> fun gl -> - let evdref = ref gl.sigma in - let rec f x = match genarg_tag x with - | IntOrVarArgType -> - mk_int_or_var_value ist (out_gen (glbwit wit_int_or_var) x) - | IdentArgType b -> - value_of_ident (interp_fresh_ident ist env - (out_gen (glbwit (wit_ident_gen b)) x)) - | VarArgType -> - mk_hyp_value ist gl (out_gen (glbwit wit_var) x) - | RefArgType -> - Value.of_constr (constr_of_global - (pf_interp_reference ist gl (out_gen (glbwit wit_ref) x))) - | GenArgType -> f (out_gen (glbwit wit_genarg) x) - | ConstrArgType -> - let (sigma,v) = mk_constr_value ist gl (out_gen (glbwit wit_constr) x) in - evdref := sigma; - v - | OpenConstrArgType false -> - let (sigma,v) = mk_open_constr_value ist gl (snd (out_gen (glbwit wit_open_constr) x)) in - evdref := sigma; - v - | ConstrMayEvalArgType -> - let (sigma,c_interp) = interp_constr_may_eval ist gl (out_gen (glbwit wit_constr_may_eval) x) in - evdref := sigma; - Value.of_constr c_interp - | ListArgType ConstrArgType -> - let wit = glbwit (wit_list wit_constr) in - let (sigma,l_interp) = - List.fold_right begin fun c (sigma,acc) -> - let (sigma,c_interp) = mk_constr_value ist { gl with sigma=sigma } c in - sigma , c_interp::acc - end (out_gen wit x) (project gl,[]) - in - evdref := sigma; - in_gen (topwit (wit_list wit_genarg)) l_interp - | ListArgType VarArgType -> - let wit = glbwit (wit_list wit_var) in - let ans = List.map (mk_hyp_value ist gl) (out_gen wit x) in - in_gen (topwit (wit_list wit_genarg)) ans - | ListArgType IntOrVarArgType -> - let wit = glbwit (wit_list wit_int_or_var) in - let ans = List.map (mk_int_or_var_value ist) (out_gen wit x) in - in_gen (topwit (wit_list wit_genarg)) ans - | ListArgType (IdentArgType b) -> - let wit = glbwit (wit_list (wit_ident_gen b)) in - let mk_ident x = value_of_ident (interp_fresh_ident ist env x) in - let ans = List.map mk_ident (out_gen wit x) in - in_gen (topwit (wit_list wit_genarg)) ans - | ListArgType _ -> app_list f x - | ExtraArgType _ -> - (** Special treatment of tactics *) - let gl = { gl with sigma = !evdref } in - if has_type x (glbwit wit_tactic) then - let tac = out_gen (glbwit wit_tactic) x in - let (sigma, v) = val_interp ist gl tac in - let () = evdref := sigma in - v - else - let (sigma, v) = Geninterp.generic_interp ist gl x in - let () = evdref := sigma in - v - | QuantHypArgType | RedExprArgType - | OpenConstrArgType _ | ConstrWithBindingsArgType - | BindingsArgType - | OptArgType _ | PairArgType _ - -> error "This argument type is not supported in tactic notations." - - in - let addvar (x, v) accu = Id.Map.add x (f v) accu in - let lfun = List.fold_right addvar l ist.lfun in - let trace = push_trace (loc,LtacNotationCall s) ist in - let gl = { gl with sigma = !evdref } in - let ist = { - lfun = lfun; - extra = TacStore.set ist.extra f_trace trace; } in - interp_tactic ist body gl + | TacAlias (loc,s,l,(_,body)) -> + Goal.env >>- fun env -> + let rec f x = match genarg_tag x with + | IntOrVarArgType -> + Proofview.tclUNIT (Goal.return (mk_int_or_var_value ist (out_gen (glbwit wit_int_or_var) x))) + | IdentArgType b -> + Proofview.tclUNIT begin + Goal.return (value_of_ident (interp_fresh_ident ist env + (out_gen (glbwit (wit_ident_gen b)) x))) + end + | VarArgType -> + Proofview.tclUNIT + (Tacmach.New.of_old (fun gl -> mk_hyp_value ist gl (out_gen (glbwit wit_var) x))) + | RefArgType -> + Proofview.tclUNIT begin + Tacmach.New.of_old (fun gl -> + Value.of_constr (constr_of_global + (pf_interp_reference ist gl (out_gen (glbwit wit_ref) x)))) + end + + | GenArgType -> f (out_gen (glbwit wit_genarg) x) + | ConstrArgType -> + Tacmach.New.of_old (fun gl -> mk_constr_value ist gl (out_gen (glbwit wit_constr) x)) >>-- fun (sigma,v) -> + Proofview.V82.tactic (tclEVARS sigma) <*> + Proofview.tclUNIT (Goal.return v) + | OpenConstrArgType false -> + Tacmach.New.of_old (fun gl -> mk_open_constr_value ist gl (snd (out_gen (glbwit wit_open_constr) x))) >>-- fun (sigma,v) -> + Proofview.V82.tactic (tclEVARS sigma) <*> + Proofview.tclUNIT (Goal.return v) + | ConstrMayEvalArgType -> + Tacmach.New.of_old (fun gl -> interp_constr_may_eval ist gl (out_gen (glbwit wit_constr_may_eval) x)) >>-- fun (sigma,c_interp) -> + Proofview.V82.tactic (tclEVARS sigma) <*> + Proofview.tclUNIT (Goal.return (Value.of_constr c_interp)) + | ListArgType ConstrArgType -> + let wit = glbwit (wit_list wit_constr) in + Tacmach.New.of_old begin fun gl -> + List.fold_right begin fun c (sigma,acc) -> + let (sigma,c_interp) = mk_constr_value ist { gl with sigma=sigma } c in + sigma , c_interp::acc + end (out_gen wit x) (project gl,[]) + end >>-- fun (sigma,l_interp) -> + Proofview.V82.tactic (tclEVARS sigma) <*> + Proofview.tclUNIT (Goal.return (in_gen (topwit (wit_list wit_genarg)) l_interp)) + | ListArgType VarArgType -> + let wit = glbwit (wit_list wit_var) in + Proofview.tclUNIT (Tacmach.New.of_old (fun gl -> + let ans = List.map (mk_hyp_value ist gl) (out_gen wit x) in + in_gen (topwit (wit_list wit_genarg)) ans + )) + | ListArgType IntOrVarArgType -> + let wit = glbwit (wit_list wit_int_or_var) in + let ans = List.map (mk_int_or_var_value ist) (out_gen wit x) in + Proofview.tclUNIT (Goal.return (in_gen (topwit (wit_list wit_genarg)) ans)) + | ListArgType (IdentArgType b) -> + let wit = glbwit (wit_list (wit_ident_gen b)) in + let mk_ident x = value_of_ident (interp_fresh_ident ist env x) in + let ans = List.map mk_ident (out_gen wit x) in + Proofview.tclUNIT (Goal.return (in_gen (topwit (wit_list wit_genarg)) ans)) + | ListArgType t -> + (* arnaud: unsafe, faire avec des combinateurs. Dans la version originale c'était juste [Genarg.app_list f x] *) + fold_list begin fun a l -> + f a >>== fun a' -> + l >>== fun l -> + Proofview.tclUNIT (Goal.return (a'::l)) + end x (Proofview.tclUNIT (Goal.return [])) >>== fun l -> + Proofview.tclUNIT (Goal.return (in_gen + (topwit (wit_list (Obj.magic t))) + l)) + | ExtraArgType _ -> + (** Special treatment of tactics *) + if has_type x (glbwit wit_tactic) then + let tac = out_gen (glbwit wit_tactic) x in + val_interp ist tac >>== fun v -> + Proofview.tclUNIT (Goal.return v) + else + Tacmach.New.of_old (fun gl -> + Geninterp.generic_interp ist gl x) >>-- fun (newsigma,v) -> + Proofview.V82.tactic (tclEVARS newsigma) <*> + Proofview.tclUNIT (Goal.return v) + | QuantHypArgType | RedExprArgType + | OpenConstrArgType _ | ConstrWithBindingsArgType + | BindingsArgType + | OptArgType _ | PairArgType _ + -> Proofview.tclZERO (UserError("" , str"This argument type is not supported in tactic notations.")) + in + let addvar (x, v) accu = + accu >>== fun accu -> + f v >>== fun v -> + Proofview.tclUNIT (Goal.return (Id.Map.add x v accu)) + in + List.fold_right addvar l (Proofview.tclUNIT (Goal.return ist.lfun)) >>= fun lfun -> + let trace = push_trace (loc,LtacNotationCall s) ist in + let ist = { + lfun = lfun; + extra = TacStore.set ist.extra f_trace trace; } in + interp_tactic ist body (* Initial call for interpretation *) @@ -1951,13 +2173,17 @@ let default_ist () = let extra = TacStore.set TacStore.empty f_debug (get_debug ()) in { lfun = Id.Map.empty; extra = extra } -let eval_tactic t gls = +let eval_tactic t = + Proofview.tclUNIT () >= fun () -> (* delay for [db_initialize] and [default_ist] *) db_initialize (); - interp_tactic (default_ist ()) t gls + interp_tactic (default_ist ()) t (* globalization + interpretation *) -let interp_tac_gen lfun avoid_ids debug t gl = + +let interp_tac_gen lfun avoid_ids debug t = + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let extra = TacStore.set TacStore.empty f_debug debug in let extra = TacStore.set extra f_avoid_ids avoid_ids in let ist = { lfun = lfun; extra = extra } in @@ -1965,24 +2191,27 @@ let interp_tac_gen lfun avoid_ids debug t gl = interp_tactic ist (intern_pure_tactic { ltacvars; ltacrecvars = Id.Map.empty; - gsigma = project gl; genv = pf_env gl } t) gl + gsigma = sigma; genv = env } t) let interp t = interp_tac_gen Id.Map.empty [] (get_debug()) t let _ = Proof_global.set_interp_tac interp -let eval_ltac_constr gl t = - interp_ltac_constr (default_ist ()) gl +let eval_ltac_constr t = + Proofview.tclUNIT () >= fun () -> (* delay for [make_empty_glob_sign] and [default_ist] *) + interp_ltac_constr (default_ist ()) (intern_tactic_or_tacarg (make_empty_glob_sign ()) t ) (* Used to hide interpretation for pretty-print, now just launch tactics *) -let hide_interp t ot gl = +let hide_interp t ot = + Goal.env >>- fun env -> + Goal.defs >>- fun sigma -> let ist = { ltacvars = Id.Set.empty; ltacrecvars = Id.Map.empty; - gsigma = project gl; genv = pf_env gl } in + gsigma = sigma; genv = env } in let te = intern_pure_tactic ist t in let t = eval_tactic te in match ot with - | None -> t gl - | Some t' -> (tclTHEN t t') gl + | None -> t + | Some t' -> Tacticals.New.tclTHEN t t' (***************************************************************************) (** Register standard arguments *) |