123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172(* 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}
*)(*
Source maps
===========
Most of this information was obtained by running the Firefox and
Chrome debuggers on some test programs.
The location of a declaration is determined by the first character of
the expression.
var x = e
^
The location of other statements is determined by looking at the first
character of the statement.
return e
^
Chrome will also stop at the very character after a return statement
before returning (which can be ambigous).
return e;if ...
^
The location of the end of the function is determined by the closing brace.
Firefox will always stop their. Chrome only if there is no return statement.
function f() { ... }
^
For an arrow function Firefox stops on the last character, while
Chrome stops on the character right after.
(x)=>x+1
^^
In Chrome the location of a function call is at the start of the name
of the function when it is explicit.
f(e) Math.cos(1.)
^ ^
Otherwise, the location of the opening parenthesis is used. Firefox
always uses this location.
(0,f)(e)(e')
^ ^
Usually, Chrome stops at the begining of statements.
if (e) { ... }
^
Firefox will rather stop on the expression when there is one.
if (e) { ... }
^
The debugger don't stop at some statements, such as function
declarations, labelled statements, and block statements.
Chrome uses the name associated to the location of each bound variable
to determine its name [1].
function f(x) { var y = ... }
^ ^ ^
Chrome uses the location of the opening parenthesis of a function
declaration to determine the function name in the stack [2].
function f() { ... }
^
[1] https://github.com/ChromeDevTools/devtools-frontend/blob/11db398f811784395a6706cf3f800014d98171d9/front_end/models/source_map_scopes/NamesResolver.ts#L238-L243
[2] https://github.com/ChromeDevTools/devtools-frontend/blob/11db398f811784395a6706cf3f800014d98171d9/front_end/models/source_map_scopes/NamesResolver.ts#L765-L768
*)open!Stdlibletstats=Debug.find"output"openJavascriptmodulePP=Pretty_printmoduleMake(D:sigvalpush_mapping:Pretty_print.pos->Source_map.map->unitvalget_file_index:string->intvalget_name_index:string->intvalhidden_location:Source_map.mapvalsource_map_enabled:boolvalaccept_unnamed_var:boolend)=structopenDletnane_of_label=function|Javascript.Label.L_->assertfalse|Javascript.Label.Sn->nletdebug_enabled=Config.Flag.debuginfo()letcurrent_loc=refUletlast_mapping_has_a_name=reffalseletoutput_debug_infofloc=letloc=(* We force a new mapping after an identifier, to avoid its name
to bleed over other identifiers, using the current location
when none is provided. *)matchlocwith|Nwhen!last_mapping_has_a_name->!current_loc|_->locinmatchlocwith|N->()|_->letlocation_changed=not(location_equalloc!current_loc)in(ifsource_map_enabled&&(!last_mapping_has_a_name||location_changed)thenmatchlocwith|N|U|Pi{Parse_info.src=None|Some"";_}->push_mapping(PP.posf)hidden_location|Pi{Parse_info.src=Somefile;line;col;_}->push_mapping(PP.posf)(Source_map.Gen_Ori{gen_line=-1;gen_col=-1;ori_source=get_file_indexfile;ori_line=line;ori_col=col}));(ifdebug_enabled&&location_changedthenmatchlocwith|N|U->PP.non_breaking_spacef;PP.stringf"/*<<?>>*/";PP.non_breaking_spacef|Pipi->PP.non_breaking_spacef;PP.stringf(Format.sprintf"/*<<%s>>*/"(Parse_info.to_stringpi));PP.non_breaking_spacef);current_loc:=loc;last_mapping_has_a_name:=falseletoutput_debug_info_identfnm_opt=ifsource_map_enabledthenmatchnm_optwith|None->(* Make sure that the name of a previous identifier does not
bleed on this one. *)output_debug_infofN|Somenm->last_mapping_has_a_name:=true;push_mapping(PP.posf)(match!current_locwith|N|U|Pi{Parse_info.src=Some""|None;_}->(* Use a dummy location. It is going to be ignored anyway *)letori_source=matchhidden_locationwith|Source_map.Gen_Ori{ori_source;_}->ori_source|_->0inSource_map.Gen_Ori_Name{gen_line=-1;gen_col=-1;ori_source;ori_line=1;ori_col=0;ori_name=get_name_indexnm}|Pi{Parse_info.src=Somefile;line;col;_}->Source_map.Gen_Ori_Name{gen_line=-1;gen_col=-1;ori_source=get_file_indexfile;ori_line=line;ori_col=col;ori_name=get_name_indexnm})letidentf~kind=function|S{name=Utf8name;var=Somev;_}->(matchkindwith|`Binding->output_debug_info_identf(Code.Var.get_namev)|`Reference->());iffalsethenPP.stringf(Printf.sprintf"/* %d */"(Code.Var.idxv));PP.stringfname|S{name=Utf8name;var=None;_}->PP.stringfname|Vv->assertaccept_unnamed_var;PP.stringf(Format.asprintf"<%a>"Code.Var.printv)letopt_identifierf~kindi=matchiwith|None->()|Somei->PP.spacef;identf~kindiletearly_error_=assertfalsetypeprec=|Expression(* 0 *)|AssignementExpression(* 1 *)|ConditionalExpression(* 2 *)|ShortCircuitExpression|CoalesceExpression|LogicalORExpression(* 3 *)|LogicalANDExpression(* 4 *)|BitwiseORExpression(* 5 *)|BitwiseXORExpression(* 6 *)|BitwiseANDExpression(* 7 *)|EqualityExpression(* 8 *)|RelationalExpression(* 9 *)|ShiftExpression(* 10 *)|AdditiveExpression(* 11 *)|MultiplicativeExpression(* 12 *)|ExponentiationExpression|UnaryExpression(* 13 *)|UpdateExpression(* 14 *)|LeftHandSideExpression(* 15 *)|NewExpression|CallOrMemberExpression|MemberExpression(* 16 *)modulePrec=structletcompare(a:prec)(b:prec)=Poly.compareab[@@@ocaml.warning"-32"]let(<=)ab=compareab<=0let(>=)ab=compareab>=0let(<)ab=compareab<0let(>)ab=compareab>0let(=)ab=compareab=0endletop_precop=matchopwith|Eq|StarEq|SlashEq|ModEq|PlusEq|MinusEq|LslEq|AsrEq|LsrEq|BandEq|BxorEq|BorEq|OrEq|AndEq|ExpEq|CoalesceEq->AssignementExpression,LeftHandSideExpression,AssignementExpression|Coalesce->CoalesceExpression,BitwiseORExpression,BitwiseORExpression|Or->LogicalORExpression,LogicalORExpression,LogicalORExpression|And->LogicalANDExpression,LogicalANDExpression,LogicalANDExpression|Bor->BitwiseORExpression,BitwiseORExpression,BitwiseORExpression|Bxor->BitwiseXORExpression,BitwiseXORExpression,BitwiseXORExpression|Band->BitwiseANDExpression,BitwiseANDExpression,BitwiseANDExpression|EqEq|NotEq|EqEqEq|NotEqEq->EqualityExpression,EqualityExpression,RelationalExpression|Gt|GtInt|Ge|GeInt|Lt|LtInt|Le|LeInt|InstanceOf|In->RelationalExpression,RelationalExpression,ShiftExpression|Lsl|Lsr|Asr->ShiftExpression,ShiftExpression,AdditiveExpression|Plus|Minus->AdditiveExpression,AdditiveExpression,MultiplicativeExpression|Mul|Div|Mod->MultiplicativeExpression,MultiplicativeExpression,ExponentiationExpression|Exp->ExponentiationExpression,UpdateExpression,ExponentiationExpressionletop_strop=matchopwith|Eq->"="|StarEq->"*="|SlashEq->"/="|ModEq->"%="|PlusEq->"+="|MinusEq->"-="|Or->"||"|OrEq->"||="|And->"&&"|AndEq->"&&="|Bor->"|"|Bxor->"^"|Band->"&"|EqEq->"=="|NotEq->"!="|EqEqEq->"==="|NotEqEq->"!=="|LslEq->"<<="|AsrEq->">>="|LsrEq->">>>="|BandEq->"&="|BxorEq->"^="|BorEq->"|="|Lt|LtInt->"<"|Le|LeInt->"<="|Gt|GtInt->">"|Ge|GeInt->">="|Lsl->"<<"|Lsr->">>>"|Asr->">>"|Plus->"+"|Minus->"-"|Mul->"*"|Div->"/"|Mod->"%"|Exp->"**"|ExpEq->"**="|CoalesceEq->"??="|Coalesce->"??"|InstanceOf|In->assertfalseletunop_strop=matchopwith|Not->"!"|Neg->"-"|Pl->"+"|Bnot->"~"|IncrA|IncrB|DecrA|DecrB|Typeof|Void|Delete|Await->assertfalseletrecends_with_if_without_elsest=matchfststwith|Labelled_statement(_,st)|If_statement(_,_,Somest)|While_statement(_,st)|For_statement(_,_,_,st)|With_statement(_,st)|ForIn_statement(_,_,st)->ends_with_if_without_elsest|ForOf_statement(_,_,st)->ends_with_if_without_elsest|ForAwaitOf_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_|Function_declaration_|Class_declaration_|Debugger_statement|Import_|Export_->falseletstarts_with~obj~funct~class_~let_identifier~async_identifierle=letrectraversele=matchewith|EObj_->obj|EFun_->funct|EClass_->class_|EVar(S{name=Utf8"let";_})->let_identifier|EVar(S{name=Utf8"async";_})->async_identifier|ESeq(e,_)->Prec.(l<=Expression)&&traverseExpressione|ECond(e,_,_)->Prec.(l<=ConditionalExpression)&&traverseShortCircuitExpressione|EAssignTarget(ObjectTarget_)->obj|EAssignTarget(ArrayTarget_)->false|EBin(op,e,_)->letout,lft,_rght=op_precopinPrec.(l<=out)&&traverselfte|EUn((IncrA|DecrA),e)->Prec.(l<=UpdateExpression)&&traverseLeftHandSideExpressione|ECallTemplate(EFun_,_,_)->(* We force parens around the function in that case.*)false|ECallTemplate(e,_,_)|ECall(e,_,_,_)|EAccess(e,_,_)|EDot(e,_,_)|EDotPrivate(e,_,_)->traverseCallOrMemberExpressione|EArrow_|EVar_|EStr_|ETemplate_|EArr_|EBool_|ENum_|ERegexp_|EUn_|ENew_|EYield_|EPrivName_->false|CoverCallExpressionAndAsyncArrowHeade|CoverParenthesizedExpressionAndArrowParameterListe->early_erroreintraverseleletcontains~in_le=letrectraversele=matchewith|EObj_->false|EFun_->false|EClass_->false|EVar(S{name=Utf8"in";_})->true|ESeq(e1,e2)->Prec.(l<=Expression)&&(traverseExpressione1||traverseExpressione2)|ECond(e1,e2,e3)->Prec.(l<=ConditionalExpression)&&(traverseShortCircuitExpressione1||traverseShortCircuitExpressione2||traverseShortCircuitExpressione3)|EAssignTarget(ObjectTarget_)->false|EAssignTarget(ArrayTarget_)->false|EBin(op,e1,e2)->letout,lft,rght=op_precopinPrec.(l<=out)&&((matchopwith|In->in_|_->false)||traverselfte1||traverserghte2)|EUn((IncrA|DecrA|IncrB|DecrB),e)->Prec.(l<=UpdateExpression)&&traverseLeftHandSideExpressione|EUn(_,e)->Prec.(l<=UnaryExpression)&&traverseUnaryExpressione|ECallTemplate(EFun_,_,_)->(* We force parens around the function in that case.*)false|ECallTemplate(e,_,_)|ECall(e,_,_,_)|EAccess(e,_,_)|EDot(e,_,_)|EDotPrivate(e,_,_)->traverseCallOrMemberExpressione|EArrow_|EVar_|EStr_|ETemplate_|EArr_|EBool_|ENum_|ERegexp_|ENew_|EYield_|EPrivName_->false|CoverCallExpressionAndAsyncArrowHeade|CoverParenthesizedExpressionAndArrowParameterListe->early_erroreintraversele(* The debuggers do not stop on some statements, like function
declarations. So there is no point in outputting some debug
information there. *)letstop_on_statementst=matchstwith|Block_|Variable_statement_|Function_declaration_|Class_declaration_|Empty_statement|Labelled_statement_|Import_|Export_->false|Expression_statement_|If_statement_|Do_while_statement_|While_statement_|For_statement_|ForIn_statement_|ForOf_statement_|ForAwaitOf_statement_|Continue_statement_|Break_statement_|Return_statement_|With_statement_|Switch_statement_|Throw_statement_|Try_statement_|Debugger_statement->trueletbest_string_quotes=letsimple=ref0anddouble=ref0infori=0toString.lengths-1domatchs.[i]with|'\''->incrsimple|'"'->incrdouble|_->()done;if!simple<!doublethen'\''else'"'letpp_stringf?(quote='"')s=letl=String.lengthsinletb=Buffer.create(String.lengths+2)inBuffer.add_charbquote;fori=0tol-1doletc=s.[i]inmatchcwith|'\000'wheni=l-1||not(Char.is_digits.[i+1])->Buffer.add_stringb"\\0"|'\b'(* 008 *)->Buffer.add_stringb"\\b"|'\t'(* 009 *)->Buffer.add_stringb"\\t"|'\n'(* 010 *)->Buffer.add_stringb"\\n"|'\011'->Buffer.add_stringb"\\v"|'\012'->Buffer.add_stringb"\\f"|'\r'(* 013 *)->Buffer.add_stringb"\\r"(* https://github.com/ocsigen/js_of_ocaml/issues/898 *)|'/'wheni>0&&Char.equals.[i-1]'<'->Buffer.add_stringb"\\/"|'\000'..'\031'|'\127'->Buffer.add_stringb"\\x";Buffer.add_char_hexbc|_->ifChar.equalcquotethen(Buffer.add_charb'\\';Buffer.add_charbc)elseBuffer.add_charbcdone;Buffer.add_charbquote;PP.stringf(Buffer.contentsb)letpp_string_litf(Stdlib.Utf8_string.Utf8s)=letquote=best_string_quotesinpp_stringf~quotesletpp_ident_or_string_litf(Stdlib.Utf8_string.Utf8s_litass)=ifis_idents_litthenPP.stringfs_litelsepp_string_litfsletreccomma_listf~force_last_commaf_eltl=matchlwith|[]->()|[x]->PP.start_groupf0;f_eltfx;ifforce_last_commaxthenPP.stringf",";PP.end_groupf|x::r->PP.start_groupf0;f_eltfx;PP.end_groupf;PP.stringf",";PP.spacef;comma_listf~force_last_commaf_eltrletcomma_list_restf~force_last_commaf_eltlf_restrest=matchl,restwith|[],None->()|[],Somerest->PP.start_groupf0;PP.stringf"...";f_restfrest;PP.end_groupf|l,None->comma_listf~force_last_commaf_eltl|l,Somer->comma_listf~force_last_comma:(fun_->false)f_eltl;PP.stringf",";PP.spacef;PP.start_groupf0;PP.stringf"...";f_restfr;PP.end_groupfletrecexpression(l:prec)fe=matchewith|EVarv->identf~kind:`Referencev|ESeq(e1,e2)->ifPrec.(l>Expression)then(PP.start_groupf1;PP.stringf"(");expressionExpressionfe1;PP.stringf",";PP.spacef;expressionExpressionfe2;ifPrec.(l>Expression)then(PP.stringf")";PP.end_groupf)|EFun(i,decl)->function_declaration'fidecl|EClass(i,cl_decl)->class_declarationficl_decl|EArrow((k,p,b,pc),consise,_)->ifPrec.(l>AssignementExpression)then(PP.start_groupf1;PP.stringf"(");PP.start_groupf1;PP.start_groupf0;(matchkwith|{async=true;generator=false}->PP.stringf"async";PP.non_breaking_spacef|{async=false;generator=false}->()|{async=true|false;generator=true}->assertfalse);(matchpwith|{list=[((BindingIdent_,None)asx)];rest=None}->formal_parameterfx;PP.stringf"=>"|_->PP.start_groupf1;PP.stringf"(";formal_parameter_listfp;PP.stringf")=>";PP.end_groupf);PP.end_groupf;(matchb,consisewith|[(Return_statement(Somee,loc),loc')],true->(* Should not starts with '{' *)PP.start_groupf1;PP.break1f;output_debug_infofloc';parenthesized_expression~obj:trueAssignementExpressionfe;PP.end_groupf;output_debug_infofloc|l,_->letb=matchlwith|[(Blockl,_)]->l|l->linPP.stringf"{";PP.breakf;function_bodyfb;output_debug_infofpc;PP.stringf"}");PP.end_groupf;ifPrec.(l>AssignementExpression)then(PP.stringf")";PP.end_groupf)|ECall(e,access_kind,el,loc)->(* Need parentheses also if within an expression [new e] *)ifPrec.(l=NewExpression||l>CallOrMemberExpression)then(PP.start_groupf1;PP.stringf"(");output_debug_infofloc;PP.start_groupf1;expressionCallOrMemberExpressionfe;PP.breakf;(* Make sure that the opening parenthesis has the appropriate info *)output_debug_infofloc;PP.start_groupf1;(matchaccess_kindwith|ANormal->PP.stringf"("|ANullish->PP.stringf"?.(");argumentsfel;PP.stringf")";PP.end_groupf;PP.end_groupf;ifPrec.(l=NewExpression||l>CallOrMemberExpression)then(PP.stringf")";PP.end_groupf)|ECallTemplate(e,t,loc)->(* Need parentheses also if within an expression [new e] *)ifPrec.(l=NewExpression||l>CallOrMemberExpression)then(PP.start_groupf1;PP.stringf"(");output_debug_infofloc;PP.start_groupf1;parenthesized_expression~funct:trueCallOrMemberExpressionfe;PP.breakf;PP.start_groupf1;templateft;PP.end_groupf;PP.end_groupf;ifPrec.(l=NewExpression||l>CallOrMemberExpression)then(PP.stringf")";PP.end_groupf)|EStrx->pp_string_litfx|ETemplatel->templatefl|EBoolb->PP.stringf(ifbthen"true"else"false")|ENumnum->lets=Num.to_stringnuminletneed_parent=ifNum.is_negnumthenPrec.(l>UnaryExpression)(* Negative numbers may need to be parenthesized. *)elsePrec.(l>=CallOrMemberExpression)(* 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|Void|Delete|Await)asop),e)->letp=UnaryExpressioninifPrec.(l>p)then(PP.start_groupf1;PP.stringf"(");PP.start_groupf0;letname=matchopwith|Typeof->"typeof"|Void->"void"|Delete->"delete"|Await->"await"|_->assertfalseinPP.stringfname;PP.spacef;expressionpfe;PP.end_groupf;ifPrec.(l>p)then(PP.stringf")";PP.end_groupf)|EUn(((IncrB|DecrB)asop),e)->letp=UpdateExpressioninifPrec.(l>p)then(PP.start_groupf1;PP.stringf"(");(matchopwith|IncrB->PP.stringf"++"|DecrB->PP.stringf"--"|_->assertfalse);expressionUnaryExpressionfe;ifPrec.(l>p)then(PP.stringf")";PP.end_groupf)|EUn(((IncrA|DecrA)asop),e)->letp=UpdateExpressioninifPrec.(l>p)then(PP.start_groupf1;PP.stringf"(");expressionLeftHandSideExpressionfe;(matchopwith|IncrA->PP.stringf"++"|DecrA->PP.stringf"--"|_->assertfalse);ifPrec.(l>p)then(PP.stringf")";PP.end_groupf)|EUn(op,e)->letp=UnaryExpressioninletneed_parent=Prec.(l>p)inifneed_parentthen(PP.start_groupf1;PP.stringf"(");PP.stringf(unop_strop);PP.spacef;expressionpfe;ifneed_parentthen(PP.stringf")";PP.end_groupf)|EBin(((InstanceOf|In)asop),e1,e2)->letout,lft,rght=op_precInstanceOfinifPrec.(l>out)then(PP.start_groupf1;PP.stringf"(");PP.start_groupf0;expressionlftfe1;PP.spacef;letname=matchopwith|InstanceOf->"instanceof"|In->"in"|_->assertfalseinPP.stringfname;PP.spacef;expressionrghtfe2;PP.end_groupf;ifPrec.(l>out)then(PP.stringf")";PP.end_groupf)|EBin(((Eq|StarEq|SlashEq|ModEq|PlusEq|MinusEq|LslEq|AsrEq|LsrEq|BandEq|BxorEq|BorEq|OrEq|AndEq|ExpEq|CoalesceEq)asop),e1,e2)->letout,lft,rght=op_precopinletlft=(* We can have e sequence of coalesce: e1 ?? e2 ?? e3,
but each expressions should be a BitwiseORExpression *)matche1,opwith|EBin(Coalesce,_,_),Coalesce->CoalesceExpression|_->lftinPP.start_groupf0;ifPrec.(l>out)thenPP.stringf"(";PP.start_groupf0;expressionlftfe1;PP.spacef;PP.stringf(op_strop);PP.end_groupf;PP.start_groupf1;PP.spacef;expressionrghtfe2;PP.end_groupf;ifPrec.(l>out)thenPP.stringf")";PP.end_groupf|EBin(op,e1,e2)->letout,lft,rght=op_precopinletlft=(* We can have e sequence of coalesce: e1 ?? e2 ?? e3,
but each expressions should be a BitwiseORExpression *)matche1,opwith|EBin(Coalesce,_,_),Coalesce->CoalesceExpression|_->lftinPP.start_groupf0;ifPrec.(l>out)thenPP.stringf"(";expressionlftfe1;PP.spacef;PP.start_groupf1;PP.stringf(op_strop);PP.spacef;expressionrghtfe2;ifPrec.(l>out)thenPP.stringf")";PP.end_groupf;PP.end_groupf|EAssignTargett->(letpropertyfp=matchpwith|TargetPropertyId(Prop_and_identid,None)->identf~kind:`Referenceid|TargetPropertyId(Prop_and_identid,Some(e,_))->identf~kind:`Referenceid;PP.spacef;PP.stringf"=";PP.spacef;expressionAssignementExpressionfe|TargetProperty(pn,e,None)->PP.start_groupf0;property_namefpn;PP.stringf":";PP.spacef;expressionAssignementExpressionfe;PP.end_groupf|TargetProperty(pn,e,Some(ini,_))->PP.start_groupf0;property_namefpn;PP.stringf":";PP.spacef;expressionAssignementExpressionfe;PP.spacef;PP.stringf"=";PP.spacef;expressionAssignementExpressionfini;PP.end_groupf|TargetPropertySpreade->PP.stringf"...";expressionAssignementExpressionfe|TargetPropertyMethod(n,m)->method_fproperty_namenminletelementfp=matchpwith|TargetElementHole->()|TargetElementId(id,None)->identf~kind:`Referenceid|TargetElementId(id,Some(e,_))->identf~kind:`Referenceid;PP.spacef;PP.stringf"=";PP.spacef;expressionAssignementExpressionfe|TargetElemente->expressionAssignementExpressionfe|TargetElementSpreade->PP.stringf"...";expressionAssignementExpressionfeinmatchtwith|ObjectTargetlist->PP.start_groupf1;PP.stringf"{";comma_listf~force_last_comma:(fun_->false)propertylist;PP.stringf"}";PP.end_groupf|ArrayTargetlist->PP.start_groupf1;PP.stringf"[";comma_listf~force_last_comma:(function|TargetElementHole->true|_->false)elementlist;PP.stringf"]";PP.end_groupf)|EArrel->PP.start_groupf1;PP.stringf"[";element_listfel;PP.stringf"]";PP.end_groupf|EAccess(e,access_kind,e')->PP.start_groupf1;letl'=matchlwith|NewExpression|MemberExpression->MemberExpression|_->CallOrMemberExpressioninexpressionl'fe;PP.breakf;PP.start_groupf1;(matchaccess_kindwith|ANormal->PP.stringf"["|ANullish->PP.stringf"?.[");expressionExpressionfe';PP.stringf"]";PP.end_groupf;PP.end_groupf|EDot(e,access_kind,Utf8nm)->(* We keep tracks of whether call expression are allowed
without parentheses within this expression *)letl'=matchlwith|NewExpression|MemberExpression->MemberExpression|_->CallOrMemberExpressioninexpressionl'fe;(matchaccess_kindwith|ANormal->PP.stringf"."|ANullish->PP.stringf"?.");PP.stringfnm|EDotPrivate(e,access_kind,Utf8nm)->(* We keep tracks of whether call expression are allowed
without parentheses within this expression *)letl'=matchlwith|NewExpression|MemberExpression->MemberExpression|_->CallOrMemberExpressioninexpressionl'fe;(matchaccess_kindwith|ANormal->PP.stringf".#"|ANullish->PP.stringf"?.#");PP.stringfnm|ENew(e,None,loc)->ifPrec.(l>NewExpression)then(PP.start_groupf1;PP.stringf"(");PP.start_groupf1;output_debug_infofloc;PP.stringf"new";PP.spacef;expressionNewExpressionfe;PP.end_groupf;ifPrec.(l>NewExpression)then(PP.stringf")";PP.end_groupf)|ENew(e,Someel,loc)->PP.start_groupf1;output_debug_infofloc;PP.stringf"new";PP.spacef;expressionMemberExpressionfe;PP.breakf;PP.start_groupf1;PP.stringf"(";argumentsfel;PP.stringf")";PP.end_groupf;PP.end_groupf|ECond(e,e1,e2)->ifPrec.(l>ConditionalExpression)then(PP.start_groupf1;PP.stringf"(");PP.start_groupf1;PP.start_groupf0;expressionShortCircuitExpressionfe;PP.end_groupf;PP.spacef;PP.start_groupf1;PP.start_groupf0;PP.stringf"?";PP.spacef;PP.end_groupf;expressionAssignementExpressionfe1;PP.end_groupf;PP.spacef;PP.start_groupf1;PP.start_groupf0;PP.stringf":";PP.spacef;PP.end_groupf;expressionAssignementExpressionfe2;PP.end_groupf;PP.end_groupf;ifPrec.(l>ConditionalExpression)then(PP.stringf")";PP.end_groupf)|EObjlst->PP.start_groupf1;PP.stringf"{";property_listflst;PP.stringf"}";PP.end_groupf|ERegexp(s,opt)->(PP.stringf"/";PP.stringfs;PP.stringf"/";matchoptwith|None->()|Someo->PP.stringfo)|EYield{delegate;expr=e}->(letkw=matchdelegatewith|false->"yield"|true->"yield*"inmatchewith|None->PP.stringfkw|Somee->ifPrec.(l>AssignementExpression)then(PP.start_groupf1;PP.stringf"(");PP.start_groupf7;PP.stringfkw;PP.non_breaking_spacef;PP.start_groupf0;expressionAssignementExpressionfe;PP.end_groupf;PP.end_groupf;ifPrec.(l>AssignementExpression)then(PP.end_groupf;PP.stringf")"(* There MUST be a space between the yield and its
argument. A line return will not work *)))|EPrivName(Utf8i)->PP.stringf"#";PP.stringfi|CoverCallExpressionAndAsyncArrowHeade|CoverParenthesizedExpressionAndArrowParameterListe->early_erroreandtemplatefl=PP.stringf"`";List.iterl~f:(function|TStr(Utf8s)->PP.stringfs|TExpe->PP.stringf"${";expressionAssignementExpressionfe;PP.stringf"}");PP.stringf"`"andproperty_namefn=matchnwith|PNI(Utf8s)->PP.stringfs|PNSs->pp_string_litfs|PNNv->expressionExpressionf(ENumv)|PComputede->PP.stringf"[";expressionExpressionfe;PP.stringf"]"andproperty_listfl=comma_listf~force_last_comma:(fun_->false)propertylandpropertyfp=matchpwith|Property(pn,e)->PP.start_groupf0;property_namefpn;PP.stringf":";PP.spacef;expressionAssignementExpressionfe;PP.end_groupf|PropertySpreade->PP.stringf"...";expressionAssignementExpressionfe|PropertyMethod(n,m)->method_fproperty_namenm|CoverInitializedName(e,_,_)->early_erroreandmethod_:'a._->(PP.t->'a->unit)->'a->method_->unit=fun(typea)f(name:PP.t->a->unit)(n:a)(m:method_)->matchmwith|MethodGet(k,l,b,loc')|MethodSet(k,l,b,loc')->(matchkwith|{async=false;generator=false}->()|_->assertfalse);letprefix=matchmwith|MethodGet_->"get"|MethodSet_->"set"|_->assertfalseinfunction_declarationfprefixname(Somen)lbloc'|Method(k,l,b,loc')->letfpnf()=(matchkwith|{async=false;generator=false}->()|{async=false;generator=true}->PP.stringf"*";PP.spacef|{async=true;generator=false}->PP.stringf"async";PP.non_breaking_spacef|{async=true;generator=true}->PP.stringf"async*";PP.spacef);namefninfunction_declarationf""fpn(Some())lbloc'andelement_listfel=comma_listf~force_last_comma:(function|ElementHole->true|_->false)elementelandelementf(e:element)=matchewith|ElementHole->()|Elemente->PP.start_groupf0;expressionAssignementExpressionfe;PP.end_groupf|ElementSpreade->PP.start_groupf0;PP.stringf"...";expressionAssignementExpressionfe;PP.end_groupfandformal_parameterfe=binding_elementfeandformal_parameter_listf{list;rest}=comma_list_restf~force_last_comma:(fun_->false)formal_parameterlistbindingrestandfunction_bodyfb=statement_listf~skip_last_semi:truebandargumentfa=PP.start_groupf0;(matchawith|Arge->expressionAssignementExpressionfe|ArgSpreade->PP.stringf"...";expressionAssignementExpressionfe);PP.end_groupfandargumentsfl=comma_listf~force_last_comma:(fun_->false)argumentlandvariable_declarationf?(in_=true)x=matchxwith|DeclIdent(i,None)->identf~kind:`Bindingi|DeclIdent(i,Some(e,loc))->PP.start_groupf1;PP.start_groupf0;identf~kind:`Bindingi;PP.spacef;PP.stringf"=";PP.end_groupf;PP.start_groupf1;PP.spacef;output_debug_infofloc;letp=(notin_)&&contains~in_:trueExpressioneinifpthen(PP.start_groupf1;PP.stringf"(");expressionAssignementExpressionfe;ifpthen(PP.stringf")";PP.end_groupf);PP.end_groupf;PP.end_groupf|DeclPattern(p,(e,loc))->PP.start_groupf1;PP.start_groupf0;patternfp;PP.spacef;PP.stringf"=";PP.end_groupf;output_debug_infofloc;PP.start_groupf1;PP.spacef;letp=(notin_)&&contains~in_:trueExpressioneinifpthen(PP.start_groupf1;PP.stringf"(");expressionAssignementExpressionfe;ifpthen(PP.stringf")";PP.end_groupf);PP.end_groupf;PP.end_groupfandbinding_propertyfx=matchxwith|Prop_binding(pn,e)->property_namefpn;PP.stringf":";PP.spacef;binding_elementfe|Prop_ident(Prop_and_identi,None)->identf~kind:`Bindingi|Prop_ident(Prop_and_identi,Some(e,loc))->identf~kind:`Bindingi;PP.spacef;PP.stringf"=";PP.spacef;output_debug_infofloc;expressionAssignementExpressionfeandbinding_elementf(b,(e:initialiseroption))=matchewith|None->bindingfb|Some(e,loc)->bindingfb;PP.spacef;PP.stringf"=";PP.spacef;output_debug_infofloc;expressionAssignementExpressionfeandbindingfx=matchxwith|BindingIdentid->identf~kind:`Bindingid|BindingPatternp->patternfpandbinding_array_eltfx=matchxwith|None->()|Somee->binding_elementfeandpatternfp=matchpwith|ObjectBinding{list;rest}->PP.start_groupf1;PP.stringf"{";comma_list_restf~force_last_comma:(fun_->false)binding_propertylist(ident~kind:`Binding)rest;PP.stringf"}";PP.end_groupf|ArrayBinding{list;rest}->PP.start_groupf1;PP.stringf"[";comma_list_restf~force_last_comma:(function|None->true|Some_->false)binding_array_eltlistbindingrest;PP.stringf"]";PP.end_groupfandvariable_declaration_list_auxf?in_l=matchlwith|[]->assertfalse|[d]->variable_declarationf?in_d|d::r->variable_declarationf?in_d;PP.stringf",";PP.spacef;variable_declaration_list_auxf?in_randvariable_declaration_kindfkind=matchkindwith|Var->PP.stringf"var"|Let->PP.stringf"let"|Const->PP.stringf"const"andvariable_declaration_list?in_kindclosef=function|[]->()|[x]->PP.start_groupf1;variable_declaration_kindfkind;PP.spacef;variable_declarationf?in_x;ifclosethenPP.stringf";";PP.end_groupf|l->PP.start_groupf1;variable_declaration_kindfkind;PP.spacef;variable_declaration_list_auxf?in_l;ifclosethenPP.stringf";";PP.end_groupfandparenthesized_expression?(last_semi=fun()->())?(obj=false)?(funct=false)?(class_=false)?(let_identifier=false)?(async_identifier=false)?(force=false)lfe=ifforce||starts_with~obj~funct~class_~let_identifier~async_identifierlethen(PP.start_groupf1;PP.stringf"(";expressionlfe;PP.stringf")";last_semi();PP.end_groupf)else(PP.start_groupf0;expressionlfe;last_semi();PP.end_groupf)andfor_bindingfkv=variable_declaration_kindfk;PP.spacef;bindingfvandstatement1?lastfs=matchswith|Block_,_->statement?lastfs|_->PP.space~indent:1f;PP.start_groupf0;statement?lastfs;PP.end_groupfandstatement?(last=false)f(s,loc)=letcan_omit_semi=PP.compactf&&lastinletlast_semi?(ret=false)()=ifcan_omit_semithen()elseifret&&source_map_enabled&&PP.compactfthen(* In Chrome, the debugger will stop right after a return
statement. We want a whitespace between this statement and
the next one to avoid confusing this location and the
location of the next statement. When pretty-printing, this
is already the case. In compact mode, we add a newline. *)PP.stringf";\n"elsePP.stringf";"inifstop_on_statementsthenoutput_debug_infofloc;matchswith|Blockb->blockfb|Variable_statement(k,l)->variable_declaration_listk(notcan_omit_semi)fl|Function_declaration(i,decl)->function_declaration'f(Somei)decl|Class_declaration(i,cl_decl)->class_declarationf(Somei)cl_decl|Empty_statement->PP.stringf";"|Debugger_statement->PP.stringf"debugger";last_semi()|Expression_statemente->(* Parentheses are required when the expression
starts syntactically with "{", "function", "async function"
or "let [" *)parenthesized_expression~last_semi~obj:true~funct:true~class_:true~let_identifier:trueExpressionfe|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,s2)->letrecitekwes1s2=(letlast_in_s1=matchs2with|None->Somelast|Some_->NoneinPP.start_groupf0;PP.start_groupf1;PP.stringfkw;PP.breakf;PP.start_groupf1;PP.stringf"(";expressionExpressionfe;PP.stringf")";PP.end_groupf;PP.end_groupf;statement1?last:last_in_s1fs1);matchs2with|None->PP.end_groupf|Some(If_statement(e,s1,s2),_)whennot(ends_with_if_without_elses1)->PP.spacef;ite"else if"es1s2;PP.end_groupf|Somes2->PP.spacef;PP.stringf"else";statement1~lastfs2;PP.end_groupfinite"if"es1s2|While_statement(e,s)->PP.start_groupf0;PP.start_groupf0;PP.stringf"while";PP.breakf;PP.start_groupf1;PP.stringf"(";expressionExpressionfe;PP.stringf")";PP.end_groupf;PP.end_groupf;statement1~lastfs;PP.end_groupf|Do_while_statement(s,e)->PP.start_groupf0;PP.stringf"do";statement1fs;PP.breakf;PP.stringf"while";PP.break1f;PP.start_groupf1;PP.stringf"(";expressionExpressionfe;PP.stringf")";last_semi();PP.end_groupf;PP.end_groupf|For_statement(e1,e2,e3,s)->PP.start_groupf0;PP.start_groupf0;PP.stringf"for";PP.breakf;PP.start_groupf1;PP.stringf"(";(matche1with|LeftNone->()|Left(Somee)->(* Should not starts with "let [" and should not contain "in" *)letforce=contains~in_:trueExpressioneinparenthesized_expression~force~let_identifier:trueExpressionfe|Right(k,l)->variable_declaration_listk~in_:falsefalsefl);PP.stringf";";(matche2with|None->()|Somee2->PP.spacef;expressionExpressionfe2);PP.stringf";";(matche3with|None->()|Somee3->PP.spacef;expressionExpressionfe3);PP.stringf")";PP.end_groupf;PP.end_groupf;statement1~lastfs;PP.end_groupf|ForIn_statement(e1,e2,s)->PP.start_groupf0;PP.start_groupf0;PP.stringf"for";PP.breakf;PP.start_groupf1;PP.stringf"(";(matche1with|Lefte->(* Should not starts with "let [" *)parenthesized_expression~let_identifier:trueLeftHandSideExpressionfe|Right(k,v)->for_bindingfkv);PP.spacef;PP.stringf"in";PP.breakf;PP.spacef;expressionExpressionfe2;PP.stringf")";PP.end_groupf;PP.end_groupf;statement1~lastfs;PP.end_groupf|ForOf_statement(e1,e2,s)->PP.start_groupf0;PP.start_groupf0;PP.stringf"for";PP.breakf;PP.start_groupf1;PP.stringf"(";(matche1with|Lefte->(* Should not starts with "let" or "async of" *)parenthesized_expression~let_identifier:true~async_identifier:trueLeftHandSideExpressionfe|Right(k,v)->for_bindingfkv);PP.spacef;PP.stringf"of";PP.breakf;PP.spacef;expressionAssignementExpressionfe2;PP.stringf")";PP.end_groupf;PP.end_groupf;statement1~lastfs;PP.end_groupf|ForAwaitOf_statement(e1,e2,s)->PP.start_groupf0;PP.start_groupf0;PP.stringf"for await";PP.breakf;PP.start_groupf1;PP.stringf"(";(matche1with|Lefte->(* Should not starts with "let" *)parenthesized_expression~let_identifier:trueLeftHandSideExpressionfe|Right(k,v)->for_bindingfkv);PP.spacef;PP.stringf"of";PP.breakf;PP.spacef;expressionAssignementExpressionfe2;PP.stringf")";PP.end_groupf;PP.end_groupf;statement1~lastfs;PP.end_groupf|Continue_statementNone->PP.stringf"continue";last_semi()|Continue_statement(Somes)->PP.stringf"continue ";let(Utf8l)=nane_of_labelsinPP.stringfl;last_semi()|Break_statementNone->PP.stringf"break";last_semi()|Break_statement(Somes)->PP.stringf"break ";let(Utf8l)=nane_of_labelsinPP.stringfl;last_semi()|Return_statement(e,loc)->(matchewith|None->PP.stringf"return";output_debug_infofloc;last_semi~ret:true()|Some(EFun(i,({async=false;generator=false},l,b,pc)))->PP.start_groupf1;PP.start_groupf0;PP.start_groupf0;PP.stringf"return function";opt_identifierf~kind:`Bindingi;PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"(";formal_parameter_listfl;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.stringf"{";PP.breakf;function_bodyfb;output_debug_infofpc;PP.stringf"}";output_debug_infofloc;last_semi~ret:true();PP.end_groupf|Somee->PP.start_groupf7;PP.stringf"return";PP.non_breaking_spacef;PP.start_groupf0;expressionExpressionfe;output_debug_infofloc;last_semi~ret:true();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)->let(Utf8l)=nane_of_labeliinPP.stringfl;PP.stringf":";PP.spacef;statement~lastfs|Switch_statement(e,cc,def,cc')->PP.start_groupf1;PP.start_groupf0;PP.stringf"switch";PP.breakf;PP.start_groupf1;PP.stringf"(";expressionExpressionfe;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.start_groupf1;PP.stringf"{";PP.breakf;letoutput_onelast(e,sl)=PP.start_groupf1;PP.stringf"case";PP.spacef;expressionExpressionfe;PP.stringf":";PP.end_groupf;PP.start_groupf1;(matchslwith|_::_->PP.spacef|[]->PP.breakf);PP.start_groupf0;statement_list~skip_last_semi:lastfsl;PP.end_groupf;PP.end_groupfinletreclooplast=function|[]->()|[x]->output_onelastx;ifnotlastthenPP.breakf|x::xs->output_onefalsex;PP.breakf;looplastxsinloop(Option.is_nonedef&&List.is_emptycc')cc;(matchdefwith|None->()|Somedef->PP.start_groupf1;PP.stringf"default:";PP.spacef;PP.start_groupf0;letlast=List.is_emptycc'instatement_list~skip_last_semi:lastfdef;PP.end_groupf;PP.end_groupf;ifnotlastthenPP.breakf);looptruecc';PP.end_groupf;PP.end_groupf;PP.breakf;PP.stringf"}"|Throw_statemente->PP.start_groupf6;PP.stringf"throw";PP.non_breaking_spacef;PP.start_groupf0;expressionExpressionfe;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";blockfb;(matchctchwith|None->()|Some(i,b)->PP.breakf;(matchiwith|None->PP.stringf"catch"|Somei->PP.stringf"catch(";formal_parameterfi;PP.stringf")");blockfb);(matchfinwith|None->()|Someb->PP.breakf;PP.stringf"finally";blockfb);PP.end_groupf|With_statement(e,s)->PP.start_groupf0;PP.stringf"with(";expressionExpressionfe;PP.stringf")";PP.breakf;statementfs;PP.end_groupf|Import({kind;from},_loc)->PP.start_groupf0;PP.stringf"import";(matchkindwith|SideEffect->()|Defaulti->PP.spacef;identf~kind:`Bindingi|Namespace(def,i)->Option.iterdef~f:(fundef->PP.spacef;identf~kind:`Bindingdef;PP.stringf",");PP.spacef;PP.stringf"* as ";identf~kind:`Bindingi|Named(def,l)->Option.iterdef~f:(fundef->PP.spacef;identf~kind:`Bindingdef;PP.stringf",");PP.spacef;PP.stringf"{";PP.spacef;comma_listf~force_last_comma:(fun_->false)(funf(s,i)->ifmatchiwith|S{name;_}whenStdlib.Utf8_string.equalnames->true|_->falsethenidentf~kind:`Bindingielse(pp_ident_or_string_litfs;PP.stringf" as ";identf~kind:`Bindingi))l;PP.spacef;PP.stringf"}");(matchkindwith|SideEffect->()|_->PP.spacef;PP.stringf"from");PP.spacef;pp_string_litffrom;PP.stringf";";PP.end_groupf|Export(e,_loc)->PP.start_groupf0;PP.stringf"export";(matchewith|ExportNamesl->PP.spacef;PP.stringf"{";PP.spacef;comma_list~force_last_comma:(fun_->false)f(funf(i,s)->ifmatchiwith|S{name;_}whenStdlib.Utf8_string.equalnames->true|_->falsethenidentf~kind:`Referenceielse(identf~kind:`Referencei;PP.stringf" as ";pp_ident_or_string_litfs))l;PP.spacef;PP.stringf"};"|ExportFrom{kind;from}->PP.spacef;(matchkindwith|Export_allNone->PP.stringf"*"|Export_all(Somes)->PP.stringf"* as ";pp_ident_or_string_litfs|Export_namesl->PP.stringf"{";PP.spacef;comma_list~force_last_comma:(fun_->false)f(funf(a,b)->ifStdlib.Utf8_string.equalabthenpp_ident_or_string_litfaelse(pp_ident_or_string_litfa;PP.stringf" as ";pp_ident_or_string_litfb))l;PP.spacef;PP.stringf"}");PP.spacef;PP.stringf"from";PP.spacef;pp_string_litffrom;PP.stringf";"|ExportDefaultExpressione->PP.spacef;PP.stringf"default";PP.spacef;parenthesized_expression~last_semi~obj:true~funct:true~class_:true~let_identifier:trueExpressionfe|ExportDefaultFun(i,decl)->PP.spacef;PP.stringf"default";PP.spacef;function_declaration'fidecl|ExportDefaultClass(id,decl)->PP.spacef;PP.stringf"default";PP.spacef;class_declarationfiddecl|ExportFun(id,decl)->PP.spacef;function_declaration'f(Someid)decl|ExportClass(id,decl)->PP.spacef;class_declarationf(Someid)decl|ExportVar(k,l)->PP.spacef;variable_declaration_listk(notcan_omit_semi)fl|CoverExportFrome->early_errore);PP.end_groupfandstatement_listf?skip_last_semib=matchbwith|[]->()|[s]->statementf?last:skip_last_semis|s::r->statementfs;PP.spacef;statement_listf?skip_last_semirandblockfb=PP.start_groupf0;PP.start_groupf1;PP.stringf"{";PP.breakf;statement_list~skip_last_semi:truefb;PP.end_groupf;PP.breakf;PP.stringf"}";PP.end_groupfandfunction_declaration:typea.'pp->string->('pp->a->unit)->aoption->_->_->_->unit=funfprefix(pp_name:_->a->unit)(name:aoption)lbodyloc->PP.start_groupf0;PP.start_groupf0;PP.start_groupf0;PP.stringfprefix;(matchnamewith|None->()|Somename->ifnot(String.is_emptyprefix)thenPP.spacef;pp_namefname);PP.end_groupf;PP.breakf;PP.start_groupf1;PP.stringf"(";formal_parameter_listfl;PP.stringf")";PP.end_groupf;PP.end_groupf;PP.start_groupf1;PP.stringf"{";PP.breakf;function_bodyfbody;PP.end_groupf;PP.breakf;output_debug_infofloc;PP.stringf"}";PP.end_groupfandfunction_declaration'f(name:_option)(k,l,b,loc')=letprefix=matchkwith|{async=false;generator=false}->"function"|{async=true;generator=false}->"async function"|{async=true;generator=true}->"async function*"|{async=false;generator=true}->"function*"infunction_declarationfprefix(ident~kind:`Binding)namelbloc'andclass_declarationfix=PP.start_groupf1;PP.start_groupf0;PP.start_groupf0;PP.stringf"class";(matchiwith|None->()|Somei->PP.spacef;identf~kind:`Bindingi);PP.end_groupf;Option.iterx.extends~f:(fune->PP.spacef;PP.stringf"extends";PP.spacef;expressionLeftHandSideExpressionfe;PP.spacef);PP.end_groupf;PP.start_groupf2;PP.stringf"{";PP.breakf;List.iter_lastx.body~f:(funlastx->(matchxwith|CEMethod(static,n,m)->PP.start_groupf0;ifstaticthen(PP.stringf"static";PP.spacef);method_fclass_element_namenm;PP.end_groupf|CEField(static,n,i)->PP.start_groupf0;ifstaticthen(PP.stringf"static";PP.spacef);class_element_namefn;(matchiwith|None->()|Some(e,loc)->PP.spacef;PP.stringf"=";PP.spacef;output_debug_infofloc;expressionAssignementExpressionfe);PP.stringf";";PP.end_groupf|CEStaticBLockl->PP.start_groupf0;PP.stringf"static";PP.spacef;blockfl;PP.end_groupf);ifnotlastthenPP.breakf);PP.end_groupf;PP.breakf;PP.stringf"}";PP.end_groupfandclass_element_namefx=matchxwith|PropNamen->property_namefn|PrivName(Utf8i)->PP.stringf"#";PP.stringfiandprogramfs=statement_listfsendletpart_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|_,_->falselethashtbl_to_listhtb=String.Hashtbl.fold(funkvl->(k,v)::l)htb[]|>List.sort~cmp:(fun(_,a)(_,b)->compareab)|>List.map~f:fstletblackbox_filename="/builtin/blackbox.ml"letprogram?(accept_unnamed_var=false)?(source_map=false)fp=lettemp_mappings=ref[]inletfiles=String.Hashtbl.create17inletnames=String.Hashtbl.create17inletpush_mapping,get_file_index,get_name_index=((funposm->temp_mappings:=(pos,m)::!temp_mappings),(funfile->tryString.Hashtbl.findfilesfilewithNot_found->letpos=String.Hashtbl.lengthfilesinString.Hashtbl.addfilesfilepos;pos),funname->tryString.Hashtbl.findnamesnamewithNot_found->letpos=String.Hashtbl.lengthnamesinString.Hashtbl.addnamesnamepos;pos)inlethidden_location=Source_map.Gen_Ori{gen_line=-1;gen_col=-1;ori_source=get_file_indexblackbox_filename;ori_line=1;ori_col=0}inletmoduleO=Make(structletpush_mapping=push_mappingletget_name_index=get_name_indexletget_file_index=get_file_indexlethidden_location=hidden_locationletsource_map_enabled=source_mapletaccept_unnamed_var=accept_unnamed_varend)inPP.set_needed_space_functionfneed_space;(matchConfig.effects()with|`Cps|`Double_translation->PP.set_adjust_indentation_functionf(funn->nmod40)|`Disabled|`Jspi|(exceptionFailure_)->());PP.start_groupf0;O.programfp;PP.end_groupf;PP.newlinef;letsm=matchsource_mapwith|false->{Source_map.sources=[];names=[];mappings=[]}|true->letsources=hashtbl_to_listfilesinletnames=hashtbl_to_listnamesinletrelocateposm=letgen_line=pos.PP.p_line+1inletgen_col=pos.PP.p_colinmatchmwith|Source_map.Gen{gen_col=_;gen_line=_}->Source_map.Gen{gen_col;gen_line}|Source_map.Gen_Orim->Source_map.Gen_Ori{mwithgen_line;gen_col}|Source_map.Gen_Ori_Namem->Source_map.Gen_Ori_Name{mwithgen_line;gen_col}inletrecbuild_mappingsposmappingprev_mappings=matchmappingwith|[]->prev_mappings|(pos',m)::rem->(* Firefox assumes that a mapping stops at the end of a
line, which is inconvenient. When this happens, we
repeat the mapping on the next line. *)ifpos'.PP.p_line=pos.PP.p_line||(pos'.p_line=pos.p_line-1&&pos.p_col=0)thenbuild_mappingspos'rem(relocatepos'm::prev_mappings)elseifpos.p_col>0thenletpos={poswithp_col=0}inbuild_mappingsposmapping(relocateposm::prev_mappings)elseletpos={poswithp_line=pos.p_line-1}inbuild_mappingsposmapping(relocateposm::prev_mappings)inletmappings=match!temp_mappingswith|[]->[]|(pos,m)::rem->build_mappingsposrem[relocateposm]in{Source_map.sources;names;mappings}inPP.checkf;(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));sm