123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921(* Js_of_ocaml compiler
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2013 Hugo Heuzard
*
* 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, with linking exception;
* either version 2.1 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)open!StdlibopenJavascriptclasstypemapper=objectmethodexpression:Javascript.expression->Javascript.expressionmethodexpression_o:Javascript.expressionoption->Javascript.expressionoptionmethodswitch_case:Javascript.expression->Javascript.expressionmethodinitialiser:Javascript.expression*Javascript.location->Javascript.expression*Javascript.locationmethodinitialiser_o:(Javascript.expression*Javascript.location)option->(Javascript.expression*Javascript.location)optionmethodvariable_declaration:Javascript.variable_declaration->Javascript.variable_declarationmethodstatement:Javascript.statement->Javascript.statementmethodstatement_o:(Javascript.statement*Javascript.location)option->(Javascript.statement*Javascript.location)optionmethodstatements:Javascript.statement_list->Javascript.statement_listmethodsource:Javascript.source_element->Javascript.source_elementmethodsources:Javascript.source_elements->Javascript.source_elementsmethodident:Javascript.ident->Javascript.identmethodprogram:Javascript.program->Javascript.programend(* generic js ast walk/map *)classmap:mapper=object(m)methodidenti=imethodstatementsl=List.mapl~f:(fun(s,pc)->m#statements,pc)methodvariable_declaration(id,eo)=m#identid,m#initialiser_oeomethodstatements=matchswith|Blockb->Block(m#statementsb)|Variable_statementl->Variable_statement(List.mapl~f:m#variable_declaration)|Empty_statement->Empty_statement|Debugger_statement->Debugger_statement|Expression_statemente->Expression_statement(m#expressione)|If_statement(e,(s,loc),sopt)->If_statement(m#expressione,(m#statements,loc),m#statement_osopt)|Do_while_statement((s,loc),e)->Do_while_statement((m#statements,loc),m#expressione)|While_statement(e,(s,loc))->While_statement(m#expressione,(m#statements,loc))|For_statement(e1,e2,e3,(s,loc))->lete1=matche1with|Lefto->Left(m#expression_oo)|Rightl->Right(List.mapl~f:(fun(id,eo)->m#identid,m#initialiser_oeo))inFor_statement(e1,m#expression_oe2,m#expression_oe3,(m#statements,loc))|ForIn_statement(e1,e2,(s,loc))->lete1=matche1with|Lefte->Left(m#expressione)|Right(id,e)->Right(m#identid,m#initialiser_oe)inForIn_statement(e1,m#expressione2,(m#statements,loc))|Continue_statements->Continue_statements|Break_statements->Break_statements|Return_statemente->Return_statement(m#expression_oe)|Labelled_statement(l,(s,loc))->Labelled_statement(l,(m#statements,loc))|Throw_statemente->Throw_statement(m#expressione)|Switch_statement(e,l,def,l')->Switch_statement(m#expressione,List.mapl~f:(fun(e,s)->m#switch_casee,m#statementss),(matchdefwith|None->None|Somel->Some(m#statementsl)),List.mapl'~f:(fun(e,s)->m#switch_casee,m#statementss))|Try_statement(b,catch,final)->Try_statement(m#statementsb,(matchcatchwith|None->None|Some(id,b)->Some(m#identid,m#statementsb)),matchfinalwith|None->None|Somes->Some(m#statementss))methodstatement_ox=matchxwith|None->None|Some(s,loc)->Some(m#statements,loc)methodswitch_casee=m#expressionemethodexpressionx=matchxwith|ESeq(e1,e2)->ESeq(m#expressione1,m#expressione2)|ECond(e1,e2,e3)->ECond(m#expressione1,m#expressione2,m#expressione3)|EBin(b,e1,e2)->EBin(b,m#expressione1,m#expressione2)|EUn(b,e1)->EUn(b,m#expressione1)|ECall(e1,e2,loc)->ECall(m#expressione1,List.mape2~f:m#expression,loc)|EAccess(e1,e2)->EAccess(m#expressione1,m#expressione2)|EDot(e1,id)->EDot(m#expressione1,id)|ENew(e1,Someargs)->ENew(m#expressione1,Some(List.mapargs~f:m#expression))|ENew(e1,None)->ENew(m#expressione1,None)|EVarv->EVar(m#identv)|EFun(idopt,params,body,nid)->letidopt=matchidoptwith|None->None|Somei->Some(m#identi)inEFun(idopt,List.mapparams~f:m#ident,m#sourcesbody,nid)|EArrl->EArr(List.mapl~f:(funx->m#expression_ox))|EObjl->EObj(List.mapl~f:(fun(i,e)->i,m#expressione))|(EStr_asx)|(EBool_asx)|(ENum_asx)|(EQuote_asx)|(ERegexp_asx)->xmethodexpression_ox=matchxwith|None->None|Somes->Some(m#expressions)methodinitialiser(e,pc)=m#expressione,pcmethodinitialiser_ox=matchxwith|None->None|Somei->Some(m#initialiseri)methodsourcex=matchxwith|Statements->Statement(m#statements)|Function_declaration(id,params,body,nid)->Function_declaration(m#identid,List.mapparams~f:m#ident,m#sourcesbody,nid)methodsourcesx=List.mapx~f:(fun(s,loc)->m#sources,loc)methodprogramx=m#sourcesxend(* var substitution *)classsubstsub=objectinheritmapmethodidentx=subxendclassmap_for_share_constant=object(m)inheritmapassupermethodexpressione=matchewith(* JavaScript engines recognize the pattern
'typeof x==="number"'; if the string is shared,
less efficient code is generated. *)|EBin(op,EUn(Typeof,e1),(EStr_ase2))->EBin(op,EUn(Typeof,super#expressione1),e2)|EBin(op,(EStr_ase1),EUn(Typeof,e2))->EBin(op,EUn(Typeof,e1),super#expressione2)(* Some js bundler get confused when the argument
of 'require' is not a literal *)|ECall(EVar(S{var=None;name="require";_}),[EStr_],_)->e|_->super#expressione(* do not replace constant in switch case *)methodswitch_casee=matchewith|ENum_|EStr_->e|_->m#expressionemethodsourcesl=matchlwith|[]->[]|((Statement(Expression_statement(EStr_)),_)asprolog)::rest->prolog::List.map_tcrest~f:(fun(x,loc)->m#sourcex,loc)|rest->List.map_tcrest~f:(fun(x,loc)->m#sourcex,loc)endclassreplace_exprf=objectinheritmap_for_share_constantassupermethodexpressione=tryEVar(fe)withNot_found->super#expressioneend(* this optimisation should be done at the lowest common scope *)classshare_constant=objectinheritmap_for_share_constantassupervalcount=Hashtbl.create17methodexpressione=lete=matchewith|EStr(s,`Utf8)when(not(String.has_backslashs))&&String.is_asciis->lete=EStr(s,`Bytes)inletn=tryHashtbl.findcountewithNot_found->0inHashtbl.replacecounte(n+1);e|EStr(_,_)|ENum_->letn=tryHashtbl.findcountewithNot_found->0inHashtbl.replacecounte(n+1);e|_->einsuper#expressionemethodprogramp=letp=super#programpinletall=Hashtbl.create17inHashtbl.iter(funxn->letshareit=matchxwith|EStr(s,_)whenn>1->ifString.lengths<20thenSome("str_"^s)elseSome("str_"^String.subs~pos:0~len:16^"_abr")|ENumswhenn>1->lets=Javascript.Num.to_stringsinletl=String.lengthsinifl>2thenSome("num_"^s)elseNone|_->Noneinmatchshareitwith|Somename->letv=Code.Var.fresh_nnameinHashtbl.addallx(Vv)|_->())count;ifHashtbl.lengthall=0thenpelseletf=Hashtbl.findallinletp=(newreplace_exprf)#programpinletall=Hashtbl.fold(funevacc->(v,Some(e,N))::acc)all[]in(Statement(Variable_statementall),N)::pendmoduleS=Code.Var.Settypet={use_name:StringSet.t;def_name:StringSet.t;def:S.t;use:S.t;count:intJavascript.IdentMap.t}letempty={def=S.empty;use=S.empty;use_name=StringSet.empty;def_name=StringSet.empty;count=Javascript.IdentMap.empty}(* def/used/free variable *)classtypefreevar=object('a)inheritmappermethodmerge_info:'a->unitmethodblock:?catch:bool->Javascript.identlist->unitmethoddef_var:Javascript.ident->unitmethoduse_var:Javascript.ident->unitmethodstate:tmethodget_free_name:StringSet.tmethodget_free:Code.Var.Set.tmethodget_def_name:StringSet.tmethodget_def:Code.Var.Set.tmethodget_use_name:StringSet.tmethodget_use:Code.Var.Set.tendclassfree=object(m:'test)inheritmapassupervallevel:int=0valmutablestate_:t=emptymethodstate=state_methodget_free=S.diffm#state.usem#state.defmethodget_def=m#state.defmethodget_free_name=StringSet.diffm#state.use_namem#state.def_namemethodget_def_name=m#state.def_namemethodget_use_name=m#state.use_namemethodget_use=m#state.usemethodmerge_infofrom=letfree_name=from#get_free_nameinletfree=from#get_freeinletcount=IdentMap.fold(funvkacc->letn=tryIdentMap.findvaccwithNot_found->0inIdentMap.addv(k+n)acc)from#state.countm#state.countinstate_<-{state_withuse_name=StringSet.unionstate_.use_namefree_name;use=S.unionstate_.usefree;count}methoduse_varx=letn=tryIdentMap.findxstate_.countwithNot_found->0inletcount=IdentMap.addx(succn)state_.countinmatchxwith|S{name;_}->state_<-{state_withuse_name=StringSet.addnamestate_.use_name;count}|Vv->state_<-{state_withuse=S.addvstate_.use;count}methoddef_varx=letn=tryIdentMap.findxstate_.countwithNot_found->0inletcount=IdentMap.addx(succn)state_.countinmatchxwith|S{name;_}->state_<-{state_withdef_name=StringSet.addnamestate_.def_name;count}|Vv->state_<-{state_withdef=S.addvstate_.def;count}methodexpressionx=matchxwith|EVarv->m#use_varv;x|EFun(ident,params,body,nid)->lettbody=({<state_=empty;level=succlevel>}:>'test)inlet()=List.iterparams~f:tbody#def_varinletbody=tbody#sourcesbodyinletident=matchidentwith|Some(Vv)whennot(S.memvtbody#state.use)->None|Some(S{name;_})whennot(StringSet.memnametbody#state.use_name)->None|Someid->tbody#def_varid;ident|None->Noneintbody#blockparams;m#merge_infotbody;EFun(ident,params,body,nid)|_->super#expressionxmethodsourcex=matchxwith|Function_declaration(id,params,body,nid)->lettbody={<state_=empty;level=succlevel>}inlet()=List.iterparams~f:tbody#def_varinletbody=tbody#sourcesbodyintbody#blockparams;m#def_varid;m#merge_infotbody;Function_declaration(id,params,body,nid)|Statement_->super#sourcexmethodblock?catch:__=()methodstatementx=matchxwith|Variable_statementl->letl=List.mapl~f:(fun(id,eopt)->m#def_varid;matcheoptwith|None->id,None|Some(e,pc)->lete=m#expressioneinid,Some(e,pc))inVariable_statementl|For_statement(Rightl,e2,e3,(s,loc))->letl=List.mapl~f:(fun(id,eopt)->m#def_varid;matcheoptwith|None->id,None|Some(e,pc)->lete=m#expressioneinid,Some(e,pc))inFor_statement(Rightl,m#expression_oe2,m#expression_oe3,(m#statements,loc))|ForIn_statement(Right(id,eopt),e2,(s,loc))->m#def_varid;letr=matcheoptwith|None->id,None|Some(e,pc)->lete=m#expressioneinid,Some(e,pc)inForIn_statement(Rightr,m#expressione2,(m#statements,loc))|Try_statement(b,w,f)->letb=m#statementsbinletsame_level=levelinlettbody={<state_=empty;level=same_level>}inletw=matchwwith|None->None|Some(id,block)->letblock=tbody#statementsblockinlet()=tbody#def_varidintbody#block~catch:true[id];(* special merge here *)(* we need to propagate both def and use .. *)(* .. except 'id' because its scope is limited to 'block' *)letcleansetsets=matchidwith|S{name;_}->set,StringSet.removenamesets|Vi->S.removeiset,setsinletdef,def_name=cleantbody#state.deftbody#state.def_nameinletuse,use_name=cleantbody#state.usetbody#state.use_nameinletcount=IdentMap.fold(funvkacc->letn=tryIdentMap.findvaccwithNot_found->0inIdentMap.addv(k+n)acc)tbody#state.countm#state.countinstate_<-{use=S.unionstate_.useuse;use_name=StringSet.unionstate_.use_nameuse_name;def=S.unionstate_.defdef;def_name=StringSet.unionstate_.def_namedef_name;count};Some(id,block)inletf=matchfwith|None->None|Someblock->Some(m#statementsblock)inTry_statement(b,w,f)|_->super#statementxendclassrename_variablekeeps=objectinheritfreeassupervalmutablesub_=newsubst(funx->x)methodmerge_infofrom=super#merge_infofrom;leth=Hashtbl.create17inlet_=StringSet.iter(funname->ifStringSet.memnamekeepsthen()elseletv=Code.Var.fresh_nnameinHashtbl.addhnamev)from#state.def_nameinletf=function|S{name;_}whenHashtbl.memhname->V(Hashtbl.findhname)|s->sinsub_<-newsubstf(* method block params *)methodexpressionx=letx=super#expressionxinmatchxwith|EFun_->sub_#expressionx|_->xmethodstatementx=letx=super#statementxinmatchxwith|Try_statement(b,w,f)->letw=matchwwith|Some(S{name;_},block)->letv=Code.Var.fresh_nnameinletsub=function|S{name=name';_}whenString.equalname'name->Vv|x->xinlets=newsubstsubinSome(Vv,s#statementsblock)|x->xinTry_statement(b,w,f)|_->xmethodsourcex=letx=super#sourcexinmatchxwith|Function_declaration(id,params,body,nid)->Function_declaration(id,List.mapparams~f:sub_#ident,sub_#sourcesbody,nid)|Statement_->xendclasscompact_vardecl=object(m)inheritfreeassupervalmutableexc_=IdentSet.emptyvalmutableinsert_=IdentSet.emptymethodexc=exc_methodprivatetranslatel=List.filter_mapl~f:(fun(id,eopt)->matcheoptwith|None->None|Some(e,_)->Some(EBin(Eq,EVarid,e)))methodprivatetranslate_stl=letl=m#translatelinmatchlwith|[]->Empty_statement|x::l->Expression_statement(List.fold_leftl~init:x~f:(funacce->ESeq(acc,e)))methodprivatetranslate_exl=letl=m#translatelinmatchlwith|[]->None|x::l->Some(List.fold_leftl~init:x~f:(funacce->ESeq(acc,e)))methodprivateexcepte=exc_<-IdentSet.addeexc_methodstatements=lets=super#statementsinmatchswith|Variable_statementl->m#translate_stl|For_statement(Rightl,e2,e3,s)->For_statement(Left(m#translate_exl),e2,e3,s)|ForIn_statement(Right(id,op),e2,s)->(matchopwith|Some_->assertfalse|None->());ForIn_statement(Left(EVarid),e2,s)|Try_statement(b,w,f)->(matchwwith|None->()|Some(id,_)->m#exceptid);Try_statement(b,w,f)|s->smethodblock?(catch=false)params=ignorecatch;List.iterparams~f:m#except;super#blockparamsmethodmerge_infofrom=super#merge_infofrom;letall=S.fold(funeacc->IdentSet.add(Ve)acc)from#state.defIdentSet.emptyinletall=StringSet.fold(funeacc->IdentSet.add(idente)acc)from#state.def_nameallininsert_<-IdentSet.diffallfrom#excmethodprivatesplitx=letrecloop=function|ESeq(e1,e2)->loope1@loope2|e->[e]inloopxmethodprivatepackallsources=letmay_flushremvarssinstr=ifList.is_emptyvarsthenrem,[],s::instrelserem,[],s::(Statement(Variable_statement(List.revvars)),N)::instrinletrem,vars,instr=List.fold_leftsources~init:(all,[],[])~f:(fun(rem,vars,instr)(s,loc)->matchswith|Statement(Expression_statemente)->letl=m#spliteinList.fold_leftl~init:(rem,vars,instr)~f:(fun(rem,vars,instr)e->matchewith|EBin(Eq,EVarid,exp)whenIdentSet.memidrem->IdentSet.removeidrem,(id,Some(exp,N))::vars,instr|x->may_flushremvars(Statement(Expression_statementx),N)instr)|Statement_ass->may_flushremvars(s,loc)instr|Function_declaration_asx->rem,vars,(x,loc)::instr)inletinstr=matchvarswith|[]->List.revinstr|d->letd=Statement(Variable_statement(List.revd))inList.rev((d,N)::instr)inletl=IdentSet.fold(funxacc->(x,None)::acc)rem[]inmatchl,instrwith|[],_->instr|l,(Statement(Variable_statementl'),loc)::rest->(Statement(Variable_statement(List.rev_appendll')),loc)::rest|l,_->(Statement(Variable_statementl),N)::instrmethodsourcex=letx=super#sourcexinmatchxwith|Function_declaration(id,params,body,nid)->letall=IdentSet.diffinsert_exc_inletbody=m#packallbodyinm#exceptid;Function_declaration(id,params,body,nid)|Statement_->xmethodexpressionx=letx=super#expressionxinmatchxwith|EFun(ident,params,body,nid)->letall=IdentSet.diffinsert_exc_inletbody=m#packallbodyin(matchidentwith|Someid->m#exceptid|None->());EFun(ident,params,body,nid)|_->xmethodstatementsl=letl=super#statementslinletl=List.fold_leftl~init:[]~f:(funacc(x,loc)->matchxwith|Expression_statemente->letl=m#spliteinletl=List.fold_leftl~init:acc~f:(funacce->(Expression_statemente,N)::acc)inl|_->(x,loc)::acc)inList.revlendclassclean=object(m)inheritmapassupermethodstatementsl=letrev_append_stxl=matchxwith|Blockb,_->List.rev_appendbl|x->x::linletl=super#statementslinletvars_rev,vars_loc,instr_rev=List.fold_leftl~init:([],N,[])~f:(fun(vars_rev,vars_loc,instr_rev)(x,loc)->matchxwith|Variable_statementlwhenConfig.Flag.compact()->letvars_loc=matchvars_locwith|Pi_asx->x|_->locinList.rev_appendlvars_rev,vars_loc,instr_rev|Empty_statement|Expression_statement(EVar_)->vars_rev,vars_loc,instr_rev|_whenList.is_emptyvars_rev->[],vars_loc,rev_append_st(x,loc)instr_rev|_->([],vars_loc,rev_append_st(x,loc)((Variable_statement(List.revvars_rev),vars_loc)::instr_rev)))inletinstr_rev=matchvars_revwith|[]->instr_rev|vars_rev->(Variable_statement(List.revvars_rev),vars_loc)::instr_revinList.revinstr_revmethodstatements=lets=super#statementsinletb=function|Block[],loc->Empty_statement,loc|Block[x],_->x|b->binletbopt=function|Some(Block[],_)->None|Some(Block[x],_)->Somex|Someb->Someb|None->Noneinmatchswith|If_statement(if',then',else')->If_statement(if',bthen',boptelse')|Do_while_statement(do',while')->Do_while_statement(bdo',while')|While_statement(cond,st)->While_statement(cond,bst)|For_statement(p1,p2,p3,st)->For_statement(p1,p2,p3,bst)|ForIn_statement(param,e,st)->ForIn_statement(param,e,bst)|Switch_statement(e,l,Some[],[])->Switch_statement(e,l,None,[])|s->smethodsourcesl=letappend_stst_revsources_rev=letst=m#statements(List.revst_rev)inletst=List.mapst~f:(fun(s,loc)->Statements,loc)inList.rev_appendstsources_revinletst_rev,sources_rev=List.fold_leftl~init:([],[])~f:(fun(st_rev,sources_rev)(x,loc)->matchxwith|Statements->(s,loc)::st_rev,sources_rev|Function_declaration_asxwhenList.is_emptyst_rev->[],(m#sourcex,loc)::sources_rev|Function_declaration_asx->[],(m#sourcex,loc)::append_stst_revsources_rev)inletsources_rev=matchst_revwith|[]->sources_rev|st_rev->append_stst_revsources_revinList.revsources_revendlettranslate_assign_op=function|Div->SlashEq|Mod->ModEq|Lsl->LslEq|Asr->AsrEq|Lsr->LsrEq|Band->BandEq|Bor->BorEq|Bxor->BxorEq|Mul->StarEq|Plus->PlusEq|Minus->MinusEq|_->assertfalseletis_one=function|ENumn->Num.is_onen|_->falseletassign_op=function|exp,EBin(Plus,exp',exp'')->(matchPoly.(exp=exp'),Poly.(exp=exp'')with|false,false->None|true,false->ifis_oneexp''thenSome(EUn(IncrB,exp))elseSome(EBin(PlusEq,exp,exp''))|false,true->ifis_oneexp'thenSome(EUn(IncrB,exp))elseSome(EBin(PlusEq,exp,exp'))|true,true->Some(EBin(StarEq,exp,ENum(Num.of_int322l))))|exp,EBin(Minus,exp',y)whenPoly.(exp=exp')->ifis_oneythenSome(EUn(DecrB,exp))elseSome(EBin(MinusEq,exp,y))|exp,EBin(Mul,exp',exp'')->(matchPoly.(exp=exp'),Poly.(exp=exp'')with|false,false->None|true,_->Some(EBin(StarEq,exp,exp''))|_,true->Some(EBin(StarEq,exp,exp')))|exp,EBin(((Div|Mod|Lsl|Asr|Lsr|Band|Bxor|Bor)asunop),exp',y)whenPoly.(exp=exp')->Some(EBin(translate_assign_opunop,exp,y))|_->Noneclasssimpl=object(m)inheritmapassupermethodexpressione=lete=super#expressioneinletis_zerox=matchNum.to_stringxwith|"0"|"0."->true|_->falseinmatchewith|EBin(Plus,e1,e2)->(matche2,e1with|ENumn,_whenNum.is_negn->EBin(Minus,e1,ENum(Num.negn))|_,ENumnwhenNum.is_negn->EBin(Minus,e2,ENum(Num.negn))|ENumzero,(ENum_asx)whenis_zerozero->x|(ENum_asx),ENumzerowhenis_zerozero->x|_->e)|EBin(Minus,e1,e2)->(matche2,e1with|ENumn,_whenNum.is_negn->EBin(Plus,e1,ENum(Num.negn))|(ENum_asx),ENumzerowhenis_zerozero->x|_->e)|_->emethodstatements=lets=super#statementsinmatchswith|Block[x]->fstx|_->smethodstatementss=lets=super#statementssinList.fold_rights~init:[]~f:(fun(st,loc)rem->matchstwith|If_statement(cond,(Return_statement(Somee1),_),Some(Return_statement(Somee2),_))->(Return_statement(Some(ECond(cond,e1,e2))),loc)::rem|If_statement(cond,(Expression_statement(EBin(Eq,v1,e1)),_),Some(Expression_statement(EBin(Eq,v2,e2)),_))whenPoly.(v1=v2)->(Expression_statement(EBin(Eq,v1,ECond(cond,e1,e2))),loc)::rem|Variable_statementl1->letx=List.mapl1~f:(function|ident,None->Variable_statement[ident,None],loc|ident,Some(exp,pc)->(matchassign_op(EVarident,exp)with|Somee->Expression_statemente,loc|None->Variable_statement[ident,Some(exp,pc)],loc))inx@rem|_->(st,loc)::rem)methodsourcesl=letappend_stst_revsources_rev=letst=m#statements(List.revst_rev)inletst=List.mapst~f:(function|(Variable_statement[(addr,Some(EFun(None,params,body,loc'),loc))],_)->Function_declaration(addr,params,body,loc'),loc|s,loc->Statements,loc)inList.rev_appendstsources_revinletst_rev,sources_rev=List.fold_leftl~init:([],[])~f:(fun(st_rev,sources_rev)x->matchxwith|Statements,loc->(s,loc)::st_rev,sources_rev|(Function_declaration_asx),locwhenList.is_emptyst_rev->[],(m#sourcex,loc)::sources_rev|(Function_declaration_asx),loc->[],(m#sourcex,loc)::append_stst_revsources_rev)inletsources_rev=matchst_revwith|[]->sources_rev|st_rev->append_stst_revsources_revinList.revsources_revend