123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(**
Universal frontend translates the parser's AST into Framework's AST.
*)openMopsaopenMopsa_universal_parsermoduleNameG=structletcompt=ref0letfresh()=letrep=!comptinincrcompt;rependopenLexingopenAstopenMopsamoduleT=AstmoduleU=U_astmoduleFloat=ItvUtils.Float(* vars to their unique identifier and declared types *)moduleMS=MapExt.StringMaptypevar_context=(int*typ)MS.ttypefun_context=(T.fundec)MS.tletbuiltin_functions=[{name="mopsa_assume";args=[None];output=T_unit};{name="append";args=[Some(T_arrayT_int);SomeT_int];output=T_unit};]letfrom_extent(e:U.extent):Location.range=etypeuvar={uvar_range:range;uvar_uid:int;uvar_orig_name:string;uvar_uniq_name:string;}typevar_kind+=|V_uvarofuvarlet()=register_var{print=(funnextfmtv->matchvkindvwith|V_uvarvar->if!Framework.Core.Ast.Var.print_uniq_with_uidthenFormat.fprintffmt"%s:%a"var.uvar_orig_namepp_relative_rangevar.uvar_rangeelseFormat.fprintffmt"%s"var.uvar_orig_name|_->nextfmtv);compare=(funnextv1v2->matchvkindv1,vkindv2with|V_uvarvar1,V_uvarvar2->Compare.compose[(fun()->Stdlib.comparevar1.uvar_uidvar2.uvar_uid);(fun()->Stdlib.comparevar1.uvar_uniq_namevar2.uvar_uniq_name)]|_->nextv1v2);}letfrom_var(v:string)(ext:U.extent)(var_ctx:var_context)=trylet(id,typ)=MS.findvvar_ctxinletuniq_name=(v^":"^string_of_intid)inmkvuniq_name(V_uvar{uvar_range=ext;uvar_uid=id;uvar_orig_name=v;uvar_uniq_name=uniq_name})typwith|Not_found->Exceptions.panic_atext"%s was not found in typing/naming context"vletrecfrom_typ(typ:U_ast.typ):typ=matchtypwith|AST_INT->T_int|AST_REAL->T_floatF_DOUBLE|AST_ARRAYt->T_array(from_typt)|AST_STRING->T_string|AST_CHAR->T_char(* find a common type for the arguments of binary operations *)letunify_typ(x:typ)(y:typ):typ=matchx,ywith|T_int,T_float_->y|T_float_,T_int->x|_->ifcompare_typxy=0thenxelseExceptions.panic"cannot unify types %a and %a"pp_typxpp_typy(* cast expression to the given type (if needed) *)letto_typ(t:typ)(e:expr):expr=letrange=erangeeinletorgt=etypeinifcompare_typorgtt=0theneelsematchekinde,orgt,twith|_,(T_int|T_float_),(T_int|T_float_)->mk_unopO_caste~etyp:trange|E_constant(C_topT_any),T_any,t->{ewithekind=E_constant(C_topt);etyp=t}|_->Exceptions.panic"cannot convert expression %a of type %a to type %a"pp_exprepp_typorgtpp_typtletfrom_binop(t:typ)(b:U.binary_op):operator=matcht,bwith|T_int,AST_PLUS->O_plus|T_int,AST_MINUS->O_minus|T_int,AST_MULTIPLY->O_mult|T_int,AST_DIVIDE->O_div|T_int,AST_EQUAL->O_eq|T_int,AST_NOT_EQUAL->O_ne|T_int,AST_LESS->O_lt|T_int,AST_LESS_EQUAL->O_le|T_int,AST_GREATER->O_gt|T_int,AST_GREATER_EQUAL->O_ge|T_int,AST_AND->O_log_and|T_int,AST_OR->O_log_or|T_string,AST_CONCAT->O_concat|T_string,AST_PLUS->O_concat|T_string,AST_EQUAL->O_eq|T_float_,AST_PLUS->O_plus|T_float_,AST_MINUS->O_minus|T_float_,AST_MULTIPLY->O_mult|T_float_,AST_DIVIDE->O_div|T_float_,AST_EQUAL->O_eq|T_float_,AST_NOT_EQUAL->O_ne|T_float_,AST_LESS->O_lt|T_float_,AST_LESS_EQUAL->O_le|T_float_,AST_GREATER->O_gt|T_float_,AST_GREATER_EQUAL->O_ge|T_array_,AST_CONCAT->O_concat|_->Exceptions.panic"operator %a cannot be used with type %a"U_ast_printer.print_binary_opbpp_typtletfrom_unop(t:typ)(b:U.unary_op):operator=matcht,bwith|T_int,AST_UNARY_PLUS->O_plus|T_int,AST_UNARY_MINUS->O_minus|T_int,AST_NOT->O_log_not|T_floatf,AST_UNARY_PLUS->O_plus|T_floatf,AST_UNARY_MINUS->O_minus|T_floatf,AST_ROUND->O_cast|_->Exceptions.panic"operator %a cannot be used with type %a"U_ast_printer.print_unary_opbpp_typtletrecfrom_expr(e:U.expr)(ext:U.extent)(var_ctx:var_context)(fun_ctx:fun_contextoption):expr=letrange=from_extentextinmatchewith|AST_unit_const->mk_expr~etyp:T_unit(E_constant(C_unit))range|AST_fun_call((f,f_ext),args)->beginletlook_in_builtins(fun_ctx)=letexceptionMatchof(exprlist*fun_builtin)intryList.iter(fun(bi:fun_builtin)->let()=Debug.debug~channel:("remove_me")"builtin: %s, fun: %s, b: %b"bi.namef(bi.name=f)inifbi.name=f&&List.lengthbi.args=List.lengthargsthenletexceptionNoMatchintryletel=List.map2(fun(e,ext)x->matchxwith|Somex->lete'=from_expreextvar_ctx(fun_ctx)inlettyp=etype'inlet()=Debug.debug~channel:("remove_me")"x: %a, typ: %a"pp_typxpp_typtypinifcompare_typtypx=0thene'elseraiseNoMatch|None->from_expreextvar_ctx(fun_ctx))argsbi.argsinraise(Match(el,bi))with|NoMatch->())builtin_functions;Exceptions.panic_atext"%s was not found in naming context nor in builtin functions"fwith|Match(el,bi)->(mk_expr~etyp:(bi.output)(E_call(mk_expr(E_function(Builtinbi))range,el))range)inmatchfun_ctxwith|None->look_in_builtins(None)|Somefun_ctx->begintryletfundec=MS.findffun_ctxinifList.lengthfundec.fun_parameters=List.lengthargsthenletel=List.map2(fun(e,ext)x->lete'=from_expreextvar_ctx(Somefun_ctx)inlettyp=etype'inifcompare_typx.vtyptyp=0thene'elseExceptions.panic_atext"type of %a incompatible with declared function"U_ast_printer.print_expre)argsfundec.fun_parametersinletrettyp=matchfundec.fun_return_typewith|None->T_int|Somet->tin(mk_expr~etyp:rettyp(E_call(mk_expr(E_function(User_definedfundec))range,el))range)elseExceptions.panic_atext"%s number of arguments incompatible with call"fwith|Not_found->beginlook_in_builtins(Somefun_ctx)endendend|AST_unary(op,(e,ext))->beginlete=from_expreextvar_ctxfun_ctxinlettyp=etypeinletop=from_unoptypopinmk_unopope~etyp:typrangeend|AST_binary(op,(e1,ext1),(e2,ext2))->beginlete1=from_expre1ext1var_ctxfun_ctxinlettyp1=etype1inlete2=from_expre2ext2var_ctxfun_ctxinlettyp2=etype2inlettyp=unify_typtyp1typ2inlete1,e2=to_typtype1,to_typtype2inletop=from_binoptypopinmk_binope1ope2~etyp:typrangeend|AST_identifier(v,ext)->mk_var(from_varvextvar_ctx)range|AST_int_const(s,_)->mk_z(Z.of_strings)range|AST_bool_const(b,_)->mk_int(ifbthen1else0)range|AST_real_const(s,_)->(* double interval enclosing the real value *)letlo=Float.of_string`DOUBLE`DOWNsandup=Float.of_string`DOUBLE`UPsinmk_float_interval~prec:F_DOUBLElouprange|AST_string_const(s,_)->mk_stringsrange|AST_char_const(c,_)->mk_int~typ:T_int(int_of_charc)range|AST_array_const(a,_)->mk_expr(E_array(List.map(fun(e,ext)->from_expreextvar_ctxfun_ctx)(Array.to_lista)))range|AST_rand((l,_),(u,_))->mk_z_interval(Z.of_stringl)(Z.of_stringu)range|AST_randf((l,_),(u,_))->mk_float_interval(float_of_stringl)(float_of_stringu)range|AST_rand_string->mk_topT_anyrange|AST_array_access((e1,ext1),(e2,ext2))->beginlete1o=e1inlete1=from_expre1ext1var_ctxfun_ctxinlete2=from_expre2ext2var_ctxfun_ctxinlete2=to_typT_inte2inmatchetype1with|T_string->mk_expr(E_subscript(e1,e2))~etyp:T_intrange|T_arrayt->mk_expr(E_subscript(e1,e2))~etyp:trange|_->Exceptions.panic_atext"%a is of type %a and can not be subscripted"U_ast_printer.print_expre1o(pp_typ)(etype1)end|AST_len(e,ext)->beginlete1=from_expreextvar_ctxfun_ctxinmatchetype1with|T_string|T_array_->mk_expr(E_lene1)~etyp:T_intrange|_->Exceptions.panic_atext"%a is of type %a and can not be lengthed"U_ast_printer.print_expre(pp_typ)(etype1)endletrecfrom_stmt(s:U.stat)(ext:U.extent)(var_ctx:var_context)(fun_ctx:fun_contextoption):stmt=letrange=from_extentextinmatchswith|AST_blockl->mk_block(List.map(fun(x,ext)->from_stmtxextvar_ctxfun_ctx)l)range|AST_assign((e1,ext1),(e2,ext2))->beginlete1o=e1inmatche1with|AST_array_access(_,_)|AST_identifier_->lete1=from_expre1ext1var_ctxfun_ctxinlete2=from_expre2ext2var_ctxfun_ctxinlete2=to_typ(etype1)e2inmk_assigne1e2range|_->Exceptions.panic_atext"%a not considered a left-value for now "U_ast_printer.print_expre1oend|AST_if((e1,ext_e1),(s1,ext_s1),Some(s2,ext_s2))->lete1=from_expre1ext_e1var_ctxfun_ctxinlets1=from_stmts1ext_s1var_ctxfun_ctxinlets2=from_stmts2ext_s2var_ctxfun_ctxinmk_ife1s1s2range|AST_if((e1,ext_e1),(s1,ext_s1),None)->lete1=from_expre1ext_e1var_ctxfun_ctxinlets1=from_stmts1ext_s1var_ctxfun_ctxinmk_ife1s1(mk_noprange)range|AST_while((e1,ext_e1),(s1,ext_s1))->lete1=from_expre1ext_e1var_ctxfun_ctxinlets1=from_stmts1ext_s1var_ctxfun_ctxinmk_whilee1s1range|AST_for((v1,ext_v1),(e1,ext_e1),(e2,ext_e2),(s1,ext_s1))->lete1=from_expre1ext_e1var_ctxfun_ctxinlete2=from_expre2ext_e2var_ctxfun_ctxinletv=from_varv1ext_v1var_ctxinlets1=from_stmts1ext_s1var_ctxfun_ctxinmk_block[mk_assign(mk_varv(tag_rangerange"var_init_for_variable"))e1(tag_rangerange"expr_init_for_variable");mk_while(mk_binop(mk_varv(tag_rangerange"var_comp_for"))O_lee2~etyp:(T_int)(tag_rangerange"comp_for"))(mk_block([s1;mk_assign(mk_varv(tag_rangerange"var_incr_for"))(mk_binop(mk_varv(tag_rangerange"var_incr_for"))O_plus(mk_zZ.one(tag_rangerange"one_for"))~etyp:(T_int)(tag_rangerange"incr_for"))(tag_rangerange"assign_for")])(tag_rangerange"body_for"))(tag_rangerange"total_for")]range|AST_return(Some(e,ext))->lete=from_expreextvar_ctxfun_ctxin{skind=S_return(Somee);srange=range}|AST_returnNone->{skind=S_returnNone;srange=range}|AST_break->{skind=S_break;srange=range}|AST_continue->{skind=S_continue;srange=range}|AST_assert(e,ext)->lete=from_expreextvar_ctxfun_ctxinmk_asserterange|AST_assume(e,ext)->lete=from_expreextvar_ctxfun_ctxinmk_assumeerange|AST_print->mk_stmtS_print_staterange|AST_expr(e,ext)->lete'=from_expreextvar_ctxfun_ctxinmk_expr_stmte'rangeletreccheck_declaration_list(dl:U.declarationU.extlist)=matchdlwith|p::q->auxpq;check_declaration_listq|[]->()andaux(((((_,v),e),_),_)asp:U.declarationU.ext)(dl:U.declarationU.extlist)=matchdlwith|((((_,v'),e'),_),_)::qwhenv=v'->Exceptions.panic_ate"%s has already been declared at %a"v'pp_rangee'|p'::q->auxpq|[]->()letvar_ctx_of_declaration(dl:U_ast.declarationU.extlist)(var_ctx:var_context)=let()=check_declaration_listdlinletadd_varvar_ctxvt=tryMS.addv(NameG.fresh(),t)var_ctxwith|Not_found->MS.addv(NameG.fresh(),t)var_ctxinletvar_ctx,gvars=List.fold_left(fun(var_ctx,gvars)((((t,v),extv),o),e)->letnew_var_ctx=add_varvar_ctxv(from_typt)inletvv=from_varvextvnew_var_ctxin(new_var_ctx,vv::gvars))(var_ctx,[])dlinvar_ctx,gvarsletvar_ctx_init_of_declaration(dl:U_ast.declarationU.extlist)(var_ctx:var_context)(fun_ctx:fun_contextoption)(nvar_ctx)=letadd_varvar_ctxvt=trymatchnvar_ctxwith|Somenvar_ctx->MS.addv(MS.findvnvar_ctx)var_ctx|None->MS.addv(NameG.fresh(),t)var_ctxwith|Not_found->assertfalseinletvar_ctx,init,gvars=List.fold_left(fun(var_ctx,init,gvars)((((t,v),extv),o),e)->letnew_var_ctx=add_varvar_ctxv(from_typt)inletvv=from_varvextvnew_var_ctxinletrange=from_extentextvinletstmt_add=mk_add(mk_varvv(tag_rangerange"initializer_var"))(tag_rangerange"initializer")inletinit=stmt_add::initinmatchowith|Some(e,ext)->lete=from_expreextvar_ctxfun_ctxinlete=to_typ(from_typt)einletrange=from_extentextinletstmt_init=mk_assign(mk_varvv(tag_rangerange"initializer_var"))e(tag_rangerange"initializer")in(new_var_ctx,stmt_init::init,vv::gvars)|None->(new_var_ctx,init,vv::gvars))(var_ctx,[],[])dlinvar_ctx,List.revinit,gvarsletvar_ctx_of_function(var_ctx:var_context)(fundec:U.fundec)=letadd_varvar_ctxvt=tryMS.addv(NameG.fresh(),t)var_ctxwith|Not_found->MS.addv(NameG.fresh(),t)var_ctxinletvar_ctx=List.fold_left(funacc((t,v),_)->add_varaccv(from_typt))var_ctxfundec.parametersinletvar_ctx,_=var_ctx_of_declarationfundec.locvarsvar_ctxinvar_ctxletvar_init_of_function(var_ctx:var_context)var_ctx_map(fun_ctx:fun_context)(fundec:U.fundec)=letnvar_ctx=MS.findfundec.funnamevar_ctx_mapinletadd_varvar_ctxn_var_ctxvt=tryMS.addv(MS.findvn_var_ctx)var_ctxwith|Not_found->assertfalseinletvar_ctx=List.fold_left(funacc((t,v),_)->add_varaccnvar_ctxv(from_typt))var_ctxfundec.parametersinletvar_ctx,init,_=var_ctx_init_of_declarationfundec.locvarsvar_ctx(Some(fun_ctx))(Somenvar_ctx)invar_ctx,initletfrom_fundec(f:U.fundec)(var_ctx:var_context):T.fundec=lettyp=OptionExt.liftfrom_typf.return_typein{fun_orig_name=f.funname;fun_uniq_name=f.funname;fun_range=from_extentf.range;fun_parameters=List.map(fun((_,v),ext)->from_varvextvar_ctx)f.parameters;fun_locvars=List.map(fun((((_,v),_),_),ext)->from_varvextvar_ctx)f.locvars;fun_body=mk_nop(from_extent(sndf.body));fun_return_type=typ;fun_return_var=None;}letfun_ctx_of_global(fl:U_ast.fundecU.extlist)(var_ctx:var_context)=List.fold_left(fun(acc,var_ctx_map)(fundec,_)->letvar_ctx=var_ctx_of_functionvar_ctxfundecin(MS.addfundec.funname(from_fundecfundecvar_ctx)acc,MS.addfundec.funnamevar_ctxvar_ctx_map))(MS.empty,MS.empty)flletadd_body(fl:fun_context)(f:string)(b:stmt):unit=tryletfundec=MS.findfflinfundec.fun_body<-b;with|Not_found->Exceptions.panic"[Universal.frontend] should not happen"letfrom_prog(p:U_ast.prog):prog_kind=letext=snd(p.main)inletvar_ctx,init,gvars=var_ctx_init_of_declarationp.gvarsMS.emptyNoneNoneinletfun_ctx,var_ctx_map=fun_ctx_of_globalp.funsvar_ctxinList.iter(fun(fundec,ext)->letvar_ctx,init=var_init_of_functionvar_ctxvar_ctx_mapfun_ctxfundecinletbody=from_stmt(fstfundec.body)(sndfundec.body)var_ctx(Somefun_ctx)inlettotal=mk_block(init@[body])(from_extentext)inadd_bodyfun_ctxfundec.funnametotal)p.funs;lettotal=from_stmt(fstp.main)(sndp.main)var_ctx(Somefun_ctx)inletwith_init=mk_block(init@[total])(from_extentext)inP_universal{universal_gvars=gvars;universal_fundecs=(MS.bindingsfun_ctx)|>List.map(snd);universal_main=with_init}letrecparse_program(files:stringlist):program=matchfileswith|[filename]->letast=U_file_parser.parse_filefilenamein{prog_kind=from_progast;prog_range=mk_program_range[filename];}|[]->panic"no input file"|_->panic"analysis of multiple files not supported"(* Front-end registration *)let()=register_frontend{lang="universal";parse=parse_program;on_panic=fun___->();}