123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)(* -------------------------------------------------------------------------- *)(* --- Pretty Printer with sharing --- *)(* -------------------------------------------------------------------------- *)openLogicopenFormatopenPlibmoduleMake(T:Term)=structopenT(* -------------------------------------------------------------------------- *)(* --- Types --- *)(* -------------------------------------------------------------------------- *)letpp_tvarnfmtn=fprintffmt"?%d"nletpp_alphafmt=function|0->pp_print_stringfmt"'a"|1->pp_print_stringfmt"'b"|2->pp_print_stringfmt"'c"|3->pp_print_stringfmt"'d"|4->pp_print_stringfmt"'e"|n->fprintffmt"?%d"(n-4)letpp_taufmtt=letn=Kind.degree_of_tautinif0<=n&&n<5thenKind.pp_taupp_alphaField.prettyADT.prettyfmttelseKind.pp_taupp_tvarnField.prettyADT.prettyfmtt(* -------------------------------------------------------------------------- *)(* --- Shareable --- *)(* -------------------------------------------------------------------------- *)letshareablee=matchT.reprewith|And_|Or_|Not_|Imply_|Eq_|Neq_|Leq_|Lt_->false|Fun(f,_)->(Fun.sortf<>Sprop&&Fun.sortf<>Sbool)|_->trueletsubtermsfe=matchT.reprewith|Rdeffts->beginmatchT.record_withftswith|None->T.lc_iterfe|Some(a,fts)->fa;List.iter(fun(_,e)->fe)ftsend|_->T.lc_iterfe(* -------------------------------------------------------------------------- *)(* --- Variables --- *)(* -------------------------------------------------------------------------- *)moduleIdx=Map.Make(String)moduleIds=Set.Make(String)typeenv={mutablebound:stringIntmap.t;(* bound var *)mutablenamed:stringTmap.t;(* named terms *)mutableindex:intIdx.t;(* index names *)mutableknown:Ids.t;(* known names *)}(* -------------------------------------------------------------------------- *)(* --- Environment --- *)(* -------------------------------------------------------------------------- *)letempty={bound=Intmap.empty;named=Tmap.empty;index=Idx.empty;known=Ids.empty;}letcopyenv={bound=env.bound;named=env.named;index=env.index;known=env.known;}(* -------------------------------------------------------------------------- *)(* --- Fresh --- *)(* -------------------------------------------------------------------------- *)letfreshnameenvbase=letrecscanenvbasek=leta=Printf.sprintf"%s_%d"basekinifIds.memaenv.knownthenscanenvbase(succk)else(env.index<-Idx.addbase(succk)env.index;a)inscanenvbase(tryIdx.findbaseenv.indexwithNot_found->0)letknownenvxs=letenv=copyenvinVars.iter(funx->letx=Plib.to_stringVar.prettyxinenv.known<-Ids.addxenv.known)xs;envletmarksenv=T.marks~shareable~subterms~shared:(funt->Tmap.memtenv.named)()letbindxtenv=letenv=copyenvinenv.named<-Tmap.addtxenv.named;env.known<-Ids.addxenv.known;envletfreshenvt=letenv=copyenvinletx=freshnameenv(T.basenamet)inenv.named<-Tmap.addtxenv.named;env.known<-Ids.addxenv.known;x,envletbind_varenvkt=letx=freshnameenv(Tau.basenamet)inenv.known<-Ids.addxenv.known;env.bound<-Intmap.addkxenv.bound;xletfind_varenvk=tryIntmap.findkenv.boundwithNot_found->Printf.sprintf"#%d"k(* -------------------------------------------------------------------------- *)(* --- Groups of Quantifiers --- *)(* -------------------------------------------------------------------------- *)moduleTauMap=Map.Make(T.Tau)letgroup_vartk=TauMap.addt[k]TauMap.emptyletgroup_addtktks=letks=k::tryTauMap.findttkswithNot_found->[]inTauMap.addtkstksletrecgroup_bindersk=function|[]->[]|(q,t)::qts->group_collectq(succk)(group_vartk)qtsandgroup_collectqkkts=function|[]->[q,kts]|(q0,t)::qts->ifq=q0&&q0<>Lambdathengroup_collectq(succk)(group_addtkkts)qtselse(q,kts)::group_collectq0(succk)(group_vartk)qts(* -------------------------------------------------------------------------- *)(* --- Output Form --- *)(* -------------------------------------------------------------------------- *)typeout=|Sumoftermlist|Atomofstring|Hboxofstring*termlist|Vboxofstring*termlist|Unopofstring*term|Binopof(term*string*term)|Condof(term*term*term)|CallofFun.t*termlist|Closureofterm*termlist|Constofterm|Accessofterm*term|Updateofterm*term*term|Recordoffieldlist|GetFieldofterm*Field.t|Abstractionof(binder*tau)list*term|Bindofintandfield=|Withofterm|FieldofField.t*term|LastofField.t*termletrecfields=function|[]->[]|[f,v]->[Last(f,v)]|(f,v)::fvs->Field(f,v)::fieldsfvsletrecabstractionqxse=matchT.reprewith|Logic.Bind(q,x,t)->abstraction((q,x)::qxs)(lc_reprt)|_->Abstraction(List.revqxs,e)letoute=matchT.reprewith|Bvar(k,_)->Bindk|Fvarx->Atom(Plib.to_stringVar.prettyx)|True->Atom"true"|False->Atom"false"|Kintz->Atom(Z.to_stringz)|Krealr->Atom(Q.to_stringr)|Times(z,e)whenZ.equalzZ.minus_one->Unop("-",e)|Times(z,e)->Hbox("*",[e_zintz;e])|Addes->Sumes|Mules->Hbox("*",es)|Div(a,b)->Binop(a,"div",b)|Mod(a,b)->Binop(a,"mod",b)|Andes->Vbox("/\\",es)|Ores->Vbox("\\/",es)|Note->Unop("not ",e)|Imply(hs,p)->Vbox("->",hs@[p])|Eq(a,b)->ifT.sorte=SpropthenVbox("<->",[a;b])elseHbox("=",[a;b])|Lt(a,b)->Hbox("<",[a;b])|Neq(a,b)->Hbox("!=",[a;b])|Leq(a,b)->Hbox("<=",[a;b])|Fun(a,es)->Call(a,es)|Apply(e,es)->Closure(e,es)|If(c,a,b)->Cond(c,a,b)|Acst(_,v)->Const(v)|Aget(a,b)->Access(a,b)|Aset(a,b,c)->Update(a,b,c)|Logic.Bind(q,x,e)->abstraction[q,x](lc_repre)|Rget(e,f)->GetField(e,f)|Rdeffvs->RecordbeginmatchT.record_withfvswith|None->fieldsfvs|Some(base,fothers)->Withbase::fieldsfothersendletnamed_outenve=tryAtom(Tmap.findeenv.named)withNot_found->oute(* -------------------------------------------------------------------------- *)(* --- Atom printer --- *)(* -------------------------------------------------------------------------- *)letrecpp_atom(env:env)(fmt:formatter)e=pp_atom_outenvfmt(named_outenve)andpp_atom_outenvfmt=function|Bindk->pp_print_stringfmt(find_varenvk)|Atomx->pp_print_stringfmtx|Call(f,es)->pp_callenvfmtfes|Sumes->fprintffmt"@[<hov 1>(%a)@]"(pp_sumfalseenv)es|Hbox(op,es)->fprintffmt"@[<hov 1>(%a)@]"(pp_hboxenvop)es|Vbox(op,es)->fprintffmt"@[<hov 1>(%a)@]"(pp_vboxenvop)es|Unop(op,e)->fprintffmt"@[<hov 3>(%s%a)@]"op(pp_atomenv)e|Binopop->fprintffmt"@[<hov 3>(%a)@]"(pp_binopenv)op|Condc->fprintffmt"@[<hv 1>(%a)@]"(pp_condenv)c|Closure(e,es)->pp_closureenvfmtees|Abstraction(qts,abs)->fprintffmt"@[<v 1>(%t)@]"(pp_abstractionenvqtsabs)|Const(v)->fprintffmt"@[<hov 2>[%a..]@]"(pp_freeenv)v|Access(a,b)->fprintffmt"@[<hov 2>%a@,[%a]@]"(pp_atomenv)a(pp_freeenv)b|Update(a,b,c)->fprintffmt"@[<hov 2>%a@,[%a@,->%a]@]"(pp_atomenv)a(pp_atomenv)b(pp_freeenv)c|GetField(e,f)->fprintffmt"%a.%a"(pp_atomenv)eField.prettyf|Recordfs->pp_fieldsenvfmtfsandpp_free_outenvfmt=function|Bindk->pp_print_stringfmt(find_varenvk)|Atomx->pp_print_stringfmtx|Call(f,es)->pp_callenvfmtfes|Sumes->fprintffmt"@[<hov 1>%a@]"(pp_sumtrueenv)es|Hbox(op,es)->fprintffmt"@[<hov 0>%a@]"(pp_hboxenvop)es|Vbox(op,es)->fprintffmt"@[<hov 0>%a@]"(pp_vboxenvop)es|Unop(op,e)->fprintffmt"@[<hov 2>%s%a@]"op(pp_atomenv)e|Binopop->fprintffmt"@[<hov 2>%a@]"(pp_binopenv)op|Condc->fprintffmt"@[<hv 0>%a@]"(pp_condenv)c|Closure(e,es)->pp_closureenvfmtees|Abstraction(qts,abs)->fprintffmt"@[<hv 0>%t@]"(pp_abstractionenvqtsabs)|(Const_|Access_|Update_|Record_|GetField_)asa->pp_atom_outenvfmtaandpp_fields(env:env)(fmt:formatter)fs=fprintffmt"@[<hv 0>{@[<hv 2>";List.iter(function|Withr->fprintffmt"@ %a with"(pp_atomenv)r|Field(f,v)->fprintffmt"@ @[<hov 2>%a =@ %a ;@]"Field.prettyf(pp_freeenv)v|Last(f,v)->fprintffmt"@ @[<hov 2>%a =@ %a@]"Field.prettyf(pp_freeenv)v)fs;fprintffmt"@]@ }@]"(* -------------------------------------------------------------------------- *)(* --- Free printer --- *)(* -------------------------------------------------------------------------- *)andpp_free(env:env)(fmt:formatter)e=pp_free_outenvfmt(named_outenve)andpp_freedef(env:env)(fmt:formatter)e=pp_free_outenvfmt(oute)(* -------------------------------------------------------------------------- *)(* --- Call printer --- *)(* -------------------------------------------------------------------------- *)andpp_call(env:env)(fmt:formatter)f=function|[]->Fun.prettyfmtf|es->fprintffmt"@[<hov 2>(%a"Fun.prettyf;List.iter(fune->fprintffmt"@ %a"(pp_atomenv)e)es;fprintffmt")@]"(* -------------------------------------------------------------------------- *)(* --- Sum printer --- *)(* -------------------------------------------------------------------------- *)andpp_sumfree(env:env)(fmt:formatter)es=letps,ns=List.fold_right(fune(ps,ns)->matchT.reprewith|Times(k,n)whenZ.equalkZ.minus_one->(ps,n::ns)|KintkwhenZ.ltkZ.zero->(ps,e_zint(Z.negk)::ns)|KrealrwhenQ.ltrQ.zero->(ps,e_real(Q.negr)::ns)|_->e::ps,ns)es([],[])inmatchps,nswith|[],[]->pp_print_stringfmt"0"|[],_->iffreethenfprintffmt"(%a)"(pp_factorenv"-")nselsepp_factorenv"-"fmtns|p::ps,ns->fprintffmt"%a%a%a"(pp_atomenv)p(pp_factorenv"+")ps(pp_factorenv"-")nsandpp_factorenvopfmtes=List.iter(fune->fprintffmt"%s@,%a"op(pp_atomenv)e)es(* -------------------------------------------------------------------------- *)(* --- Horizontal Boxes --- *)(* -------------------------------------------------------------------------- *)andpp_hbox(env:env)(sep:string)(fmt:formatter)=function|[]->pp_print_stringfmt"()"|e::es->fprintffmt"%a%a"(pp_atomenv)e(pp_factorenvsep)es(* -------------------------------------------------------------------------- *)(* --- Vertical Boxes --- *)(* -------------------------------------------------------------------------- *)andpp_vbox(env:env)(sep:string)(fmt:formatter)=function|[]->()|e::es->pp_atomenvfmte;List.iter(fune->fprintffmt"@ %s %a"sep(pp_atomenv)e)es(* -------------------------------------------------------------------------- *)(* --- Specific Operators --- *)(* -------------------------------------------------------------------------- *)andpp_binop(env:env)(fmt:formatter)(a,op,b)=fprintffmt"%a@ %s %a"(pp_atomenv)aop(pp_atomenv)bandpp_cond(env:env)(fmt:formatter)(c,a,b)=fprintffmt"if %a@ then %a@ else %a"(pp_atomenv)c(pp_atomenv)a(pp_atomenv)bandpp_closure(env:env)(fmt:formatter)ees=fprintffmt"@[<hov 3>(%a"(pp_atomenv)e;List.iter(fune->fprintffmt"@ %a"(pp_atomenv)e)es;fprintffmt")@]"(* -------------------------------------------------------------------------- *)(* --- Abstraction --- *)(* -------------------------------------------------------------------------- *)andpp_abstraction(env:env)qtsabs(fmt:formatter)=letenv=copyenvinletgroups=group_binders0qtsinletsize=List.lengthqtsinletlast=Bvars.order(lc_varsabs)+size-1inList.iter(fun(q,m)->matchqwith|Forall->fprintffmt"@[<hov 4>forall %a.@]@ "(pp_groupenvlast)m|Exists->fprintffmt"@[<hov 4>exists %a.@]@ "(pp_groupenvlast)m|Lambda->fprintffmt"@[<hov 4>fun %a ->@]@ "(pp_groupenvlast)m)groups;pp_shareenvfmtabsandpp_group(env:env)(last:int)(fmt:formatter)m=letsep=reffalseinTauMap.iter(funtks->if!septhenfprintffmt",@,";Plib.iteri(funidxk->letx=bind_varenv(last-k)tinmatchidxwith|Isingle|Ifirst->pp_print_stringfmtx|Imiddle|Ilast->fprintffmt",@,%s"x)(List.revks);fprintffmt":%a"pp_taut;sep:=true;)m(* -------------------------------------------------------------------------- *)(* --- Sharing --- *)(* -------------------------------------------------------------------------- *)andpp_share(env:env)(fmt:formatter)t=beginfprintffmt"@[<hv 0>";letsharedt=Tmap.memtenv.namedinletts=T.shared~shareable~shared~subterms[t]inletenv=List.fold_left(funenvt->letx,env_x=freshenvtinfprintffmt"@[<hov 4>let %s =@ %a in@]@ "x(pp_atomenv)t;env_x)envtsinpp_freeenvfmtt;fprintffmt"@]";end(* -------------------------------------------------------------------------- *)(* --- Entry Point --- *)(* -------------------------------------------------------------------------- *)letpp_term_env(env:env)(fmt:formatter)t=pp_shareenvfmttletpp_def_env(env:env)(fmt:formatter)t=pp_freedefenvfmttletpp_term(env:env)(fmt:formatter)t=pp_term_env(copyenv)fmttletpp_def(env:env)(fmt:formatter)t=pp_def_env(copyenv)fmttend