123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514(* 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. *)openImporttype('a,'b)st={get:'aoption;set:'boption}letassert_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`)"leterror_if_bs_or_non_namespaced~loctxt=matchtxtwith|"bs"->Location.raise_errorf~loc"The `[@bs]' attribute has been removed in favor of `[@u]'."|other->ifString.starts_with~prefix:"bs."other||not(Melange_ffi.External_ffi_attributes.is_mel_attributetxt)thenLocation.raise_errorf~loc"`[@bs.*]' and non-namespaced attributes have been removed in favor \
of `[@mel.*]' attributes."letprocess_method_attributes_revattrs=letexceptionLocalofLocation.t*stringintryletret=List.fold_left~f:(fun(st,acc)({attr_name={txt;loc};attr_payload=payload;_}asattr)->matchtxtwith|"mel.get"|"bs.get"|"get"->error_if_bs_or_non_namespaced~loctxt;letresult=matchAst_payload.ident_or_record_as_configpayloadwith|Errors->raise(Local(loc,s))|Okconfig->List.fold_left~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)~init:(false,false)configin({stwithget=Someresult},acc)|"mel.set"|"bs.set"|"set"->error_if_bs_or_non_namespaced~loctxt;letresult=matchAst_payload.ident_or_record_as_configpayloadwith|Errors->raise(Local(loc,s))|Okconfig->List.fold_left~f:(fun_st({txt;loc},opt_expr)->(*FIXME*)iftxt="no_get"thenmatchopt_exprwith|None->`No_get|Somee->ifassert_bool_litethen`No_getelse`GetelseError.err~locUnsupported_predicates)~init:`Getconfigin(* properties -- void
[@@set{only}] *)({stwithset=Someresult},acc)|_->(st,attr::acc))~init:({get=None;set=None},[])attrsinOkretwithLocal(loc,s)->Error(loc,s)typeattr_kind=|Nothing|Meth_callbackofattribute|Uncurryofattribute|Methodofattributeletprocess_attributes_revattrs:attr_kind*attributelist=List.fold_left~f:(fun(st,acc)({attr_name={txt;loc};_}asattr)->match(txt,st)with|"u",(Nothing|Uncurry_)->(Uncurryattr,acc)(* TODO: warn unused/duplicated attribute *)|("mel.this"|"bs.this"|"this"),(Nothing|Meth_callback_)->error_if_bs_or_non_namespaced~loctxt;(Meth_callbackattr,acc)|("mel.meth"|"bs.meth"|"meth"),(Nothing|Method_)->error_if_bs_or_non_namespaced~loctxt;(Methodattr,acc)|("u"|"mel.this"|"this"),_->Error.err~locConflict_u_mel_this_mel_meth|_,_->(st,attr::acc))~init:(Nothing,[])attrsletprocess_pexp_fun_attributes_revattrs=List.fold_left~f:(fun(st,acc)({attr_name={txt;loc};_}asattr)->matchtxtwith|"mel.open"|"bs.open"->error_if_bs_or_non_namespaced~loctxt;(true,acc)|_->(st,attr::acc))~init:(false,[])attrsletprocess_uncurriedattrs=List.fold_left~f:(fun(st,acc)({attr_name={txt;_};_}asattr)->match(txt,st)with"u",_->(true,acc)|_,_->(st,attr::acc))~init:(false,[])attrsletis_uncurriedattr=matchattrwith|{attr_name={Location.txt="u";_};_}->true|_->falseletmel_get={attr_name={txt="mel.get";loc=Location.none};attr_payload=PStr[];attr_loc=Location.none;}letmel_get_index={attr_name={txt="mel.get_index";loc=Location.none};attr_payload=PStr[];attr_loc=Location.none;}letmel_get_arity={attr_name={txt="internal.arity";loc=Location.none};attr_payload=PStr[{pstr_desc=Pstr_eval({pexp_loc=Location.none;pexp_loc_stack=[];pexp_attributes=[];pexp_desc=Pexp_constant(Pconst_integer(string_of_int1,None));},[]);pstr_loc=Location.none;};];attr_loc=Location.none;}letmel_set={attr_name={txt="mel.set";loc=Location.none};attr_payload=PStr[];attr_loc=Location.none;}letinternal_expansive=letinternal_expansive_label="internal.expansive"in{attr_name={txt=internal_expansive_label;loc=Location.none};attr_payload=PStr[];attr_loc=Location.none;}letmel_return_undefined={attr_name={txt="mel.return";loc=Location.none};attr_payload=PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_ident{txt=Lident"undefined_to_opt";loc=Location.none};pexp_loc=Location.none;pexp_loc_stack=[];pexp_attributes=[];},[]);pstr_loc=Location.none;};];attr_loc=Location.none;}typeas_const_payload=Intofint|Strofstring|Js_literal_strofstringletiter_process_mel_string_or_int_as(attrs:attributes)=letst=refNoneinList.iter~f:(fun({attr_name={txt;loc};attr_payload=payload;_}asattr)->matchtxtwith|"mel.as"|"bs.as"|"as"->error_if_bs_or_non_namespaced~loctxt;if!st=Nonethen(Mel_ast_invariant.mark_used_mel_attributeattr;matchAst_payload.is_single_intpayloadwith|None->(matchpayloadwith|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constant(Pconst_string(s,_,((None|Some"json")asdec)));pexp_loc;_;},_);_;};]->ifdec=Nonethenst:=Some(Strs)else((matchMelange_ffi.Classify_function.classify~check:(pexp_loc,Melange_ffi.Flow_ast_utils.flow_deli_offsetdec)swith|Js_literal_->()|_->Location.raise_errorf~loc:pexp_loc"`[@mel.as {json| ... |json}]' only supports \
JavaScript literals");st:=Some(Js_literal_strs))|_->Error.err~locExpect_int_or_string_or_json_literal)|Somev->st:=Some(Intv))elseError.err~locDuplicated_mel_as|_->())attrs;!st(* duplicated @uncurry @string not allowed,
it is worse in @uncurry since it will introduce
inconsistency in arity *)letiter_process_mel_string_int_unwrap_uncurryattrs=letst=ref`Nothinginletassignv({attr_name={loc;_};_}asattr)=if!st=`Nothingthen(Mel_ast_invariant.mark_used_mel_attributeattr;st:=v)elseError.err~locConflict_attributesinList.iter~f:(fun({attr_name={txt;loc};attr_payload=payload;_}asattr)->matchtxtwith|"mel.string"|"bs.string"|"string"->error_if_bs_or_non_namespaced~loctxt;assign`Stringattr|"mel.int"|"bs.int"|"int"->error_if_bs_or_non_namespaced~loctxt;assign`Intattr|"mel.ignore"|"bs.ignore"|"ignore"->error_if_bs_or_non_namespaced~loctxt;assign`Ignoreattr|"mel.unwrap"|"bs.unwrap"|"unwrap"->error_if_bs_or_non_namespaced~loctxt;assign`Unwrapattr|"mel.uncurry"|"bs.uncurry"|"uncurry"->error_if_bs_or_non_namespaced~loctxt;assign(`Uncurry(Ast_payload.is_single_intpayload))attr|_->())attrs;!stletiter_process_mel_string_asattrs:stringoption=letst=refNoneinList.iter~f:(fun({attr_name={txt;loc};attr_payload=payload;_}asattr)->matchtxtwith|"mel.as"|"bs.as"|"as"->error_if_bs_or_non_namespaced~loctxt;if!st=Nonethen(matchAst_payload.is_single_stringpayloadwith|None->Error.err~locExpect_string_literal|Some(v,_dec)->Mel_ast_invariant.mark_used_mel_attributeattr;st:=Somev)elseError.err~locDuplicated_mel_as|_->())attrs;!stletfirst_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_attributeattrs=letst=refNoneinlet_ffi,rest=List.partitionattrs~f:(function|{Parsetree.attr_name={txt="mel.internal.ffi";loc};attr_payload;_;}->(match!stwith|Some_->Location.raise_errorf~loc"Duplicate `[@mel.internal.ffi \"..\"]' annotation"|None->(matchattr_payloadwith|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constantconst;_},_);_;};]->(matchconstwith|Pconst_string(s,_,_)->st:=Somes;true|_->false)|_->Location.raise_errorf~loc"`[@mel.internal.ffi \"..\"]' annotation must be a string"))|_->false)in(!st,rest)(**
[@@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_asattrs=letst=refNoneinList.iter~f:(fun({attr_name={txt;loc};attr_payload=payload;_}asattr)->matchtxtwith|"mel.as"|"bs.as"|"as"->error_if_bs_or_non_namespaced~loctxt;if!st=Nonethen(matchAst_payload.is_single_intpayloadwith|None->Error.err~locExpect_int_literal|Some_asv->Mel_ast_invariant.mark_used_mel_attributeattr;st:=v)elseError.err~locDuplicated_mel_as|_->())attrs;!stlethas_mel_optionalattrs:bool=List.exists~f:(fun({attr_name={txt;loc};_}asattr)->matchtxtwith|"mel.optional"|"bs.optional"|"optional"->error_if_bs_or_non_namespaced~loctxt;Mel_ast_invariant.mark_used_mel_attributeattr;true|_->false)attrsletis_inline:attribute->bool=fun{attr_name={txt;loc};_}->matchtxtwith|"mel.inline"->true|"bs.inline"->error_if_bs_or_non_namespaced~loctxt;false|_->falselethas_inline_payloadattrs=List.find_opt~f:is_inlineattrsletis_mel_as{attr_name={txt;loc};_}=matchtxtwith|"mel.as"->true|"bs.as"|"as"->error_if_bs_or_non_namespaced~loctxt;false|_->falselethas_mel_as_payloadattrs=List.fold_left~f:(fun(attrs,found)attr->match(is_mel_asattr,found)with|true,None->(attrs,Someattr)|false,Some_|false,None->(attr::attrs,found)|true,Some_->Location.raise_errorf~loc:attr.attr_loc"Duplicate `%@mel.as' attribute found")~init:([],None)attrsletocaml_warningw={attr_name={txt="ocaml.warning";loc=Location.none};attr_payload=PStrAst_helper.[Str.eval(Exp.constant(Pconst_string(w,Location.none,None)))];attr_loc=Location.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"letmel_ffi=fun(t:Melange_ffi.External_ffi_types.t)->{Parsetree.attr_name={txt="mel.internal.ffi";loc=Location.none};attr_loc=Location.none;attr_payload=PStr[Ast_helper.(Str.eval(Exp.constant(Const.string(Melange_ffi.External_ffi_types.to_stringt))));];}