123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264(* Yoann Padioleau
*
* Copyright (C) 2019 r2c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library 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 file
* license.txt for more details.
*)openCommonmoduleA=Ast_jsmoduleC=Cst_jsmoduleG=Ast_generic(*****************************************************************************)(* Prelude *)(*****************************************************************************)(* Poor's man Javascript transpiler!
* Probably incorrect and incomplete but good enough for codegraph.
*
* You can test the babel transpiler and see live how it transpiles code
* here: https://babeljs.io/repl (great ressource).
*
* alt:
* - just call babel
* - r2s's transpiler (calls babel internally)
*
* related:
* - babel and its "polyfill"
*)(*****************************************************************************)(* Xhp *)(*****************************************************************************)(* TODO probably incomplete *)letid_of_tagtag=A.Id(tag,refA.NotResolved)letxhp_attr_valueexprx=matchxwith|C.XhpAttrStringstr->A.Stringstr|C.XhpAttrExpr(_,e,_)->expre(* todo: should probably use Obj instead of tuples with string keys *)letxhp_attributeexprx=matchxwith|C.XhpAttrNoValue(str)->A.Arr[A.Stringstr]|C.XhpAttrValue(str,_tok,attrval)->letv=xhp_attr_valueexprattrvalinA.Arr[A.Stringstr;v]|C.XhpAttrSpread(_,(tokdot,e),_)->A.Apply(A.IdSpecial(A.Spread,tokdot),[expre])letrecxhpexprx=matchxwith|C.XhpSingleton(tag,attrs,_tok)->letid=id_of_tagtaginletargs1=List.map(xhp_attributeexpr)attrsinletargs2=[]in(* TODO: is it the actual result? good enough for codegraph for now *)A.Apply(id,[A.Arrargs1;A.Arrargs2])|C.Xhp(tag,attrs,_tok,body,_endtag_opt)->letid=id_of_tagtaginletargs1=List.map(xhp_attributeexpr)attrsinletargs2=List.map(xhp_bodyexpr)bodyinA.Apply(id,[A.Arrargs1;A.Arrargs2])andxhp_bodyexprx=matchxwith(* todo: contain enclosing quote? *)|C.XhpTextstr->A.Stringstr|C.XhpNestedx->xhpexprx|C.XhpExpr(_,eopt,_)->(matcheoptwith|None->A.Nop|Somee->expre)(*****************************************************************************)(* Patterns *)(*****************************************************************************)(* TODO incomplete, handle all patterns, and compare with
* what babel actually does.
*)(* mostly a dupe of graph_code.ml, but avoid deps and take a tok *)letcnt=ref0letgensym_namestok=incrcnt;spf"!%s__%d!"s!cnt,tokletvar_of_simple_pattern(expr,fname)init_builderpat=matchpatwith(* { x } = varname; -~> x = varname.x *)|C.PatId(name,None)->letname=fnamenameinletinit=init_buildernamein{A.v_name=name;v_kind=A.Let;v_init=init;v_resolved=refA.NotResolved;}(* { x = y } = varname; -~> x = pfff_builtin_default(varname.x, y) *)|C.PatId(name,Some(tok,e))->letname=fnamenameinlete=expreinletinit1=init_buildernameinletinit=A.Apply(A.Id(("pfff_builtin_default",tok),refA.NotResolved),[init1;e])in{A.v_name=name;v_kind=A.Let;v_init=init;v_resolved=refA.NotResolved;}|_->failwith"TODO: simple pattern not handled"letcompile_pattern(expr,fname,fpname)varnamepat=matchpatwith(* 'var { x, y } = varname' -~> 'var x = varname.x; var y = varname.y;' *)|C.PatObjx->x|>C.unbrace|>C.uncomma|>List.map(funpat->(matchpatwith|C.PatId_->letinit_buildername=A.ObjAccess(A.Id(varname,refA.NotResolved),A.PNname)invar_of_simple_pattern(expr,fname)init_builderpat(* { x: y, z } = varname; *)|C.PatProp(pname,_tok,pat)->letpname=fpnamepnameinletinit_builder_name=A.ObjAccess(A.Id(varname,refA.NotResolved),pname)invar_of_simple_pattern(expr,fname)init_builderpat|_->failwith"TODO: PatObj pattern not handled"))(* 'var [x,y] = varname' -~> 'var x = varname[0]; var y = varname[1] *)|C.PatArrx->letxs=x|>C.unbraceinletidx=ref0inletaux_patpat=matchpatwith|C.PatId_->letinit_builder(_name,tok)=A.ArrAccess(A.Id(varname,refA.NotResolved),A.Num(string_of_int!idx,tok))invar_of_simple_pattern(expr,fname)init_builderpat|C.PatDots(tok,pat)->letinit_builder(_name,_tok)=A.Apply(A.ObjAccess(A.Id(varname,refA.NotResolved),(A.PN(("slice",tok)))),[A.Num(string_of_int!idx,tok)])invar_of_simple_pattern(expr,fname)init_builderpat|_->failwith"TODO: PatArr pattern not handled"inletrecauxxs=matchxswith|[]->[]|[Right_]->failwith"useless comma"|[Leftpat]->[aux_patpat]|(Leftpat)::(Right_)::xs->letvar=aux_patpatinincridx;var::auxxs(* elision *)|(Right_)::xs->incridx;auxxs|Left_::Left_::_->failwith"Impossible Left Left"inauxxs|_->failwith"TODO: pattern not handled"letvar_pattern(expr,fname,fpname)x=matchx.C.vpat_initwith|None->failwith"weird var_pattern without init; Part of ForOf?"|Some(tok,e)->lete=expreinletvname,vars=matchewith|A.Id(name,_)->name,[]|_->letintermediate=gensym_name"tmp"tokinletvar={A.v_name=intermediate;v_kind=A.Let;v_init=e;v_resolved=refA.NotResolved}inintermediate,[var]invars@compile_pattern(expr,fname,fpname)vnamex.C.vpat(*****************************************************************************)(* Iterator for of *)(*****************************************************************************)(* for (xx of yy) -~>
* for (var _iterator = yy[Symbol.iterator](), _step;
* !(_step = _iterator.next()).done;;) {
* xx = _step.value;
* TODO probably incomplete.
*)letforof(lhs_var,tok,e2,st)(expr,stmt,var_binding)=lete2=expre2inletst=stmtstinletiterator="!iterator!",tokinletstep="!step!",tokinletsymbol_iterator=A.ObjAccess(A.Id(("Symbol",tok),refA.NotResolved),A.PN("iterator",tok))inletfor_init=Left[{A.v_name=iterator;v_kind=A.Let;v_resolved=refA.NotResolved;v_init=A.Apply(A.ArrAccess(e2,symbol_iterator),[])};{A.v_name=step;v_kind=A.Let;v_resolved=refA.NotResolved;v_init=A.Nop;}]inletfor_cond=A.Apply(A.IdSpecial(A.ArithOpG.Not,tok),[A.ObjAccess(A.Assign(A.Id(step,refA.NotResolved),A.Apply(A.ObjAccess(A.Id(iterator,refA.NotResolved),A.PN("next",tok)),[])),A.PN("done",tok))])inletstep_value=A.ObjAccess(A.Id(step,refA.NotResolved),A.PN("value",tok))inletstep_value_cst=C.Period(C.Vstep,tok,("value",tok))inletvars_or_assign_stmts=matchlhs_varwith|C.LHS2e->lete=exprein[A.ExprStmt(A.Assign(e,step_value))]|C.ForVar((vkind,_tok),binding)->letbinding=matchbindingwith|C.VarClassicx->ifx.C.v_init<>Nonethenfailwith"for-of loop variable can not have an initializer";C.VarClassic{xwithC.v_init=Some(tok,step_value_cst)}|C.VarPatternx->ifx.C.vpat_init<>Nonethenfailwith"for-of loop variable can not have an initializer";C.VarPattern{xwithC.vpat_init=Some(tok,step_value_cst)}invar_bindingvkindbinding|>List.map(funvar->A.VarDeclvar)inletfinalst=vars_or_assign_stmts@stin[A.For(A.ForClassic(for_init,for_cond,A.Nop),A.Blockfinalst)]