123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442(* Js_of_ocaml library
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2010 Jérôme Vouillon
* Laboratoire PPS - CNRS Université Paris Diderot
*
* 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, with linking exception;
* either version 2.1 of the License, or (at your option) any 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.
*)letrnd=Random.State.make[|0x313511d4|]letrandom_var()=Format.sprintf"jsoo_%08Lx"(Random.State.int64rnd0x100000000L)letrandom_tvar()=Format.sprintf"jsoo_%08Lx"(Random.State.int64rnd0x100000000L)moduleStringMap=Map.Make(String)openCamlp4moduleId:Sig.Id=structletname="Javascript"letversion="1.0"endmoduleMake(Syntax:Sig.Camlp4Syntax)=structopenSigincludeSyntaxletinside_Js=lazy(trymatchFilename.basename(Filename.chop_extension(!Camlp4_config.current_input_file))with|"js"|"Js"->true|_->falsewithInvalid_argument_->false)letjs_t_id_locs=ifLazy.forceinside_Jsthen<:ctyp<$lid:s$>>else<:ctyp<Js.$lid:s$>>letjs_u_id_locs=ifLazy.forceinside_Jsthen<:expr<Unsafe.$lid:s$>>else<:expr<Js.Unsafe.$lid:s$>>letjs_id_locs=ifLazy.forceinside_Jsthen<:expr<$lid:s$>>else<:expr<Js.$lid:s$>>letrecfilterstream=matchstreamwithparser[<'(KEYWORD"#",loc);rest>]->beginmatchrestwithparser[<'(KEYWORD"#",loc')>]->[<'(KEYWORD"##",Loc.mergelocloc');filterrest>]|[<>]->[<'(KEYWORD"#",loc);filterrest>]end|[<'other;rest>]->[<'other;filterrest>]let_=Token.Filter.define_filter(Gram.get_filter())(funold_filterstream->old_filter(filterstream))letrecparse_comma_liste=matchewith<:expr<$e1$,$e2$>>->e1::parse_comma_liste2|_->[e]letrecto_sem_expr_locl=matchlwith[]->assertfalse|[e]->e|e1::rem-><:expr<$e1$;$to_sem_expr_locrem$>>letmake_array_locl=matchlwith[]-><:expr<[||]>>|_-><:expr<[|$to_sem_expr_locl$|]>>letwith_typeet=let_loc=Ast.loc_of_exprein<:expr<($e$:$t$)>>letunescapelab=assert(lab<>"");letlab=iflab.[0]='_'thenString.sublab1(String.lengthlab-1)elselabintryleti=String.rindexlab'_'inifi=0thenraiseNot_found;String.sublab0iwithNot_found->labletfresh_type_loc=<:ctyp<'$random_tvar()$>>letarrows_locargsret=List.fold_right(funarg_typrem_typ-><:ctyp<$arg_typ$->$rem_typ$>>)argsretletfuns_locargsret=List.fold_right(funxnext_fun-><:expr<fun$lid:x$->$next_fun$>>)argsretletrecapply_locinit=function|[]->init|x::xs->apply_loc<:expr<$init$$x$>>xsletconstrain_types_loce_loc(e:string)v_loc(v:string)v_typm_locmm_typargs=lettyp_var=fresh_typee_locinletcstr=let_loc=e_locin<:expr<(($lid:e$:$js_t_id_loc"t"$<..>):$js_t_id_loc"t"$$typ_var$)>>inletx=let_loc=e_locin<:expr<x>>inletbody=let_loc=Syntax.Loc.mergee_locm_locin<:expr<($x$#$lid:m$:$m_typ$)>>inlety=let_loc=v_locin<:expr<($lid:v$:$v_typ$)>>inletres=List.fold_right(fun(e,x,t)e'->let_loc=Ast.loc_of_exprein<:expr<let_=($lid:x$:$t$)in$e'$>>)args<:expr<$y$>>in<:expr<letmoduleM=structvalueres=let_=$cstr$inlet_=fun(x:$typ_var$)->$body$in$res$;endinM.res>>letmethod_call_locobjlablab_locargs=letargs=List.map(fune->letmy_var=random_var()inletmy_typ=fresh_type_locin(e,my_var,my_typ))argsinletret_typ=fresh_type_locinletmethod_type=arrows_loc(List.map(fun(_,_,ty)->ty)args)<:ctyp<$js_t_id_loc"meth"$$ret_typ$>>inleto="jsoo_self"inletres="jsoo_res"inletmeth_args=List.map(fun(_,x,_)-><:expr<$js_u_id_loc"inject"$$lid:x$>>)argsinletmeth_args=make_array_locmeth_argsinleto_loc=Ast.loc_of_exprobjinletbinding=List.map(fun(e,x,_)-><:binding<$lid:x$=$e$>>)argsinletbody=<:expr<let$lid:o$=$obj$inlet$lid:res$=$js_u_id_loc"meth_call"$$lid:o$$str:unescapelab$$meth_args$in$constrain_types_loco_loco_locresret_typlab_loclabmethod_typeargs$>>inmatchargswith|[]->body|_-><:expr<let$list:binding$in$body$>>letnew_object_locconstructorargs=letargs=List.map(fune->(e,fresh_type_loc))argsinletobj_type=<:ctyp<$js_t_id_loc"t"$$fresh_type_loc$>>inletconstr_fun_type=arrows_loc(List.mapsndargs)obj_typeinletargs=List.map(fun(e,t)-><:expr<$js_u_id_loc"inject"$$with_typeet$>>)argsinletargs=make_array_locargsinletx=random_var()inletconstr=with_typeconstructor<:ctyp<$js_t_id_loc"constr"$$constr_fun_type$>>inwith_type<:expr<let$lid:x$=$constr$in$js_u_id_loc"new_obj"$$lid:x$$args$>><:ctyp<$obj_type$>>letrecparse_field_listl=matchlwith<:rec_binding<$f1$;$f2$>>->f1::parse_field_listf2|_->[l]letrecparse_class_str_listl=matchlwith|<:class_str_item<$f1$;$f2$>>->f1::parse_class_str_listf2|_->[l]type'aloc='a*Loc.ttypeval_={val_label:stringloc;val_mutabl:bool;val_body:Ast.exprloc;val_typ:Ast.ctyp;}typemeth_={meth_label:stringloc;meth_body:Ast.exprloc;meth_fun_typ:Ast.ctyplist;meth_ret_typ:Ast.ctyp;}typeval_and_meth=[`Valofval_|`Methofmeth_]letparse_fieldf:val_and_meth=matchfwith<:rec_binding<$label$=$e$>>->letlab_loc,lab=matchlabelwith|Ast.IdLid(loc,lab)->loc,lab|_->assertfalseinlete_loc=Ast.loc_of_expreinlett=fresh_typelab_locin`Val{val_label=lab,lab_loc;val_mutabl=false;val_body=e,e_loc;val_typ=t}|_->assertfalseletparse_class_itemc:val_and_meth=let_loc=Ast.loc_of_class_str_itemcinmatchcwith|<:class_str_item<value$lab$=$e$>>->lete_loc=Ast.loc_of_expreinlett=fresh_type_locin`Val{val_label=lab,_loc;val_mutabl=false;val_body=e,e_loc;val_typ=t}|<:class_str_item<valuemutable$label$=$e$>>->lete_loc=Ast.loc_of_expreinlett=fresh_type_locin`Val{val_label=label,_loc;val_mutabl=true;val_body=e,e_loc;val_typ=t}|<:class_str_item<method$label$=$e$>>->lete_loc=Ast.loc_of_expreinletrecget_argx=matchxwith|<:expr<fun$_x$->$e$>>->(fresh_typee_loc)::get_arge|_->[]inlet_loc=e_locinlett=fresh_type_locin`Meth{meth_label=label,_loc;meth_body=e,e_loc;meth_fun_typ=get_arge;meth_ret_typ=t}|c->letloc=Ast.loc_of_class_str_itemcinFormat.eprintf"This field is not valid inside a js literal object (%s)@."(Loc.to_stringloc);failwith"Error while preprocessing with with Js_of_ocaml extention syntax"letliteral_object_loc?self(fields:val_and_methlist)=letself_typ=fresh_type_locinlet_=List.fold_left(funacc(`Val{val_label=(lab,loc);_}|`Meth{meth_label=(lab,loc);_})->lettxt=unescapelabinifStringMap.memtxtaccthenletdetailsname=ifname<>txtthenPrintf.sprintf" (normalized to %S)"txtelse""inlet(loc',name')=StringMap.findtxtaccinFormat.eprintf"Duplicated label %S%s at %s@.%S%s previously seen at %s@."lab(detailslab)(Loc.to_stringloc)name'(detailsname')(Loc.to_stringloc');failwith"Error while preprocessing with with Js_of_ocaml extention syntax"elseStringMap.addtxt(loc,lab)acc)StringMap.emptyfieldsinletcreate_method_type=function|`Val{val_label=(label,_loc);val_mutabl=true;val_typ;_}-><:ctyp<$lid:label$:($js_t_id_loc"prop"$$val_typ$)>>|`Val{val_label=(label,_loc);val_mutabl=false;val_typ;_}-><:ctyp<$lid:label$:($js_t_id_loc"readonly_prop"$$val_typ$)>>|`Meth{meth_label=(label,_loc);meth_fun_typ;meth_ret_typ;_}->letall=arrows_locmeth_fun_typ<:ctyp<$js_t_id_loc"meth"$$meth_ret_typ$>>in<:ctyp<$lid:label$:$all$>>inletobj_type=<:ctyp<<$list:List.mapcreate_method_typefields$>>>inletrecannotate_bodyfun_tyret_tybody=matchfun_ty,bodywith|ty::types,(<:expr<fun$pat$->$body$>>)-><:expr<fun($pat$:$ty$)->$annotate_bodytypesret_tybody$>>|[],body-><:expr<($body$:$ret_ty$)>>|_->raise(Invalid_argument"Inconsistent number of arguments")inletcreate_value=function|`Val{val_label=(lab,_loc);val_body=(e,_);val_typ;_}->lab,<:expr<$with_typeeval_typ$>>|`Meth{meth_label=(lab,_loc);meth_body=(e,_);meth_fun_typ;meth_ret_typ;_}->lete,wrapper=matchselfwith|None->e,"wrap_callback"|Someself_pat->annotate_body(self_typ::meth_fun_typ)meth_ret_typ<:expr<fun$self_pat$->$e$>>,"wrap_meth_callback"inlab,<:expr<$js_id_locwrapper$$e$>>inletargs=List.mapcreate_valuefieldsinletmake_obj=funs_loc(List.map(fun(name,_expr)->name)args)(<:expr<($js_u_id_loc"obj"$$make_array_loc(List.map(fun(name,_)-><:expr<($str:unescapename$,$js_u_id_loc"inject"$$lid:name$)>>)args)$:$js_t_id_loc"t"$$obj_type$as$self_typ$)>>)inletbindings=List.map(fun(lab,expr)-><:binding<$lid:lab$=$expr$>>)(("make_obj",make_obj)::args)in<:expr<let$list:bindings$in$apply_loc<:expr<make_obj>>(List.map(fun(lab,_)-><:expr<$lid:lab$>>)args)$>>letjsmeth=Gram.Entry.mk"jsmeth"letopt_class_self_patt_jsoo=Gram.Entry.mk"opt_class_self_patt_jsoo"EXTENDGramjsmeth:[["##";lab=label->(_loc,lab)]];opt_class_self_patt_jsoo:[["(";p=patt;")"->p|"(";p=patt;":";t=ctyp;")"-><:patt<($p$:$t$)>>|-><:patt<_>>]];expr:BEFORE"."["##"RIGHTA[e=SELF;(lab_loc,lab)=jsmeth->leto="jsoo_obj"inleto_loc=Ast.loc_of_expreinletres="jsoo_res"in<:expr<let$lid:o$=$e$inlet$lid:res$=$js_u_id_loc"get"$$lid:o$$str:unescapelab$in$constrain_types_loco_loco_locres<:ctyp<'jsoo_res>>lab_loclab<:ctyp<$js_t_id_loc"gen_prop"$<get:'jsoo_res;..>>>[]$>>|e1=SELF;(lab_loc,lab)=jsmeth;"<-";e2=exprLEVEL"top"->leto="jsoo_obj"inleto_loc=Ast.loc_of_expre1inletv="jsoo_arg"in<:expr<let$lid:o$=$e1$and$lid:v$=$e2$inlet_=$constrain_types_loco_loco(Ast.loc_of_expre2)v<:ctyp<'jsoo_arg>>lab_loclab<:ctyp<$js_t_id_loc"gen_prop"$<set:'jsoo_arg->unit;..>>>[]$in$js_u_id_loc"set"$$lid:o$$str:unescapelab$($lid:v$)>>|e=SELF;(lab_loc,lab)=jsmeth;"(";")"->method_call_locelablab_loc[]|e=SELF;(lab_loc,lab)=jsmeth;"(";l=comma_expr;")"->method_call_locelablab_loc(parse_comma_listl)]];expr:LEVEL"simple"[["jsnew";e=exprLEVEL"label";"(";")"->new_object_loce[]|"jsnew";e=exprLEVEL"label";"(";l=comma_expr;")"->new_object_loce(parse_comma_listl)|"jsobject";"end"-><:expr<($js_u_id_loc"obj"$[||]:$js_t_id_loc"t"$<>)>>|"jsobject";self=opt_class_self_patt_jsoo;l=class_structure;"end"->letfield_list=parse_class_str_listlinletfields=List.mapparse_class_itemfield_listinliteral_object_loc~selffields(* | "{:"; ":}" -> <:expr< ($js_u_id _loc "obj"$ [| |] : Js.t < > ) >> *)(* | "{:"; l = field_expr_list; ":}" -> *)(* let field_list = parse_field_list l in *)(* let fields = List.map parse_field field_list in *)(* literal_object _loc fields *)]];END(*XXX n-ary methods
how to express optional fields? if they are there, they must have
some type, but they do not have to be there
use variant types instead of object types?
in a negative position... (but then we have to negate again...)
{ foo: "bar", baz : 7 } : [`foo of string field | `baz of int field] obj
let f (x : t) = (x : [< `foo of string field | `baz of int field| `x of string field] obj)
XXXX
module WEIRDMODULENAME = struct type 'a o = 'a Js.t val unsafe_get = Js.Unsafe.get ... end
(let module M = WEIRDMODULENAME in (M.unsafe_get : <x : 'a M.meth> -> 'a))
XXXX be more careful with error messages:
put coercions against arguments or whole expression
*)endmoduleM=Register.OCamlSyntaxExtension(Id)(Make)(* open Camlp4.PreCast *)(* let expand _loc _ str = *)(* let lex = Compiler.Parse_js.lexer_from_string ~rm_comment:true str in *)(* let p = Compiler.Parse_js.parse lex in *)(* <:expr< 5 >> *)(* let _ = Syntax.Quotation.add "js" Syntax.Quotation.DynAst.expr_tag expand *)