123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: 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, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program 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. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** Relation with printing builder *)moduletypeOrderedType=sigtypetvalcompare:t->t->intvalprint:Format.formatter->t->unitendmoduleMake(L:OrderedType)(R:OrderedType)=structexceptionAlready_PairedmoduleLR=MapExt.Make(L)moduleRL=MapExt.Make(R)typet={lr:R.tLR.t;rl:L.tRL.t;}letcompare(e:t)(e':t):int=tryletr=LR.fold(funkvacc->tryletv'=LR.findkaccinifR.comparev'v=0thenLR.removekaccelseraiseExitwith|Not_found->raiseExit)e.lre'.lrinifLR.cardinalr=0then0else-1with|Exit->1letempty={lr=LR.empty;rl=RL.empty}letfold(f:L.t*R.t->'a->'a)(e:t)(a:'a)=LR.fold(funkvacc->f(k,v)acc)e.lraletiter(f:L.t*R.t->unit)(e:t):unit=fold(funpacc->fp)e()letremove_l(l:L.t)(e:t)=tryletb=LR.findle.lrin{lr=LR.removele.lr;rl=RL.removebe.rl}with|Not_found->eletremove_r(r:R.t)(e:t)=tryletl=RL.findre.rlin{lr=LR.removele.lr;rl=RL.removere.rl}with|Not_found->eletadd((l,r):L.t*R.t)(e:t)=tryletr'=LR.findle.lrinifR.comparerr'=0theneelseraiseAlready_Pairedwith|Not_found->{lr=LR.addlre.lr;rl=RL.addrle.rl}letmem((l,r):L.t*R.t)(e:t)=tryletr'=LR.findle.lrinR.comparerr'=0with|Not_found->falseletconcat(e1:t)(e2:t)=letpatchkpvpcomparekv1v2=matchv1,v2with|None,None->None|Somevv,None|None,Somevv->Somevv|Somevv1,Somevv2->ifcomparevv1vv2=0thenSomevv1elseExceptions.panic"Equiva.concat: key %a points to different values %a and %a"kpkvpvv1vpvv2in{lr=LR.merge(patchL.printR.printR.compare)e1.lre2.lr;rl=RL.merge(patchR.printL.printL.compare)e1.rle2.rl;}letmem_l(l:L.t)(e:t)=LR.memle.lrletmem_r(r:R.t)(e:t)=RL.memre.rlletfind_lle=LR.findle.lrletfind_rle=RL.findle.rlletfind_l_opt(l:L.t)(e:t):R.toption=trySome(LR.findle.lr)with|Not_found->Noneletfind_r_opt(r:R.t)(e:t):L.toption=trySome(RL.findre.rl)with|Not_found->Noneletmap(f:(L.t*R.t)->(L.t*R.t))(e:t):t=fold(funpacc->add(fp)acc)eemptyletfilter(f:(L.t*R.t)->bool)(e:t):t=fold(funpacc->iffpthenaddpaccelseacc)eemptyletexists(f:(L.t*R.t)->bool)(e:t):bool=letexceptionFoundOneintryiter(funp->iffpthenraiseFoundOne)e;falsewith|FoundOne->trueletforall(f:(L.t*R.t)->bool)(e:t):bool=letexceptionFoundNotintryiter(funp->ifnot(fp)thenraiseFoundNot)e;truewith|FoundNot->falseend