123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openLogic_ptreeopenCil_typesopenCil_datatype(* -------------------------------------------------------------------------- *)(* --- Region Specifications --- *)(* -------------------------------------------------------------------------- *)typepath=|Aliasoflocation*term_lval|Fieldoflocation*term_lval*fieldinfo*fieldinfo|Rangeoflocation*term*typ*term*termtyperegion={named:string;paths:pathlist;flags:Attr.flags;}(* -------------------------------------------------------------------------- *)(* --- Printers --- *)(* -------------------------------------------------------------------------- *)letpp_namedfmta=ifa<>""thenFormat.fprintffmt"%s: "aletpp_pathfmt=function|Alias(_,lv)->Printer.pp_term_lvalfmtlv|Field(_,lv,f,g)->letfieldlvf=Logic_const.addTermOffsetLval(TField(f,TNoOffset))lvinFormat.fprintffmt"%a..%a"Printer.pp_term_lval(fieldlvf)Printer.pp_term_lval(fieldlvg)|Range(_,p,_,a,b)->Format.fprintffmt"%a[%a..%a]"Printer.pp_termpPrinter.pp_termaPrinter.pp_termbletpp_regionfmtr=matchr.pathswith|[]->Format.pp_print_stringfmt""|p::ps->beginFormat.fprintffmt"@[<hov 2>";pp_namedfmtr.named;pp_pathfmtp;List.iter(Format.fprintffmt",@ %a"pp_path)ps;Attr.iter(Format.fprintffmt",@ \\%a"Attr.pp_attr)r.flags;Format.fprintffmt"@]";endletpp_regionsfmt=function|[]->Format.pp_print_stringfmt""|r::rs->beginFormat.fprintffmt"@[<hv 0>";pp_regionfmtr;List.iter(Format.fprintffmt",@ %a"pp_region)rs;Format.fprintffmt"@]";end(* -------------------------------------------------------------------------- *)(* --- Parsing Environment --- *)(* -------------------------------------------------------------------------- *)typeenv={context:Logic_typing.typing_context;mutableesource:Filepos.t;mutableenamed:string;mutableeflags:Attr.flags;mutablerpaths:pathlist;mutableregions:regionlist;}leterror(env:env)~locmsg=env.context.errorlocmsg(* -------------------------------------------------------------------------- *)(* --- Syntactic Filter --- *)(* -------------------------------------------------------------------------- *)letlrangeenv(e:lexpr)=matche.lexpr_nodewith|PLrange(None,None)->()|_->errorenv~loc:e.lexpr_loc"Range [..] expected"letreclpathenv(e:lexpr)=letloc=e.lexpr_locinmatche.lexpr_nodewith|PLvar_->()|PLdot(p,_)|PLarrow(p,_)|PLunop(Ustar,p)|PLunop(Uamp,p)->lpathenvp|PLbinop(p,Badd,rg)|PLarrget(p,rg)->lpathenvp;lrangeenvrg|PLcast(_,p)->lpathenvp|_->errorenv~loc"Unexpected l-value for region spec"(* -------------------------------------------------------------------------- *)(* --- Parsers --- *)(* -------------------------------------------------------------------------- *)letparse_termenvt=letopenLogic_typinginletg=env.contexting.type_termgg.pre_statetletparse_lvalenvp=lett=parse_termenvpinmatcht.term_nodewith|TLvallv->lv|_->errorenv~loc:p.lexpr_loc"Expected l-value for region path"letparse_integerenvp=letv=parse_termenvpinifnot@@Ast_types.is_logic_integralv.term_typethenerrorenv~loc:p.lexpr_loc"Expected integer term for object bounds";vletparse_pointerenvp=letloc=p.lexpr_locinleta=parse_termenvpinlette=matchAst_types.unroll_logica.term_typewith|Ctype{tnode=TPtrte}->te|_->errorenv~loc"Expected pointer l-value for region object"inte,aletreclast_field=function|TNoOffset|TModel_->raiseNot_found|TField(fd,TNoOffset)->TNoOffset,fd|TField(f0,ofs)->letofs,fd=last_fieldofsinTField(f0,ofs),fd|TIndex(k0,ofs)->letofs,fd=last_fieldofsinTIndex(k0,ofs),fdletparse_fieldenvp=tryleth,ofs=parse_lvalenvpinletofs,fd=last_fieldofsinifnotfd.fcomp.cstructthenerrorenv~loc:p.lexpr_loc"Expected struct field for range path";(h,ofs),fdwithNot_found->errorenv~loc:p.lexpr_loc"Expected field l-value for range path"letgarbage=Attr.(add`Garbageempty)letappliesflags=function|Range_->true|Alias(_,(TVar{lv_origin=Somev},_))->flags=garbage&&v.vformal&&Ast_types.is_struct_or_unionv.vtype|Alias_|Field_->falseletflushsourceenv=ifenv.eflags<>Attr.empty&¬@@List.exists(appliesenv.eflags)env.rpathsthenOptions.warning~source:env.esource"%a has no object to apply on"Attr.prettyenv.eflags;ifenv.rpaths<>[]thenbeginenv.regions<-{named=env.enamed;flags=env.eflags;paths=List.revenv.rpaths;}::env.regions;env.esource<-source;env.rpaths<-[];env.eflags<-Attr.empty;endletrecparse_region(env:env)p=matchp.lexpr_nodewith|PLvar"\\nullable"->env.eflags<-Attr.add`Nullableenv.eflags|PLvar"\\allocated"->env.eflags<-Attr.add`Allocatedenv.eflags|PLvar"\\garbage"->env.eflags<-Attr.add`Garbageenv.eflags|PLvar"\\readonly"->env.eflags<-Attr.add`Readonlyenv.eflags|PLnamed(name,p)->flush(fstp.lexpr_loc)env;env.enamed<-name;parse_regionenvp|PLrange(Somea,Someb)->letl1,f=parse_fieldenvainletl2,g=parse_fieldenvbinifnot(Term_lval.equall1l2)thenerrorenv~loc:p.lexpr_loc"Field range from different region paths";env.rpaths<-Field(p.lexpr_loc,l1,f,g)::env.rpaths|PLarrget(p,{lexpr_node=PLrange(Somea,Someb)})->lette,q=parse_pointerenvpinleta=parse_integerenvainletb=parse_integerenvbinenv.rpaths<-Range(p.lexpr_loc,q,te,a,b)::env.rpaths|PLunop(Ustar,p)->lette,q=parse_pointerenvpinletzero=Logic_const.tinteger~loc:p.lexpr_loc0inenv.rpaths<-Range(p.lexpr_loc,q,te,zero,zero)::env.rpaths|_->letlv=lpathenvp;parse_lvalenvpinenv.rpaths<-Alias(p.lexpr_loc,lv)::env.rpaths(* -------------------------------------------------------------------------- *)(* --- Spec Typechecking & Printing --- *)(* -------------------------------------------------------------------------- *)letkspec=ref0letregistry=Hashtbl.create0letof_extidid=tryHashtbl.findregistryidwithNot_found->[]letof_extension=function|{ext_name="region";ext_kind=Ext_idk}->of_extidk|_->[]letof_code_annot=function|{annot_content=AExtended(_,_,e)}->of_extensione|_->[]letof_behaviorbhv=List.concat_mapof_extensionbhv.b_extendedlettypechecktyping_contextlocps=letenv={esource=fstloc;enamed="";eflags=Attr.empty;context=typing_context;rpaths=[];regions=[];}inList.iter(parse_regionenv)ps;letid=!kspecinincrkspec;flush(fstloc)env;Hashtbl.addregistryid@@List.revenv.regions;Ext_ididletprinter_ppfmt=function|Ext_idk->letrs=tryHashtbl.findregistrykwithNot_found->[]inpp_regionsfmtrs|_->()let()=beginAcsl_extension.register_behavior~plugin:"region""region"typecheck~printerfalse;Acsl_extension.register_code_annot~plugin:"region""alias"typecheck~printerfalse;end(* -------------------------------------------------------------------------- *)