123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Js_ast.mli *)typeexpr=|Numberoffloat|Stringofstring|Boolofbool|Null|Nameofstring|This|Arrayofexprlist|Objectof(string*expr)list|Functionoffunc|Unaryofstring*expr|Updateofstring*bool*expr|Binaryofstring*expr*expr|Logicalofstring*expr*expr|Assignofstring*expr*expr|Conditionalofexpr*expr*expr|Memberofexpr*string|Indexofexpr*expr|Callofexpr*exprlist|Newofexpr*exprlist|Regexofstring*stringandfunc={name:stringoption;params:stringlist;body:stmtlist;arrow:bool}andstmt={line:int;stmt:statement}andstatement=|Exprofexpr|Letoflet_kind*(string*exproption)list|Function_decloffunc|Returnofexproption|Ifofexpr*stmt*stmtoption|Whileofexpr*stmt|Forofstmtoption*exproption*exproption*stmt|For_ofoflet_kind*string*expr*stmt|Break|Continue|Throwofexpr|Tryofstmtlist*string*stmtlist|Blockofstmtlist|Emptyandlet_kind=Let_kind|Const_kind|Var_kindtypeprogram=stmtlist(*****************************************************************************)(* Numbers *)(*****************************************************************************)(* the shortest of 15, 16 and 17 significant digits that reads back as
the same float: 17 always do (a double's 53 bits), fewer usually do,
and a person wants 0.1, not 0.10000000000000001 *)letnumber_to_string(f:float):string=ifFloat.is_nanfthen"NaN"elseiff=Float.infinitythen"Infinity"elseiff=Float.neg_infinitythen"-Infinity"elseifFloat.is_integerf&&Float.absf<1e21thenPrintf.sprintf"%.0f"felseletshortest=List.find(funp->float_of_string(Printf.sprintf"%.*g"pf)=f)[15;16;17]inPrintf.sprintf"%.*g"shortestf(*****************************************************************************)(* Printing *)(*****************************************************************************)letkind_to_string(k:let_kind):string=matchkwithLet_kind->"Let"|Const_kind->"Const"|Var_kind->"Var"letlist(f:'a->string)(xs:'alist):string=String.concat", "(List.mapfxs)letrecexpr_to_string(e:expr):string=letp=Printf.sprintfinmatchewith|Numberf->number_to_stringf|Strings->p"%S"s|Boolb->string_of_boolb|Null->"null"|Namex->x|This->"this"|Arrayes->p"[%s]"(listexpr_to_stringes)|Objectkvs->p"{%s}"(list(fun(k,v)->k^": "^expr_to_stringv)kvs)|Function{arrow=true;params;body=[{stmt=Return(Somee);_}];_}->p"(%s) => %s"(String.concat", "params)(expr_to_stringe)|Functionf->func_to_stringf|Unary(("typeof"asop),e)->p"(%s %s)"op(expr_to_stringe)|Unary(op,e)->p"(%s%s)"op(expr_to_stringe)|Update(op,true,e)->p"(%s%s)"op(expr_to_stringe)|Update(op,false,e)->p"(%s%s)"(expr_to_stringe)op|Binary(op,a,b)|Logical(op,a,b)|Assign(op,a,b)->p"(%s %s %s)"(expr_to_stringa)op(expr_to_stringb)|Conditional(c,a,b)->p"(%s ? %s : %s)"(expr_to_stringc)(expr_to_stringa)(expr_to_stringb)|Member(o,x)->p"(%s.%s)"(expr_to_stringo)x|Index(o,i)->p"(%s[%s])"(expr_to_stringo)(expr_to_stringi)|Call(f,args)->p"(%s(%s))"(expr_to_stringf)(listexpr_to_stringargs)|New(f,args)->p"(new %s(%s))"(expr_to_stringf)(listexpr_to_stringargs)|Regex(r,f)->p"/%s/%s"rfandfunc_to_string(f:func):string=Printf.sprintf"%s%s [%s] [%s]"(iff.arrowthen"Arrow"else"Function")(matchf.namewithSomen->" "^n|None->"")(String.concat"; "f.params)(body_to_stringf.body)andbody_to_string(body:stmtlist):string=String.concat"; "(List.mapstmt_to_stringbody)andstmt_to_string(s:stmt):string=letp=Printf.sprintfinlete=expr_to_stringinletoptfx=matchxwithSomex->fx|None->"none"inmatchs.stmtwith|Exprx->"Expr "^ex|Let(k,decls)->kind_to_stringk^" "^list(fun(x,init)->matchinitwithSomev->x^" "^ev|None->x)decls|Function_declf->func_to_stringf|ReturnNone->"Return"|Return(Somex)->"Return "^ex|If(c,a,None)->p"If (%s, %s)"(ec)(stmt_to_stringa)|If(c,a,Someb)->p"If (%s, %s, %s)"(ec)(stmt_to_stringa)(stmt_to_stringb)|While(c,b)->p"While (%s, %s)"(ec)(stmt_to_stringb)|For(init,test,update,b)->p"For (%s, %s, %s, %s)"(optstmt_to_stringinit)(optetest)(opteupdate)(stmt_to_stringb)|For_of(k,x,xs,b)->p"For_of (%s %s, %s, %s)"(kind_to_stringk)x(exs)(stmt_to_stringb)|Break->"Break"|Continue->"Continue"|Throwx->"Throw "^ex|Try(body,x,handler)->p"Try [%s] catch %s [%s]"(body_to_stringbody)x(body_to_stringhandler)|Blockbody->p"Block [%s]"(body_to_stringbody)|Empty->"Empty"