Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_deriving_enum.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160openPpxlibopenAsttypesopenParsetreeopenAst_helperopenPpx_deriving.Ast_convenienceletderiver="enum"letraise_errorf=Ppx_deriving.raise_errorfletattr_valuecontext=Attribute.declare"deriving.enum.value"contextAst_pattern.(single_expr_payload(eint__))(funi->i)letconstr_attr_value=attr_valueAttribute.Context.constructor_declarationletrtag_attr_value=attr_valueAttribute.Context.rtagletmappings_of_typetype_decl=letmapaccrev_mappingsattr_valuexconstr_name=letvalue=matchAttribute.getattr_valuexwith|Someidx->idx|None->accin(value+1,(value,constr_name)::rev_mappings)inletkind,(_,rev_mappings)=matchtype_decl.ptype_kind,type_decl.ptype_manifestwith|Ptype_variantconstrs,_->`Regular,List.fold_left(fun(acc,rev_mappings)({pcd_name;pcd_args;pcd_attributes;pcd_loc}asconstr)->ifpcd_args<>Pcstr_tuple([])thenraise_errorf~loc:pcd_loc"%s can be derived only for argumentless constructors"deriver;mapaccrev_mappingsconstr_attr_valueconstrpcd_name)(0,[])constrs|Ptype_abstract,Some{ptyp_desc=Ptyp_variant(constrs,Closed,None);ptyp_loc}->`Polymorphic,List.fold_left(fun(acc,rev_mappings)row_field->leterror_inheritloc=raise_errorf~loc:ptyp_loc"%s cannot be derived for inherited variant cases"deriverinleterror_argumentsloc=raise_errorf~loc:ptyp_loc"%s can be derived only for argumentless constructors"deriverinletloc=row_field.prf_locinmatchrow_field.prf_descwith|Rinherit_->error_inheritloc|Rtag(name,true,[])->mapaccrev_mappingsrtag_attr_valuerow_fieldname|Rtag_->error_argumentsloc)(0,[])constrs|_->raise_errorf~loc:type_decl.ptype_loc"%s can be derived only for variants"deriverinlet()=(* Check for duplicate mappings. Consider for example:
type t =
| A [@value 1]
| B [@value 1]
| C [@value 1]
[@@deriving enum]
We generate an error that looks as follows (the ">" indicate
quoted source with locations), with sub-errors/sub-locations:
> type t = [...]
Error: enum: duplicate value 1 for constructors A, B, C.
> | A [@value 1]
Declaration of A
> | B [@value 1]
Declaration of B
> | C [@value 1]
Declaration of C
*)letrev_dom=ref[]inletgroups=Hashtbl.create(List.lengthrev_mappings)in(* Iteration order from last to first ensures that each group is in source order in errors. *)rev_mappings|>List.iter(fun(v,constr)->ifnot(Hashtbl.memgroupsv)thenrev_dom:=v::!rev_dom;Hashtbl.addgroupsvconstr;);letdom=List.rev!rev_domindom|>List.iter(funv->matchHashtbl.find_allgroupsvwith|[]->assertfalse|[constr]->()|(_::_)asconflict_constrs->letsigil=matchkindwith`Regular->""|`Polymorphic->"`"inletsub=conflict_constrs|>List.map(fun{txt;loc}->(* NB! do not use loc_ghost for submessage because newer compilers will hide it *)Ocaml_common.Location.errorf~loc"Declaration of %s%s"sigiltxt)inraise_errorf~sub~loc:type_decl.ptype_loc"%s: duplicate value %d for constructors %s."deriverv(String.concat", "(List.map(func->sigil^c.txt)conflict_constrs)));inkind,List.revrev_mappings(* Put the mappings in source order. *)letstr_of_type({ptype_loc=_}astype_decl)=letkind,mappings=mappings_of_typetype_declinletpattname=matchkindwith|`Regular->Pat.construct(mknoloc(Lidentname))None|`Polymorphic->Pat.variantnameNoneandexprname=matchkindwith|`Regular->Exp.construct(mknoloc(Lidentname))None|`Polymorphic->Exp.variantnameNoneinletto_enum_cases=List.map(fun(value,{txt=name})->Exp.case(pattname)(intvalue))mappingsandfrom_enum_cases=List.map(fun(value,{txt=name})->Exp.case(pintvalue)(constr"Some"[exprname]))mappings@[Exp.case(Pat.any())(constr"None"[])]andindexes=List.mapfstmappingsin[Vb.mk(pvar(Ppx_deriving.mangle_type_decl(`Prefix"min")type_decl))(int(List.fold_leftminmax_intindexes));Vb.mk(pvar(Ppx_deriving.mangle_type_decl(`Prefix"max")type_decl))(int(List.fold_leftmaxmin_intindexes));Vb.mk(pvar(Ppx_deriving.mangle_type_decl(`Suffix"to_enum")type_decl))(Exp.function_to_enum_cases);Vb.mk(pvar(Ppx_deriving.mangle_type_decl(`Suffix"of_enum")type_decl))(Exp.function_from_enum_cases)]letsig_of_typetype_decl=letloc={type_decl.ptype_locwithloc_ghost=true}inlettyp=Ppx_deriving.core_type_of_type_decltype_declin[Sig.value(Val.mk(mknoloc(Ppx_deriving.mangle_type_decl(`Prefix"min")type_decl))[%type:Ppx_deriving_runtime.int]);Sig.value(Val.mk(mknoloc(Ppx_deriving.mangle_type_decl(`Prefix"max")type_decl))[%type:Ppx_deriving_runtime.int]);Sig.value(Val.mk(mknoloc(Ppx_deriving.mangle_type_decl(`Suffix"to_enum")type_decl))[%type:[%ttyp]->Ppx_deriving_runtime.int]);Sig.value(Val.mk(mknoloc(Ppx_deriving.mangle_type_decl(`Suffix"of_enum")type_decl))[%type:Ppx_deriving_runtime.int->[%ttyp]Ppx_deriving_runtime.option])]letimpl_generator=Deriving.Generator.V2.make_noarg(fun~ctxt:_(_,type_decls)->[Str.valueNonrecursive(List.concat(List.mapstr_of_typetype_decls))])letintf_generator=Deriving.Generator.V2.make_noarg(fun~ctxt:_(_,type_decls)->List.concat(List.mapsig_of_typetype_decls))letderiving:Deriving.t=Deriving.addderiver~str_type_decl:impl_generator~sig_type_decl:intf_generator