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/>. *)(* *)(****************************************************************************)(** Visitor of Python AST. *)openMopsaopenAst(* Assumes: List.length (List.flatten old_struct) = List.length new_els *)(* Ensures: list list structure is the same between old_struct and the output *)letrecompose(old_struct:'alistlist)(new_els:'alist):'alistlist=letrecaux(old_struct:'alistlist)(new_els:'alist)(acc_cur:'alist):'alistlist=matchold_structwith|[]->assert(new_els=[]);assert(acc_cur=[]);[]|oldhdl::oldtll->beginmatcholdhdlwith|[]->List.revacc_cur::auxoldtllnew_els[]|ohd::otl->beginmatchnew_elswith|[]->assertfalse|ehd::etl->aux(otl::oldtll)etl(ehd::acc_cur)endendinauxold_structnew_els[](* Assumes: there are as many non-none elements in old as they are in news *)(* Ensures: the structure from old is preserved but with the new values provided in news *)letfill_some(old:'aoptionlist)(news:'blist):'boptionlist=List.fold_left(fun(news,acc)old_el->matchold_elwith|None->(news,None::acc)|Some_->beginmatchnewswith|[]->assertfalse|hdn::tln->(tln,Somehdn::acc)end)(news,[])old|>snd|>List.revlet()=register_expr_visitor(fundefaultexp->matchekindexpwith|E_py_ll_hasattr(e1,e2)->{exprs=[e1;e2];stmts=[];},(funparts->lete1,e2=matchparts.exprswith|[e1;e2]->e1,e2|_->assertfalsein{expwithekind=E_py_ll_hasattr(e1,e2)})|E_py_ll_getattr(e1,e2)->{exprs=[e1;e2];stmts=[];},(funparts->lete1,e2=matchparts.exprswith|[e1;e2]->e1,e2|_->assertfalsein{expwithekind=E_py_ll_getattr(e1,e2)})|E_py_ll_setattr(e1,e2,Somee3)->{exprs=[e1;e2;e3];stmts=[];},(funparts->lete1,e2,e3=matchparts.exprswith|[e1;e2;e3]->e1,e2,e3|_->assertfalsein{expwithekind=E_py_ll_setattr(e1,e2,Somee3)})|E_py_ll_setattr(e1,e2,None)->{exprs=[e1;e2];stmts=[];},(funparts->lete1,e2=matchparts.exprswith|[e1;e2;e3]->e1,e2|_->assertfalsein{expwithekind=E_py_ll_setattr(e1,e2,None)})|E_py_undefined_->leafexp|E_py_object_->leafexp|E_py_annote->{exprs=[e];stmts=[];},(funparts->{expwithekind=E_py_annot(List.hdparts.exprs)})|E_py_check_annot(e1,e2)->{exprs=[e1;e2];stmts=[];},(function|{exprs=[v1;v2]}->{expwithekind=E_py_check_annot(v1,v2)}|_->assertfalse)|E_py_listelts->{exprs=elts;stmts=[];},(funparts->{expwithekind=E_py_list(parts.exprs)})|E_py_setelts->{exprs=elts;stmts=[];},(funparts->{expwithekind=E_py_set(parts.exprs)})|E_py_tupleelts->{exprs=elts;stmts=[];},(funparts->{expwithekind=E_py_tuple(parts.exprs)})|E_py_attribute(obj,attr)->{exprs=[obj];stmts=[];},(funparts->{expwithekind=E_py_attribute(List.hdparts.exprs,attr)})|E_py_dict(keys,values)->{exprs=keys@values;stmts=[];},(function|{exprs}->letrecnhdnl=ifn=0then[]elsematchlwith|hd::tl->hd::(nhd(n-1)tl)|_->assertfalseandntlnl=ifn=0thenlelsematchlwith|_::tl->ntl(n-1)tl|_->assertfalseinletkeys=nhd(List.lengthkeys)exprsandvalues=ntl(List.lengthkeys)exprsin{expwithekind=E_py_dict(keys,values)})|E_py_index_subscript(obj,index)->{exprs=[obj;index];stmts=[];},(funparts->{expwithekind=E_py_index_subscript(List.hdparts.exprs,List.hd@@List.tlparts.exprs)})|E_py_slice_subscript(obj,a,b,s)->{exprs=[obj;a;s;b];stmts=[];},(function{exprs=[obj;a;s;b]}->{expwithekind=E_py_slice_subscript(obj,a,b,s)}|_->assertfalse)|E_py_yield(e)->{exprs=[e];stmts=[];},(function{exprs=[e]}->{expwithekind=E_py_yield(e)}|_->assertfalse)|E_py_yield_from(e)->{exprs=[e];stmts=[];},(function{exprs=[e]}->{expwithekind=E_py_yield_from(e)}|_->assertfalse)|E_py_if(test,body,orelse)->{exprs=[test;body;orelse];stmts=[];},(function{exprs=[test;body;orelse]}->{expwithekind=E_py_if(test,body,orelse)}|_->assertfalse)|E_py_list_comprehension(e,comprhs)|E_py_set_comprehension(e,comprhs)|E_py_generator_comprehension(e,comprhs)->letopenUniversal.Astinletiters,targets,conds=comprhs|>List.fold_left(fun(acc1,acc2,acc3)(target,iter,conds)->(* todo: do not change conds into stmts, use the structure of comprhs in the rebuild function to know if sth is an iter or a compr *)iter::acc1,target::acc2,(Universal.Ast.mk_block(List.map(funx->Universal.Ast.mk_expr_stmtxexp.erange)conds)exp.erange)::acc3)([],[],[])in{exprs=e::iters;stmts=conds},(function|{exprs=e::iters;stmts=conds}->letcomprhs=List.combine(List.combineiterstargets)conds|>List.fold_left(funacc((iter,target),conds)->(target,iter,matchskindcondswith|S_block(l,_)->List.map(funx->matchskindxwith|S_expressione->e|_->assertfalse)l|_->assertfalse)::acc)[]inbeginmatchekindexpwith|E_py_list_comprehension_->{expwithekind=E_py_list_comprehension(e,comprhs)}|E_py_set_comprehension_->{expwithekind=E_py_set_comprehension(e,comprhs)}|E_py_generator_comprehension_->{expwithekind=E_py_generator_comprehension(e,comprhs)}|_->assertfalseend|_->assertfalse)|E_py_dict_comprehension(k,v,comprhs)->letiters,targets=comprhs|>List.fold_left(funacc(target,iter,conds)->matchcondswith|[]->iter::fstacc,target::sndacc|_->assertfalse)([],[])in{exprs=k::v::iters;stmts=[]},(function|{exprs=k::v::iters}->letcomprhs=List.combineiterstargets|>List.fold_left(funacc(iter,target)->(target,iter,[])::acc)[]in{expwithekind=E_py_dict_comprehension(k,v,comprhs)}|_->assertfalse)|E_py_call(f,args,keywords)->{exprs=f::args@(List.mapsndkeywords);stmts=[];},(funparts->letf=List.hdparts.exprsinletargs,kwvals=Utils.partition_list_by_length(List.lengthargs)(List.tlparts.exprs)inletkeywords=List.combinekeywordskwvals|>List.map(fun((k,_),v)->(k,v))in{expwithekind=E_py_call(f,args,keywords)})|E_py_bytes_->leafexp|E_py_lambda(l)->letdefaults=l.py_lambda_defaults|>List.fold_left(funacc->function|None->acc|Somee->e::acc)[]|>List.revin{exprs=l.py_lambda_body::defaults;stmts=[];},(funparts->letbody=List.hdparts.exprsanddefaults=List.tlparts.exprsinletdefaults,_=l.py_lambda_defaults|>List.fold_left(fun(acc,defaults)->function|None->(None::acc,defaults)|Somee->lete=List.hddefaultsin(Somee::acc,List.tldefaults))([],defaults)inletl={lwithpy_lambda_body=body;py_lambda_defaults=List.revdefaults}in{expwithekind=E_py_lambda(l)})|E_py_multi_compare(left,ops,rights)->{exprs=left::rights;stmts=[];},(function|{exprs=left::rights}->{expwithekind=E_py_multi_compare(left,ops,rights)}|_->assertfalse)|_->defaultexp);register_stmt_visitor(fundefaultstmt->matchskindstmtwith|S_py_class(cls)->{exprs=cls.py_cls_bases;stmts=[cls.py_cls_body];},(function{exprs=bases;stmts=[body]}->{stmtwithskind=S_py_class({clswithpy_cls_body=body;py_cls_bases=bases})}|_->assertfalse)|S_py_function(func)->(* FIXME: filter_map in 4.08 *)letfilter_mapfl=List.fold_left(funaccel->matchfelwith|None->acc|Somev->v::acc)[]l|>List.revinletdefaults=filter_map(funx->x)func.py_func_defaultsinletdecors=func.py_func_decorsinlettypes_in=filter_map(funx->x)func.py_func_types_ininlettype_out=matchfunc.py_func_type_outwith|None->[]|Somex->[x]inletall=[defaults;decors;types_in;type_out]inletallf=List.flattenallin{exprs=allf;stmts=[func.py_func_body];},(function|{exprs;stmts=[body]}->letnall=recomposeallexprsinbeginmatchnallwith|[def;dec;tyin;tyout]->letndefaults=fill_somefunc.py_func_defaultsdefinletndecors=decinletntypes_in=fill_somefunc.py_func_types_intyininletntype_out=List.hd@@fill_some[func.py_func_type_out]tyoutin{stmtwithskind=S_py_function({funcwithpy_func_defaults=ndefaults;py_func_decors=ndecors;py_func_types_in=ntypes_in;py_func_type_out=ntype_out;py_func_body=body})}|_->assertfalseend|_->assertfalse)|S_py_raise(None)->leafstmt|S_py_raise(Somee)->{exprs=[e];stmts=[];},(funparts->{stmtwithskind=S_py_raise(Some(List.hdparts.exprs))})|S_py_try(body,excepts,orelse,finally)->letpy_excs,py_bodies=List.fold_left(fun(acce,accb)el->matchel.py_excpt_typewith|None->(acce,el.py_excpt_body::accb)|Somee->(e::acce,el.py_excpt_body::accb))([],[])exceptsinletpy_excs,py_bodies=List.revpy_excs,List.revpy_bodiesin{exprs=py_excs;stmts=body::orelse::finally::py_bodies;},(function|{exprs;stmts=body'::orelse'::finally'::bodies}->letopy_excs=fill_some(List.map(funx->x.py_excpt_type)excepts)exprsinletexcepts'=List.rev@@List.fold_left2(funacc(oty,stmt)except->{py_excpt_type=oty;py_excpt_name=except.py_excpt_name;py_excpt_body=stmt}::acc)[](List.combineopy_excspy_bodies)exceptsin{stmtwithskind=S_py_try(body',excepts',orelse',finally')}|_->assertfalse)|S_py_while(test,body,orelse)->{exprs=[test];stmts=[body;orelse];},(function|{exprs=[test'];stmts=[body';orelse']}->{stmtwithskind=S_py_while(test',body',orelse')}|_->assertfalse)|S_py_if(test,sthen,selse)->{exprs=[test];stmts=[sthen;selse];},(function|{exprs=[test'];stmts=[sthen';selse']}->{stmtwithskind=S_py_if(test',sthen',selse')}|_->assertfalse)|S_py_for(target,iter,body,orelse)->{exprs=iter::target::[];stmts=[body;orelse]},(function|{exprs=iter::target::[];stmts=[body;orelse]}->{stmtwithskind=S_py_for(target,iter,body,orelse)}|_->assertfalse)|S_py_multi_assign(targets,e)->{exprs=[e];stmts=[]},(function{exprs=[e]}->{stmtwithskind=S_py_multi_assign(targets,e)}|_->assertfalse)|S_py_aug_assign(x,op,e)->{exprs=[x;e];stmts=[]},(function|{exprs=[x;e]}->{stmtwithskind=S_py_aug_assign(x,op,e)}|_->assertfalse)|S_py_annot(x,typ)->{exprs=[x;typ];stmts=[]},(function|{exprs=[x;typ]}->{stmtwithskind=S_py_annot(x,typ)}|_->assertfalse)|S_py_check_annot(x,typ)->{exprs=[x;typ];stmts=[]},(function|{exprs=[x;typ]}->{stmtwithskind=S_py_check_annot(x,typ)}|_->assertfalse)|S_py_import_->leafstmt|S_py_import_from_->leafstmt|S_py_delete(e)->{exprs=[e];stmts=[];},(funparts->{stmtwithskind=S_py_delete(List.hdparts.exprs)})|S_py_assert(test,None)->{exprs=[test];stmts=[];},(function|{exprs=[test]}->{stmtwithskind=S_py_assert(test,None)}|_->assertfalse)|S_py_assert(test,Somemsg)->{exprs=[test;msg];stmts=[];},(function|{exprs=[test;msg]}->{stmtwithskind=S_py_assert(test,Somemsg)}|_->assertfalse)|S_py_with(ctx,None,body)->{exprs=[ctx];stmts=[body];},(function|{exprs=[ctx];stmts=[body]}->{stmtwithskind=S_py_with(ctx,None,body)}|_->assertfalse)|S_py_with(ctx,Sometarget,body)->{exprs=[ctx];stmts=[body]},(function|{exprs=[ctx];stmts=[body]}->{stmtwithskind=S_py_with(ctx,Sometarget,body)}|_->assertfalse)|_->defaultstmt);()