Skip to content

Commit aef90c7

Browse files
committed
Use an explicit type for cenum
1 parent 5acacec commit aef90c7

File tree

1 file changed

+90
-83
lines changed

1 file changed

+90
-83
lines changed

ppx/ppx_cstruct.ml

Lines changed: 90 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -332,135 +332,136 @@ let output_struct_sig loc s =
332332
type enum_op =
333333
| Enum_to_sexp
334334
| Enum_of_sexp
335-
| Enum_get of prim * (label Loc.loc * int64) list
336-
| Enum_set of prim * (label Loc.loc * int64) list
337-
| Enum_print of (label Loc.loc * int64) list
338-
| Enum_parse of (label Loc.loc * int64) list
339-
340-
let enum_print name =
341-
sprintf "%s_to_string" name.txt
342-
343-
let enum_parse name =
344-
sprintf "string_to_%s" name.txt
345-
346-
let enum_op_name name = function
347-
| Enum_to_sexp -> sprintf "sexp_of_%s" name.txt
348-
| Enum_of_sexp -> sprintf "%s_of_sexp" name.txt
349-
| Enum_get _ -> sprintf "int_to_%s" name.txt
350-
| Enum_set _ -> sprintf "%s_to_int" name.txt
351-
| Enum_print _ -> enum_print name
352-
| Enum_parse _ -> enum_parse name
353-
354-
let declare_enum_expr name = function
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))
360+
in
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))
371+
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
355379
| Enum_to_sexp ->
356-
[%expr Sexplib.Sexp.Atom ([%e Ast.evar (enum_print name)] x) ]
380+
[%expr Sexplib.Sexp.Atom ([%e Ast.evar (enum_op_name cenum Enum_print)] x) ]
357381
| Enum_of_sexp ->
358382
[%expr
359383
match x with
360384
| Sexplib.Sexp.List _ ->
361385
raise (Sexplib.Pre_sexp.Of_sexp_error (Failure "expected Atom, got List", x))
362386
| Sexplib.Sexp.Atom v ->
363-
match [%e Ast.evar (enum_parse name)] v with
387+
match [%e Ast.evar (enum_op_name cenum Enum_parse)] v with
364388
| None ->
365389
raise (Sexplib.Pre_sexp.Of_sexp_error (Failure "unable to parse enum string", x))
366390
| Some r -> r
367391
]
368-
| Enum_get (prim, fields) ->
369-
let pat_integer f suffix i =
370-
Pat.constant (Pconst_integer(f i, suffix))
371-
in
372-
let pattfn = match prim with
373-
| Char ->
374-
(fun i -> Ast.pchar (Char.chr (Int64.to_int i)))
375-
| (UInt8 | UInt16) -> pat_integer Int64.to_string None
376-
| UInt32 -> pat_integer (fun i -> Int32.to_string (Int64.to_int32 i)) (Some 'l')
377-
| UInt64 -> pat_integer Int64.to_string (Some 'L')
378-
in
392+
| Enum_get ->
379393
let getters = (List.map (fun ({txt = f; _},i) ->
380-
Exp.case (pattfn i) [%expr Some [%e Ast.constr f []]]
394+
Exp.case (enum_pattern cenum i) [%expr Some [%e Ast.constr f []]]
381395
) fields) @ [Exp.case [%pat? _] [%expr None]]
382396
in
383397
Exp.match_ [%expr x] getters
384-
| Enum_set (prim, fields) ->
385-
let expr_integer f suffix i =
386-
Exp.constant (Pconst_integer(f i, suffix))
387-
in
388-
let intfn = match prim with
389-
| Char -> (fun i -> Ast.char (Char.chr (Int64.to_int i)))
390-
| (UInt8 | UInt16) -> expr_integer Int64.to_string None
391-
| UInt32 -> expr_integer (fun i -> Int32.to_string (Int64.to_int32 i)) (Some 'l')
392-
| UInt64 -> expr_integer Int64.to_string (Some 'L')
393-
in
398+
| Enum_set ->
394399
let setters = List.map (fun ({txt = f; _},i) ->
395-
Exp.case (Ast.pconstr f []) (intfn i)
400+
Exp.case (Ast.pconstr f []) (enum_integer cenum i)
396401
) fields in
397402
Exp.match_ [%expr x] setters
398-
| Enum_print fields ->
403+
| Enum_print ->
399404
let printers = List.map (fun ({txt = f; _},_) ->
400405
Exp.case (Ast.pconstr f []) (Ast.str f)
401406
) fields in
402407
Exp.match_ [%expr x] printers
403-
| Enum_parse fields ->
408+
| Enum_parse ->
404409
let parsers = List.map (fun ({txt = f; _},_) ->
405410
Exp.case (Ast.pstr f) [%expr Some [%e Ast.constr f []]]
406411
) fields in
407412
Exp.match_ [%expr x]
408413
(parsers @ [Exp.case [%pat? _] [%expr None]])
409414

