123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Translate a CST into a AST by resolving types, variables and
functions defined in the project. *)openMopsa_utilsopenMopsa_c_parseropenLocationopenCstletdebugfmt=Debug.debug~channel:"c_stubs_parser.passes.cst_to_ast"fmt(** {2 Generic visitors} *)(** ******************** *)letrecvisit_listvisitlprjfunc=matchlwith|[]->[]|hd::tl->lethd'=visithdprjfuncinlettl'=visit_listvisittlprjfuncinhd'::tl'letrecvisit_list_extvisitlprjfunc=matchlwith|[]->[],[],[]|hd::tl->lethd',ext1,ext2=visithdprjfuncinlettl',ext1',ext2'=visit_list_extvisittlprjfuncinhd'::tl',ext1@ext1',ext2@ext2'letvisit_optionvisitoprjfunc=matchowith|None->None|Somex->Some(visitxprjfunc)letvisit_pairvisitor1visitor2(x,y)prjfunc=(visitor1xprjfunc,visitor2yprjfunc)(** {2 Types} *)(** ********* *)letfind_recordrprj=letopenC_ASTinStringMap.bindingsprj.proj_records|>List.split|>snd|>List.find(funr'->comparer'.record_org_namer.vname=0)letfind_typedeftprj=letopenC_ASTinStringMap.bindingsprj.proj_typedefs|>List.split|>snd|>List.find(funt'->comparet'.typedef_org_namet.vname=0)letfind_enumeprj=letopenC_ASTinStringMap.bindingsprj.proj_enums|>List.split|>snd|>List.find(fune'->comparee'.enum_org_namee.vname=0)letfind_functionfprj=tryletopenC_ASTinbind_rangef@@funf->StringMap.bindingsprj.proj_funcs|>List.split|>snd|>List.find(funf'->comparef'.func_org_namef.vname=0)withNot_found->Exceptions.panic_atf.range"function %s not found"f.content.vnameletrecunroll_typet=letopenC_ASTinmatchfsttwith|T_typedeftd->unroll_typetd.typedef_def|T_enume->T_integer(matche.enum_integer_typewithSomes->s|None->assertfalse),sndt|_->tletvisit_qualq=C_AST.{qual_is_const=q.c_qual_const}letrecvisit_qual_typtprjfunc:C_AST.type_qual=let(t0,q)=tinlett0'=visit_typt0prjfuncinletq'=visit_qualqint0',q'andvisit_typtprjfunc=matchtwith|T_void->C_AST.T_void|T_char->C_AST.(T_integer(CharSIGNED))(* FIXME: get the signedness defined by the platform *)|T_signed_char->C_AST.(T_integerSIGNED_CHAR)|T_unsigned_char->C_AST.(T_integerUNSIGNED_CHAR)|T_signed_short->C_AST.(T_integerSIGNED_SHORT)|T_unsigned_short->C_AST.(T_integerUNSIGNED_SHORT)|T_signed_int->C_AST.(T_integerSIGNED_INT)|T_unsigned_int->C_AST.(T_integerUNSIGNED_INT)|T_signed_long->C_AST.(T_integerSIGNED_LONG)|T_unsigned_long->C_AST.(T_integerUNSIGNED_LONG)|T_signed_long_long->C_AST.(T_integerSIGNED_LONG_LONG)|T_unsigned_long_long->C_AST.(T_integerUNSIGNED_LONG_LONG)|T_signed_int128->C_AST.(T_integerSIGNED_INT128)|T_unsigned_int128->C_AST.(T_integerUNSIGNED_INT128)|T_float->C_AST.(T_floatFLOAT)|T_double->C_AST.(T_floatDOUBLE)|T_long_double->C_AST.(T_floatLONG_DOUBLE)|T_float128->C_AST.(T_floatFLOAT128)|T_array(t,len)->C_AST.T_array(visit_qual_typtprjfunc,visit_array_lengthlenprjfunc)|T_struct(s)->C_AST.T_record(find_recordsprj)|T_union(u)->C_AST.T_record(find_recorduprj)|T_typedef(t)->C_AST.T_typedef(find_typedeftprj)|T_pointer(t)->C_AST.T_pointer(visit_qual_typtprjfunc)|T_enum(e)->C_AST.T_enum(find_enumeprj)|T_unknown->Exceptions.panic"unknown type not resolved"andvisit_array_lengthlenprjfunc=matchlenwith|A_no_length->C_AST.No_length|A_constant_lengthn->C_AST.Length_cstnletint_type=C_AST.(T_integerSIGNED_INT,no_qual)letbool_type=C_AST.(T_bool,no_qual)letfloat_type=C_AST.(T_floatFLOAT,no_qual)letdouble_type=C_AST.(T_floatDOUBLE,no_qual)letlong_type=C_AST.(T_integerSIGNED_LONG,no_qual)letunsigned_long_type=C_AST.(T_integerUNSIGNED_LONG,no_qual)letlong_long_type=C_AST.(T_integerSIGNED_LONG_LONG,no_qual)letunsigned_long_long_type=C_AST.(T_integerUNSIGNED_LONG_LONG,no_qual)letstring_types=C_AST.(T_array((T_integer(SIGNED_CHAR),no_qual),Length_cst(Z.of_int(1+String.lengths))),no_qual)letchar_type=C_AST.(T_integer(CharSIGNED),no_qual)letpointer_typet=C_AST.(T_pointert,no_qual)letvoid_type=C_AST.(T_void,no_qual)letis_int_typt=matchunroll_typet|>fstwith|C_AST.T_integer_->true|_->falseletis_float_typt=matchunroll_typet|>fstwith|C_AST.T_float_->true|_->falseletis_pointer_typt=matchunroll_typet|>fstwith|C_AST.T_pointer_->true|_->falseletis_array_typt=matchunroll_typet|>fstwith|C_AST.T_array_->true|_->falseletpointed_typeranget=matchfst(unroll_typet)with|C_AST.T_pointert'->t'|C_AST.T_array(t',_)->t'|_->Exceptions.panic_atrange"pointed_type(cst_to_ast.ml): unsupported type %s"(C_print.string_of_type_qualt)letis_record_typt=matchfst(unroll_typet)with|C_AST.T_record_->true|_->falseletsubscript_typet=pointed_typetletattribute_typeobjf=Exceptions.warn"attribute_typ: supporting only int attributes";int_typeletbuiltin_typefargs=matchfwith|LENGTH->unsigned_long_type|BYTES->unsigned_long_type|OFFSET->long_type|INDEX->long_type|BASE->pointer_typeC_AST.(T_void,no_qual)|PRIMED->letarg=List.hdargsinarg.content.Ast.typ|VALID_FLOAT|FLOAT_INF|FLOAT_NAN->int_type|ALIVE->int_type|RESOURCE->int_type(** {2 Records} *)(** *********** *)letrecfind_fieldrangetf=matchfst(unroll_typet)with|C_AST.T_recordr->letrecaux=function|[]->raiseNot_found|field::tlwhenfield.C_AST.field_org_name=f->field(* case of anonymous records *)|field::tlwhenfield.field_org_name=""&&is_record_typfield.field_type->begintryfind_fieldrangefield.field_typefwithNot_found->auxtlend|_::tl->auxtlinaux(Array.to_listr.C_AST.record_fields)|_->Exceptions.panic_atrange"field_type(cst_to_ast.ml): unsupported type %s"(C_print.string_of_type_qualt)letfind_field_checktfrange=tryfind_fieldrangetfwithNot_found->Exceptions.panic_atrange"type %s has no field named %s"(C_print.string_of_type_qualt)f(** {2 Expressions} *)(** *************** *)letvisit_varvrangeprjfunc=letopenC_ASTinifv.vlocalthen{var_uid=v.vuid;(** FIXME: ensure that v.vuid is unique in the entire project *)var_org_name=v.vname;var_unique_name=v.vname^(string_of_intv.vuid);(** FIXME: give better unique names *)var_kind=Variable_localfunc;var_type=visit_qual_typv.vtypprjfunc;var_init=None;var_init_org=None;var_range=Clang_AST.{range_begin={eloc_loc={loc_file=get_range_startv.vrange|>get_pos_file;loc_line=get_range_startv.vrange|>get_pos_line;loc_column=get_range_startv.vrange|>get_pos_column;};eloc_stack=[];};range_end={eloc_loc={loc_file=get_range_endv.vrange|>get_pos_file;loc_line=get_range_endv.vrange|>get_pos_line;loc_column=get_range_endv.vrange|>get_pos_column;};eloc_stack=[];}};var_com=[];var_before_stmts=[];var_after_stmts=[];var_attrs=[];}else(* Search for the variable in the parameters of the function or
the globals of the project *)letvars=Array.to_listfunc.func_parameters@(StringMap.bindingsprj.proj_vars|>List.split|>snd)intryList.find(funv'->comparev'.var_org_namev.vname=0)varswithNot_found->Exceptions.panic_atrange"undeclared variable %a"pp_varvletint_rank=letopenC_ASTinfunction|Char_|UNSIGNED_CHAR|SIGNED_CHAR->0|UNSIGNED_SHORT|SIGNED_SHORT->1|UNSIGNED_INT|SIGNED_INT->2|UNSIGNED_LONG|SIGNED_LONG->3|UNSIGNED_LONG_LONG|SIGNED_LONG_LONG->4|UNSIGNED_INT128|SIGNED_INT128->5letint_sign=letopenC_ASTinfunction|SIGNED_CHAR|SIGNED_SHORT|SIGNED_INT|SIGNED_LONG|SIGNED_LONG_LONG|SIGNED_INT128->true|UNSIGNED_CHAR|UNSIGNED_SHORT|UNSIGNED_INT|UNSIGNED_LONG|UNSIGNED_LONG_LONG|UNSIGNED_INT128->false|CharSIGNED->true|CharUNSIGNED->falseletmake_unsigned=letopenC_ASTinfunction|Char_|UNSIGNED_CHAR|SIGNED_CHAR->UNSIGNED_CHAR|UNSIGNED_SHORT|SIGNED_SHORT->UNSIGNED_SHORT|UNSIGNED_INT|SIGNED_INT->UNSIGNED_INT|UNSIGNED_LONG|SIGNED_LONG->UNSIGNED_LONG|UNSIGNED_LONG_LONG|SIGNED_LONG_LONG->UNSIGNED_LONG_LONG|UNSIGNED_INT128|SIGNED_INT128->UNSIGNED_INT128letrank_float=letopenC_ASTinfunction|FLOAT16->0|FLOAT->1|DOUBLE->2|LONG_DOUBLE->3|FLOAT128->4letis_int_binop=function|EQ|NEQ|LT|LE|GT|GE|LAND|LOR->true|_->falseletbinop_typerangeprjt1t2=letopenC_ASTinletopenC_utilsinmatchfst(unroll_typet1),fst(unroll_typet2)with|x1,x2whentype_compatibleprj.proj_targetx1x2->t1|T_floata,T_floatb->ifrank_floata>=rank_floatbthent1elset2|T_float_,T_integer_->t1|T_integer_,T_float_->t2|T_integera,T_integerb->(* Usual arithmetic conversions (C99 6.3.1.8) *)(* same sign: the highest ranked wins *)ifint_signa=int_signbthenifint_ranka>=int_rankbthent1elset2(* if the unsigned has greater or equal rank, it wins *)elseifnot(int_signa)&&int_ranka>=int_rankbthent1elseifnot(int_signb)&&int_rankb>=int_rankathent2(* if the signed can hold all unsigned values, it wins *)elseifint_signa&&sizeof_intprj.proj_targeta>sizeof_intprj.proj_targetbthent1elseifint_signb&&sizeof_intprj.proj_targetb>sizeof_intprj.proj_targetathent2(* otherwise, use an unsigned version of the signed type *)elseifint_signathenT_integer(make_unsigneda),sndt1elseT_integer(make_unsignedb),sndt2|T_pointer_,T_integer_->t1|T_integer_,T_pointer_->t2|T_array_,T_integer_->t1|T_integer_,T_array_->t2|T_pointer(T_void,_),(T_pointer_|T_array_)->t2|(T_pointer_|T_array_),T_pointer(T_void,_)->t1|T_pointer(p1,_),T_pointer(p2,_)whentype_equalprj.proj_targetp1p2->t1|T_pointerp,T_array(e,_)whentype_qual_compatibleprj.proj_targetpe->t1|T_array(e,_),T_pointerpwhentype_qual_compatibleprj.proj_targetpe->t2|_->Exceptions.warn_atrange"binop_type: unsupported case: %s and %s"(C_print.string_of_type_qualt1)(C_print.string_of_type_qualt2);t1(* Integer promotions (C99 6.3.1.1) *)letinteger_promotionprj(e:Ast.exprwith_range)=letopenC_ASTinletopenC_utilsinbind_rangee@@funee->lett=unroll_typeee.typinmatchfsttwith|T_integer(SIGNED_INT|UNSIGNED_INT|SIGNED_LONG|UNSIGNED_LONG|SIGNED_LONG_LONG|UNSIGNED_LONG_LONG|SIGNED_INT128|UNSIGNED_INT128)->ee|T_integer(CharSIGNED|SIGNED_CHAR|SIGNED_SHORT)|T_bool->lettt=(T_integerSIGNED_INT),sndtin{kind=E_cast(tt,false,e);typ=tt}|T_integer((CharUNSIGNED|UNSIGNED_CHAR|UNSIGNED_SHORT)asi)->(* signed int wins if it can represent all unsigned values *)letii=ifsizeof_intprj.proj_targeti<sizeof_intprj.proj_targetSIGNED_INTthenSIGNED_INTelseUNSIGNED_INTinlettt=(T_integerii),sndtin{kind=E_cast(tt,false,e);typ=tt}|T_float_->ee|T_pointer_->ee|T_array_->ee|_->Exceptions.panic_ate.range"promote_expression_type: unsupported type %s"(C_print.string_of_type_qualt)letpromote_expression_typeprjtarget_type(e:Ast.exprwith_range)=ifis_float_typtarget_typethenlett=e.content.typiniftarget_type==ttheneelsewith_rangeAst.{kind=E_cast(target_type,false,e);typ=target_type}e.rangeelseinteger_promotionprjeletrecvisit_expreprjfunc:Ast.exprwith_range=bind_rangee@@funee->letkind,typ=matcheewith|E_topt->lett=visit_qual_typtprjfuncinAst.E_topt,t|E_int(n,NO_SUFFIX)->Ast.E_int(n),int_type|E_int(n,LONG)->Ast.E_int(n),long_type|E_int(n,UNSIGNED_LONG)->Ast.E_int(n),unsigned_long_type|E_int(n,LONG_LONG)->Ast.E_int(n),long_long_type|E_int(n,UNSIGNED_LONG_LONG)->Ast.E_int(n),unsigned_long_long_type|E_float(f)->Ast.E_float(f),float_type|E_string(s)->Ast.E_string(s),string_types|E_char(c)->Ast.E_char(c),char_type|E_invalid->Ast.E_invalid,pointer_typevoid_type|E_var(v)->letv=visit_varve.rangeprjfuncinAst.E_varv,v.var_type|E_unop(op,e')->lete'=visit_expre'prjfuncinlete'=promote_expression_typeprje'.content.type'inletee'=with_rangeAst.{kind=E_unop(op,e');typ=e'.content.typ}e.rangeinE_cast(e'.content.typ,false,ee'),e'.content.typ|E_binop(op,e1,e2)->lete1=visit_expre1prjfuncinlete2=visit_expre2prjfuncinlett=binop_typee.rangeprje1.content.type2.content.typinlete1=promote_expression_typeprjte1inlete2=promote_expression_typeprjte2inifis_int_binopopthenE_binop(op,e1,e2),int_typeelseletee=with_rangeAst.{kind=E_binop(op,e1,e2);typ=t}e.rangeinE_cast(t,false,ee),t|E_addr_of(e')->lete'=visit_expre'prjfuncinAst.E_addr_ofe',pointer_typee'.content.typ|E_deref(e')->lete'=visit_expre'prjfuncinAst.E_derefe',pointed_typee.rangee'.content.typ|E_cast(t,e')->lett=visit_qual_typtprjfuncinAst.E_cast(t,true,visit_expre'prjfunc),t|E_subscript(a,i)->leta=visit_expraprjfuncinAst.E_subscript(a,visit_expriprjfunc),subscript_typee.rangea.content.typ|E_member(s,f)->lets=visit_exprsprjfuncinletfield=find_field_checks.content.typfe.rangeinAst.E_member(s,field.field_index,f),field.field_type|E_arrow(p,f)->letp=visit_exprpprjfuncinletfield=find_field_check(pointed_typee.rangep.content.typ)fe.rangeinAst.E_arrow(p,field.field_index,f),field.field_type|E_conditional(c,e1,e2)->letc=visit_exprcprjfuncinlete1=visit_expre1prjfuncinlete2=visit_expre2prjfuncinE_conditional(c,e1,e2),e1.content.typ(* FIXME: handle the case when e1 and e2 have different types *)|E_sizeof_expr(e)->lete=visit_expreprjfuncinlettyp=matchunroll_typee.content.typ|>fstwith|C_AST.T_void->C_AST.(T_integerSIGNED_CHAR)|t->tinletsize=C_utils.sizeof_type!target_infotypinAst.E_int(size),int_type|E_sizeof_type(t)->lettyp,_=visit_qual_typt.contentprjfuncinletsize=C_utils.sizeof_type!target_infotypinAst.E_int(size),int_type|E_builtin_call(f,args)->letargs=List.map(funa->visit_expraprjfunc)argsinAst.E_builtin_call(f,args),builtin_typefargs|E_return->Ast.E_return,func.func_return|E_raisemsg->Ast.E_raise(msg),int_typeinAst.{kind;typ}(** {2 Formulas} *)(** ************ *)letvisit_intervaliprjfunc={Ast.itv_lb=visit_expri.itv_lbprjfunc;itv_open_lb=i.itv_open_lb;itv_ub=visit_expri.itv_ubprjfunc;itv_open_ub=i.itv_open_ub;}letvisit_setsprjfunc=matchswith|S_interval(itv)->Ast.S_interval(visit_intervalitvprjfunc)|S_resource(r)->Ast.S_resource(r.vname)letrecvisit_formulafprjfunc=bind_rangef@@funff->matchffwith|F_expr(e)->Ast.F_expr(visit_expreprjfunc)|F_bool(b)->Ast.F_boolb|F_binop(op,f1,f2)->Ast.F_binop(op,visit_formulaf1prjfunc,visit_formulaf2prjfunc)|F_notf'->Ast.F_not(visit_formulaf'prjfunc)|F_forall(v,t,s,f')->letv'=visit_varvf.rangeprjfuncinAst.F_forall(v',visit_setsprjfunc,visit_formulaf'prjfunc)|F_exists(v,t,s,f')->letv'=visit_varvf.rangeprjfuncinAst.F_exists(v',visit_setsprjfunc,visit_formulaf'prjfunc)|F_in(e,s)->Ast.F_in(visit_expreprjfunc,visit_setsprjfunc)|F_otherwise(f,e)->Ast.F_otherwise(visit_formulafprjfunc,visit_expreprjfunc)|F_if(c,f1,f2)->Ast.F_if(visit_formulacprjfunc,visit_formulaf1prjfunc,visit_formulaf2prjfunc)(** {2 Stub sections} *)(** **************** *)letvisit_requiresreqprjfunc=bind_rangereq@@funreq->visit_formulareqprjfuncletvisit_assumesasmprjfunc=bind_rangeasm@@funasm->visit_formulaasmprjfuncletvisit_assignsaprjfunc=bind_rangea@@funa->Ast.{assign_target=visit_expra.Cst.assign_targetprjfunc;assign_offset=(visit_list@@visit_interval)a.Cst.assign_offsetprjfunc;}letvisit_ensuresensprjfunc=bind_rangeens@@funens->visit_formulaensprjfuncletvisit_freefreeprjfunc=bind_rangefree@@funfree->visit_exprfreeprjfuncletvisit_locallocprjfunc=bind_rangeloc@@funl->letlvar=visit_varl.lvarloc.rangeprjfuncinletlval=matchl.lvalwith|L_newr->Ast.L_newr.vname|L_call(f,args)->letf=find_functionfprjin(* Check arguments number *)letgiven=List.lengthargsinletaccepted=Array.lengthf.content.func_parametersinifnotf.content.func_variadicthen(ifgiven<>acceptedthenExceptions.panic_atloc.range"function '%s' accepts %d argument%a, but %d given"f.content.func_org_nameacceptedDebug.plurial_intacceptedgiven)else(ifgiven<acceptedthenExceptions.panic_atloc.range"function '%s' accepts at least %d argument%a, but %d given"f.content.func_org_nameacceptedDebug.plurial_intacceptedgiven);Ast.L_call(f,visit_listvisit_exprargsprjfunc)inAst.{lvar;lval}letvisit_messagemsgprjfunc=bind_rangemsg@@funm->{Ast.message_kind=m.message_kind;message_body=m.message_body;}letvisit_leafleafprjfunc=matchleafwith|Cst.S_locallocal->letlocal=visit_locallocalprjfuncinAst.S_locallocal,[local],[]|S_assumesassumes->S_assumes(visit_assumesassumesprjfunc),[],[]|S_requiresrequires->S_requires(visit_requiresrequiresprjfunc),[],[]|S_assignsassigns->letassigns=visit_assignsassignsprjfuncinS_assignsassigns,[],[assigns]|S_ensuresensures->S_ensures(visit_ensuresensuresprjfunc),[],[]|S_freefree->S_free(visit_freefreeprjfunc),[],[]|S_messagemsg->S_message(visit_messagemsgprjfunc),[],[]letvisit_casecaseprjfunc=letbody,locals,assigns=visit_list_extvisit_leafcase.content.case_bodyprjfuncinAst.{case_label=case.content.case_label;case_body=body;case_locals=locals;case_assigns=assigns;case_range=case.range;},assignsletvisit_sectionsectprjfunc=matchsectwith|Cst.S_leafleaf->letleaf,locals,assigns=visit_leafleafprjfuncinAst.S_leafleaf,locals,assigns|S_casecase->letcase,assigns=visit_casecaseprjfuncinS_case(case),[],assigns(** {2 Entry point} *)(** *************** *)letdoit(prj:C_AST.project)(func:C_AST.func)(stub:Cst.stub):Ast.stub=letbody,locals,assigns=visit_list_extvisit_sectionstub.contentprjfuncinAst.{stub_name=func.C_AST.func_org_name;stub_params=Array.to_listfunc.C_AST.func_parameters;stub_body=body;stub_locals=locals;stub_assigns=assigns;stub_range=stub.range;}