123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217(************************************************************************)(* * The Coq Proof Assistant / The Coq 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) *)(************************************************************************)openConstrinternopenPatternopsopenPpopenCAstopenNamegenopenGenredexpropenGlob_termopenGlob_opsopenTacredopenCErrorsopenUtilopenNamesopenNameopsopenLibnamesopenTacmachopenTactic_debugopenConstrexpropenTermopsopenTacexpropenGenargopenGeninterpopenStdargopenTacargopenPrinteropenPretypingopenTactypesopenTacticsopenLocusopenTacinternopenTaccoerceopenProofview.NotationsopenContext.Named.DeclarationopenLtac_pretypeletltac_trace_info=Tactic_debug.ltac_trace_infolethas_type:typea.Val.t->atyped_abstract_argument_type->bool=funvwit->letVal.Dyn(t,_)=vinlett'=matchval_tagwitwith|Val.Baset'->t'|_->assertfalse(* not used in this module *)inmatchVal.eqtt'with|None->false|SomeRefl->trueletprj:typea.aVal.typ->Val.t->aoption=funtv->letVal.Dyn(t',x)=vinmatchVal.eqtt'with|None->None|SomeRefl->Somexletin_listtagv=lettag=matchtagwithVal.Basetag->tag|_->assertfalseinVal.Dyn(Val.typ_list,List.map(funx->Val.Dyn(tag,x))v)letin_genwitv=lett=matchval_tagwitwith|Val.Baset->t|_->assertfalse(* not used in this module *)inVal.Dyn(t,v)letout_genwitv=lett=matchval_tagwitwith|Val.Baset->t|_->assertfalse(* not used in this module *)inmatchprjtvwithNone->assertfalse|Somex->xletval_tagwit=val_tag(topwitwit)letpr_argument_typearg=letVal.Dyn(tag,_)=arginVal.prtagtypevalue=Val.tletpush_applapplargs=matchapplwith|UnnamedAppl->UnnamedAppl|GlbAppll->GlbAppl(List.map(fun(h,vs)->(h,vs@args))l)letpr_genericarg=letVal.Dyn(tag,_)=arginstr"<"++Val.prtag++str":("++Pptactic.pr_valuePptactic.ltoparg++str")>"letpr_applhvs=Pptactic.pr_ltac_constanth++spc()++Pp.prlist_with_sepspcpr_genericvsletrecname_with_listapplt=matchapplwith|[]->t|(h,vs)::l->Proofview.Trace.name_tactic(fun()->pr_applhvs)(name_with_listlt)letname_if_globapplt=matchapplwith|UnnamedAppl->t|GlbAppll->name_with_listltletcombine_applappl1appl2=matchappl1,appl2with|UnnamedAppl,a|a,UnnamedAppl->a|GlbAppll1,GlbAppll2->GlbAppl(l2@l1)letof_tacvaluev=in_gen(topwitwit_tacvalue)vletto_tacvaluev=out_gen(topwitwit_tacvalue)v(* Debug reference *)letdebug=refDebugOff(* Sets the debugger on or off *)letset_debugpos=debug:=pos(* Gives the state of debug; disabled in worker processes *)letget_debug()=ifFlags.async_proofs_is_worker()thenDebugOffelse!debugletlog_trace=reffalseletis_traced()=!log_trace||!debug<>DebugOff||!Flags.profile_ltac(** More naming applications *)letname_vfunapplvle=ifis_traced()&&has_typevle(topwitwit_tacvalue)thenmatchto_tacvaluevlewith|VFun(appl0,trace,loc,lfun,vars,t)->of_tacvalue(VFun(combine_applappl0appl,trace,loc,lfun,vars,t))|_->vleelsevlemoduleTacStore=Geninterp.TacStoreletf_avoid_ids:Id.Set.tTacStore.field=TacStore.field()(* ids inherited from the call context (needed to get fresh ids) *)letf_debug:debug_infoTacStore.field=TacStore.field()letf_trace:ltac_traceTacStore.field=TacStore.field()letf_loc:Loc.tTacStore.field=TacStore.field()(* Signature for interpretation: val_interp and interpretation functions *)typeinterp_sign=Geninterp.interp_sign={lfun:valueId.Map.t;poly:bool;extra:TacStore.t}letadd_extra_tracetraceextra=TacStore.setextraf_tracetraceletextract_traceist=ifis_traced()thenmatchTacStore.getist.extraf_tracewith|None->[],[]|Sometrace->traceelse[],[]letadd_extra_loclocextra=matchlocwith|None->extra|Someloc->TacStore.setextraf_loclocletextract_locist=TacStore.getist.extraf_locletensure_loclocist=matchlocwith|None->ist|Someloc->matchextract_locistwith|None->{istwithextra=TacStore.setist.extraf_locloc}|Some_->istletprint_top_valenvv=Pptactic.pr_valuePptactic.ltopvletcatching_errorcall_tracefail(e,info)=letinner_trace=Option.default[](Exninfo.getinfoltac_trace_info)inifList.is_emptycall_trace&&List.is_emptyinner_tracethenfail(e,info)elsebeginassert(CErrors.noncriticale);(* preserved invariant *)letinner_trace=List.filter(funi->not(List.memqicall_trace))inner_traceinletnew_trace=inner_trace@call_traceinletlocated_exc=(e,Exninfo.addinfoltac_trace_infonew_trace)infaillocated_excendletupdate_locloc(e,infoase')=leteloc=Loc.get_locinfoinifLoc.finereloc(Someloc)thene'else(* eloc missing or refers to inside of Ltac function *)(e,Loc.add_locinfoloc)letcatch_error_with_trace_locloccall_tracefx=tryfxwithewhenCErrors.noncriticale->lete=Exninfo.captureeinlete=Option.cata(funloc->update_locloce)elocincatching_errorcall_traceExninfo.iraiseeletcatch_error_locloctac=matchlocwith|None->tac|Someloc->Proofview.tclORELSEtac(funexn->let(e,info)=update_loclocexninProofview.tclZERO~infoe)letwrap_errortack=ifis_traced()thenProofview.tclORELSEtackelsetacletwrap_error_locloctack=ifis_traced()thenProofview.tclORELSEtackelsecatch_error_locloctacletcatch_error_taccall_tracetac=wrap_errortac(catching_errorcall_trace(fun(e,info)->Proofview.tclZERO~infoe))letcatch_error_tac_locloccall_tracetac=wrap_error_locloctac(catching_errorcall_trace(fun(e,info)->Proofview.tclZERO~infoe))letcurr_debugist=matchTacStore.getist.extraf_debugwith|None->DebugOff|Somelevel->levelletpr_closureenvistbody=letpp_body=Pptactic.pr_glob_tacticenvbodyinletpr_sep()=fnl()inletpr_iarg(id,arg)=letarg=pr_argument_typearginhov0(Id.printid++spc()++str":"++spc()++arg)inletpp_iargs=v0(prlist_with_seppr_seppr_iarg(Id.Map.bindingsist))inpp_body++fnl()++str"in environment "++fnl()++pp_iargsletpr_inspectenvexprresult=letpp_expr=Pptactic.pr_glob_tacticenvexprinletpp_result=ifhas_typeresult(topwitwit_tacvalue)thenmatchto_tacvalueresultwith|VFun(_,_,_,ist,ul,b)->letbody=ifList.is_emptyulthenbelseCAst.make(TacFun(ul,b))instr"a closure with body "++fnl()++pr_closureenvistbody|VRec(ist,body)->str"a recursive closure"++fnl()++pr_closureenv!istbodyelseletpp_type=pr_argument_typeresultinstr"an object of type"++spc()++pp_typeinpp_expr++fnl()++str"this is "++pp_result(* Transforms an id into a constr if possible, or fails with Not_found *)letconstr_of_idenvid=EConstr.mkVar(let_=Environ.lookup_namedidenvinid)(** Generic arguments : table of interpretation functions *)letpush_tracecallist=ifis_traced()thenmatchTacStore.getist.extraf_tracewith|None->[call],[ist.lfun]|Some(trace,varmaps)->call::trace,ist.lfun::varmapselse[],[]letpropagate_traceistlocidv=ifhas_typev(topwitwit_tacvalue)thenlettacv=to_tacvaluevinmatchtacvwith|VFun(appl,_,_,lfun,it,b)->letkn=matchapplwith|GlbAppl((kn,_)::_)->Somekn|_->Noneinlett=ifList.is_emptyitthenbelseCAst.make(TacFun(it,b))inlettrace=push_trace(loc,LtacVarCall(kn,id,t))istinletans=VFun(appl,trace,loc,lfun,it,b)inProofview.tclUNIT(of_tacvalueans)|_->Proofview.tclUNITvelseProofview.tclUNITvletappend_tracetracev=ifhas_typev(topwitwit_tacvalue)thenmatchto_tacvaluevwith|VFun(appl,trace',loc,lfun,it,b)->of_tacvalue(VFun(appl,trace',loc,lfun,it,b))|_->velsev(* Dynamically check that an argument is a tactic *)letcoerce_to_tacticlocidv=letfail()=user_err?loc(str"Variable "++Id.printid++str" should be bound to a tactic.")inifhas_typev(topwitwit_tacvalue)thenlettacv=to_tacvaluevinmatchtacvwith|VFun(appl,trace,_,lfun,it,b)->of_tacvalue(VFun(appl,trace,loc,lfun,it,b))|_->fail()elsefail()letintro_pattern_of_identid=CAst.make@@IntroNaming(IntroIdentifierid)letvalue_of_identid=in_gen(topwitwit_intro_pattern)(intro_pattern_of_identid)let(+++)lfun1lfun2=Id.Map.foldId.Map.addlfun1lfun2letextend_values_with_bindings(ln,lm)lfun=letof_cubc=matchcwith|[],c->Value.of_constrc|_->in_gen(topwitwit_constr_under_binders)cin(* For compatibility, bound variables are visible only if no other
binding of the same name exists *)letaccu=Id.Map.mapvalue_of_identlninletaccu=lfun+++accuinId.Map.fold(funidcaccu->Id.Map.addid(of_cubc)accu)lmacculetflush_value_evarssigmav=ifhas_typev(topwitwit_constr)thenletc=out_gen(topwitwit_constr)vinletc=tryEConstr.of_constr(Evarutil.flush_and_check_evarssigmac)withEvarutil.Uninstantiated_evar_->(* How to tell to not use this binding anymore? *)(* If it is used it might fail because of the evar *)(* But this has to work if it is not used *)cinin_gen(topwitwit_constr)celsevletflush_ist_evarssigmaist={istwithlfun=Id.Map.map(flush_value_evarssigma)ist.lfun}(***************************************************************************)(* Evaluation/interpretation *)letis_variableenvid=Id.List.memid(ids_of_named_context(Environ.named_contextenv))letdebugging_stepistpp=matchcurr_debugistwith|DebugOnlev->Tactic_debug.defer_output(fun_->(str"Level "++intlev++str": "++pp()++fnl()))|_->Proofview.NonLogical.return()letdebugging_exception_stepistsignal_anomalyepp=letexplain_exc=ifsignal_anomalythenexplain_logic_errorelseexplain_logic_error_no_anomalyindebugging_stepist(fun()->pp()++spc()++str"raised the exception"++fnl()++explain_exce)letensure_freshnessenv=(* We anonymize declarations which we know will not be used *)(* This assumes that the original context had no rels *)process_rel_context(funde->EConstr.push_rel(Context.Rel.Declaration.set_nameAnonymousd)e)env(* Raise Not_found if not in interpretation sign *)lettry_interp_ltac_varcoerceistenv{loc;v=id}=letv=Id.Map.findidist.lfunintrycoercevwithCannotCoerceTos->Taccoerce.error_ltac_variable?locidenvvsletinterp_ltac_varcoerceistenvlocid=trytry_interp_ltac_varcoerceistenvlocidwithNot_found->anomaly(str"Detected '"++Id.printlocid.v++str"' as ltac var at interning time.")letinterp_identistenvsigmaid=trytry_interp_ltac_var(coerce_var_to_identfalseenvsigma)ist(Some(env,sigma))(CAst.makeid)withNot_found->id(* Interprets an optional identifier, bound or fresh *)letinterp_nameistenvsigma=function|Anonymous->Anonymous|Nameid->Name(interp_identistenvsigmaid)letinterp_intro_pattern_varlocistenvsigmaid=trytry_interp_ltac_var(coerce_to_intro_patternsigma)ist(Some(env,sigma))(CAst.make?locid)withNot_found->IntroNaming(IntroIdentifierid)letinterp_intro_pattern_naming_varlocistenvsigmaid=trytry_interp_ltac_var(coerce_to_intro_pattern_namingsigma)ist(Some(env,sigma))(CAst.make?locid)withNot_found->IntroIdentifieridletinterp_intist({loc;v=id}aslocid)=trytry_interp_ltac_varcoerce_to_intistNonelocidwithNot_found->user_err?loc(str"Unbound variable "++Id.printid++str".")letinterp_int_or_varist=function|ArgVarlocid->interp_intistlocid|ArgArgn->nletinterp_int_or_var_as_listist=function|ArgVar({v=id}aslocid)->(trycoerce_to_int_or_var_list(Id.Map.findidist.lfun)withNot_found|CannotCoerceTo_->[ArgArg(interp_intistlocid)])|ArgArgnasx->[x]letinterp_int_or_var_lististl=List.flatten(List.map(interp_int_or_var_as_listist)l)(* Interprets a bound variable (especially an existing hypothesis) *)letinterp_hypistenvsigma({loc;v=id}aslocid)=(* Look first in lfun for a value coercible to a variable *)trytry_interp_ltac_var(coerce_to_hypenvsigma)ist(Some(env,sigma))locidwithNot_found->(* Then look if bound in the proof context at calling time *)ifis_variableenvidthenidelseLoc.raise?loc(Logic.RefinerError(env,sigma,Logic.NoSuchHypid))letinterp_hyp_list_as_lististenvsigma({loc;v=id}asx)=trycoerce_to_hyp_listenvsigma(Id.Map.findidist.lfun)withNot_found|CannotCoerceTo_->[interp_hypistenvsigmax]letinterp_hyp_lististenvsigmal=List.flatten(List.map(interp_hyp_list_as_lististenvsigma)l)letinterp_referenceistenvsigma=function|ArgArg(_,r)->r|ArgVar{loc;v=id}->trytry_interp_ltac_var(coerce_to_referencesigma)ist(Some(env,sigma))(CAst.make?locid)withNot_found->tryGlobRef.VarRef(get_id(Environ.lookup_namedidenv))withNot_foundasexn->let_,info=Exninfo.captureexninNametab.error_global_not_found~info(qualid_of_ident?locid)lettry_interp_evaluableenv(loc,id)=letv=Environ.lookup_namedidenvinmatchvwith|LocalDef_->EvalVarRefid|_->error_not_evaluable(GlobRef.VarRefid)letinterp_evaluableistenvsigma=function|ArgArg(r,Some{loc;v=id})->(* Maybe [id] has been introduced by Intro-like tactics *)begintrytry_interp_evaluableenv(loc,id)withNot_foundasexn->matchrwith|EvalConstRef_->r|_->let_,info=Exninfo.captureexninNametab.error_global_not_found~info(qualid_of_ident?locid)end|ArgArg(r,None)->r|ArgVar{loc;v=id}->trytry_interp_ltac_var(coerce_to_evaluable_refenvsigma)ist(Some(env,sigma))(CAst.make?locid)withNot_found->trytry_interp_evaluableenv(loc,id)withNot_foundasexn->let_,info=Exninfo.captureexninNametab.error_global_not_found~info(qualid_of_ident?locid)(* Interprets an hypothesis name *)letinterp_occurrencesistoccs=Locusops.occurrences_map(interp_int_or_var_listist)occsletinterp_hyp_locationistenvsigma((occs,id),hl)=((interp_occurrencesistoccs,interp_hypistenvsigmaid),hl)letinterp_hyp_location_list_as_lististenvsigma((occs,id),hlasx)=matchoccs,hlwith|AllOccurrences,InHyp->List.map(funid->((AllOccurrences,id),InHyp))(interp_hyp_list_as_lististenvsigmaid)|_,_->[interp_hyp_locationistenvsigmax]letinterp_hyp_location_lististenvsigmal=List.flatten(List.map(interp_hyp_location_list_as_lististenvsigma)l)letinterp_clauseistenvsigma{onhyps=ol;concl_occs=occs}:clause={onhyps=Option.map(interp_hyp_location_lististenvsigma)ol;concl_occs=interp_occurrencesistoccs}(* Interpretation of constructions *)(* Extract the constr list from lfun *)letextract_ltac_constr_valuesistenv=letfoldidvaccu=tryletc=coerce_to_constrenvvinId.Map.addidcaccuwithCannotCoerceTo_->accuinId.Map.foldfoldist.lfunId.Map.empty(** ppedrot: I have changed the semantics here. Before this patch, closure was
implemented as a list and a variable could be bound several times with
different types, resulting in its possible appearance on both sides. This
could barely be defined as a feature... *)(* Extract the identifier list from lfun: join all branches (what to do else?)*)letrecintropattern_idsaccu{loc;v=pat}=matchpatwith|IntroNaming(IntroIdentifierid)->Id.Set.addidaccu|IntroAction(IntroOrAndPattern(IntroAndPatternl))->List.fold_leftintropattern_idsaccul|IntroAction(IntroOrAndPattern(IntroOrPatternll))->List.fold_leftintropattern_idsaccu(List.flattenll)|IntroAction(IntroInjectionl)->List.fold_leftintropattern_idsaccul|IntroAction(IntroApplyOn({v=c},pat))->intropattern_idsaccupat|IntroNaming(IntroAnonymous|IntroFresh_)|IntroAction(IntroWildcard|IntroRewrite_)|IntroForthcoming_->acculetextract_idsidslfunaccu=letfoldidvaccu=ifhas_typev(topwitwit_intro_pattern)thenlet{v=ipat}=out_gen(topwitwit_intro_pattern)vinifId.List.memididsthenaccuelseintropattern_idsaccu(CAst.makeipat)elseaccuinId.Map.foldfoldlfunacculetdefault_fresh_id=Id.of_string"H"letinterp_fresh_idistenvsigmal=letextract_identistenvsigmaid=trytry_interp_ltac_var(coerce_to_ident_not_freshsigma)ist(Some(env,sigma))(CAst.makeid)withNot_found->idinletids=List.map_filter(functionArgVar{v=id}->Someid|_->None)linletavoid=matchTacStore.getist.extraf_avoid_idswith|None->Id.Set.empty|Somel->linletavoid=extract_idsidsist.lfunavoidinletid=ifList.is_emptylthendefault_fresh_idelselets=String.concat""(List.map(function|ArgArgs->s|ArgVar{v=id}->Id.to_string(extract_identistenvsigmaid))l)inlets=ifCLexer.is_keywordsthens^"0"elsesinId.of_stringsinTactics.fresh_id_in_envavoididenv(* Extract the uconstr list from lfun *)letextract_ltac_constr_contextistenvsigma=letadd_uconstridvmap=tryId.Map.addid(coerce_to_uconstrv)mapwithCannotCoerceTo_->mapinletadd_constridvmap=tryId.Map.addid(coerce_to_constrenvv)mapwithCannotCoerceTo_->mapinletadd_identidvmap=tryId.Map.addid(coerce_var_to_identfalseenvsigmav)mapwithCannotCoerceTo_->mapinletfoldidv{idents;typed;untyped;genargs}=letidents=add_identidvidentsinlettyped=add_constridvtypedinletuntyped=add_uconstridvuntypedin{idents;typed;untyped;genargs}inletempty={idents=Id.Map.empty;typed=Id.Map.empty;untyped=Id.Map.empty;genargs=ist.lfun}inId.Map.foldfoldist.lfunempty(** Significantly simpler than [interp_constr], to interpret an
untyped constr, it suffices to adjoin a closure environment. *)letinterp_glob_closureistenvsigma?(kind=WithoutTypeConstraint)?(pattern_mode=false)(term,term_expr_opt)=letclosure=extract_ltac_constr_contextistenvsigmainmatchterm_expr_optwith|None->{closure;term}|Someterm_expr->(* If at toplevel (term_expr_opt<>None), the error can be due to
an incorrect context at globalization time: we retype with the
now known intros/lettac/inversion hypothesis names *)letconstr_context=Id.Set.union(Id.Map.domainclosure.typed)(Id.Map.domainclosure.untyped)inletltacvars={ltac_vars=constr_context;ltac_bound=Id.Map.domainist.lfun;ltac_extra=Genintern.Store.empty;}in{closure;term=for_grammar(fun()->intern_genkind~pattern_mode~ltacvarsenvsigmaterm_expr)()}letinterp_uconstristenvsigmac=interp_glob_closureistenvsigmacletinterp_genkindistpattern_modeflagsenvsigmac=letkind_for_intern=matchkindwithOfType_->WithoutTypeConstraint|_->kindinlet{closure=constrvars;term}=interp_glob_closureistenvsigma~kind:kind_for_intern~pattern_modecinletvars={ltac_constrs=constrvars.typed;ltac_uconstrs=constrvars.untyped;ltac_idents=constrvars.idents;ltac_genargs=ist.lfun;}inletloc=loc_of_glob_constrterminlettrace=push_trace(loc,LtacConstrInterp(env,sigma,term,vars))istinlet(stack,_)=tracein(* save and restore the current trace info because the called routine later starts
with an empty trace *)Tactic_debug.push_chunktrace;trylet(evd,c)=catch_error_with_trace_loclocstack(understand_ltacflagsenvsigmavarskind)termin(* spiwack: to avoid unnecessary modifications of tacinterp, as this
function already use effect, I call [run] hoping it doesn't mess
up with any assumption. *)Proofview.NonLogical.run(db_constr(curr_debugist)envevdc);Tactic_debug.pop_chunk();(evd,c)withreraise->letreraise=Exninfo.capturereraiseinTactic_debug.pop_chunk();Exninfo.iraisereraiseletconstr_flags()={use_coercions=true;use_typeclasses=UseTC;solve_unification_constraints=true;fail_evar=true;expand_evars=true;program_mode=false;polymorphic=false;}(* Interprets a constr; expects evars to be solved *)letinterp_constr_genkindistenvsigmac=letflags={(constr_flags())withpolymorphic=ist.Geninterp.poly}ininterp_genkindistfalseflagsenvsigmacletinterp_constr=interp_constr_genWithoutTypeConstraintletinterp_type=interp_constr_genIsTypeletopen_constr_use_classes_flags()={use_coercions=true;use_typeclasses=UseTC;solve_unification_constraints=true;fail_evar=false;expand_evars=true;program_mode=false;polymorphic=false;}letopen_constr_no_classes_flags()={use_coercions=true;use_typeclasses=NoUseTC;solve_unification_constraints=true;fail_evar=false;expand_evars=true;program_mode=false;polymorphic=false;}letpure_open_constr_flags={use_coercions=true;use_typeclasses=NoUseTC;solve_unification_constraints=true;fail_evar=false;expand_evars=false;program_mode=false;polymorphic=false;}(* Interprets an open constr *)letinterp_open_constr?(expected_type=WithoutTypeConstraint)?(flags=open_constr_no_classes_flags())istenvsigmac=interp_genexpected_typeistfalseflagsenvsigmacletinterp_open_constr_with_classes?(expected_type=WithoutTypeConstraint)istenvsigmac=interp_genexpected_typeistfalse(open_constr_use_classes_flags())envsigmacletinterp_pure_open_constrist=interp_genWithoutTypeConstraintistfalsepure_open_constr_flagsletinterp_typed_patternistenvsigma(_,c,_)=letsigma,c=interp_genWithoutTypeConstraintisttruepure_open_constr_flagsenvsigmacin(* FIXME: it is necessary to be unsafe here because of the way we handle
evars in the pretyper. Sometimes they get solved eagerly. *)legacy_bad_pattern_of_constrenvsigmac(* Interprets a constr expression *)letinterp_constr_in_compound_listinj_fundest_funinterp_funistenvsigmal=lettry_expand_ltac_varsigmax=trymatchDAst.get(fst(dest_funx))with|GVarid->letv=Id.Map.findidist.lfuninsigma,List.mapinj_fun(coerce_to_constr_listenvv)|_->raiseNot_foundwithCannotCoerceTo_|Not_found->(* dest_fun, List.assoc may raise Not_found *)letsigma,c=interp_funistenvsigmaxinsigma,[c]inletsigma,l=List.fold_left_maptry_expand_ltac_varsigmalinsigma,List.flattenlletinterp_constr_lististenvsigmac=interp_constr_in_compound_list(funx->x)(funx->x)interp_constristenvsigmacletinterp_open_constr_list=interp_constr_in_compound_list(funx->x)(funx->x)interp_open_constr(* Interprets a reduction expression *)letinterp_unfoldistenvsigma(occs,qid)=(interp_occurrencesistoccs,interp_evaluableistenvsigmaqid)letinterp_flagistenvsigmared={redwithrConst=List.map(interp_evaluableistenvsigma)red.rConst}letinterp_constr_with_occurrencesistenvsigma(occs,c)=let(sigma,c_interp)=interp_constristenvsigmacinsigma,(interp_occurrencesistoccs,c_interp)letinterp_closed_typed_pattern_with_occurrencesistenvsigma(occs,a)=letp=matchawith|Inl(ArgVar{loc;v=id})->(* This is the encoding of an ltac var supposed to be bound
prioritary to an evaluable reference and otherwise to a constr
(it is an encoding to satisfy the "union" type given to Simpl) *)letcoerce_eval_ref_or_constrx=tryInl(coerce_to_evaluable_refenvsigmax)withCannotCoerceTo_->letc=coerce_to_closed_constrenvxinInr(legacy_bad_pattern_of_constrenvsigmac)in(trytry_interp_ltac_varcoerce_eval_ref_or_constrist(Some(env,sigma))(CAst.make?locid)withNot_foundasexn->let_,info=Exninfo.captureexninNametab.error_global_not_found~info(qualid_of_ident?locid))|Inl(ArgArg_asb)->Inl(interp_evaluableistenvsigmab)|Inrc->Inr(interp_typed_patternistenvsigmac)ininterp_occurrencesistoccs,pletinterp_constr_with_occurrences_and_name_as_list=interp_constr_in_compound_list(func->((AllOccurrences,c),Anonymous))(function((occs,c),Anonymous)whenoccs==AllOccurrences->c|_->raiseNot_found)(funistenvsigma(occ_c,na)->let(sigma,c_interp)=interp_constr_with_occurrencesistenvsigmaocc_cinsigma,(c_interp,interp_nameistenvsigmana))letinterp_red_expristenvsigma=function|Unfoldl->sigma,Unfold(List.map(interp_unfoldistenvsigma)l)|Foldl->let(sigma,l_interp)=interp_constr_lististenvsigmalinsigma,Foldl_interp|Cbvf->sigma,Cbv(interp_flagistenvsigmaf)|Cbnf->sigma,Cbn(interp_flagistenvsigmaf)|Lazyf->sigma,Lazy(interp_flagistenvsigmaf)|Patternl->let(sigma,l_interp)=Evd.MonadR.List.map_right(funcsigma->interp_constr_with_occurrencesistenvsigmac)lsigmainsigma,Patternl_interp|Simpl(f,o)->sigma,Simpl(interp_flagistenvsigmaf,Option.map(interp_closed_typed_pattern_with_occurrencesistenvsigma)o)|CbvVmo->sigma,CbvVm(Option.map(interp_closed_typed_pattern_with_occurrencesistenvsigma)o)|CbvNativeo->sigma,CbvNative(Option.map(interp_closed_typed_pattern_with_occurrencesistenvsigma)o)|(Red_|Hnf|ExtraRedExpr_asr)->sigma,rletinterp_may_evalfistenvsigma=function|ConstrEval(r,c)->let(sigma,redexp)=interp_red_expristenvsigmarinlet(sigma,c_interp)=fistenvsigmacinlet(redfun,_)=Redexpr.reduction_of_red_exprenvredexpinredfunenvsigmac_interp|ConstrContext({loc;v=s},c)->let(sigma,ic)=fistenvsigmacinletctxt=trytry_interp_ltac_varcoerce_to_constr_contextist(Some(env,sigma))(CAst.make?locs)withNot_found->user_err?loc(str"Unbound context identifier"++Id.prints++str".")inletc=Constr_matching.instantiate_contextctxticinTyping.solve_evarsenvsigmac|ConstrTypeOfc->let(sigma,c_interp)=fistenvsigmacinlet(sigma,t)=Typing.type_of~refresh:trueenvsigmac_interpin(sigma,t)|ConstrTermc->tryfistenvsigmacwithreraise->letreraise=Exninfo.capturereraisein(* spiwack: to avoid unnecessary modifications of tacinterp, as this
function already use effect, I call [run] hoping it doesn't mess
up with any assumption. *)Proofview.NonLogical.run(debugging_exception_stepistfalse(fstreraise)(fun()->str"interpretation of term "++pr_glob_constr_envenvsigma(fstc)));Exninfo.iraisereraise(* Interprets a constr expression possibly to first evaluate *)letinterp_constr_may_evalistenvsigmac=let(sigma,csr)=tryinterp_may_evalinterp_constristenvsigmacwithreraise->letreraise=Exninfo.capturereraisein(* spiwack: to avoid unnecessary modifications of tacinterp, as this
function already use effect, I call [run] hoping it doesn't mess
up with any assumption. *)Proofview.NonLogical.run(debugging_exception_stepistfalse(fstreraise)(fun()->str"evaluation of term"));Exninfo.iraisereraiseinbegin(* spiwack: to avoid unnecessary modifications of tacinterp, as this
function already use effect, I call [run] hoping it doesn't mess
up with any assumption. *)Proofview.NonLogical.run(db_constr(curr_debugist)envsigmacsr);sigma,csrend(** TODO: should use dedicated printers *)letmessage_of_valuev=letpr_with_envpr=Ftactic.enterbeginfungl->Ftactic.return(pr(pf_envgl)(projectgl))endinletopenGenprintinmatchgeneric_val_printvwith|TopPrinterBasicpr->Ftactic.return(pr())|TopPrinterNeedsContextpr->pr_with_envpr|TopPrinterNeedsContextAndLevel{default_ensure_surrounded;printer}->pr_with_env(funenvsigma->printerenvsigmadefault_ensure_surrounded)letinterp_message_tokenist=function|MsgStrings->Ftactic.return(strs)|MsgIntn->Ftactic.return(intn)|MsgIdent{loc;v=id}->letv=trySome(Id.Map.findidist.lfun)withNot_found->Noneinmatchvwith|None->Ftactic.lift(letinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(Id.printid++str" not found."))|Somev->message_of_valuevletinterp_messageistl=letopenFtacticinFtactic.List.map(interp_message_tokenist)l>>=funl->Ftactic.return(prlist_with_sepspc(funx->x)l)letrecinterp_intro_patternistenvsigma=with_loc_val(fun?loc->function|IntroActionpat->letpat=interp_intro_pattern_actionistenvsigmapatinCAst.make?loc@@IntroActionpat|IntroNaming(IntroIdentifierid)->CAst.make?loc@@interp_intro_pattern_varlocistenvsigmaid|IntroNamingpat->CAst.make?loc@@IntroNaming(interp_intro_pattern_naminglocistenvsigmapat)|IntroForthcoming_asx->CAst.make?locx)andinterp_intro_pattern_naminglocistenvsigma=function|IntroFreshid->IntroFresh(interp_identistenvsigmaid)|IntroIdentifierid->interp_intro_pattern_naming_varlocistenvsigmaid|IntroAnonymousasx->xandinterp_intro_pattern_actionistenvsigma=function|IntroOrAndPatternl->letl=interp_or_and_intro_patternistenvsigmalinIntroOrAndPatternl|IntroInjectionl->letl=interp_intro_pattern_list_as_lististenvsigmalinIntroInjectionl|IntroApplyOn({loc;v=c},ipat)->letcenvsigma=interp_open_constristenvsigmacinletipat=interp_intro_patternistenvsigmaipatinIntroApplyOn(CAst.make?locc,ipat)|IntroWildcard|IntroRewrite_asx->xandinterp_or_and_intro_patternistenvsigma=function|IntroAndPatternl->letl=List.map(interp_intro_patternistenvsigma)linIntroAndPatternl|IntroOrPatternll->letll=List.map(interp_intro_pattern_list_as_lististenvsigma)llinIntroOrPatternllandinterp_intro_pattern_list_as_lististenvsigma=function|[{loc;v=IntroNaming(IntroIdentifierid)}]asl->(trycoerce_to_intro_pattern_list?locsigma(Id.Map.findidist.lfun)withNot_found|CannotCoerceTo_->List.map(interp_intro_patternistenvsigma)l)|l->List.map(interp_intro_patternistenvsigma)lletinterp_intro_pattern_naming_optionistenvsigma=function|None->None|Somelpat->Some(map_with_loc(fun?locpat->interp_intro_pattern_naminglocistenvsigmapat)lpat)letinterp_or_and_intro_pattern_optionistenvsigma=function|None->None|Some(ArgVar{loc;v=id})->(matchinterp_intro_pattern_varlocistenvsigmaidwith|IntroAction(IntroOrAndPatternl)->Some(CAst.make?locl)|_->user_err?loc(str"Cannot coerce to a disjunctive/conjunctive pattern."))|Some(ArgArg{loc;v=l})->letl=interp_or_and_intro_patternistenvsigmalinSome(CAst.make?locl)letinterp_intro_pattern_optionistenvsigma=function|None->None|Someipat->letipat=interp_intro_patternistenvsigmaipatinSomeipatletinterp_in_hyp_asistenvsigma(id,ipat)=letipat=interp_intro_pattern_optionistenvsigmaipatin(interp_hypistenvsigmaid,ipat)letinterp_binding_nameistenvsigma=function|AnonHypn->AnonHypn|NamedHypid->(* If a name is bound, it has to be a quantified hypothesis *)(* user has to use other names for variables if these ones clash with *)(* a name intended to be used as a (non-variable) identifier *)trytry_interp_ltac_var(coerce_to_quantified_hypothesissigma)ist(Some(env,sigma))idwithNot_found->NamedHypidletinterp_declared_or_quantified_hypothesisistenvsigma=function|AnonHypn->AnonHypn|NamedHypid->trytry_interp_ltac_var(coerce_to_decl_or_quant_hypsigma)ist(Some(env,sigma))idwithNot_found->NamedHypidletinterp_bindingistenvsigma{loc;v=(b,c)}=letsigma,c=interp_open_constristenvsigmacinsigma,(CAst.make?loc(interp_binding_nameistenvsigmab,c))letinterp_bindingsistenvsigma=function|NoBindings->sigma,NoBindings|ImplicitBindingsl->letsigma,l=interp_open_constr_lististenvsigmalinsigma,ImplicitBindingsl|ExplicitBindingsl->letsigma,l=List.fold_left_map(interp_bindingistenv)sigmalinsigma,ExplicitBindingslletinterp_constr_with_bindingsistenvsigma(c,bl)=letsigma,bl=interp_bindingsistenvsigmablinletsigma,c=interp_constristenvsigmacinsigma,(c,bl)letinterp_open_constr_with_bindingsistenvsigma(c,bl)=letsigma,bl=interp_bindingsistenvsigmablinletsigma,c=interp_open_constristenvsigmacinsigma,(c,bl)letloc_of_bindings=function|NoBindings->None|ImplicitBindingsl->loc_of_glob_constr(fst(List.lastl))|ExplicitBindingsl->(List.lastl).locletinterp_open_constr_with_bindings_locist((c,_),blascb)=letloc1=loc_of_glob_constrcinletloc2=loc_of_bindingsblinletloc=Loc.merge_optloc1loc2inletfenvsigma=interp_open_constr_with_bindingsistenvsigmacbin(loc,f)letinterp_destruction_argistglarg=matchargwith|keep,ElimOnConstrc->keep,ElimOnConstrbeginfunenvsigma->interp_open_constr_with_bindingsistenvsigmacend|keep,ElimOnAnonHypnasx->x|keep,ElimOnIdent{loc;v=id}->leterror()=user_err?loc(strbrk"Cannot coerce "++Id.printid++strbrk" neither to a quantified hypothesis nor to a term.")inlettry_cast_idid'=ifTactics.is_quantified_hypothesisid'glthenkeep,ElimOnIdent(CAst.make?locid')else(keep,ElimOnConstrbeginfunenvsigma->try(sigma,(constr_of_idenvid',NoBindings))withNot_found->user_err?loc(Id.printid++strbrk" binds to "++Id.printid'++strbrk" which is neither a declared nor a quantified hypothesis.")end)intry(* FIXME: should be moved to taccoerce *)letv=Id.Map.findidist.lfuninifhas_typev(topwitwit_intro_pattern)thenletv=out_gen(topwitwit_intro_pattern)vinmatchvwith|{v=IntroNaming(IntroIdentifierid)}->try_cast_idid|_->error()elseifhas_typev(topwitwit_hyp)thenletid=out_gen(topwitwit_hyp)vintry_cast_ididelseifhas_typev(topwitwit_int)thenkeep,ElimOnAnonHyp(out_gen(topwitwit_int)v)elsematchValue.to_constrvwith|None->error()|Somec->keep,ElimOnConstr(funenvsigma->(sigma,(c,NoBindings)))withNot_found->(* We were in non strict (interactive) mode *)ifTactics.is_quantified_hypothesisidglthenkeep,ElimOnIdent(CAst.make?locid)elseletc=(DAst.make?loc@@GVarid,Some(CAst.make@@CRef(qualid_of_ident?locid,None)))inletfenvsigma=let(sigma,c)=interp_open_constristenvsigmacin(sigma,(c,NoBindings))inkeep,ElimOnConstrf(* Associates variables with values and gives the remaining variables and
values *)lethead_with_value(lvar,lval)=letrechead_with_value_reclacc=function|([],[])->(lacc,[],[])|(vr::tvr,ve::tve)->(matchvrwith|Anonymous->head_with_value_reclacc(tvr,tve)|Namev->head_with_value_rec((v,ve)::lacc)(tvr,tve))|(vr,[])->(lacc,vr,[])|([],ve)->(lacc,[],ve)inhead_with_value_rec[](lvar,lval)(** [interp_context ctxt] interprets a context (as in
{!Matching.matching_result}) into a context value of Ltac. *)letinterp_contextctxt=in_gen(topwitwit_constr_context)ctxtleteval_patternlfunistenvsigma(bvars,_,pat)=(bvars,Constr_matching.instantiate_patternenvsigmalfunpat)letread_patternlfunistenvsigma=function|Subterm(ido,c)->Subterm(ido,eval_patternlfunistenvsigmac)|Termc->Term(eval_patternlfunistenvsigmac)(* Reads the hypotheses of a Match Context rule *)letcons_and_check_nameidl=ifId.List.memidlthenuser_err(str"Hypothesis pattern-matching variable "++Id.printid++str" used twice in the same pattern.")elseid::lletrecread_match_goal_hypslfunistenvsigmalidh=function|(Hyp({loc;v=na}aslocna,mp))::tl->letlidh'=Name.fold_rightcons_and_check_namenalidhinHyp(locna,read_patternlfunistenvsigmamp)::(read_match_goal_hypslfunistenvsigmalidh'tl)|(Def({loc;v=na}aslocna,mv,mp))::tl->letlidh'=Name.fold_rightcons_and_check_namenalidhinDef(locna,read_patternlfunistenvsigmamv,read_patternlfunistenvsigmamp)::(read_match_goal_hypslfunistenvsigmalidh'tl)|[]->[](* Reads the rules of a Match Context or a Match *)letrecread_match_rulelfunistenvsigma=function|(Alltc)::tl->(Alltc)::(read_match_rulelfunistenvsigmatl)|(Pat(rl,mp,tc))::tl->Pat(read_match_goal_hypslfunistenvsigma[]rl,read_patternlfunistenvsigmamp,tc)::read_match_rulelfunistenvsigmatl|[]->[](* Fully evaluate an untyped constr *)lettype_uconstr?(flags=(constr_flags()))?(expected_type=WithoutTypeConstraint)istc=letflags={flagswithpolymorphic=ist.Geninterp.poly}inbeginfunenvsigma->Pretyping.understand_uconstr~flags~expected_typeenvsigmacend(* Interprets an l-tac expression into a value *)letrecval_interpist?(appl=UnnamedAppl)(tac:glob_tactic_expr):Val.tFtactic.t=(* The name [appl] of applied top-level Ltac names is ignored in
[value_interp]. It is installed in the second step by a call to
[name_vfun], because it gives more opportunities to detect a
[VFun]. Otherwise a [Ltac t := let x := .. in tac] would never
register its name since it is syntactically a let, not a
function. *)let(loc,tac2)=CAst.(tac.loc,tac.v)inletvalue_interpist=matchtac2with|TacFun(it,body)->Ftactic.return(of_tacvalue(VFun(UnnamedAppl,extract_traceist,extract_locist,ist.lfun,it,body)))|TacLetIn(true,l,u)->interp_letrecistlu|TacLetIn(false,l,u)->interp_letinistlu|TacMatchGoal(lz,lr,lmr)->interp_match_goalistlzlrlmr|TacMatch(lz,c,lmr)->interp_matchistlzclmr|TacArgv->interp_tacargistv|_->(* Delayed evaluation *)Ftactic.return(of_tacvalue(VFun(UnnamedAppl,extract_traceist,extract_locist,ist.lfun,[],tac)))inletopenFtacticinControl.check_for_interrupt();matchcurr_debugistwith|DebugOnlev->letevalv=letist={istwithextra=TacStore.setist.extraf_debugv}invalue_interpist>>=funv->return(name_vfunapplv)inTactic_debug.debug_promptlevtacevalist.lfun(TacStore.getist.extraf_trace)|_->value_interpist>>=funv->return(name_vfunapplv)andeval_tactic_ististtac:unitProofview.tactic=let(loc,tac2)=CAst.(tac.loc,tac.v)inmatchtac2with|TacAtomt->letcall=LtacAtomCalltinlet(stack,_)=push_trace(loc,call)istinProfile_ltac.do_profile"eval_tactic:2"stack(catch_error_tac_loclocstack(interp_atomicistt))|TacFun_|TacLetIn_|TacMatchGoal_|TacMatch_->interp_tacticisttac|TacId[]->Proofview.tclLIFT(db_breakpoint(curr_debugist)[])|TacIds->letmsgnl=letopenFtacticininterp_messageists>>=funmsg->return(hov0msg,hov0msg)inletprint(_,msgnl)=Proofview.(tclLIFT(NonLogical.print_infomsgnl))inletlog(msg,_)=Proofview.Trace.log(fun()->msg)inletbreak=Proofview.tclLIFT(db_breakpoint(curr_debugist)s)inFtactic.runmsgnlbeginfunmsgnl->printmsgnl<*>logmsgnl<*>breakend|TacFail(g,n,s)->letmsg=interp_messageistsinlettac~infol=Tacticals.tclFAILn~info(interp_int_or_varistn)linlettac=matchgwith|TacLocal->letinfo=Exninfo.reify()infunl->Proofview.tclINDEPENDENT(tac~infol)|TacGlobal->letinfo=Exninfo.reify()intac~infoinFtactic.runmsgtac|TacProgresstac->Tacticals.tclPROGRESS(interp_tacticisttac)|TacAbstract(t,ido)->letcall=LtacMLCalltacinlet(stack,_)=push_trace(None,call)istinProfile_ltac.do_profile"eval_tactic:TacAbstract"stack(catch_error_tacstackbeginProofview.Goal.enterbeginfungl->Abstract.tclABSTRACT(Option.map(interp_identist(pf_envgl)(projectgl))ido)(interp_tactic(flush_ist_evars(projectgl)ist)t)endend)|TacThen(t1,t)->Tacticals.tclTHEN(interp_tacticistt1)(interp_tacticistt)|TacDispatchtl->Proofview.tclDISPATCH(List.map(interp_tacticist)tl)|TacExtendTac(tf,t,tl)->Proofview.tclEXTEND(Array.map_to_list(interp_tacticist)tf)(interp_tacticistt)(Array.map_to_list(interp_tacticist)tl)|TacThens(t1,tl)->Tacticals.tclTHENS(interp_tacticistt1)(List.map(interp_tacticist)tl)|TacThens3parts(t1,tf,t,tl)->Tacticals.tclTHENS3PARTS(interp_tacticistt1)(Array.map(interp_tacticist)tf)(interp_tacticistt)(Array.map(interp_tacticist)tl)|TacDo(n,tac)->Tacticals.tclDO(interp_int_or_varistn)(interp_tacticisttac)|TacTimeout(n,tac)->Tacticals.tclTIMEOUT(interp_int_or_varistn)(interp_tacticisttac)|TacTime(s,tac)->Tacticals.tclTIMEs(interp_tacticisttac)|TacTrytac->Tacticals.tclTRY(interp_tacticisttac)|TacRepeattac->Tacticals.tclREPEAT(interp_tacticisttac)|TacOr(tac1,tac2)->Tacticals.tclOR(interp_tacticisttac1)(interp_tacticisttac2)|TacOncetac->Tacticals.tclONCE(interp_tacticisttac)|TacExactlyOncetac->Tacticals.tclEXACTLY_ONCE(interp_tacticisttac)|TacIfThenCatch(t,tt,te)->Tacticals.tclIFCATCH(interp_tacticistt)(fun()->interp_tacticisttt)(fun()->interp_tacticistte)|TacOrelse(tac1,tac2)->Tacticals.tclORELSE(interp_tacticisttac1)(interp_tacticisttac2)|TacFirstl->Tacticals.tclFIRST(List.map(interp_tacticist)l)|TacSolvel->Tacticals.tclSOLVE(List.map(interp_tacticist)l)|TacCompletetac->Tacticals.tclCOMPLETE(interp_tacticisttac)|TacArg_->Ftactic.run(val_interp(ensure_loclocist)tac)(funv->tactic_of_valueistv)|TacSelect(sel,tac)->Goal_select.tclSELECTsel(interp_tacticisttac)(* For extensions *)|TacAlias(s,l)->letalias=Tacenv.interp_aliassinProofview.tclProofInfo[@ocaml.warning"-3"]>>=fun(_name,poly)->let(>>=)=Ftactic.bindinletinterp_vars=Ftactic.List.map(funv->interp_tacargistv)linlettacl=letaddvarxvaccu=Id.Map.addxvaccuinletlfun=List.fold_right2addvaralias.Tacenv.alias_argslist.lfuninlettrace=push_trace(loc,LtacNotationCalls)istinletist={lfun;poly;extra=add_extra_locloc(add_extra_tracetraceist.extra)}inval_interpistalias.Tacenv.alias_body>>=funv->Ftactic.lift(tactic_of_valueistv)inlettac=Ftactic.with_envinterp_vars>>=fun(env,lr)->letname()=Pptactic.pr_alias(funv->print_top_valenvv)0slrinProofview.Trace.name_tacticname(taclr)(* spiwack: this use of name_tactic is not robust to a
change of implementation of [Ftactic]. In such a situation,
some more elaborate solution will have to be used. *)inlettac=letlen1=List.lengthalias.Tacenv.alias_argsinletlen2=List.lengthliniflen1=len2thentacelseletinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"Arguments length mismatch: \
expected "++intlen1++str", found "++intlen2)inFtactic.runtac(fun()->Proofview.tclUNIT())|TacML(opn,l)->lettrace=push_trace(Loc.tag?loc@@LtacMLCalltac)istinletist={istwithextra=TacStore.setist.extraf_tracetrace;}inlettac=Tacenv.interp_ml_tacticopninletargs=Ftactic.List.map_right(funa->interp_tacargista)linlettacargs=letname()=Pptactic.pr_extend(funv->print_top_val()v)0opnargsinlet(stack,_)=traceinProofview.Trace.name_tacticname(catch_error_tac_loclocstack(tacargsist))inFtactic.runargstacandforce_vrecistv:Val.tFtactic.t=ifhas_typev(topwitwit_tacvalue)thenletv=to_tacvaluevinmatchvwith|VRec(lfun,body)->val_interp{istwithlfun=!lfun}body|v->Ftactic.return(of_tacvaluev)elseFtactic.returnvandinterp_ltac_reference?loc'mustbetacistr:Val.tFtactic.t=matchrwith|ArgVar{loc;v=id}->letv=tryId.Map.findidist.lfunwithNot_found->in_gen(topwitwit_hyp)idinletopenFtacticinforce_vrecistv>>=beginfunv->Ftactic.lift(propagate_traceistlocidv)>>=funv->ifmustbetacthenFtactic.return(coerce_to_tacticlocidv)elseFtactic.returnvend|ArgArg(loc,r)->Proofview.tclProofInfo[@ocaml.warning"-3"]>>=fun(_name,poly)->letids=extract_ids[]ist.lfunId.Set.emptyinletloc_info=(Option.defaultlocloc',LtacNameCallr)inletextra=TacStore.setist.extraf_avoid_idsidsinlettrace=push_traceloc_infoistinletextra=TacStore.setextraf_tracetraceinletist={lfun=Id.Map.empty;poly;extra}inletappl=GlbAppl[r,[]]in(* We call a global ltac reference: add a loc on its executation only if not
already in another global reference *)letist=ensure_loclocistinlet(stack,_)=traceinProfile_ltac.do_profile"interp_ltac_reference"stack~count_call:false(catch_error_tac_loc(* loc for interpretation *)locstack(val_interp~applist(Tacenv.interp_ltacr)))andinterp_tacargistarg:Val.tFtactic.t=matchargwith|TacGeneric(_,arg)->interp_genargistarg|Referencer->interp_ltac_referencefalseistr|ConstrMayEvalc->Ftactic.enterbeginfungl->letsigma=projectglinletenv=Proofview.Goal.envglinlet(sigma,c_interp)=interp_constr_may_evalistenvsigmacinProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Ftactic.return(Value.of_constrc_interp))end|TacCall{v=(r,[])}->interp_ltac_referencetrueistr|TacCall{loc;v=(f,l)}->let(>>=)=Ftactic.bindininterp_ltac_referencetrueistf>>=funfv->Ftactic.List.map(funa->interp_tacargista)l>>=funlargs->interp_applocistfvlargs|TacFreshIdl->Ftactic.enterbeginfungl->letid=interp_fresh_idist(pf_envgl)(projectgl)linFtactic.return(in_gen(topwitwit_intro_pattern)(CAst.make@@IntroNaming(IntroIdentifierid)))end|TacPretypec->Ftactic.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinletc=interp_uconstristenvsigmacinlet(sigma,c)=type_uconstristcenvsigmainProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Ftactic.return(Value.of_constrc))end|TacNumgoals->Ftactic.liftbeginletopenProofview.NotationsinProofview.numgoals>>=funi->Proofview.tclUNIT(Value.of_inti)end|Tacexpt->val_interpistt(* Interprets an application node *)andinterp_applocistfvlargs:Val.tFtactic.t=Proofview.tclProofInfo[@ocaml.warning"-3"]>>=fun(_name,poly)->let(>>=)=Ftactic.bindinletfail~info=Tacticals.tclZEROMSG~info(str"Illegal tactic application.")inifhas_typefv(topwitwit_tacvalue)thenmatchto_tacvaluefvwith(* if var=[] and body has been delayed by val_interp, then body
is not a tactic that expects arguments.
Otherwise Ltac goes into an infinite loop (val_interp puts
a VFun back on body, and then interp_app is called again...) *)|(VFun(appl,trace,_,olfun,(_::_asvar),body)|VFun(appl,trace,_,olfun,([]asvar),({CAst.v=(TacFun_)}|{CAst.v=(TacLetIn_)}|{CAst.v=(TacMatchGoal_)}|{CAst.v=(TacMatch_)}|{CAst.v=(TacArg_)}asbody)))->let(extfun,lvar,lval)=head_with_value(var,largs)inletfoldaccu(id,v)=Id.Map.addidvaccuinletnewlfun=List.fold_leftfoldolfunextfuninifList.is_emptylvarthenbeginwrap_errorbeginletist={lfun=newlfun;poly;extra=TacStore.setist.extraf_tracetrace}inlet(stack,_)=traceinProfile_ltac.do_profile"interp_app"stack~count_call:false(catch_error_tac_loclocstack(val_interp(ensure_loclocist)body))>>=funv->Ftactic.return(name_vfun(push_applappllargs)v)endbeginfun(e,info)->Proofview.tclLIFT(debugging_exception_stepistfalsee(fun()->str"evaluation"))<*>Proofview.tclZERO~infoeendend>>=funv->(* No errors happened, we propagate the trace *)letv=append_tracetracevinletcall_debugenv=Proofview.tclLIFT(debugging_stepist(fun()->str"evaluation returns"++fnl()++pr_valueenvv))inbeginletopenGenprintinmatchgeneric_val_printvwith|TopPrinterBasic_->call_debugNone|TopPrinterNeedsContext_|TopPrinterNeedsContextAndLevel_->Proofview.Goal.enter(fungl->call_debug(Some(pf_envgl,projectgl)))end<*>ifList.is_emptylvalthenFtactic.returnvelseinterp_applocistvlvalelseFtactic.return(of_tacvalue(VFun(push_applappllargs,trace,loc,newlfun,lvar,body)))|(VFun(appl,trace,_,olfun,[],body))->letextra_args=List.lengthlargsinletinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"Illegal tactic application: got "++str(string_of_intextra_args)++str" extra "++str(String.pluralextra_args"argument")++str".")|VRec(_,_)->letinfo=Exninfo.reify()infail~infoelseletinfo=Exninfo.reify()infail~info(* Gives the tactic corresponding to the tactic value *)andtactic_of_valueistvle=ifhas_typevle(topwitwit_tacvalue)thenmatchto_tacvaluevlewith|VFun(appl,trace,loc,lfun,[],t)->Proofview.tclProofInfo[@ocaml.warning"-3"]>>=fun(_name,poly)->letist={lfun=lfun;poly;(* todo: debug stack needs "trace" but that gives incorrect results for profiling
Couldn't figure out how to make them play together. Currently no way both can
be enabled. Perhaps profiling should be redesigned as suggested in profile_ltac.mli *)extra=TacStore.setist.extraf_trace(if!Flags.profile_ltacthen([],[])elsetrace);}inlettac=name_if_globappl(eval_tactic_ististt)inlet(stack,_)=traceinProfile_ltac.do_profile"tactic_of_value"stack(catch_error_tac_loclocstacktac)|VFun(appl,_,loc,vmap,vars,_)->lettactic_nm=matchapplwithUnnamedAppl->"An unnamed user-defined tactic"|GlbApplapps->letnms=List.map(fun(kn,_)->string_of_qualid(Tacenv.shortest_qualid_of_tactickn))appsinmatchnmswith[]->assertfalse|kn::_->"The user-defined tactic \""^kn^"\""(* TODO: when do we not have a singleton? *)inletnumargs=List.lengthvarsinletgivenargs=List.map(fun(arg,_)->Names.Id.to_stringarg)(Names.Id.Map.bindingsvmap)inletnumgiven=List.lengthgivenargsinletinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(Pp.strtactic_nm++Pp.str" was not fully applied:"++spc()++(matchnumargswith0->assertfalse|1->Pp.str"There is a missing argument for variable "++(Name.print(List.hdvars))|_->Pp.str"There are missing arguments for variables "++pr_enumName.printvars)++Pp.pr_comma()++matchnumgivenwith0->Pp.str"no arguments at all were provided."|1->Pp.str"an argument was provided for variable "++Pp.str(List.hdgivenargs)++Pp.str"."|_->Pp.str"arguments were provided for variables "++pr_enumPp.strgivenargs++Pp.str".")|VRec_->letinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"A fully applied tactic is expected.")elseifhas_typevle(topwitwit_tactic)thenlettac=out_gen(topwitwit_tactic)vleintactic_of_valueisttacelseletinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"Expression does not evaluate to a tactic.")(* Interprets the clauses of a recursive LetIn *)andinterp_letrecistllcu=Proofview.tclUNIT()>>=fun()->(* delay for the effects of [lref], just in case. *)letlref=refist.lfuninletfoldaccu({v=na},b)=letv=of_tacvalue(VRec(lref,CAst.make(TacArgb)))inName.fold_right(funid->Id.Map.addidv)naaccuinletlfun=List.fold_leftfoldist.lfunllcinlet()=lref:=lfuninletist={istwithlfun}inval_interpistu(* Interprets the clauses of a LetIn *)andinterp_letinistllcu=letrecfoldlfun=function|[]->letist={istwithlfun}inval_interpistu|({v=na},body)::defs->Ftactic.bind(interp_tacargistbody)(funv->fold(Name.fold_right(funid->Id.Map.addidv)nalfun)defs)infoldist.lfunllc(** [interp_match_success lz ist succ] interprets a single matching success
(of type {!Tactic_matching.t}). *)andinterp_match_successist{Tactic_matching.subst;context;terms;lhs}=Proofview.tclProofInfo[@ocaml.warning"-3"]>>=fun(_name,poly)->let(>>=)=Ftactic.bindinletlctxt=Id.Map.mapinterp_contextcontextinlethyp_subst=Id.Map.mapValue.of_constrtermsinletlfun=extend_values_with_bindingssubst(lctxt+++hyp_subst+++ist.lfun)inletist={istwithlfun}inval_interpistlhs>>=funv->ifhas_typev(topwitwit_tacvalue)thenmatchto_tacvaluevwith|VFun(appl,trace,loc,lfun,[],t)->letist={lfun=lfun;poly;extra=TacStore.setist.extraf_tracetrace}inlettac=eval_tactic_ististtinletdummy=VFun(appl,extract_traceist,loc,Id.Map.empty,[],CAst.make(TacId[]))inlet(stack,_)=traceincatch_error_tacstack(tac<*>Ftactic.return(of_tacvaluedummy))|_->Ftactic.returnvelseFtactic.returnv(** [interp_match_successes lz ist s] interprets the stream of
matching of successes [s]. If [lz] is set to true, then only the
first success is considered, otherwise further successes are tried
if the left-hand side fails. *)andinterp_match_successeslzists=letgeneral=letopenTacticalsinletbreak(e,info)=matchewith|FailError(0,_)->None|FailError(n,s)->Some(FailError(predn,s),info)|_->NoneinProofview.tclBREAKbreaks>>=funans->interp_match_successistansinmatchlzwith|General->general|Select->begin(* Only keep the first matching result, we don't backtrack on it *)lets=Proofview.tclONCEsins>>=funans->interp_match_successistansend|Once->(* Once a tactic has succeeded, do not backtrack anymore *)Proofview.tclONCEgeneral(* Interprets the Match expressions *)andinterp_matchistlzconstrlmr=let(>>=)=Ftactic.bindinbeginwrap_error(interp_ltac_constristconstr)beginfunction|(e,info)->Proofview.tclLIFT(debugging_exception_stepisttruee(fun()->str"evaluation of the matched expression"))<*>Proofview.tclZERO~infoeendend>>=funconstr->Ftactic.enterbeginfungl->letsigma=projectglinletenv=Proofview.Goal.envglinletilr=read_match_rule(extract_ltac_constr_valuesistenv)istenvsigmalmrininterp_match_successeslzist(Tactic_matching.match_termenvsigmaconstrilr)end(* Interprets the Match Context expressions *)andinterp_match_goalistlzlrlmr=Ftactic.enterbeginfungl->letsigma=projectglinletenv=Proofview.Goal.envglinlethyps=Proofview.Goal.hypsglinlethyps=iflrthenList.revhypselsehypsinletconcl=Proofview.Goal.conclglinletilr=read_match_rule(extract_ltac_constr_valuesistenv)istenvsigmalmrininterp_match_successeslzist(Tactic_matching.match_goalenvsigmahypsconclilr)end(* Interprets extended tactic generic arguments *)andinterp_genargistx:Val.tFtactic.t=letopenFtactic.Notationsin(* Ad-hoc handling of some types. *)lettag=genarg_tagxinifargument_type_eqtag(unquote(topwit(wit_listwit_hyp)))theninterp_genarg_var_lististxelseifargument_type_eqtag(unquote(topwit(wit_listwit_constr)))theninterp_genarg_constr_lististxelseletGenArg(Glbwitwit,x)=xinmatchwitwith|ListArgwit->letmapx=interp_genargist(Genarg.in_gen(glbwitwit)x)inFtactic.List.mapmapx>>=funl->Ftactic.return(Val.Dyn(Val.typ_list,l))|OptArgwit->beginmatchxwith|None->Ftactic.return(Val.Dyn(Val.typ_opt,None))|Somex->interp_genargist(Genarg.in_gen(glbwitwit)x)>>=funx->Ftactic.return(Val.Dyn(Val.typ_opt,Somex))end|PairArg(wit1,wit2)->let(p,q)=xininterp_genargist(Genarg.in_gen(glbwitwit1)p)>>=funp->interp_genargist(Genarg.in_gen(glbwitwit2)q)>>=funq->Ftactic.return(Val.Dyn(Val.typ_pair,(p,q)))|ExtraArgs->Geninterp.interpwitistx(** returns [true] for genargs which have the same meaning
independently of goals. *)andinterp_genarg_constr_lististx=Ftactic.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletlc=Genarg.out_gen(glbwit(wit_listwit_constr))xinlet(sigma,lc)=interp_constr_lististenvsigmalcinletlc=in_list(val_tagwit_constr)lcinProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Ftactic.returnlc)endandinterp_genarg_var_lististx=Ftactic.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletlc=Genarg.out_gen(glbwit(wit_listwit_hyp))xinletlc=interp_hyp_lististenvsigmalcinletlc=in_list(val_tagwit_hyp)lcinFtactic.returnlcend(* Interprets tactic expressions : returns a "constr" *)andinterp_ltac_constriste:EConstr.tFtactic.t=let(>>=)=Ftactic.bindinbeginwrap_error(val_interpiste)beginfunction(err,info)->matcherrwith|Not_found->Ftactic.enterbeginfungl->letenv=Proofview.Goal.envglinProofview.tclLIFTbegindebugging_stepist(fun()->str"evaluation failed for"++fnl()++Pptactic.pr_glob_tacticenve)end<*>Proofview.tclZERONot_foundend|err->Proofview.tclZERO~infoerrendend>>=funresult->Ftactic.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglintryletcresult=coerce_to_closed_constrenvresultinProofview.tclLIFTbegindebugging_stepist(fun()->Pptactic.pr_glob_tacticenve++fnl()++str" has value "++fnl()++pr_econstr_envenvsigmacresult)end<*>Ftactic.returncresultwithCannotCoerceTo_asexn->let_,info=Exninfo.captureexninletenv=Proofview.Goal.envglinTacticals.tclZEROMSG~info(str"Must evaluate to a closed term"++fnl()++str"offending expression: "++fnl()++pr_inspectenveresult)end(* Interprets tactic expressions : returns a "tactic" *)andinterp_tacticisttac:unitProofview.tactic=Ftactic.run(val_interpisttac)(funv->tactic_of_valueistv)(* Provides a "name" for the trace to atomic tactics *)andname_atomic?envtacexprtac:unitProofview.tactic=beginmatchenvwith|Somee->Proofview.tclUNITe|None->Proofview.tclENVend>>=funenv->Proofview.tclEVARMAP>>=funsigma->letname()=Pptactic.pr_atomic_tacticenvsigmatacexprinProofview.Trace.name_tacticnametac(* Interprets a primitive tactic *)andinterp_atomicisttac:unitProofview.tactic=matchtacwith(* Basic tactics *)|TacIntroPattern(ev,l)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinletl'=interp_intro_pattern_list_as_lististenvsigmalinname_atomic~env(TacIntroPattern(ev,l))(* spiwack: print uninterpreted, not sure if it is the
expected behaviour. *)(Tactics.intro_patternsevl')end|TacApply(a,ev,cb,cl)->(* spiwack: until the tactic is in the monad *)Proofview.Trace.name_tactic(fun()->Pp.str"<apply>")beginProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinletl=List.map(fun(k,c)->letloc,f=interp_open_constr_with_bindings_locistcin(k,(CAst.make?locf)))cbinlettac=matchclwith|[]->Tactics.apply_with_delayed_bindings_genaevl|cl->letcl=List.map(interp_in_hyp_asistenvsigma)clinList.fold_right(fun(id,ipat)->Tactics.apply_delayed_inaevidlipat)clTacticals.tclIDTACintacendend|TacElim(ev,(keep,cb),cbo)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinletsigma,cb=interp_open_constr_with_bindingsistenvsigmacbinletsigma,cbo=Option.fold_left_map(interp_open_constr_with_bindingsistenv)sigmacboinletnamed_tac=lettac=Tactics.elimevkeepcbcboinname_atomic~env(TacElim(ev,(keep,cb),cbo))tacinTacticals.tclWITHHOLESevnamed_tacsigmaend|TacCase(ev,(keep,cb))->Proofview.Goal.enterbeginfungl->letsigma=projectglinletenv=Proofview.Goal.envglinletsigma,cb=interp_open_constr_with_bindingsistenvsigmacbinletnamed_tac=lettac=Tactics.general_case_analysisevkeepcbinname_atomic~env(TacCase(ev,(keep,cb)))tacinTacticals.tclWITHHOLESevnamed_tacsigmaend|TacMutualFix(id,n,l)->(* spiwack: until the tactic is in the monad *)Proofview.Trace.name_tactic(fun()->Pp.str"<mutual fix>")beginProofview.Goal.enterbeginfungl->letenv=pf_envglinletfsigma(id,n,c)=let(sigma,c_interp)=interp_typeistenvsigmacinsigma,(interp_identistenvsigmaid,n,c_interp)inlet(sigma,l_interp)=Evd.MonadR.List.map_right(funcsigma->fsigmac)l(projectgl)inTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Tactics.mutual_fix(interp_identistenvsigmaid)nl_interp0)endend|TacMutualCofix(id,l)->(* spiwack: until the tactic is in the monad *)Proofview.Trace.name_tactic(fun()->Pp.str"<mutual cofix>")beginProofview.Goal.enterbeginfungl->letenv=pf_envglinletfsigma(id,c)=let(sigma,c_interp)=interp_typeistenvsigmacinsigma,(interp_identistenvsigmaid,c_interp)inlet(sigma,l_interp)=Evd.MonadR.List.map_right(funcsigma->fsigmac)l(projectgl)inTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Tactics.mutual_cofix(interp_identistenvsigmaid)l_interp0)endend|TacAssert(ev,b,t,ipat,c)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinlet(sigma,c)=letexpected_type=ifOption.is_emptytthenWithoutTypeConstraintelseIsTypeinletflags=open_constr_use_classes_flags()ininterp_open_constr~expected_type~flagsistenvsigmacinletipat'=interp_intro_pattern_optionistenvsigmaipatinlettac=Option.map(Option.map(interp_tacticist))tinTacticals.tclWITHHOLESev(name_atomic~env(TacAssert(ev,b,Option.map(Option.mapignore)t,ipat,c))(Tactics.forwardbtacipat'c))sigmaend|TacGeneralizecl->Proofview.Goal.enterbeginfungl->letsigma=projectglinletenv=Proofview.Goal.envglinletsigma,cl=interp_constr_with_occurrences_and_name_as_lististenvsigmaclinTacticals.tclWITHHOLESfalse(name_atomic~env(TacGeneralizecl)(Tactics.generalize_gencl))sigmaend|TacLetTac(ev,na,c,clp,b,eqpat)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinletclp=interp_clauseistenvsigmaclpinleteqpat=interp_intro_pattern_naming_optionistenvsigmaeqpatinifLocusops.is_nowhereclp(* typically "pose" *)then(* We try to fully-typecheck the term *)letflags=open_constr_use_classes_flags()inlet(sigma,c_interp)=interp_open_constr~flagsistenvsigmacinletna=interp_nameistenvsigmanainletlet_tac=ifbthenTactics.pose_tacnac_interpelseletid=Option.default(CAst.makeIntroAnonymous)eqpatinletwith_eq=Some(true,id)inTactics.letin_tacwith_eqnac_interpNoneLocusops.nowhereinTacticals.tclWITHHOLESev(name_atomic~env(TacLetTac(ev,na,c_interp,clp,b,eqpat))let_tac)sigmaelse(* We try to keep the pattern structure as much as possible *)letlet_pat_tacbnaccleqpat=letid=Option.default(CAst.makeIntroAnonymous)eqpatinletwith_eq=ifbthenNoneelseSome(true,id)inTactics.letin_pat_tacevwith_eqnacclinlet(sigma',c)=interp_pure_open_constristenvsigmacinname_atomic~env(TacLetTac(ev,na,c,clp,b,eqpat))(Tacticals.tclWITHHOLESev(let_pat_tacb(interp_nameistenvsigmana)(sigma,c)clpeqpat)sigma')end(* Derived basic tactics *)|TacInductionDestruct(isrec,ev,(l,el))->(* spiwack: some unknown part of destruct needs the goal to be
prenormalised. *)Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinletl=List.mapbeginfun(c,(ipato,ipats),cls)->(* TODO: move sigma as a side-effect *)(* spiwack: the [*p] variants are for printing *)letcp=cinletc=interp_destruction_argistglcinletipato=interp_intro_pattern_naming_optionistenvsigmaipatoinletipatsp=ipatsinletipats=interp_or_and_intro_pattern_optionistenvsigmaipatsinletcls=Option.map(interp_clauseistenvsigma)clsin((c,(ipato,ipats),cls),(cp,(ipato,ipatsp),cls))endlinletl,lp=List.splitlinletsigma,el=Option.fold_left_map(interp_open_constr_with_bindingsistenv)sigmaelinTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(name_atomic~env(TacInductionDestruct(isrec,ev,(lp,el)))(Tactics.induction_destructisrecev(l,el)))end(* Conversion *)|TacReduce(r,cl)->Proofview.Goal.enterbeginfungl->let(sigma,r_interp)=interp_red_exprist(pf_envgl)(projectgl)rinTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Tactics.reducer_interp(interp_clauseist(pf_envgl)(projectgl)cl))end|TacChange(check,None,c,cl)->(* spiwack: until the tactic is in the monad *)Proofview.Trace.name_tactic(fun()->Pp.str"<change>")beginProofview.Goal.enterbeginfungl->letis_onhyps=matchcl.onhypswith|None|Some[]->true|_->falseinletis_onconcl=matchcl.concl_occswith|AtLeastOneOccurrence|AllOccurrences|NoOccurrences->true|_->falseinletc_interppatvarsenvsigma=letlfun'=Id.Map.fold(funidclfun->Id.Map.addid(Value.of_constrc)lfun)patvarsist.lfuninletist={istwithlfun=lfun'}inifis_onhyps&&is_onconcltheninterp_typeistenvsigmacelseinterp_constristenvsigmacinTactics.change~checkNonec_interp(interp_clauseist(pf_envgl)(projectgl)cl)endend|TacChange(check,Someop,c,cl)->(* spiwack: until the tactic is in the monad *)Proofview.Trace.name_tactic(fun()->Pp.str"<change>")beginProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinletop=interp_typed_patternistenvsigmaopinletto_catch=functionNot_found->true|e->CErrors.is_anomalyeinletc_interppatvarsenvsigma=letlfun'=Id.Map.fold(funidclfun->Id.Map.addid(Value.of_constrc)lfun)patvarsist.lfuninletenv=ensure_freshnessenvinletist={istwithlfun=lfun'}intryinterp_constristenvsigmacwithewhento_catche(* Hack *)->user_err(strbrk"Failed to get enough information from the left-hand side to type the right-hand side.")inTactics.change~check(Someop)c_interp(interp_clauseistenvsigmacl)endend(* Equality and inversion *)|TacRewrite(ev,l,cl,by)->Proofview.Goal.enterbeginfungl->letl'=List.map(fun(b,m,(keep,c))->letfenvsigma=interp_open_constr_with_bindingsistenvsigmacin(b,m,keep,f))linletenv=Proofview.Goal.envglinletsigma=projectglinletcl=interp_clauseistenvsigmaclinname_atomic~env(TacRewrite(ev,l,cl,Option.mapignoreby))(Equality.general_multi_rewriteevl'cl(Option.map(funby->Tacticals.tclCOMPLETE(interp_tacticistby),Equality.Naive)by))end|TacInversion(DepInversion(k,c,ids),hyp)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinlet(sigma,c_interp)=matchcwith|None->sigma,None|Somec->let(sigma,c_interp)=interp_constristenvsigmacinsigma,Somec_interpinletdqhyps=interp_declared_or_quantified_hypothesisistenvsigmahypinletids_interp=interp_or_and_intro_pattern_optionistenvsigmaidsinTacticals.tclWITHHOLESfalse(name_atomic~env(TacInversion(DepInversion(k,c_interp,ids),dqhyps))(Inv.dinvkc_interpids_interpdqhyps))sigmaend|TacInversion(NonDepInversion(k,idl,ids),hyp)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinlethyps=interp_hyp_lististenvsigmaidlinletdqhyps=interp_declared_or_quantified_hypothesisistenvsigmahypinletids_interp=interp_or_and_intro_pattern_optionistenvsigmaidsinname_atomic~env(TacInversion(NonDepInversion(k,hyps,ids),dqhyps))(Inv.inv_clausekids_interphypsdqhyps)end|TacInversion(InversionUsing(c,idl),hyp)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinlet(sigma,c_interp)=interp_constristenvsigmacinletdqhyps=interp_declared_or_quantified_hypothesisistenvsigmahypinlethyps=interp_hyp_lististenvsigmaidlinTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(name_atomic~env(TacInversion(InversionUsing(c_interp,hyps),dqhyps))(Leminv.lemInv_clausedqhypsc_interphyps))end(* Initial call for interpretation *)letdefault_ist()=letextra=TacStore.setTacStore.emptyf_debug(get_debug())in{lfun=Id.Map.empty;poly=false;extra=extra}leteval_tactict=ifget_debug()<>DebugOffthenProofview.tclUNIT()>>=fun()->(* delay for [default_ist] *)Proofview.tclLIFT(db_initializetrue)<*>eval_tactic_ist(default_ist())telseProofview.tclUNIT()>>=fun()->(* delay for [default_ist] *)eval_tactic_ist(default_ist())tleteval_tactic_ististt=Proofview.tclLIFT(db_initializefalse)<*>eval_tactic_ististt(** FFI *)moduleValue=structincludeTaccoerce.Valueletof_closureisttac=letclosure=VFun(UnnamedAppl,extract_traceist,None,ist.lfun,[],tac)inof_tacvalueclosureletapply_exprfargs=letfoldarg(i,vars,lfun)=letid=Id.of_string("x"^string_of_inti)inletx=Reference(ArgVarCAst.(makeid))in(succi,x::vars,Id.Map.addidarglfun)inlet(_,args,lfun)=List.fold_rightfoldargs(0,[],Id.Map.empty)inletlfun=Id.Map.add(Id.of_string"F")flfuninletist={(default_ist())withlfun=lfun;}inist,CAst.make@@TacArg(TacCall(CAst.make(ArgVarCAst.(make@@Id.of_string"F"),args)))(** Apply toplevel tactic values *)letapply(f:value)(args:valuelist)=letist,tac=apply_exprfargsineval_tactic_ististtacletapply_val(f:value)(args:valuelist)=letist,tac=apply_exprfargsinval_interpisttacend(* globalization + interpretation *)letinterp_tac_genlfunavoid_idsdebugt=Proofview.tclProofInfo[@ocaml.warning"-3"]>>=fun(_name,poly)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletextra=TacStore.setTacStore.emptyf_debugdebuginletextra=TacStore.setextraf_avoid_idsavoid_idsinletist={lfun;poly;extra}inletltacvars=Id.Map.domainlfunineval_tactic_istist(intern_pure_tactic{(Genintern.empty_glob_signenv)withltacvars}t)endletinterpt=interp_tac_genId.Map.emptyId.Set.empty(get_debug())t(* MUST be marshallable! *)typeltac_expr={global:bool;ast:Tacexpr.raw_tactic_expr;}(* Used to hide interpretation for pretty-print, now just launch tactics *)(* [global] means that [t] should be internalized outside of goals. *)lethide_interp{global;ast}=lethide_interpenv=letist=Genintern.empty_glob_signenvinlette=intern_pure_tacticistastinlett=eval_tacticteintinifglobalthenProofview.tclENV>>=funenv->hide_interpenvelseProofview.Goal.enterbeginfungl->hide_interp(Proofview.Goal.envgl)endletComTactic.Interpreterhide_interp=ComTactic.register_tactic_interpreter"ltac1"hide_interp(***************************************************************************)(** Register standard arguments *)letregister_interp0witf=letopenFtactic.Notationsinletinterpistv=fistv>>=funv->Ftactic.return(Val.inject(val_tagwit)v)inGeninterp.register_interp0witinterpletdef_internistx=(ist,x)letdef_subst_x=xletdef_interpistx=Ftactic.returnxletdeclare_uniformt=Genintern.register_intern0tdef_intern;Genintern.register_subst0tdef_subst;register_interp0tdef_interplet()=declare_uniformwit_unitlet()=declare_uniformwit_intlet()=declare_uniformwit_natlet()=declare_uniformwit_boollet()=declare_uniformwit_stringletliftf=();funistx->Ftactic.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinFtactic.return(fistenvsigmax)endletliftsf=();funistx->Ftactic.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinlet(sigma,v)=fistenvsigmaxinProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(* FIXME once we don't need to catch side effects *)(Proofview.tclTHEN(Proofview.Unsafe.tclSETENV(Global.env()))(Ftactic.returnv))endletinterp_bindings'istbl=Ftactic.returnbeginfunenvsigma->interp_bindingsistenvsigmablendletinterp_constr_with_bindings'istc=Ftactic.returnbeginfunenvsigma->interp_constr_with_bindingsistenvsigmacendletinterp_open_constr_with_bindings'istc=Ftactic.returnbeginfunenvsigma->interp_open_constr_with_bindingsistenvsigmacendletinterp_destruction_arg'istc=Ftactic.enterbeginfungl->Ftactic.return(interp_destruction_argistglc)endletinterp_pre_identistenvsigmas=s|>Id.of_string|>interp_identistenvsigma|>Id.to_stringlet()=register_interp0wit_int_or_var(funistn->Ftactic.return(interp_int_or_varistn));register_interp0wit_nat_or_var(funistn->Ftactic.return(interp_int_or_varistn));register_interp0wit_smart_global(liftinterp_reference);register_interp0wit_ref(liftinterp_reference);register_interp0wit_pre_ident(liftinterp_pre_ident);register_interp0wit_ident(liftinterp_ident);register_interp0wit_hyp(liftinterp_hyp);register_interp0wit_intropattern(liftinterp_intro_pattern)[@warning"-3"];register_interp0wit_simple_intropattern(liftinterp_intro_pattern);register_interp0wit_clause_dft_concl(liftinterp_clause);register_interp0wit_constr(liftsinterp_constr);register_interp0wit_tacvalue(funistv->Ftactic.returnv);register_interp0wit_red_expr(liftsinterp_red_expr);register_interp0wit_quant_hyp(liftinterp_declared_or_quantified_hypothesis);register_interp0wit_open_constr(liftsinterp_open_constr);register_interp0wit_bindingsinterp_bindings';register_interp0wit_constr_with_bindingsinterp_constr_with_bindings';register_interp0wit_open_constr_with_bindingsinterp_open_constr_with_bindings';register_interp0wit_destruction_arginterp_destruction_arg';()let()=letinterpisttac=Ftactic.return(Value.of_closureisttac)inregister_interp0wit_tacticinterplet()=letinterpisttac=eval_tactic_ististtac>>=fun()->Ftactic.return()inregister_interp0wit_ltacinterplet()=register_interp0wit_uconstr(funistc->Ftactic.enterbeginfungl->Ftactic.return(interp_uconstrist(Proofview.Goal.envgl)(Tacmach.projectgl)c)end)(***************************************************************************)(* Other entry points *)letval_interpisttack=Ftactic.run(val_interpisttac)kletinterp_ltac_constristck=Ftactic.run(interp_ltac_constristc)kletinterp_redexpenvsigmar=letist=default_ist()inletgist=Genintern.empty_glob_signenvininterp_red_expristenvsigma(intern_red_exprgistr)(***************************************************************************)(* Backwarding recursive needs of tactic glob/interp/eval functions *)let_=leteval?loc~polyenvsigmatycontac=letlfun=GlobEnv.lfunenvinletextra=TacStore.setTacStore.emptyf_debug(get_debug())inletist={lfun;poly;extra;}inlettac=eval_tactic_ististtacin(* EJGA: We should also pass the proof name if desired, for now
poly seems like enough to get reasonable behavior in practice
*)letname=Id.of_string"ltac_gen"inletsigma,ty=matchtyconwith|Somety->sigma,ty|None->GlobEnv.new_type_evarenvsigma~src:(loc,Evar_kinds.InternalHole)inlet(c,sigma)=Proof.refine_by_tactic~name~poly(GlobEnv.renamed_envenv)sigmatytacinletj={Environ.uj_val=EConstr.of_constrc;uj_type=ty}in(j,sigma)inGlobEnv.register_constr_interp0wit_tacticevalletvernac_debugb=set_debug(ifbthenTactic_debug.DebugOn0elseTactic_debug.DebugOff)let()=letopenGoptionsindeclare_bool_option{optdepr=false;optkey=["Ltac";"Debug"];optread=(fun()->get_debug()!=Tactic_debug.DebugOff);optwrite=vernac_debug}let()=letopenGoptionsindeclare_bool_option{optdepr=false;optkey=["Ltac";"Backtrace"];optread=(fun()->!log_trace);optwrite=(funb->log_trace:=b)}let()=Hook.setVernacentries.interp_redexp_hookinterp_redexp