123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363moduleParsetree=Ppxlib.ParsetreemoduleAsttypes=Ppxlib.AsttypesmoduleLongident=Ppxlib.LongidentmoduleLocation=Ppxlib.LocationopenPpxlib.AstopenPpxlib.Ast_helperletmkloctxtloc={txt;loc}letmkloc_opt?(loc=!default_loc)x=mklocxlocletstr?loc?attrss=Exp.constant?loc?attrs(Const.strings)letpvar?locname=Pat.var?loc(mkloc_opt?locname)letidentx=Exp.ident(mkloc_opt(Longident.Lidentx))letunit?loc?attrs()=Exp.construct?loc?attrs(mkloc_opt?loc(Longident.Lident"()"))Nonelettunit?loc()=Typ.constr(mkloc_opt?loc(Longident.Lident"unit"))[]typeerror=|No_parameter|Missing_parameter_type|Missing_parameter_name|Reserved_parameterofstring|Duplicated_parameterofstring|No_return_typeletprint_error~loc(e:error)=leterror_str=matchewith|No_parameter->"The function must have at least one parameter"|Missing_parameter_type->"Missing parameter type anotation"|Missing_parameter_name->"The parameter should be a variable"|Reserved_parameternm->Printf.sprintf"Parameter '%s' has a reserved name"nm|Duplicated_parameternm->Printf.sprintf"Two parameters have name '%s'"nm|No_return_type->"An Lwt.t return type is mandatory"inLocation.raise_errorf~loc"%s"error_strletrpc_namefun_name=letfilename=Filename.(!Ocaml_common.Location.input_name|>chop_extension|>basename)inFormat.sprintf"%s.%s"filenamefun_nameletexpr_tuplel=matchlwith|[]->unit()|[(_,x,_)]->identx|_->Exp.tuple(List.map(fun(_,x,_)->identx)l)letpat_tuplel=matchlwith|[]->Pat.any()|[(_,x,_)]->pvarx|_->Pat.tuple(List.map(fun(_,x,_)->pvarx)l)lettyp_tuplel=matchlwith|[]->tunit()|[(_,_,ty)]->ty|_->Typ.tuple(List.map(fun(_,_,ty)->ty)l)(** Extract T in the type expr [T Lwt.t], return None otherwise. *)letextract_lwt_t=function[%type:[%t?ty]Lwt.t]->Somety|_->None(** Extract T in the expression [(.. : T Lwt.t)], return None otherwise. *)letextract_lwt_t_expr=function|[%expr([%e?_]:[%t?t])]->extract_lwt_tt|_->None(** Name of an argument. Raise an error if there is no label and [pattern] is
not [Ppat_var]. *)letarg_namelabelvar_pattern=matchlabel,var_patternwith|(Labelledn|Optionaln),_->n|Nolabel,{ppat_desc=Ppat_varvar;_}->var.txt|Nolabel,_->print_error~loc:var_pattern.ppat_locMissing_parameter_nameletprocess_paramlabeldefpat=letparamvar_patty=letname=arg_namelabelvar_patinletty=matchlabel,defwith|Optional_,Some_->letloc=ty.ptyp_locin[%type:[%tty]option]|_->tyin`Param(label,name,ty)inmatchpatwith(* [(var_pat : ty)] or [~(label : ty)]. *)|[%pat?([%p?var_pat]:[%t?ty])]->paramvar_patty|_->(matchdefwith(* [?(label = (def : ty))]. *)|Some[%expr([%e?_]:[%t?ty])]->parampatty|_->print_error~loc:pat.ppat_locMissing_parameter_type)letreccollect_paramslexpr=matchexpr.pexp_descwith|Pexp_function(params,constraint_,Pfunction_bodyexpr')->letreclooplparams=matchparamswith|[]->let(l,has_unit),typ=collect_paramslexpr'inlettyp=matchtyp,constraint_with|Some_,_->typ|None,Some(Pconstraintcstr)->extract_lwt_tcstr|None,_->Nonein(l,has_unit),typ|param::rest->(matchparam.pparam_descwith|Pparam_val(label,def,pat)->(matchpat.ppat_descwith|Ppat_construct({txt=Lident"()";_},None)whenlabel=Nolabel&&def=None->let(l,_),typ=collect_paramslexpr'in(l,true),typ|_->(matchprocess_paramlabeldefpatwith|`Param(label,name,ty)->loop((label,name,ty)::l)rest))|Pparam_newtype_->looplrest)inlooplparams|Pexp_constraint(e,_)->let(l,has_unit),typ=collect_paramsleinlettyp=iftyp=Nonethenextract_lwt_t_exprexprelsetypin(l,has_unit),typ|_->(List.revl,false),extract_lwt_t_exprexprletmk_function_param?(loc=Location.none)?(label=Nolabel)?defexprpat={pparam_loc=loc;pparam_desc=Pparam_val(label,defexpr,pat)}letmake_funloc(params,has_unit_arg)body=letparams=List.fold_right(fun(label,ident,_)acc->mk_function_param~label(pvarident)::acc)params(ifhas_unit_argthen[mk_function_param[%pat?()]]else[])inExp.mk~loc(Pexp_function(params,None,Pfunction_bodybody))letbuild_paramsloc(params,has_unit)=List.map(fun(label,x,_)->label,identx)params@ifhas_unitthen[Nolabel,[%expr()]]else[]letapplyargsexpr=Exp.applyexprargsletserver_function~loc~kind~fun_varexpr'=letexpr=matchkindwith|`Connected->[%exprfun(myid:Os_types.User.id)->[%eexpr']]|`Any->[%exprfun(myid_o:Os_types.User.idoption)->[%eexpr']]|`None->expr'in[%strilet%server[%pfun_var]=[%eexpr]]letserver_cacher~loc~kind~cache~fun_name~fun_var~params=matchcachewith|None->[%strilet%server_=()]|Somereturn_typ->letid_param=matchkindwith|`Connected->[Nolabel,[%exprmyid]]|`Any->[Nolabel,[%exprmyid_o]]|`None->[]inletcacheexpr=[%exprlet%lwtx=[%eexpr]inBs_proxy.cache[%derive.caching:[%treturn_typ]]x]inletparametrize_idexpr=matchkindwith|`Connected->[%exprfunmyid->[%eexpr]]|`Any->[%exprfunmyid_o->[%eexpr]]|`None->exprinletexpr=fun_name|>ident|>apply(id_param@build_paramslocparams)|>cache|>make_funlocparams|>parametrize_idin[%strilet%server[%pfun_var]=[%eexpr][@@ocaml.warning"-16"]]letserver_wrapper~loc~kind~raw~cache~fun_name~fun_var~params=ifrawthen[%strilet%server_=()]elseletid_param=matchkindwith|`Connected->[Nolabel,[%exprOs_current_user.get_current_userid()]]|`Any->[Nolabel,[%exprOs_current_user.Opt.get_current_userid()]]|`None->[]inletuncacheexpr=ifcache<>Nonethen[%exprBs_proxy.extract[%eexpr]]elseexprinletexpr=fun_name|>ident|>apply(id_param@build_paramslocparams)|>uncache|>make_funlocparamsin[%strilet%server[%pfun_var]=[%eexpr][@@ocaml.warning"-16-32"]]letclient_wrapper~loc~kind~raw~cache~fun_name~fun_var~params=letid_param=matchkindwith|`Connected->[Nolabel,[%exprmyid]]|`Any->[Nolabel,[%exprmyid_o]]|`None->[]inletuncacheexpr=ifcache<>Nonethen[%exprBs_proxy.extract[%eexpr]]elseexprinletparametrize'expr=[%exprfun[%ppat_tuple(fstparams)]->[%eexpr]]inletparametrize_idexpr=matchkindwith|`Connected->[%exprfunmyid->[%eexpr]]|`Any->[%exprfunmyid_o->[%eexpr]]|`None->exprinletwrapexpr=ifrawthenexprelsematchkindwith|`Connected->[%exprOs_session.connected_rpc[%eexpr]]|`Any->[%exprOs_session.Opt.connected_rpc[%eexpr]]|`None->[%exprOs_session.connected_wrapper[%eexpr]]inletexpr=fun_name|>ident|>apply(id_param@build_paramslocparams)|>uncache|>parametrize'|>parametrize_id|>wrapinletexpr=[%expr~%(Eliom_client.server_function~name:[%estr(rpc_namefun_name)][%json:[%ttyp_tuple(fstparams)]][%eexpr])[%eexpr_tuple(fstparams)]]in[%strilet%client[%pfun_var]=[%emake_funlocparamsexpr][@@ocaml.warning"-16"]]letraw=reffalseletcache=reffalseletis_special_argument=function|[%pat?myid]->Some`Connected|[%pat?myid_o]->Some`Any|_->Noneletreccheck_myidexpr=matchexprwith|{pexp_desc=Pexp_function({pparam_desc=Pparam_val(Nolabel,None,pat);_}::rest,constraint_,(Pfunction_bodybody_exprasbody))}->(matchis_special_argumentpat,restwith|Somesp,[]->sp,body_expr|Somesp,rest->sp,{exprwithpexp_desc=Pexp_function(rest,constraint_,body)}|None,_->`None,expr)|[%expr([%e?e]:[%t?t])]->letkind,new_e=check_myideinifkind<>`Nonethenkind,{exprwithpexp_desc=Pexp_constraint(new_e,t)}else`None,expr|_->`None,exprletextension_impl~legacy~loc~path:_~return_typ_hintfun_nameexpr=letraw=!raw&¬!cacheinletcache=(notlegacy)&&!cacheinletfun_var=pvar~loc:fun_name.locfun_name.txtinletfun_name=fun_name.txtinletkind,expr'=ifrawthen`None,exprelsecheck_myidexprinletparams,return_typ=collect_params[]expr'inletreturn_typ=matchreturn_typwithSome_->return_typ|None->return_typ_hintin(matchparamswith|[],false->print_error~locNo_parameter|l,_->ignore(List.fold_left(funacc(_,nm,_)->ifList.memnmaccthenprint_error~loc(Duplicated_parameternm);ifnm="myid"||nm="myid_o"thenprint_error~loc(Reserved_parameternm);nm::acc)[]l));ifcache&&return_typ=Nonethenprint_error~locNo_return_type;letcache=ifcachethenreturn_typelseNoneinStr.include_~loc(Incl.mk~loc(Mod.structure~loc[server_function~loc~kind~fun_varexpr';server_cacher~loc~kind~cache~fun_name~fun_var~params;client_wrapper~loc~kind~raw~cache~fun_name~fun_var~params;server_wrapper~loc~kind~raw~cache~fun_name~fun_var~params]))letrecreturn_type_of_arrowty=matchty.ptyp_descwith|Ptyp_arrow(_,_,ret)->return_type_of_arrowret|_->tyletlwt_return_typeconstraint_opt=matchconstraint_optwith|Some(Pvc_constraint{typ;_})->extract_lwt_t(return_type_of_arrowtyp)|_->Noneletextension~legacy~loc~pathfun_nameexprconstraint_opt=extension_impl~legacy~loc~path~return_typ_hint:(lwt_return_typeconstraint_opt)fun_nameexprletvb_pattern=letopenPpxlib.Ast_patterninvalue_binding~pat:(ppat_var__')~expr:__~constraint_:__letpattern=letopenPpxlib.Ast_patterninpstr(pstr_valuenonrecursive(vb_pattern^::nil)^::nil)letextensions=letopenPpxlibinList.concat@@List.map(fun(legacy,exts)->List.map(funext->Extension.declareextExtension.Context.structure_itempattern(extension~legacy))exts)[true,["cw_rpc";"crpc";"crpc_opt"];false,["rpc"]]letdriver_args=[("--rpc-raw",Arg.Unit(fun()->raw:=true)," Do not insert any ocsigen-start session wrapper.");("--rpc-cache",Arg.Unit(fun()->cache:=true)," Insert caching directives (for internal use at Be Sport).")]let()=List.iter(fun(key,spec,doc)->Ppxlib.Driver.add_argkeyspec~doc)driver_argsletrules=List.mapPpxlib.Context_free.Rule.extensionextensionslet()=Ppxlib.Driver.register_transformation~rules"rpc"