123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openLangopenLang.FopenConditionsopenTactical(* -------------------------------------------------------------------------- *)(* --- Compound Equality --- *)(* -------------------------------------------------------------------------- *)typeupdate=term*term*termtypeequality=|Recordofterm*term*Lang.fieldlist(* a.f = b.f forall f *)|Array1ofupdate*term*tau|Array2ofupdate*update*tau(* -------------------------------------------------------------------------- *)(* --- Record Patterns --- *)(* -------------------------------------------------------------------------- *)letget_record_assoc=function|(f,_)::_->Some(Lang.fields_of_fieldf)|_->Noneletget_record_type=function|Qed.Logic.Recordfts->get_record_assocfts|_->Noneletget_record_terma=matchF.reprawith|Qed.Logic.Rdeffvs->get_record_assocfvs|Qed.Logic.Fvarx->get_record_type(F.tau_of_varx)|_->None(* -------------------------------------------------------------------------- *)(* --- Array Patterns --- *)(* -------------------------------------------------------------------------- *)letrectypeof_indexak=tryF.typeofkwithNot_found->matchF.reprawith|Qed.Logic.Aset(a,k,_)->typeof_indexak|_->typeof_domainaandtypeof_domaina=matchF.typeofawith|Qed.Logic.Array(t,_)->t|_->raiseNot_foundandtypeof_update(a,k,_)=typeof_indexakletget_array_updatea=matchF.reprawith|Qed.Logic.Aset(a,k,v)->Some(a,k,v)|_->None(* -------------------------------------------------------------------------- *)(* --- Equality Patterns --- *)(* -------------------------------------------------------------------------- *)letarray1upda=lett=trytypeof_domainawithNot_found->typeof_updateupdinArray1(upd,a,t)letarray2pq=lett=trytypeof_updatepwithNot_found->typeof_updateqinArray2(p,q,t)letget_compound_cmpab=matchget_record_termawith|Somefs->Record(a,b,fs)|None->matchget_record_termbwith|Somefs->Record(a,b,fs)|None->matchget_array_updatea,get_array_updatebwith|None,None->raiseNot_found|Someupd,None->array1updb|None,Someupd->array1upda|Somep,Someq->array2pqletget_compound_equalitye=matchF.reprewith|Qed.Logic.Eq(a,b)->true,get_compound_cmpab|Qed.Logic.Neq(a,b)->false,get_compound_cmpab|_->raiseNot_found(* -------------------------------------------------------------------------- *)(* --- Clauses --- *)(* -------------------------------------------------------------------------- *)letfieldabf=Format.asprintf"Field %a"Lang.Field.prettyf,F.p_equal(F.e_getfieldaf)(F.e_getfieldbf)letindex~pooltau=letx=F.freshpooltauin[x],F.e_varxleteqijp=F.p_imply(F.p_equalij)pletneqijp=F.p_imply(F.p_neqij)pletget1akv=F.p_equal(F.e_getak)vletget2abk=F.p_equal(F.e_getak)(F.e_getbk)letclause~pool=function|Record(a,b,fs)->List.map(fieldab)fs|Array1((a,i,u),b,t)->letks,k=index~pooltin["Updated",get1biu;"Others",F.p_forallks(neqik(get2abk))]|Array2((a,i,u),(b,j,v),t)->letks,k=index~pooltin["Updated (both)",eqij(F.p_equaluv);"Updated (left)",neqij(get1ajv);"Updated (right)",neqij(get1biu);"Others",F.p_forallks(neqik(neqjk(get2abk)))](* -------------------------------------------------------------------------- *)(* --- Compound Tactic --- *)(* -------------------------------------------------------------------------- *)letconjcs=F.p_allsndcsletdisjcs=F.p_any(fun(_,p)->F.p_notp)csletnegative(f,p)=f,When(F.p_notp)letnameeq=ifeqthen"eq"else"neq"letkind=functionRecord_->"compound"|Array1_|Array2_->"array"letequalityeq=ifeqthen"equality"else"dis-equality"letprocess_expand(feedback:Tactical.feedback)?ate=letpool=feedback#poolinleteq,cmp=get_compound_equalityeinfeedback#set_title"Compound (%s)"(nameeq);feedback#set_descr"Expand %s %s"(kindcmp)(equalityeq);lete'=(ifeqthenconjelsedisj)(clause~poolcmp)inletcases=[feedback#get_title,F.p_true,e,F.e_prope']inTactical.rewrite?atcasesletprocess_have(feedback:Tactical.feedback)s=letpool=feedback#poolinlete=F.e_prop(Conditions.haves)inleteq,cmp=get_compound_equalityeinifeqthenbeginfeedback#set_title"Compound (eq)";feedback#set_descr"Expand %s equality"(kindcmp);letcases=["Compound (eq)",When(conj(clause~poolcmp))]inTactical.replace~at:s.idcasesendelsebeginfeedback#set_title"Compound (split)";feedback#set_descr"Split %s dis-equality"(kindcmp);letcases=List.mapnegative(clause~poolcmp)inTactical.replace~at:s.idcasesendletprocess_goal(feedback:Tactical.feedback)p=letpool=feedback#poolinleteq,cmp=get_compound_equality(F.e_propp)inifeqthenbeginfeedback#set_title"Compound (split)";feedback#set_descr"Split %s equality"(kindcmp);Tactical.split(clause~poolcmp);endelsebeginfeedback#set_title"Compound (neq)";feedback#set_descr"Expand compound dis-equality";letcases=["Compound (neq)",disj(clause~poolcmp)]inTactical.splitcasesendclasscompound=objectinheritTactical.make~id:"Wp.compound"~title:"Compound"~descr:"Decompose compound equalities"~params:[]methodselectfeedback(s:Tactical.selection)=letprocess=matchswith|Clause(Steps)->process_havefeedbacks|Clause(Goalp)->process_goalfeedbackp|Inside(_,e)->process_expandfeedback?at:(Tactical.ats)e|Empty|Compose_|Multi_->raiseNot_foundinApplicableprocessendlettactical=Tactical.export(newcompound)letstrategy=Strategy.maketactical~arguments:[]