123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201(* 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.
*)moduleJ=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!
var x = 0/0;
!(x < 0) and x >= 0 give different result
| 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 _ -> J.ENum 1. *)|J.ECond(e,J.ENum"1",J.ENum"0")->e|J.ECond(e,J.ENum"0",J.ENum"1")->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[]->[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_statementiffalseinifx1<>x2thenraiseNot_assignment;letexp=ife1=ethenJ.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),_wheniffalse=unoptiffalse'->if_statement_2(J.EBin(J.And,e,e'))lociftrue'truestopiffalsefalsestop|(J.If_statement(e',iftrue',iffalse'),loc),_wheniffalse=iftrue'->if_statement_2(J.EBin(J.And,e,J.EUn(J.Not,e')))loc(unoptiffalse')truestopiffalsefalsestop|_,(J.If_statement(e',iftrue',iffalse'),loc)wheniftrue=iftrue'->if_statement_2(J.EBin(J.Or,e,e'))lociftruetruestop(unoptiffalse')falsestop|_,(J.If_statement(e',iftrue',iffalse'),loc)wheniftrue=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)->List.fold_leftget_variableacc(e1::el)|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(funacci->matchiwith|None->acc|Somee1->get_variableacce1)acca|J.EObjl->List.fold_left(funacc(_,e1)->get_variableacce1)accl