12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265(* 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.
*)(* Beware automatic semi-colon insertion...
{v
a=b
++c
v}
is not the same as
{v
a=b ++c
v}
see so-called "restricted productions":
the space cannot be replaced by a newline in the following expressions:
{v
e ++
e --
continue e
break e
return e
throw
v}
*)open!Stdlibletstats=Debug.find"output"openJavascriptmodulePP=Pretty_printmoduleMake(D:sigvalsource_map:Source_map.toptionend)=structlettemp_mappings=ref[]letpush_mapping,get_file_index,get_name_index,source_map_enabled=letidx_files=ref0inletidx_names=ref0inletfiles=Hashtbl.create17inletnames=Hashtbl.create17inmatchD.source_mapwith|None->(fun__->()),(fun_->-1),(fun_->-1),false|Somesm->List.iter(List.revsm.Source_map.sources)~f:(funf->Hashtbl.addfilesf!idx_files;incridx_files);((funposm->temp_mappings:=(pos,m)::!temp_mappings),(funfile->tryHashtbl.findfilesfilewithNot_found->letpos=!idx_filesinHashtbl.addfilesfilepos;incridx_files;sm.Source_map.sources<-file::sm.Source_map.sources;pos),(funname->tryHashtbl.findnamesnamewithNot_found->letpos=!idx_namesinHashtbl.addnamesnamepos;incridx_names;sm.Source_map.names<-name::sm.Source_map.names;pos),true)letdebug_enabled=Config.Flag.debuginfo()letoutput_debug_infofloc=(ifdebug_enabledthenmatchlocwith|Pi{Parse_info.name=Somefile;line;col;_}|Pi{Parse_info.src=Somefile;line;col;_}->PP.non_breaking_spacef;PP.stringf(Format.sprintf"/*<<%s %d %d>>*/"filelinecol);PP.non_breaking_spacef|N->()|U|Pi_->PP.non_breaking_spacef;PP.stringf"/*<<?>>*/";PP.non_breaking_spacef);ifsource_map_enabledthenmatchlocwith|N->()|U|Pi{Parse_info.src=None;_}->push_mapping(PP.posf){Source_map.gen_line=-1;gen_col=-1;ori_source=-1;ori_line=-1;ori_col=-1;ori_name=None}|Pi{Parse_info.src=Somefile;line;col;_}->push_mapping(PP.posf){Source_map.gen_line=-1;gen_col=-1;ori_source=get_file_indexfile;ori_line=line;ori_col=col;ori_name=None}letoutput_debug_info_identfnmloc=ifsource_map_enabledthenmatchlocwith|None->()|Some{Parse_info.src=Somefile;line;col;_}->push_mapping(PP.posf){Source_map.gen_line=-1;gen_col=-1;ori_source=get_file_indexfile;ori_line=line;ori_col=col;ori_name=Some(get_name_indexnm)}|Some_->()letidentf=function|S{name;var=Somev;_}->output_debug_info_identfname(Code.Var.get_locv);PP.stringfname|S{name;var=None;loc=Pipi}->output_debug_info_identfname(Somepi);PP.stringfname|S{name;var=None;loc=U|N}->PP.stringfname|V_v->assertfalseletopt_identifierfi=matchiwith|None->()|Somei->PP.spacef;identfiletrecformal_parameter_listfl=matchlwith|[]->()|[i]->identfi|i::r->identfi;PP.stringf",";PP.breakf;formal_parameter_listfr(*
0 Expression
1 AssignementExpression
2 ConditionalExpression
3 LogicalORExpression
4 LogicalANDExpression
5 BitwiseORExpression
6 BitwiseXORExpression
7 BitwiseANDExpression
8 EqualityExpression
9 RelationalExpression
10 ShiftExpression
11 AdditiveExpression
12 MultiplicativeExpression
13 UnaryExpression
14 PostfixExpression
15 LeftHandsideExpression
NewExpression
CallExpression
16 MemberExpression
FunctionExpression
PrimaryExpression
*)letop_precop=matchopwith|Eq|StarEq|SlashEq|ModEq|PlusEq|MinusEq|LslEq|AsrEq|LsrEq|BandEq|BxorEq|BorEq->1,13,1(*
| Or -> 3, 3, 4
| And -> 4, 4, 5
| Bor -> 5, 5, 6
| Bxor -> 6, 6, 7
| Band -> 7, 7, 8
*)|Or->3,3,3|And->4,4,4|Bor->5,5,5|Bxor->6,6,6|Band->7,7,7|EqEq|NotEq|EqEqEq|NotEqEq->8,8,9|Gt|Ge|Lt|Le|InstanceOf|In->9,9,10|Lsl|Lsr|Asr->10,10,11|Plus|Minus->11,11,12|Mul|Div|Mod->12,12,13letop_strop=matchopwith|Eq->"="|StarEq->"*="|SlashEq->"/="|ModEq->"%="|PlusEq->"+="|MinusEq->"-="|Or->"||"|And->"&&"|Bor->"|"|Bxor->"^"|Band->"&"|EqEq->"=="|NotEq->"!="|EqEqEq->"==="|NotEqEq->"!=="|LslEq->"<<="|AsrEq->">>="|LsrEq->">>>="|BandEq->"&="|BxorEq->"^="|BorEq->"|="|Lt->"<"|Le->"<="|Gt->">"|Ge->">="|Lsl->"<<"|Lsr->">>>"|Asr->">>"|Plus->"+"|Minus->"-"|Mul->"*"|Div->"/"|Mod->"%"|InstanceOf|In->assertfalseletunop_strop=matchopwith|Not->"!"|Neg->"-"|Pl->"+"|Bnot->"~"|IncrA|IncrB|DecrA|DecrB|Typeof|Void|Delete->assertfalseletrecends_with_if_without_elsest=matchfststwith|Labelled_statement(_,st)|If_statement(_,_,Somest)|While_statement(_,st)|For_statement(_,_,_,st)|ForIn_statement(_,_,st)->ends_with_if_without_elsest|If_statement(_,_,None)->true|Block_|Variable_statement_|Empty_statement|Expression_statement_|Continue_statement_|Break_statement_|Return_statement_|Throw_statement_|Do_while_statement_|Switch_statement_|Try_statement_|Debugger_statement->falseletrecneed_parenle=matchewith|ESeq(e,_)->l<=0&&need_paren0e|ECond(e,_,_)->l<=2&&need_paren3e|EBin(op,e,_)->letout,lft,_rght=op_precopinl<=out&&need_parenlfte|ECall(e,_,_)|EAccess(e,_)|EDot(e,_)->l<=15&&need_paren15e|EVar_|EStr_|EArr_|EBool_|ENum_|EQuote_|ERegexp_|EUn_|ENew_->false|EFun_|EObj_->trueletbest_string_quotes=letsimple=ref0anddouble=ref0infori=0toString.lengths-1domatchs.[i]with|'\''->incrsimple|'"'->incrdouble|_->()done;if!simple<!doublethen'\''else'"'letarray_str1=Array.init256~f:(funi->String.make1(Char.chri))letarray_conv=Array.init16~f:(funi->String.make1"0123456789abcdef".[i])letpp_stringf?(quote='"')?(utf=false)s=letquote_s=String.make1quoteinPP.stringfquote_s;letl=String.lengthsinfori=0tol-1doletc=s.[i]inmatchcwith|'\000'wheni=l-1||not(Char.is_nums.[i+1])->PP.stringf"\\0"|'\b'->PP.stringf"\\b"|'\t'->PP.stringf"\\t"|'\n'->PP.stringf"\\n"(* This escape sequence is not supported by IE < 9
| '\011' -> "\\v"
*)|'\012'->PP.stringf"\\f"(* https://github.com/ocsigen/js_of_ocaml/issues/898 *)|'/'wheni>0&&Char.equals.[i-1]'<'->PP.stringf"\\/"|'\\'whennotutf->PP.stringf"\\\\"|'\r'->PP.stringf"\\r"|'\000'..'\031'|'\127'->letc=Char.codecinPP.stringf"\\x";PP.stringf(Array.unsafe_getarray_conv(clsr4));PP.stringf(Array.unsafe_getarray_conv(cland0xf))|'\128'..'\255'whennotutf->letc=Char.codecinPP.stringf"\\x";PP.stringf(Array.unsafe_getarray_conv(clsr4));PP.stringf(Array.unsafe_getarray_conv(cland0xf))|_->ifChar.equalcquotethen(PP.stringf"\\";PP.stringf(Array.unsafe_getarray_str1(Char.codec)))elsePP.stringf(Array.unsafe_getarray_str1(Char.codec))done;PP.stringfquote_sletrecexpressionlfe=matchewith|EVarv->identfv|ESeq(e1,e2)->ifl>0then(PP.start_groupf1;PP.stringf"(");expression0fe1;PP.stringf",";PP.breakf;expression0fe2;ifl>0then(PP.stringf")";PP.end_groupf)|EFun(i,l,b,pc)->PP.start_groupf1;PP.start_groupf0;PP.start_groupf0;PP.stringf"function";opt_identifierfi;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"(";formal_parameter_listfl;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"{";function_bodyfb;output_debug_infofpc;PP.stringf"}";PP.end_groupf;PP.end_groupf|ECall(e,el,loc)->ifl>15then(PP.start_groupf1;PP.stringf"(");output_debug_infofloc;PP.start_groupf1;expression15fe;PP.breakf;PP.start_groupf1;PP.stringf"(";argumentsfel;PP.stringf")";PP.end_groupf;PP.end_groupf;ifl>15then(PP.stringf")";PP.end_groupf)|EStr(s,kind)->letquote=best_string_quotesinpp_stringf~utf:Poly.(kind=`Utf8)~quotes|EBoolb->PP.stringf(ifbthen"true"else"false")|ENumnum->lets=Num.to_stringnuminletneed_parent=ifNum.is_negnumthenl>13(* Negative numbers may need to be parenthesized. *)elsel=15(* Parenthesize as well when followed by a dot. *)&&(not(Char.equals.[0]'I'))(* Infinity *)&¬(Char.equals.[0]'N')(* NaN *)inifneed_parentthenPP.stringf"(";PP.stringfs;ifneed_parentthenPP.stringf")"|EUn(Typeof,e)->ifl>13then(PP.start_groupf1;PP.stringf"(");PP.start_groupf0;PP.stringf"typeof";PP.spacef;expression13fe;PP.end_groupf;ifl>13then(PP.stringf")";PP.end_groupf)|EUn(Void,e)->ifl>13then(PP.start_groupf1;PP.stringf"(");PP.start_groupf0;PP.stringf"void";PP.spacef;expression13fe;PP.end_groupf;ifl>13then(PP.stringf")";PP.end_groupf)|EUn(Delete,e)->ifl>13then(PP.start_groupf1;PP.stringf"(");PP.start_groupf0;PP.stringf"delete";PP.spacef;expression13fe;PP.end_groupf;ifl>13then(PP.stringf")";PP.end_groupf)|EUn(((IncrA|DecrA|IncrB|DecrB)asop),e)->ifl>13then(PP.start_groupf1;PP.stringf"(");ifPoly.(op=IncrA)||Poly.(op=DecrA)thenexpression13fe;ifPoly.(op=IncrA)||Poly.(op=IncrB)thenPP.stringf"++"elsePP.stringf"--";ifPoly.(op=IncrB)||Poly.(op=DecrB)thenexpression13fe;ifl>13then(PP.stringf")";PP.end_groupf)|EUn(op,e)->ifl>13then(PP.start_groupf1;PP.stringf"(");PP.stringf(unop_strop);PP.spacef;expression13fe;ifl>13then(PP.stringf")";PP.end_groupf)|EBin(InstanceOf,e1,e2)->letout,lft,rght=op_precInstanceOfinifl>outthen(PP.start_groupf1;PP.stringf"(");PP.start_groupf0;expressionlftfe1;PP.spacef;PP.stringf"instanceof";PP.spacef;expressionrghtfe2;PP.end_groupf;ifl>outthen(PP.stringf")";PP.end_groupf)|EBin(In,e1,e2)->letout,lft,rght=op_precInstanceOfinifl>outthen(PP.start_groupf1;PP.stringf"(");PP.start_groupf0;expressionlftfe1;PP.spacef;PP.stringf"in";PP.spacef;expressionrghtfe2;PP.end_groupf;ifl>outthen(PP.stringf")";PP.end_groupf)|EBin(op,e1,e2)->letout,lft,rght=op_precopinifl>outthen(PP.start_groupf1;PP.stringf"(");expressionlftfe1;PP.spacef;PP.stringf(op_strop);PP.spacef;expressionrghtfe2;ifl>outthen(PP.stringf")";PP.end_groupf)|EArrel->PP.start_groupf1;PP.stringf"[";element_listfel;PP.stringf"]";PP.end_groupf|EAccess(e,e')->ifl>15then(PP.start_groupf1;PP.stringf"(");PP.start_groupf1;expression15fe;PP.breakf;PP.start_groupf1;PP.stringf"[";expression0fe';PP.stringf"]";PP.end_groupf;PP.end_groupf;ifl>15then(PP.stringf")";PP.end_groupf)|EDot(e,nm)->ifl>15then(PP.start_groupf1;PP.stringf"(");expression15fe;PP.stringf".";PP.stringfnm;ifl>15then(PP.stringf")";PP.end_groupf)|ENew(e,None)->(*FIX: should omit parentheses when possible*)ifl>15then(PP.start_groupf1;PP.stringf"(");PP.start_groupf1;PP.stringf"new";PP.spacef;expression16fe;PP.breakf;PP.stringf"()";PP.end_groupf;ifl>15then(PP.stringf")";PP.end_groupf)|ENew(e,Someel)->ifl>15then(PP.start_groupf1;PP.stringf"(");PP.start_groupf1;PP.stringf"new";PP.spacef;expression16fe;PP.breakf;PP.start_groupf1;PP.stringf"(";argumentsfel;PP.stringf")";PP.end_groupf;PP.end_groupf;ifl>15then(PP.stringf")";PP.end_groupf)|ECond(e,e1,e2)->ifl>2then(PP.start_groupf1;PP.stringf"(");PP.start_groupf1;PP.start_groupf0;expression3fe;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"?";expression1fe1;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf":";expression1fe2;PP.end_groupf;PP.end_groupf;ifl>2then(PP.stringf")";PP.end_groupf)|EObjlst->PP.start_groupf1;PP.stringf"{";property_name_and_value_listflst;PP.stringf"}";PP.end_groupf|ERegexp(s,opt)->(PP.stringf"/";PP.stringfs;PP.stringf"/";matchoptwith|None->()|Someo->PP.stringfo)|EQuotes->PP.stringf"(";PP.stringfs;PP.stringf")"andproperty_namefn=matchnwith|PNIs->PP.stringfs|PNSs->letquote=best_string_quotesinpp_stringf~utf:true~quotes|PNNv->expression0f(ENumv)andproperty_name_and_value_listfl=matchlwith|[]->()|[(pn,e)]->PP.start_groupf0;property_namefpn;PP.stringf":";PP.breakf;expression1fe;PP.end_groupf|(pn,e)::r->PP.start_groupf0;property_namefpn;PP.stringf":";PP.breakf;expression1fe;PP.end_groupf;PP.stringf",";PP.breakf;property_name_and_value_listfrandelement_listfel=matchelwith|[]->()|[e]->(matchewith|None->PP.stringf","|Somee->PP.start_groupf0;expression1fe;PP.end_groupf)|e::r->(matchewith|None->()|Somee->PP.start_groupf0;expression1fe;PP.end_groupf);PP.stringf",";PP.breakf;element_listfrandfunction_bodyfb=source_elementsf~skip_last_semi:truebandargumentsfl=matchlwith|[]->()|[(e,s)]->PP.start_groupf0;(matchswith|`Spread->PP.stringf"..."|`Not_spread->());expression1fe;PP.end_groupf|(e,s)::r->PP.start_groupf0;(matchswith|`Spread->PP.stringf"..."|`Not_spread->());expression1fe;PP.end_groupf;PP.stringf",";PP.breakf;argumentsfrandvariable_declarationf(i,init)=matchinitwith|None->identfi|Some(e,pc)->PP.start_groupf1;output_debug_infofpc;identfi;PP.stringf"=";PP.breakf;expression1fe;PP.end_groupfandvariable_declaration_list_auxfl=matchlwith|[]->assertfalse|[d]->variable_declarationfd|d::r->variable_declarationfd;PP.stringf",";PP.breakf;variable_declaration_list_auxfrandvariable_declaration_listclosef=function|[]->()|[(i,None)]->PP.start_groupf1;PP.stringf"var";PP.spacef;identfi;ifclosethenPP.stringf";";PP.end_groupf|[(i,Some(e,pc))]->PP.start_groupf1;output_debug_infofpc;PP.stringf"var";PP.spacef;identfi;PP.stringf"=";PP.break1f;PP.start_groupf0;expression1fe;ifclosethenPP.stringf";";PP.end_groupf;PP.end_groupf|l->PP.start_groupf1;PP.stringf"var";PP.spacef;variable_declaration_list_auxfl;ifclosethenPP.stringf";";PP.end_groupfandopt_expressionlfe=matchewith|None->()|Somee->expressionlfeandstatement?(last=false)f(s,loc)=letlast_semi()=iflastthen()elsePP.stringf";"inoutput_debug_infofloc;matchswith|Blockb->blockfb|Variable_statementl->variable_declaration_list(notlast)fl|Empty_statement->PP.stringf";"|Debugger_statement->PP.stringf"debugger";last_semi()|Expression_statemente->(* Parentheses are required when the expression
starts syntactically with "{" or "function" *)ifneed_paren0ethen(PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";last_semi();PP.end_groupf)else(PP.start_groupf0;expression0fe;last_semi();PP.end_groupf)|If_statement(e,s1,(Some_ass2))whenends_with_if_without_elses1->(* Dangling else issue... *)statement~lastf(If_statement(e,(Block[s1],N),s2),N)|If_statement(e,s1,Some((Block_,_)ass2))->PP.start_groupf0;PP.start_groupf1;PP.stringf"if";PP.breakf;PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.break1f;PP.start_groupf0;statementfs1;PP.end_groupf;PP.breakf;PP.stringf"else";PP.break1f;PP.start_groupf0;statement~lastfs2;PP.end_groupf;PP.end_groupf|If_statement(e,s1,Somes2)->PP.start_groupf0;PP.start_groupf1;PP.stringf"if";PP.breakf;PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.break1f;PP.start_groupf0;statementfs1;PP.end_groupf;PP.breakf;PP.stringf"else";PP.space~indent:1f;PP.start_groupf0;statement~lastfs2;PP.end_groupf;PP.end_groupf|If_statement(e,s1,None)->PP.start_groupf1;PP.start_groupf0;PP.stringf"if";PP.breakf;PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf0;statement~lastfs1;PP.end_groupf;PP.end_groupf|While_statement(e,s)->PP.start_groupf1;PP.start_groupf0;PP.stringf"while";PP.breakf;PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf0;statement~lastfs;PP.end_groupf;PP.end_groupf|Do_while_statement(((Block_,_)ass),e)->PP.start_groupf0;PP.stringf"do";PP.break1f;PP.start_groupf0;statementfs;PP.end_groupf;PP.breakf;PP.stringf"while";PP.break1f;PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";last_semi();PP.end_groupf;PP.end_groupf|Do_while_statement(s,e)->PP.start_groupf0;PP.stringf"do";PP.space~indent:1f;PP.start_groupf0;statementfs;PP.end_groupf;PP.breakf;PP.stringf"while";PP.breakf;PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";last_semi();PP.end_groupf;PP.end_groupf|For_statement(e1,e2,e3,s)->PP.start_groupf1;PP.start_groupf0;PP.stringf"for";PP.breakf;PP.start_groupf1;PP.stringf"(";(matche1with|Lefte->opt_expression0fe|Rightl->variable_declaration_listfalsefl);PP.stringf";";PP.breakf;opt_expression0fe2;PP.stringf";";PP.breakf;opt_expression0fe3;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf0;statement~lastfs;PP.end_groupf;PP.end_groupf|ForIn_statement(e1,e2,s)->PP.start_groupf1;PP.start_groupf0;PP.stringf"for";PP.breakf;PP.start_groupf1;PP.stringf"(";(matche1with|Lefte->expression0fe|Rightv->variable_declaration_listfalsef[v]);PP.spacef;PP.stringf"in";PP.breakf;PP.spacef;expression0fe2;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf0;statement~lastfs;PP.end_groupf;PP.end_groupf|Continue_statementNone->PP.stringf"continue";last_semi()|Continue_statement(Somes)->PP.stringf"continue ";PP.stringf(Javascript.Label.to_strings);last_semi()|Break_statementNone->PP.stringf"break";last_semi()|Break_statement(Somes)->PP.stringf"break ";PP.stringf(Javascript.Label.to_strings);last_semi()|Return_statemente->(matchewith|None->PP.stringf"return";last_semi()|Some(EFun(i,l,b,pc))->PP.start_groupf1;PP.start_groupf0;PP.start_groupf0;PP.stringf"return function";opt_identifierfi;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"(";formal_parameter_listfl;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"{";function_bodyfb;output_debug_infofpc;PP.stringf"}";last_semi();PP.end_groupf;PP.end_groupf|Somee->PP.start_groupf7;PP.stringf"return";PP.non_breaking_spacef;PP.start_groupf0;expression0fe;last_semi();PP.end_groupf;PP.end_groupf(* There MUST be a space between the return and its
argument. A line return will not work *))|Labelled_statement(i,s)->PP.stringf(Javascript.Label.to_stringi);PP.stringf":";PP.breakf;statement~lastfs|Switch_statement(e,cc,def,cc')->PP.start_groupf1;PP.start_groupf0;PP.stringf"switch";PP.breakf;PP.start_groupf1;PP.stringf"(";expression0fe;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"{";letoutput_onelast(e,sl)=PP.start_groupf1;PP.start_groupf1;PP.stringf"case";PP.spacef;expression0fe;PP.stringf":";PP.end_groupf;PP.breakf;PP.start_groupf0;statement_list~skip_last_semi:lastfsl;PP.end_groupf;PP.end_groupf;PP.breakfinletreclooplast=function|[]->()|[x]->output_onelastx|x::xs->output_onefalsex;looplastxsinloop(Option.is_nonedef&&List.is_emptycc')cc;(matchdefwith|None->()|Somedef->PP.start_groupf1;PP.stringf"default:";PP.breakf;PP.start_groupf0;statement_list~skip_last_semi:(List.is_emptycc')fdef;PP.end_groupf;PP.end_groupf);looptruecc';PP.stringf"}";PP.end_groupf;PP.end_groupf|Throw_statemente->PP.start_groupf6;PP.stringf"throw";PP.non_breaking_spacef;PP.start_groupf0;expression0fe;last_semi();PP.end_groupf;PP.end_groupf(* There must be a space between the return and its
argument. A line return would not work *)|Try_statement(b,ctch,fin)->PP.start_groupf0;PP.stringf"try";PP.space~indent:1f;blockfb;(matchctchwith|None->()|Some(i,b)->PP.breakf;PP.start_groupf1;PP.stringf"catch(";identfi;PP.stringf")";PP.breakf;blockfb;PP.end_groupf);(matchfinwith|None->()|Someb->PP.breakf;PP.start_groupf1;PP.stringf"finally";PP.spacef;blockfb;PP.end_groupf);PP.end_groupfandstatement_listf?skip_last_semib=matchbwith|[]->()|[s]->statementf?last:skip_last_semis|s::r->statementfs;PP.breakf;statement_listf?skip_last_semirandblockfb=PP.start_groupf1;PP.stringf"{";statement_list~skip_last_semi:truefb;PP.stringf"}";PP.end_groupfandsource_elementf?skip_last_semise=matchsewith|Statements,loc->statementf?last:skip_last_semi(s,loc)|Function_declaration(i,l,b,loc'),loc->output_debug_infofloc;PP.start_groupf1;PP.start_groupf0;PP.start_groupf0;PP.stringf"function";PP.spacef;identfi;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"(";formal_parameter_listfl;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"{";function_bodyfb;output_debug_infofloc';PP.stringf"}";PP.end_groupf;PP.end_groupfandsource_elementsf?skip_last_semise=matchsewith|[]->()|[s]->source_elementf?skip_last_semis|s::r->source_elementfs;PP.breakf;source_elementsf?skip_last_semirandprogramfs=source_elementsfsendletpart_of_ident=leta=Array.init256~f:(funi->matchChar.chriwith|'a'..'z'|'A'..'Z'|'0'..'9'|'_'|'$'->true|_->false)infunc->Array.unsafe_geta(Char.codec)letneed_spaceab=(* do not concat 2 different identifier *)(part_of_identa&&part_of_identb)(* do not generate end_of_line_comment.
handle the case of "num / /* comment */ b " *)||matcha,bwith|'/','/'(* https://github.com/ocsigen/js_of_ocaml/issues/507 *)|'-','-'|'+','+'->true|_,_->falseletprogramf?source_mapp=letsmo=matchsource_mapwith|None->None|Some(_,sm)->SomesminletmoduleO=Make(structletsource_map=smoend)inPP.set_needed_space_functionfneed_space;PP.start_groupf0;O.programfp;PP.end_groupf;PP.newlinef;(matchsource_mapwith|None->()|Some(out_file,sm)->letsm={smwithSource_map.sources=List.revsm.Source_map.sources;Source_map.names=List.revsm.Source_map.names}inletsources=sm.Source_map.sourcesinletsources_content=matchsm.Source_map.sources_contentwith|None->None|Some[]->Some(List.mapsources~f:(funfile->matchBuiltins.findfilewith|Somef->Some(Builtins.File.contentf)|None->ifSys.file_existsfilethenletcontent=Fs.read_filefileinSomecontentelseNone))|Some_->assertfalseinletsources=List.mapsources~f:(funfilename->matchBuiltins.findfilenamewith|None->filename|Some_->Filename.concat"/builtin"filename)inletmappings=List.map!O.temp_mappings~f:(fun(pos,m)->{mwith(* [p_line] starts at zero, [gen_line] at 1 *)Source_map.gen_line=pos.PP.p_line+1;Source_map.gen_col=pos.PP.p_col})inletsm={smwithSource_map.sources;sources_content;mappings}inleturlData=matchout_filewith|None->letdata=Source_map_io.to_stringsmin"data:application/json;base64,"^Base64.encode_exndata|Someout_file->Source_map_io.to_filesmout_file;Filename.basenameout_fileinPP.newlinef;PP.stringf(Printf.sprintf"//# sourceMappingURL=%s\n"urlData));ifstats()thenletsizei=Printf.sprintf"%.2fKo"(float_of_inti/.1024.)inlet_percentnd=Printf.sprintf"%.1f%%"(float_of_intn*.100./.float_of_intd)inlettotal_s=PP.totalfinFormat.eprintf"total size : %s@."(sizetotal_s)