123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276(* Js_of_ocaml compiler
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2010 Jérôme Vouillon
* Laboratoire PPS - CNRS Université Paris Diderot
*
* 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!StdlibmoduleJ=Javascriptletrecenot_rece=let((_,cost)asres)=matchewith|J.ESeq(e1,e2)->lete2',cost=enot_rece2inJ.ESeq(e1,e2'),cost|J.ECond(e1,e2,e3)->lete2',cost2=enot_rece2inlete3',cost3=enot_rece3inJ.ECond(e1,e2',e3'),cost2+cost3|J.EBin(op,e1,e2)->(matchopwith|J.Or->lete1',cost1=enot_rece1inlete2',cost2=enot_rece2inJ.EBin(J.And,e1',e2'),cost1+cost2|J.And->lete1',cost1=enot_rece1inlete2',cost2=enot_rece2inJ.EBin(J.Or,e1',e2'),cost1+cost2|J.EqEq->J.EBin(J.NotEq,e1,e2),0|J.NotEq->J.EBin(J.EqEq,e1,e2),0|J.EqEqEq->J.EBin(J.NotEqEq,e1,e2),0|J.NotEqEq->J.EBin(J.EqEqEq,e1,e2),0|J.LtInt->(* not (a < b) *)(* a >= b *)J.EBin(J.GeInt,e1,e2),0|J.GtInt->(* not (a > b) *)(* a <= b *)J.EBin(J.LeInt,e1,e2),0|J.LeInt->J.EBin(J.GtInt,e1,e2),0|J.GeInt->J.EBin(J.LtInt,e1,e2),0(* Disabled: this is not correct!
{[ !(x < 0) ]} and {[ x >= 0 ]} give different result when x = nan
{[
| J.Lt ->
(J.EBin (J.Le, e2, e1), 0)
| J.Le ->
(J.EBin (J.Lt, e2, e1), 0)
]}
*)|_->J.EUn(J.Not,e),1)|J.EUn(J.Not,e)->e,0|J.EUn((J.Neg|J.Pl|J.Typeof|J.Void|J.Delete|J.Bnot),_)->J.EUn(J.Not,e),0|J.EBoolb->J.EBool(notb),0|J.ECall_|J.ECallTemplate_|J.EAccess_|J.EDot_|J.EDotPrivate_|J.ENew_|J.EVar_|J.EPrivName_|J.EFun_|J.EArrow_|J.EStr_|J.EArr_|J.ENum_|J.EObj_|J.ERegexp_|J.EYield_|J.ETemplate_|J.EAssignTarget_|J.EClass_|J.EUn(J.Await,_)|J.EUn((J.IncrA|J.IncrB|J.DecrA|J.DecrB),_)->J.EUn(J.Not,e),1|J.CoverCallExpressionAndAsyncArrowHead_|J.CoverParenthesizedExpressionAndArrowParameterList_->assertfalseinifcost<=1thenreselseJ.EUn(J.Not,e),1letenote=fst(enot_rece)letunblockst=matchstwith|J.Blockl,_->l|_->[st]letblockl=matchlwith|[x]->x|l->J.Blockl,J.NexceptionNot_expressionletrecexpression_of_statement_listl=matchlwith|(J.Return_statement(Somee),_)::_->e|(J.Expression_statemente,_)::rem->J.ESeq(e,expression_of_statement_listrem)|_->raiseNot_expressionletexpression_of_statementst=matchfststwith|J.Return_statement(Somee)->e|J.Blockl->expression_of_statement_listl|_->raiseNot_expressionexceptionNot_assignmentletrecassignment_of_statement_listl=matchlwith|[(J.Variable_statement(Var,[(DeclIdent_asvd)]),_)]->vd|[(J.Variable_statement(Var,[(DeclPattern_asvd)]),_)]->vd|(J.Expression_statemente,_)::rem->(matchassignment_of_statement_listremwith|DeclIdent(x,Some(e',nid))->DeclIdent(x,Some(J.ESeq(e,e'),nid))|DeclIdent(_,None)->assertfalse|DeclPattern(p,(e',nid))->DeclPattern(p,(J.ESeq(e,e'),nid)))|_->raiseNot_assignmentletassignment_of_statementst=matchfststwith|J.Variable_statement(Var,[(DeclIdent(_,Some_)asvd)])->vd|J.Blockl->assignment_of_statement_listl|_->raiseNot_assignmentletsimplify_condition=function|J.ECond(e,J.ENumone,J.ENumzero)whenJ.Num.is_oneone&&J.Num.is_zerozero->e|J.ECond(e,J.ENumzero,J.ENumone)whenJ.Num.is_oneone&&J.Num.is_zerozero->J.EUn(J.Not,e)|J.ECond(J.EBin((J.NotEqEq|J.NotEq),J.ENumn,y),e1,e2)|J.ECond(J.EBin((J.NotEqEq|J.NotEq),y,J.ENumn),e1,e2)->J.ECond(J.EBin(J.Band,y,J.ENumn),e1,e2)|cond->condletrecdepth=function|J.Blockb->depth_blockb+1|Function_declaration(_,(_,_,b,_))->depth_blockb+1|Class_declaration(_,cl)->depth_class_blockcl.body+1|Variable_statement_->1|Empty_statement->1|Expression_statement_->1|If_statement(_,(t,_),None)->deptht+1|If_statement(_,(t,_),Some(f,_))->max(deptht)(depthf)+1|Do_while_statement((s,_),_)->depths+1|While_statement(_,(s,_))->depths+1|For_statement(_,_,_,(s,_))->depths+1|ForIn_statement(_,_,(s,_))->depths+1|ForOf_statement(_,_,(s,_))->depths+1|ForAwaitOf_statement(_,_,(s,_))->depths+1|Continue_statement_->1|Break_statement_->1|Return_statement_->1|Labelled_statement(_,(s,_))->depths|Switch_statement(_,c1,None,c2)->max(depth_block(List.concat_map~f:sndc1))(depth_block(List.concat_map~f:sndc2))|Switch_statement(_,c1,Somel,c2)->max(max(depth_block(List.concat_map~f:sndc1))(depth_block(List.concat_map~f:sndc2)))(depth_blockl)|Throw_statement_->1|Try_statement(b,_,None)->depth_blockb+1|Try_statement(b,_,Someb2)->max(depth_blockb)(depth_blockb2)+1|With_statement(_,(st,_))->depthst+1|Debugger_statement->1|Import_->1|Export_->1anddepth_blockb=List.fold_leftb~init:0~f:(funacc(s,_)->maxacc(depths))anddepth_class_blockb=List.fold_leftb~init:0~f:(funaccs->matchswith|J.CEMethod_->acc|J.CEField_->acc|J.CEStaticBLockb->depth_blockb+2)letrecif_statement_2elociftruetruestopiffalsefalsestop=lete=simplify_conditioneinmatchfstiftrue,fstiffalsewith(* Empty blocks *)|J.Block[],J.Block[]->(matchewith|J.EVar_->[]|_->[J.Expression_statemente,loc])|J.Block[],_->if_statement_2(enote)lociffalsefalsestopiftruetruestop|_,J.Block[]->[J.If_statement(e,iftrue,None),loc]|_->(try(* Generates conditional *)letvd1=assignment_of_statementiftrueinletvd2=assignment_of_statementiffalseinmatchvd1,vd2with|DeclIdent(x1,Some(e1,_)),DeclIdent(x2,Some(e2,_))whenPoly.(x1=x2)->letexp=ifPoly.(e1=e)thenJ.EBin(J.Or,e,e2)elseJ.ECond(e,e1,e2)in[J.Variable_statement(Var,[DeclIdent(x1,Some(exp,loc))]),loc]|DeclPattern(p1,(e1,_)),DeclPattern(p2,(e2,_))whenPoly.(p1=p2)->letexp=ifPoly.(e1=e)thenJ.EBin(J.Or,e,e2)elseJ.ECond(e,e1,e2)in[J.Variable_statement(Var,[DeclPattern(p1,(exp,loc))]),loc]|_->raiseNot_assignmentwithNot_assignment->(trylete1=expression_of_statementiftrueinlete2=expression_of_statementiffalsein[J.Return_statement(Some(J.ECond(e,e1,e2))),loc]withNot_expression->lettruestop,falsestop=iftruestop&&falsestopthenletdtrue=depth(fstiftrue)inletdfalse=depth(fstiffalse)inifdtrue<=dfalsethentrue,falseelsefalse,trueelsetruestop,falsestopiniftruestopthen(J.If_statement(e,iftrue,None),loc)::unblockiffalseelseiffalsestopthen(J.If_statement(enote,iffalse,None),loc)::unblockiftrueelse[J.If_statement(e,iftrue,Someiffalse),loc]))letunoptb=matchbwith|Someb->b|None->J.Block[],J.Nletif_statementelociftruetruestopiffalsefalsestop=(*FIX: should be done at an earlier stage*)lete=simplify_conditioneinmatchiftrue,iffalsewith(* Shared statements *)|(J.If_statement(e',iftrue',iffalse'),loc),_whenPoly.(iffalse=unoptiffalse')->if_statement_2(J.EBin(J.And,e,e'))lociftrue'truestopiffalsefalsestop|(J.If_statement(e',iftrue',iffalse'),loc),_whenPoly.(iffalse=iftrue')->if_statement_2(J.EBin(J.And,e,J.EUn(J.Not,e')))loc(unoptiffalse')truestopiffalsefalsestop|_,(J.If_statement(e',iftrue',iffalse'),loc)whenPoly.(iftrue=iftrue')->if_statement_2(J.EBin(J.Or,e,e'))lociftruetruestop(unoptiffalse')falsestop|_,(J.If_statement(e',iftrue',iffalse'),loc)whenPoly.(iftrue=unoptiffalse')->if_statement_2(J.EBin(J.Or,e,J.EUn(J.Not,e')))lociftruetruestopiftrue'falsestop|_->if_statement_2elociftruetruestopiffalsefalsestop