123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203(* 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(* 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.EAccess_|J.EDot_|J.ENew_|J.EVar_|J.EFun_|J.EStr_|J.EArr_|J.ENum_|J.EObj_|J.EQuote_|J.ERegexp_|J.EUn((J.IncrA|J.IncrB|J.DecrA|J.DecrB),_)->J.EUn(J.Not,e),1inifcost<=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[(x,Somee)],_)]->x,e|(J.Expression_statemente,_)::rem->letx,(e',nid)=assignment_of_statement_listreminx,(J.ESeq(e,e'),nid)|_->raiseNot_assignmentletassignment_of_statementst=matchfststwith|J.Variable_statement[(x,Somee)]->x,e|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->condletrecif_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 *)letx1,(e1,_)=assignment_of_statementiftrueinletx2,(e2,_)=assignment_of_statementiffalseinifPoly.(x1<>x2)thenraiseNot_assignment;letexp=ifPoly.(e1=e)thenJ.EBin(J.Or,e,e2)elseJ.ECond(e,e1,e2)in[J.Variable_statement[x1,Some(exp,loc)],loc]withNot_assignment->(trylete1=expression_of_statementiftrueinlete2=expression_of_statementiffalsein[J.Return_statement(Some(J.ECond(e,e1,e2))),loc]withNot_expression->iftruestopthen(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_2elociftruetruestopiffalsefalsestopletrecget_variableacc=function|J.ESeq(e1,e2)|J.EBin(_,e1,e2)|J.EAccess(e1,e2)->get_variable(get_variableacce1)e2|J.ECond(e1,e2,e3)->get_variable(get_variable(get_variableacce1)e2)e3|J.EUn(_,e1)|J.EDot(e1,_)|J.ENew(e1,None)->get_variableacce1|J.ECall(e1,el,_)|J.ENew(e1,Someel)->(e1,`Not_spread)::el|>List.map~f:(fun(a,_)->a)|>List.fold_left~init:acc~f:get_variable|J.EVar(J.Vv)->Code.Var.Set.addvacc|J.EVar(J.S_)->acc|J.EFun_|J.EStr_|J.EBool_|J.ENum_|J.EQuote_|J.ERegexp_->acc|J.EArra->List.fold_left~f:(funacci->matchiwith|None->acc|Somee1->get_variableacce1)~init:acca|J.EObjl->List.fold_left~f:(funacc(_,e1)->get_variableacce1)~init:accl