Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file melange_ppx.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347(* Copyright (C) 2018 Hongbo Zhang, Authors of ReScript
* Copyright (C) 2023 Antonio Nuno Monteiro
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* In addition to the permissions granted to you by the LGPL, you may combine
* or link a "work that uses the Library" with a publicly distributed version
* of this file to produce a combined library or application, then distribute
* that combined work under the terms of your choosing, with no requirement
* to comply with the obligations normally placed on you by section 4 of the
* LGPL version 3 (or the corresponding section of a later version of the LGPL
* should you choose to use a 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. *)(* When we design a ppx, we should keep it simple, and also think about
how it would work with other tools like merlin and ocamldep *)(*
1. extension point
{[
[%bs.raw{| blabla |}]
]}
will be desugared into
{[
let module Js =
struct unsafe_js : string -> 'a end
in Js.unsafe_js {| blabla |}
]}
The major benefit is to better error reporting (with locations).
Otherwise
{[
let f u = Js.unsafe_js u
let _ = f (1 + 2)
]}
And if it is inlined some where
*)openPpxliblet()=Ast_derive_projector.init();Ast_derive_js_mapper.init()letsucceedattrattrs=matchattrswith|[_]->()|_->Bs_ast_invariant.mark_used_bs_attributeattr;Bs_ast_invariant.warn_discarded_unused_attributesattrsmoduleExternal=structletrule=letrulelabel=letcontext =Extension.Context.expressioninletextractor=Ast_pattern.(single_expr_payload(pexp_ident__'))inlethandler ~ctxt:_ident =matchidentwith|{txt=Lidentx;loc}->Ast_extensions.handle_externallocx|>Melange_ppxlib_ast.To_ppxlib.copy_expression(* do we need support [%external gg.xx ]
{[ Js.Undefined.to_opt (if Js.typeof x == "undefined" then x else Js.Undefined.empty ) ]}
*)|{loc;txt=_}->Location.raise_errorf~loc"external expects a single identifier"inletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.external"endmodule Raw=structletstru_rule=letrulelabel=letcontext =Extension.Context.structure_iteminletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{loc;txt=payload}=letstru=letpayload=Melange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadin[Ast_extensions.handle_raw_structure locpayload]inMelange_ppxlib_ast.To_ppxlib.copy_structurestru|>List.hdinletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.raw"letrule=letrulelabel=letcontext =Extension.Context.expressioninletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{loc;txt=payload}=letpayload=Melange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadinAst_extensions.handle_raw~kind:Raw_explocpayload|>Melange_ppxlib_ast.To_ppxlib.copy_expressioninletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.raw"letrules =[stru_rule;rule]endmodulePrivate=structletexpand (stru:Ast_structure.t)=Typemod_hide.checkstru;letlast_loc=(List.hdstru).pstr_locinletfirst_loc=(List.hdstru).pstr_locinletloc={first_loc withloc_end=last_loc.loc_end}inMelange_compiler_libs.Ast_helper.[Str.open_(Opn.mk~override:Override(Mod.structure~loc~attrs:Typemod_hide.attrsstru));]|>Melange_ppxlib_ast.To_ppxlib.copy_structure|>List.hdletrule=letrulelabel=letcontext =Extension.Context.structure_iteminletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{txt=payload;loc}=matchMelange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadwith|PStrwork->expandwork|PSig_|PTyp _|PPat_->Location.raise_errorf~loc"private extension is not support"inletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"private"endmodule Debugger=structletrule=letrulelabel=letcontext =Extension.Context.expressioninletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{txt=payload;loc}=letpayload=Melange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadinletopenMelange_compiler_libs.Ast_helperinExp.mk~loc(Ast_extensions.handle_debuggerlocpayload)|>Melange_ppxlib_ast.To_ppxlib.copy_expressioninletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.debugger"endmodule Re=structletrule=letrulelabel=letcontext =Extension.Context.expressioninletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{txt=payload;loc}=letpayload=Melange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadinletopenMelange_compiler_libs.Ast_helperinExp.constraint_~loc(Ast_extensions.handle_raw~kind:Raw_relocpayload)(Ast_comb.to_js_re_typeloc)|>Melange_ppxlib_ast.To_ppxlib.copy_expressioninletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.re"endmoduleTime=structletrule=letrulelabel=letcontext =Extension.Context.expressioninletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{txt=payload;loc}=letopenMelange_compiler_libs.Ast_helperinmatchMelange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadwith|PStr[{pstr_desc=Pstr_eval(e,_)}]->letlocString=ifloc.loc_ghostthen"GHOST LOC"elseletloc_start=loc.loc_startinlet file,lnum,__=(loc_start.pos_fname,loc_start.pos_lnum,loc_start.pos_cnum-loc_start.pos_bol)inPrintf.sprintf"%s %d"(Filename.basenamefile)lnumin(* let e = self.expr self e in *)Exp.sequence~loc(Ast_compatible.app1~loc(Exp.ident~loc{loc;txt=Ldot(Ldot (Lident"Js","Console"),"timeStart");})(Ast_compatible.const_exp_string~loclocString))(Exp.let_~locNonrecursive[Vb.mk~loc(Pat.var~loc{loc;txt="timed" })e](Exp.sequence~loc(Ast_compatible.app1~loc(Exp.ident~loc{loc;txt=Ldot (Ldot(Lident"Js","Console"),"timeEnd");})(Ast_compatible.const_exp_string~loclocString))(Exp.ident~loc {loc;txt=Lident"timed"})))|>Melange_ppxlib_ast.To_ppxlib.copy_expression|_->Location.raise_errorf~loc"expect a boolean expression in the payload"inletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.time"endmodule Node=structletrule=letrulelabel=letcontext =Extension.Context.expressioninletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{txt=payload;loc}=letpayload=Melange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadinletstrips=matchswith"_module"->"module"|x->xinmatchAst_payload.as_identpayloadwith|Some{txt=Lident(("__filename"|"__dirname"|"_module"|"require")asname);loc;}->letopen Melange_compiler_libs.Ast_helperinletexp=Ast_extensions.handle_externalloc(stripname)inlettyp=Ast_core_type.lift_option_type(ifname="_module"thenTyp.constr~loc{txt=Ldot(Lident "Node","node_module");loc}[]elseifname="require"thenTyp.constr~loc{txt=Ldot(Lident "Node","node_require");loc}[]elseAst_literal.type_string~loc())inExp.constraint_~locexptyp|>Melange_ppxlib_ast.To_ppxlib.copy_expression|Some_|None->(matchpayloadwith|PTyp_->Location.raise_errorf~loc"Illegal payload, expect an expression payload instead of \
type payload"|PPat_->Location.raise_errorf~loc"Illegal payload, expect an expression payload instead of \
pattern payload"|_->Location.raise_errorf~loc"Illegal payload")inlet extender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.node"endmodule Obj=structtypelabel_exprs =(Longident.tAsttypes.loc*Parsetree.expression)listletrule=letrulelabel=letcontext =Extension.Context.expressioninletextractor=Ast_pattern.(__')inlethandler ~ctxt:_{txt=payload;loc}=matchMelange_ppxlib_ast.Of_ppxlib.copy_payloadpayloadwith|PStr[{pstr_desc=Pstr_eval(({pexp_desc=Pexp_record(label_exprs,None)}ase),_);};]->{ewithpexp_desc=Ast_extensions.Make.record_as_js_objecte.pexp_loclabel_exprs;}|>Melange_ppxlib_ast.To_ppxlib.copy_expression|_->Location.raise_errorf~loc"Expect a record expression here"inletextender=Extension.V3.declarelabelcontextextractorhandlerinContext_free.Rule.extensionextenderinrule"bs.obj"endlet()=letmoduleLocation=Ocaml_common.LocationinLocation.register_error_of_exn(funexn->matchMelange_compiler_libs.Location.error_of_exnexnwith|Some(`Okreport)->Some report|None|Some`Already_displayed->None)let()=Driver.add_arg"-unsafe"(Unit(fun()->Ocaml_common.Clflags.unsafe:=true))~doc:"Do not compile bounds checking on array and string access";Driver.V2.register_transformation"melange"~rules:(Raw.rules@[External.rule;Private.rule;Debugger.rule;Re.rule;Time.rule;Node.rule;Obj.rule;])