Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_sexp_message_expander.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183openBaseopenPpxlibopenAst_builder.Defaultletomit_nil_attr=Attribute.declare"sexp_message.sexp.omit_nil"Attribute.Context.core_typeAst_pattern.(pstrnil)();;letoption_attr=Attribute.declare"sexp_message.sexp.option"Attribute.Context.core_typeAst_pattern.(pstrnil)();;letsexp_atom~locx=[%exprPpx_sexp_conv_lib.Sexp.Atom[%ex]]letsexp_list~locx=[%exprPpx_sexp_conv_lib.Sexp.List[%ex]]letsexp_inline~locl=matchlwith|[x]->x|_->sexp_list~loc(elist~locl);;(* Same as Ppx_sexp_value.omittable_sexp *)typeomittable_sexp=|Presentofexpression|OptionalofLocation.t*expression*(expression->expression)|Omit_nilofLocation.t*expression*(expression->expression)|Absentletpresent_or_omit_nil~loc~omit_nilexpr=ifomit_nilthenOmit_nil(loc,expr,Fn.id)elsePresentexpr;;letwrap_sexp_if_presentomittable_sexp~f=matchomittable_sexpwith|Presente->Present(fe)|Optional(loc,e,k)->Optional(loc,e,fune->f(ke))|Omit_nil(loc,e,k)->Omit_nil(loc,e,fune->f(ke))|Absent->Absent;;letsexp_of_constraint~omit_nil~locexprctyp=letoptionalty=letsexp_of=Ppx_sexp_conv_expander.Sexp_of.core_typetyinOptional(loc,expr,funexpr->eapply~locsexp_of[expr])inmatchctypwith|[%type:[%t?ty]sexp_option]->optionalty|[%type:[%t?ty]option]whenOption.is_some(Attribute.getoption_attrctyp)->optionalty|[%type:[%t?ty]option]whenomit_nil->optionalty|_->letexpr=letsexp_of=Ppx_sexp_conv_expander.Sexp_of.core_typectypineapply~locsexp_of[expr]inletomit_nil_attr=lazy((* this is lazy so using [@omit_nil] inside [%message.omit_nil] is an error (unused
attribute) *)matchAttribute.getomit_nil_attrctypwith|Some()->true|None->false)inpresent_or_omit_nil~locexpr~omit_nil:(omit_nil||Lazy.forceomit_nil_attr);;letsexp_of_constant~locconst=letftyp=eapply~loc(evar~loc("Ppx_sexp_conv_lib.Conv.sexp_of_"^typ))[pexp_constant~locconst]inmatchconstwith|Pconst_integer_->f"int"|Pconst_char_->f"char"|Pconst_string_->f"string"|Pconst_float_->f"float";;letrewrite_heree=matche.pexp_descwith|Pexp_extension({txt="here";_},PStr[])->Ppx_here_expander.lift_position_as_string~loc:e.pexp_loc|_->e;;letsexp_of_expr~omit_nile=lete=rewrite_hereeinletloc={e.pexp_locwithloc_ghost=true}inmatche.pexp_descwith|Pexp_constant(Pconst_string("",_,_))->Absent|Pexp_constantconst->present_or_omit_nil~loc~omit_nil:false(sexp_of_constant~locconst)|Pexp_constraint(expr,ctyp)->sexp_of_constraint~omit_nil~locexprctyp|_->present_or_omit_nil~loc~omit_nil:false[%exprPpx_sexp_conv_lib.Conv.sexp_of_string[%ee]];;letsexp_of_labelled_expr~omit_nil(label,e)=letloc={e.pexp_locwithloc_ghost=true}inmatchlabel,e.pexp_descwith|Nolabel,Pexp_constraint(expr,_)->letexpr_str=Pprintast.string_of_expressionexprinletke=sexp_inline~loc[sexp_atom~loc(estring~locexpr_str);e]inwrap_sexp_if_present(sexp_of_expr~omit_nile)~f:k|Nolabel,_->sexp_of_expr~omit_nile|Labelled"_",_->sexp_of_expr~omit_nile|Labelledlabel,_->letke=sexp_inline~loc[sexp_atom~loc(estring~loclabel);e]inwrap_sexp_if_present(sexp_of_expr~omit_nile)~f:k|Optional_,_->(* Could be used to encode sexp_option if that's ever needed. *)Location.raise_errorf~loc"ppx_sexp_value: optional argument not allowed here";;letsexp_of_labelled_exprs~omit_nil~loclabels_and_exprs=letloc={locwithloc_ghost=true}inletl=List.maplabels_and_exprs~f:(sexp_of_labelled_expr~omit_nil)inletres=List.fold_left(List.revl)~init:(elist~loc[])~f:(funacce->matchewith|Absent->acc|Presente->[%expr[%ee]::[%eacc]]|Optional(_,v_opt,k)->(* We match simultaneously on the head and tail in the generated code to avoid
changing their respective typing environments. *)[%exprmatch[%ev_opt],[%eacc]with|None,tl->tl|Somev,tl->[%ek[%exprv]]::tl]|Omit_nil(_,e,k)->[%exprmatch[%ee],[%eacc]with|Ppx_sexp_conv_lib.Sexp.List[],tl->tl|v,tl->[%ek[%exprv]]::tl])inlethas_optional_values=List.existsl~f:(function|(Optional_|Omit_nil_:omittable_sexp)->true|Present_|Absent->false)in(* The two branches do the same thing, but when there are no optional values, we can do
it at compile-time, which avoids making the generated code ugly. *)ifhas_optional_valuesthen[%exprmatch[%eres]with|[h]->h|([]|_::_::_)asres->[%esexp_list~loc[%exprres]]]else(matchreswith|[%expr[[%e?h]]]->h|_->sexp_list~locres);;letexpand~omit_nil~path:_e=letloc=e.pexp_locinletlabelled_exprs=matche.pexp_descwith|Pexp_apply(f,args)->(Nolabel,f)::args|_->[Nolabel,e]insexp_of_labelled_exprs~omit_nil~loclabelled_exprs;;letexpand_opt~omit_nil~loc~path=function|None->letloc={locwithloc_ghost=true}insexp_list~loc(elist~loc[])|Somee->expand~omit_nil~pathe;;