|
(************************************************************************)
(* * The Rocq Prover / The Rocq Development Team *)
(* v * Copyright INRIA, CNRS and contributors *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
{
open Pp
open Stdarg
open Tacarg
open Extraargs
open Mod_subst
open Names
open CErrors
open Util
open Equality
open Tactypes
open Proofview.Notations
open Attributes
open Vernacextend
open G_redexpr
}
DECLARE PLUGIN "rocq-runtime.plugins.ltac"
TACTIC EXTEND assert_succeeds
| [ "assert_succeeds" tactic3(tac) ]
-> { Internals.assert_succeeds (Tacinterp.tactic_of_value ist tac) }
END
TACTIC EXTEND replace
| [ "replace" uconstr(c1) "with" constr(c2) clause(cl) by_arg_tac(tac) ]
-> { Internals.replace_in_clause_maybe_by ist None c1 c2 cl tac }
END
TACTIC EXTEND replace_term_left
| [ "replace" "->" uconstr(c) clause(cl) ]
-> { Internals.replace_term ist (Some true) c cl }
END
TACTIC EXTEND replace_left
| ["replace" "->" uconstr(c1) "with" constr(c2) clause(cl) by_arg_tac(tac) ]
-> { Internals.replace_in_clause_maybe_by ist (Some true) c1 c2 cl tac }
END
TACTIC EXTEND replace_term_right
| [ "replace" "<-" uconstr(c) clause(cl) ]
-> { Internals.replace_term ist (Some false) c cl }
END
TACTIC EXTEND replace_right
| [ "replace" "<-" uconstr(c1) "with" constr(c2) clause(cl) by_arg_tac(tac) ]
-> { Internals.replace_in_clause_maybe_by ist (Some false) c1 c2 cl tac }
END
TACTIC EXTEND replace_term
| [ "replace" uconstr(c) clause(cl) ]
-> { Internals.replace_term ist None c cl }
END
TACTIC EXTEND simplify_eq
| [ "simplify_eq" ] -> { dEq ~keep_proofs:None false None }
| [ "simplify_eq" destruction_arg(c) ] -> { Internals.mytclWithHoles (dEq ~keep_proofs:None) false c }
END
TACTIC EXTEND esimplify_eq
| [ "esimplify_eq" ] -> { dEq ~keep_proofs:None true None }
| [ "esimplify_eq" destruction_arg(c) ] -> { Internals.mytclWithHoles (dEq ~keep_proofs:None) true c }
END
TACTIC EXTEND discriminate
| [ "discriminate" ] -> { discr_tac false None }
| [ "discriminate" destruction_arg(c) ] ->
{ Internals.mytclWithHoles discr_tac false c }
END
TACTIC EXTEND ediscriminate
| [ "ediscriminate" ] -> { discr_tac true None }
| [ "ediscriminate" destruction_arg(c) ] ->
{ Internals.mytclWithHoles discr_tac true c }
END
{
let isInjPat pat = match pat.CAst.v with IntroAction (IntroInjection _) -> Some pat.CAst.loc | _ -> None
let decode_inj_ipat ?loc = function
(* For the "as [= pat1 ... patn ]" syntax *)
| [{ CAst.v = IntroAction (IntroInjection ipat) }] -> ipat
(* For the "as pat1 ... patn" syntax *)
| ([] | [_]) as ipat -> ipat
| pat1::pat2::_ as ipat ->
(* To be sure that there is no confusion of syntax, we check that no [= ...] occurs
in the non-singleton list of patterns *)
match isInjPat pat1 with
| Some _ -> user_err ?loc:pat2.CAst.loc (str "Unexpected pattern.")
| None ->
match List.map_filter isInjPat ipat with
| loc :: _ -> user_err ?loc (str "Unexpected injection pattern.")
| [] -> ipat
}
TACTIC EXTEND injection
| [ "injection" ] -> { injClause None None false None }
| [ "injection" destruction_arg(c) ] -> { Internals.mytclWithHoles (injClause None None) false c }
END
TACTIC EXTEND einjection
| [ "einjection" ] -> { injClause None None true None }
| [ "einjection" destruction_arg(c) ] -> { Internals.mytclWithHoles (injClause None None) true c }
END
TACTIC EXTEND injection_as
| [ "injection" "as" simple_intropattern_list(ipat)] ->
{ injClause None (Some (decode_inj_ipat ipat)) false None }
| [ "injection" destruction_arg(c) "as" simple_intropattern_list(ipat)] ->
{ Internals.mytclWithHoles (injClause None (Some (decode_inj_ipat ipat))) false c }
END
TACTIC EXTEND einjection_as
| [ "einjection" "as" simple_intropattern_list(ipat)] ->
{ injClause None (Some (decode_inj_ipat ipat)) true None }
| [ "einjection" destruction_arg(c) "as" simple_intropattern_list(ipat)] ->
{ Internals.mytclWithHoles (injClause None (Some (decode_inj_ipat ipat))) true c }
END
TACTIC EXTEND simple_injection
| [ "simple" "injection" ] -> { simpleInjClause None false None }
| [ "simple" "injection" destruction_arg(c) ] -> { Internals.mytclWithHoles (simpleInjClause None) false c }
END
TACTIC EXTEND dependent_rewrite
| [ "dependent" "rewrite" orient(b) constr(c) ] -> { rewriteInConcl b c }
| [ "dependent" "rewrite" orient(b) constr(c) "in" hyp(id) ]
-> { rewriteInHyp b c id }
END
(**********************************************************************)
(* Decompose *)
TACTIC EXTEND decompose_sum
| [ "decompose" "sum" constr(c) ] -> { Elim.h_decompose_or c }
END
TACTIC EXTEND decompose_record
| [ "decompose" "record" constr(c) ] -> { Elim.h_decompose_and c }
END
(**********************************************************************)
(* Contradiction *)
{
open Contradiction
}
TACTIC EXTEND absurd
| [ "absurd" constr(c) ] -> { absurd c }
END
TACTIC EXTEND contradiction
| [ "contradiction" constr_with_bindings_opt(c) ] ->
{ Internals.onSomeWithHoles contradiction c }
END
(**********************************************************************)
(* AutoRewrite *)
{
open Autorewrite
}
TACTIC EXTEND autorewrite
| [ "autorewrite" "with" ne_preident_list(l) clause(cl) ] ->
{ auto_multi_rewrite l ( cl) }
| [ "autorewrite" "with" ne_preident_list(l) clause(cl) "using" tactic(t) ] ->
{
auto_multi_rewrite_with (Tacinterp.tactic_of_value ist t) l cl
}
END
TACTIC EXTEND autorewrite_star
| [ "autorewrite" "*" "with" ne_preident_list(l) clause(cl) ] ->
{ auto_multi_rewrite ~conds:AllMatches l cl }
| [ "autorewrite" "*" "with" ne_preident_list(l) clause(cl) "using" tactic(t) ] ->
{ auto_multi_rewrite_with ~conds:AllMatches (Tacinterp.tactic_of_value ist t) l cl }
END
(**********************************************************************)
(* Rewrite star *)
{
let rewrite_star ist clause orient occs c (tac : Geninterp.Val.t option) =
let tac' = Option.map (fun t -> Tacinterp.tactic_of_value ist t, FirstSolved) tac in
Internals.with_delayed_uconstr ist c
(fun c -> general_rewrite ~where:clause ~l2r:orient occs ?tac:tac' ~freeze:true ~dep:true ~with_evars:true (c,NoBindings))
}
TACTIC EXTEND rewrite_star
| [ "rewrite" "*" orient(o) uconstr(c) "in" hyp(id) "at" occurrences(occ) by_arg_tac(tac) ] ->
{ rewrite_star ist (Some id) o (occurrences_of occ) c tac }
| [ "rewrite" "*" orient(o) uconstr(c) "at" occurrences(occ) "in" hyp(id) by_arg_tac(tac) ] ->
{ rewrite_star ist (Some id) o (occurrences_of occ) c tac }
| [ "rewrite" "*" orient(o) uconstr(c) "in" hyp(id) by_arg_tac(tac) ] ->
{ rewrite_star ist (Some id) o Locus.AllOccurrences c tac }
| [ "rewrite" "*" orient(o) uconstr(c) "at" occurrences(occ) by_arg_tac(tac) ] ->
{ rewrite_star ist None o (occurrences_of occ) c tac }
| [ "rewrite" "*" orient(o) uconstr(c) by_arg_tac(tac) ] ->
{ rewrite_star ist None o Locus.AllOccurrences c tac }
END
(**********************************************************************)
(* Hint Rewrite *)
{
let classify_hint _ = VtSideff ([], VtLater)
}
(* XXX get this out of ltac plugin (need to bring orient with it) *)
VERNAC COMMAND EXTEND HintRewrite CLASSIFIED BY { classify_hint }
| #[ polymorphic; locality = hint_locality; ] [ "Hint" "Rewrite" orient(o) ne_constr_list(l) ":" ne_preident_list(bl) ] ->
{ add_rewrite_hint ~locality ~poly:polymorphic bl o None l }
| #[ polymorphic; locality = hint_locality; ] [ "Hint" "Rewrite" orient(o) ne_constr_list(l) "using" generic_tactic(t)
":" ne_preident_list(bl) ] ->
{ add_rewrite_hint ~locality ~poly:polymorphic bl o (Some t) l }
| #[ polymorphic; locality = hint_locality; ] [ "Hint" "Rewrite" orient(o) ne_constr_list(l) ] ->
{ add_rewrite_hint ~locality ~poly:polymorphic ["core"] o None l }
| #[ polymorphic; locality = hint_locality; ] [ "Hint" "Rewrite" orient(o) ne_constr_list(l) "using" generic_tactic(t) ] ->
{ add_rewrite_hint ~locality ~poly:polymorphic ["core"] o (Some t) l }
END
(**********************************************************************)
(* Refine *)
TACTIC EXTEND refine
| [ "refine" uconstr(c) ] ->
{ Internals.refine_tac ist ~simple:false ~with_classes:true c }
END
TACTIC EXTEND simple_refine
| [ "simple" "refine" uconstr(c) ] ->
{ Internals.refine_tac ist ~simple:true ~with_classes:true c }
END
TACTIC EXTEND notcs_refine
| [ "notypeclasses" "refine" uconstr(c) ] ->
{ Internals.refine_tac ist ~simple:false ~with_classes:false c }
END
TACTIC EXTEND notcs_simple_refine
| [ "simple" "notypeclasses" "refine" uconstr(c) ] ->
{ Internals.refine_tac ist ~simple:true ~with_classes:false c }
END
(* Solve unification constraints using heuristics or fail if any remain *)
TACTIC EXTEND solve_constraints
| [ "solve_constraints" ] -> { Refine.solve_constraints }
END
(**********************************************************************)
(* Inversion lemmas (Leminv) *)
{
open Inv
open Leminv
let seff id = VtSideff ([id.CAst.v], VtLater)
}
VERNAC COMMAND EXTEND DeriveInversionClear
| #[ polymorphic; ] [ "Derive" "Inversion_clear" identref(na) "with" constr(c) "Sort" sort_quality_or_set(s) ]
=> { seff na }
-> {
add_inversion_lemma_exn ~poly:polymorphic na c s false inv_clear_tac }
| #[ polymorphic; ] [ "Derive" "Inversion_clear" identref(na) "with" constr(c) ] => { seff na }
-> {
add_inversion_lemma_exn ~poly:polymorphic na c UnivGen.QualityOrSet.prop false inv_clear_tac }
END
VERNAC COMMAND EXTEND DeriveInversion
| #[ polymorphic; ] [ "Derive" "Inversion" identref(na) "with" constr(c) "Sort" sort_quality_or_set(s) ]
=> { seff na }
-> {
add_inversion_lemma_exn ~poly:polymorphic na c s false inv_tac }
| #[ polymorphic; ] [ "Derive" "Inversion" identref(na) "with" constr(c) ] => { seff na }
-> {
add_inversion_lemma_exn ~poly:polymorphic na c UnivGen.QualityOrSet.prop false inv_tac }
END
VERNAC COMMAND EXTEND DeriveDependentInversion
| #[ polymorphic; ] [ "Derive" "Dependent" "Inversion" identref(na) "with" constr(c) "Sort" sort_quality_or_set(s) ]
=> { seff na }
-> {
add_inversion_lemma_exn ~poly:polymorphic na c s true dinv_tac }
END
VERNAC COMMAND EXTEND DeriveDependentInversionClear
| #[ polymorphic; ] [ "Derive" "Dependent" "Inversion_clear" identref(na) "with" constr(c) "Sort" sort_quality_or_set(s) ]
=> { seff na }
-> {
add_inversion_lemma_exn ~poly:polymorphic na c s true dinv_clear_tac }
END
(**********************************************************************)
(* Subst *)
TACTIC EXTEND subst
| [ "subst" ne_hyp_list(l) ] -> { subst l }
| [ "subst" ] -> { subst_all () }
END
{
let simple_subst_tactic_flags =
{ only_leibniz = true; rewrite_dependent_proof = false }
}
TACTIC EXTEND simple_subst
| [ "simple" "subst" ] -> { subst_all ~flags:simple_subst_tactic_flags () }
END
{
open Evar_tactics
}
(**********************************************************************)
(* Evar creation *)
(* TODO: add support for some test similar to g_constr.name_colon so that
expressions like "evar (list A)" do not raise a syntax error *)
TACTIC EXTEND evar
| [ "evar" test_lpar_id_colon "(" ident(id) ":" lconstr(typ) ")" ] -> { let_evar (Name.Name id) typ }
| [ "evar" constr(typ) ] -> { let_evar Name.Anonymous typ }
END
TACTIC EXTEND instantiate
| [ "instantiate" "(" ident(id) ":=" lglob(c) ")" ] ->
{ instantiate_tac_by_name id c }
| [ "instantiate" "(" natural(i) ":=" lglob(c) ")" hloc(hl) ] ->
{ instantiate_tac i c hl }
END
(**********************************************************************)
(** Nijmegen "step" tactic for setoid rewriting *)
{
open Tactics
open Libobject
(* Registered lemmas are expected to be of the form
x R y -> y == z -> x R z (in the right table)
x R y -> x == z -> z R y (in the left table)
*)
let transitivity_right_table = Summary.ref [] ~name:"transitivity-steps-r"
let transitivity_left_table = Summary.ref [] ~name:"transitivity-steps-l"
(* [step] tries to apply a rewriting lemma; then apply [tac] intended to
complete to proof of the last hypothesis (assumed to state an equality) *)
let step left x tac =
let l =
List.map (fun lem ->
let lem = EConstr.of_constr lem in
Tacticals.tclTHENLAST
(apply_with_bindings (lem, ImplicitBindings [x]))
tac)
!(if left then transitivity_left_table else transitivity_right_table)
in
Tacticals.tclFIRST l
(* Main function to push lemmas in persistent environment *)
let cache_transitivity_lemma (left,lem) =
if left then
transitivity_left_table := lem :: !transitivity_left_table
else
transitivity_right_table := lem :: !transitivity_right_table
let subst_transitivity_lemma (subst,(b,ref)) = (b,subst_mps subst ref)
let inTransitivity : bool * Constr.t -> obj =
declare_object @@ global_object_nodischarge "TRANSITIVITY-STEPS"
~cache:cache_transitivity_lemma
~subst:(Some subst_transitivity_lemma)
(* Main entry points *)
let add_transitivity_lemma left lem =
let env = Global.env () in
let sigma = Evd.from_env env in
let lem',ctx (*FIXME*) = Constrintern.interp_constr env sigma lem in
let lem' = EConstr.to_constr sigma lem' in
Lib.add_leaf (inTransitivity (left,lem'))
}
(* Vernacular syntax *)
TACTIC EXTEND stepl
| ["stepl" constr(c) "by" tactic(tac) ] -> { step true c (Tacinterp.tactic_of_value ist tac) }
| ["stepl" constr(c) ] -> { step true c (Proofview.tclUNIT ()) }
END
TACTIC EXTEND stepr
| ["stepr" constr(c) "by" tactic(tac) ] -> { step false c (Tacinterp.tactic_of_value ist tac) }
| ["stepr" constr(c) ] -> { step false c (Proofview.tclUNIT ()) }
END
VERNAC COMMAND EXTEND AddStepl CLASSIFIED AS SIDEFF
| [ "Declare" "Left" "Step" constr(t) ] ->
{ add_transitivity_lemma true t }
END
VERNAC COMMAND EXTEND AddStepr CLASSIFIED AS SIDEFF
| [ "Declare" "Right" "Step" constr(t) ] ->
{ add_transitivity_lemma false t }
END
(**********************************************************************)
(* sozeau: abs/gen for induction on instantiated dependent inductives, using "Ford" induction as
defined by Conor McBride *)
TACTIC EXTEND generalize_eqs
| ["generalize_eqs" hyp(id) ] -> { Generalize.abstract_generalize ~generalize_vars:false id }
END
TACTIC EXTEND dep_generalize_eqs
| ["dependent" "generalize_eqs" hyp(id) ] -> { Generalize.abstract_generalize ~generalize_vars:false ~force_dep:true id }
END
TACTIC EXTEND generalize_eqs_vars
| ["generalize_eqs_vars" hyp(id) ] -> { Generalize.abstract_generalize ~generalize_vars:true id }
END
TACTIC EXTEND dep_generalize_eqs_vars
| ["dependent" "generalize_eqs_vars" hyp(id) ] -> { Generalize.abstract_generalize ~force_dep:true ~generalize_vars:true id }
END
(** Tactic to automatically simplify hypotheses of the form [Π Δ, x_i = t_i -> T]
where [t_i] is closed w.r.t. Δ. Such hypotheses are automatically generated
during dependent induction. For internal use. *)
TACTIC EXTEND specialize_eqs
| [ "specialize_eqs" hyp(id) ] -> { specialize_eqs id }
END
TACTIC EXTEND destauto DEPRECATED { Deprecation.make ~since:"8.20" () }
| [ "destauto" ] -> { Internals.destauto }
| [ "destauto" "in" hyp(id) ] -> { Internals.destauto_in id }
END
(**********************************************************************)
(**********************************************************************)
(* A version of abstract constructing transparent terms *)
(* Introduced by Jason Gross and Benjamin Delaware in June 2016 *)
(**********************************************************************)
TACTIC EXTEND transparent_abstract
| [ "transparent_abstract" tactic3(t) ] -> { Proofview.Goal.enter begin fun gl ->
Abstract.tclABSTRACT ~opaque:false None (Tacinterp.tactic_of_value ist t) end; }
| [ "transparent_abstract" tactic3(t) "using" ident(id) ] -> { Proofview.Goal.enter begin fun gl ->
Abstract.tclABSTRACT ~opaque:false (Some id) (Tacinterp.tactic_of_value ist t) end; }
END
(* ********************************************************************* *)
TACTIC EXTEND constr_eq
| [ "constr_eq" constr(x) constr(y) ] -> { Tactics.constr_eq ~strict:false x y }
END
TACTIC EXTEND constr_eq_strict
| [ "constr_eq_strict" constr(x) constr(y) ] -> { Tactics.constr_eq ~strict:true x y }
END
TACTIC EXTEND constr_eq_nounivs
| [ "constr_eq_nounivs" constr(x) constr(y) ] -> {
Proofview.tclEVARMAP >>= fun sigma ->
if EConstr.eq_constr_nounivs sigma x y then Proofview.tclUNIT () else Tacticals.tclFAIL (str "Not equal") }
END
TACTIC EXTEND is_evar
| [ "is_evar" constr(x) ] -> { Internals.is_evar x }
END
TACTIC EXTEND has_evar
| [ "has_evar" constr(x) ] -> { Internals.has_evar x }
END
TACTIC EXTEND is_hyp
| [ "is_var" constr(x) ] -> { Internals.is_var x }
END
TACTIC EXTEND is_fix
| [ "is_fix" constr(x) ] -> { Internals.is_fix x }
END
TACTIC EXTEND is_cofix
| [ "is_cofix" constr(x) ] -> { Internals.is_cofix x }
END
TACTIC EXTEND is_ind
| [ "is_ind" constr(x) ] -> { Internals.is_ind x }
END
TACTIC EXTEND is_constructor
| [ "is_constructor" constr(x) ] -> { Internals.is_constructor x }
END
TACTIC EXTEND is_proj
| [ "is_proj" constr(x) ] -> { Internals.is_proj x }
END
TACTIC EXTEND is_const
| [ "is_const" constr(x) ] -> { Internals.is_const x }
END
(* Shelves all the goals under focus. *)
TACTIC EXTEND shelve
| [ "shelve" ] -> { Proofview.shelve }
END
(* Shelves the unifiable goals under focus, i.e. the goals which
appear in other goals under focus (the unfocused goals are not
considered). *)
TACTIC EXTEND shelve_unifiable
| [ "shelve_unifiable" ] -> { Proofview.shelve_unifiable }
END
(* Unshelves the goal shelved by the tactic. *)
TACTIC EXTEND unshelve
| [ "unshelve" tactic1(t) ] -> { Internals.unshelve ist t }
END
(* Command to add every unshelved variables to the focus *)
VERNAC COMMAND EXTEND Unshelve STATE proof
| [ "Unshelve" ]
=> { classify_as_proofstep }
-> { fun ~pstate -> Declare.Proof.map ~f:(fun p -> Proof.unshelve p) pstate }
END
(* Gives up on the goals under focus: the goals are considered solved,
but the proof cannot be closed until the user goes back and solve
these goals. *)
TACTIC EXTEND give_up
| [ "give_up" ] ->
{ Proofview.give_up }
END
(* cycles [n] goals *)
TACTIC EXTEND cycle
| [ "cycle" int_or_var(n) ] -> { Proofview.cycle n }
END
(* swaps goals number [i] and [j] *)
TACTIC EXTEND swap
| [ "swap" int_or_var(i) int_or_var(j) ] -> { Proofview.swap i j }
END
(* reverses the list of focused goals *)
TACTIC EXTEND revgoals
| [ "revgoals" ] -> { Proofview.revgoals }
END
{
type cmp =
| Eq
| Lt | Le
| Gt | Ge
type 'i test =
| Test of cmp * 'i * 'i
let pr_cmp = function
| Eq -> Pp.str"="
| Lt -> Pp.str"<"
| Le -> Pp.str"<="
| Gt -> Pp.str">"
| Ge -> Pp.str">="
let pr_cmp' _prc _prlc _prt = pr_cmp
let pr_test_gen f (Test(c,x,y)) =
Pp.(f x ++ pr_cmp c ++ f y)
let pr_test = pr_test_gen (Pputils.pr_or_var Pp.int)
let pr_test' _prc _prlc _prt = pr_test
let pr_itest = pr_test_gen Pp.int
let pr_itest' _prc _prlc _prt = pr_itest
}
ARGUMENT EXTEND comparison PRINTED BY { pr_cmp' }
| [ "=" ] -> { Eq }
| [ "<" ] -> { Lt }
| [ "<=" ] -> { Le }
| [ ">" ] -> { Gt }
| [ ">=" ] -> { Ge }
END
{
let interp_test ist env sigma = function
| Test (c,x,y) ->
Test(c,Tacinterp.interp_int_or_var ist x,Tacinterp.interp_int_or_var ist y)
}
ARGUMENT EXTEND test
PRINTED BY { pr_itest' }
INTERPRETED BY { interp_test }
RAW_PRINTED BY { pr_test' }
GLOB_PRINTED BY { pr_test' }
| [ int_or_var(x) comparison(c) int_or_var(y) ] -> { Test(c,x,y) }
END
{
let interp_cmp = function
| Eq -> Int.equal
| Lt -> ((<):int->int->bool)
| Le -> ((<=):int->int->bool)
| Gt -> ((>):int->int->bool)
| Ge -> ((>=):int->int->bool)
let run_test = function
| Test(c,x,y) -> interp_cmp c x y
let guard tst =
if run_test tst then
Proofview.tclUNIT ()
else
let msg = Pp.(str"Condition not satisfied:"++ws 1++(pr_itest tst)) in
Tacticals.tclZEROMSG msg
}
TACTIC EXTEND guard
| [ "guard" test(tst) ] -> { guard tst }
END
TACTIC EXTEND decompose
| [ "decompose" "[" ne_constr_list(l) "]" constr(c) ] -> { Internals.decompose l c }
END
(** library/keys *)
VERNAC COMMAND EXTEND Declare_keys CLASSIFIED AS SIDEFF
| [ "Declare" "Equivalent" "Keys" constr(c) constr(c') ] -> { Internals.declare_equivalent_keys c c' }
END
VERNAC COMMAND EXTEND Print_keys CLASSIFIED AS QUERY
| [ "Print" "Equivalent" "Keys" ] -> { Feedback.msg_notice (Keys.pr_keys Printer.pr_global) }
END
VERNAC COMMAND EXTEND OptimizeProof
| ![ proof ] [ "Optimize" "Proof" ] => { classify_as_proofstep } ->
{ fun ~pstate -> Declare.Proof.compact pstate }
| [ "Optimize" "Heap" ] => { classify_as_proofstep } ->
{ Gc.compact () }
END
TACTIC EXTEND optimize_heap
| [ "optimize_heap" ] -> { Internals.tclOPTIMIZE_HEAP }
END
VERNAC COMMAND EXTEND infoH CLASSIFIED AS QUERY
| ![ proof_query ] [ "infoH" tactic(tac) ] -> { Internals.infoH tac }
END
(** Tactic analogous to [Strategy] vernacular *)
TACTIC EXTEND with_strategy
| [ "with_strategy" strategy_level_or_var(v) "[" ne_smart_global_list(q) "]" tactic3(tac) ] -> {
with_set_strategy [(v, q)] (Tacinterp.tactic_of_value ist tac)
}
END
[ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
]
|