123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266(* 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_statement(EVar_)->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)