123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* 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
*)let()=Ast_derive_projector.init();Ast_derive_js_mapper.init()letsucceedattrattrs=matchattrswith|[_]->()|_->Bs_ast_invariant.mark_used_bs_attributeattr;Bs_ast_invariant.warn_discarded_unused_attributes attrstypemapper=Ast_mapper.mapperletdefault_mapper =Ast_mapper.default_mapperletdefault_expr_mapper =Ast_mapper.default_mapper.exprletexpr_mapper (self:mapper)(e:Parsetree.expression)=matche.pexp_descwith|Pexp_constant(Pconst_string(s,loc,Somedelim))->Ast_utf8_string_interp.transformeslocdelim(* End rewriting *)|Pexp_functioncases->((* {[ function [@bs.exn]
| Not_found -> 0
| Invalid_argument -> 1
]}*)matchAst_attributes.process_pexp_fun_attributes_reve.pexp_attributeswith|false,_->default_expr_mapperselfe|true,pexp_attributes->Ast_bs_open.convertBsErrorFunction e.pexp_locselfpexp_attributescases)|Pexp_fun(label,_,pat,body)->(matchAst_attributes.process_attributes_reve.pexp_attributeswith|Nothing,_->default_expr_mapperselfe|Uncurry_,pexp_attributes->{ewithpexp_desc=Ast_uncurry_gen.to_uncurry_fne.pexp_locselflabelpatbody;pexp_attributes;}|Method_,_->Location.raise_errorf~loc:e.pexp_loc"%@meth is not supported in function expression"|Meth_callback_,pexp_attributes->(* FIXME: does it make sense to have a label for [this] ? *){ewithpexp_desc=Ast_uncurry_gen.to_method_callbacke.pexp_locselflabelpatbody;pexp_attributes;})|Pexp_apply(fn,args)->Ast_exp_apply.app_exp_mappereselffnargs|Pexp_object{pcstr_self;pcstr_fields}->(matchAst_attributes.process_bse.pexp_attributeswith|true,pexp_attributes->{ewithpexp_desc=Ast_util.ocaml_obj_as_js_objecte.pexp_locselfpcstr_selfpcstr_fields;pexp_attributes;}|false,_->default_expr_mapperselfe)|Pexp_match(b,[{pc_lhs={ppat_desc=Ppat_construct({txt=Lident"true"},None)};pc_guard=None;pc_rhs=t_exp;};{pc_lhs ={ppat_desc=Ppat_construct({txt=Lident"false"},None)};pc_guard=None;pc_rhs=f_exp;};])|Pexp_match(b,[{pc_lhs={ppat_desc=Ppat_construct({txt=Lident"false"},None)};pc_guard=None;pc_rhs=f_exp;};{pc_lhs ={ppat_desc=Ppat_construct({txt=Lident"true"},None)};pc_guard=None;pc_rhs=t_exp;};])->default_expr_mapper self{ewithpexp_desc=Pexp_ifthenelse(b,t_exp,Somef_exp)}|Pexp_let(r,vbs,sub_expr)->{ewithpexp_desc =Pexp_let(r,Ast_tuple_pattern_flatten.value_bindings_mapperselfvbs,self.exprselfsub_expr);}|_->default_expr_mapperselfelettyp_mapper(self:mapper)(typ:Parsetree.core_type)=Ast_core_type_class_type.typ_mapperselftypletclass_type_mapper(self:mapper)({pcty_attributes;pcty_loc}asctd:Parsetree.class_type)=match Ast_attributes.process_bspcty_attributeswith|false,_->default_mapper.class_typeselfctd|true,pcty_attributes->(match ctd.pcty_descwith|Pcty_signature{pcsig_self;pcsig_fields}->letpcsig_self =self.typ selfpcsig_selfin{ctd withpcty_desc=Pcty_signature{pcsig_self;pcsig_fields=Ast_core_type_class_type.handle_class_type_fieldsselfpcsig_fields;};pcty_attributes;}|Pcty_open_(* let open M in CT *)|Pcty_constr_|Pcty_extension_|Pcty_arrow_->Location.raise_errorf~loc:pcty_loc"invalid or unused attribute `bs`")(* {[class x : int -> object
end [@bs]
]}
Actually this is not going to happpen as below is an invalid syntax
{[class type x = int -> object
end[@bs]]}
*)letclass_expr_mapper(self:mapper)(ce:Parsetree.class_expr)=matchce.pcl_descwith|Pcl_let(r,vbs,sub_ce)->{cewithpcl_desc =Pcl_let(r,Ast_tuple_pattern_flatten.value_bindings_mapperselfvbs,self.class_exprselfsub_ce);}|_->default_mapper.class_exprselfceletsignature_item_mapper(self:mapper)(sigi:Parsetree.signature_item)=matchsigi.psig_descwith|Psig_type (rf,tdcls)->Ast_tdcls.handleTdclsInSigiselfsigirftdcls|Psig_value({pval_attributes;pval_prim }asvalue_desc)->(letpval_attributes=self.attributesselfpval_attributesinifAst_attributes.rs_externalspval_attributespval_primthenAst_external.handleExternalInSigselfvalue_descsigielsematchAst_attributes.has_inline_payloadpval_attributeswith|Some({attr_payload=PStr[{pstr_desc=Pstr_eval({pexp_desc},_)}];_;}asattr)->(matchpexp_descwith|Pexp_constant(Pconst_string(s,_,dec))->succeedattrpval_attributes;{sigi withpsig_desc=Psig_value{value_descwithpval_prim=External_ffi_types.inline_string_primitivesdec;pval_attributes=[];};}|Pexp_constant(Pconst_integer(s,None))->succeedattrpval_attributes;lets=Int32.of_string sin{sigiwithpsig_desc=Psig_value{value_descwithpval_prim=External_ffi_types.inline_int_primitives;pval_attributes =[];};}|Pexp_constant(Pconst_integer(s,Some'L'))->lets=Int64.of_stringsinsucceedattrpval_attributes;{sigi withpsig_desc=Psig_value{value_descwithpval_prim=External_ffi_types.inline_int64_primitives;pval_attributes=[];};}|Pexp_constant(Pconst_float(s,None))->succeedattrpval_attributes;{sigi withpsig_desc=Psig_value{value_descwithpval_prim=External_ffi_types.inline_float_primitives;pval_attributes=[];};}|Pexp_construct({txt=Lident(("true"|"false")astxt)},None)->succeedattrpval_attributes;{sigi withpsig_desc=Psig_value{value_descwithpval_prim=External_ffi_types.inline_bool_primitive(txt="true");pval_attributes=[];};}|_->default_mapper.signature_itemselfsigi)|Some_|None->default_mapper.signature_itemselfsigi)|_->default_mapper.signature_itemselfsigiletstructure_item_mapper(self:mapper)(str:Parsetree.structure_item)=match str.pstr_descwith|Pstr_type (rf,tdcls)(* [ {ptype_attributes} as tdcl ] *)->Ast_tdcls.handleTdclsInStruselfstrrftdcls|Pstr_primitiveprimwhen Ast_attributes.rs_externalsprim.pval_attributesprim.pval_prim->Ast_external.handleExternalInStruselfprimstr|Pstr_value(Nonrecursive,[{pvb_pat={ppat_desc=Ppat_varpval_name}aspvb_pat;pvb_expr;pvb_attributes;pvb_loc;};])->(let pvb_expr=self.exprselfpvb_exprinletpvb_attributes=self.attributesselfpvb_attributesinlethas_inline_property=Ast_attributes.has_inline_payloadpvb_attributesinmatch(has_inline_property,pvb_expr.pexp_desc)with|Someattr,Pexp_constant(Pconst_string(s,_,dec))->succeedattrpvb_attributes;{strwithpstr_desc=Pstr_primitive{pval_name;pval_type=Ast_literal.type_string();pval_loc=pvb_loc;pval_attributes=[];pval_prim=External_ffi_types.inline_string_primitivesdec;};}|Someattr,Pexp_constant(Pconst_integer(s,None))->lets=Int32.of_stringsinsucceedattrpvb_attributes;{strwithpstr_desc=Pstr_primitive{pval_name;pval_type=Ast_literal.type_int();pval_loc=pvb_loc;pval_attributes=[];pval_prim=External_ffi_types.inline_int_primitives;};}|Someattr,Pexp_constant(Pconst_integer(s,Some'L'))->lets=Int64.of_stringsinsucceedattrpvb_attributes;{strwithpstr_desc=Pstr_primitive{pval_name;pval_type=Ast_literal.type_int64;pval_loc=pvb_loc;pval_attributes=[];pval_prim=External_ffi_types.inline_int64_primitives;};}|Someattr,Pexp_constant(Pconst_float(s,None))->succeedattrpvb_attributes;{strwithpstr_desc=Pstr_primitive{pval_name;pval_type=Ast_literal.type_float;pval_loc=pvb_loc;pval_attributes=[];pval_prim=External_ffi_types.inline_float_primitives;};}|(Someattr,Pexp_construct({txt=Lident(("true"|"false")astxt)},None))->succeedattrpvb_attributes;{strwithpstr_desc=Pstr_primitive{pval_name;pval_type=Ast_literal.type_bool();pval_loc=pvb_loc;pval_attributes=[];pval_prim=External_ffi_types.inline_bool_primitive(txt="true");};}|_->{strwithpstr_desc=Pstr_value(Nonrecursive,Ast_tuple_pattern_flatten.value_bindings_mapperself[{pvb_pat;pvb_expr;pvb_attributes;pvb_loc}]);})|Pstr_value (r,vbs)->{strwithpstr_desc =Pstr_value(r,Ast_tuple_pattern_flatten.value_bindings_mapperselfvbs);}|Pstr_attribute{attr_name={txt="bs.config"|"config"};_}->str|_->default_mapper.structure_itemselfstrletmapper:mapper={default_mapperwithexpr=expr_mapper;typ=typ_mapper;class_type=class_type_mapper;class_expr=class_expr_mapper;signature_item=signature_item_mapper;structure_item=structure_item_mapper;(* Ad-hoc way to internalize stuff *)label_declaration=(funselflbl->letlbl=default_mapper.label_declarationselflblinmatchlbl.pld_attributeswith|[{attr_name={txt="internal"};_}]->{lblwithpld_name={lbl.pld_namewithtxt=String.capitalize_asciilbl.pld_name.txt;};pld_attributes=[];}|_->lbl);}