123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenLocus(** Utilities on or_var *)letor_var_mapf=function|ArgArgx->ArgArg(fx)|ArgVar_asy->y(** Utilities on occurrences *)letoccurrences_mapf=function|OnlyOccurrencesl->letl'=flinifl'=[]thenNoOccurrenceselseOnlyOccurrencesl'|AllOccurrencesButl->letl'=flinifl'=[]thenAllOccurrenceselseAllOccurrencesButl'|(NoOccurrences|AllOccurrences|AtLeastOneOccurrence)aso->otypeoccurrences_count={current:int;remaining:intlist;where:(bool*int)}leterror_invalid_occurrencel=CErrors.user_errPp.(str("Invalid occurrence "^String.plural(List.lengthl)"number"^": ")++prlist_with_sepspcintl++str".")letinitialize_occurrence_counteroccs=let(nowhere_except_in,occs)=matchoccswith|AtLeastOneOccurrence->(false,[])|AllOccurrences->(false,[])|AllOccurrencesButl->(false,List.sort_uniquizeInt.comparel)|NoOccurrences->(true,[])|OnlyOccurrencesl->(true,List.sort_uniquizeInt.comparel)inletmax=matchoccswith|n::_whenn<=0->error_invalid_occurrence[n]|[]->0|_->Util.List.lastoccsin{current=0;remaining=occs;where=(nowhere_except_in,max)}letupdate_occurrence_counter{current;remaining;where=(nowhere_except_in,_aswhere)}=letcurrent=succcurrentinmatchremainingwith|occ::remainingwhenInt.equalcurrentocc->(nowhere_except_in,{current;remaining;where})|_->(notnowhere_except_in,{current;remaining;where})letcheck_used_occurrences{remaining}=ifnot(Util.List.is_emptyremaining)thenerror_invalid_occurrenceremainingletoccurrences_done{current;where=(nowhere_except_in,max)}=nowhere_except_in&¤t>maxletcurrent_occurrence{current}=currentletmore_specific_occurrences{current;where=(_,max)}=current<=maxletis_selectedocc=function|AtLeastOneOccurrence->true|AllOccurrences->true|AllOccurrencesButl->not(Int.List.memoccl)|OnlyOccurrencesl->Int.List.memoccl|NoOccurrences->false(** Usual clauses *)letallHypsAndConcl={onhyps=None;concl_occs=AllOccurrences}letallHyps={onhyps=None;concl_occs=NoOccurrences}letonConcl={onhyps=Some[];concl_occs=AllOccurrences}letnowhere={onhyps=Some[];concl_occs=NoOccurrences}letonHyph={onhyps=Some[(AllOccurrences,h),InHyp];concl_occs=NoOccurrences}letis_nowhere=function|{onhyps=Some[];concl_occs=NoOccurrences}->true|_->falseletis_all_occurrences=function|AtLeastOneOccurrence|AllOccurrences->true|_->false(** Clause conversion functions, parametrized by a hyp enumeration function *)(** From [clause] to [simple_clause] *)letsimple_clause_ofenum_hypscl=leterror_occurrences()=CErrors.user_errPp.(str"This tactic does not support occurrences selection")inleterror_body_selection()=CErrors.user_errPp.(str"This tactic does not support body selection")inlethyps=matchcl.onhypswith|None->List.mapOption.make(enum_hyps())|Somel->List.map(fun((occs,id),w)->ifnot(is_all_occurrencesoccs)thenerror_occurrences();ifw=InHypValueOnlythenerror_body_selection();Someid)linifcl.concl_occs=NoOccurrencesthenhypselseifnot(is_all_occurrencescl.concl_occs)thenerror_occurrences()elseNone::hyps(** From [clause] to [concrete_clause] *)letconcrete_clause_ofenum_hypscl=lethyps=matchcl.onhypswith|None->letfid=OnHyp(id,AllOccurrences,InHyp)inList.mapf(enum_hyps())|Somel->List.map(fun((occs,id),w)->OnHyp(id,occs,w))linifcl.concl_occs=NoOccurrencesthenhypselseOnConclcl.concl_occs::hyps(** Miscellaneous functions *)letout_arg=function|ArgVar_->CErrors.anomaly(Pp.str"Unevaluated or_var variable.")|ArgArgx->xletoccurrences_of_hypidcls=letrechyp_occ=function[]->NoOccurrences,InHyp|((occs,id'),hl)::_whenNames.Id.equalidid'->occurrences_map(List.mapout_arg)occs,hl|_::l->hyp_occlinmatchcls.onhypswithNone->AllOccurrences,InHyp|Somel->hyp_occlletoccurrences_of_goalcls=occurrences_map(List.mapout_arg)cls.concl_occsletin_every_hypcls=Option.is_emptycls.onhypsletclause_with_generic_occurrencescls=lethyps=matchcls.onhypswith|None->true|Somehyps->List.for_all(function((AllOccurrences,_),_)->true|_->false)hypsinletconcl=matchcls.concl_occswith|AtLeastOneOccurrence|AllOccurrences|NoOccurrences->true|_->falseinhyps&&conclletclause_with_generic_context_selectioncls=lethyps=matchcls.onhypswith|None->true|Somehyps->List.for_all(function((AllOccurrences,_),InHyp)->true|_->false)hypsinletconcl=matchcls.concl_occswith|AtLeastOneOccurrence|AllOccurrences|NoOccurrences->true|_->falseinhyps&&concl