123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317open!Baseopen!PpxlibopenAst_builder.DefaultopenHelpersopenLifted.Monad_infix(* Generates the signature for type conversion from S-expressions *)moduleSig_generate_of_sexp=structlettype_of_of_sexp~loct=letloc={locwithloc_ghost=true}in[%type:Sexplib0.Sexp.t->[%tt]];;letmk_typetd=combinator_type_of_type_declarationtd~f:type_of_of_sexpletsig_of_tdwith_polytd=letof_sexp_type=mk_typetdinletloc=td.ptype_locinletof_sexp_item=psig_value~loc(value_description~loc~name:(Located.map(funs->s^"_of_sexp")td.ptype_name)~type_:of_sexp_type~prim:[])inmatchwith_poly,is_polymorphic_varianttd~sig_:truewith|true,`Surely_not->Location.raise_errorf~loc"Sig_generate_of_sexp.sig_of_td: sexp_poly annotation but type is surely not a \
polymorphic variant"|false,(`Surely_not|`Maybe)->[of_sexp_item]|(true|false),`Definitely|true,`Maybe->[of_sexp_item;psig_value~loc(value_description~loc~name:(Located.map(funs->"__"^s^"_of_sexp__")td.ptype_name)~type_:of_sexp_type~prim:[])];;letmk_sig~poly~loc:_~path:_(_rf,tds)=List.concat_maptds~f:(sig_of_tdpoly)endmoduleStr_generate_of_sexp=structmodulePtag_error_function=structtypet=|Ptag_no_args|Ptag_takes_argsendmoduleRow_or_constructor=structtypet=|Rowofrow_field|Constructorofconstructor_declarationendletwith_error_source~loc~full_type_namemake_body=letlifted=letname=lazy(Fresh_name.create"error_source"~loc)inmake_body~error_source:(fun()->Fresh_name.expression(forcename))>>|funbody->matchLazy.is_valnamewith|false->(* no references to [name], no need to define it *)body|true->(* add a definition for [name] *)[%exprlet[%pFresh_name.pattern(forcename)]=[%eestring~locfull_type_name]in[%ebody]]inLifted.let_bind_user_expressionslifted~loc;;(* Utility functions for polymorphic variants *)(* Handle backtracking when variants do not match *)lethandle_no_variant_matchlocexpr=[[%pat?Sexplib0.Sexp_conv_error.No_variant_match]-->expr];;(* Generate code depending on whether to generate a match for the last
case of matching a variant *)lethandle_variant_match_lastloc~match_last~fresh_atommatches=matchmatch_last,matcheswith|true,[{pc_lhs=_;pc_guard=None;pc_rhs=expr}]|_,[{pc_lhs=[%pat?_];pc_guard=None;pc_rhs=expr}]->expr|_->pexp_match~loc(Fresh_name.expressionfresh_atom)matches;;(* Generate code for matching malformed S-expressions *)letmk_variant_other_matches~error_source~fresh__sexplocrev_elscall=letcoll_structsacc(loc,cnstr)=(pstring~loccnstr-->match(call:Ptag_error_function.t)with|Ptag_no_args->[%exprSexplib0.Sexp_conv_error.ptag_no_args[%eerror_source()][%eFresh_name.expressionfresh__sexp]]|Ptag_takes_args->[%exprSexplib0.Sexp_conv_error.ptag_takes_args[%eerror_source()][%eFresh_name.expressionfresh__sexp]])::accinletexc_no_variant_match=[%pat?_]-->[%exprSexplib0.Sexp_conv_error.no_variant_match()]inList.fold_left~f:coll_structs~init:[exc_no_variant_match]rev_els;;(* Split the row fields of a variant type into lists of atomic variants,
structured variants, atomic variants + included variant types,
and structured variants + included variant types. *)letsplit_row_field~loc(atoms,structs,ainhs,sinhs)row_field=matchrow_field.prf_descwith|Rtag({txt=cnstr;_},true,[])->lettpl=loc,cnstrintpl::atoms,structs,`Atpl::ainhs,sinhs|Rtag({txt=cnstr;_},false,[tp])->letloc=tp.ptyp_locinatoms,(loc,cnstr)::structs,ainhs,`S(loc,cnstr,tp,row_field)::sinhs|Rinheritinh->letiinh=`Iinhinatoms,structs,iinh::ainhs,iinh::sinhs|Rtag(_,true,[_])|Rtag(_,_,_::_::_)->Location.raise_errorf~loc"split_row_field/&"|Rtag(_,false,[])->assertfalse;;lettype_constr_of_sexp?(internal=false)idargs=type_constr_convidargs~f:(funs->lets=s^"_of_sexp"inifinternalthen"__"^s^"__"elses);;(* Conversion of types *)letrectype_of_sexp~error_source~typevars?full_type?(internal=false)typ:Conversion.t=letloc=typ.ptyp_locinmatchtypwith|_whenOption.is_some(Attribute.getAttrs.opaquetyp)->Conversion.of_reference_exn[%exprSexplib0.Sexp_conv.opaque_of_sexp]|[%type:[%t?_]sexp_opaque]|[%type:_]->Conversion.of_reference_exn[%exprSexplib0.Sexp_conv.opaque_of_sexp]|[%type:[%t?ty1]sexp_list]->letarg1=Conversion.to_expression~loc(type_of_sexp~error_source~typevarsty1)inConversion.of_reference_exn[%exprSexplib0.Sexp_conv.list_of_sexp[%earg1]]|[%type:[%t?ty1]sexp_array]->letarg1=Conversion.to_expression~loc(type_of_sexp~error_source~typevarsty1)inConversion.of_reference_exn[%exprSexplib0.Sexp_conv.array_of_sexp[%earg1]]|{ptyp_desc=Ptyp_tupletp;_}->Conversion.of_lambda(tuple_of_sexp~error_source~typevars(loc,tp))|{ptyp_desc=Ptyp_varparm;_}->(matchMap.findtypevarsparmwith|Somefresh->Conversion.of_reference_exn(Fresh_name.expressionfresh)|None->Location.raise_errorf~loc"ppx_sexp_conv: unbound type variable '%s"parm)|{ptyp_desc=Ptyp_constr(id,args);_}->letargs=List.mapargs~f:(funarg->Conversion.to_expression~loc(type_of_sexp~error_source~typevarsarg))inConversion.of_reference_exn(type_constr_of_sexp~loc~internalidargs)|{ptyp_desc=Ptyp_arrow(_,_,_);_}->Conversion.of_reference_exn[%exprSexplib0.Sexp_conv.fun_of_sexp]|{ptyp_desc=Ptyp_variant(row_fields,Closed,_);_}->variant_of_sexp~error_source~typevars?full_type(loc,row_fields)|{ptyp_desc=Ptyp_poly(parms,poly_tp);_}->poly_of_sexp~error_source~typevarsparmspoly_tp|{ptyp_desc=Ptyp_variant(_,Open,_);_}|{ptyp_desc=Ptyp_object(_,_);_}|{ptyp_desc=Ptyp_class(_,_);_}|{ptyp_desc=Ptyp_alias(_,_);_}|{ptyp_desc=Ptyp_package_;_}|{ptyp_desc=Ptyp_extension_;_}->Location.raise_errorf~loc"Type unsupported for ppx [of_sexp] conversion"(* Conversion of tuples *)andtuple_of_sexp~error_source~typevars(loc,tps)=letfps=List.map~f:(type_of_sexp~error_source~typevars)tpsinlet({bindings;arguments;converted}:Conversion.Apply_all.t)=Conversion.apply_all~locfpsinletn=List.lengthfpsinletfresh_sexp=Fresh_name.create"sexp"~locin[[%pat?Sexplib0.Sexp.List[%pplist~locarguments]]-->pexp_let~locNonrecursivebindings(pexp_tuple~locconverted);Fresh_name.patternfresh_sexp-->[%exprSexplib0.Sexp_conv_error.tuple_of_size_n_expected[%eerror_source()][%eeint~locn][%eFresh_name.expressionfresh_sexp]]](* Generate code for matching included variant types *)andhandle_variant_inh~error_source~typevars~fresh_atom~fresh__sexpfull_type~match_lastother_matchesinh=letloc=inh.ptyp_locinletfunc_expr=type_of_sexp~error_source~typevars~internal:trueinhinletapp=Conversion.of_reference_exn(Conversion.apply~locfunc_expr(Fresh_name.expressionfresh__sexp))inletmatch_exc=handle_no_variant_matchloc(handle_variant_match_lastloc~match_last~fresh_atomother_matches)inletnew_other_matches=[[%pat?_]-->pexp_try~loc[%expr([%eConversion.to_expression~locapp]:>[%treplace_variables_by_underscoresfull_type])]match_exc]innew_other_matches,true(* Generate code for matching atomic variants *)andmk_variant_match_atom~error_source~typevars~fresh_atom~fresh__sexplocfull_typerev_atoms_inhsrev_structs=letcoll(other_matches,match_last)=function|`A(loc,cnstr)->letnew_match=pstring~loccnstr-->pexp_variant~loccnstrNoneinnew_match::other_matches,false|`Iinh->handle_variant_inh~error_source~typevars~fresh_atom~fresh__sexpfull_type~match_lastother_matchesinhinletother_matches=mk_variant_other_matches~error_source~fresh__sexplocrev_structsPtag_takes_argsinletmatch_atoms_inhs,match_last=List.fold_left~f:coll~init:(other_matches,false)rev_atoms_inhsinhandle_variant_match_lastloc~match_last~fresh_atommatch_atoms_inhs(* Variant conversions *)(* Match arguments of constructors (variants or sum types) *)andmk_cnstr_args_match~error_source~typevars~loc~is_variant~fresh__sexp~fresh__tag~fresh_sexp_argscnstrtpsrow=letcnstrvars_expr=ifis_variantthenpexp_variant~loccnstr(Somevars_expr)elsepexp_construct~loc(Located.lident~loccnstr)(Somevars_expr)inmatchtpswith|[tp]whenOption.is_some(match(row:Row_or_constructor.t)with|Rowr->Attribute.getAttrs.list_polyr|Constructorc->Attribute.getAttrs.list_variantc)->(matchtpwith|[%type:[%t?tp]list]->letcnv=Conversion.to_expression~loc(type_of_sexp~error_source~typevarstp)incnstr[%exprSexplib0.Sexp_conv.list_map[%ecnv][%eFresh_name.expressionfresh_sexp_args]]|_->(matchrowwith|Row_->Attrs.invalid_attribute~locAttrs.list_poly"_ list"|Constructor_->Attrs.invalid_attribute~locAttrs.list_variant"_ list"))|[[%type:[%t?tp]sexp_list]]->letcnv=Conversion.to_expression~loc(type_of_sexp~error_source~typevarstp)incnstr[%exprSexplib0.Sexp_conv.list_map[%ecnv][%eFresh_name.expressionfresh_sexp_args]]|_->letbindings,patts,good_arg_match=letfps=List.map~f:(type_of_sexp~error_source~typevars)tpsinlet({bindings;arguments;converted}:Conversion.Apply_all.t)=Conversion.apply_all~locfpsinletgood_arg_match=cnstr(pexp_tuple~locconverted)inbindings,arguments,good_arg_matchin[%exprmatch[%eFresh_name.expressionfresh_sexp_args]with|[%pplist~locpatts]->[%epexp_let~locNonrecursivebindingsgood_arg_match]|_->[%eifis_variantthen[%exprSexplib0.Sexp_conv_error.ptag_incorrect_n_args[%eerror_source()][%eFresh_name.expressionfresh__tag][%eFresh_name.expressionfresh__sexp]]else[%exprSexplib0.Sexp_conv_error.stag_incorrect_n_args[%eerror_source()][%eFresh_name.expressionfresh__tag][%eFresh_name.expressionfresh__sexp]]]](* Generate code for matching structured variants *)andmk_variant_match_struct~error_source~typevars~fresh_atom~fresh__sexp~fresh_sexp_argslocfull_typerev_structs_inhsrev_atoms=lethas_structs_ref=reffalseinletcoll(other_matches,match_last)=function|`S(loc,cnstr,tp,row)->has_structs_ref:=true;letfresh__tag=Fresh_name.create"_tag"~locinletexpr=mk_cnstr_args_match~error_source~typevars~loc:tp.ptyp_loc~is_variant:true~fresh__sexp~fresh__tag~fresh_sexp_argscnstr[tp](Rowrow)inletnew_match=ppat_alias~loc[%pat?[%ppstring~loccnstr]](Fresh_name.to_string_locfresh__tag)-->exprinnew_match::other_matches,false|`Iinh->handle_variant_inh~error_source~typevars~fresh_atom~fresh__sexpfull_type~match_lastother_matchesinhinletother_matches=mk_variant_other_matches~error_source~fresh__sexplocrev_atomsPtag_no_argsinletmatch_structs_inhs,match_last=List.fold_left~f:coll~init:(other_matches,false)rev_structs_inhsin(handle_variant_match_lastloc~match_last~fresh_atommatch_structs_inhs,!has_structs_ref)(* Generate code for handling atomic and structured variants (i.e. not
included variant types) *)andhandle_variant_tag~error_source~typevarslocfull_typerow_field_list=letfresh_atom=Fresh_name.create"atom"~locinletfresh_sexp=Fresh_name.create"sexp"~locinletfresh__sexp=Fresh_name.create"_sexp"~locinletfresh_sexp_args=Fresh_name.create"sexp_args"~locinletrev_atoms,rev_structs,rev_atoms_inhs,rev_structs_inhs=List.fold_left~f:(split_row_field~loc)~init:([],[],[],[])row_field_listinletmatch_struct,has_structs=mk_variant_match_struct~error_source~typevars~fresh_atom~fresh__sexp~fresh_sexp_argslocfull_typerev_structs_inhsrev_atomsinletmaybe_sexp_args_patt=ifhas_structsthenFresh_name.patternfresh_sexp_argselse[%pat?_]in[ppat_alias~loc[%pat?Sexplib0.Sexp.Atom[%pFresh_name.patternfresh_atom]](Fresh_name.to_string_locfresh__sexp)-->mk_variant_match_atom~error_source~typevars~fresh_atom~fresh__sexplocfull_typerev_atoms_inhsrev_structs;ppat_alias~loc[%pat?Sexplib0.Sexp.List(Sexplib0.Sexp.Atom[%pFresh_name.patternfresh_atom]::[%pmaybe_sexp_args_patt])](Fresh_name.to_string_locfresh__sexp)-->match_struct;ppat_alias~loc[%pat?Sexplib0.Sexp.List(Sexplib0.Sexp.List_::_)](Fresh_name.to_string_locfresh_sexp)-->[%exprSexplib0.Sexp_conv_error.nested_list_invalid_poly_var[%eerror_source()][%eFresh_name.expressionfresh_sexp]];ppat_alias~loc[%pat?Sexplib0.Sexp.List[]](Fresh_name.to_string_locfresh_sexp)-->[%exprSexplib0.Sexp_conv_error.empty_list_invalid_poly_var[%eerror_source()][%eFresh_name.expressionfresh_sexp]]](* Generate matching code for variants *)andvariant_of_sexp~error_source~typevars?full_type(loc,row_fields)=letis_contained,full_type=matchfull_typewith|None->true,ptyp_variant~locrow_fieldsClosedNone|Somefull_type->false,full_typeinlettop_match=letfresh_sexp=Fresh_name.create~loc"sexp"inmatchrow_fieldswith|{prf_desc=Rinheritinh;_}::rest->letrecloopinhrow_fields=letcall=[%expr([%eConversion.to_expression~loc(type_of_sexp~error_source~typevars~internal:trueinh)][%eFresh_name.expressionfresh_sexp]:>[%treplace_variables_by_underscoresfull_type])]inmatchrow_fieldswith|[]->call|h::t->letexpr=matchh.prf_descwith|Rinheritinh->loopinht|_->letrftag_matches=handle_variant_tag~error_source~typevarslocfull_typerow_fieldsinpexp_match~loc(Fresh_name.expressionfresh_sexp)rftag_matchesinpexp_try~loccall(handle_no_variant_matchlocexpr)in[Fresh_name.patternfresh_sexp-->loopinhrest]|_::_->handle_variant_tag~error_source~typevarslocfull_typerow_fields|[]->Location.raise_errorf~loc"of_sexp is not supported for empty polymorphic variants (impossible?)"inifis_containedthen(letfresh_sexp=Fresh_name.create"sexp"~locinConversion.of_lambda[Fresh_name.patternfresh_sexp-->[%exprtry[%epexp_match~loc(Fresh_name.expressionfresh_sexp)top_match]with|Sexplib0.Sexp_conv_error.No_variant_match->Sexplib0.Sexp_conv_error.no_matching_variant_found[%eerror_source()][%eFresh_name.expressionfresh_sexp]]])elseConversion.of_lambdatop_matchandpoly_of_sexp~error_source~typevarsparmstp=letloc=tp.ptyp_locinlettypevars=List.foldparms~init:typevars~f:(funmapparm->Map.setmap~key:parm.txt~data:(Fresh_name.create("_of_"^parm.txt)~loc:parm.loc))inletbindings=letmk_bindingparm=letfresh=Map.find_exntypevarsparm.txtinletfresh_sexp=Fresh_name.create"sexp"~locinvalue_binding~loc~pat:(Fresh_name.patternfresh)~expr:[%exprfun[%pFresh_name.patternfresh_sexp]->Sexplib0.Sexp_conv_error.record_poly_field_value[%eerror_source()][%eFresh_name.expressionfresh_sexp]]inList.map~f:mk_bindingparmsinConversion.bind(type_of_sexp~error_source~typevarstp)bindings;;typefield={ld:label_declaration;field_name:Fresh_name.t;value_name:Fresh_name.t}letmake_fieldld=letfield_name=Fresh_name.of_string_locld.pld_nameinletvalue_name=Fresh_name.of_string_locld.pld_namein{ld;field_name;value_name};;(* Generate code for extracting record fields *)letmk_extract_fields~error_source~typevars~allow_extra_fields~fresh_duplicates~fresh_extra~fresh_field_name~fresh_sexp~fresh__field_sexp~fresh__field_sexps(loc,flds)=letrecloopinitscases=function|[]->inits,cases|fld::more_flds->letloc=fld.ld.pld_name.locinletnm=fld.ld.pld_name.txtin(matchRecord_field_attrs.Of_sexp.create~locfld.ld,fld.ld.pld_typewith|Sexp_bool,_->letinits=[%exprfalse]::initsinletcases=(pstring~locnm-->[%exprifStdlib.(!)[%eFresh_name.expressionfld.field_name]thenStdlib.(:=)[%eFresh_name.expressionfresh_duplicates]([%eFresh_name.expressionfresh_field_name]::Stdlib.(!)[%eFresh_name.expressionfresh_duplicates])else(match[%eFresh_name.expressionfresh__field_sexps]with|[]->Stdlib.(:=)[%eFresh_name.expressionfld.field_name]true|_::_->Sexplib0.Sexp_conv_error.record_sexp_bool_with_payload[%eerror_source()][%eFresh_name.expressionfresh_sexp])])::casesinloopinitscasesmore_flds|Sexp_optiontp,_|((SpecificRequired|Specific(Default_)|Omit_nil|Sexp_array_|Sexp_list_),tp)->letinits=[%exprStdlib.Option.None]::initsinletunrolled=Conversion.apply~loc(type_of_sexp~error_source~typevarstp)(Fresh_name.expressionfresh__field_sexp)inletfresh_fvalue=Fresh_name.create"fvalue"~locinletcases=(pstring~locnm-->[%exprmatchStdlib.(!)[%eFresh_name.expressionfld.field_name]with|Stdlib.Option.None->let[%pFresh_name.patternfresh__field_sexp]=[%eFresh_name.expressionfresh__field_sexp]()inlet[%pFresh_name.patternfresh_fvalue]=[%eunrolled]inStdlib.(:=)[%eFresh_name.expressionfld.field_name](Stdlib.Option.Some[%eFresh_name.expressionfresh_fvalue])|Stdlib.Option.Some_->Stdlib.(:=)[%eFresh_name.expressionfresh_duplicates]([%eFresh_name.expressionfresh_field_name]::Stdlib.(!)[%eFresh_name.expressionfresh_duplicates])])::casesinloopinitscasesmore_flds)inlethandle_extra=[([%pat?_]-->ifallow_extra_fieldsthen[%expr()]else[%exprifStdlib.(!)Sexplib0.Sexp_conv.record_check_extra_fieldsthenStdlib.(:=)[%eFresh_name.expressionfresh_extra]([%eFresh_name.expressionfresh_field_name]::Stdlib.(!)[%eFresh_name.expressionfresh_extra])else()])]inloop[]handle_extra(List.revflds);;(* Generate code for handling the result of matching record fields *)letmk_handle_record_match_result~error_source~typevars~fresh_sexphas_poly(loc,flds)~wrap_expr=lethas_nonopt_fields=reffalseinletres_tpls,bi_lst,good_patts=letrecloop((res_tpls,bi_lst,good_patts)asacc)=function|({ld={pld_name={txt=nm;loc};_};_}asfld)::more_flds->letfld_expr=[%exprStdlib.(!)[%eFresh_name.expressionfld.field_name]]inletmk_default()=bi_lst,Fresh_name.patternfld.value_name::good_pattsinletnew_bi_lst,new_good_patts=matchRecord_field_attrs.Of_sexp.create~locfld.ldwith|Specific(Default_)|Sexp_bool|Sexp_option_|Sexp_list_|Sexp_array_|Omit_nil->mk_default()|SpecificRequired->has_nonopt_fields:=true;([%exprSexplib0.Sexp_conv.(=)[%efld_expr]Stdlib.Option.None,[%eestring~locnm]]::bi_lst,[%pat?Stdlib.Option.Some[%pFresh_name.patternfld.value_name]]::good_patts)inletacc=fld_expr::res_tpls,new_bi_lst,new_good_pattsinloopaccmore_flds|[]->accinloop([],[],[])(List.revflds)inletcnvt_valuefld=matchRecord_field_attrs.Of_sexp.create~locfld.ldwith|Sexp_list_->letfresh_v=Fresh_name.create"v"~locin[%exprmatch[%eFresh_name.expressionfld.value_name]with|Stdlib.Option.None->[]|Stdlib.Option.Some[%pFresh_name.patternfresh_v]->[%eFresh_name.expressionfresh_v]]|>Lifted.return|Sexp_array_->letfresh_v=Fresh_name.create"v"~locin[%exprmatch[%eFresh_name.expressionfld.value_name]with|Stdlib.Option.None->[||]|Stdlib.Option.Some[%pFresh_name.patternfresh_v]->[%eFresh_name.expressionfresh_v]]|>Lifted.return|Specific(Defaultlifted_default)->lifted_default>>=fundefault->letfresh_v=Fresh_name.create"v"~locin[%exprmatch[%eFresh_name.expressionfld.value_name]with|Stdlib.Option.None->[%edefault]|Stdlib.Option.Some[%pFresh_name.patternfresh_v]->[%eFresh_name.expressionfresh_v]]|>Lifted.return|Sexp_bool|Sexp_option_|SpecificRequired->Fresh_name.expressionfld.value_name|>Lifted.return|Omit_nil->letfresh_e=Fresh_name.create"e"~locinletfresh_v=Fresh_name.create"v"~locin[%exprmatch[%eFresh_name.expressionfld.value_name]with|Stdlib.Option.Some[%pFresh_name.patternfresh_v]->[%eFresh_name.expressionfresh_v]|Stdlib.Option.None->(* We change the exception so it contains a sub-sexp of the
initial sexp, otherwise sexplib won't find the source location
for the error. *)(try[%eConversion.apply~loc(type_of_sexp~error_source~typevarsfld.ld.pld_type)[%exprSexplib0.Sexp.List[]]]with|Sexplib0.Sexp_conv_error.Of_sexp_error([%pFresh_name.patternfresh_e],_)->Stdlib.raise(Sexplib0.Sexp_conv_error.Of_sexp_error([%eFresh_name.expressionfresh_e],[%eFresh_name.expressionfresh_sexp])))]|>Lifted.returninletlifted_match_good_expr=ifhas_polythenList.map~f:cnvt_valueflds|>Lifted.all>>|pexp_tuple~locelse(letcnvtfld=cnvt_valuefld>>|funfield->Located.lident~locfld.ld.pld_name.txt,fieldinList.map~f:cnvtflds|>Lifted.all>>|funfields->wrap_expr(pexp_record~locfieldsNone))inletexpr=pexp_tuple~locres_tplsinletpatt=ppat_tuple~locgood_pattsinlifted_match_good_expr>>|funmatch_good_expr->if!has_nonopt_fieldsthenpexp_match~locexpr[patt-->match_good_expr;[%pat?_]-->[%exprSexplib0.Sexp_conv_error.record_undefined_elements[%eerror_source()][%eFresh_name.expressionfresh_sexp][%eelist~locbi_lst]]]elsepexp_match~locexpr[patt-->match_good_expr];;(* Generate code for converting record fields *)letmk_cnv_fields~error_source~typevars~allow_extra_fields~fresh_sexp~fresh_field_sexpshas_poly(loc,flds)~wrap_expr=letfresh_duplicates=Fresh_name.create~loc"duplicates"inletfresh_extra=Fresh_name.create~loc"extra"inletfresh_field_name=Fresh_name.create~loc"field_name"inletfresh__field_sexp=Fresh_name.create~loc"_field_sexp"inletfresh__field_sexps=Fresh_name.create~loc"_field_sexps"inletexpr_ref_inits,mc_fields=mk_extract_fields~error_source~typevars~allow_extra_fields~fresh_duplicates~fresh_extra~fresh_field_name~fresh_sexp~fresh__field_sexp~fresh__field_sexps(loc,flds)inletfield_refs=List.map2_exnfldsexpr_ref_inits~f:(funfldinit->value_binding~loc~pat:(Fresh_name.patternfld.field_name)~expr:[%exprStdlib.ref[%einit]])inmk_handle_record_match_result~error_source~typevars~fresh_sexphas_poly(loc,flds)~wrap_expr>>|funresult_expr->letfresh_iter=Fresh_name.create~loc"iter"inletfresh_tail=Fresh_name.create~loc"tail"inletfresh_x=Fresh_name.create~loc"x"inpexp_let~locNonrecursive(field_refs@[value_binding~loc~pat:(Fresh_name.patternfresh_duplicates)~expr:[%exprStdlib.ref[]];value_binding~loc~pat:(Fresh_name.patternfresh_extra)~expr:[%exprStdlib.ref[]]])[%exprletrec[%pFresh_name.patternfresh_iter]=[%epexp_function~loc[[%pat?Sexplib0.Sexp.List(Sexplib0.Sexp.Atom[%pFresh_name.patternfresh_field_name]::[%pppat_alias~loc[%pat?[]|[_]](Fresh_name.to_string_locfresh__field_sexps)])::[%pFresh_name.patternfresh_tail]]-->[%exprlet[%pFresh_name.patternfresh__field_sexp]=fun()->match[%eFresh_name.expressionfresh__field_sexps]with|[[%pFresh_name.patternfresh_x]]->[%eFresh_name.expressionfresh_x]|[]->Sexplib0.Sexp_conv_error.record_only_pairs_expected[%eerror_source()][%eFresh_name.expressionfresh_sexp]|_->assertfalsein[%epexp_match~loc(Fresh_name.expressionfresh_field_name)mc_fields];[%eFresh_name.expressionfresh_iter][%eFresh_name.expressionfresh_tail]];[%pat?[%pppat_alias~loc[%pat?Sexplib0.Sexp.Atom_|Sexplib0.Sexp.List_](Fresh_name.to_string_locfresh_sexp)]::_]-->[%exprSexplib0.Sexp_conv_error.record_only_pairs_expected[%eerror_source()][%eFresh_name.expressionfresh_sexp]];[%pat?[]]-->[%expr()]]]in[%eFresh_name.expressionfresh_iter][%eFresh_name.expressionfresh_field_sexps];matchStdlib.(!)[%eFresh_name.expressionfresh_duplicates]with|_::_->Sexplib0.Sexp_conv_error.record_duplicate_fields[%eerror_source()](Stdlib.(!)[%eFresh_name.expressionfresh_duplicates])[%eFresh_name.expressionfresh_sexp]|[]->(matchStdlib.(!)[%eFresh_name.expressionfresh_extra]with|_::_->Sexplib0.Sexp_conv_error.record_extra_fields[%eerror_source()](Stdlib.(!)[%eFresh_name.expressionfresh_extra])[%eFresh_name.expressionfresh_sexp]|[]->[%eresult_expr])];;letis_poly(_,flds)=List.existsflds~f:(function|{pld_type={ptyp_desc=Ptyp_poly_;_};_}->true|_->false);;letlabel_declaration_list_of_sexp~error_source~typevars~allow_extra_fields~fresh_sexp~fresh_field_sexpslocflds~wrap_expr=lethas_poly=is_poly(loc,flds)inletflds=List.mapflds~f:make_fieldinmk_cnv_fields~error_source~typevars~allow_extra_fields~fresh_sexp~fresh_field_sexpshas_poly(loc,flds)~wrap_expr>>|funcnv_fields->ifhas_polythen(letflds=List.mapflds~f:(funfld->fld.ld,Fresh_name.of_string_locfld.ld.pld_name)inletpatt=ppat_tuple~loc(List.mapflds~f:(fun(_,fresh)->Fresh_name.patternfresh))inletrecord_def=wrap_expr(pexp_record~loc(List.mapflds~f:(fun({pld_name={txt=name;loc};_},fresh)->Located.lident~locname,Fresh_name.expressionfresh))None)inpexp_let~locNonrecursive[value_binding~loc~pat:patt~expr:cnv_fields]record_def)elsecnv_fields;;(* Generate matching code for records *)letrecord_of_sexp~error_source~typevars~allow_extra_fields(loc,flds)=letfresh_sexp=Fresh_name.create"sexp"~locinletfresh_field_sexps=Fresh_name.create"field_sexps"~locinlabel_declaration_list_of_sexp~error_source~typevars~allow_extra_fields~fresh_sexp~fresh_field_sexpslocflds~wrap_expr:(funx->x)>>|funsuccess_expr->Conversion.of_lambda[ppat_alias~loc[%pat?Sexplib0.Sexp.List[%pFresh_name.patternfresh_field_sexps]](Fresh_name.to_string_locfresh_sexp)-->success_expr;ppat_alias~loc[%pat?Sexplib0.Sexp.Atom_](Fresh_name.to_string_locfresh_sexp)-->[%exprSexplib0.Sexp_conv_error.record_list_instead_atom[%eerror_source()][%eFresh_name.expressionfresh_sexp]]];;(* Sum type conversions *)(* Generate matching code for well-formed S-expressions wrt. sum types *)letmk_good_sum_matches~error_source~typevars(loc,cds)=List.mapcds~f:(funcd->matchcdwith|{pcd_name=cnstr;pcd_args=Pcstr_recordfields;_}->letlcstr=pstring~loc(String.uncapitalizecnstr.txt)inletstr=pstring~loccnstr.txtinletfresh_field_sexps=Fresh_name.create"field_sexps"~locinletfresh_sexp=Fresh_name.create"sexp"~locinletfresh__tag=Fresh_name.create"_tag"~locinlabel_declaration_list_of_sexp~error_source~typevars~allow_extra_fields:(Option.is_some(Attribute.getAttrs.allow_extra_fields_cdcd))~fresh_sexp~fresh_field_sexpslocfields~wrap_expr:(fune->pexp_construct~loc(Located.lident~loccnstr.txt)(Somee))>>|funexpr->ppat_alias~loc[%pat?Sexplib0.Sexp.List(Sexplib0.Sexp.Atom[%pppat_alias~loc[%pat?[%plcstr]|[%pstr]](Fresh_name.to_string_locfresh__tag)]::[%pFresh_name.patternfresh_field_sexps])](Fresh_name.to_string_locfresh_sexp)-->expr|{pcd_name=cnstr;pcd_args=Pcstr_tuple[];_}->Attrs.fail_if_allow_extra_field_cd~loccd;letlcstr=pstring~loc(String.uncapitalizecnstr.txt)inletstr=pstring~loccnstr.txtin[%pat?Sexplib0.Sexp.Atom([%plcstr]|[%pstr])]-->pexp_construct~loc(Located.lident~loccnstr.txt)None|>Lifted.return|{pcd_name=cnstr;pcd_args=Pcstr_tuple(_::_astps);_}->Attrs.fail_if_allow_extra_field_cd~loccd;letlcstr=pstring~loc(String.uncapitalizecnstr.txt)inletstr=pstring~loccnstr.txtinletfresh__sexp=Fresh_name.create"_sexp"~locinletfresh__tag=Fresh_name.create"_tag"~locinletfresh_sexp_args=Fresh_name.create"sexp_args"~locinppat_alias~loc[%pat?Sexplib0.Sexp.List(Sexplib0.Sexp.Atom[%pppat_alias~loc[%pat?[%plcstr]|[%pstr]](Fresh_name.to_string_locfresh__tag)]::[%pFresh_name.patternfresh_sexp_args])](Fresh_name.to_string_locfresh__sexp)-->mk_cnstr_args_match~error_source~typevars~loc~is_variant:false~fresh__sexp~fresh__tag~fresh_sexp_argscnstr.txttps(Constructorcd)|>Lifted.return);;(* Generate matching code for malformed S-expressions with good tags
wrt. sum types *)letmk_bad_sum_matches~error_source(loc,cds)=letfresh_sexp=Fresh_name.create"sexp"~locinList.mapcds~f:(function|{pcd_name=cnstr;pcd_args=Pcstr_tuple[];_}->letlcstr=pstring~loc(String.uncapitalizecnstr.txt)inletstr=pstring~loccnstr.txtinppat_alias~loc[%pat?Sexplib0.Sexp.List(Sexplib0.Sexp.Atom([%plcstr]|[%pstr])::_)](Fresh_name.to_string_locfresh_sexp)-->[%exprSexplib0.Sexp_conv_error.stag_no_args[%eerror_source()][%eFresh_name.expressionfresh_sexp]]|{pcd_name=cnstr;pcd_args=Pcstr_tuple(_::_)|Pcstr_record_;_}->letlcstr=pstring~loc(String.uncapitalizecnstr.txt)inletstr=pstring~loccnstr.txtinppat_alias~loc[%pat?Sexplib0.Sexp.Atom([%plcstr]|[%pstr])](Fresh_name.to_string_locfresh_sexp)-->[%exprSexplib0.Sexp_conv_error.stag_takes_args[%eerror_source()][%eFresh_name.expressionfresh_sexp]]);;(* Generate matching code for sum types *)letsum_of_sexp~error_source~typevars(loc,alts)=letfresh_sexp=Fresh_name.create"sexp"~locin[mk_good_sum_matches~error_source~typevars(loc,alts)|>Lifted.all;mk_bad_sum_matches~error_source(loc,alts)|>Lifted.return;[ppat_alias~loc[%pat?Sexplib0.Sexp.List(Sexplib0.Sexp.List_::_)](Fresh_name.to_string_locfresh_sexp)-->[%exprSexplib0.Sexp_conv_error.nested_list_invalid_sum[%eerror_source()][%eFresh_name.expressionfresh_sexp]];ppat_alias~loc[%pat?Sexplib0.Sexp.List[]](Fresh_name.to_string_locfresh_sexp)-->[%exprSexplib0.Sexp_conv_error.empty_list_invalid_sum[%eerror_source()][%eFresh_name.expressionfresh_sexp]];Fresh_name.patternfresh_sexp-->[%exprSexplib0.Sexp_conv_error.unexpected_stag[%eerror_source()][%eFresh_name.expressionfresh_sexp]]]|>Lifted.return]|>Lifted.all>>|List.concat>>|Conversion.of_lambda;;(* Empty type *)letnil_of_sexp~error_sourceloc:Conversion.t=Conversion.of_reference_exn[%exprSexplib0.Sexp_conv_error.empty_type[%eerror_source()]];;(* Generate code from type definitions *)lettd_of_sexp~typevars~loc:_~poly~path~rec_flagtd=lettps=List.maptd.ptype_params~f:get_type_param_nameinlet{ptype_name={txt=type_name;loc=_};ptype_loc=loc;_}=tdinletfull_type=core_type_of_type_declarationtd|>replace_variables_by_underscoresinletis_private=matchtd.ptype_privatewith|Private->true|Public->falseinifis_privatethenLocation.raise_errorf~loc"of_sexp is not supported for private type";letcreate_internal_function=matchis_polymorphic_varianttd~sig_:falsewith|`Definitely->true|`Maybe->poly|`Surely_not->ifpolythenLocation.raise_errorf~loc"sexp_poly annotation on a type that is surely not a polymorphic variant";falseinletbody~error_source=letbody=matchtd.ptype_kindwith|Ptype_variantalts->Attrs.fail_if_allow_extra_field_td~loctd;sum_of_sexp~error_source~typevars(td.ptype_loc,alts)|Ptype_recordlbls->record_of_sexp~error_source~typevars~allow_extra_fields:(Option.is_some(Attribute.getAttrs.allow_extra_fields_tdtd))(loc,lbls)|Ptype_open->Location.raise_errorf~loc"ppx_sexp_conv: open types not supported"|Ptype_abstract->Attrs.fail_if_allow_extra_field_td~loctd;(matchtd.ptype_manifestwith|None->nil_of_sexp~error_sourcetd.ptype_loc|>Lifted.return|Somety->type_of_sexp~error_source~full_type~typevars~internal:create_internal_functionty|>Lifted.return)in(* Prevent violation of value restriction, problems with recursive types, and
toplevel effects by eta-expanding function definitions *)body>>|Conversion.to_value_expression~locinletexternal_name=type_name^"_of_sexp"inletinternal_name="__"^type_name^"_of_sexp__"inletarg_patts,arg_exprs=List.unzip(List.map~f:(funtp->letname=Map.find_exntypevarstp.txtinFresh_name.patternname,Fresh_name.expressionname)tps)inletfull_type_name=Printf.sprintf"%s.%s"pathtype_nameinletinternal_fun_body=ifcreate_internal_functionthenSome(with_error_source~loc~full_type_name(fun~error_source->body~error_source>>|funbody->eta_reduce_if_possible_and_nonrec~rec_flag(eabstract~locarg_pattsbody)))elseNoneinletexternal_fun_body=letbody_below_lambdas~error_source=letfresh_sexp=Fresh_name.create"sexp"~locinifcreate_internal_functionthen(letno_variant_match_mc=[[%pat?Sexplib0.Sexp_conv_error.No_variant_match]-->[%exprSexplib0.Sexp_conv_error.no_matching_variant_found[%eerror_source()][%eFresh_name.expressionfresh_sexp]]]inletinternal_call=letinternal_expr=pexp_ident~loc{loc;txt=Lidentinternal_name}ineapply~locinternal_expr(arg_exprs@[Fresh_name.expressionfresh_sexp])inlettry_with=pexp_try~locinternal_callno_variant_match_mcin[%exprfun[%pFresh_name.patternfresh_sexp]->[%etry_with]]|>Lifted.return)elsebody~error_sourceinletbody_with_lambdas~error_source=body_below_lambdas~error_source>>|funbody->eta_reduce_if_possible_and_nonrec~rec_flag(eabstract~locarg_pattsbody)inwith_error_source~loc~full_type_namebody_with_lambdasinlettyp=Sig_generate_of_sexp.mk_typetdinletmk_bindingfunc_namebody=constrained_function_bindingloctdtyp~tps~func_namebodyinletinternal_bindings=matchinternal_fun_bodywith|None->[]|Somebody->[mk_bindinginternal_namebody]inletexternal_binding=mk_bindingexternal_nameexternal_fun_bodyininternal_bindings,[external_binding];;(* Generate code from type definitions *)lettds_of_sexp~loc~poly~path(rec_flag,tds)=lettds=List.map~f:name_type_params_in_tdtdsinlettypevarstd=List.foldtd.ptype_params~init:(Map.empty(moduleString))~f:(funmapparam->letname=get_type_param_nameparaminMap.setmap~key:name.txt~data:(Fresh_name.create("_of_"^name.txt)~loc:name.loc))inletsingleton=matchtdswith|[_]->true|_->falseinifsingletonthen(letrec_flag=really_recursive_respecting_opaquerec_flagtdsinmatchrec_flagwith|Recursive->letbindings=List.concat_maptds~f:(funtd->lettypevars=typevarstdinletinternals,externals=td_of_sexp~typevars~loc~poly~path~rec_flagtdininternals@externals)inpstr_value_list~locRecursivebindings|Nonrecursive->List.concat_maptds~f:(funtd->lettypevars=typevarstdinletinternals,externals=td_of_sexp~typevars~loc~poly~path~rec_flagtdinpstr_value_list~locNonrecursiveinternals@pstr_value_list~locNonrecursiveexternals))else(letbindings=List.concat_maptds~f:(funtd->lettypevars=typevarstdinletinternals,externals=td_of_sexp~typevars~poly~loc~path~rec_flagtdininternals@externals)inpstr_value_list~locrec_flagbindings);;letcore_type_of_sexp~pathcore_type=letloc={core_type.ptyp_locwithloc_ghost=true}inletfull_type_name=Printf.sprintf"%s line %i: %s"pathloc.loc_start.pos_lnum(string_of_core_typecore_type)inwith_error_source~loc~full_type_name(fun~error_source->type_of_sexp~error_source~typevars:(Map.empty(moduleString))core_type|>Conversion.to_value_expression~loc|>Merlin_helpers.hide_expression|>Lifted.return);;end