123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)(* -------------------------------------------------------------------------- *)(* --- Model Registry --- *)(* -------------------------------------------------------------------------- *)typemodel={id:string;(* Identifier Basename for Model (unique) *)descr:string;(* Title of the Model (for pretty) *)emitter:Emitter.t;hypotheses:hypotheses;configure:(unit->rollback);}androllback=(unit->unit)andscope=Global|KfofKernel_function.tandhypotheses=MemoryContext.partition->MemoryContext.partitionandcontext=model*scopeandt=contextletnohyp(_kf)=MemoryContext.emptymoduleMODEL=structtypet=modelletida=a.idletdescra=a.descrlethasha=Hashtbl.hasha.idletequalab=String.equala.idb.idletcompareab=String.comparea.idb.idletrepr={id="?model";descr="?model";emitter=Emitter.kernel;configure=(fun()->(fun()->()));hypotheses=nohyp;}endmoduleMINDEX=Hashtbl.Make(MODEL)moduleMODELS=structmoduleH=Datatype.String.Mapleth=refH.empty(* NOT PROJECTIFIED : Models are defined at Plugin load-time,
for all projects *)letmemid=H.memid!hletaddm=h:=H.addm.idm!hendletregister~id?(descr=id)~configure?(hypotheses=nohyp)()=ifMODELS.memidthenWp_parameters.fatal"Duplicate model '%s'"id;letemitter=lete_name="Wp."^idinletcorrectness=[]inlettuning=[Wp_parameters.Provers.parameter]inEmitter.createe_name[Emitter.Property_status]~correctness~tuninginletmodel={id=id;descr;emitter;configure;hypotheses;}inMODELS.addmodel;modelletget_descrm=m.descrletget_emitterm=m.emittermoduleSCOPE=structtypet=scopeletid=function|Global->"__frama_c_global"|Kff->Kernel_function.get_namefletcomparefg=matchf,gwith|Global,Global->0|Global,_->(-1)|_,Global->1|Kff,Kfg->Kernel_function.comparefgletequalfg=(comparefg=0)lethash=functionGlobal->0|Kfkf->Kernel_function.hashkfendmoduleS=structtypet=contextletid(model,scope)=matchscopewith|Global->model.id|Kfkf->Printf.sprintf"%s_%s"model.id(Kernel_function.get_namekf)lethash(m,s)=matchswith|Global->2*MODEL.hashm|Kfkf->3*MODEL.hashm+5*Kernel_function.hashkfletequal(m1,s1)(m2,s2)=MODEL.equalm1m2&&SCOPE.equals1s2letcompare(m1,s1)(m2,s2)=letcmp=MODEL.comparem1m2inifcmp<>0thencmpelseSCOPE.compares1s2endletcontext:(string*context)Context.value=Context.create"WpContext"letconfigure(model,_)=model.configure()leton_contextgammafx=letid=S.idgammainletcurrent=Context.pushcontext(id,gamma)inletrollback=tryconfiguregammawith_->Kernel.fatal"Model configuration failed"inContext.configure();tryletresult=fxinContext.popcontextcurrent;rollback();resultwitherr->Context.popcontextcurrent;rollback();raiseerrletis_defined()=Context.definedcontextletget_ident()=Context.getcontext|>fstletget_context()=Context.getcontext|>sndletget_model()=get_context()|>fstletget_scope()=get_context()|>sndletcompute_hypothesesmf=on_context(m,Kff)m.hypothesesMemoryContext.emptyletdirectory()=get_model()|>MODEL.id|>Wp_parameters.get_output_dirmoduletypeEntries=sigtypekeytypedatavalname:stringvalcompare:key->key->intvalpretty:Format.formatter->key->unitendmoduletypeRegistry=sigmoduleE:Entriestypekey=E.keytypedata=E.datavalid:basename:string->key->stringvalmem:key->boolvalfind:key->datavalget:key->dataoptionvalclear:unit->unitvalremove:key->unitvaldefine:key->data->unitvalupdate:key->data->unitvalmemoize:(key->data)->key->datavalcompile:(key->data)->key->unitvalcallback:(key->data->unit)->unitvaliter:(key->data->unit)->unitvaliter_sorted:(key->data->unit)->unitendlettypes=Hashtbl.create8letfreetypea=tryletn=Hashtbl.findtypesainHashtbl.replacetypesa(succn);Printf.sprintf"%s#%d"anwithNot_found->Hashtbl.addtypesa1;amoduleNAMES=Map.Make(String)moduleIndex(E:Entries)=structmoduleE=Etypekey=E.keytypedata=E.datamoduleKEY=structtypet=E.keyletcompare=E.compareendmoduleMAP=Map.Make(KEY)moduleSET=Set.Make(KEY)letdemon=ref[]typeentries={mutableindex:E.dataMAP.t;mutableident:stringMAP.t;mutablenames:intNAMES.t;mutablelock:SET.t;}letcreate()={index=MAP.empty;ident=MAP.empty;names=NAMES.empty;lock=SET.empty;}moduleENTRIES:Datatype.Swithtypet=entries=Datatype.Make(structtypet=entriesincludeDatatype.Undefinedletmem_project=Datatype.never_any_projectletreprs=[create()]letname=freetype("Wp.Context.Index."^E.name)end)moduleREGISTRY=State_builder.Hashtbl(Datatype.String.Hashtbl)(ENTRIES)(structletname=freetype("Wp.Context."^E.name)letdependencies=[Ast.self]letsize=32end)(* Projectified entry map, indexed by model *)letentries():entries=letcid=get_ident()intryREGISTRY.findcidwithNot_found->lete=create()inREGISTRY.addcide;eletclear()=beginlete=entries()ine.index<-MAP.empty;e.lock<-SET.empty;endletremovek=beginlete=entries()ine.index<-MAP.removeke.index;e.lock<-SET.removeke.lock;endletmemk=lete=entries()inMAP.memke.index||SET.memke.lockletfindk=lete=entries()inMAP.findke.indexletgetk=trySome(findk)withNot_found->Noneletid~basenamek=beginlete=entries()intryMAP.findke.identwithNot_found->letkid,id=tryletkid=succ(NAMES.findbasenamee.names)inkid,Printf.sprintf"%s_%d"basenamekidwithNot_found->0,basenameine.names<-NAMES.addbasenamekide.names;e.ident<-MAP.addkide.ident;idendletfirekd=List.iter(funf->fkd)!demonletcallbackf=demon:=!demon@[f]letdefinekd=beginlete=entries()inifMAP.memke.indexthenWp_parameters.fatal"Duplicate definition (%s:%a)"E.nameE.prettyk;ifSET.memke.lockthenWp_parameters.fatal"Locked definition (%s:%a)"E.nameE.prettyk;e.index<-MAP.addkde.index;firekd;endletupdatekd=beginlete=entries()ine.index<-MAP.addkde.index;firekd;endletmemoizefk=lete=entries()intryMAP.findke.indexwithNot_found->letlock=e.lockine.lock<-SET.addke.lock;letd=fkine.index<-MAP.addkde.index;firekd;e.lock<-lock;d(* in case of exception, the entry remains intentionally locked *)letcompilefk=ignore(memoizefk)letiterf=MAP.iterf(entries()).indexletiter_sortedf=lete=entries()inlets=MAP.fold(funk_s->SET.addks)e.indexSET.emptyinSET.iter(funk->fk(MAP.findke.index))sendmoduleStatic(E:Entries)=structmoduleE=Etypekey=E.keytypedata=E.datamoduleKEY=structtypet=E.keyletcompare=E.compareendmoduleMAP=Map.Make(KEY)moduleSET=Set.Make(KEY)letdemon=ref[]typeentries={mutableindex:E.dataMAP.t;mutableident:stringMAP.t;mutablenames:intNAMES.t;mutablelock:SET.t;}letcreate()={index=MAP.empty;ident=MAP.empty;names=NAMES.empty;lock=SET.empty;}moduleENTRIES:Datatype.Swithtypet=entries=Datatype.Make(structtypet=entriesincludeDatatype.Undefinedletreprs=[create()]letname="Wp.Context.Index."^E.nameletmem_project=Datatype.never_any_projectend)moduleREGISTRY=State_builder.Ref(ENTRIES)(structletname="Wp.Context."^E.nameletdependencies=[Ast.self]letdefault=createend)(* Projectified entry map *)letentries():entries=REGISTRY.get()letclear()=beginlete=entries()ine.index<-MAP.empty;e.lock<-SET.empty;endletremovek=beginlete=entries()ine.index<-MAP.removeke.index;e.lock<-SET.removeke.lock;endletmemk=lete=entries()inMAP.memke.index||SET.memke.lockletfindk=lete=entries()inMAP.findke.indexletgetk=trySome(findk)withNot_found->Noneletid~basenamek=beginlete=entries()intryMAP.findke.identwithNot_found->letkid,id=tryletkid=succ(NAMES.findbasenamee.names)inkid,Printf.sprintf"%s_%d"basenamekidwithNot_found->0,basenameine.names<-NAMES.addbasenamekide.names;e.ident<-MAP.addkide.ident;idendletfirekd=List.iter(funf->fkd)!demonletcallbackf=demon:=!demon@[f]letdefinekd=beginlete=entries()inifMAP.memke.indexthenWp_parameters.fatal"Duplicate definition (%s:%a)"E.nameE.prettyk;ifSET.memke.lockthenWp_parameters.fatal"Locked definition (%s:%a)"E.nameE.prettyk;e.index<-MAP.addkde.index;firekd;endletupdatekd=beginlete=entries()ine.index<-MAP.addkde.index;firekd;endletmemoizefk=lete=entries()intryMAP.findke.indexwithNot_found->letlock=e.lockine.lock<-SET.addke.lock;letd=fkine.index<-MAP.addkde.index;firekd;e.lock<-lock;d(* in case of exception, the entry remains intentionally locked *)letcompilefk=ignore(memoizefk)letiterf=MAP.iterf(entries()).indexletiter_sortedf=lete=entries()inlets=MAP.fold(funk_s->SET.addks)e.indexSET.emptyinSET.iter(funk->fk(MAP.findke.index))sendmoduletypeKey=sigtypetvalcompare:t->t->intvalpretty:Format.formatter->t->unitendmoduletypeData=sigtypekeytypedatavalname:stringvalcompile:key->dataendmoduletypeIData=sigtypekeytypedatavalname:stringvalbasename:key->stringvalcompile:key->string->dataendmoduletypeGenerator=sigtypekeytypedatavalmem:key->boolvalget:key->datavalset:key->data->unitvalremove:key->unitvalclear:unit->unitendmoduleStaticGenerator(K:Key)(D:Datawithtypekey=K.t)=structmoduleG=Static(structincludeKincludeDend)typekey=D.keytypedata=D.dataletget=G.memoizeD.compileletset=G.updateletmem=G.memletclear=G.clearletremove=G.removeendmoduleGenerator(K:Key)(D:Datawithtypekey=K.t)=structmoduleG=Index(structincludeKincludeDend)typekey=D.keytypedata=D.dataletget=G.memoizeD.compileletset=G.updateletmem=G.memletclear=G.clearletremove=G.removeendmoduleGeneratorID(K:Key)(D:IDatawithtypekey=K.t)=structmoduleG=Index(structincludeKincludeDend)typekey=D.keytypedata=D.dataletget=G.memoize(funk->D.compilek(G.id~basename:(D.basenamek)k))letset=G.updateletmem=G.memletclear=G.clearletremove=G.removeendmoduleStaticGeneratorID(K:Key)(D:IDatawithtypekey=K.t)=structmoduleG=Static(structincludeKincludeDend)typekey=D.keytypedata=D.dataletget=G.memoize(funk->D.compilek(G.id~basename:(D.basenamek)k))letset=G.updateletmem=G.memletclear=G.clearletremove=G.removeend