12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198(************************************************************************)(* * 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_opsopenTacredopenCErrorsopenUtilopenNamesopenNameopsopenLibnamesopenTacmach.NewopenTactic_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.prtagletsafe_msgnls=Proofview.NonLogical.catch(Proofview.NonLogical.print_debug(s++fnl()))(fun_->Proofview.NonLogical.print_warning(str"bug in the debugger: an exception is raised while printing debug information"++fnl()))typevalue=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)vletlog_trace=reffalseletis_traced()=!log_trace||!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->[]|Somel->lelse[]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 *)letnew_trace=inner_trace@call_traceinletlocated_exc=(e,Exninfo.addinfoltac_trace_infonew_trace)infaillocated_excendletupdate_loclocuse_finer(e,infoase')=matchlocwith|Someloc->ifuse_finerthen(* ensure loc if there is none *)matchLoc.get_locinfowith|None->(e,Loc.add_locinfoloc)|_->(e,info)else(* override loc (because loc refers to inside of Ltac functions) *)(e,Loc.add_locinfoloc)|None->e'letcatch_error_with_trace_loclocuse_finercall_tracefx=tryfxwithewhenCErrors.noncriticale->lete=Exninfo.captureeinlete=update_loclocuse_finereincatching_errorcall_traceExninfo.iraiseeletcatch_error_loclocuse_finertac=Proofview.tclORELSEtac(funexn->let(e,info)=update_loclocuse_finerexninProofview.tclZERO~infoe)letwrap_errortack=ifis_traced()thenProofview.tclORELSEtackelsetacletwrap_error_loclocuse_finertack=ifis_traced()thenProofview.tclORELSEtackelsecatch_error_loclocuse_finertacletcatch_error_taccall_tracetac=wrap_errortac(catching_errorcall_trace(fun(e,info)->Proofview.tclZERO~infoe))letcatch_error_tac_loclocuse_finercall_tracetac=wrap_error_loclocuse_finertac(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]|Sometrace->(call::trace)else[]letpropagate_traceistlocidv=ifhas_typev(topwitwit_tacvalue)thenlettacv=to_tacvaluevinmatchtacvwith|VFun(appl,_,_,lfun,it,b)->lett=ifList.is_emptyitthenbelseCAst.make(TacFun(it,b))inlettrace=push_trace(loc,LtacVarCall(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'@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=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)lmaccu(***************************************************************************)(* Evaluation/interpretation *)letis_variableenvid=Id.List.memid(ids_of_named_context(Environ.named_contextenv))(* Debug reference *)letdebug=refDebugOff(* Sets the debugger mode *)letset_debugpos=debug:=pos(* Gives the state of debug *)letget_debug()=!debugletdebugging_stepistpp=matchcurr_debugistwith|DebugOnlev->safe_msgnl(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))(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))(make?locid)withNot_found->IntroNaming(IntroIdentifierid)letinterp_intro_pattern_naming_varlocistenvsigmaid=trytry_interp_ltac_var(coerce_to_intro_pattern_namingsigma)ist(Some(env,sigma))(make?locid)withNot_found->IntroIdentifieridletinterp_intist({loc;v=id}aslocid)=trytry_interp_ltac_varcoerce_to_intistNonelocidwithNot_found->user_err?loc~hdr:"interp_int"(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))(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))(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(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))(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}=letidents=add_identidvidentsinlettyped=add_constridvtypedinletuntyped=add_uconstridvuntypedin{idents;typed;untyped}inletempty={idents=Id.Map.empty;typed=Id.Map.empty;untyped=Id.Map.empty}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=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(term,vars))istinlet(evd,c)=catch_error_with_trace_locloctruetrace(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);(evd,c)letconstr_flags()={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_typeclasses=UseTC;solve_unification_constraints=true;fail_evar=false;expand_evars=true;program_mode=false;polymorphic=false;}letopen_constr_no_classes_flags()={use_typeclasses=NoUseTC;solve_unification_constraints=true;fail_evar=false;expand_evars=true;program_mode=false;polymorphic=false;}letpure_open_constr_flags={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. *)pattern_of_constrenvsigma(EConstr.Unsafe.to_constrc)(* 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(pattern_of_constrenvsigma(EConstr.to_constrsigmac))in(trytry_interp_ltac_varcoerce_eval_ref_or_constrist(Some(env,sigma))(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)->(trylet(sigma,ic)=fistenvsigmacinletctxt=try_interp_ltac_varcoerce_to_constr_contextist(Some(env,sigma))(make?locs)inletctxt=EConstr.Unsafe.to_constrctxtinletic=EConstr.Unsafe.to_constricinletc=subst_meta[Constr_matching.special_meta,ic]ctxtinTyping.solve_evarsenvsigma(EConstr.of_constrc)with|Not_found->user_err?loc~hdr:"interp_may_eval"(str"Unbound context identifier"++Id.prints++str"."))|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.New.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->let(sigma,pat)=interp_intro_pattern_actionistenvsigmapatinsigma,make?loc@@IntroActionpat|IntroNaming(IntroIdentifierid)->sigma,make?loc@@interp_intro_pattern_varlocistenvsigmaid|IntroNamingpat->sigma,make?loc@@IntroNaming(interp_intro_pattern_naminglocistenvsigmapat)|IntroForthcoming_asx->sigma,make?locx)andinterp_intro_pattern_naminglocistenvsigma=function|IntroFreshid->IntroFresh(interp_identistenvsigmaid)|IntroIdentifierid->interp_intro_pattern_naming_varlocistenvsigmaid|IntroAnonymousasx->xandinterp_intro_pattern_actionistenvsigma=function|IntroOrAndPatternl->let(sigma,l)=interp_or_and_intro_patternistenvsigmalinsigma,IntroOrAndPatternl|IntroInjectionl->letsigma,l=interp_intro_pattern_list_as_lististenvsigmalinsigma,IntroInjectionl|IntroApplyOn({loc;v=c},ipat)->letcenvsigma=interp_open_constristenvsigmacinletsigma,ipat=interp_intro_patternistenvsigmaipatinsigma,IntroApplyOn(make?locc,ipat)|IntroWildcard|IntroRewrite_asx->sigma,xandinterp_or_and_intro_patternistenvsigma=function|IntroAndPatternl->letsigma,l=List.fold_left_map(interp_intro_patternistenv)sigmalinsigma,IntroAndPatternl|IntroOrPatternll->letsigma,ll=List.fold_left_map(interp_intro_pattern_list_as_lististenv)sigmallinsigma,IntroOrPatternllandinterp_intro_pattern_list_as_lististenvsigma=function|[{loc;v=IntroNaming(IntroIdentifierid)}]asl->(trysigma,coerce_to_intro_pattern_list?locsigma(Id.Map.findidist.lfun)withNot_found|CannotCoerceTo_->List.fold_left_map(interp_intro_patternistenv)sigmal)|l->List.fold_left_map(interp_intro_patternistenv)sigmalletinterp_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->sigma,None|Some(ArgVar{loc;v=id})->(matchinterp_intro_pattern_varlocistenvsigmaidwith|IntroAction(IntroOrAndPatternl)->sigma,Some(make?locl)|_->user_err?loc(str"Cannot coerce to a disjunctive/conjunctive pattern."))|Some(ArgArg{loc;v=l})->letsigma,l=interp_or_and_intro_patternistenvsigmalinsigma,Some(make?locl)letinterp_intro_pattern_optionistenvsigma=function|None->sigma,None|Someipat->letsigma,ipat=interp_intro_patternistenvsigmaipatinsigma,Someipatletinterp_in_hyp_asistenvsigma(id,ipat)=letsigma,ipat=interp_intro_pattern_optionistenvsigmaipatinsigma,(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))(makeid)withNot_found->NamedHypidletinterp_declared_or_quantified_hypothesisistenvsigma=function|AnonHypn->AnonHypn|NamedHypid->trytry_interp_ltac_var(coerce_to_decl_or_quant_hypsigma)ist(Some(env,sigma))(makeid)withNot_found->NamedHypidletinterp_bindingistenvsigma{loc;v=(b,c)}=letsigma,c=interp_open_constristenvsigmacinsigma,(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(make?locid')else(keep,ElimOnConstrbeginfunenvsigma->try(sigma,(constr_of_idenvid',NoBindings))withNot_found->user_err?loc~hdr:"interp_destruction_arg"(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(make?locid)elseletc=(DAst.make?loc@@GVarid,Some(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)ctxt(* Reads a pattern by substituting vars of lfun *)letuse_types=falseleteval_patternlfunistenvsigma(bvars,(glob,_),patasc)=ifuse_typesthen(bvars,interp_typed_patternistenvsigmac)else(bvars,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~hdr:"read_match_goal_hyps"(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=beginfunenvsigma->let{closure;term}=cinletvars={ltac_constrs=closure.typed;ltac_uconstrs=closure.untyped;ltac_idents=closure.idents;ltac_genargs=Id.Map.empty;}inletflags={flagswithpolymorphic=ist.Geninterp.poly}inunderstand_ltacflagsenvsigmavarsexpected_typetermend(* 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_promptlevtaceval|_->value_interpist>>=funv->return(name_vfunapplv)andeval_tactic_ististtac:unitProofview.tactic=let(loc,tac2)=CAst.(tac.loc,tac.v)inmatchtac2with|TacAtomt->letcall=LtacAtomCalltinlettrace=push_trace(loc,call)istinProfile_ltac.do_profile"eval_tactic:2"trace(catch_error_tac_locloctruetrace(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.New.tclFAIL~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.New.tclPROGRESS(interp_tacticisttac)|TacShowHypstac->Proofview.V82.tacticbeginTacticals.tclSHOWHYPS(Proofview.V82.of_tactic(interp_tacticisttac))end|TacAbstract(t,ido)->letcall=LtacMLCalltacinlettrace=push_trace(None,call)istinProfile_ltac.do_profile"eval_tactic:TacAbstract"trace(catch_error_tactracebeginProofview.Goal.enterbeginfungl->Abstract.tclABSTRACT(Option.map(interp_identist(pf_envgl)(projectgl))ido)(interp_tacticistt)endend)|TacThen(t1,t)->Tacticals.New.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.New.tclTHENS(interp_tacticistt1)(List.map(interp_tacticist)tl)|TacThens3parts(t1,tf,t,tl)->Tacticals.New.tclTHENS3PARTS(interp_tacticistt1)(Array.map(interp_tacticist)tf)(interp_tacticistt)(Array.map(interp_tacticist)tl)|TacDo(n,tac)->Tacticals.New.tclDO(interp_int_or_varistn)(interp_tacticisttac)|TacTimeout(n,tac)->Tacticals.New.tclTIMEOUT(interp_int_or_varistn)(interp_tacticisttac)|TacTime(s,tac)->Tacticals.New.tclTIMEs(interp_tacticisttac)|TacTrytac->Tacticals.New.tclTRY(interp_tacticisttac)|TacRepeattac->Tacticals.New.tclREPEAT(interp_tacticisttac)|TacOr(tac1,tac2)->Tacticals.New.tclOR(interp_tacticisttac1)(interp_tacticisttac2)|TacOncetac->Tacticals.New.tclONCE(interp_tacticisttac)|TacExactlyOncetac->Tacticals.New.tclEXACTLY_ONCE(interp_tacticisttac)|TacIfThenCatch(t,tt,te)->Tacticals.New.tclIFCATCH(interp_tacticistt)(fun()->interp_tacticisttt)(fun()->interp_tacticistte)|TacOrelse(tac1,tac2)->Tacticals.New.tclORELSE(interp_tacticisttac1)(interp_tacticisttac2)|TacFirstl->Tacticals.New.tclFIRST(List.map(interp_tacticist)l)|TacSolvel->Tacticals.New.tclSOLVE(List.map(interp_tacticist)l)|TacCompletetac->Tacticals.New.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.New.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)0opnargsinProofview.Trace.name_tacticname(catch_error_tac_loclocfalsetrace(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_loclocistinProfile_ltac.do_profile"interp_ltac_reference"trace~count_call:false(catch_error_tac_loc(* loc for interpretation *)locfalsetrace(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)(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.New.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_trace[]}inProfile_ltac.do_profile"interp_app"trace~count_call:false(catch_error_tac_loclocfalsetrace(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.New.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;extra=TacStore.setist.extraf_trace[];}inlettac=name_if_globappl(eval_tactic_ististt)inProfile_ltac.do_profile"tactic_of_value"trace(catch_error_tac_loclocfalsetracetac)|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.New.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.New.tclZEROMSG~info(str"A fully applied tactic is expected.")elseifhas_typevle(topwitwit_tactic)thenlettac=out_gen(topwitwit_tactic)vleintactic_of_valueisttacelseletinfo=Exninfo.reify()inTacticals.New.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[]))incatch_error_tactrace(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.New.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=projectglinletsigma,l'=interp_intro_pattern_list_as_lististenvsigmalinTacticals.New.tclWITHHOLESev(name_atomic~env(TacIntroPattern(ev,l))(* spiwack: print uninterpreted, not sure if it is the
expected behaviour. *)(Tactics.intro_patternsevl'))sigmaend|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,(make?locf)))cbinletsigma,tac=matchclwith|[]->sigma,Tactics.apply_with_delayed_bindings_genaevl|cl->letsigma,cl=List.fold_left_map(interp_in_hyp_asistenv)sigmaclinsigma,List.fold_right(fun(id,ipat)->Tactics.apply_delayed_inaevidlipat)clTacticals.New.tclIDTACinTacticals.New.tclWITHHOLESevtacsigmaendend|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.New.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.New.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.New.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.New.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~flagsistenvsigmacinletsigma,ipat'=interp_intro_pattern_optionistenvsigmaipatinlettac=Option.map(Option.map(interp_tacticist))tinTacticals.New.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.New.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(makeIntroAnonymous)eqpatinletwith_eq=Some(true,id)inTactics.letin_tacwith_eqnac_interpNoneLocusops.nowhereinTacticals.New.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(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.New.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=projectglinletsigma,l=List.fold_left_mapbeginfunsigma(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=ipatsinletsigma,ipats=interp_or_and_intro_pattern_optionistenvsigmaipatsinletcls=Option.map(interp_clauseistenvsigma)clsinsigma,((c,(ipato,ipats),cls),(cp,(ipato,ipatsp),cls))endsigmalinletl,lp=List.splitlinletsigma,el=Option.fold_left_map(interp_open_constr_with_bindingsistenv)sigmaelinTacticals.New.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.New.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.New.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_hypothesisistenvsigmahypinletsigma,ids_interp=interp_or_and_intro_pattern_optionistenvsigmaidsinTacticals.New.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_hypothesisistenvsigmahypinletsigma,ids_interp=interp_or_and_intro_pattern_optionistenvsigmaidsinTacticals.New.tclWITHHOLESfalse(name_atomic~env(TacInversion(NonDepInversion(k,hyps,ids),dqhyps))(Inv.inv_clausekids_interphypsdqhyps))sigmaend|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.New.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=Proofview.tclUNIT()>>=fun()->(* delay for [default_ist] *)Proofview.tclLIFTdb_initialize<*>eval_tactic_ist(default_ist())tleteval_tactic_ististt=Proofview.tclLIFTdb_initialize<*>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(liftsinterp_intro_pattern)[@warning"-3"];register_interp0wit_simple_intropattern(liftsinterp_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.New.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