123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Program variables. *)openMopsa_utilsopenTypopenSemanticletprint_uniq_with_uid=reftrue(* force value of print_uniq_with_uid in the computation performed by f *)letforce_print_uniq_with_uid(b:bool)(f:unit->'a):'a=letold=!print_uniq_with_uidinprint_uniq_with_uid:=b;letr=f()inprint_uniq_with_uid:=old;rtypevar_kind=..typemode=|WEAK|STRONGtypevar={vname:string;vkind:var_kind;vtyp:typ;vmode:mode;vsemantic:semantic;}(** Accessor functions *)letvnamev=v.vnameletvkindv=v.vkindletvtypv=v.vtypletvmodev=v.vmodeletvsemanticv=v.vsemanticletmkvnamekind?(mode=STRONG)?(semantic=any_semantic)typ={vname=name;vkind=kind;vtyp=typ;vmode=mode;vsemantic=semantic}(** Internal pretty printer chain over variable kinds *)letvar_pp_chain=TypeExt.mk_print_chain(funfmtv->Format.pp_print_stringfmtv.vname)(** Internal compare chain over variable kinds *)letvar_compare_chain=TypeExt.mk_compare_chain(funv1v2->Stdlib.comparev1.vkindv2.vkind)letpp_modefmt=function|STRONG->Format.fprintffmt"STRONG"|WEAK->Format.fprintffmt"WEAK"letpp_varfmtv=TypeExt.printvar_pp_chainfmtvletcompare_mode(m1:mode)(m2:mode)=comparem1m2letcompare_varv1v2=ifv1==v2then0elseCompare.compose[(fun()->TypeExt.comparevar_compare_chainv1v2);(fun()->compare_typv1.vtypv2.vtyp);(fun()->compare_modev1.vmodev2.vmode);(fun()->compare_semanticv1.vsemanticv2.vsemantic);]letregister_var_comparef=TypeExt.register_comparefvar_compare_chainletregister_var_ppf=TypeExt.register_printfvar_pp_chainletregister_varinfo=TypeExt.registerinfovar_compare_chainvar_pp_chain(*========================================================================*)(** {2 Generation of fresh variables} *)(*========================================================================*)(** Internal counter for fresh variables *)letvcounter=ref0(** Create a fresh variable. Function [f] is given a fresh and unique
identifier. It should return a unique name and a variable kind
*)letmkfresh(f:int->string*var_kind)typ?(mode=STRONG)()=incrvcounter;letname,kind=f!vcounterinmkvnamekind~modetyp(** Temporary fixes for frontends *)letstart_vcounter_at(d:int):unit=assert(!vcounter<=d);vcounter:=dletget_vcounter_val()=!vcounter(*========================================================================*)(** {2 Common kinds of variables} *)(*========================================================================*)typevar_kind+=(** Variables identified by their unique id *)|V_uniqofstring(** Original name *)*int(** Unique ID *)(** Temporary variables *)|V_tmpofint(** Unique ID *)(** Attribute attached to a variable *)|V_var_attrofvar(** Attach variable *)*string(** Attribute *)(** Attribute attached to a range of program location *)|V_range_attrofLocation.range(** Attach range *)*string(** Attribute *)(** Create a fresh temporary variable *)letmk_uniq_varoriguid?(mode=STRONG)typ=letname=orig^":"^(string_of_intuid)inmkvname(V_uniq(orig,uid))~modetyp(** Create a fresh variable with a unique ID *)letmk_fresh_uniq_varorig?(mode=STRONG)typ()=mkfresh(funuid->letname=orig^":"^(string_of_intuid)inname,(V_uniq(orig,uid)))typ~mode()(** Create a fresh temporary variable *)letmktmp?(typ=T_any)?(mode=STRONG)()=mkfresh(funuid->letname="$tmp"^(string_of_intuid)inname,V_tmpuid)typ~mode()(** Create a variable attribute *)letmk_attr_varvattr?(mode=STRONG)?(semantic=any_semantic)typ=letname=v.vname^"."^attrinmkvname(V_var_attr(v,attr))~mode~semantictyp(** Create a program range attribute *)letmk_range_attr_varrangeattr?(mode=STRONG)?(semantic=any_semantic)typ=letname=Format.asprintf"%a.%s"Location.pp_rangerangeattrinmkvname(V_range_attr(range,attr))~mode~semantictyp(** Return the original name of variables with UIDs *)letget_orig_vnamev=matchv.vkindwith|V_uniq(orig,_)->orig|_->v.vname(** Change the original name of variables with UIDs *)letset_orig_vnamenamev=letuid=matchv.vkindwithV_uniq(_,uid)->uid|_->assertfalseinmk_uniq_varnameuidv.vtyp(** Return the weakest mode between m1 and m2 *)letweakest_modem1m2=matchm1,m2with|STRONG,STRONG->STRONG|_->WEAK(** Registration of the common variable kinds *)let()=register_var{compare=(funnextv1v2->matchvkindv1,vkindv2with|V_uniq(orig,uid),V_uniq(orig',uid')->Stdlib.compareuiduid'|V_tmp(uid),V_tmp(uid')->Stdlib.compareuiduid'|V_var_attr(v,attr),V_var_attr(v',attr')->Compare.compose[(fun()->compareattrattr');(fun()->compare_varvv');]|V_range_attr(r,attr),V_range_attr(r',attr')->Compare.compose[(fun()->compareattrattr');(fun()->Location.compare_rangerr');]|_->nextv1v2);print=(funnextfmtv->matchvkindvwith|V_uniq(orig,uid)->if!print_uniq_with_uidthenFormat.fprintffmt"%s:%d"origuidelseFormat.fprintffmt"%s"orig|V_var_attr(v,a)->Format.fprintffmt"%s(%a)"app_varv|V_tmp_|V_range_attr_->Format.pp_print_stringfmtv.vname|_->nextfmtv)}(*========================================================================*)(** {2 Utility modules} *)(*========================================================================*)moduleVarSet=SetExt.Make(structtypet=varletcompare=compare_varend)moduleVarMap=MapExt.Make(structtypet=varletcompare=compare_varend)