123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)(* -------------------------------------------------------------------------- *)(* --- Base Type for Splitting --- *)(* -------------------------------------------------------------------------- *)openCil_typesopenCil_datatypetypetag=|THENofstmt|ELSEofstmt|CALLofstmt*kernel_function|CASEofstmt*int64list|DEFAULTofstmt|ASSERTofidentified_predicate*int*int(* part *)letprettyfmt=function|THEN_->Format.fprintffmt"Then"|ELSE_->Format.fprintffmt"Else"|CASE(_,[])->Format.fprintffmt"Case(s)"|CASE(_,[k])->Format.fprintffmt"Case %s"(Int64.to_stringk)|CASE(_,k::ks)->Format.fprintffmt"@[Cases %s"(Int64.to_stringk);List.iter(funk->Format.fprintffmt",@,%s"(Int64.to_stringk))ks;Format.fprintffmt"@]"|CALL(_,kf)->Format.fprintffmt"Call %a"Kernel_function.prettykf|DEFAULT_->Format.fprintffmt"Default"|ASSERT(_,k,n)->Format.fprintffmt"Disjunction (%d/%d)"knletloc=function|THENs|ELSEs|CASE(s,_)|CALL(s,_)|DEFAULTs->Stmt.locs|ASSERT(p,_,_)->p.ip_content.tp_statement.pred_locletcomparepq=ifp==qthen0elsematchp,qwith|THENs,THENt->Stmt.comparest|THEN_,_->(-1)|_,THEN_->1|ELSEs,ELSEt->Stmt.comparest|ELSE_,_->(-1)|_,ELSE_->1|CASE(s1,k1),CASE(s2,k2)->letc=Stmt.compares1s2inifc=0thenStdlib.comparek1k2elsec|CASE_,_->(-1)|_,CASE_->1|DEFAULTs,DEFAULTt->Stmt.comparest|DEFAULT_,_->(-1)|_,DEFAULT_->1|CALL(s1,f1),CALL(s2,f2)->letc=Stmt.compares1s2inifc=0thenKernel_function.comparef1f2elsec|CALL_,_->(-1)|_,CALL_->1|ASSERT(ip1,k1,_),ASSERT(ip2,k2,_)->letc=Stdlib.compareip1.ip_idip2.ip_idinifc=0thenk1-k2elsec(* -------------------------------------------------------------------------- *)(* --- Assertion Disjunction --- *)(* -------------------------------------------------------------------------- *)letrecdisjunctionp=tryunwrappwithExit->[p]andunwrapp=matchp.pred_contentwith|Por(a,b)->disjunctiona@disjunctionb|Plet(f,a)->List.map(funq->{pwithpred_content=Plet(f,q)})(unwrapa)|Pexists(qs,p)->List.map(funq->{pwithpred_content=Pexists(qs,q)})(unwrapp)|Pat(p,l)->List.map(funq->{pwithpred_content=Pat(q,l)})(unwrapp)|_->raiseExitletpredicateip=ip.ip_content.tp_statementletrecenumerateipkn=function|[]->[]|p::ps->(ASSERT(ip,k,n),p)::enumerateip(succk)npsletcasesip=tryletps=unwrap(predicateip)inSome(enumerateip1(List.lengthps)ps)withExit->None(* -------------------------------------------------------------------------- *)(* --- Switch Cases --- *)(* -------------------------------------------------------------------------- *)letswitch_casesstmtks=CASE(stmt,ks)letswitch_defaultstmt=DEFAULTstmtletif_thenstmt=THENstmtletif_elsestmt=ELSEstmtletcallstmtkf=CALL(stmt,kf)(* -------------------------------------------------------------------------- *)(* --- Switch Cases --- *)(* -------------------------------------------------------------------------- *)moduleTags=Qed.Listset.Make(structtypet=tagletcompare=compareletequalxy=(comparexy=0)end)moduleM=Qed.Listmap.Make(Tags)moduleI=Map.Make(Tags)type'at='aM.tletreccompactmerge=function|([]|[_])asm->m|((k1,v1)ase)::(((k2,v2)::r)asm)->ifTags.comparek1k2=0thencollectmergek1[v2;v1]relsee::compactmergemandcollectmergekvs=function|[]->[k,mergevs]|((k',v')::r)asm->ifTags.comparekk'=0thencollectmergek(v'::vs)relse(k,mergevs)::compactmergemletbytags(k,_)(k',_)=Tags.comparekk'letapplytagmergem=(* compaction is only required when some split in m already has the tag *)letcompaction=reffalseinletm=List.sortbytags(List.map(fun(tgs,v)->ifnot!compaction&&Tags.memtagtgsthencompaction:=true;Tags.addtagtgs,v)m)inif!compactionthencompactmergemelsem(* let filter phi m = M.filter (fun key _ -> phi key) m *)letlength=List.lengthletempty=[]letsingletone=[[],e]letunmarkmergem=[[],merge(List.mapsndm)]letunionmergem1m2=M.union(fun_->merge)m1m2letrecmerge~left~both~rightm1m2=matchm1,m2with|[],[]->[]|_,[]->List.map(fun(k,v)->k,leftv)m1|[],_->List.map(fun(k,v)->k,rightv)m2|(k1,v1)::w1,(k2,v2)::w2->letcmp=Tags.comparek1k2inifcmp<0then(k1,leftv1)::merge~left~both~rightw1m2elseifcmp>0then(k2,rightv2)::merge~left~both~rightm1w2else(k1,bothv1v2)::merge~left~both~rightw1w2letmerge_allmerge=function|[]->[]|[m]->m|[m1;m2]->M.union(fun_uv->merge[u;v])m1m2|ms->lett=refI.emptyinList.iter(List.iter(fun(k,v)->tryletr=(I.findk!t)inr:=v::!rwithNot_found->t:=I.addk(ref[v])!t))ms;I.fold(funkrm->match!rwith|[]->m|[v]->(k,v)::m|vs->(k,mergevs)::m)!t[]letmap=M.mapletiter=M.iterletfold=M.foldletexistsfxs=List.exists(fun(_,x)->fx)xsletfor_allfxs=List.for_all(fun(_,x)->fx)xsletfilterfxs=List.filter(fun(_,x)->fx)xs