Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_lwt.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366open!PpxlibopenAst_builder.Default(** {2 Convenient stuff} *)letwith_locf{txt;loc}=f~loctxt(** Test if a case is a catchall. *)letis_catchallcase=letrecis_catchall_patp=matchp.ppat_descwith|Ppat_any|Ppat_var_->true|Ppat_alias(p,_)|Ppat_constraint(p,_)->is_catchall_patp|_->falseincase.pc_guard=None&&is_catchall_patcase.pc_lhs(** Add a wildcard case in there is none. Useful for exception handlers. *)letadd_wildcard_casecases=lethas_wildcard=List.existsis_catchallcasesinifnothas_wildcardthencases@(letloc=Location.nonein[case~lhs:[%pat?exn]~guard:None~rhs:[%exprLwt.failexn]])elsecases(** {3 Internal names} *)letlwt_prefix="__ppx_lwt_"(** {2 Here we go!} *)letdefault_loc=refLocation.noneletsequence=reftrueletstrict_seq=reftrueletused_no_sequence_option=reffalseletused_no_strict_sequence_option=reffalseletno_sequence_option()=sequence:=false;used_no_sequence_option:=trueletno_strict_sequence_option()=strict_seq:=false;used_no_strict_sequence_option:=true(** let%lwt related functions *)letgen_namei=lwt_prefix^string_of_inti(** [p = x] ≡ [__ppx_lwt_$i = x] *)letgen_bindingsl=letauxibinding={bindingwithpvb_pat=pvar~loc:binding.pvb_expr.pexp_loc(gen_namei)}inList.mapiauxl(** [p = x] and e ≡ [Lwt.bind __ppx_lwt_$i (fun p -> e)] *)letgen_bindse_locle=letrecauxibindings=matchbindingswith|[]->e|binding::t->letname=(* __ppx_lwt_$i, at the position of $x$ *)evar~loc:binding.pvb_expr.pexp_loc(gen_namei)inletfun_=letloc=e_locin[%expr(fun[%pbinding.pvb_pat]->[%eaux(i+1)t])]inletnew_exp=letloc=e_locin[%exprletmoduleReraise=structexternalreraise:exn->'a="%reraise"endinLwt.backtrace_bind(funexn->tryReraise.reraiseexnwithexn->exn)[%ename][%efun_]]in{new_expwithpexp_attributes=binding.pvb_attributes}inaux0lletlwt_sequencemapper~exp~lhs~rhs~ext_loc=letpat=letloc=ext_locin[%pat?()]inletlhs,rhs=mapper#expressionlhs,mapper#expressionrhsinletloc=exp.pexp_locin[%exprletmoduleReraise=structexternalreraise:exn->'a="%reraise"endinLwt.backtrace_bind(funexn->tryReraise.reraiseexnwithexn->exn)[%elhs](fun[%ppat]->[%erhs])](** For expressions only *)(* We only expand the first level after a %lwt.
After that, we call the mapper to expand sub-expressions. *)letlwt_expressionmapperexpattributesext_loc=default_loc:=exp.pexp_loc;letpexp_attributes=attributes@exp.pexp_attributesinmatchexp.pexp_descwith(* $e$;%lwt $e'$ ≡ [Lwt.bind $e$ (fun $p$ -> $e'$)] *)|Pexp_sequence(lhs,rhs)->Some(lwt_sequencemapper~exp~lhs~rhs~ext_loc)(* [let%lwt $p$ = $e$ in $e'$] ≡ [Lwt.bind $e$ (fun $p$ -> $e'$)] *)|Pexp_let(Nonrecursive,vbl,e)->letnew_exp=pexp_let~loc:!default_locNonrecursive(gen_bindingsvbl)(gen_bindsexp.pexp_locvble)inSome(mapper#expression{new_expwithpexp_attributes})(* [match%lwt $e$ with $c$] ≡ [Lwt.bind $e$ (function $c$)]
[match%lwt $e$ with exception $x$ | $c$] ≡
[Lwt.try_bind (fun () -> $e$) (function $c$) (function $x$)] *)|Pexp_match(e,cases)->letexns,cases=cases|>List.partition(function|{pc_lhs=[%pat?exception[%p?_]];_}->true|_->false)inifcases=[]thenLocation.raise_errorf~loc:exp.pexp_loc"match%%lwt must contain at least one non-exception pattern.";letexns=exns|>List.map(function|{pc_lhs=[%pat?exception[%p?pat]];_}ascase->{casewithpc_lhs=pat}|_->assertfalse)inletexns=add_wildcard_caseexnsinletnew_exp=matchexnswith|[]->letloc=!default_locin[%exprLwt.bind[%ee][%epexp_function~loccases]]|_->letloc=!default_locin[%exprLwt.try_bind(fun()->[%ee])[%epexp_function~loccases][%epexp_function~locexns]]inSome(mapper#expression{new_expwithpexp_attributes})(* [assert%lwt $e$] ≡
[try Lwt.return (assert $e$) with exn -> Lwt.fail exn] *)|Pexp_asserte->letnew_exp=letloc=!default_locin[%exprtryLwt.return(assert[%ee])withexn->Lwt.failexn]inSome(mapper#expression{new_expwithpexp_attributes})(* [while%lwt $cond$ do $body$ done] ≡
[let rec __ppx_lwt_loop () =
if $cond$ then Lwt.bind $body$ __ppx_lwt_loop
else Lwt.return_unit
in __ppx_lwt_loop]
*)|Pexp_while(cond,body)->letnew_exp=letloc=!default_locin[%exprletrec__ppx_lwt_loop()=if[%econd]thenLwt.bind[%ebody]__ppx_lwt_loopelseLwt.return_unitin__ppx_lwt_loop()]inSome(mapper#expression{new_expwithpexp_attributes})(* [for%lwt $p$ = $start$ (to|downto) $end$ do $body$ done] ≡
[let __ppx_lwt_bound = $end$ in
let rec __ppx_lwt_loop $p$ =
if $p$ COMP __ppx_lwt_bound then Lwt.return_unit
else Lwt.bind $body$ (fun () -> __ppx_lwt_loop ($p$ OP 1))
in __ppx_lwt_loop $start$]
*)|Pexp_for({ppat_desc=Ppat_varp_var;_}asp,start,bound,dir,body)->letcomp,op=letloc=!default_locinmatchdirwith|Upto->evar~loc">",evar~loc"+"|Downto->evar~loc"<",evar~loc"-"inletp'=with_locevarp_varinletexp_bound=letloc=bound.pexp_locin[%expr__ppx_lwt_bound]inletpat_bound=letloc=bound.pexp_locin[%pat?__ppx_lwt_bound]inletnew_exp=letloc=!default_locin[%exprlet[%ppat_bound]:int=[%ebound]inletrec__ppx_lwt_loop[%pp]=if[%ecomp][%ep'][%eexp_bound]thenLwt.return_unitelseLwt.bind[%ebody](fun()->__ppx_lwt_loop([%eop][%ep']1))in__ppx_lwt_loop[%estart]]inSome(mapper#expression{new_expwithpexp_attributes})(* [try%lwt $e$ with $c$] ≡
[Lwt.catch (fun () -> $e$) (function $c$)]
*)|Pexp_try(expr,cases)->letcases=add_wildcard_casecasesinletnew_exp=letloc=!default_locin[%exprletmoduleReraise=structexternalreraise:exn->'a="%reraise"endinLwt.backtrace_catch(funexn->tryReraise.reraiseexnwithexn->exn)(fun()->[%eexpr])[%epexp_function~loccases]]inSome(mapper#expression{new_expwithpexp_attributes})(* [if%lwt $c$ then $e1$ else $e2$] ≡
[match%lwt $c$ with true -> $e1$ | false -> $e2$]
[if%lwt $c$ then $e1$] ≡
[match%lwt $c$ with true -> $e1$ | false -> Lwt.return_unit]
*)|Pexp_ifthenelse(cond,e1,e2)->lete2=matche2with|None->letloc=!default_locin[%exprLwt.return_unit]|Somee->einletcases=letloc=!default_locin[case~lhs:[%pat?true]~guard:None~rhs:e1;case~lhs:[%pat?false]~guard:None~rhs:e2;]inletnew_exp=letloc=!default_locin[%exprLwt.bind[%econd][%epexp_function~loccases]]inSome(mapper#expression{new_expwithpexp_attributes})|_->Noneletwarned=reffalseclassmapper=object(self)inheritAst_traverse.mapassupermethod!structure=beginfunstructure->if!warnedthensuper#structurestructureelsebeginwarned:=true;letstructure=super#structurestructureinletloc=Location.in_file!Ocaml_common.Location.input_nameinletwarn_ifconditionmessagestructure=ifconditionthen(pstr_attribute~loc(attribute_of_warninglocmessage))::structureelsestructureinstructure|>warn_if(!used_no_strict_sequence_option)("-no-strict-sequence is a deprecated Lwt PPX option\n"^" See https://github.com/ocsigen/lwt/issues/495")|>warn_if(!used_no_sequence_option)("-no-sequence is a deprecated Lwt PPX option\n"^" See https://github.com/ocsigen/lwt/issues/495")endendmethod!expression=(funexpr->matchexprwith|{pexp_desc=Pexp_extension({txt="lwt";loc=ext_loc},PStr[{pstr_desc=Pstr_eval(exp,_);_}]);_}->beginmatchlwt_expressionselfexpexpr.pexp_attributesext_locwith|Someexpr'->expr'|None->exprend(* [($e$)[%finally $f$]] ≡
[Lwt.finalize (fun () -> $e$) (fun () -> $f$)] *)|[%expr[%e?exp][%finally[%e?finally]]]|[%expr[%e?exp][%lwt.finally[%e?finally]]]->letnew_exp=letloc=!default_locin[%exprletmoduleReraise=structexternalreraise:exn->'a="%reraise"endinLwt.backtrace_finalize(funexn->tryReraise.reraiseexnwithexn->exn)(fun()->[%eexp])(fun()->[%efinally])]insuper#expression{new_expwithpexp_attributes=expr.pexp_attributes@exp.pexp_attributes}|[%expr[%finally[%e?_]]]|[%expr[%lwt.finally[%e?_]]]->Location.raise_errorf~loc:expr.pexp_loc"Lwt's finally should be used only with the syntax: \"(<expr>)[%%finally ...]\"."|_->super#expressionexpr)method!structure_item=(funstri->default_loc:=stri.pstr_loc;matchstriwith|[%strilet%lwt[%p?var]=[%e?exp]]->letwarning=estring~loc:!default_loc("let%lwt should not be used at the module item level.\n"^"Replace let%lwt x = e by let x = Lwt_main.run (e)")inletloc=!default_locin[%strilet[%pvar]=(Lwt_main.run[@ocaml.ppwarning[%ewarning]])[%esuper#expressionexp]]|x->super#structure_itemx);endletargs=["-no-sequence",Arg.Unitno_sequence_option," has no effect (deprecated)";"-no-strict-sequence",Arg.Unitno_strict_sequence_option," has no effect (deprecated)";]let()=letmapper=newmapperinDriver.register_transformation"ppx_lwt"~impl:mapper#structure~intf:mapper#signature;List.iter(fun(key,spec,doc)->Driver.add_argkeyspec~doc)args