123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365(************************************************************************)(* * 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) *)(************************************************************************)openPpopenCErrorsopenUtilopenNamesopenConstropenEConstropenGenredexpropenPatternopenReductionopsopenTacredopenCClosureopenRedFlagsopenLibobjectletwarn_vm_disabled=CWarnings.create~name:"vm-compute-disabled"~category:"bytecode-compiler"(fun()->strbrk"vm_compute disabled at configure time; falling back to cbv.")(* call by value normalisation function using the virtual machine *)letcbv_vmenvsigmac=if(Environ.typing_flagsenv).enable_VMthenletctyp=Retyping.get_type_ofenvsigmacinVnorm.cbv_vmenvsigmacctypelsebeginwarn_vm_disabled();computeenvsigmacendletwarn_native_compute_disabled=CWarnings.create~name:"native-compute-disabled"~category:"native-compiler"(fun()->strbrk"native_compute disabled at configure time; falling back to vm_compute.")letcbv_nativeenvsigmac=ifFlags.get_native_compiler()thenletctyp=Retyping.get_type_ofenvsigmacinNativenorm.native_normenvsigmacctypelse(warn_native_compute_disabled();cbv_vmenvsigmac)letwhd_cbn=Cbn.whd_cbnletsimplIsCbn=Goptions.declare_bool_option_and_ref~depr:false~key:["SimplIsCbn"]~value:falseletset_strategy_onerefl=letk=matchrefwith|EvalConstRefsp->ConstKeysp|EvalVarRefid->VarKeyidinlet()=Global.set_strategyklinmatchk,lwith|ConstKeysp,Conv_oracle.Opaque->()|ConstKeysp,_->ifDeclareops.is_opaque(Global.lookup_constantsp)thenuser_err(str"Cannot make"++spc()++Nametab.pr_global_envId.Set.empty(GlobRef.ConstRefsp)++spc()++str"transparent because it was declared opaque.")|_->()letcache_strategy(_,str)=List.iter(fun(lev,ql)->List.iter(funq->set_strategy_oneqlev)ql)strletsubst_strategy(subs,(local,obj))=local,List.Smart.map(fun(k,qlasentry)->letql'=List.Smart.map(Tacred.subst_evaluable_referencesubs)qlinifql==ql'thenentryelse(k,ql'))objletmap_strategyfl=letl'=List.fold_right(fun(lev,ql)str->letql'=List.fold_right(funqql->matchfqwithSomeq'->q'::ql|None->ql)ql[]inifList.is_emptyql'thenstrelse(lev,ql')::str)l[]inifList.is_emptyl'thenNoneelseSome(false,l')letclassify_strategy(local,_)=iflocalthenDisposeelseSubstituteletdisch_refref=matchrefwithEvalConstRefc->Someref|EvalVarRefid->ifLib.is_in_section(GlobRef.VarRefid)thenNoneelseSomerefletdischarge_strategy(local,obj)=iflocalthenNoneelsemap_strategydisch_refobjtypestrategy_obj=bool*(Conv_oracle.level*evaluable_global_referencelist)listletinStrategy:strategy_obj->obj=declare_object{(default_object"STRATEGY")withcache_function=cache_strategy;load_function=(fun_obj->cache_strategyobj);subst_function=subst_strategy;discharge_function=discharge_strategy;classify_function=classify_strategy;}letset_strategylocalstr=Lib.add_leaf(inStrategy(local,str))(* Generic reduction: reduction functions used in reduction tactics *)typered_expr=(constr,evaluable_global_reference,constr_pattern)red_expr_gentypered_expr_val=(constr,evaluable_global_reference,constr_pattern,CClosure.RedFlags.reds)red_expr_gen0letmake_flag_constant=function|EvalVarRefid->fVARid|EvalConstRefsp->fCONSTspletmake_flagenvf=letred=no_redinletred=iff.rBetathenred_addredfBETAelseredinletred=iff.rMatchthenred_addredfMATCHelseredinletred=iff.rFixthenred_addredfFIXelseredinletred=iff.rCofixthenred_addredfCOFIXelseredinletred=iff.rZetathenred_addredfZETAelseredinletred=iff.rDeltathen(* All but rConst *)letred=red_addredfDELTAinletred=red_add_transparentred(Conv_oracle.get_transp_state(Environ.oracleenv))inList.fold_right(funvred->red_subred(make_flag_constantv))f.rConstredelse(* Only rConst *)letred=red_addredfDELTAinList.fold_right(funvred->red_addred(make_flag_constantv))f.rConstredinred(* table of custom reductino fonctions, not synchronized,
filled via ML calls to [declare_reduction] *)letreduction_tab=refString.Map.empty(* table of custom reduction expressions, synchronized,
filled by command Declare Reduction *)letred_expr_tab=Summary.refString.Map.empty~name:"Declare Reduction"letdeclare_reductionsf=ifString.Map.mems!reduction_tab||String.Map.mems!red_expr_tabthenuser_err(str"There is already a reduction expression of name "++strs++str".")elsereduction_tab:=String.Map.addsf!reduction_tabletcheck_custom=function|ExtraRedExprs->ifnot(String.Map.mems!reduction_tab||String.Map.mems!red_expr_tab)thenuser_err(str"Reference to undefined reduction expression "++strs++str".")|_->()letdecl_red_exprse=ifString.Map.mems!reduction_tab||String.Map.mems!red_expr_tabthenuser_err(str"There is already a reduction expression of name "++strs++str".")elsebegincheck_custome;red_expr_tab:=String.Map.addse!red_expr_tabendletout_arg=function|Locus.ArgVar_->anomaly(Pp.str"Unevaluated or_var variable.")|Locus.ArgArgx->xletout_occurrencesoccs=letoccs=Locusops.occurrences_map(List.mapout_arg)occsinmatchoccswith|Locus.OnlyOccurrences(n::_asnl)whenn<0->Locus.AllOccurrencesBut(List.mapabsnl)|Locus.OnlyOccurrencesnlwhenList.exists(funn->n<0)nl->CErrors.user_errPp.(str"Illegal negative occurrence number.")|Locus.OnlyOccurrences_|Locus.AllOccurrencesBut_|Locus.NoOccurrences|Locus.AllOccurrences|Locus.AtLeastOneOccurrence->occsletout_with_occurrences(occs,c)=(out_occurrencesoccs,c)lete_redfenvevmc=evm,fenvevmclethead_style=false(* Turn to true to have a semantics where simpl
only reduce at the head when an evaluable reference is given, e.g.
2+n would just reduce to S(1+n) instead of S(S(n)) *)letcontextualizefg=function|Some(occs,c)->letl=out_occurrencesoccsinletb,c,h=matchcwith|Inlr->true,PRef(global_of_evaluable_referencer),f|Inrc->false,c,fine_red(contextuallyb(l,c)(fun_->h))|None->e_redgletwarn_simpl_unfolding_modifiers=CWarnings.create~name:"simpl-unfolding-modifiers"~category:"tactics"(fun()->Pp.strbrk"The legacy simpl ignores constant unfolding modifiers.")letreceval_red_exprenv=function|Simpl(f,o)->let()=ifnot(simplIsCbn()||List.is_emptyf.rConst)thenwarn_simpl_unfolding_modifiers()inletf=ifsimplIsCbn()thenmake_flagenvfelseCClosure.all(* dummy *)inSimpl(f,o)|Cbvf->Cbv(make_flagenvf)|Cbnf->Cbn(make_flagenvf)|Lazyf->Lazy(make_flagenvf)|ExtraRedExprs->beginmatchString.Map.finds!red_expr_tabwith|e->eval_red_exprenve|exceptionNot_found->ExtraRedExprs(* delay to runtime interpretation *)end|(Red_|Hnf|Unfold_|Fold_|Pattern_|CbvVm_|CbvNative_)ase->eletreduction_of_red_expr_val=function|Redinternal->ifinternalthen(e_redtry_red_product,DEFAULTcast)else(e_redred_product,DEFAULTcast)|Hnf->(e_redhnf_constr,DEFAULTcast)|Simpl(f,o)->letwhd_am=ifsimplIsCbn()thenwhd_cbnfelsewhd_simplinletam=ifsimplIsCbn()thenCbn.norm_cbnfelsesimplin(contextualize(ifhead_stylethenwhd_amelseam)amo,DEFAULTcast)|Cbvf->(e_red(cbv_norm_flagsf),DEFAULTcast)|Cbnf->(e_red(Cbn.norm_cbnf),DEFAULTcast)|Lazyf->(e_red(clos_norm_flagsf),DEFAULTcast)|Unfoldubinds->(e_red(unfoldn(List.mapout_with_occurrencesubinds)),DEFAULTcast)|Foldcl->(e_red(fold_commandscl),DEFAULTcast)|Patternlp->(pattern_occs(List.mapout_with_occurrenceslp),DEFAULTcast)|ExtraRedExprs->(try(e_red(String.Map.finds!reduction_tab),DEFAULTcast)withNot_found->user_err(str"Unknown user-defined reduction \""++strs++str"\"."))|CbvVmo->(contextualizecbv_vmcbv_vmo,VMcast)|CbvNativeo->(contextualizecbv_nativecbv_nativeo,NATIVEcast)letreduction_of_red_exprenvr=reduction_of_red_expr_val(eval_red_exprenvr)(* Possibly equip a reduction with the occurrences mentioned in an
occurrence clause *)leterror_illegal_clause()=CErrors.user_errPp.(str"\"at\" clause not supported in presence of an occurrence clause.")leterror_multiple_patterns()=CErrors.user_errPp.(str"\"at\" clause in occurences not supported with multiple patterns or references.")leterror_illegal_non_atomic_clause()=CErrors.user_errPp.(str"\"at\" clause not supported in presence of a non atomic \"in\" clause.")leterror_at_in_occurrences_not_supported()=CErrors.user_errPp.(str"\"at\" clause not supported for this reduction tactic.")letbind_red_expr_occurrencesoccsnbclredexp=letopenLocusinlethas_at_clause=function|Unfoldl->List.exists(fun(occl,_)->occl!=AllOccurrences)l|Patternl->List.exists(fun(occl,_)->occl!=AllOccurrences)l|Simpl(_,Some(occl,_))->occl!=AllOccurrences|_->falseinifoccs==AllOccurrencesthenifnbcl>1&&has_at_clauseredexpthenerror_illegal_non_atomic_clause()elseredexpelsematchredexpwith|Unfold(_::_::_)->error_multiple_patterns()|Unfold[(occl,c)]->ifoccl!=AllOccurrencesthenerror_illegal_clause()elseUnfold[(occs,c)]|Pattern(_::_::_)->error_multiple_patterns()|Pattern[(occl,c)]->ifoccl!=AllOccurrencesthenerror_illegal_clause()elsePattern[(occs,c)]|Simpl(f,Some(occl,c))->ifoccl!=AllOccurrencesthenerror_illegal_clause()elseSimpl(f,Some(occs,c))|CbvVm(Some(occl,c))->ifoccl!=AllOccurrencesthenerror_illegal_clause()elseCbvVm(Some(occs,c))|CbvNative(Some(occl,c))->ifoccl!=AllOccurrencesthenerror_illegal_clause()elseCbvNative(Some(occs,c))|Red_|Hnf|Cbv_|Lazy_|Cbn_|ExtraRedExpr_|Fold_|Simpl(_,None)|CbvVmNone|CbvNativeNone->error_at_in_occurrences_not_supported()|Unfold[]|Pattern[]->assertfalseletreduction_of_red_expr_val?occsr=letr=matchoccswith|None->r|Some(occs,nbcl)->bind_red_expr_occurrencesoccsnbclrinreduction_of_red_expr_valrletsubst_mpssubstc=EConstr.of_constr(Mod_subst.subst_mpssubst(EConstr.Unsafe.to_constrc))letsubst_red_exprsubs=letenv=Global.env()inletsigma=Evd.from_envenvinRedops.map_red_expr_gen(subst_mpssubs)(Tacred.subst_evaluable_referencesubs)(Patternops.subst_patternenvsigmasubs)letinReduction:bool*string*red_expr->obj=declare_object{(default_object"REDUCTION")withcache_function=(fun(_,s,e)->decl_red_exprse);load_function=(fun_(_,s,e)->decl_red_exprse);subst_function=(fun(subs,(b,s,e))->b,s,subst_red_exprsubse);classify_function=(fun((b,_,_))->ifbthenDisposeelseSubstitute)}letdeclare_red_exprlocalitysexpr=Lib.add_leaf(inReduction(locality,s,expr))