@@ -329,98 +329,139 @@ let output_struct_sig loc s =
329329 (op_typ op)))
330330 (ops_for s)
331331
332- let output_enum _loc name fields width ~sexp =
333- let intfn,pattfn = match ty_of_string width with
334- | None -> loc_err _loc " enum: unknown width specifier %s" width
335- | Some Char ->
336- (fun i -> Exp. constant (Pconst_char (Char. chr @@ Int64. to_int i))),
337- (fun i -> Pat. constant (Pconst_char (Char. chr @@ Int64. to_int i)))
338- | Some (UInt8 | UInt16 ) ->
339- (fun i -> Exp. constant (Pconst_integer (Int64. to_string i, None ))),
340- (fun i -> Pat. constant (Pconst_integer (Int64. to_string i, None )))
341- | Some UInt32 ->
342- (fun i -> Exp. constant (Pconst_integer (Int32. to_string (Int64. to_int32 i), Some 'l' ))),
343- (fun i -> Pat. constant (Pconst_integer (Int32. to_string (Int64. to_int32 i), Some 'l' )))
344- | Some UInt64 ->
345- (fun i -> Exp. constant (Pconst_integer (Int64. to_string i, Some 'L' ))),
346- (fun i -> Pat. constant (Pconst_integer (Int64. to_string i, Some 'L' )))
332+ type enum_op =
333+ | Enum_to_sexp
334+ | Enum_of_sexp
335+ | Enum_get
336+ | Enum_set
337+ | Enum_print
338+ | Enum_parse
339+
340+ type cenum =
341+ { name : string Loc .loc ;
342+ fields : (string Loc .loc * int64 ) list ;
343+ prim : prim ;
344+ sexp : bool ;
345+ }
346+
347+ let enum_op_name cenum =
348+ let s = cenum.name.txt in
349+ function
350+ | Enum_to_sexp -> sprintf " sexp_of_%s" s
351+ | Enum_of_sexp -> sprintf " %s_of_sexp" s
352+ | Enum_get -> sprintf " int_to_%s" s
353+ | Enum_set -> sprintf " %s_to_int" s
354+ | Enum_print -> sprintf " %s_to_string" s
355+ | Enum_parse -> sprintf " string_to_%s" s
356+
357+ let enum_pattern {prim; _} =
358+ let pat_integer f suffix i =
359+ Pat. constant (Pconst_integer (f i, suffix))
347360 in
348- let decls = List. map (fun (f ,_ ) -> Type. constructor f) fields in
349- let getters = (List. map (fun ({txt = f ; _} ,i ) ->
350- {pc_lhs = pattfn i; pc_guard = None ; pc_rhs = Ast. constr " Some" [Ast. constr f []]}
351- ) fields) @ [{pc_lhs = Pat. any () ; pc_guard = None ; pc_rhs = Ast. constr " None" [] }] in
352- let setters = List. map (fun ({txt = f ; _} ,i ) ->
353- {pc_lhs = Ast. pconstr f [] ; pc_guard = None ; pc_rhs = intfn i}
354- ) fields in
355- let printers = List. map (fun ({txt = f ; _} ,_ ) ->
356- {pc_lhs = Ast. pconstr f [] ; pc_guard = None ; pc_rhs = Ast. str f}) fields in
357- let parsers = List. map (fun ({txt = f ; _} ,_ ) ->
358- {pc_lhs = Ast. pstr f; pc_guard = None ; pc_rhs = Ast. constr " Some" [Ast. constr f []]}) fields in
359- let getter {txt = x ; _} = sprintf " int_to_%s" x in
360- let setter {txt = x ; _} = sprintf " %s_to_int" x in
361- let printer {txt = x ; _} = sprintf " %s_to_string" x in
362- let parse {txt = x ; _} = sprintf " string_to_%s" x in
363- let of_sexp {txt = x ; _} = sprintf " %s_of_sexp" x in
364- let to_sexp {txt = x ; _} = sprintf " sexp_of_%s" x in
365- let output_sexp_struct =
366- [
367- [% stri
368- let [% p Ast. pvar (to_sexp name)] = fun x ->
369- Sexplib.Sexp. Atom ([% e Ast. evar (printer name)] x)];
370- [% stri
371- let [% p Ast. pvar (of_sexp name)] = fun x ->
372- match x with
373- | Sexplib.Sexp. List _ ->
374- raise (Sexplib.Pre_sexp. Of_sexp_error (Failure " expected Atom, got List" , x))
375- | Sexplib.Sexp. Atom v ->
376- match [% e Ast. evar (parse name)] v with
377- | None ->
378- raise (Sexplib.Pre_sexp. Of_sexp_error (Failure " unable to parse enum string" , x))
379- | Some r -> r
380- ]
381- ] in
382- Str. type_ Recursive [Type. mk ~kind: (Ptype_variant decls) name] ::
383- [% stri
384- let [% p Ast. pvar (getter name)] = fun x -> [% e Exp. match_ [% expr x] getters]] ::
385- [% stri
386- let [% p Ast. pvar (setter name)] = fun x -> [% e Exp. match_ [% expr x] setters]] ::
387- [% stri
388- let [% p Ast. pvar (printer name)] = fun x -> [% e Exp. match_ [% expr x] printers]] ::
389- [% stri
390- let [% p Ast. pvar (parse name)] = fun x ->
391- [% e Exp. match_ [% expr x]
392- (parsers @ [{pc_lhs = Pat. any () ; pc_guard = None ; pc_rhs = Ast. constr " None" [] }])]] ::
393- if sexp then output_sexp_struct else []
394-
395- let output_enum_sig _loc name fields width ~sexp =
396- let oty = match ty_of_string width with
397- | None -> loc_err _loc " enum: unknown width specifier %s" width
398- | Some Char -> [% type : char ]
399- | Some (UInt8 |UInt16 ) -> [% type : int ]
400- | Some UInt32 -> [% type : int32 ]
401- | Some UInt64 -> [% type : int64 ]
361+ match prim with
362+ | Char ->
363+ (fun i -> Ast. pchar (Char. chr (Int64. to_int i)))
364+ | (UInt8 | UInt16 ) -> pat_integer Int64. to_string None
365+ | UInt32 -> pat_integer (fun i -> Int32. to_string (Int64. to_int32 i)) (Some 'l' )
366+ | UInt64 -> pat_integer Int64. to_string (Some 'L' )
367+
368+ let enum_integer {prim; _} =
369+ let expr_integer f suffix i =
370+ Exp. constant (Pconst_integer (f i, suffix))
402371 in
372+ match prim with
373+ | Char -> (fun i -> Ast. char (Char. chr (Int64. to_int i)))
374+ | (UInt8 | UInt16 ) -> expr_integer Int64. to_string None
375+ | UInt32 -> expr_integer (fun i -> Int32. to_string (Int64. to_int32 i)) (Some 'l' )
376+ | UInt64 -> expr_integer Int64. to_string (Some 'L' )
377+
378+ let declare_enum_expr ({fields; _} as cenum ) = function
379+ | Enum_to_sexp ->
380+ [% expr Sexplib.Sexp. Atom ([% e Ast. evar (enum_op_name cenum Enum_print )] x) ]
381+ | Enum_of_sexp ->
382+ [% expr
383+ match x with
384+ | Sexplib.Sexp. List _ ->
385+ raise (Sexplib.Pre_sexp. Of_sexp_error (Failure " expected Atom, got List" , x))
386+ | Sexplib.Sexp. Atom v ->
387+ match [% e Ast. evar (enum_op_name cenum Enum_parse )] v with
388+ | None ->
389+ raise (Sexplib.Pre_sexp. Of_sexp_error (Failure " unable to parse enum string" , x))
390+ | Some r -> r
391+ ]
392+ | Enum_get ->
393+ let getters = (List. map (fun ({txt = f ; _} ,i ) ->
394+ Exp. case (enum_pattern cenum i) [% expr Some [% e Ast. constr f []]]
395+ ) fields) @ [Exp. case [% pat? _] [% expr None ]]
396+ in
397+ Exp. match_ [% expr x] getters
398+ | Enum_set ->
399+ let setters = List. map (fun ({txt = f ; _} ,i ) ->
400+ Exp. case (Ast. pconstr f [] ) (enum_integer cenum i)
401+ ) fields in
402+ Exp. match_ [% expr x] setters
403+ | Enum_print ->
404+ let printers = List. map (fun ({txt = f ; _} ,_ ) ->
405+ Exp. case (Ast. pconstr f [] ) (Ast. str f)
406+ ) fields in
407+ Exp. match_ [% expr x] printers
408+ | Enum_parse ->
409+ let parsers = List. map (fun ({txt = f ; _} ,_ ) ->
410+ Exp. case (Ast. pstr f) [% expr Some [% e Ast. constr f []]]
411+ ) fields in
412+ Exp. match_ [% expr x]
413+ (parsers @ [Exp. case [% pat? _] [% expr None ]])
414+
415+ let enum_ops_for {sexp; _} =
416+ Enum_get ::
417+ Enum_set ::
418+ Enum_print ::
419+ Enum_parse ::
420+ if sexp then
421+ [ Enum_to_sexp
422+ ; Enum_of_sexp
423+ ]
424+ else
425+ []
426+
427+ let enum_type_decl {name; fields; _} =
403428 let decls = List. map (fun (f ,_ ) -> Type. constructor f) fields in
404- let getter {txt = x ; _} = sprintf " int_to_%s" x in
405- let setter {txt = x ; _} = sprintf " %s_to_int" x in
406- let printer {txt = x ; _} = sprintf " %s_to_string" x in
407- let parse {txt = x ; _} = sprintf " string_to_%s" x in
408- let of_sexp {txt = x ; _} = sprintf " %s_of_sexp" x in
409- let to_sexp {txt = x ; _} = sprintf " sexp_of_%s" x in
410- let ctyo = [% type : [% t Ast. tconstr name.txt []] option ] in
429+ Type. mk ~kind: (Ptype_variant decls) name
430+
431+ let output_enum cenum =
432+ Str. type_ Recursive [enum_type_decl cenum] ::
433+ List. map
434+ (fun op ->
435+ [% stri
436+ let [@ ocaml.warning " -32" ] [% p Ast. pvar (enum_op_name cenum op)] =
437+ fun x -> [% e declare_enum_expr cenum op]
438+ ])
439+ (enum_ops_for cenum)
440+
441+ let enum_op_type {name; prim; _} =
411442 let cty = Ast. tconstr name.txt [] in
412- let output_sexp_sig =
413- [
414- Sig. value ( Val. mk ( Loc. mkloc (to_sexp name) _loc) [% type : [ % t cty] -> Sexplib.Sexp. t]);
415- Sig. value ( Val. mk ( Loc. mkloc (of_sexp name) _loc) [% type : Sexplib.Sexp. t -> [ % t cty]])
416- ]
443+ let oty = match prim with
444+ | Char -> [ % type : char ]
445+ | ( UInt8 | UInt16 ) -> [% type : int ]
446+ | UInt32 -> [% type : int32 ]
447+ | UInt64 -> [ % type : int64 ]
417448 in
418- Sig. type_ Recursive [Type. mk ~kind: (Ptype_variant decls) name] ::
419- Sig. value (Val. mk (Loc. mkloc (getter name) _loc) [% type : [% t oty] -> [% t ctyo]]) ::
420- Sig. value (Val. mk (Loc. mkloc (setter name) _loc) [% type : [% t cty] -> [% t oty]]) ::
421- Sig. value (Val. mk (Loc. mkloc (printer name) _loc) [% type : [% t cty] -> string ]) ::
422- Sig. value (Val. mk (Loc. mkloc (parse name) _loc) [% type : string -> [% t cty] option ]) ::
423- if sexp then output_sexp_sig else []
449+ function
450+ | Enum_get -> [% type : [% t oty] -> [% t cty] option ]
451+ | Enum_set -> [% type : [% t cty] -> [% t oty]]
452+ | Enum_print -> [% type : [% t cty] -> string ]
453+ | Enum_parse -> [% type : string -> [% t cty] option ]
454+ | Enum_to_sexp -> [% type : [% t cty] -> Sexplib.Sexp. t]
455+ | Enum_of_sexp -> [% type : Sexplib.Sexp. t -> [% t cty]]
456+
457+ let output_enum_sig loc (cenum :cenum ) =
458+ Sig. type_ Recursive [enum_type_decl cenum] ::
459+ List. map
460+ (fun op ->
461+ let name = enum_op_name cenum op in
462+ let typ = enum_op_type cenum op in
463+ Sig. value (Val. mk (Loc. mkloc name loc) typ))
464+ (enum_ops_for cenum)
424465
425466let constr_enum = function
426467 | {pcd_name = f ; pcd_args = Pcstr_tuple [] ; pcd_attributes = attrs ; _} ->
@@ -500,7 +541,15 @@ let cenum decl =
500541 | (f , None) -> incr_n () ; (f, ! n)
501542 | (f , Some i ) -> n := i; (f, i)
502543 ) fields in
503- name, fields, width, sexp
544+ let prim = match ty_of_string width with
545+ | None -> loc_err loc " enum: unknown width specifier %s" width
546+ | Some p -> p
547+ in
548+ { name;
549+ fields;
550+ prim;
551+ sexp;
552+ }
504553
505554let signature_item' mapper = function
506555 | {psig_desc =
@@ -510,8 +559,7 @@ let signature_item' mapper = function
510559 | {psig_desc =
511560 Psig_extension (({txt = " cenum" ; _}, PStr [{pstr_desc = Pstr_type (_, [decl]); _}]), _);
512561 psig_loc = loc} ->
513- let name, fields, width, sexp = cenum decl in
514- output_enum_sig loc name fields width ~sexp
562+ output_enum_sig loc (cenum decl)
515563 | other ->
516564 [default_mapper.signature_item mapper other]
517565
@@ -525,9 +573,8 @@ let structure_item' mapper = function
525573 output_struct loc (cstruct decl)
526574 | {pstr_desc =
527575 Pstr_extension (({txt = " cenum" ; _}, PStr [{pstr_desc = Pstr_type (_, [decl]); _}]), _);
528- pstr_loc = loc} ->
529- let name, fields, width, sexp = cenum decl in
530- output_enum loc name fields width ~sexp
576+ _ } ->
577+ output_enum (cenum decl)
531578 | other ->
532579 [default_mapper.structure_item mapper other]
533580
0 commit comments