123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787(************************************************************************)(* * 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) *)(************************************************************************)openPpopenCErrorsopenCAstopenGenredexpropenGlob_termopenUtilopenNamesopenLibnamesopenSmartlocateopenConstrexpropenTermopsopenTacexpropenGenargopenStdargopenTacargopenNamegenopenTactypesopenTacticsopenLocus(** Globalization of tactic expressions :
Conversion from [raw_tactic_expr] to [glob_tactic_expr] *)leterror_tactic_expected?loc=user_err?loc(str"Tactic expected.")(** Generic arguments *)typeglob_sign=Genintern.glob_sign={ltacvars:Id.Set.t;(* ltac variables and the subset of vars introduced by Intro/Let/... *)genv:Environ.env;extra:Genintern.Store.t;intern_sign:Genintern.intern_variable_status;strict_check:bool;}letmake_empty_glob_sign~strict=Genintern.empty_glob_sign~strict(Global.env())(* We have identifier <| global_reference <| constr *)letfind_identidist=Id.Set.memidist.ltacvars||Id.List.memid(ids_of_named_context(Environ.named_contextist.genv))(* a "var" is a ltac var or a var introduced by an intro tactic *)letfind_varidist=Id.Set.memidist.ltacvarsletfind_hypidist=Id.List.memid(ids_of_named_context(Environ.named_contextist.genv))(* Globalize a name introduced by Intro/LetTac/... ; it is allowed to *)(* be fresh in which case it is binding later on *)letintern_identsistid=(* We use identifier both for variables and new names; thus nothing to do *)ifnot(find_identidist)thens:=Id.Set.addid!s;idletintern_namelist=function|Anonymous->Anonymous|Nameid->Name(intern_identlistid)(* Globalize a name which must be bound -- actually just check it is bound *)letintern_hypist({loc;v=id}aslocid)=ifnotist.strict_checkthenlocidelseiffind_identidistthenmakeidelseCErrors.user_err?locPp.(str"Hypothesis"++spc()++Id.printid++spc()++str"was not found in the current environment.")letintern_or_varfist=function|ArgVarlocid->ArgVar(intern_hypistlocid)|ArgArgx->ArgArg(fx)letintern_int_or_var=intern_or_var(fun(n:int)->n)letintern_string_or_var=intern_or_var(fun(s:string)->s)letintern_global_referenceistqid=ifqualid_is_identqid&&find_var(qualid_basenameqid)istthenArgVar(make?loc:qid.CAst.loc@@qualid_basenameqid)elseifqualid_is_identqid&&find_hyp(qualid_basenameqid)istthenletid=qualid_basenameqidinArgArg(qid.CAst.loc,GlobRef.VarRefid)elseletr=trylocate_global_with_alias~head:trueqidwith|Not_foundasexn->ifnotist.strict_check&&qualid_is_identqidthenletid=qualid_basenameqidinGlobRef.VarRefidelselet_,info=Exninfo.captureexninNametab.error_global_not_found~infoqidinArgArg(qid.CAst.loc,r)letintern_ltac_variableistqid=ifqualid_is_identqid&&find_var(qualid_basenameqid)istthen(* A local variable of any type *)ArgVar(make?loc:qid.CAst.loc@@qualid_basenameqid)elseraiseNot_foundletintern_constr_referencestrictistqid=letid=qualid_basenameqidinifqualid_is_identqid&¬strict&&find_hyp(qualid_basenameqid)istthen(DAst.make@@GVarid),Some(make@@CRef(qid,None))elseifqualid_is_identqid&&find_var(qualid_basenameqid)istthen(DAst.make@@GVarid),ifstrictthenNoneelseSome(make@@CRef(qid,None))elseDAst.make@@GRef(locate_global_with_aliasqid,None),ifstrictthenNoneelseSome(make@@CRef(qid,None))(* Internalize an isolated reference in position of tactic *)letwarn_deprecated_tactic=Deprecation.create_warning~object_name:"Tactic"~warning_name_if_no_since:"deprecated-tactic"pr_qualidletwarn_deprecated_alias=Deprecation.create_warning~object_name:"Tactic Notation"~warning_name_if_no_since:"deprecated-tactic-notation"Pptactic.pr_alias_keyletintern_isolated_global_tactic_referenceqid=letloc=qid.CAst.locinletkn=Tacenv.locate_tacticqidinOption.iter(fundepr->warn_deprecated_tactic?loc(qid,depr))@@Tacenv.tac_deprecationkn;TacCall(CAst.make?loc(ArgArg(loc,kn),[]))letintern_isolated_tactic_referencestrictistqid=(* An ltac reference *)tryReference(intern_ltac_variableistqid)withNot_found->(* A global tactic *)tryintern_isolated_global_tactic_referenceqidwithNot_found->(* Tolerance for compatibility, allow not to use "constr:" *)tryConstrMayEval(ConstrTerm(intern_constr_referencestrictistqid))withNot_foundasexn->(* Reference not found *)let_,info=Exninfo.captureexninNametab.error_global_not_found~infoqid(* Internalize an applied tactic reference *)letintern_applied_global_tactic_referenceqid=letloc=qid.CAst.locinletkn=Tacenv.locate_tacticqidinOption.iter(fundepr->warn_deprecated_tactic?loc(qid,depr))@@Tacenv.tac_deprecationkn;ArgArg(loc,kn)letintern_applied_tactic_referenceistqid=(* An ltac reference *)tryintern_ltac_variableistqidwithNot_found->(* A global tactic *)tryintern_applied_global_tactic_referenceqidwithNot_foundasexn->(* Reference not found *)let_,info=Exninfo.captureexninNametab.error_global_not_found~infoqid(* Intern a reference parsed in a non-tactic entry *)letintern_non_tactic_referencestrictistqid=(* An ltac reference *)tryReference(intern_ltac_variableistqid)withNot_found->(* A constr reference *)tryConstrMayEval(ConstrTerm(intern_constr_referencestrictistqid))withNot_found->(* Tolerance for compatibility, allow not to use "ltac:" *)tryintern_isolated_global_tactic_referenceqidwithNot_foundasexn->(* By convention, use IntroIdentifier for unbound ident, when not in a def *)ifqualid_is_identqid&¬strictthenletid=qualid_basenameqidinletipat=in_gen(glbwitwit_intro_pattern)(make?loc:qid.CAst.loc@@IntroNaming(IntroIdentifierid))inTacGeneric(None,ipat)else(* Reference not found *)let_,info=Exninfo.captureexninNametab.error_global_not_found~infoqidletintern_message_tokenist=function|(MsgString_|MsgInt_asx)->x|MsgIdentid->MsgIdent(intern_hypistid)letintern_messageist=List.map(intern_message_tokenist)letintern_quantified_hypothesisist=function|AnonHypn->AnonHypn|NamedHypid->(* Uncomment to disallow "intros until n" in ltac when n is not bound *)NamedHyp((*snd (intern_hyp ist (dloc,*)id(* ))*))letintern_binding_nameistx=(* We use identifier both for variables and binding names *)(* Todo: consider the body of the lemma to which the binding refer
and if a term w/o ltac vars, check the name is indeed quantified *)xletintern_constr_genpattern_modeisarity{ltacvars=lfun;genv=env;extra;intern_sign;strict_check}c=letscope=ifisaritythenPretyping.IsTypeelsePretyping.WithoutTypeConstraintinletltacvars={Constrintern.ltac_vars=lfun;ltac_bound=Id.Set.empty;ltac_extra=extra;}inletc'=Constrintern.intern_corescope~strict_check~pattern_mode~ltacvarsenvEvd.(from_envenv)intern_signcin(c',ifstrict_checkthenNoneelseSomec)letintern_constr=intern_constr_genfalsefalseletintern_type=intern_constr_genfalsetrue(* Globalize bindings *)letintern_bindingist=map(fun(b,c)->intern_binding_nameistb,intern_constristc)letintern_bindingsist=function|NoBindings->NoBindings|ImplicitBindingsl->ImplicitBindings(List.map(intern_constrist)l)|ExplicitBindingsl->ExplicitBindings(List.map(intern_bindingist)l)letintern_constr_with_bindingsist(c,bl)=(intern_constristc,intern_bindingsistbl)letintern_constr_with_bindings_argist(clear,c)=(clear,intern_constr_with_bindingsistc)letrecintern_intro_patternlfist=map(function|IntroNamingpat->IntroNaming(intern_intro_pattern_naminglfistpat)|IntroActionpat->IntroAction(intern_intro_pattern_actionlfistpat)|IntroForthcoming_asx->x)andintern_intro_pattern_naminglfist=function|IntroIdentifierid->IntroIdentifier(intern_identlfistid)|IntroFreshid->IntroFresh(intern_identlfistid)|IntroAnonymousasx->xandintern_intro_pattern_actionlfist=function|IntroOrAndPatternl->IntroOrAndPattern(intern_or_and_intro_patternlfistl)|IntroInjectionl->IntroInjection(List.map(intern_intro_patternlfist)l)|IntroWildcard|IntroRewrite_asx->x|IntroApplyOn({loc;v=c},pat)->IntroApplyOn(make?loc@@intern_constristc,intern_intro_patternlfistpat)andintern_or_and_intro_patternlfist=function|IntroAndPatternl->IntroAndPattern(List.map(intern_intro_patternlfist)l)|IntroOrPatternll->IntroOrPattern(List.map(List.map(intern_intro_patternlfist))ll)letintern_or_and_intro_pattern_loclfist=function|ArgVar{v=id}asx->iffind_varidistthenxelseuser_errPp.(str"Disjunctive/conjunctive introduction pattern expected.")|ArgArgll->ArgArg(map(funl->intern_or_and_intro_patternlfistl)ll)letintern_intro_pattern_naming_loclfist=map(funpat->intern_intro_pattern_naminglfistpat)(* TODO: catch ltac vars *)letintern_destruction_argist=function|clear,ElimOnConstrc->clear,ElimOnConstr(intern_constr_with_bindingsistc)|clear,ElimOnAnonHypnasx->x|clear,ElimOnIdent{loc;v=id}->ifist.strict_checkthen(* If in a defined tactic, no intros-until *)letc,p=intern_constrist(make@@CRef(qualid_of_identid,None))inmatchDAst.getcwith|GVarid->clear,ElimOnIdent(make?loc:c.locid)|_->clear,ElimOnConstr((c,p),NoBindings)elseclear,ElimOnIdent(make?locid)letevalref_of_globref?locr=let()=(* only dump section variables not proof context variables
(broken if variables got renamed) *)letis_proof_variable=matchrwith|GlobRef.VarRefx->(tryignore(Global.lookup_namedx);falsewithNot_found->true)|_->falseinifnotis_proof_variablethenDumpglob.add_glob?locrinTacred.soft_evaluable_of_global_reference?locrletintern_smart_globalist=function|{v=ANr}->intern_global_referenceistr|{v=ByNotation(ntn,sc);loc}->ArgArg(loc,(Notation.interp_notation_as_global_reference?loc~head:trueGlobRef.(functionConstRef_|VarRef_->true|_->false)ntnsc))letintern_constr_with_occurrencesist(l,c)=(l,intern_constristc)letintern_constr_patternist~as_type~ltacvarspc=letltacvars={Constrintern.ltac_vars=ltacvars;ltac_bound=Id.Set.empty;ltac_extra=ist.extra;}inletmetas,pat=Constrintern.intern_constr_patternist.genvEvd.(from_envist.genv)~as_type~ltacvarspcinlet(glob,_asc)=intern_constr_gentruefalseistpcinletbound_names=Glob_ops.bound_glob_varsglobinmetas,(bound_names,c,pat)letintern_typed_patternistp=(* we cannot ensure in non strict mode that the pattern is closed *)(* keeping a constr_expr copy is too complicated and we want anyway to *)(* type it, so we remember the pattern as a glob_constr only *)letmetas=ifist.strict_checkthenletltacvars={Constrintern.ltac_vars=ist.ltacvars;ltac_bound=Id.Set.empty;ltac_extra=ist.extra;}infst@@Constrintern.intern_constr_patternist.genvEvd.(from_envist.genv)~ltacvarspelseId.Set.emptyinletc=intern_constr_gentruefalseistpinmetas,cletintern_local_evalrefistqid=ifqualid_is_identqid&&find_var(qualid_basenameqid)istthenSome(ArgVar(make?loc:qid.CAst.loc@@qualid_basenameqid))elseifqualid_is_identqid&&find_hyp(qualid_basenameqid)istthenletid=qualid_basenameqidinletloc=qid.locinletr=GlobRef.VarRefidinletr=evalref_of_globref?locrinletshort=ifist.strict_checkthenNoneelseSome(CAst.make?locid)inSome(ArgArg(r,short))elseNoneletintern_red_expristr=letltac_sign={Constrintern.ltac_vars=ist.ltacvars;ltac_bound=Id.Set.empty;ltac_extra=ist.extra;}inletist={Redexpr.Intern.strict_check=ist.strict_check;local_ref=intern_local_evalrefist;global_ref=(fun?shortr->ArgArg(r,short));intern_constr=intern_constrist;ltac_sign;pattern_of_glob=(func->(c,None));intern_pattern=(func->snd@@intern_typed_patternistc);}inRedexpr.Intern.intern_red_expristrletintern_hyp_listist=List.map(intern_hypist)letintern_in_hyp_asistlf(idl,ipat)=(intern_hypistidl,Option.map(intern_intro_patternlfist)ipat)letintern_inversion_strengthlfist=function|NonDepInversion(k,idl,ids)->NonDepInversion(k,intern_hyp_lististidl,Option.map(intern_or_and_intro_pattern_loclfist)ids)|DepInversion(k,copt,ids)->DepInversion(k,Option.map(intern_constrist)copt,Option.map(intern_or_and_intro_pattern_loclfist)ids)|InversionUsing(c,idl)->InversionUsing(intern_constristc,intern_hyp_lististidl)(* Interprets an hypothesis name *)letintern_hyp_locationist((occs,id),hl)=((Locusops.occurrences_map(List.map(intern_int_or_varist))occs,intern_hypistid),hl)(* Reads a pattern *)letintern_patternist?(as_type=false)ltacvars=function|Subterm(ido,pc)->let(metas,pc)=intern_constr_patternist~as_type:false~ltacvarspcinido,metas,Subterm(ido,pc)|Termpc->let(metas,pc)=intern_constr_patternist~as_type~ltacvarspcinNone,metas,Termpcletintern_constr_may_evalist=function|ConstrEval(r,c)->ConstrEval(intern_red_expristr,intern_constristc)|ConstrContext(locid,c)->ConstrContext(intern_hypistlocid,intern_constristc)|ConstrTypeOfc->ConstrTypeOf(intern_constristc)|ConstrTermc->ConstrTerm(intern_constristc)letname_consaccu=function|Anonymous->accu|Nameid->Id.Set.addidacculetopt_consaccu=function|None->accu|Someid->Id.Set.addidaccu(* Reads the hypotheses of a "match goal" rule *)letrecintern_match_goal_hypsist?(as_type=false)lfun=function|(Hyp({v=na}aslocna,mp))::tl->letido,metas1,pat=intern_patternist~as_type:truelfunmpinletlfun,metas2,hyps=intern_match_goal_hypsistlfuntlinletlfun'=name_cons(opt_conslfunido)nainlfun',Id.Set.unionmetas1metas2,Hyp(locna,pat)::hyps|(Def({v=na}aslocna,mv,mp))::tl->letido,metas1,patv=intern_patternist~as_type:falselfunmvinletido',metas2,patt=intern_patternist~as_type:truelfunmpinletlfun,metas3,hyps=intern_match_goal_hypsist~as_typelfuntlinletlfun'=name_cons(opt_cons(opt_conslfunido)ido')nainlfun',Id.Set.unionmetas1(Id.Set.unionmetas2metas3),Def(locna,patv,patt)::hyps|[]->lfun,Id.Set.empty,[](* Utilities *)letextract_let_nameslrc=letfoldaccu({loc;v=name},_)=Nameops.Name.fold_right(funidaccu->ifId.Set.memidaccuthenuser_err?loc(str"This variable is bound several times.")elseId.Set.addidaccu)nameaccuinList.fold_leftfoldId.Set.emptylrcletclause_appf=function{onhyps=None;concl_occs=nl}->{onhyps=None;concl_occs=nl}|{onhyps=Somel;concl_occs=nl}->{onhyps=Some(List.mapfl);concl_occs=nl}(* Globalizes tactics : raw_tactic_expr -> glob_tactic_expr *)letrecintern_atomiclfistx=match(x:raw_atomic_tactic_expr)with(* Basic tactics *)|TacIntroPattern(ev,l)->TacIntroPattern(ev,List.map(intern_intro_patternlfist)l)|TacApply(a,ev,cb,inhyp)->TacApply(a,ev,List.map(intern_constr_with_bindings_argist)cb,List.map(intern_in_hyp_asistlf)inhyp)|TacElim(ev,cb,cbo)->TacElim(ev,intern_constr_with_bindings_argistcb,Option.map(intern_constr_with_bindingsist)cbo)|TacCase(ev,cb)->TacCase(ev,intern_constr_with_bindings_argistcb)|TacMutualFix(id,n,l)->letf(id,n,c)=(intern_identlfistid,n,intern_typeistc)inTacMutualFix(intern_identlfistid,n,List.mapfl)|TacMutualCofix(id,l)->letf(id,c)=(intern_identlfistid,intern_typeistc)inTacMutualCofix(intern_identlfistid,List.mapfl)|TacAssert(ev,b,otac,ipat,c)->TacAssert(ev,b,Option.map(Option.map(intern_pure_tacticist))otac,Option.map(intern_intro_patternlfist)ipat,intern_constr_genfalse(not(Option.is_emptyotac))istc)|TacGeneralizecl->TacGeneralize(List.map(fun(c,na)->intern_constr_with_occurrencesistc,intern_namelfistna)cl)|TacLetTac(ev,na,c,cls,b,eqpat)->letna=intern_namelfistnainTacLetTac(ev,na,intern_constristc,(clause_app(intern_hyp_locationist)cls),b,(Option.map(intern_intro_pattern_naming_loclfist)eqpat))(* Derived basic tactics *)|TacInductionDestruct(ev,isrec,(l,el))->TacInductionDestruct(ev,isrec,(List.map(fun(c,(ipato,ipats),cls)->(intern_destruction_argistc,(Option.map(intern_intro_pattern_naming_loclfist)ipato,Option.map(intern_or_and_intro_pattern_loclfist)ipats),Option.map(clause_app(intern_hyp_locationist))cls))l,Option.map(intern_constr_with_bindingsist)el))(* Conversion *)|TacReduce(r,cl)->TacReduce(intern_red_expristr,clause_app(intern_hyp_locationist)cl)|TacChange(check,None,c,cl)->letis_onhyps=matchcl.onhypswith|None|Some[]->true|_->falseinletis_onconcl=matchcl.concl_occswith|AtLeastOneOccurrence|AllOccurrences|NoOccurrences->true|_->falseinTacChange(check,None,(ifis_onhyps&&is_onconclthenintern_typeistcelseintern_constristc),clause_app(intern_hyp_locationist)cl)|TacChange(check,Somep,c,cl)->letmetas,pat=intern_typed_patternistpinletltacvars=Id.Set.unionist.ltacvarsmetasinletist'={istwithltacvars}inTacChange(check,Somepat,intern_constrist'c,clause_app(intern_hyp_locationist)cl)(* Equality and inversion *)|TacRewrite(ev,l,cl,by)->TacRewrite(ev,List.map(fun(b,m,c)->(b,m,intern_constr_with_bindings_argistc))l,clause_app(intern_hyp_locationist)cl,Option.map(intern_pure_tacticist)by)|TacInversion(inv,hyp)->TacInversion(intern_inversion_strengthlfistinv,intern_quantified_hypothesisisthyp)andintern_tacticonlytacisttac=snd(intern_tactic_seqonlytacisttac)andintern_tactic_seqonlytacisttac=let(loc,tac)=CAst.(tac.loc,tac.v)inmatchtacwith|TacAtomt->letlf=refist.ltacvarsinlett=intern_atomiclfisttin!lf,CAst.make?loc(TacAtomt)|TacFuntacfun->ist.ltacvars,(CAst.make?loc(TacFun(intern_tactic_funisttacfun)))|TacLetIn(isrec,l,u)->letltacvars=Id.Set.union(extract_let_namesl)ist.ltacvarsinletist'={istwithltacvars}inletl=List.map(fun(n,b)->(n,intern_tacargist.strict_checkfalse(ifisrecthenist'elseist)b))linist.ltacvars,CAst.make?loc(TacLetIn(isrec,l,intern_tacticonlytacist'u))|TacMatchGoal(lz,lr,lmr)->ist.ltacvars,CAst.make?loc(TacMatchGoal(lz,lr,intern_match_ruleonlytacist~as_type:truelmr))|TacMatch(lz,c,lmr)->ist.ltacvars,CAst.make?loc(TacMatch(lz,intern_tactic_or_tacargistc,intern_match_ruleonlytacistlmr))|TacIdl->ist.ltacvars,CAst.make?loc(TacId(intern_messageistl))|TacFail(g,n,l)->ist.ltacvars,CAst.make?loc(TacFail(g,intern_int_or_varistn,intern_messageistl))|TacProgresstac->ist.ltacvars,CAst.make?loc(TacProgress(intern_pure_tacticisttac))|TacAbstract(tac,s)->ist.ltacvars,CAst.make?loc(TacAbstract(intern_pure_tacticisttac,s))|TacThen(t1,t2)->letlfun',t1=intern_tactic_seqonlytacistt1inletlfun'',t2=intern_tactic_seqonlytac{istwithltacvars=lfun'}t2inlfun'',CAst.make?loc(TacThen(t1,t2))|TacDispatchtl->ist.ltacvars,CAst.make?loc(TacDispatch(List.map(intern_pure_tacticist)tl))|TacExtendTac(tf,t,tl)->ist.ltacvars,CAst.make?loc(TacExtendTac(Array.map(intern_pure_tacticist)tf,intern_pure_tacticistt,Array.map(intern_pure_tacticist)tl))|TacThens3parts(t1,tf,t2,tl)->letlfun',t1=intern_tactic_seqonlytacistt1inletist'={istwithltacvars=lfun'}in(* Que faire en cas de (tac complexe avec Match et Thens; tac2) ?? *)lfun',CAst.make?loc(TacThens3parts(t1,Array.map(intern_pure_tacticist')tf,intern_pure_tacticist't2,Array.map(intern_pure_tacticist')tl))|TacThens(t,tl)->letlfun',t=intern_tactic_seqtrueisttinletist'={istwithltacvars=lfun'}in(* Que faire en cas de (tac complexe avec Match et Thens; tac2) ?? *)lfun',CAst.make?loc(TacThens(t,List.map(intern_pure_tacticist')tl))|TacDo(n,tac)->ist.ltacvars,CAst.make?loc(TacDo(intern_int_or_varistn,intern_pure_tacticisttac))|TacTrytac->ist.ltacvars,CAst.make?loc(TacTry(intern_pure_tacticisttac))|TacRepeattac->ist.ltacvars,CAst.make?loc(TacRepeat(intern_pure_tacticisttac))|TacTimeout(n,tac)->ist.ltacvars,CAst.make?loc(TacTimeout(intern_int_or_varistn,intern_tacticonlytacisttac))|TacTime(s,tac)->ist.ltacvars,CAst.make?loc(TacTime(s,intern_tacticonlytacisttac))|TacOr(tac1,tac2)->ist.ltacvars,CAst.make?loc(TacOr(intern_pure_tacticisttac1,intern_pure_tacticisttac2))|TacOncetac->ist.ltacvars,CAst.make?loc(TacOnce(intern_pure_tacticisttac))|TacExactlyOncetac->ist.ltacvars,CAst.make?loc(TacExactlyOnce(intern_pure_tacticisttac))|TacIfThenCatch(tac,tact,tace)->ist.ltacvars,CAst.make?loc(TacIfThenCatch(intern_pure_tacticisttac,intern_pure_tacticisttact,intern_pure_tacticisttace))|TacOrelse(tac1,tac2)->ist.ltacvars,CAst.make?loc(TacOrelse(intern_pure_tacticisttac1,intern_pure_tacticisttac2))|TacFirstl->ist.ltacvars,CAst.make?loc(TacFirst(List.map(intern_pure_tacticist)l))|TacSolvel->ist.ltacvars,CAst.make?loc(TacSolve(List.map(intern_pure_tacticist)l))|TacArga->ist.ltacvars,intern_tactic_as_argloconlytacista|TacSelect(sel,tac)->ist.ltacvars,CAst.make?loc(TacSelect(sel,intern_pure_tacticisttac))(* For extensions *)|TacAlias(s,l)->letalias=Tacenv.interp_aliassinOption.iter(funo->warn_deprecated_alias?loc(s,o))@@alias.Tacenv.alias_deprecation;letl=List.map(intern_tacargist.strict_checkfalseist)linist.ltacvars,CAst.make?loc(TacAlias(s,l))|TacML(opn,l)->let_ignore=Tacenv.interp_ml_tacticopninist.ltacvars,CAst.make?loc(TacML(opn,List.map(intern_tacargist.strict_checkfalseist)l))andintern_tactic_as_argloconlytacista=matchintern_tacargist.strict_checkonlytacistawith|TacCall_|Reference_|TacGeneric_asa->CAst.make?loc(TacArga)|Tacexpa->a|ConstrMayEval_|TacFreshId_|TacPretype_|TacNumgoalsasa->ifonlytacthenerror_tactic_expected?locelseCAst.make?loc(TacArga)andintern_tactic_or_tacargist=intern_tacticfalseistandintern_pure_tacticist=intern_tactictrueistandintern_tactic_funist(var,body)=letlfun=List.fold_leftname_consist.ltacvarsvarin(var,intern_tactic_or_tacarg{istwithltacvars=lfun}body)andintern_tacargstrictonlytacist=function|Referencer->intern_non_tactic_referencestrictistr|ConstrMayEvalc->ConstrMayEval(intern_constr_may_evalistc)|TacCall{loc;v=(f,[])}->intern_isolated_tactic_referencestrictistf|TacCall{loc;v=(f,l)}->TacCall(CAst.make?loc(intern_applied_tactic_referenceistf,List.map(intern_tacargist.strict_checkfalseist)l))|TacFreshIdx->TacFreshId(List.map(intern_string_or_varist)x)|TacPretypec->TacPretype(intern_constristc)|TacNumgoals->TacNumgoals|Tacexpt->Tacexp(intern_tacticonlytacistt)|TacGeneric(isquot,arg)->letarg=intern_genargistarginTacGeneric(isquot,arg)(* Reads the rules of a Match Context or a Match *)andintern_match_ruleonlytacist?(as_type=false)=function|(Alltc)::tl->All(intern_tacticonlytacisttc)::(intern_match_ruleonlytacist~as_typetl)|(Pat(rl,mp,tc))::tl->let{ltacvars=lfun;genv=env}=istinletlfun',metas1,hyps=intern_match_goal_hypsist~as_typelfunrlinletido,metas2,pat=intern_patternist~as_typelfunmpinletltacvars=Id.Set.union(opt_conslfun'ido)metas1inletltacvars=Id.Set.unionltacvarsmetas2inletist'={istwithltacvars}inPat(hyps,pat,intern_tacticonlytacist'tc)::(intern_match_ruleonlytacist~as_typetl)|[]->[]andintern_genargist(GenArg(Rawwitwit,x))=matchwitwith|ListArgwit->letmapx=letans=intern_genargist(in_gen(rawwitwit)x)inout_gen(glbwitwit)ansinin_gen(glbwit(wit_listwit))(List.mapmapx)|OptArgwit->letans=matchxwith|None->in_gen(glbwit(wit_optwit))None|Somex->lets=out_gen(glbwitwit)(intern_genargist(in_gen(rawwitwit)x))inin_gen(glbwit(wit_optwit))(Somes)inans|PairArg(wit1,wit2)->letp,q=xinletp=out_gen(glbwitwit1)(intern_genargist(in_gen(rawwitwit1)p))inletq=out_gen(glbwitwit2)(intern_genargist(in_gen(rawwitwit2)q))inin_gen(glbwit(wit_pairwit1wit2))(p,q)|ExtraArgs->snd(Genintern.generic_internist(in_gen(rawwitwit)x))(** Other entry points *)letglob_tacticx=intern_pure_tactic(make_empty_glob_sign~strict:true)xletglob_tactic_envlenvx=letltacvars=List.fold_left(funaccux->Id.Set.addxaccu)Id.Set.emptylinintern_pure_tactic{(Genintern.empty_glob_sign~strict:trueenv)withltacvars}xletintern_strategyists=letrecauxstratvars=function|Rewrite.StratVarx->(* We could make this whole branch assert false, since it's
unreachable except from plugins. But maybe it's useful if any
plug-in wants to craft a strategy by hand. *)ifId.Set.memx.vstratvarsthenRewrite.StratVarx.velseCErrors.user_err?loc:x.locPp.(str"Unbound strategy"++spc()++Id.printx.v)|StratConstr({v=CRef(qid,None)},true)whenidset_mem_qualidqidstratvars->let(_,x)=repr_qualidqidinRewrite.StratVarx|StratConstr(c,b)->StratConstr(intern_constristc,b)|StratFix(x,s)->StratFix(x.v,aux(Id.Set.addx.vstratvars)s)|StratId|StratFail|StratReflass->s|StratUnary(s,str)->StratUnary(s,auxstratvarsstr)|StratBinary(s,str,str')->StratBinary(s,auxstratvarsstr,auxstratvarsstr')|StratNAry(s,strs)->StratNAry(s,List.map(auxstratvars)strs)|StratTermsl->StratTerms(List.map(intern_constrist)l)|StratHints(b,id)->StratHints(b,id)|StratEvalr->StratEval(intern_red_expristr)|StratFoldc->StratFold(intern_constristc)inauxId.Set.emptys(** Registering *)letliftintern=();funistx->(ist,internistx)let()=letintern_intro_patternistpat=letlf=refId.Set.emptyinletans=intern_intro_patternlfistpatinletist={istwithltacvars=!lf}in(ist,ans)inGenintern.register_intern0wit_intropatternintern_intro_pattern[@warning"-3"];Genintern.register_intern0wit_simple_intropatternintern_intro_patternlet()=letintern_clauseistcl=letans=clause_app(intern_hyp_locationist)clin(ist,ans)inGenintern.register_intern0wit_clause_dft_conclintern_clauseletintern_ident'istid=letlf=refId.Set.emptyin(ist,intern_identlfistid)letintern_ltacisttac=intern_pure_tactic{istwithstrict_check=true}taclet()=Genintern.register_intern0wit_int_or_var(liftintern_int_or_var);Genintern.register_intern0wit_nat_or_var(liftintern_int_or_var);Genintern.register_intern0wit_smart_global(liftintern_smart_global);Genintern.register_intern0wit_ref(liftintern_global_reference);Genintern.register_intern0wit_pre_ident(funistc->(ist,c));Genintern.register_intern0wit_identintern_ident';Genintern.register_intern0wit_hyp(liftintern_hyp);Genintern.register_intern0wit_tactic(liftintern_tactic_or_tacarg);Genintern.register_intern0wit_ltac(liftintern_ltac);Genintern.register_intern0wit_quant_hyp(liftintern_quantified_hypothesis);Genintern.register_intern0wit_constr(funistc->(ist,intern_constristc));Genintern.register_intern0wit_uconstr(funistc->(ist,intern_constristc));Genintern.register_intern0wit_open_constr(funistc->(ist,intern_constristc));Genintern.register_intern0Redexpr.wit_red_expr(liftintern_red_expr);Genintern.register_intern0wit_bindings(liftintern_bindings);Genintern.register_intern0wit_constr_with_bindings(liftintern_constr_with_bindings);Genintern.register_intern0wit_destruction_arg(liftintern_destruction_arg);()(** Substitution for notations containing tactic-in-terms *)letnotation_subst_avoidbindingstac=letfoldidcaccu=letloc=Glob_ops.loc_of_glob_constrcinletc=ConstrMayEval(ConstrTerm(c,None))in(make?loc@@Nameid,c)::accuinletbindings=Id.Map.foldfoldbindings[]in(* This is theoretically not correct due to potential variable
capture, but Ltac has no true variables so one cannot simply
substitute *)ifList.is_emptybindingsthentacelseCAst.make(TacLetIn(false,bindings,tac))let()=Genintern.register_ntn_subst0wit_tacticnotation_subst