12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661(************************************************************************)(* * The Rocq Prover / The Rocq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* must be before open Libobject, otherwise Dyn is Libobject.Dyn *)moduleSynclassDyn=Dyn.Make()openPpopenUtilopenCAstopenCErrorsopenNamesopenLibnamesopenLibobjectopenNametabopenTac2expropenTac2printopenTac2intern(** Grammar entries *)modulePltac=structletltac2_expr=Procq.Entry.make"ltac2_expr"lettac2expr_in_env=Procq.Entry.make"tac2expr_in_env"letq_ident=Procq.Entry.make"q_ident"letq_bindings=Procq.Entry.make"q_bindings"letq_with_bindings=Procq.Entry.make"q_with_bindings"letq_intropattern=Procq.Entry.make"q_intropattern"letq_intropatterns=Procq.Entry.make"q_intropatterns"letq_destruction_arg=Procq.Entry.make"q_destruction_arg"letq_induction_clause=Procq.Entry.make"q_induction_clause"letq_conversion=Procq.Entry.make"q_conversion"letq_orient=Procq.Entry.make"q_orient"letq_rewriting=Procq.Entry.make"q_rewriting"letq_clause=Procq.Entry.make"q_clause"letq_dispatch=Procq.Entry.make"q_dispatch"letq_occurrences=Procq.Entry.make"q_occurrences"letq_reference=Procq.Entry.make"q_reference"letq_strategy_flag=Procq.Entry.make"q_strategy_flag"letq_constr_matching=Procq.Entry.make"q_constr_matching"letq_goal_matching=Procq.Entry.make"q_goal_matching"letq_hintdb=Procq.Entry.make"q_hintdb"letq_move_location=Procq.Entry.make"q_move_location"letq_pose=Procq.Entry.make"q_pose"letq_assert=Procq.Entry.make"q_assert"endlet()=letentries=[Procq.Entry.AnyPltac.ltac2_expr;]inProcq.register_grammars_by_name"ltac2"entries(** Tactic definition *)typetacdef={tacdef_local:bool;tacdef_mutable:bool;tacdef_expr:glb_tacexpr;tacdef_type:type_scheme;tacdef_deprecation:Deprecation.toption;}letdefine_tacdef((_,kn),def)=letdata={Tac2env.gdata_expr=def.tacdef_expr;gdata_type=def.tacdef_type;gdata_mutable=def.tacdef_mutable;gdata_deprecation=def.tacdef_deprecation;gdata_mutation_history=[];}inTac2env.define_globalkndataletpush_tacdefvisibility((sp,kn),def)=ifnotdef.tacdef_localthenTac2env.push_ltacvisibilitysp(TacConstantkn)letload_tacdefiobj=push_tacdef(Untili)obj;define_tacdefobjletopen_tacdefiobj=push_tacdef(Exactlyi)obj(* Not sure if it's correct that we don't "open", do Until 1 and
Exactly 1 have the same effect? *)letcache_tacdef((sp,kn),defasobj)=(* unconditional unlike push_tacdef *)Tac2env.push_ltac(Until1)sp(TacConstantkn);define_tacdefobjletsubst_tacdef(subst,def)=letexpr'=subst_exprsubstdef.tacdef_exprinlettype'=subst_type_schemesubstdef.tacdef_typeinifexpr'==def.tacdef_expr&&type'==def.tacdef_typethendefelse{defwithtacdef_expr=expr';tacdef_type=type'}letclassify_tacdefo=SubstituteletinTacDef:Id.t->tacdef->obj=declare_named_object{(default_object"TAC2-DEFINITION")withcache_function=cache_tacdef;load_function=load_tacdef;open_function=filtered_openopen_tacdef;subst_function=subst_tacdef;classify_function=classify_tacdef}(** Type definition *)typetypdef={typdef_local:bool;typdef_abstract:bool;typdef_expr:glb_quant_typedef;}letchange_kn_labelknid=letmp=KerName.modpathkninKerName.makempidletchange_sp_labelspid=let(dp,_)=Libnames.repr_pathspinLibnames.make_pathdpidletpush_typedef_contentsvisibilityspkn(_,def)=matchdefwith|GTydDef_->()|GTydAlg{galg_constructors=cstrs}->(* Register constructors *)letiter(user_warns,c,_)=letspc=change_sp_labelspcinletknc=change_kn_labelkncinTac2env.push_constructor?user_warnsvisibilityspckncinList.iteritercstrs|GTydRecfields->(* Register fields *)letiter(c,_,_)=letspc=change_sp_labelspcinletknc=change_kn_labelkncinTac2env.push_projectionvisibilityspckncinList.iteriterfields|GTydOpn->()letpush_typedefvisibilityspkndef=Tac2env.push_typevisibilityspkn;push_typedef_contentsvisibilityspkndefletnexti=letans=!iinlet()=incriinansletdefine_typedefkn(params,defasqdef)=matchdefwith|GTydDef_->Tac2env.define_typeknqdef|GTydAlg{galg_constructors=cstrs}->(* Define constructors *)letconstant=ref0inletnonconstant=ref0inletiter(_warn,c,args)=letknc=change_kn_labelkncinlettag=ifList.is_emptyargsthennextconstantelsenextnonconstantinletdata={Tac2env.cdata_prms=params;cdata_type=kn;cdata_args=args;cdata_indx=Sometag;}inTac2env.define_constructorkncdatainTac2env.define_typeknqdef;List.iteritercstrs|GTydRecfs->(* Define projections *)letiteri(id,mut,t)=letknp=change_kn_labelknidinletproj={Tac2env.pdata_prms=params;pdata_type=kn;pdata_ptyp=t;pdata_mutb=mut;pdata_indx=i;}inTac2env.define_projectionknpprojinTac2env.define_typeknqdef;List.iteriiterfs|GTydOpn->Tac2env.define_typeknqdefletperform_typdefvs((sp,kn),def)=letexpr=def.typdef_exprinletexpr=ifdef.typdef_abstractthenfstexpr,GTydDefNoneelseexprinlet()=ifnotdef.typdef_localthenpush_typedefvsspknexprindefine_typedefknexprletload_typdefiobj=perform_typdef(Untili)objletopen_typdefiobj=perform_typdef(Exactlyi)objletcache_typdef((sp,kn),def)=let()=push_typedef(Until1)spkndef.typdef_exprindefine_typedefkndef.typdef_exprletsubst_typdef(subst,def)=letexpr'=subst_quant_typedefsubstdef.typdef_exprinifexpr'==def.typdef_exprthendefelse{defwithtypdef_expr=expr'}letclassify_typdefo=SubstituteletinTypDef:Id.t->typdef->obj=declare_named_object{(default_object"TAC2-TYPE-DEFINITION")withcache_function=cache_typdef;load_function=load_typdef;open_function=filtered_openopen_typdef;subst_function=subst_typdef;classify_function=classify_typdef}(** Type extension *)typeextension_data={edata_warn:UserWarn.toption;edata_name:Id.t;edata_args:intglb_typexprlist;}typetypext={typext_local:bool;typext_prms:int;typext_type:type_constant;typext_expr:extension_datalist;}letpush_typextvisprefixdef=letiterdata=letspc=Libnames.add_path_suffixprefix.obj_pathdata.edata_nameinletknc=KerName.makeprefix.obj_mpdata.edata_nameinletuser_warns=data.edata_warninTac2env.push_constructor?user_warnsvisspckncinList.iteriterdef.typext_exprletdefine_typextmpdef=letiterdata=letknc=KerName.makempdata.edata_nameinletcdata={Tac2env.cdata_prms=def.typext_prms;cdata_type=def.typext_type;cdata_args=data.edata_args;cdata_indx=None;}inTac2env.define_constructorknccdatainList.iteriterdef.typext_exprletcache_typext(prefix,def)=let()=define_typextprefix.obj_mpdefinpush_typext(Until1)prefixdefletperform_typextvs(prefix,def)=let()=ifnotdef.typext_localthenpush_typextvsprefixdefindefine_typextprefix.obj_mpdefletload_typextiobj=perform_typext(Untili)objletopen_typextiobj=perform_typext(Exactlyi)objletsubst_typext(subst,e)=letopenMod_substinletsubst_datadata=letedata_args=List.Smart.map(fune->subst_typesubste)data.edata_argsinifedata_args==data.edata_argsthendataelse{datawithedata_args}inlettypext_type=subst_knsubste.typext_typeinlettypext_expr=List.Smart.mapsubst_datae.typext_expriniftypext_type==e.typext_type&&typext_expr==e.typext_exprtheneelse{ewithtypext_type;typext_expr}letclassify_typexto=SubstituteletinTypExt:typext->obj=declare_named_object_gen{(default_object"TAC2-TYPE-EXTENSION")withcache_function=cache_typext;load_function=load_typext;open_function=filtered_openopen_typext;subst_function=subst_typext;classify_function=classify_typext}(** Toplevel entries *)(** Mangle recursive tactics *)letinline_rec_tactictactics=letmap(id,e)=letmap_body({loc;v=id},e)=CAst.(make?loc@@CPatVar(Nameid)),einletbnd=List.mapmap_bodytacticsinletvar_of_id{loc;v=id}=letqid=qualid_of_ident?locidinCAst.make?loc@@CTacRef(RelIdqid)inletloc0=e.locinlete=CAst.make?loc:loc0@@CTacLet(true,bnd,var_of_idid)in(id,e)inList.mapmaptacticsletcheck_lowercase{loc;v=id}=ifTac2env.is_constructor(Libnames.qualid_of_identid)thenuser_err?loc(str"The identifier "++Id.printid++str" must start with a lowercase letter.")letcheck_uppercase{loc;v=id}=ifnot@@Tac2env.is_constructor(Libnames.qualid_of_identid)thenuser_err?loc(str"The identifier "++Id.printid++str" must start with an uppercase letter.")letpp_not_value_reason=function|MutString->str"(it contains a string literal, and strings are mutable)"|Application->str"(it contains an application)"|MutDefkn->str"(it contains mutable definition "++pr_tacrefId.Set.emptykn|MutCtorkn->str"(it contains a constructor of type "++pr_typrefkn++str" which has mutable fields)"|MutProjkn->str"(it contains a mutable projection from type "++pr_typrefkn++str")"|MaybeValButNotSupported->mt()letcheck_value?loce=matchcheck_valueewith|None->()|Somereason->letppreason=pp_not_value_reasonreasoninuser_err?loc(str"Tactic definition must be a syntactical value"++(ifismtppreasonthenmt()elsespc()++ppreason)++str"."++spc()++str"Consider using a thunk.")letcheck_ltac_exists{loc;v=id}=letkn=Lib.make_knidinletexists=trylet_=Tac2env.interp_globalknintruewithNot_found->falseinifexiststhenuser_err?loc(str"Tactic "++Names.Id.printid++str" already exists")letregister_ltac?deprecation?(local=false)?(mut=false)isrectactics=letmap({loc;v=na},e)=letid=matchnawith|Anonymous->user_err?loc(str"Tactic definition must have a name")|Nameid->idinlet()=check_lowercaseCAst.(make?locid)in(CAst.(make?locid),e)inlettactics=List.mapmaptacticsinlettactics=ifisrectheninline_rec_tactictacticselsetacticsinletmap(lid,({loc=eloc}ase))=let(e,t)=intern~strict:true[]einlet()=check_value?loc:eloceinlet()=check_ltac_existslidin(lid.v,e,t)inletdefs=List.mapmaptacticsinletiter(id,e,t)=letdef={tacdef_local=local;tacdef_mutable=mut;tacdef_expr=e;tacdef_type=t;tacdef_deprecation=deprecation;}inLib.add_leaf(inTacDefiddef)inList.iteriterdefsletqualid_to_identqid=ifqualid_is_identqidthenCAst.make?loc:qid.CAst.loc@@qualid_basenameqidelseuser_err?loc:qid.CAst.loc(str"Identifier expected")letregister_typedef?(local=false)?(abstract=false)isrectypes=letsame_name({v=id1},_)({v=id2},_)=Id.equalid1id2inlet()=matchList.duplicatessame_nametypeswith|[]->()|({loc;v=id},_)::_->user_err?loc(str"Multiple definition of the type name "++Id.printid)inlet()=letcheck_existing_type({v=id},_)=let(_,kn)=Lib.make_fonameidintrylet_=Tac2env.interp_typekninuser_err(str"Multiple definition of the type name "++Id.printid)withNot_found->()inList.itercheck_existing_typetypesinletcheck({loc;v=id},(params,def))=letsame_name{v=id1}{v=id2}=Id.equalid1id2inlet()=matchList.duplicatessame_nameparamswith|[]->()|{loc;v=id}::_->user_err?loc(str"The type parameter "++Id.printid++str" occurs several times")inmatchdefwith|CTydDef_->ifisrecthenuser_err?loc(str"The type abbreviation "++Id.printid++str" cannot be recursive")|CTydAlgcs->letsame_name(_,id1,_)(_,id2,_)=Id.equalid1.vid2.vinlet()=matchList.duplicatessame_namecswith|[]->()|(_,id,_)::_->user_err(str"Multiple definitions of the constructor "++Id.printid.v)inlet()=List.iter(fun(_,id,_)->check_uppercaseid)csinlet()=letcheck_existing_ctor(_,id,_)=let(_,kn)=Lib.make_fonameid.vintrylet_=Tac2env.interp_constructorkninuser_err(str"Constructor already defined in this module "++Id.printid.v)withNot_found->()inList.itercheck_existing_ctorcsin()|CTydRecps->letsame_name(id1,_,_)(id2,_,_)=Id.equalid1id2inlet()=matchList.duplicatessame_namepswith|[]->()|(id,_,_)::_->user_err(str"Multiple definitions of the projection "++Id.printid)in()|CTydOpn->ifisrecthenuser_err?loc(str"The open type declaration "++Id.printid++str" cannot be recursive");ifabstractthen(* Naive implementation allows to use and match on already
existing constructors but not declare new ones outside the
type's origin module. Not sure that's what we want so
forbid it for now. *)user_err?loc(str"Open types currently do not support #[abstract].")inlet()=List.iterchecktypesinletself=ifisrecthenletfoldaccu({v=id},(params,_))=Id.Map.addid(Lib.make_knid,List.lengthparams)accuinList.fold_leftfoldId.Map.emptytypeselseId.Map.emptyinletmap({v=id},def)=lettypdef={typdef_local=local;typdef_abstract=abstract;typdef_expr=intern_typedefselfdef;}in(id,typdef)inlettypes=List.mapmaptypesinletiter(id,def)=Lib.add_leaf(inTypDefiddef)inList.iteritertypesletregister_primitive?deprecation?(local=false)({loc;v=id}aslid)tml=let()=check_ltac_existslidinlett=intern_open_typetinlet()=trylet_=Tac2env.interp_primitivemlin()withNot_found->user_err?loc(str"Unregistered primitive "++quote(strml.mltac_plugin)++spc()++quote(strml.mltac_tactic))inlete=GTacPrmmlinletdef={tacdef_local=local;tacdef_mutable=false;tacdef_expr=e;tacdef_type=t;tacdef_deprecation=deprecation;}inLib.add_leaf(inTacDefiddef)letregister_open?(local=false)qid(params,def)=letkn=tryTac2env.locate_typeqidwithNot_found->user_err?loc:qid.CAst.loc(str"Unbound type "++pr_qualidqid)inlet(tparams,t)=Tac2env.interp_typekninlet()=matchtwith|GTydOpn->()|GTydAlg_|GTydRec_|GTydDef_->user_err?loc:qid.CAst.loc(str"Type "++pr_qualidqid++str" is not an open type")inlet()=ifnot(Int.equal(List.lengthparams)tparams)thenTac2intern.error_nparams_mismatch?loc:qid.CAst.loc(List.lengthparams)tparamsinmatchdefwith|CTydOpn->()|CTydAlgdef->let()=letsame_name(_,id1,_)(_,id2,_)=Id.equalid1.vid2.vinlet()=matchList.duplicatessame_namedefwith|[]->()|(_,id,_)::_->user_err(str"Multiple definitions of the constructor "++Id.printid.v)inletcheck_existing_ctor(_,id,_)=let(_,kn)=Lib.make_fonameid.vintrylet_=Tac2env.interp_constructorkninuser_err(str"Constructor already defined in this module "++Id.printid.v)withNot_found->()inlet()=List.itercheck_existing_ctordefin()inletintern_typet=lettpe=CTydDef(Somet)inlet(_,ans)=intern_typedefId.Map.empty(params,tpe)inmatchanswith|GTydDef(Somet)->t|_->assertfalseinletmap(atts,id,tpe)=let()=check_uppercaseidinletwarn=Attributes.parseAttributes.user_warnsattsinlettpe=List.mapintern_typetpein{edata_warn=warn;edata_name=id.v;edata_args=tpe}inletdef=List.mapmapdefinletdef={typext_local=local;typext_type=kn;typext_prms=tparams;typext_expr=def;}inLib.add_leaf(inTypExtdef)|CTydRec_|CTydDef_->user_err?loc:qid.CAst.loc(str"Extensions only accept inductive constructors")letregister_type?local?abstractisrectypes=matchtypeswith|[qid,true,def]->let()=ifisrecthenuser_err?loc:qid.CAst.loc(str"Extensions cannot be recursive.")inlet()=ifOption.defaultfalseabstractthenuser_err?loc:qid.loc(str"Extensions cannot be abstract.")inregister_open?localqiddef|_->letmap(qid,redef,def)=let()=ifredefthenuser_err?loc:qid.loc(str"Types can only be extended one by one")in(qualid_to_identqid,def)inlettypes=List.mapmaptypesinregister_typedef?local?abstractisrectypesletload_import_typei((sp,kn),orig)=letdef=Tac2env.interp_typeoriginpush_typedef_contents(Untili)sporigdefletopen_import_typei((sp,kn),orig)=letdef=Tac2env.interp_typeoriginpush_typedef_contents(Exactlyi)sporigdefletcache_import_typeo=load_import_type1oletinImportType=declare_named_object{(default_object"TAC2-IMPORT-TYPE")withcache_function=cache_import_type;load_function=load_import_type;open_function=filtered_openopen_import_type;subst_function=(fun(subst,kn)->Mod_subst.subst_knsubstkn);(* NB don't bother supporting Local as it doesn't seem useful *)classify_function=(fun_->Substitute);}(* TODO deprecate attr *)letimport_typeqidas_id=let()=ifLib.sections_are_opened()then(* if you want to implement it take care that the "orig" type isn't local to the section *)CErrors.user_errPp.(str"Ltac2 Import Type not supported in sections.")inmatchTac2env.locate_typeqidwith|exceptionNot_found->CErrors.user_err?loc:qid.locPp.(str"Unknown Ltac2 type "++pr_qualidqid++str".")|orig->letparams,_=Tac2env.interp_typeoriginletalias_def=GTypRef(Otherorig,List.initparams(funi->GTypVari))inLib.add_leaf(inTypDefas_id{typdef_local=false;typdef_abstract=false;typdef_expr=params,GTydDef(Somealias_def);});Lib.add_leaf(inImportTypeas_idorig)(** Parsing *)type'atoken=|TacTermofstring|TacNonTermofName.t*'atypesyntax_class_rule=|SyntaxRule:(raw_tacexpr,_,'a)Procq.Symbol.t*('a->raw_tacexpr)->syntax_class_rulemoduleTac2Custom=KerNametypeused_levels=Int.Set.tTac2Custom.Map.tletno_used_levels=Tac2Custom.Map.emptyletunion_used_levelsab=Tac2Custom.Map.union(fun_ab->Some(Int.Set.unionab))ab(* hardcoded syntactic classes, from ltac2 or further plugins *)type'glbsyntax_class_decl={intern_synclass:sexprlist->used_levels*'glb;interp_synclass:'glb->syntax_class_rule;}typesyntax_class=SynclassDyn.tmoduleSynclassInterpMap=SynclassDyn.Map(structtype'at='a->syntax_class_ruleend)letsyntax_class_interns:(sexprlist->used_levels*SynclassDyn.t)Id.Map.tref=refId.Map.emptyletsyntax_class_interps=refSynclassInterpMap.emptymoduleCustomV=structincludeTac2Customletis_var_=Noneletstage=Summary.Stage.Synterpletsummary_name="ltac2_customentrytab"endmoduleCustomTab=Nametab.EasyNoWarn(CustomV)()letltac2_custom_map:raw_tacexprProcq.Entry.tTac2Custom.Map.tProcq.GramState.field=Procq.GramState.field"ltac2_custom_map"letltac2_custom_entry:(Tac2Custom.t,raw_tacexpr)Procq.entry_command=Procq.create_entry_command"ltac2"{eext_fun=(funknestate->letmap=Option.defaultTac2Custom.Map.empty(Procq.GramState.getstateltac2_custom_map)inletmap=Tac2Custom.Map.addknemapinProcq.GramState.setstateltac2_custom_mapmap);eext_name=(funkn->"custom-ltac2:"^Tac2Custom.to_stringkn);eext_eq=Tac2Custom.equal;}letfind_custom_entrykn=Tac2Custom.Map.getkn@@Option.get@@Procq.GramState.get(Procq.gramstate())ltac2_custom_maplet()=Metasyntax.register_custom_grammar_for_print@@funname->matchCustomTab.locatenamewith|exceptionNot_found->None|name->Some[Any(find_custom_entryname)]letload_custom_entryi((sp,kn),local)=let()=CustomTab.push(Untili)spkninlet()=Procq.extend_entry_commandltac2_custom_entrykninlet()=assert(notlocal)in()letimport_custom_entryi((sp,kn),local)=let()=CustomTab.push(Exactlyi)spknin()letcache_custom_entryo=load_custom_entry1o;import_custom_entry1oletinCustomEntry:Id.t->bool->Libobject.obj=declare_named_object{(default_object"Ltac2 custom entry")withobject_stage=Synterp;cache_function=cache_custom_entry;load_function=load_custom_entry;open_function=filtered_openimport_custom_entry;subst_function=(fun(_,x)->x);classify_function=(funlocal->iflocalthenDisposeelseSubstitute);}letcheck_custom_entry_nameid=(* XXX allow it anyway? the name can be accessed by qualifying it *)ifId.Map.memid!syntax_class_internsthenCErrors.user_errPp.(str"Cannot declare "++Id.printid++str" as a ltac2 custom entry:"++spc()++str"that name is already used for a builtin syntactic class.")elseifCustomTab.exists(Lib.make_pathid)thenCErrors.user_errPp.(str"Ltac2 custom entry "++Id.printid++str" already exists.")letregister_custom_entryname=letname=name.CAst.vincheck_custom_entry_namename;(* not yet implemented: module local custom entries
NB: will need checks that exported notations don't rely on the local entries *)letlocal=falseinLib.add_leaf(inCustomEntrynamelocal)letregister_syntax_classid(s:_syntax_class_decl)=assert(not(Id.Map.memid!syntax_class_interns));lettag=SynclassDyn.create(Id.to_stringid)inletinternargs=letused,data=s.intern_synclassargsinused,SynclassDyn.Dyn(tag,data)insyntax_class_interns:=Id.Map.addidintern!syntax_class_interns;syntax_class_interps:=SynclassInterpMap.addtags.interp_synclass!syntax_class_interpsletlevel_namelev=string_of_intlevletterminal_synclass_tag:stringSynclassDyn.tag=SynclassDyn.create"<terminal>"letinterp_terminalstr:syntax_class_rule=letv_unit=CAst.make@@CTacCst(AbsKn(Tuple0))inSyntaxRule(Procq.Symbol.token(Tok.PIDENT(Somestr)),(fun_->v_unit))let()=syntax_class_interps:=SynclassInterpMap.addterminal_synclass_taginterp_terminal!syntax_class_interpstypecustom_synclass_data={custom_synclass_name:Tac2Custom.t;custom_synclass_level:intoption;}letinterp_custom_entrydata:syntax_class_rule=letename=data.custom_synclass_nameinletentry=find_custom_entryenameinmatchdata.custom_synclass_levelwith|None->SyntaxRule(Procq.Symbol.ntermentry,(funexpr->expr))|Somelev->SyntaxRule(Procq.Symbol.ntermlentry(level_namelev),(funexpr->expr))letcustom_synclass_tag:custom_synclass_dataSynclassDyn.tag=SynclassDyn.create"<custom>"let()=syntax_class_interps:=SynclassInterpMap.addcustom_synclass_taginterp_custom_entry!syntax_class_interpsletintern_custom_entry?locqidenameargs:used_levels*custom_synclass_data=letlev=matchargswith|[]->None|[SexprInt{CAst.v=lev}]->Somelev|_::_->CErrors.user_err?locPp.(str"Invalid arguments for ltac2 custom entry "++pr_qualidqid++str".")inletused=matchlevwith|None->no_used_levels|Somelev->Tac2Custom.Map.singletonename(Int.Set.singletonlev)inused,{custom_synclass_name=ename;custom_synclass_level=lev;}letintern_syntactic_class?locqidargs=letis_class=ifqualid_is_identqidthenId.Map.find_opt(qualid_basenameqid)!syntax_class_internselseNoneinmatchis_classwith|Someintern->internargs|None->matchCustomTab.locateqidwith|kn->letused,data=intern_custom_entry?locqidknargsinused,SynclassDyn.Dyn(custom_synclass_tag,data)|exceptionNot_found->CErrors.user_err?loc(str"Unknown syntactic class"++spc()++pr_qualidqid)moduleParseToken=structletloc_of_token=function|SexprStr{loc}->loc|SexprInt{loc}->loc|SexprRec(loc,_,_)->Somelocletintern_syntax_class=function|SexprRec(_,{loc;v=Someid},toks)->intern_syntactic_classidtoks|SexprStr{v=str}->no_used_levels,SynclassDyn.Dyn(terminal_synclass_tag,str)|tok->letloc=loc_of_tokentokinCErrors.user_err?loc(str"Invalid parsing token")letcheck_namena=matchna.CAst.vwith|None->Anonymous|Someid->letid=ifqualid_is_identidthenqualid_basenameidelseCErrors.user_err?loc:id.locPp.(str"Must be an identifier.")inlet()=check_lowercase(CAst.make?loc:na.CAst.locid)inNameidletparse_token=function|SexprStr{v=s}->no_used_levels,TacTerms|SexprRec(_,na,[tok])->letna=check_namenainletused,syntax_class=intern_syntax_classtokinused,TacNonTerm(na,syntax_class)|tok->letloc=loc_of_tokentokinCErrors.user_err?loc(str"Invalid parsing token")letname_of_token=function|SexprStr_->Anonymous|SexprRec(_,na,_)->check_namena|tok->letloc=loc_of_tokentokinCErrors.user_err?loc(str"Invalid parsing token")letrecprint_syntax_class=function|SexprStrs->strs.CAst.v|SexprInti->inti.CAst.v|SexprRec(_,{v=na},[])->Option.catapr_qualid(str"_")na|SexprRec(_,{v=na},e)->Option.catapr_qualid(str"_")na++str"("++pr_sequenceprint_syntax_classe++str")"letprint_token=function|SexprStr{v=s}->quote(strs)|SexprRec(_,{v=na},[tok])->print_syntax_classtok|_->assertfalseendletintern_syntax_class=ParseToken.intern_syntax_classtypesynext={synext_kn:KerName.t;(* for printing, XXX print the internalized version? *)synext_raw:sexprlist;synext_used:used_levels;synext_tok:SynclassDyn.ttokenlist;synext_entry:Tac2Custom.toption*int;synext_loc:bool;synext_depr:Deprecation.toption;}typekrule=|KRule:(raw_tacexpr,_,'act,Loc.t->raw_tacexpr)Procq.Rule.t*((Loc.t->(Name.t*raw_tacexpr)list->raw_tacexpr)->'act)->kruleletinterp_syntax_class(SynclassDyn.Dyn(tag,data))=letinterp=SynclassInterpMap.findtag!syntax_class_interpsininterpdataletrecget_rule(tok:SynclassDyn.ttokenlist):krule=matchtokwith|[]->KRule(Procq.Rule.stop,funkloc->kloc[])|TacNonTerm(na,v)::tok->letSyntaxRule(syntax_class,inj)=interp_syntax_classvinletKRule(rule,act)=get_ruletokinletrule=Procq.Rule.nextrulesyntax_classinletactke=act(funlocacc->kloc((na,inje)::acc))inKRule(rule,act)|TacTermt::tok->letKRule(rule,act)=get_ruletokinletrule=Procq.(Rule.nextrule(Symbol.token(CLexer.terminalt)))inletactk_=actkinKRule(rule,act)letdeprecated_ltac2_notation=Deprecation.create_warning~object_name:"Ltac2 notation"~warning_name_if_no_since:"deprecated-ltac2-notation"(fun(toks:sexprlist)->pr_sequenceParseToken.print_tokentoks)letltac2_levels=Procq.GramState.field"ltac2_levels"(* XXX optional lev and do reusefirst like in egramrocq? *)letfresh_levelstentrylev=matchentrywith|None->st,None|Someentry->letall_levels=Option.defaultTac2Custom.Map.empty@@Procq.GramState.getstltac2_levelsinletentry_levels=Option.defaultInt.Set.empty@@Tac2Custom.Map.find_optentryall_levelsinletlast_before=Int.Set.find_first_opt(funlev'->lev'>=lev)entry_levelsinifOption.equalInt.equallast_before(Somelev)thenst,Noneelseletpos=matchlast_beforewith|None->Gramlib.Gramext.First|Somelev'->Gramlib.Gramext.After(level_namelev')inletentry_levels=Int.Set.addleventry_levelsinletall_levels=Tac2Custom.Map.addentryentry_levelsall_levelsinletst=Procq.GramState.setstltac2_levelsall_levelsinst,Someposletcheck_levelsstused_levels=letall_levels=Option.defaultTac2Custom.Map.empty@@Procq.GramState.getstltac2_levelsinletiterknused=letknown=Option.defaultInt.Set.empty(Tac2Custom.Map.find_optknall_levels)inletmissing=Int.Set.diffusedknowninifnot(Int.Set.is_emptymissing)thenCErrors.user_errPp.(str"Unknown "++str(String.plural(Int.Set.cardinalmissing)"level")++str" for ltac2 custom entry "++CustomTab.prkn)inTac2Custom.Map.iteriterused_levelsletperform_notationsynst=lettok=syn.synext_tokinletused=syn.synext_usedinletKRule(rule,act)=get_ruletokinletmklocargs=let()=matchsyn.synext_deprwith|None->()|Somedepr->deprecated_ltac2_notation~loc(syn.synext_raw,depr)inletmap(na,e)=((CAst.make?loc:e.locna),e)inletbnd=List.mapmapargsinCAst.make~loc@@CTacSyn(bnd,syn.synext_kn)inletrule=Procq.Production.makerule(actmk)inletentry,lev=syn.synext_entryinletst,fresh=fresh_levelstentrylevinlet()=check_levelsstusedinletpos=Some(level_namelev)inletrule=matchfreshwith|None->Procq.Reuse(pos,[rule])|Somepos'->(* BothA means we can have SELF on both the left and right of a rule. *)Procq.Fresh(pos',[pos,SomeBothA,[rule]])inletentry=matchentrywith|None->Pltac.ltac2_expr|Someentry->find_custom_entryentryin[Procq.ExtendRule(entry,rule)],stletltac2_notation=Procq.create_grammar_command"ltac2-notation"{gext_fun=perform_notation;gext_eq=(==)(* FIXME *)}letcache_synextsyn=Procq.extend_grammar_command~ignore_kw:falseltac2_notationsynletsubst_synext(subst,syn)=letkn=Mod_subst.subst_knsubstsyn.synext_kninifkn==syn.synext_knthensynelse{synwithsynext_kn=kn}letclassify_synexto=ifo.synext_locthenDisposeelseSubstituteletltac2_notation_cat=Libobject.create_category"ltac2.notations"letinTac2Notation:synext->obj=declare_object{(default_object"TAC2-NOTATION")withobject_stage=Summary.Stage.Synterp;cache_function=cache_synext;open_function=simple_open~cat:ltac2_notation_catcache_synext;subst_function=subst_synext;classify_function=classify_synext}letcache_synext_interp(local,kn,tac)=Tac2env.define_notationkntacletsubst_notation_datasubst=function|Tac2env.UntypedNotabodyasn->letbody'=Tac2intern.subst_rawexprsubstbodyinifbody'==bodythennelseUntypedNotabody'|TypedNota{nota_prms=prms;nota_argtys=argtys;nota_ty=ty;nota_body=body}asn->letbody'=Tac2intern.subst_exprsubstbodyinletargtys'=Id.Map.Smart.map(subst_typesubst)argtysinletty'=subst_typesubsttyinifbody'==body&&argtys'==argtys&&ty'==tythennelseTypedNota{nota_body=body';nota_argtys=argtys';nota_ty=ty';nota_prms=prms}letsubst_synext_interp(subst,(local,kn,tacaso))=lettac'=subst_notation_datasubsttacinletkn'=Mod_subst.subst_knsubstkninifkn'==kn&&tac'==tacthenoelse(local,kn',tac')letclassify_synext_interp(local,_,_)=iflocalthenDisposeelseSubstituteletinTac2NotationInterp:(bool*KerName.t*Tac2env.notation_data)->obj=declare_object{(default_object"TAC2-NOTATION-INTERP")withcache_function=cache_synext_interp;open_function=simple_open~cat:ltac2_notation_catcache_synext_interp;subst_function=subst_synext_interp;classify_function=classify_synext_interp}typeabbreviation={abbr_body:raw_tacexpr;abbr_depr:Deprecation.toption;}letperform_abbreviationvisibility((sp,kn),abbr)=let()=Tac2env.push_ltacvisibilitysp(TacAliaskn)inTac2env.define_alias?deprecation:abbr.abbr_deprknabbr.abbr_bodyletload_abbreviationiobj=perform_abbreviation(Untili)objletopen_abbreviationiobj=perform_abbreviation(Exactlyi)objletcache_abbreviation((sp,kn),abbr)=let()=Tac2env.push_ltac(Until1)sp(TacAliaskn)inTac2env.define_alias?deprecation:abbr.abbr_deprknabbr.abbr_bodyletsubst_abbreviation(subst,abbr)=letbody'=subst_rawexprsubstabbr.abbr_bodyinifbody'==abbr.abbr_bodythenabbrelse{abbr_body=body';abbr_depr=abbr.abbr_depr}letclassify_abbreviationo=SubstituteletinTac2Abbreviation:Id.t->abbreviation->obj=declare_named_object{(default_object"TAC2-ABBREVIATION")withcache_function=cache_abbreviation;load_function=load_abbreviation;open_function=filtered_open~cat:ltac2_notation_catopen_abbreviation;subst_function=subst_abbreviation;classify_function=classify_abbreviation}letrecstring_of_syntax_class=function|SexprStrs->Printf.sprintf"str(%s)"s.CAst.v|SexprInti->Printf.sprintf"int(%i)"i.CAst.v|SexprRec(_,{v=na},[])->Option.catastring_of_qualid"_"na|SexprRec(_,{v=na},e)->Printf.sprintf"%s(%s)"(Option.catastring_of_qualid"_"na)(String.concat" "(List.mapstring_of_syntax_classe))letstring_of_token=function|SexprStr{v=s}->Printf.sprintf"str(%s)"s|SexprRec(_,{v=na},[tok])->string_of_syntax_classtok|_->assertfalseletmake_fresh_keytokens=letprods=String.concat"_"(List.mapstring_of_tokentokens)in(* We embed the hash of the kernel name in the label so that the identifier
should be mostly unique. This ensures that including two modules
together won't confuse the corresponding labels. *)lethash=(ModPath.hash(Lib.current_mp()))land0x7FFFFFFFinletlbl=Id.of_string_soft(Printf.sprintf"%s_%08X"prodshash)inLib.make_knlbltypenotation_interpretation_data=|AbbreviationofId.t*Deprecation.toption*raw_tacexpr|Synextofbool*KerName.t*Id.Set.t*raw_tacexprtypenotation_target=qualidoption*intoptionletpr_register_notationtkn(entry,lev)body=letpptarget=matchentry,levwith|None,None->mt()|None,Somelev->spc()++str": "++intlev|Someentry,None->spc()++str": "++pr_qualidentry|Someentry,Somelev->spc()++str": "++pr_qualidentry++str"("++intlev++str")"inprlist_with_sepspcTac2print.pr_syntax_classtkn++pptarget++spc()++hov2(str":= "++Tac2print.pr_rawexpr_genE5~avoid:Id.Set.emptybody)letpr_register_abbreviationidbody=Id.printid.CAst.v++hov2(str":= "++Tac2print.pr_rawexpr_genE5~avoid:Id.Set.emptybody)letregister_abbreviationattsidbody=letdeprecation=Attributes.(parsedeprecation)attsinlet()=check_lowercaseidinAbbreviation(id.CAst.v,deprecation,body)letwarn_deprecated_notation_for_abbreviation=CWarnings.create~name:"ltac2-notation-for-abbreviation"~category:Deprecation.Version.v9_2(fun()->strbrk"Use of \"Ltac2 Notation\" keyword for abbreviations is deprecated, use \"Ltac2 Abbreviation\" instead.")lettactic_qualid=qualid_of_ident(Id.of_string"tactic")letregister_notationattstkn(entry,lev)body=matchtkn,entry,levwith|[SexprRec(_,{loc;v=Someid},[])],None,None->warn_deprecated_notation_for_abbreviation();letid=ifqualid_is_identidthenqualid_basenameidelseCErrors.user_err?loc:id.locPp.(str"Must be an identifier.")inregister_abbreviationattsCAst.(make?locid)body|_->letdeprecation,local=Attributes.(parseNotations.(deprecation++locality))attsinletlocal=Option.defaultfalselocalin(* Check that the tokens make sense *)letentries=List.mapParseToken.name_of_tokentkninletfoldaccutok=matchtokwith|Nameid->Id.Set.addidaccu|Anonymous->accuinletids=List.fold_leftfoldId.Set.emptyentriesinletentry=matchentrywith|Someentry->ifqualid_eqentrytactic_qualidthenNoneelsebegintrySome(CustomTab.locateentry)withNot_found->CErrors.user_errPp.(str"Unknown entry "++pr_qualidentry++str".")end|None->Nonein(* Globalize so that names are absolute *)letlev=ifOption.has_someentrythenletlev=matchlevwith|Somelev->lev|None->user_err(str"Custom entry level must be explicit.")inlet()=iflev<0thenuser_err(str"Custom entry levels must be nonnegative.")inlevelsematchlevwith|Somen->let()=ifn<0||n>6thenuser_err(str"Notation levels must range between 0 and 6")inn|None->(* autodetect level *)beginmatchtknwith|SexprStrs::_whenNames.Id.is_valids.CAst.v->1|_->5endinletkey=make_fresh_keytkninlettokens=List.rev_mapParseToken.parse_tokentkninletused,tokens=List.splittokensinletused=List.fold_leftunion_used_levelsno_used_levelsusedinletext={synext_kn=key;synext_raw=tkn;synext_used=used;synext_tok=tokens;synext_entry=(entry,lev);synext_loc=local;synext_depr=deprecation;}inLib.add_leaf(inTac2Notationext);Synext(local,key,ids,body)letregister_notation_interpretation=function|Abbreviation(id,deprecation,body)->letbody=Tac2intern.globalizeId.Set.emptybodyinletabbr={abbr_body=body;abbr_depr=deprecation}inLib.add_leaf(inTac2Abbreviationidabbr)|Synext(local,kn,ids,body)->letdata=intern_notation_dataidsbodyinLib.add_leaf(inTac2NotationInterp(local,kn,data))typeredefinition={redef_local:Libobject.locality;redef_kn:ltac_constant;redef_body:glb_tacexpr;redef_old:Id.toption;}letperform_redefinition(prefix,redef)=letkn=redef.redef_kninletdata=Tac2env.interp_globalkninletbody=matchredef.redef_oldwith|None->redef.redef_body|Someid->(* Rebind the old value with a let-binding *)GTacLet(false,[Nameid,data.Tac2env.gdata_expr],redef.redef_body)inlethistory=ifOption.has_someredef.redef_oldthendata.gdata_mutation_historyelse[]inletdata={datawithgdata_expr=body;gdata_mutation_history=prefix.Libobject.obj_mp::history;}inTac2env.define_globalkndataletload_redefinition_(_,redefaso)=matchredef.redef_localwith|Local->assertfalse|Export->()|SuperGlobal->perform_redefinitionoletopen_redefinition(_,redefaso)=matchredef.redef_localwith|Local->assertfalse|Export->perform_redefinitiono|SuperGlobal->()letsubst_redefinition(subst,redef)=letkn=Mod_subst.subst_knsubstredef.redef_kninletbody=Tac2intern.subst_exprsubstredef.redef_bodyinifkn==redef.redef_kn&&body==redef.redef_bodythenredefelse{redef_local=redef.redef_local;redef_kn=kn;redef_body=body;redef_old=redef.redef_old;}letclassify_redefinitiono=matcho.redef_localwith|Local->Dispose|Export|SuperGlobal->SubstituteletinTac2Redefinition:redefinition->obj=declare_named_object_gen{(default_object"TAC2-REDEFINITION")withcache_function=perform_redefinition;load_function=load_redefinition;open_function=simple_openopen_redefinition;subst_function=subst_redefinition;classify_function=classify_redefinition;}letregister_redefinition~localqidold({loc=eloc}ase)=letlocal=matchlocalwith|None->ifLib.sections_are_opened()thenLocalelseExport|Somelocal->Locality.check_locality_nodischargeLocal;localinletkn=tryTac2env.locate_ltacqidwithNot_found->user_err?loc:qid.CAst.loc(str"Unknown tactic "++pr_qualidqid)inletkn=matchknwith|TacConstantkn->kn|TacAlias_->user_err?loc:qid.CAst.loc(str"Cannot redefine syntactic abbreviations")inletdata=Tac2env.interp_globalkninlet()=ifnot(data.Tac2env.gdata_mutable)thenuser_err?loc:qid.CAst.loc(str"The tactic "++pr_qualidqid++str" is not declared as mutable")inletctx=matcholdwith|None->[]|Some{CAst.v=id}->[id,data.Tac2env.gdata_type]inlet(e,t)=intern~strict:truectxeinlet()=check_value?loc:eloceinlet()=ifnot(Tac2intern.check_subtypetdata.Tac2env.gdata_type)thenletname=int_name()inuser_err?loc:qid.CAst.loc(str"Type "++pr_glbtypename(sndt)++str" is not a subtype of "++pr_glbtypename(snddata.Tac2env.gdata_type))inletold=Option.map(fun{CAst.v=id}->id)oldinletdef={redef_local=local;redef_kn=kn;redef_body=e;redef_old=old;}inLib.add_leaf(inTac2Redefinitiondef)letperform_eval~pstatee=letenv=Global.env()inlet(e,ty)=Tac2intern.intern~strict:false[]einletv=Tac2interp.interpTac2interp.empty_environmenteinletproof=matchpstatewith|None->letsigma=Evd.from_envenvinletname=Id.of_string"ltac2"inProof.start~name~poly:PolyFlags.defaultsigma[]|Somepstate->Declare.Proof.getpstateinlet(proof,_,ans)=Proof.run_tactic(Global.env())vproofinlet{Proof.sigma}=Proof.dataproofinletname=int_name()inFeedback.msg_notice(str"- : "++pr_glbtypename(sndty)++spc()++str"="++spc()++Tac2print.pr_valexprenvsigmaans(sndty))(** Toplevel entries *)letwarn_modtype=CWarnings.create~name:"ltac2-in-modtype"~category:CWarnings.CoreCategories.ltac2~default:AsErrorPp.(funwhat->strbrk"Ltac2 "++strwhat++strbrk" should not be defined inside module types: functor application to arguments of this module type will be unchecked")letcheck_modtypewhat=ifLib.is_modtype()thenwarn_modtypewhatletabstract_att=Attributes.bool_attribute~name:"abstract"letregister_structattsstr=matchstrwith|StrVal(mut,isrec,e)->check_modtype"definitions";letdeprecation,local=Attributes.(parseNotations.(deprecation++locality))attsinregister_ltac?deprecation?local~mutisrece|StrTyp(isrec,t)->check_modtype"types";letlocal,abstract=Attributes.(parseNotations.(locality++abstract_att))attsinregister_type?local?abstractisrect|StrPrm(id,t,ml)->check_modtype"externals";letdeprecation,local=Attributes.(parseNotations.(deprecation++locality))attsinregister_primitive?deprecation?localidtml|StrMut(qid,old,e)->letlocal=Attributes.(parseexplicit_hint_locality)attsinregister_redefinition~localqidolde(** Toplevel exception *)let{Goptions.get=compact_bt}=Goptions.declare_bool_option_and_ref~key:["Ltac2";"Backtrace";"Compact"]~value:true()letpr_frame=function|FrAnone->ifcompact_bt()thenstr"Call <fun>"elsestr"Call {"++pr_glbexpr~avoid:Id.Set.emptye++str"}"|FrLtackn->str"Call "++pr_tacrefId.Set.emptykn|FrPrimml->str"Prim <"++strml.mltac_plugin++str":"++strml.mltac_tactic++str">"|FrExtn(tag,arg)->ifcompact_bt()thenfmt"Extn <%s>"(Tac2dyn.Arg.reprtag)elseletobj=Tac2env.interp_ml_objecttaginletenv=Global.env()inletsigma=Evd.from_envenvinstr"Extn "++str(Tac2dyn.Arg.reprtag)++str":"++spc()++obj.Tac2env.ml_printenvsigmaargletprint_raw_errorknargs=lett_exn=KerName.makeTac2env.rocq_prefix(Id.of_string"exn")inletv=Tac2ffi.of_open(kn,args)inlett=GTypRef(Othert_exn,[])inletc=Tac2print.pr_valexpr(Global.env())Evd.emptyvtinhov0(str"Uncaught Ltac2 exception:"++spc()++hov0c)letprint_errorknargs=letenv=Global.env()inletsigma=Evd.from_envenvinletuser_print=KerName.makeTac2quote.Refs.control_prefix(Id.of_string"print_exn")inletuser_print=Tac2interp.eval_globaluser_printinletuser_print=Tac2ffi.(to_fun1of_exn(to_optionto_pp))user_printinletuser_print()=letres,_,_,_,_=Proofview.apply~name:(Id.of_string_soft"ltac2 error printing")~poly:PolyFlags.defaultenv(user_print(Tac2interp.LtacError(kn,args),Exninfo.null))(snd@@Proofview.initsigma[])inresinmatchuser_print()with|Somemsg->msg|None->print_raw_errorknargs|exceptionewhenCErrors.noncriticale->lete=Exninfo.captureeinletppe=matchewith|Tac2interp.LtacError(kn',args'),_info->(* don't use iprint: high risk of looping *)(* XXX print the info? currently CErrors.print_extra is not exposed *)print_raw_errorkn'args'|_->CErrors.iprinteinprint_raw_errorknargs++fnl()++hov2(str"Custom Ltac2 printer failed:"++spc()++ppe)let()=register_handlerbeginfunction|Tac2interp.LtacError(kn,args)->Some(print_errorknargs)|_->Noneendlet()=CErrors.register_additional_error_infobeginfuninfo->if!Tac2bt.print_ltac2_backtracethenletbt=Exninfo.getinfoTac2bt.backtraceinmatchbtwith|None->None|Somebt->letbt=List.revbtinletbt=str"Backtrace:"++fnl()++prlist_with_sepfnlpr_framebt++fnl()inSomebtelseNoneend(** Printing *)letprint_constant~print_defqid?infodata=lete=data.Tac2env.gdata_exprinlet(_,t)=data.Tac2env.gdata_typeinletismut=ifdata.gdata_mutablethenspc()++str"(* mutable *)"elsemt()inlethistory=ifnotprint_defthenmt()elsematchdata.gdata_mutation_historywith|[]->mt()|mods->letpr_onemp=letqid=tryNametab.shortest_qualid_of_modulempwithNot_found->tryNametab.shortest_qualid_of_dir(DirOpenModulemp)withNot_found->Nametab.shortest_qualid_of_dir(DirOpenModtypemp)inpr_qualidqidinletredef=prlist_with_sepfnlpr_onemodsinfnl()++str"Redefined by:"++fnl()++redefinletname=int_name()inletdef=ifprint_defthenfnl()++hov2(pr_qualidqid++spc()++str":="++spc()++pr_glbexpr~avoid:Id.Set.emptye)elsemt()inletinfo=matchinfowith|None->mt()|Someinfo->fnl()++fnl()++hov2(str"Compiled as"++spc()++strinfo.Tac2env.source)inhov0(hov2(pr_qualidqid++spc()++str":"++spc()++pr_glbtypenamet++ismut)++def++info++history)letprint_type~print_defqidkn=letnparams,data=Tac2env.interp_typekninletname=int_name()inletparams=List.initnparams(funi->GTypVari)inletty=matchparamswith|[]->pr_qualidqid|[t]->pr_glbtypenamet++spc()++pr_qualidqid|_->surround(prlist_with_seppr_comma(pr_glbtypename)params)++spc()++pr_qualidqidinletdef=ifnotprint_def||(matchdatawithGTydDefNone->true|_->false)thenmt()elsespc()++str":= "++matchdatawith|GTydDefNone->assertfalse|GTydDef(Somet)->pr_glbtypenamet|GTydAlg{galg_constructors=[]}->str"[ ]"|GTydAlg{galg_constructors=ctors}->letpr_ctor(_,id,argtys)=(* XXX print warning atrtribute? *)hov0(Id.printid++ifCList.is_emptyargtysthenmt()elsespc()++surround(prlist_with_seppr_comma(pr_glbtypename)argtys))inhv0(str"[ "++prlist_with_sep(fun()->spc()++str"| ")pr_ctorctors++str" ]")|GTydRecfields->letpr_field(id,ismut,t)=hov0((ifismutthenstr"mutable "elsemt())++Id.printid++spc()++str": "++pr_glbtypenamet)++str";"inhv2(str"{ "++prlist_with_sepspcpr_fieldfields++str" }")|GTydOpn->letctors=KerName.Map.bindings(Tac2env.find_all_constructors_in_typekn)inifCList.is_emptyctorsthenstr"[ .. ]"elseletpr_ctor(ckn,cdata)=letargtys=cdata.Tac2env.cdata_argsinhov0(Tac2print.pr_constructorckn++ifCList.is_emptyargtysthenmt()elsespc()++surround(prlist_with_seppr_comma(pr_glbtypename)argtys))inhov0(str"[ .."++spc()++str"| "++prlist_with_sep(fun()->spc()++str"| ")pr_ctorctors++str" ]")inhov2(ty++def)letprint_tacref~print_defqid=function|TacConstantkn->letdata=Tac2env.interp_globalkninletinfo=Option.mapfst(Tac2env.get_compiled_globalkn)inprint_constant~print_defqiddata?info|TacAliaskn->let{Tac2env.alias_body=body}=Tac2env.interp_aliaskninstr"Notation"++spc()++pr_qualidqid++str" :="++spc()++Tac2print.pr_rawexpr_genE5~avoid:Id.Set.emptybodyletprint_constructorqidkn=letcdata=Tac2env.interp_constructorkninletname=int_name()inletty=GTypRef(Othercdata.cdata_type,List.initcdata.cdata_prms(funi->GTypVari))inletty=List.fold_right(funargty->GTypArrow(arg,ty))cdata.cdata_argstyinpr_qualidqid++spc()++str": "++Tac2print.pr_glbtypenametyletlocatable_ltac2="Ltac2"typeltac2_object=|Typeoftype_constant|Constructorofltac_constructor|TacRefoftacrefletlocate_objectqid=tryType(Tac2env.locate_typeqid)withNot_found->tryConstructor(Tac2env.locate_constructorqid)withNot_found->TacRef(Tac2env.locate_ltacqid)letlocate_all_objectqid=letopenTac2envin(List.map(funx->Typex)(locate_extended_all_typeqid))@(List.map(funx->Constructorx)(locate_extended_all_constructorqid))@(List.map(funx->TacRefx)(locate_extended_all_ltacqid))letshortest_qualid_of_object=function|Typekn->Tac2env.shortest_qualid_of_typekn|Constructorkn->Tac2env.shortest_qualid_of_constructorkn|TacRefkn->Tac2env.shortest_qualid_of_ltacId.Set.emptyknletpath_of_object=function|Typekn->Tac2env.path_of_typekn|Constructorkn->Tac2env.path_of_constructorkn|TacRefkn->Tac2env.path_of_ltacknletprint_object~print_defqid=function|Typekn->str"Ltac2 Type"++spc()++print_type~print_defqidkn|Constructorkn->str"Ltac2 constructor"++spc()++print_constructorqidkn|TacRefkn->str"Ltac2 "++print_tacref~print_defqidknlet()=letopenPrettypinletlocateqid=trySome(qid,locate_objectqid)withNot_found->Noneinletlocate_allqid=List.map(funx->qid,x)(locate_all_objectqid)inletshortest_qualid(_,kn)=shortest_qualid_of_objectkninletname(_,kn)=lethdr=matchknwith|Type_->str"Ltac2 Type"|TacRef(TacConstant_)->str"Ltac2"|TacRef(TacAlias_)->str"Ltac2 Notation"|Constructor_->str"Ltac2 Constructor"inhdr++spc()++pr_path(path_of_objectkn)inletprint(qid,kn)=print_object~print_def:trueqidkninletabout(qid,kn)=print_object~print_def:falseqidkninregister_locatablelocatable_ltac2{locate;locate_all;shortest_qualid;name;print;about;}letprint_located_tacticqid=Feedback.msg_notice(Prettyp.print_located_other(Global.env())locatable_ltac2qid)letprint_ltac2qid=ifTac2env.is_constructorqidthenletkn=tryTac2env.locate_constructorqidwithNot_found->user_err?loc:qid.CAst.loc(str"Unknown constructor "++pr_qualidqid)inFeedback.msg_notice(print_constructorqidkn)elseletkn=tryTac2env.locate_ltacqidwithNot_found->user_err?loc:qid.CAst.loc(str"Unknown tactic "++pr_qualidqid)inFeedback.msg_notice(print_tacref~print_def:trueqidkn)letprint_ltac2_typeqid=matchTac2env.locate_typeqidwith|exceptionNot_found->user_err?loc:qid.CAst.loc(str"Unknown Ltac2 type "++pr_qualidqid)|kn->Feedback.msg_notice(print_type~print_def:trueqidkn)letprint_signatures()=letentries=KerName.Map.bindings(Tac2env.globals())inletsort(kn1,_)(kn2,_)=KerName.comparekn1kn2inletentries=List.sortsortentriesinletmap(kn,entry)=letqid=trySome(Tac2env.shortest_qualid_of_ltacId.Set.empty(TacConstantkn))withNot_found->Noneinmatchqidwith|None->None|Someqid->Some(qid,entry)inletentries=List.map_filtermapentriesinletpr_entry(qid,data)=hov2(print_constant~print_def:falseqiddata)inFeedback.msg_notice(prlist_with_sepfnlpr_entryentries)lettypecheck_expre=lete,(_,t)=Tac2intern.intern~strict:false[]einletname=int_name()inletpp=pr_glbexpr_genE5~avoid:Id.Set.emptye++spc()++str":"++spc()++pr_glbtypenametinFeedback.msg_noticeppletglobalize_expre=letavoid=Id.Set.emptyinlete=Tac2intern.debug_globalize_allow_extavoideinFeedback.msg_notice(Tac2print.pr_rawexpr_genE5~avoide)(** Calling tactics *)letltac2_interpe=letloc=e.locinlet(e,t)=intern~strict:false[]einlet()=check_unit?loctinlettac=Tac2interp.interpTac2interp.empty_environmenteinProofview.tclIGNOREtacletComTactic.Interpreterltac2_interp=ComTactic.register_tactic_interpreter"rocq-runtime.plugins.ltac2"ltac2_interpletcall~pstateg~with_end_tactac=letg=Option.default(Goal_select.get_default_goal_selector())ginComTactic.solve~pstate~with_end_tacg~info:None(ltac2_interptac)letcall_par~pstatetac=ComTactic.solve_parallel~pstate~info:None(ltac2_interptac)~abstract:false(** Primitive algebraic types than can't be defined Rocq-side *)letregister_prim_algnameparamsdef=letid=Id.of_stringnameinletdef=List.map(fun(cstr,tpe)->(None,Id.of_string_softcstr,tpe))definletgetn(const,nonconst)(_,c,args)=matchargswith|[]->(succconst,nonconst)|_::_->(const,succnonconst)inletnconst,nnonconst=List.fold_leftgetn(0,0)definletalg={galg_constructors=def;galg_nconst=nconst;galg_nnonconst=nnonconst;}inletdef=(params,GTydAlgalg)inletdef={typdef_local=false;typdef_abstract=false;typdef_expr=def}inLib.add_leaf(inTypDefiddef)letrocq_defn=KerName.makeTac2env.rocq_prefix(Id.of_stringn)letdef_unit={typdef_local=false;typdef_abstract=false;typdef_expr=0,GTydDef(Some(GTypRef(Tuple0,[])));}lett_list=rocq_def"list"let()=letobj()=letunit=Id.of_string"unit"inLib.add_leaf(inTypDefunitdef_unit);register_prim_alg"list"1[("[]",[]);("::",[GTypVar0;GTypRef(Othert_list,[GTypVar0])]);];inMltop.(declare_cache_obj_full(interp_only_objobj)"rocq-runtime.plugins.ltac2")