123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Print - pretty-printing of expressions values *)openMopsa_utilsopenAst.VaropenAst.ExpropenYojson.BasicmoduleMap=MapExtPolymoduleSet=SetExtPoly(****************************************************************************)(** {1 Print objects} *)(****************************************************************************)typesymbols={sopen:string;ssep:string;sbind:string;sclose:string;}type('k,'v)map=('k,'v)Map.ttype'vset='vSet.ttypeprint_object=|Empty|Boolofbool|IntofZ.t|Floatoffloat|Stringofstring|Varofvar|Mapof(print_object,print_object)map*symbols|Listofprint_objectlist*symbols|Setofprint_objectset*symbolsletdefault_map_symbols={sopen="";ssep=",";sclose="";sbind=":"}letdefault_list_symbols={sopen="[";ssep=",";sclose="]";sbind=""}letdefault_set_symbols={sopen="{";ssep=",";sclose="}";sbind=""}letreccompare_print_objecto1o2=matcho1,o2with|Empty,Empty->0|Boolb1,Boolb2->compareb1b2|Intn1,Intn2->Z.comparen1n2|Floatf1,Floatf2->comparef1f2|Strings1,Strings2->String.compares1s2|Varv1,Varv2->compare_varv1v2|Map(m1,_),Map(m2,_)->Map.comparecompare_print_objectm1m2|List(l1,_),List(l2,_)->Compare.listcompare_print_objectl1l2|Set(s1,_),Set(s2,_)->Set.compares1s2|_->compareo1o2(****************************************************************************)(** {1 Printers} *)(****************************************************************************)typeprinter={mutablebody:print_object;mutableprev_exprs:ExprSet.t;}letget_printed_objectprinter=printer.bodyletempty_printer()={body=Empty;prev_exprs=ExprSet.empty}letget_printed_exprsprinter=ExprSet.elementsprinter.prev_exprsletadd_printed_exprprinterexp=printer.prev_exprs<-ExprSet.addexpprinter.prev_exprsletmem_printed_exprprinterexp=ExprSet.memexpprinter.prev_exprs(****************************************************************************)(** {1 Print paths} *)(****************************************************************************)typeprint_selector=|Keyofstring|Indexofint|Objofprint_objecttypeprint_path=print_selectorlistletrecfind_print_objectpathobj=matchpath,objwith|[],_->obj(* Maps *)|Keyk::tl,Map(m,_)->find_print_objecttl(Map.find(Stringk)m)|Keyk::tl,Empty->Empty|Key_::_,_->Exceptions.panic"find_print_object: key selector on non-map object"|Objo::tl,Map(m,_)->find_print_objecttl(Map.findom)|Objo::tl,Empty->Empty|Obj_::_,_->Exceptions.panic"find_print_object: obj selector on non-map object"(* Lists *)|Indexi::tl,List(l,_)->begintryfind_print_objecttl(List.nthli)withFailure_->raiseNot_foundend|Indexi::tl,Empty->Empty|Index_::_,_->Exceptions.panic"find_print_object: index selector on non-list object"letrecmatch_print_object_keysreobj=matchobjwith|Map(map,sym)->letmap'=Map.fold(funkvacc->matchkwith|Strings->ifStr.string_matchres0thenMap.addkvaccelseacc|_->acc)map(Map.empty~compare:compare_print_object)inifMap.is_emptymap'thenEmptyelseMap(map',sym)|List(list,sym)->letlist'=List.fold_left(funaccv->letv'=match_print_object_keysrevinmatchv'with|Empty->acc|_->v'::acc)[]listiniflist'=[]thenEmptyelseList(List.revlist',sym)|Set(set,sym)->letset'=Set.fold(funvacc->letv'=match_print_object_keysrevinmatchv'with|Empty->acc|_->Set.addv'acc)set(Set.emptycompare_print_object)inifSet.is_emptyset'thenEmptyelseSet(set',sym)|Empty|Int_|Bool_|Float_|String_|Var_->obj(****************************************************************************)(** {1 Generic print functions} *)(****************************************************************************)letrecis_leaf=function|Empty|Bool_|Int_|Float_|String_|Var_->true|Map_->false|List(l,_)->List.for_allis_leafl|Set(s,_)->Set.for_allis_leafsletrecis_atomic=function|Empty|Bool_|Int_|Float_|String_|Var_->true|_->falseletis_empty=function|Empty->true|_->falseletrecpp_print_objectfmt=function|Empty->()|Boolb->Format.pp_print_boolfmtb|Intn->Z.pp_printfmtn|Floatf->Format.pp_print_floatfmtf|Strings->Format.pp_print_stringfmts|Varv->pp_varfmtv|Map(m,sym)->letsopen=ifsym.sopen=""then""elsesym.sopen^" "inletsclose=ifsym.sclose=""then""else" "^sym.scloseinFormat.(fprintffmt"%s @[<v>%a@] %s"sopen(pp_print_list~pp_sep:(funfmt()->fprintffmt"%s@ "sym.ssep)(funfmt(k,v)->ifis_leafvthenfprintffmt"@[<hov2>%a %s @,%a@]"pp_print_objectksym.sbindpp_print_objectvelsefprintffmt"@[<v2>%a %s @,%a@]"pp_print_objectksym.sbindpp_print_objectv))(Map.bindingsm)sclose)|List(l,sym)->letsopen=ifsym.sopen=""then""elsesym.sopen^" "inletsclose=ifsym.sclose=""then""else" "^sym.scloseinFormat.(fprintffmt"%s@[<hv>%a@]%s"sopen(pp_print_list~pp_sep:(funfmt()->fprintffmt"%s@ "sym.ssep)pp_print_object)lsclose)|Set(s,sym)->letsopen=ifsym.sopen=""then""elsesym.sopen^" "inletsclose=ifsym.sclose=""then""else" "^sym.scloseinFormat.(fprintffmt"%s @[<hv>%a@] %s"sopen(pp_print_list~pp_sep:(funfmt()->fprintffmt"%s@ "sym.ssep)pp_print_object)(Set.elementss)sclose)letrecmergeo1o2=ifcompareo1o2=0theno1elseifis_emptyo1theno2elseifis_emptyo2theno1elseifis_atomico1&&is_atomico2thenList([o1;o2],default_list_symbols)elsematcho1,o2with|Empty,o|o,Empty->o|List(l1,sym1),List(l2,sym2)->List(l1@l2,sym1)|List(l,sym),o|o,List(l,sym)->List(o::l,sym)|Map(m1,sym1),Map(m2,sym2)->letm=Map.map2zo(funk1v1->v1)(funk2v2->v2)(funkv1v2->mergev1v2)m1m2inMap(m,sym1)|Set(s1,sym1),Set(s2,sym2)->Set(Set.unions1s2,sym1)|Set(s,sym),o|o,Set(s,sym)->Set(Set.addos,sym)|_->Exceptions.panic"merge:@\n @[%a@]@\nand@\n @[%a@]"pp_print_objecto1pp_print_objecto2letrecsingletonpathobj=matchpathwith|[]->obj|Keyk::tl->Map(Map.singleton~compare:compare_print_object(Stringk)(singletontlobj),default_map_symbols)|Indexi::tl->ifi=0thenList([singletontlobj],default_list_symbols)elseList(List.init(i-1)(fun_->Empty)@[singletontlobj],default_list_symbols)|Objo::tl->Map(Map.singleton~compare:compare_print_objecto(singletontlobj),default_map_symbols)letpprint?(path=[])printerobj=printer.body<-merge(singletonpathobj)printer.bodyletpflushfmtprinter=pp_print_objectfmtprinter.bodyletformatffmtx=letprinter=empty_printer()infprinterx;pflushfmtprinterletunformat?(path=[])fprinterx=Format.kasprintf(funstr->pprintprinter(Stringstr)~path)"%a"fxletpboxfx=letprinter=empty_printer()infprinterx;printer.bodyletfboxfmt=Format.kasprintf(funstr->pbox(funprinterstr->pprintprinter(Stringstr))str)fmtletfprint?(path=[])printerfmt=Format.kasprintf(funstr->pprint~pathprinter(Stringstr))fmtletsprintfx=Format.asprintf"%a"(formatf)xletfkeyfmt=Format.kasprintf(funstr->Keystr)fmtletpkeyfx=fkey"%a"(formatf)x(****************************************************************************)(** {1 Typed print functions} *)(****************************************************************************)letpp_int?(path=[])printern=pprint~pathprinter(Int(Z.of_intn))letpp_z?(path=[])printerz=pprint~pathprinter(Intz)letpp_bool?(path=[])printerb=pprint~pathprinter(Boolb)letpp_float?(path=[])printerf=pprint~pathprinter(Floatf)letpp_string?(path=[])printerstr=pprint~pathprinter(Stringstr)letpp_variable?(path=[])printerv=pprint~pathprinter(Varv)letpp_obj_list?(path=[])?(lopen=default_list_symbols.sopen)?(lsep=default_list_symbols.ssep)?(lclose=default_list_symbols.sclose)printerl=pprint~pathprinter(List(l,{default_list_symbolswithsopen=lopen;ssep=lsep;sclose=lclose}))letpp_list?(path=[])?(lopen=default_list_symbols.sopen)?(lsep=default_list_symbols.ssep)?(lclose=default_list_symbols.sclose)fprinterl=pp_obj_list~path~lopen~lsep~lcloseprinter(List.map(pboxf)l)letpp_obj_map?(path=[])?(mopen=default_map_symbols.sopen)?(msep=default_list_symbols.ssep)?(mclose=default_map_symbols.sclose)?(mbind=default_map_symbols.sbind)printerl=letm=Map.of_listcompare_print_objectlinpprint~pathprinter(Map(m,{sopen=mopen;ssep=msep;sclose=mclose;sbind=mbind}))letpp_map?(path=[])?(mopen=default_map_symbols.sopen)?(msep=default_list_symbols.ssep)?(mclose=default_map_symbols.sclose)?(mbind=default_map_symbols.sbind)fkfvprinterl=pp_obj_map~path~mopen~msep~mclose~mbindprinter(List.map(fun(k,v)->(pboxfkk,pboxfvv))l)letpp_mapi?(path=[])?(mopen=default_map_symbols.sopen)?(msep=default_list_symbols.ssep)?(mclose=default_map_symbols.sclose)?(mbind=default_map_symbols.sbind)fkfvprinterl=pp_obj_map~path~mopen~msep~mclose~mbindprinter(List.map(fun(k,v)->(pboxfkk,pboxfv(k,v)))l)letpp_obj_set?(path=[])?(sopen=default_set_symbols.sopen)?(ssep=default_set_symbols.ssep)?(sclose=default_set_symbols.sclose)printers=pprint~pathprinter(Set(s,{default_set_symbolswithsopen;ssep;sclose}))letpp_set?(path=[])?(sopen=default_set_symbols.sopen)?(ssep=default_set_symbols.ssep)?(sclose=default_set_symbols.sclose)fprinters=letl=List.map(pboxf)(Set.elementss)inpp_obj_set~path~sopen~ssep~scloseprinter(Set.of_listcompare_print_objectl)(****************************************************************************)(** {1 JSON} *)(****************************************************************************)letrecprint_object_to_json=function|Empty->`Null|Boolb->`Boolb|Intn->`Int(Z.to_intn)|Floatf->`Floatf|Strings->`Strings|Varv->`String(Format.asprintf"%a"pp_varv)|Map(m,_)->`Assoc(Map.bindingsm|>List.map(fun(k,v)->letk=Format.asprintf"%a"pp_print_objectkink,print_object_to_jsonv))|List(l,_)->`List(List.mapprint_object_to_jsonl)|Set(s,_)->`List(Set.elementss|>List.mapprint_object_to_json)letrecjson_to_print_object=function|`Null->Empty|`Boolb->Boolb|`Intn->Int(Z.of_intn)|`Floatf->Floatf|`Strings->Strings|`Assoca->letm=List.map(fun(k,v)->(Stringk,json_to_print_objectv))a|>Map.of_listcompare_print_objectinMap(m,default_map_symbols)|`Listl->List(List.mapjson_to_print_objectl,default_list_symbols)