123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446(* 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. *)openImportmoduleExternal_arg_spec=Melange_ffi.External_arg_spectypest={get:(bool*bool)option;set:[`Get|`No_get]option}letprocess_method_attributes_rev=letexceptionLocalofLocation.t*stringinletassert_bool_lit(e:expression)=matche.pexp_descwith|Pexp_construct({txt=Lident"true";_},None)->true|Pexp_construct({txt=Lident"false";_},None)->false|_->Location.raise_errorf~loc:e.pexp_loc"expected this expression to be a boolean literal (`true` or `false`)"infunattrs->tryletret=List.fold_leftattrs~init:({get=None;set=None},[])~f:(fun(st,acc)attr->let{attr_name={txt;loc};attr_payload=payload;_}=attrinmatchtxtwith|"mel.get"->letresult=matchAst_payload.ident_or_record_as_configpayloadwith|Errors->raise(Local(loc,s))|Okconfig->List.fold_leftconfig~init:(false,false)~f:(fun(null,undefined)({txt;loc},opt_expr)->matchtxtwith|"null"->((matchopt_exprwith|None->true|Somee->assert_bool_lite),undefined)|"undefined"->(null,matchopt_exprwith|None->true|Somee->assert_bool_lite)|"nullable"->(matchopt_exprwith|None->(true,true)|Somee->letv=assert_bool_litein(v,v))|_->Error.err~locUnsupported_predicates)in({stwithget=Someresult},acc)|"mel.set"->letresult=matchAst_payload.ident_or_record_as_configpayloadwith|Errors->raise(Local(loc,s))|Okconfig->List.fold_leftconfig~init:`Get~f:(fun_st({txt;loc},opt_expr)->(*FIXME*)matchtxtwith|"no_get"->(matchopt_exprwith|None->`No_get|Somee->(matchassert_bool_litewith|true->`No_get|false->`Get))|_->Error.err~locUnsupported_predicates)in(* properties -- void
[@@set{only}] *)({stwithset=Someresult},acc)|_->(st,attr::acc))inOkretwithLocal(loc,s)->Error(loc,s)moduleKind=structtypet=|Nothing|Meth_callbackofattribute|Uncurryofattribute|Methodofattributeendletprocess_attributes_revattrs:Kind.t*attributelist=List.fold_left~init:(Kind.Nothing,[])attrs~f:(fun(st,acc)({attr_name={txt;loc};_}asattr)->match(txt,st)with|"u",(Kind.Nothing|Uncurry_)->(Uncurryattr,acc)(* TODO: warn unused/duplicated attribute *)|"mel.this",(Nothing|Meth_callback_)->(Meth_callbackattr,acc)|"mel.meth",(Nothing|Method_)->(Methodattr,acc)|("u"|"mel.this"),_->Error.err~locConflict_u_mel_this_mel_meth|_,_->(st,attr::acc))letprocess_pexp_fun_attributes_revattrs=List.fold_left~init:(false,[])attrs~f:(fun(st,acc)({attr_name={txt;loc=_};_}asattr)->matchtxtwith"mel.open"->(true,acc)|_->(st,attr::acc))letprocess_uncurriedattrs=List.fold_left~init:(false,[])attrs~f:(fun(st,acc)({attr_name={txt;_};_}asattr)->match(txt,st)with"u",_->(true,acc)|_,_->(st,attr::acc))letis_uncurried=function|{attr_name={Location.txt="u";_};_}->true|_->falseletattrnamepayload={attr_name={txt=name;loc=Location.none};attr_payload=PStrpayload;attr_loc=Location.none;}letmel_get=attr"mel.get"[]letmel_get_index=attr"mel.get_index"[]letmel_set=attr"mel.set"[]letmel_get_arity=attr"internal.arity"[Ast_builder.Default.pstr_eval~loc:Location.none(Ast_builder.Default.pexp_constant~loc:Location.none(Pconst_integer("1",None)))[];]letinternal_expansive=attr"internal.expansive"[]letmel_return_undefined=attr"mel.return"[Ast_builder.Default.pstr_eval~loc:Location.none(Ast_builder.Default.pexp_ident~loc:Location.none{txt=Lident"undefined_to_opt";loc=Location.none})[];]letiter_process_mel_as_cst=letrecinnerattrs(st:External_arg_spec.Arg_cst.toption)=matchattrswith|({attr_name={txt;loc};attr_payload=payload;_}asattr)::rest->(matchtxtwith|"mel.as"->(matchstwith|Some_->Error.err~locDuplicated_mel_as|None->(Mel_ast_invariant.mark_used_mel_attributeattr;matchAst_payload.is_single_intpayloadwith|Somev->innerrest(Some(Intv))|None->(matchpayloadwith|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constant(Pconst_string(s,_,((None|Some"json")asdec)));pexp_loc;_;},_);_;};]->(matchdecwith|None->innerrest(Some(External_arg_spec.Arg_cst.Strs))|Some_->(matchMelange_ffi.Classify_function.classify~loc:pexp_loc~check_errors:(Check{delimiter=dec})swith|Js_literal_->()|Js_function_|Js_exp_unknown->Location.raise_errorf~loc:pexp_loc"`[@mel.as {json| ... |json}]' only supports \
JavaScript literals");innerrest(Some(Js_literals)))|_->Error.err~locExpect_int_or_string_or_json_literal)))|_->innerrestst)|[]->stinfun(attrs:attributes)->innerattrsNonemoduleParam_modifier=structtypekind=|Nothing|Spread|Uncurryofintoption(* uncurry arity *)|Unwrap|Ignore|String|Inttypet={kind:kind;loc:Location.t}end(* duplicated @uncurry @string not allowed,
it is worse in @uncurry since it will introduce
inconsistency in arity.
Supported external param type modifiers:
- [@mel.unwrap] -> [ `A of int ] becomes `foo(42)`
- [@mel.uncurry] -> uncurries callbacks in externals
- [@mel.ignore] -> useful to combine with GADTs, e.g.
('a kind [@mel.ignore ] -> 'a -> 'a)
- [@mel.spread] -> [ `A of int ] -> unit becomes `foo("a", 42)` -- supports
`@mel.as` -- previously [@mel.string] *)letiter_process_mel_param_modifier=letassign({attr_name={loc;_};_}asattr)stv=matchstwith|Param_modifier.Nothing->Mel_ast_invariant.mark_used_mel_attributeattr;{Param_modifier.kind=v;loc}|_->Error.err~locConflict_attributesinletrecinnerattrs{Param_modifier.kind=st;loc}=matchattrswith|({attr_name={txt;loc=_};attr_payload=payload;_}asattr)::rest->letst'=matchtxtwith|"mel.spread"->assignattrstSpread|"mel.string"->assignattrstString|"mel.int"->assignattrstInt|"mel.ignore"->assignattrstIgnore|"mel.unwrap"->assignattrstUnwrap|"mel.uncurry"->assignattrst(Uncurry(Ast_payload.is_single_intpayload))|_->{kind=st;loc}ininnerrestst'|[]->{Param_modifier.kind=st;loc}infunattrs->innerattrs{Param_modifier.kind=Nothing;loc=Location.none}letiter_process_mel_string_as=letrecinnerattrsst=matchattrswith|({attr_name={txt;loc};attr_payload=payload;_}asattr)::rest->(matchtxtwith|"mel.as"->(matchstwith|None->(matchAst_payload.is_single_stringpayloadwith|None->Error.err~locExpect_string_literal|Some(v,_dec)->Mel_ast_invariant.mark_used_mel_attributeattr;innerrest(Somev))|Some_->Error.err~locDuplicated_mel_as)|_->innerrestst)|[]->stinfunattrs->innerattrsNoneletfirst_char_special(x:string)=matchxwith|""->false|_->(matchString.unsafe_getx0with|'#'|'?'|'%'->true|_->(* XXX(anmonteiro): Upstream considers "builtin" attributes ones that
start with `?`. We keep the original terminology of `caml_` (and,
incidentally, `nativeint_`). *)String.starts_withx~prefix:"caml_"||String.starts_withx~prefix:"nativeint_")letfirst_marshal_char(x:string)=x<>""&&String.unsafe_getx0='\132'letprims_to_be_encoded(attrs:stringlist)=matchattrswith|[]->assertfalse(* normal val declaration *)|x::_whenfirst_char_specialx->false|_::x::_whenfirst_marshal_charx->false|_->trueletpartition_by_mel_ffi_attribute=letrecinnerattrsaccst=matchattrswith|({attr_name={txt="mel.internal.ffi";loc};attr_payload;_}asx)::rest->(matchstwith|None->(matchattr_payloadwith|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constantconst;_},_);_;};]->(matchconstwith|Pconst_string(s,_,_)->innerrestacc(Somes)|_->innerrest(x::acc)st)|_->Location.raise_errorf~loc"`[@mel.internal.ffi \"..\"]' annotation must be a string")|Some_->Location.raise_errorf~loc"Duplicate `[@mel.internal.ffi \"..\"]' annotation")|x::xs->innerxs(x::acc)st|[]->(st,List.revacc)infunattrs->innerattrs[]None(**
[@@inline]
let a = 3
[@@inline]
let a : 3
They are not considered externals, they are part of the language
*)letrs_externalsattrspval_prim=matchpval_primwith|[]->(* This is val *)false|_::_->(letmel_ffi,attrs=partition_by_mel_ffi_attributeattrsinmatchmel_ffiwith|Some_->false|None->(matchattrswith|[]->prims_to_be_encodedpval_prim|_::_->Melange_ffi.External_ffi_attributes.has_mel_attributes(List.map~f:(fun{attr_name={txt;_};_}->txt)attrs)||prims_to_be_encodedpval_prim))letiter_process_mel_int_as=letrecinnerattrsacc=matchattrswith|({attr_name={txt="mel.as";loc};attr_payload=payload;_}asattr)::rest->(matchaccwith|None->(matchAst_payload.is_single_intpayloadwith|None->Error.err~locExpect_int_literal|Some_asv->Mel_ast_invariant.mark_used_mel_attributeattr;innerrestv)|Some_->Error.err~locDuplicated_mel_as)|_::rest->innerrestacc|[]->accinfunattrs->innerattrsNonelethas_mel_optionalattrs:bool=List.exists~f:(fun({attr_name={txt;loc=_};_}asattr)->matchtxtwith|"mel.optional"->Mel_ast_invariant.mark_used_mel_attributeattr;true|_->false)attrslethas_inline_payloadattrs=List.find_opt~f:(fun{attr_name={txt;loc=_};_}->txt="mel.inline")attrslethas_mel_as_payloadattrs=List.fold_left~f:(fun(attrs,found)attr->matchattr.attr_name.txtwith|"mel.as"->(matchfoundwith|Some_->Location.raise_errorf~loc:attr.attr_loc"Duplicate `%@mel.as' attribute found"|None->(attrs,Someattr))|_->(attr::attrs,found))~init:([],None)attrsletocaml_warningw=attr"ocaml.warning"[Ast_builder.Default.pstr_eval~loc:Location.none(Ast_builder.Default.pexp_constant~loc:Location.none(Pconst_string(w,Location.none,None)))[];](* We disable warning 61 in Melange externals since they're substantially
different from OCaml externals. This warning doesn't make sense for a JS
runtime *)letunboxable_type_in_prim_decl=ocaml_warning"-unboxable-type-in-prim-decl"letignored_extra_argument=ocaml_warning"-ignored-extra-argument"letunused_type_declaration=ocaml_warning"-unused-type-declaration"letmel_ffi=fun(t:Melange_ffi.External_ffi_types.t)->attr"mel.internal.ffi"[Ast_builder.Default.pstr_eval~loc:Location.none(Ast_builder.Default.pexp_constant~loc:Location.none(Pconst_string(Melange_ffi.External_ffi_types.to_stringt,Location.none,None)))[];]