@@ -329,98 +329,139 @@ let output_struct_sig loc s =
329
329
(op_typ op)))
330
330
(ops_for s)
331
331
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))
347
360
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))
402
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
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; _} =
403
428
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; _} =
411
442
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 ]
417
448
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)
424
465
425
466
let constr_enum = function
426
467
| {pcd_name = f ; pcd_args = Pcstr_tuple [] ; pcd_attributes = attrs ; _} ->
@@ -500,7 +541,15 @@ let cenum decl =
500
541
| (f , None) -> incr_n () ; (f, ! n)
501
542
| (f , Some i ) -> n := i; (f, i)
502
543
) 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
+ }
504
553
505
554
let signature_item' mapper = function
506
555
| {psig_desc =
@@ -510,8 +559,7 @@ let signature_item' mapper = function
510
559
| {psig_desc =
511
560
Psig_extension (({txt = " cenum" ; _}, PStr [{pstr_desc = Pstr_type (_, [decl]); _}]), _);
512
561
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)
515
563
| other ->
516
564
[default_mapper.signature_item mapper other]
517
565
@@ -525,9 +573,8 @@ let structure_item' mapper = function
525
573
output_struct loc (cstruct decl)
526
574
| {pstr_desc =
527
575
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)
531
578
| other ->
532
579
[default_mapper.structure_item mapper other]
533
580
0 commit comments