410-
let enum_ops_for loc fields width ~sexp =
411-
let prim = match ty_of_string width with
412-
| None -> loc_err loc "enum: unknown width specifier %s" width
413-
| Some p -> p
414-
in
415-
let output_sexp_struct =
415+
let enum_ops_for {sexp; _} =
416+
Enum_get ::
417+
Enum_set ::
418+
Enum_print ::
419+
Enum_parse ::
420+
if sexp then
416421
[ Enum_to_sexp
417422
; Enum_of_sexp
418423
]
419-
in
420-
(Enum_get (prim, fields)) ::
421-
(Enum_set (prim, fields)) ::
422-
(Enum_print fields) ::
423-
(Enum_parse fields) ::
424-
if sexp then output_sexp_struct else []
424+
else
425+
[]
425426

426-
let enum_type_decl name fields =
427+
let enum_type_decl {name; fields; _} =
427428
let decls = List.map (fun (f,_) -> Type.constructor f) fields in
428429
Type.mk ~kind:(Ptype_variant decls) name
429430

430-
let output_enum loc name fields width ~sexp =
431-
Str.type_ Recursive [enum_type_decl name fields] ::
431+
let output_enum cenum =
432+
Str.type_ Recursive [enum_type_decl cenum] ::
432433
List.map
433434
(fun op ->
434435
[%stri
435-
let[@ocaml.warning "-32"] [%p Ast.pvar (enum_op_name name op)] =
436-
fun x -> [%e declare_enum_expr name op]
436+
let[@ocaml.warning "-32"] [%p Ast.pvar (enum_op_name cenum op)] =
437+
fun x -> [%e declare_enum_expr cenum op]
437438
])
438-
(enum_ops_for loc fields width ~sexp)
439+
(enum_ops_for cenum)
439440

440-
let enum_op_type name =
441-
let cty = Ast.tconstr name [] in
442-
let oty prim = match prim with
441+
let enum_op_type {name; prim; _} =
442+
let cty = Ast.tconstr name.txt [] in
443+
let oty = match prim with
443444
| Char -> [%type: char]
444445
| (UInt8|UInt16) -> [%type: int]
445446
| UInt32 -> [%type: int32]
446447
| UInt64 -> [%type: int64]
447448
in
448449
function
449-
| Enum_get (prim, _) -> [%type: [%t oty prim] -> [%t cty] option]
450-
| Enum_set (prim, _) -> [%type: [%t cty] -> [%t oty prim]]
451-
| Enum_print _ -> [%type: [%t cty] -> string]
452-
| Enum_parse _ -> [%type: string -> [%t cty] option]
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]
453454
| Enum_to_sexp -> [%type: [%t cty] -> Sexplib.Sexp.t]
454455
| Enum_of_sexp -> [%type: Sexplib.Sexp.t -> [%t cty]]
455456

456-
let output_enum_sig loc name fields width ~sexp =
457-
Sig.type_ Recursive [enum_type_decl name fields] ::
457+
let output_enum_sig loc (cenum:cenum) =
458+
Sig.type_ Recursive [enum_type_decl cenum] ::
458459
List.map
459460
(fun op ->
460-
let name = enum_op_name name op in
461-
let typ = enum_op_type name op in
461+
let name = enum_op_name cenum op in
462+
let typ = enum_op_type cenum op in
462463
Sig.value (Val.mk (Loc.mkloc name loc) typ))
463-
(enum_ops_for loc fields width ~sexp)
464+
(enum_ops_for cenum)
464465

465466
let constr_enum = function
466467
| {pcd_name = f; pcd_args = Pcstr_tuple []; pcd_attributes = attrs; _} ->
@@ -540,7 +541,15 @@ let cenum decl =
540541
| (f, None) -> incr_n (); (f, !n)
541542
| (f, Some i) -> n := i; (f, i)
542543
) fields in
543-
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+
}
544553

545554
let signature_item' mapper = function
546555
| {psig_desc =
@@ -550,8 +559,7 @@ let signature_item' mapper = function
550559
| {psig_desc =
551560
Psig_extension (({txt = "cenum"; _}, PStr [{pstr_desc = Pstr_type(_, [decl]); _}]), _);
552561
psig_loc = loc} ->
553-
let name, fields, width, sexp = cenum decl in
554-
output_enum_sig loc name fields width ~sexp
562+
output_enum_sig loc (cenum decl)
555563
| other ->
556564
[default_mapper.signature_item mapper other]
557565

@@ -565,9 +573,8 @@ let structure_item' mapper = function
565573
output_struct loc (cstruct decl)
566574
| {pstr_desc =
567575
Pstr_extension (({txt = "cenum"; _}, PStr [{pstr_desc = Pstr_type(_, [decl]); _}]), _);
568-
pstr_loc = loc} ->
569-
let name, fields, width, sexp = cenum decl in
570-
output_enum loc name fields width ~sexp
576+
_ } ->
577+
output_enum (cenum decl)
571578
| other ->
572579
[default_mapper.structure_item mapper other]
573580

0 commit comments

Comments
 (0)