1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215(************************************************************************)(* * 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)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))(* 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_tactic(flush_ist_evars(projectgl)ist)t)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