123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593(************************************************************************)(* * 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) *)(************************************************************************)openPpopenNamesopenUtilopenCAstopenTac2dynopenTac2expropenTac2qexpr(** Generic arguments *)letwit_pattern=Arg.create"pattern"letwit_reference=Arg.create"reference"letwit_ident=Arg.create"ident"letwit_constr=Arg.create"constr"letwit_open_constr=Arg.create"open_constr"letwit_preterm=Arg.create"preterm"(** Syntactic quoting of expressions. *)letprefix_genn=MPfile(DirPath.make(List.mapId.of_string[n;"Ltac2"]))letcontrol_prefix=prefix_gen"Control"letpattern_prefix=prefix_gen"Pattern"letarray_prefix=prefix_gen"Array"letconstr_prefix=prefix_gen"Constr"letformat_prefix=MPdot(prefix_gen"Message",Label.make"Format")letkernameprefixn=KerName.makeprefix(Label.of_id(Id.of_string_softn))letstd_coren=kernameTac2env.std_prefixnletcoq_coren=kernameTac2env.coq_prefixnletcontrol_coren=kernamecontrol_prefixnletpattern_coren=kernamepattern_prefixnletin_constrmodsn=letmp=List.fold_left(funmpmod_->MPdot(mp,Label.of_id@@Id.of_stringmod_))constr_prefixmodsinkernamempnletglobal_ref?lockn=CAst.make?loc@@CTacRef(AbsKn(TacConstantkn))letconstructor?locknargs=letcst=CAst.make?loc@@CTacCst(AbsKn(Otherkn))inifList.is_emptyargsthencstelseCAst.make?loc@@CTacApp(cst,args)letstd_constructor?locnameargs=constructor?loc(std_corename)argsletstd_proj?locname=AbsKn(std_corename)letthunke=lett_unit=coq_core"unit"inletloc=e.locinletty=CAst.make?loc@@CTypRef(AbsKn(Othert_unit),[])inletpat=CAst.make?loc@@CPatVar(Anonymous)inletpat=CAst.make?loc@@CPatCnv(pat,ty)inCAst.make?loc@@CTacFun([pat],e)letof_pairfg{loc;v=(e1,e2)}=CAst.make?loc@@CTacApp(CAst.make?loc@@CTacCst(AbsKn(Tuple2)),[fe1;ge2])letof_tuple?locel=matchelwith|[]->CAst.make?loc@@CTacCst(AbsKn(Tuple0))|[e]->e|el->letlen=List.lengthelinCAst.make?loc@@CTacApp(CAst.make?loc@@CTacCst(AbsKn(Tuplelen)),el)letof_string{loc;v=n}=CAst.make?loc@@CTacAtm(AtmStrn)letof_int{loc;v=n}=CAst.make?loc@@CTacAtm(AtmIntn)letof_option?locfopt=matchoptwith|None->constructor?loc(coq_core"None")[]|Somee->constructor?loc(coq_core"Some")[fe]letinj_wit?locwitx=CAst.make?loc@@CTacExt(wit,x)letof_variable{loc;v=id}=letqid=Libnames.qualid_of_ident?locidinifTac2env.is_constructorqidthenCErrors.user_err?loc(str"Invalid identifier"++spc()++Id.printid++spc()++str"classifying as an Ltac2 constructor")elseCAst.make?loc@@CTacRef(RelIdqid)letof_antif=function|QExprx->fx|QAntiid->of_variableidletof_ident{loc;v=id}=inj_wit?locwit_identidletquote_constr?(delimiters=[])c=letloc=Constrexpr_ops.constr_loccinList.fold_left(funcd->CAst.make?loc@@Constrexpr.(CDelimiters(DelimUnboundedScope,Id.to_stringd,c)))cdelimitersletof_constr?delimitersc=letloc=Constrexpr_ops.constr_loccinletc=quote_constr?delimiterscininj_wit?locwit_constrcletof_open_constr?delimitersc=letloc=Constrexpr_ops.constr_loccinletc=quote_constr?delimiterscininj_wit?locwit_open_constrcletof_preterm?delimitersc=letloc=Constrexpr_ops.constr_loccinletc=quote_constr?delimiterscininj_wit?locwit_pretermcletof_open_constr_expected_istype?delimitersc=let{loc}asc=quote_constr?delimiterscinletmke=CAst.make?loceinletc=letsc=Notation.current_type_scope_names()inletdelim=List.filter_map(funsc->Notation.scope_delimiters(Notation.find_scopesc))scin(* Not sure if this puts the delimiters in the correct order, usually we have just "type" *)List.fold_left(funcdelim->mk@@Constrexpr.CDelimiters(DelimOnlyTmpScope,delim,c))cdeliminletc=inj_wit?locwit_pretermcinletgrefn=global_ref?locninmk@@CTacApp(gref@@in_constr["Pretype"]"pretype",[mk@@CTacApp(gref@@in_constr["Pretype";"Flags"]"open_constr_flags_with_tc_kn",[of_tuple?loc[]]);gref@@in_constr["Pretype"]"expected_istype";c])letof_bool?locb=letc=ifbthencoq_core"true"elsecoq_core"false"inconstructor?locc[]letrecof_list?locf=function|[]->constructor(coq_core"[]")[]|e::l->constructor?loc(coq_core"::")[fe;of_list?locfl]letarray_literal?loca=ifCList.is_emptyathenglobal_ref?loc(kernamearray_prefix"empty")elseletof_list_kn=global_ref?loc(kernamearray_prefix"of_list")inCAst.make?loc@@CTacApp(of_list_kn,[of_list?loc(funx->x)a])letof_qhyp{loc;v=h}=matchhwith|QAnonHypn->std_constructor?loc"AnonHyp"[of_intn]|QNamedHypid->std_constructor?loc"NamedHyp"[of_identid]letof_bindings{loc;v=b}=matchbwith|QNoBindings->std_constructor?loc"NoBindings"[]|QImplicitBindingstl->std_constructor?loc"ImplicitBindings"[of_list?locof_open_constrtl]|QExplicitBindingstl->letmape=of_pair(funq->of_antiof_qhypq)of_open_constreinstd_constructor?loc"ExplicitBindings"[of_list?locmaptl]letof_constr_with_bindingsc=of_pairof_open_constrof_bindingscletrecof_intro_pattern{loc;v=pat}=matchpatwith|QIntroForthcomingb->std_constructor?loc"IntroForthcoming"[of_boolb]|QIntroNaminginame->std_constructor?loc"IntroNaming"[of_intro_pattern_naminginame]|QIntroActioniact->std_constructor?loc"IntroAction"[of_intro_pattern_actioniact]andof_intro_pattern_naming{loc;v=pat}=matchpatwith|QIntroIdentifierid->std_constructor?loc"IntroIdentifier"[of_antiof_identid]|QIntroFreshid->std_constructor?loc"IntroFresh"[of_antiof_identid]|QIntroAnonymous->std_constructor?loc"IntroAnonymous"[]andof_intro_pattern_action{loc;v=pat}=matchpatwith|QIntroWildcard->std_constructor?loc"IntroWildcard"[]|QIntroOrAndPatternpat->std_constructor?loc"IntroOrAndPattern"[of_or_and_intro_patternpat]|QIntroInjectionil->std_constructor?loc"IntroInjection"[of_intro_patternsil]|QIntroApplyOn(c,i)->std_constructor?loc"IntroApplyOn"[thunk@@of_open_constrc;of_intro_patterni]|QIntroRewriteb->std_constructor?loc"IntroRewrite"[of_bool?locb]andof_or_and_intro_pattern{loc;v=pat}=matchpatwith|QIntroOrPatternill->std_constructor?loc"IntroOrPattern"[of_list?locof_intro_patternsill]|QIntroAndPatternil->std_constructor?loc"IntroAndPattern"[of_intro_patternsil]andof_intro_patterns{loc;v=l}=of_list?locof_intro_patternlletof_hyp_location_flag?loc=function|Locus.InHyp->std_constructor?loc"InHyp"[]|Locus.InHypTypeOnly->std_constructor?loc"InHypTypeOnly"[]|Locus.InHypValueOnly->std_constructor?loc"InHypValueOnly"[]letof_occurrences{loc;v=occ}=matchoccwith|QAllOccurrences->std_constructor?loc"AllOccurrences"[]|QAllOccurrencesButoccs->letmapocc=of_antiof_intoccinletoccs=of_list?locmapoccsinstd_constructor?loc"AllOccurrencesBut"[occs]|QNoOccurrences->std_constructor?loc"NoOccurrences"[]|QOnlyOccurrencesoccs->letmapocc=of_antiof_intoccinletoccs=of_list?locmapoccsinstd_constructor?loc"OnlyOccurrences"[occs]letof_hyp_location?loc((occs,id),flag)=of_tuple?loc[of_antiof_identid;of_occurrencesoccs;of_hyp_location_flag?locflag;]letof_clause{loc;v=cl}=lethyps=of_option?loc(funl->of_list?locof_hyp_locationl)cl.q_onhypsinletconcl=of_occurrencescl.q_concl_occsinCAst.make?loc@@CTacRec(None,[std_proj"on_hyps",hyps;std_proj"on_concl",concl;])letof_destruction_arg{loc;v=arg}=matchargwith|QElimOnConstrc->letarg=thunk(of_constr_with_bindingsc)instd_constructor?loc"ElimOnConstr"[arg]|QElimOnIdentid->std_constructor?loc"ElimOnIdent"[of_identid]|QElimOnAnonHypn->std_constructor?loc"ElimOnAnonHyp"[of_intn]letof_induction_clause{loc;v=cl}=letarg=of_destruction_argcl.indcl_arginleteqn=of_option?locof_intro_pattern_namingcl.indcl_eqninletas_=of_option?locof_or_and_intro_patterncl.indcl_asinletin_=of_option?locof_clausecl.indcl_ininCAst.make?loc@@CTacRec(None,[std_proj"indcl_arg",arg;std_proj"indcl_eqn",eqn;std_proj"indcl_as",as_;std_proj"indcl_in",in_;])letcheck_pattern_id?locid=ifTac2env.is_constructor(Libnames.qualid_of_identid)thenCErrors.user_err?loc(str"Invalid pattern binding name "++Id.printid)letpattern_varspat=letrecaux()accupat=matchpat.CAst.vwith|Constrexpr.CPatVarid|Constrexpr.CEvar({CAst.v=id},[])->letloc=pat.CAst.locinlet()=check_pattern_id?locidinId.Map.addidlocaccu|_->Constrexpr_ops.fold_constr_expr_with_binders(fun_()->())aux()accupatinaux()Id.Map.emptypatletabstract_varsloc?typvarstac=letget_namena=matchna.CAst.vwith|Nameid->Some(CAst.make?loc:na.CAst.locid)|Anonymous->Noneinletdef=List.find_mapget_namevarsinletna,tac=matchdefwith|None->(Anonymous,tac)|Someid0->(* Trick: in order not to shadow a variable nor to choose an arbitrary
name, we reuse one which is going to be shadowed by the matched
variables anyways. *)letbuild_bindings(n,accu){CAst.loc;CAst.v=na}=matchnawith|Anonymous->(n+1,accu)|Name_->letget=global_ref?loc(kernamearray_prefix"get")inletargs=[of_variableid0;of_intCAst.(make?locn)]inlete=CAst.make?loc@@CTacApp(get,args)inletaccu=(CAst.make?loc@@CPatVarna,e)::accuin(n+1,accu)inlet(_,bnd)=List.fold_leftbuild_bindings(0,[])varsinlettac=CAst.make?loc@@CTacLet(false,bnd,tac)in(Nameid0.CAst.v,tac)inletpat=CAst.make?loc@@CPatVarnainletpat=matchtypwith|None->pat|Sometyp->lett_array=coq_core"array"inlettyp=CAst.make?loc@@CTypRef(AbsKn(Othert_array),[typ])inCAst.make?loc@@CPatCnv(pat,typ)inCAst.make?loc@@CTacFun([pat],tac)letof_patternp=inj_wit?loc:p.CAst.locwit_patternpletof_conversion{loc;v=c}=matchcwith|QConvertc->letpat=of_option?locof_patternNoneinletc=CAst.make?loc@@CTacFun([CAst.make?loc@@CPatVarAnonymous],of_constrc)inof_tuple?loc[pat;c]|QConvertWith(pat,c)->letvars=pattern_varspatinletpat=of_option?locof_pattern(Somepat)inletc=of_constrcin(* Order is critical here *)letvars=List.map(fun(id,loc)->CAst.make?loc(Nameid))(Id.Map.bindingsvars)inletc=abstract_varslocvarscinof_tuple[pat;c]letof_repeat{loc;v=r}=matchrwith|QPreciselyn->std_constructor?loc"Precisely"[of_intn]|QUpTon->std_constructor?loc"UpTo"[of_intn]|QRepeatStar->std_constructor?loc"RepeatStar"[]|QRepeatPlus->std_constructor?loc"RepeatPlus"[]letof_orient{loc;v=b}=lethelperb=ifbthenstd_constructor?loc"LTR"[]elsestd_constructor?loc"RTL"[]inof_option?lochelperbletof_rewriting{loc;v=rew}=letorient=of_orientrew.rew_orientinletrepeat=of_repeatrew.rew_repeatinletequatn=thunk(of_constr_with_bindingsrew.rew_equatn)inCAst.make?loc@@CTacRec(None,[std_proj"rew_orient",orient;std_proj"rew_repeat",repeat;std_proj"rew_equatn",equatn;])letof_hyp?locid=lethyp=global_ref?loc(control_core"hyp")inCAst.make?loc@@CTacApp(hyp,[of_identid])letof_exact_hyp?locid=letrefine=global_ref?loc(control_core"refine")inCAst.make?loc@@CTacApp(refine,[thunk(of_hyp?locid)])letof_exact_var?locid=letrefine=global_ref?loc(control_core"refine")inCAst.make?loc@@CTacApp(refine,[thunk(of_variableid)])letof_dispatchtacs=letloc=tacs.locinletdefault=function|Somee->thunke|None->thunk(CAst.make?loc@@CTacCst(AbsKn(Tuple0)))inletmape=of_pairdefault(funl->of_list?locdefaultl)(CAst.make?loce)inof_pair(funl->of_list?locdefaultl)(funr->of_option?locmapr)tacsletmake_red_flagl=letopenGenredexprinletrecadd_flagred=function|[]->red|{v=flag}::lf->letred=matchflagwith|QHead->{redwithrStrength=Head}|QBeta->{redwithrBeta=true}|QMatch->{redwithrMatch=true}|QFix->{redwithrFix=true}|QCofix->{redwithrCofix=true}|QZeta->{redwithrZeta=true}|QConst{loc;v=l}->ifred.rDeltathenCErrors.user_err?locPp.(str"Cannot set both constants to unfold and constants not to unfold");{redwithrConst=red.rConst@l}|QDeltaBut{loc;v=l}->ifred.rConst<>[]&¬red.rDeltathenCErrors.user_err?locPp.(str"Cannot set both constants to unfold and constants not to unfold");{redwithrConst=red.rConst@l;rDelta=true}|QIota->{redwithrMatch=true;rFix=true;rCofix=true}inadd_flagredlfinadd_flag{rBeta=false;rMatch=false;rFix=false;rCofix=false;rZeta=false;rDelta=false;rConst=[];rStrength=Norm;}lletof_referencer=letof_refref=inj_wit?loc:ref.locwit_referencerefinof_antiof_refrletof_strength?locs=lets=letopenGenredexprinmatchswith|Norm->std_core"Norm"|Head->std_core"Head"inconstructor?locs[]letof_strategy_flag{loc;v=flag}=letopenGenredexprinletflag=make_red_flagflaginCAst.make?loc@@CTacRec(None,[std_proj"rStrength",of_strength?locflag.rStrength;std_proj"rBeta",of_bool?locflag.rBeta;std_proj"rMatch",of_bool?locflag.rMatch;std_proj"rFix",of_bool?locflag.rFix;std_proj"rCofix",of_bool?locflag.rCofix;std_proj"rZeta",of_bool?locflag.rZeta;std_proj"rDelta",of_bool?locflag.rDelta;std_proj"rConst",of_list?locof_referenceflag.rConst;])letof_hintdb{loc;v=hdb}=matchhdbwith|QHintAll->of_option?loc(funl->of_list(funid->of_antiof_identid)l)None|QHintDbsids->of_option?loc(funl->of_list(funid->of_antiof_identid)l)(Someids)letextract_name?locoid=matchoidwith|None->Anonymous|Someid->let()=check_pattern_id?locidinNameid(** For every branch in the matching, generate a corresponding term of type
[(match_kind * pattern * (context -> constr array -> 'a))]
where the function binds the names from the pattern to the contents of the
constr array. *)letof_constr_matching{loc;v=m}=letmap{loc;v=({loc=ploc;v=pat},tac)}=let(knd,pat,na)=matchpatwith|QConstrMatchPatternpat->letknd=constructor?loc(pattern_core"MatchPattern")[]in(knd,pat,Anonymous)|QConstrMatchContext(id,pat)->letna=extract_name?locidinletknd=constructor?loc(pattern_core"MatchContext")[]in(knd,pat,na)inletvars=pattern_varspatin(* Order of elements is crucial here! *)letvars=Id.Map.bindingsvarsinletvars=List.map(fun(id,loc)->CAst.make?loc(Nameid))varsin(* Annotate the bound array variable with constr type *)lettyp=lett_constr=coq_core"constr"inCAst.make?loc@@CTypRef(AbsKn(Othert_constr),[])inlete=abstract_varsloc~typvarstacinlete=CAst.make?loc@@CTacFun([CAst.make?loc@@CPatVarna],e)inletpat=inj_wit?loc:plocwit_patternpatinof_tuple[knd;pat;e]inlete=of_list?locmapmine(** From the patterns and the body of the branch, generate:
- a goal pattern: (constr_match list * constr_match)
- a branch function (ident array -> context array -> constr array -> context -> 'a)
*)letof_goal_matching{loc;v=gm}=letmk_pat{loc;v=p}=matchpwith|QConstrMatchPatternpat->letknd=constructor?loc(pattern_core"MatchPattern")[]in(CAst.make?locAnonymous,pat,knd)|QConstrMatchContext(id,pat)->letna=extract_name?locidinletknd=constructor?loc(pattern_core"MatchContext")[]in(CAst.make?locna,pat,knd)inletmk_gpat{loc;v=p}=letconcl_pat=p.q_goal_match_conclinlethyps_pats=p.q_goal_match_hypsinlet(concl_ctx,concl_pat,concl_knd)=mk_patconcl_patinletvars=pattern_varsconcl_patinletmapaccu(na,bod,pat)=matchbodwith|None->let(ctx,pat,knd)=mk_patpatinletvars=pattern_varspatin(Id.Map.foldId.Map.addvarsaccu,(na,None,(ctx,knd,pat)))|Somebod->letbctx,bpat,bknd=mk_patbodinlet(ctx,pat,knd)=mk_patpatinletbvars=pattern_varsbpatinletvars=pattern_varspatinletaccu=Id.Map.foldId.Map.addbvarsaccuinletaccu=Id.Map.foldId.Map.addvarsaccuin(accu,(na,Some((bctx,bknd,bpat)),(ctx,knd,pat)))inlet(vars,hyps_pats)=List.fold_left_mapmapvarshyps_patsinletconcl=of_tuple[concl_knd;of_patternconcl_pat]inletof_hyp_pat(_,bpat,(_,knd,pat))=letbpat=Option.map(fun(_,a,b)->(a,b))bpatinletof_mpat(a,b)=of_tuple[a;of_patternb]inof_tuple[of_optionof_mpatbpat;of_mpat(knd,pat)]inletr=of_tuple[of_list?locof_hyp_pathyps_pats;concl]inlethyps=List.map(fun(na,_,_)->na)hyps_patsinlethbctx=CList.filter_map(fun(_,b,_)->Option.mappi1b)hyps_patsinlethctx=CList.map(fun(_,_,(na,_,_))->na)hyps_patsin(* Order of elements is crucial here! *)letvars=Id.Map.bindingsvarsinletsubst=List.map(fun(id,loc)->CAst.make?loc(Nameid))varsin(r,hyps,hbctx,hctx,subst,concl_ctx)inletmap{loc;v=(pat,tac)}=let(pat,hyps,hbctx,hctx,subst,cctx)=mk_gpatpatinlettac=CAst.make?loc@@CTacFun([CAst.make?loc@@CPatVarcctx.CAst.v],tac)inlettac=abstract_varslocsubsttacinlettac=abstract_varslochctxtacinlettac=abstract_varslochbctxtacinlettac=abstract_varslochypstacinof_tuple?loc[pat;tac]inlete=of_list?locmapgminlettykn=pattern_core"goal_matching"inletty=CAst.make?loc(CTypRef(AbsKn(Othertykn),[CAst.make?loc(CTypVarAnonymous)]))inCAst.make?loc(CTacCnv(e,ty))letof_move_location{loc;v=mv}=matchmvwith|QMoveAfterid->std_constructor?loc"MoveAfter"[of_antiof_identid]|QMoveBeforeid->std_constructor?loc"MoveBefore"[of_antiof_identid]|QMoveFirst->std_constructor?loc"MoveFirst"[]|QMoveLast->std_constructor?loc"MoveLast"[]letof_posep=of_pair(funid->of_option(funid->of_antiof_identid)id)of_open_constrpletof_assertion{loc;v=ast}=matchastwith|QAssertType(ipat,c,tac)->letipat=of_optionof_intro_patternipatinletc=of_open_constr_expected_istypecinlettac=of_optionthunktacinstd_constructor?loc"AssertType"[ipat;c;tac]|QAssertValue(id,c)->letid=of_antiof_identidinletc=of_constrcinstd_constructor?loc"AssertValue"[id;c]letof_formataccu=function|Tac2print.FmtString->CAst.make@@CTacApp(global_ref(kernameformat_prefix"string"),[accu])|Tac2print.FmtInt->CAst.make@@CTacApp(global_ref(kernameformat_prefix"int"),[accu])|Tac2print.FmtConstr->CAst.make@@CTacApp(global_ref(kernameformat_prefix"constr"),[accu])|Tac2print.FmtIdent->CAst.make@@CTacApp(global_ref(kernameformat_prefix"ident"),[accu])|Tac2print.FmtLiterallit->lets=of_string(CAst.makelit)inCAst.make@@CTacApp(global_ref(kernameformat_prefix"literal"),[s;accu])|Tac2print.FmtAlpha->CAst.make@@CTacApp(global_ref(kernameformat_prefix"alpha"),[accu])letof_format{v=fmt;loc}=letfmt=tryTac2print.parse_formatfmtwithTac2print.InvalidFormat->CErrors.user_err?loc(str"Invalid format")inletstop=global_ref(kernameformat_prefix"stop")inList.fold_leftof_formatstopfmt