123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106openBaseopen!PpxlibmoduleEntry=structincludeStringletsexp_of="sexp_of"letof_sexp="of_sexp"letsexp="sexp"letbin_io="bin_io"letvariants="variants"letequal="equal"letcompare="compare"endletattribute_name="deriving"typet=Entry.tlistletempty=[]letaddtentry=ifList.existst~f:(Entry.(=)entry)thentelset@[entry]letmem=List.mem~equal:String.equalmoduleExtra=structtypet=Entry.tlistletlabel="extra_derive"letpattern=Ast_pattern.(elist(pexp_ident(lident__)))letarg=Deriving.Args.arglabelpatternendletcreate?extra(td:type_declaration)how_to_diffsig_or_struct~builder=letopen(valbuilder:Builder.S)inletextra=matchextrawith|None->[]|Some[]->raise_error(Extra.label^" should not be empty")|Some(_::_asextra)->extrainletderiving=List.concat_maptd.ptype_attributes~f:(fun{attr_name;attr_payload;_}->ifnot(String.(=)attr_name.txtattribute_name||String.(=)attr_name.txt(attribute_name^"_inline"))then[]else(matchattr_payloadwith|PSig_|PTyp_|PPat_->[]|PStrstr->List.concat_mapstr~f:(funitem->matchitem.pstr_descwith|Pstr_eval(expr,[])->letrecget(expr:expression)=matchexpr.pexp_descwith|Pexp_ident{txt=Lidentd;_}->[d]|Pexp_tuplelist->List.concat_maplist~f:get|Pexp_apply({pexp_desc=Pexp_ident{txt=Lidentd;_};_},_)->[d]|_->[]ingetexpr|_->[])))inletdefault=List.filterderiving~f:(Set.memEntry.(Set.of_list(moduleEntry)[sexp_of;of_sexp;sexp;bin_io]))@match(how_to_diff:How_to_diff.Atomic.toption),sig_or_structwith|None,_|_,`sig_->[]|Some{using_compare},`struct_->[(ifusing_comparethenEntry.compareelseEntry.equal)]inmatchList.find_all_dupsextra~compare:String.comparewith|[]->List.foldextra~init:default~f:(funtentry->ifmemtentrythenraise_error("Unnecessary entry "^entry^" in "^Extra.label^". "^entry^" is already derived by default")elseaddtentry)|dups->raise_error("Duplicate entries in "^Extra.label^": "^String.concat~sep:", "dups);;letattributet~builder=letopen(valbuilder:Builder.S)inletopenBuild_helperinmatchtwith|[]->None|what_to_derive->letwhat_to_derive=Tuple(List.mapwhat_to_derive~f:(funentry->Text(Entry.to_stringentry)))inattribute~name:(Located.mkattribute_name)~payload:(PStr[pstr_eval(ewhat_to_derive)[]])|>Option.return;;