1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155(* 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=Poly.(loc<>!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("<"^Code.Var.to_stringv^">")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)&&(Poly.(op=In&&in_)||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_nums.[i+1])->Buffer.add_stringb"\\0"|'\b'->Buffer.add_stringb"\\b"|'\t'->Buffer.add_stringb"\\t"|'\n'->Buffer.add_stringb"\\n"(* This escape sequence is not supported by IE < 9
| '\011' -> "\\v"
*)|'\012'->Buffer.add_stringb"\\f"(* https://github.com/ocsigen/js_of_ocaml/issues/898 *)|'/'wheni>0&&Char.equals.[i-1]'<'->Buffer.add_stringb"\\/"|'\r'->Buffer.add_stringb"\\r"|'\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"(");ifPoly.(op=IncrB)thenPP.stringf"++"elsePP.stringf"--";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;ifPoly.(op=IncrA)thenPP.stringf"++"elsePP.stringf"--";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=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=Hashtbl.create17inletnames=Hashtbl.create17inletpush_mapping,get_file_index,get_name_index=((funposm->temp_mappings:=(pos,m)::!temp_mappings),(funfile->tryHashtbl.findfilesfilewithNot_found->letpos=Hashtbl.lengthfilesinHashtbl.addfilesfilepos;pos),funname->tryHashtbl.findnamesnamewithNot_found->letpos=Hashtbl.lengthnamesinHashtbl.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;ifConfig.Flag.effects()thenPP.set_adjust_indentation_functionf(funn->nmod40);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