123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459(* Generated code should depend on the environment in scope as little as possible.
E.g. rather than [foo = []] do [match foo with [] ->], to eliminate the use of [=]. It
is especially important to not use polymorphic comparisons, since we are moving more
and more to code that doesn't have them in scope. *)(* Note: I am introducing a few unnecessary explicit closures, (not all of them some are
unnecessary due to the value restriction).
*)openBaseopenPpxlibopenAst_builder.DefaultincludePpx_compare_expander_intftypekind=Compare|EqualmoduletypeParams=sigvalname:stringvalkind:kindvalchain:expression->expression->expressionvalconst:loc:Location.t->Ordering.t->expressionvalresult_type:loc:Location.t->core_typevalpoly:loc:Location.t->expression->expression->expressionvalabstract:loc:Location.t->type_name:string->expression->expression->expressionmoduleAttrs:AttrsendmoduleMake_attrs(Name:sigvalname:stringend):Attrs=structletignore=Attribute.declare(Name.name^".ignore")Attribute.Context.label_declarationAst_pattern.(pstrnil)()endmoduleCompare_params:Params=structletname="compare"letkind=Compareletchainab=letloc=a.pexp_locin[%exprmatch[%ea]with|0->[%eb]|n->n]letconst~loc(ord:Ordering.t)=eint~loc(matchordwith|Less->-1|Equal->0|Greater->1)letresult_type~loc=[%type:int]letpoly~locab=[%exprPpx_compare_lib.polymorphic_compare[%ea][%eb]]letabstract~loc~type_nameab=[%exprPpx_compare_lib.compare_abstract~type_name:[%eestring~loctype_name][%ea][%eb]]moduleAttrs=Make_attrs(structletname=nameend)endmoduleEqual_params:Params=structletname="equal"letkind=Equalletchainab=letloc=a.pexp_locin[%exprPpx_compare_lib.(&&)[%ea][%eb]]letconst~loc(ord:Ordering.t)=matchordwith|Equal->[%exprtrue]|Less|Greater->[%exprfalse]letresult_type~loc=[%type:bool]letpoly~locab=[%exprPpx_compare_lib.polymorphic_equal[%ea][%eb]]letabstract~loc~type_nameab=[%exprPpx_compare_lib.equal_abstract~type_name:[%eestring~loctype_name][%ea][%eb]]moduleAttrs=Make_attrs(structletname=nameend)endmoduleMake(Params:Params)=structopenParamsmoduleAttrs=Attrsletstr_attributes=[Attribute.TAttrs.ignore]letis_ignoredld=letloc=ld.pld_locinmatchkind,Attribute.getCompare_params.Attrs.ignoreld,Attribute.getEqual_params.Attrs.ignoreldwith|_,Some(),Some()|Compare,Some(),None|Equal,None,Some()->true|_,None,None->false|Compare,None,Some()->Location.raise_errorf~loc"Cannot use [@@equal.ignore] with [@@@@deriving compare]."|Equal,Some(),None->Location.raise_errorf~loc"Cannot use [@@compare.ignore] with [@@@@deriving equal]"letwith_tupleloc~value~tysf=(* generate
let id_1, id_2, id_3, ... id_n = value in expr
where expr is the result of (f [id_1, ty_1 ; id_2, ty_2; ...])
*)letnames_types=List.maptys~f:(funt->gen_symbol~prefix:"t"(),t)inletpattern=letl=List.mapnames_types~f:(fun(n,_)->pvar~locn)inppat_tuple~loclinlete=f(List.mapnames_types~f:(fun(n,t)->(evar~locn,t)))inletbinding=value_binding~loc~pat:pattern~expr:valueinpexp_let~locNonrecursive[binding]eletphys_equal_firstabcmp=letloc=cmp.pexp_locin[%exprifPpx_compare_lib.phys_equal[%ea][%eb]then[%econst~locEqual]else[%ecmp]]letrecchain_if~loc=function|[]->const~locEqual|[x]->x|x::xs->chainx(chain_if~loc:x.pexp_locxs)lettp_namen=Printf.sprintf"_cmp__%s"nlettype_~locty=[%type:[%tty]->[%tty]->[%tresult_type~loc]]letfunction_name=function|"t"->name|s->name^"_"^sletreccompare_applied~constructor~argsvalue1value2=letargs=List.mapargs~f:(compare_of_ty_fun~type_constraint:false)@[value1;value2]intype_constr_conv~loc:(Located.locconstructor)constructorargs~f:function_nameandcompare_of_tupleloctysvalue1value2=with_tupleloc~value:value1~tys(funelems1->with_tupleloc~value:value2~tys(funelems2->letexprs=List.map2_exnelems1elems2~f:(fun(v1,t)(v2,_)->compare_of_tytv1v2)inchain_if~locexprs))andcompare_variantlocrow_fieldsvalue1value2=letmap=function|Rtag({txt=cnstr;_},_attrs,true,_)|Rtag({txt=cnstr;_},_attrs,_,[])->case~guard:None~lhs:(ppat_tuple~loc[ppat_variant~loccnstrNone;ppat_variant~loccnstrNone])~rhs:(const~locEqual)|Rtag({txt=cnstr;_},_attrs,false,tp::_)->letv1=gen_symbol~prefix:"_left"()andv2=gen_symbol~prefix:"_right"()inletbody=compare_of_tytp(evar~locv1)(evar~locv2)incase~guard:None~lhs:(ppat_tuple~loc[ppat_variant~loccnstr(Some(pvar~locv1));ppat_variant~loccnstr(Some(pvar~locv2))])~rhs:body|Rinherit{ptyp_desc=Ptyp_constr(id,args);_}->(* quite sadly, this code doesn't handle:
type 'a id = 'a with compare
type t = [ `a | [ `b ] id ] with compare
because it will generate a pattern #id, when id is not even a polymorphic
variant in the first place.
The culprit is caml though, since it only allows #id but not #([`b] id)
*)letv1=gen_symbol~prefix:"_left"()andv2=gen_symbol~prefix:"_right"()incase~guard:None~lhs:(ppat_tuple~loc[ppat_alias~loc(ppat_type~locid)(Located.mk~locv1);ppat_alias~loc(ppat_type~locid)(Located.mk~locv2)])~rhs:(compare_applied~constructor:id~args(evar~locv1)(evar~locv2))|Rinheritty->Location.raise_errorf~loc:ty.ptyp_loc"Ppx_compare.compare_variant: unknown type"inlete=letmatched=pexp_tuple~loc[value1;value2]inmatchList.map~f:maprow_fieldswith|[v]->pexp_match~locmatched[v]|l->pexp_match~locmatched(l@(* Providing we didn't screw up badly we now know that the tags of the variants
are different. We let pervasive do its magic. *)[case~guard:None~lhs:[%pat?(x,y)]~rhs:(poly~loc[%exprx][%expry])])inphys_equal_firstvalue1value2eandbranches_of_sumcds=letrightmost_index=(List.lengthcds-1)inList.concat(List.mapicds~f:(funicd->letrightmost=i=rightmost_indexinletloc=cd.pcd_locinifOption.is_somecd.pcd_resthen(* If we get GADTs support, fix the constant sum type optimization for them *)Location.raise_errorf~loc"GADTs are not supported by comparelib";matchcd.pcd_argswith|Pcstr_recordlds->letvalue1=gen_symbol~prefix:"_a"()inletvalue2=gen_symbol~prefix:"_b"()inletres=case~guard:None~lhs:(ppat_tuple~loc[pconstructcd(Some(pvar~locvalue1));pconstructcd(Some(pvar~locvalue2))])~rhs:(compare_of_record_no_phys_equalloclds(evar~locvalue1)(evar~locvalue2))inifrightmostthen[res]elseletpany=ppat_any~locinletpcnstr=pconstructcd(Somepany)inletcaselrord=case~guard:None~lhs:(ppat_tuple~loc[l;r])~rhs:(const~locord)in[res;casepcnstrpanyLess;casepanypcnstrGreater]|Pcstr_tuplepcd_args->matchpcd_argswith|[]->letpcnstr=pconstructcdNoneinletpany=ppat_any~locinletcaselrord=case~guard:None~lhs:(ppat_tuple~loc[l;r])~rhs:(const~locord)inifrightmostthen[casepcnstrpcnstrEqual]else[casepcnstrpcnstrEqual;casepcnstrpanyLess;casepanypcnstrGreater]|tps->letids_ty=List.maptps~f:(funty->leta=gen_symbol~prefix:"_a"()inletb=gen_symbol~prefix:"_b"()in(a,b,ty))inletlpatt=List.mapids_ty~f:(fun(l,_r,_ty)->pvar~locl)|>ppat_tuple~locandrpatt=List.mapids_ty~f:(fun(_l,r,_ty)->pvar~locr)|>ppat_tuple~locandbody=List.mapids_ty~f:(fun(l,r,ty)->compare_of_tyty(evar~locl)(evar~locr))|>chain_if~locinletres=case~guard:None~lhs:(ppat_tuple~loc[pconstructcd(Somelpatt);pconstructcd(Somerpatt)])~rhs:bodyinifrightmostthen[res]elseletpany=ppat_any~locinletpcnstr=pconstructcd(Somepany)inletcaselrord=case~guard:None~lhs:(ppat_tuple~loc[l;r])~rhs:(const~locord)in[res;casepcnstrpanyLess;casepanypcnstrGreater]))andcompare_sumloccdsvalue1value2=letis_sum_type_with_all_constant_constructors=List.for_allcds~f:(funcd->(Option.is_nonecd.pcd_res)&&(* we could support GADTs, but the general case
doesn't, so let's hold off *)(matchcd.pcd_argswith|Pcstr_tuplel->List.is_emptyl|Pcstr_recordl->List.is_emptyl))inifis_sum_type_with_all_constant_constructorsthenbegin(* the compiler will optimize the polymorphic comparison to an integer one *)poly~locvalue1value2endelsebeginletmcs=branches_of_sumcdsinlete=pexp_match~loc(pexp_tuple~loc[value1;value2])mcsinphys_equal_firstvalue1value2eendandcompare_of_tytyvalue1value2=letloc=ty.ptyp_locinmatchty.ptyp_descwith|Ptyp_constr(constructor,args)->compare_applied~constructor~argsvalue1value2|Ptyp_tupletys->compare_of_tupleloctysvalue1value2|Ptyp_varname->eapply~loc(evar~loc(tp_namename))[value1;value2]|Ptyp_arrow_->Location.raise_errorf~loc"ppx_compare: Functions can not be compared."|Ptyp_variant(row_fields,Closed,None)->compare_variantlocrow_fieldsvalue1value2|Ptyp_any->[%exprlet_=[%evalue1]and_=[%evalue2]in[%econst~locEqual]]|_->Location.raise_errorf~loc"ppx_compare: unknown type"andcompare_of_ty_fun~type_constraintty=letloc=ty.ptyp_locinleta=gen_symbol~prefix:"a"()inletb=gen_symbol~prefix:"b"()inlete_a=evar~locainlete_b=evar~locbinletmk_patx=iftype_constraintthenppat_constraint~loc(pvar~locx)tyelsepvar~locxineta_reduce_if_possible[%exprfun[%pmk_pata][%pmk_patb]->[%ecompare_of_tytye_ae_b]]andcompare_of_record_no_phys_equallocldsvalue1value2=letis_evar=function|{pexp_desc=Pexp_ident_;_}->true|_->falseinassert(is_evarvalue1);assert(is_evarvalue2);List.filterlds~f:(funld->not(is_ignoredld))|>List.map~f:(funld->letloc=ld.pld_locinletlabel=Located.maplidentld.pld_nameincompare_of_tyld.pld_type(pexp_field~locvalue1label)(pexp_field~locvalue2label))|>chain_if~locletcompare_of_recordlocldsvalue1value2=compare_of_record_no_phys_equallocldsvalue1value2|>phys_equal_firstvalue1value2letcompare_abstractloctype_namev_av_b=abstract~loc~type_namev_av_bletscheme_of_tdtd=letloc=td.ptype_locinlettype_=combinator_type_of_type_declarationtd~f:type_inmatchtd.ptype_paramswith|[]->type_|l->letvars=List.mapl~f:get_type_param_nameinptyp_poly~locvarstype_letcompare_of_tdtd~rec_flag=letloc=td.ptype_locinleta=gen_symbol~prefix:"a"()inletb=gen_symbol~prefix:"b"()inletv_a=evar~locainletv_b=evar~locbinletfunction_body=matchtd.ptype_kindwith|Ptype_variantcds->compare_sumloccdsv_av_b|Ptype_recordlds->compare_of_recordlocldsv_av_b|Ptype_open->Location.raise_errorf~loc"ppx_compare: open types are not yet supported"|Ptype_abstract->matchtd.ptype_manifestwith|None->compare_abstractloctd.ptype_name.txtv_av_b|Somety->matchty.ptyp_descwith|Ptyp_variant(_,Open,_)|Ptyp_variant(_,Closed,Some(_::_))->Location.raise_errorf~loc:ty.ptyp_loc"ppx_compare: cannot compare open polymorphic variant types"|Ptyp_variant(row_fields,_,_)->compare_variantlocrow_fieldsv_av_b|_->compare_of_tytyv_av_binletextra_names=List.maptd.ptype_params~f:(funp->tp_name(get_type_param_namep).txt)inletpatts=List.map(extra_names@[a;b])~f:(pvar~loc)andbnd=pvar~loc(function_nametd.ptype_name.txt)inletpoly_scheme=(matchextra_nameswith[]->false|_::_->true)inletbody=eta_reduce_if_possible_and_nonrec~rec_flag(eabstract~locpattsfunction_body)inifpoly_schemethenvalue_binding~loc~pat:(ppat_constraint~locbnd(scheme_of_tdtd))~expr:bodyelsevalue_binding~loc~pat:bnd~expr:(pexp_constraint~locbody(scheme_of_tdtd))letstr_type_decl~loc~path:_(rec_flag,tds)=letrec_flag=(objectinherittype_is_recursiverec_flagtdsassupermethod!label_declarationld=ifnot(is_ignoredld)thensuper#label_declarationldend)#go()inletbindings=List.maptds~f:(compare_of_td~rec_flag)in[pstr_value~locrec_flagbindings]letsig_type_decl~loc:_~path:_(_rec_flag,tds)=List.maptds~f:(funtd->letcompare_of=combinator_type_of_type_declarationtd~f:type_inletname=function_nametd.ptype_name.txtinletloc=td.ptype_locinpsig_value~loc(value_description~loc~name:{td.ptype_namewithtxt=name}~type_:compare_of~prim:[]))letcompare_core_typety=compare_of_ty_fun~type_constraint:truetyletcore_type=compare_core_typeendmoduleCompare=structincludeMake(Compare_params)letequal_core_typety=letloc=ty.ptyp_locinletarg1=gen_symbol()inletarg2=gen_symbol()in[%expr(fun[%ppvar~locarg1][%ppvar~locarg2]->match[%ecompare_core_typety][%eevar~locarg1][%eevar~locarg2]with|0->true|_->false)]endmoduleEqual=Make(Equal_params)