123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198openBaseopenPpxlibopenAst_builder.Defaultletomit_nil=Attribute.declare"sexp_value.sexp.omit_nil"Attribute.Context.core_typeAst_pattern.(pstrnil)()letoption=Attribute.declare"sexp_value.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]]letreclist_and_tail_of_ast_listrev_ele=matche.pexp_descwith|Pexp_construct({txt=Lident"::";_},Some{pexp_desc=Pexp_tuple[hd;tl];_})->list_and_tail_of_ast_list(hd::rev_el)tl|Pexp_construct({txt=Lident"[]";_},None)->List.revrev_el,None|_->List.revrev_el,Somee;;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";;typeomittable_sexp=|Presentofexpression|Optionalof(Location.t*string)*expression*(expression->expression)(* In [Optional (_, e, k)], [e] is an ast whose values have type ['a option], and [k] is
a function from ast of type ['a] to ast of type [Sexp.t]. The None case should not be
displayed, and the [a] in the Some case should be displayed by calling [k] on it. *)|Omit_nilofLocation.t*expression*(expression->expression)(* In [Omit_nil (_, e, k)], [e] is an ast of type [Sexp.t], and [k] if a function
ast of type [Sexp.t] and returns an other [Sexp.t].
When [e] is [List []], it should be not displayed. Otherwise [e] should be
displayed by calling [k] on it. *)letwrap_sexp_if_presentomittable_sexp~f=matchomittable_sexpwith|Optional(loc,e,k)->Optional(loc,e,(fune->f(ke)))|Presente->Present(fe)|Omit_nil(loc,e,k)->Omit_nil(loc,e,(fune->f(ke)))letsexp_of_constraint~locexprctyp=matchctypwith|[%type:[%t?ty]sexp_option]->letsexp_of=Ppx_sexp_conv_expander.Sexp_of.core_typetyinOptional((loc,"sexp_option"),expr,funexpr->eapply~locsexp_of[expr])|[%type:[%t?ty]option]whenOption.is_some(Attribute.getoptionctyp)->letsexp_of=Ppx_sexp_conv_expander.Sexp_of.core_typetyinOptional((loc,"[@sexp.optional]"),expr,funexpr->eapply~locsexp_of[expr])|_->letexpr=letsexp_of=Ppx_sexp_conv_expander.Sexp_of.core_typectypineapply~locsexp_of[expr]inmatchAttribute.getomit_nilctypwith|Some()->Omit_nil(loc,expr,Fn.id)|None->Presentexpr;;letrecsexp_of_exprexpr=matchomittable_sexp_of_exprexprwith|Presentv->v|Optional((loc,s),_,_)->Location.raise_errorf~loc"ppx_sexp_value: cannot handle %s in this context"s|Omit_nil(loc,_,_)->Location.raise_errorf~loc"ppx_sexp_value: cannot handle [@omit_nil] in this context"andomittable_sexp_of_exprexpr=letloc=expr.pexp_locinwrap_sexp_if_present~f:(funnew_expr->{new_exprwithpexp_attributes=expr.pexp_attributes})(matchexpr.pexp_descwith|Pexp_ifthenelse(e1,e2,e3)->Present{exprwithpexp_desc=Pexp_ifthenelse(e1,sexp_of_expre2,matche3with|None->None|Somee->Some(sexp_of_expre))}|Pexp_constraint(expr,ctyp)->sexp_of_constraint~locexprctyp|Pexp_construct({txt=Lident"[]";_},None)|Pexp_construct({txt=Lident"::";_},Some{pexp_desc=Pexp_tuple[_;_];_})->letel,tl=list_and_tail_of_ast_list[]exprinletel=List.mapel~f:omittable_sexp_of_exprinlettl=matchtlwith|None->[%expr[]]|Somee->[%exprmatch[%esexp_of_expre]with|Ppx_sexp_conv_lib.Sexp.Listl->l|Ppx_sexp_conv_lib.Sexp.Atom_assexp->[sexp]]inPresent(sexp_of_omittable_sexp_listlocel~tl)|Pexp_constantconst->Present(sexp_of_constant~locconst)|Pexp_extension({txt="here";_},PStr[])->Present(sexp_atom~loc(Ppx_here_expander.lift_position_as_string~loc))|Pexp_construct({txt=Lident"()";_},None)->Present(sexp_list~loc(elist~loc[]))|Pexp_construct({txt=Lidentconstr;_},None)|Pexp_variant(constr,None)->Present(sexp_atom~loc(estring~locconstr))|Pexp_construct({txt=Lidentconstr;_},Somearg)|Pexp_variant(constr,Somearg)->letkhole=sexp_list~loc(elist~loc[sexp_atom~loc(estring~locconstr);hole])inwrap_sexp_if_present(omittable_sexp_of_exprarg)~f:k|Pexp_tupleel->letel=List.mapel~f:omittable_sexp_of_exprinPresent(sexp_of_omittable_sexp_listlocel~tl:(elist~loc[]))|Pexp_record(fields,None)->Present(sexp_of_record~locfields)|Pexp_apply({pexp_desc=Pexp_ident{txt=Lident"~~";_};_},[(Nolabel,{pexp_desc=Pexp_constraint(expr,ctyp);_})])->letexpr_str=Pprintast.string_of_expressionexprinletkhole=sexp_list~loc(elist~loc[sexp_atom~loc(estring~locexpr_str);hole])inwrap_sexp_if_present(sexp_of_constraint~locexprctyp)~f:k|_->Location.raise_errorf~loc"ppx_sexp_value: don't know how to handle this construct")andsexp_of_omittable_sexp_listlocel~tl=letl=List.fold_left(List.revel)~init:tl~f:(funacce->matchewith|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])insexp_list~loclandsexp_of_record~locfields=sexp_of_omittable_sexp_listloc~tl:(elist~loc[])(List.mapfields~f:(fun(id,e)->letloc={id.locwithloc_end=e.pexp_loc.loc_end}inletname=String.concat~sep:"."(Longident.flatten_exnid.txt)inletkhole=sexp_list~loc(elist~loc[sexp_atom~loc(estring~loc:id.locname);hole])inwrap_sexp_if_present(omittable_sexp_of_expre)~f:k));;let()=Driver.register_transformation"sexp_value"~extensions:[Extension.declare"sexp"Extension.Context.expressionAst_pattern.(pstr(pstr_eval__nil^::nil))(fun~loc:_~path:_e->sexp_of_expre)];;