889 lines
25 KiB
OCaml
889 lines
25 KiB
OCaml
open Ppx_sexp_conv_lib
|
|
open Conv
|
|
|
|
(* Module names below are used in error messages being tested. *)
|
|
[@@@warning "-unused-module"]
|
|
|
|
module Sum_and_polymorphic_variants = struct
|
|
type poly =
|
|
[ `No_arg
|
|
| `One_arg of int
|
|
| `One_tuple of int * string
|
|
| `Two_args of int * string
|
|
]
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ =
|
|
List.iter
|
|
(fun (value, sexp) ->
|
|
assert (sexp_of_poly value = sexp);
|
|
assert (poly_of_sexp sexp = value))
|
|
[ `No_arg, Sexp.Atom "No_arg"
|
|
; (`One_arg 1, Sexp.(List [ Atom "One_arg"; Atom "1" ]))
|
|
; ( `One_tuple (1, "a")
|
|
, Sexp.(List [ Atom "One_tuple"; List [ Atom "1"; Atom "a" ] ]) )
|
|
; (`Two_args (1, "a"), Sexp.(List [ Atom "Two_args"; List [ Atom "1"; Atom "a" ] ]))
|
|
]
|
|
;;
|
|
|
|
type nominal =
|
|
| No_arg
|
|
| One_arg of int
|
|
| One_tuple of (int * string)
|
|
| Two_args of int * string
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ =
|
|
List.iter
|
|
(fun (value, sexp) ->
|
|
assert (sexp_of_nominal value = sexp);
|
|
assert (nominal_of_sexp sexp = value))
|
|
[ No_arg, Sexp.Atom "No_arg"
|
|
; (One_arg 1, Sexp.(List [ Atom "One_arg"; Atom "1" ]))
|
|
; (One_tuple (1, "a"), Sexp.(List [ Atom "One_tuple"; List [ Atom "1"; Atom "a" ] ]))
|
|
; (Two_args (1, "a"), Sexp.(List [ Atom "Two_args"; Atom "1"; Atom "a" ]))
|
|
]
|
|
;;
|
|
end
|
|
|
|
module Records = struct
|
|
type t =
|
|
{ a : int
|
|
; b : (float * string) list option
|
|
}
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ =
|
|
let t = { a = 2; b = Some [ 1., "a"; 2.3, "b" ] } in
|
|
let sexp = Sexplib.Sexp.of_string "((a 2)(b (((1 a)(2.3 b)))))" in
|
|
assert (t_of_sexp sexp = t);
|
|
assert (sexp_of_t t = sexp)
|
|
;;
|
|
|
|
let%expect_test _ =
|
|
let sexp = Sexplib.Sexp.of_string "((a)(b ()))" in
|
|
Expect_test_helpers_core.show_raise (fun () -> t_of_sexp sexp);
|
|
[%expect
|
|
{|
|
|
(raised (
|
|
Of_sexp_error
|
|
"ppx_sexp_test.ml.Records.t_of_sexp: record conversion: only pairs expected, their first element must be an atom"
|
|
(invalid_sexp ((a) (b ())))))
|
|
|}]
|
|
;;
|
|
|
|
let%expect_test _ =
|
|
let sexp = Sexplib.Sexp.of_string "((a 1)(a))" in
|
|
Expect_test_helpers_core.show_raise (fun () -> t_of_sexp sexp);
|
|
[%expect
|
|
{|
|
|
(raised (
|
|
Of_sexp_error
|
|
"ppx_sexp_test.ml.Records.t_of_sexp: duplicate fields: a"
|
|
(invalid_sexp ((a 1) (a)))))
|
|
|}]
|
|
;;
|
|
|
|
let%expect_test _ =
|
|
let sexp = Sexplib.Sexp.of_string "((a 3 4))" in
|
|
Expect_test_helpers_core.show_raise (fun () -> t_of_sexp sexp);
|
|
[%expect
|
|
{|
|
|
(raised (
|
|
Of_sexp_error
|
|
"ppx_sexp_test.ml.Records.t_of_sexp: record conversion: only pairs expected, their first element must be an atom"
|
|
(invalid_sexp (a 3 4))))
|
|
|}]
|
|
;;
|
|
|
|
let%expect_test _ =
|
|
let sexp = Sexplib.Sexp.of_string "((c 3))" in
|
|
Expect_test_helpers_core.show_raise (fun () -> t_of_sexp sexp);
|
|
[%expect
|
|
{|
|
|
(raised (
|
|
Of_sexp_error
|
|
"ppx_sexp_test.ml.Records.t_of_sexp: extra fields: c"
|
|
(invalid_sexp ((c 3)))))
|
|
|}]
|
|
;;
|
|
end
|
|
|
|
module Inline_records = struct
|
|
type t =
|
|
| A of
|
|
{ a : int
|
|
; b : (float * string) list option
|
|
}
|
|
| B of int
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ =
|
|
let t = A { a = 2; b = Some [ 1., "a"; 2.3, "b" ] } in
|
|
let sexp = Sexplib.Sexp.of_string "(A (a 2)(b (((1 a)(2.3 b)))))" in
|
|
assert (t_of_sexp sexp = t);
|
|
assert (sexp_of_t t = sexp)
|
|
;;
|
|
end
|
|
|
|
module User_specified_conversion = struct
|
|
type my_float = float
|
|
|
|
let sexp_of_my_float n = Sexp.Atom (Printf.sprintf "%.4f" n)
|
|
let my_float_of_sexp = float_of_sexp
|
|
|
|
let%test_unit _ =
|
|
let my_float : my_float = 1.2 in
|
|
let sexp = Sexp.Atom "1.2000" in
|
|
assert (my_float_of_sexp sexp = my_float);
|
|
assert (sexp_of_my_float my_float = sexp)
|
|
;;
|
|
end
|
|
|
|
module Exceptions : sig
|
|
(* no sexp_grammars for exceptions, as they can't be parsed *)
|
|
exception E0 [@@deriving sexp]
|
|
exception E1 of string [@@deriving sexp]
|
|
exception E2 of string * int [@@deriving sexp]
|
|
exception E_tuple of (string * int) [@@deriving sexp]
|
|
|
|
exception
|
|
E_record of
|
|
{ a : string
|
|
; b : int
|
|
}
|
|
[@@deriving sexp]
|
|
end = struct
|
|
exception E0 [@@deriving sexp]
|
|
exception E1 of string [@@deriving sexp]
|
|
exception E2 of string * int [@@deriving sexp]
|
|
exception E_tuple of (string * int) [@@deriving sexp]
|
|
|
|
exception
|
|
E_record of
|
|
{ a : string
|
|
; b : int
|
|
}
|
|
[@@deriving sexp]
|
|
|
|
let%test_unit _ =
|
|
let cases =
|
|
[ E0, "ppx_sexp_test.ml.Exceptions.E0"
|
|
; E1 "a", "(ppx_sexp_test.ml.Exceptions.E1 a)"
|
|
; E2 ("b", 2), "(ppx_sexp_test.ml.Exceptions.E2 b 2)"
|
|
; E_tuple ("c", 3), "(ppx_sexp_test.ml.Exceptions.E_tuple(c 3))"
|
|
; E_record { a = "c"; b = 3 }, "(ppx_sexp_test.ml.Exceptions.E_record(a c)(b 3))"
|
|
]
|
|
in
|
|
List.iter
|
|
(fun (exn, sexp_as_str) ->
|
|
let sexp = Sexplib.Sexp.of_string sexp_as_str in
|
|
assert ([%sexp_of: exn] exn = sexp))
|
|
cases
|
|
;;
|
|
end
|
|
|
|
module Abstract_types_are_allowed_in_structures : sig
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Manifest_types = struct
|
|
type a = { t : int }
|
|
type b = a = { t : int } [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Uses_of_exn = struct
|
|
type t = int * exn [@@deriving sexp_of]
|
|
end
|
|
|
|
module Function_types : sig
|
|
type t1 = int -> unit [@@deriving sexp, sexp_grammar]
|
|
type t2 = label:int -> ?optional:int -> unit -> unit [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type t1 = int -> unit [@@deriving sexp, sexp_grammar]
|
|
type t2 = label:int -> ?optional:int -> unit -> unit [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module No_unused_rec = struct
|
|
type r = { r : int } [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Field_name_should_not_be_rewritten = struct
|
|
open No_unused_rec
|
|
|
|
type nonrec r = { r : r }
|
|
|
|
let _ = fun (r : r) -> r.r
|
|
end
|
|
|
|
module Polymorphic_variant_inclusion = struct
|
|
type sub1 =
|
|
[ `C1
|
|
| `C2
|
|
]
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
type 'b sub2 =
|
|
[ `C4
|
|
| `C5 of 'b
|
|
]
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
type ('a, 'b) t = [ sub1 | `C3 of [ `Nested of 'a ] | 'b sub2 | `C6 ] option
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ =
|
|
let cases : ((string * string, float) t * _) list =
|
|
[ None, "()"
|
|
; Some `C1, "(C1)"
|
|
; Some `C2, "(C2)"
|
|
; Some (`C3 (`Nested ("a", "b"))), "((C3 (Nested (a b))))"
|
|
; Some `C4, "(C4)"
|
|
; Some (`C5 1.5), "((C5 1.5))"
|
|
; Some `C6, "(C6)"
|
|
]
|
|
in
|
|
List.iter
|
|
(fun (t, sexp_as_str) ->
|
|
let sexp = Sexplib.Sexp.of_string sexp_as_str in
|
|
assert ([%of_sexp: (string * string, float) t] sexp = t);
|
|
assert ([%sexp_of: (string * string, float) t] t = sexp))
|
|
cases
|
|
;;
|
|
|
|
type sub1_alias = sub1 [@@deriving sexp_poly, sexp_grammar]
|
|
|
|
type u =
|
|
[ `A
|
|
| sub1_alias
|
|
| `D
|
|
]
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ =
|
|
let cases : (u * _) list = [ `A, "A"; `C1, "C1"; `C2, "C2"; `D, "D" ] in
|
|
List.iter
|
|
(fun (u, sexp_as_str) ->
|
|
let sexp = Sexplib.Sexp.of_string sexp_as_str in
|
|
assert ([%of_sexp: u] sexp = u);
|
|
assert ([%sexp_of: u] u = sexp))
|
|
cases
|
|
;;
|
|
end
|
|
|
|
module Polymorphic_record_field = struct
|
|
type 'x t =
|
|
{ poly : 'a 'b. 'a list
|
|
; maybe_x : 'x option
|
|
}
|
|
[@@deriving sexp]
|
|
|
|
let%test_unit _ =
|
|
let t x = { poly = []; maybe_x = Some x } in
|
|
let sexp = Sexplib.Sexp.of_string "((poly ())(maybe_x (1)))" in
|
|
assert (t_of_sexp int_of_sexp sexp = t 1);
|
|
assert (sexp_of_t sexp_of_int (t 1) = sexp)
|
|
;;
|
|
end
|
|
|
|
module No_unused_value_warnings : sig end = struct
|
|
module No_warning : sig
|
|
type t = [ `A ] [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type t = [ `A ] [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Empty = struct end
|
|
|
|
module No_warning2 (X : sig
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end) =
|
|
struct end
|
|
|
|
(* this one can't be handled (what if Empty was a functor, huh?) *)
|
|
(* module No_warning3(X : sig type t with sexp end) = Empty *)
|
|
module type S = sig
|
|
type t = [ `A ] [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module No_warning4 : S = struct
|
|
type t = [ `A ] [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module No_warning5 : S = (
|
|
(
|
|
struct
|
|
type t = [ `A ] [@@deriving sexp, sexp_grammar]
|
|
end :
|
|
S) :
|
|
S)
|
|
|
|
module Nested_functors (M1 : sig
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end) (M2 : sig
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end) =
|
|
struct end
|
|
|
|
let () =
|
|
let module M : sig
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end
|
|
in
|
|
()
|
|
;;
|
|
|
|
module Include = struct
|
|
include (
|
|
struct
|
|
type t = int [@@deriving sexp, sexp_grammar]
|
|
end :
|
|
sig
|
|
type t [@@deriving sexp, sexp_grammar]
|
|
end
|
|
with type t := int)
|
|
end
|
|
end
|
|
|
|
module Default = struct
|
|
type t = { a : int [@default 2] } [@@deriving sexp, sexp_grammar]
|
|
|
|
let%test _ = Sexp.(List [ List [ Atom "a"; Atom "1" ] ]) = sexp_of_t { a = 1 }
|
|
let%test _ = Sexp.(List [ List [ Atom "a"; Atom "2" ] ]) = sexp_of_t { a = 2 }
|
|
let%test _ = t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "1" ] ]) = { a = 1 }
|
|
let%test _ = t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "2" ] ]) = { a = 2 }
|
|
let%test _ = t_of_sexp Sexp.(List []) = { a = 2 }
|
|
end
|
|
|
|
module Type_alias = struct
|
|
(* checking that the [as 'a] is supported and ignored in signatures, that it still
|
|
exports the sexp_of_t__ when needed *)
|
|
module B : sig
|
|
type a = [ `A ]
|
|
type t = [ `A ] as 'a constraint 'a = a [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type a = [ `A ] [@@deriving sexp, sexp_grammar]
|
|
type t = [ `A ] [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
let%test _ = Sexp.to_string (B.sexp_of_t `A) = "A"
|
|
let%test _ = `A = B.t_of_sexp (Sexplib.Sexp.of_string "A")
|
|
|
|
module B2 = struct
|
|
type t =
|
|
[ B.t
|
|
| `B
|
|
]
|
|
[@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module C : sig
|
|
type t = int as 'a [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type t = int [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module D : sig
|
|
type t = 'a constraint 'a = int [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type t = int [@@deriving sexp, sexp_grammar]
|
|
end
|
|
end
|
|
|
|
module Tricky_variants = struct
|
|
(* Checking that the generated code compiles (there used to be a problem with subtyping
|
|
constraints preventing proper generalization). *)
|
|
type t = [ `a ] [@@deriving sexp, sexp_grammar]
|
|
type 'a u = [ t | `b of 'a ] * int [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Drop_default = struct
|
|
open! Base
|
|
open Expect_test_helpers_core
|
|
|
|
type t = { a : int } [@@deriving equal]
|
|
|
|
let test ?cr t_of_sexp sexp_of_t =
|
|
let ( = ) = Sexp.( = ) in
|
|
require ?cr [%here] (Sexp.(List [ List [ Atom "a"; Atom "1" ] ]) = sexp_of_t { a = 1 });
|
|
require ?cr [%here] (Sexp.(List []) = sexp_of_t { a = 2 });
|
|
let ( = ) = equal in
|
|
require ?cr [%here] (t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "1" ] ]) = { a = 1 });
|
|
require ?cr [%here] (t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "2" ] ]) = { a = 2 });
|
|
require ?cr [%here] (t_of_sexp Sexp.(List []) = { a = 2 })
|
|
;;
|
|
|
|
type my_int = int [@@deriving sexp, sexp_grammar]
|
|
|
|
module Poly = struct
|
|
type nonrec t = t = { a : my_int [@default 2] [@sexp_drop_default Poly.( = )] }
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ = test t_of_sexp sexp_of_t
|
|
end
|
|
|
|
module Equal = struct
|
|
let equal_my_int = equal_int
|
|
|
|
type nonrec t = t = { a : my_int [@default 2] [@sexp_drop_default.equal] }
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ = test t_of_sexp sexp_of_t
|
|
end
|
|
|
|
module Compare = struct
|
|
let compare_my_int = compare_int
|
|
|
|
type nonrec t = t = { a : my_int [@default 2] [@sexp_drop_default.compare] }
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ = test t_of_sexp sexp_of_t
|
|
end
|
|
|
|
module Sexp = struct
|
|
type nonrec t = t = { a : my_int [@default 2] [@sexp_drop_default.sexp] }
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ = test t_of_sexp sexp_of_t
|
|
end
|
|
end
|
|
|
|
module Drop_if = struct
|
|
type t = { a : int [@default 2] [@sexp_drop_if fun x -> x mod 2 = 0] }
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test _ = Sexp.(List [ List [ Atom "a"; Atom "1" ] ]) = sexp_of_t { a = 1 }
|
|
let%test _ = Sexp.(List []) = sexp_of_t { a = 2 }
|
|
let%test _ = Sexp.(List [ List [ Atom "a"; Atom "3" ] ]) = sexp_of_t { a = 3 }
|
|
let%test _ = Sexp.(List []) = sexp_of_t { a = 4 }
|
|
let%test _ = t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "1" ] ]) = { a = 1 }
|
|
let%test _ = t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "2" ] ]) = { a = 2 }
|
|
let%test _ = t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "3" ] ]) = { a = 3 }
|
|
let%test _ = t_of_sexp Sexp.(List [ List [ Atom "a"; Atom "4" ] ]) = { a = 4 }
|
|
let%test _ = t_of_sexp Sexp.(List []) = { a = 2 }
|
|
|
|
type u =
|
|
{ a : int
|
|
[@sexp_drop_if
|
|
fun x ->
|
|
(* pa_type_conv used to drop parens altogether, causing type errors in the
|
|
following code *)
|
|
let pair = x, 2 in
|
|
match Some pair with
|
|
| None -> true
|
|
| Some (x, y) -> x = y]
|
|
}
|
|
[@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Omit_nil = struct
|
|
type natural_option = int
|
|
|
|
let sexp_of_natural_option i = if i >= 0 then sexp_of_int i else sexp_of_unit ()
|
|
|
|
let natural_option_of_sexp = function
|
|
| Sexp.List [] -> -1
|
|
| sexp -> int_of_sexp sexp
|
|
;;
|
|
|
|
let natural_option_sexp_grammar : natural_option Sexplib0.Sexp_grammar.t =
|
|
{ untyped = Union [ List Empty; Integer ] }
|
|
;;
|
|
|
|
let check sexp_of_t t_of_sexp str t =
|
|
let sexp = Sexplib.Sexp.of_string str in
|
|
assert (sexp = sexp_of_t t);
|
|
assert (t_of_sexp sexp = t)
|
|
;;
|
|
|
|
type t = { a : natural_option [@sexp.omit_nil] } [@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ = check sexp_of_t t_of_sexp "()" { a = -1 }
|
|
let%test_unit _ = check sexp_of_t t_of_sexp "((a 1))" { a = 1 }
|
|
|
|
type t2 = A of { a : int list [@sexp.omit_nil] } [@@deriving sexp, sexp_grammar]
|
|
|
|
let%test_unit _ = check sexp_of_t2 t2_of_sexp "(A)" (A { a = [] })
|
|
let%test_unit _ = check sexp_of_t2 t2_of_sexp "(A (a (1)))" (A { a = [ 1 ] })
|
|
end
|
|
|
|
module No_unused_rec_warning = struct
|
|
type r = { field : r -> unit } [@@deriving sexp_of]
|
|
end
|
|
|
|
module True_and_false = struct
|
|
type t =
|
|
| True
|
|
| False
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test _ = Sexp.to_string (sexp_of_t True) = "True"
|
|
let%test _ = Sexp.to_string (sexp_of_t False) = "False"
|
|
let%test _ = True = t_of_sexp (Sexplib.Sexp.of_string "True")
|
|
let%test _ = False = t_of_sexp (Sexplib.Sexp.of_string "False")
|
|
let%test _ = True = t_of_sexp (Sexplib.Sexp.of_string "true")
|
|
let%test _ = False = t_of_sexp (Sexplib.Sexp.of_string "false")
|
|
|
|
type u =
|
|
| True of int
|
|
| False of int
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test _ = Sexp.to_string (sexp_of_u (True 1)) = "(True 1)"
|
|
let%test _ = Sexp.to_string (sexp_of_u (False 2)) = "(False 2)"
|
|
let%test _ = True 1 = u_of_sexp (Sexplib.Sexp.of_string "(True 1)")
|
|
let%test _ = False 2 = u_of_sexp (Sexplib.Sexp.of_string "(False 2)")
|
|
let%test _ = True 1 = u_of_sexp (Sexplib.Sexp.of_string "(true 1)")
|
|
let%test _ = False 2 = u_of_sexp (Sexplib.Sexp.of_string "(false 2)")
|
|
|
|
exception True [@@deriving sexp]
|
|
|
|
let%test _ = "ppx_sexp_test.ml.True_and_false.True" = Sexp.to_string (sexp_of_exn True)
|
|
|
|
exception False of int [@@deriving sexp]
|
|
|
|
let%test _ =
|
|
"(ppx_sexp_test.ml.True_and_false.False 1)" = Sexp.to_string (sexp_of_exn (False 1))
|
|
;;
|
|
|
|
type v =
|
|
[ `True
|
|
| `False of int
|
|
]
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let%test _ = Sexp.to_string (sexp_of_v `True) = "True"
|
|
let%test _ = Sexp.to_string (sexp_of_v (`False 2)) = "(False 2)"
|
|
end
|
|
|
|
module Gadt = struct
|
|
let is_eq sexp str =
|
|
let sexp2 = Sexplib.Sexp.of_string str in
|
|
if sexp <> sexp2
|
|
then (
|
|
Printf.printf "%S vs %S\n%!" (Sexp.to_string sexp) str;
|
|
assert false)
|
|
;;
|
|
|
|
(* plain type without argument *)
|
|
type 'a s = Packed : 'a s [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: int s] Packed) "Packed"
|
|
|
|
(* two kind of existential variables *)
|
|
type 'a t = Packed : 'a * _ * ('b[@sexp.opaque]) -> 'a t [@warning "-3"]
|
|
[@@deriving sexp_of]
|
|
|
|
let%test_unit _ =
|
|
is_eq ([%sexp_of: int t] (Packed (2, "asd", 1.))) "(Packed 2 _ <opaque>)"
|
|
;;
|
|
|
|
(* plain type with argument *)
|
|
type 'a u = A : 'a -> 'a u [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: int u] (A 2)) "(A 2)"
|
|
|
|
(* recursive *)
|
|
type v = A : v option -> v [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: v] (A (Some (A None)))) "(A((A())))"
|
|
|
|
(* implicit existential variable *)
|
|
type w = A : 'a * int * ('a -> string) -> w [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: w] (A (1., 2, string_of_float))) "(A _ 2 <fun>)"
|
|
|
|
(* tricky variable naming *)
|
|
type 'a x = A : 'a -> 'b x [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: int x] (A 1.)) "(A _)"
|
|
|
|
(* interaction with inline record *)
|
|
type _ x2 = A : { x : 'c } -> 'c x2 [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: int x2] (A { x = 1 })) "(A (x 1))"
|
|
|
|
(* unused but colliding variables *)
|
|
type (_, _) y = A : ('a, 'a) y [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: (int, int) y] A) "A"
|
|
|
|
(* making sure we're not reversing parameters *)
|
|
type (_, _) z = A : ('a * 'b) -> ('a, 'b) z [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: (int, string) z] (A (1, "a"))) "(A (1 a))"
|
|
|
|
(* interaction with universal quantifiers *)
|
|
type _ z2 = A : { x : 'c. 'c option } -> 'c z2 [@@deriving sexp_of]
|
|
|
|
let%test_unit _ = is_eq ([%sexp_of: unit z2] (A { x = None })) "(A (x ()))"
|
|
end
|
|
|
|
module Anonymous_variable = struct
|
|
type _ t = int [@@deriving sexp, sexp_grammar]
|
|
|
|
let%test _ = Sexp.to_string ([%sexp_of: _ t] 2) = "2"
|
|
let%test _ = [%of_sexp: _ t] (Sexplib.Sexp.of_string "2") = 2
|
|
|
|
(* making sure we don't generate signatures like (_ -> Sexp.t) -> _ t -> Sexp.t which
|
|
are too general *)
|
|
module M : sig
|
|
type _ t [@@deriving sexp, sexp_grammar]
|
|
end = struct
|
|
type 'a t = 'a [@@deriving sexp, sexp_grammar]
|
|
end
|
|
end
|
|
|
|
module Record_field_disambiguation = struct
|
|
type a =
|
|
{ fl : float
|
|
; b : b
|
|
}
|
|
|
|
and b = { fl : int } [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Private = struct
|
|
type t = private int [@@deriving sexp_of]
|
|
type ('a, 'b) u = private t [@@deriving sexp_of]
|
|
type ('a, 'b, 'c) v = private ('a, 'b) u [@@deriving sexp_of]
|
|
end
|
|
|
|
module Nonregular_types = struct
|
|
type 'a nonregular =
|
|
| Leaf of 'a
|
|
| Branch of ('a * 'a) nonregular
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
type 'a variant = [ `A of 'a ] [@@deriving sexp, sexp_grammar]
|
|
|
|
type ('a, 'b) nonregular_with_variant =
|
|
| Branch of ([ | 'a list variant ], 'b) nonregular_with_variant
|
|
[@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Opaque = struct
|
|
type t = (int[@sexp.opaque]) list [@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "(<opaque> <opaque>)"
|
|
let t = [ 1; 2 ]
|
|
let%test _ = sexp_of_t t = sexp
|
|
|
|
let%test _ =
|
|
match t_of_sexp sexp with
|
|
| _ -> false
|
|
| exception _ -> true
|
|
;;
|
|
|
|
type u = ([ `A of int ][@sexp.opaque]) [@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "<opaque>"
|
|
let u = `A 1
|
|
let%test _ = sexp_of_u u = sexp
|
|
|
|
let%test _ =
|
|
match u_of_sexp sexp with
|
|
| _ -> false
|
|
| exception _ -> true
|
|
;;
|
|
end
|
|
|
|
module Optional = struct
|
|
type t = { optional : int option [@sexp.option] } [@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "()"
|
|
let t = { optional = None }
|
|
let%test _ = t_of_sexp sexp = t
|
|
let%test _ = sexp_of_t t = sexp
|
|
let sexp = Sexplib.Sexp.of_string "((optional 5))"
|
|
let t = { optional = Some 5 }
|
|
let%test _ = t_of_sexp sexp = t
|
|
let%test _ = sexp_of_t t = sexp
|
|
end
|
|
|
|
module Nonempty = struct
|
|
type t =
|
|
{ list : int list [@sexp.list]
|
|
; array : int array [@sexp.array]
|
|
}
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "()"
|
|
let t = { list = []; array = [||] }
|
|
let%test _ = t_of_sexp sexp = t
|
|
let%test _ = sexp_of_t t = sexp
|
|
let sexp = Sexplib.Sexp.of_string "((list (1 2 3)) (array (3 2 1)))"
|
|
let t = { list = [ 1; 2; 3 ]; array = [| 3; 2; 1 |] }
|
|
let%test _ = t_of_sexp sexp = t
|
|
let%test _ = sexp_of_t t = sexp
|
|
end
|
|
|
|
module Boolean = struct
|
|
type t = { no_arg : bool [@sexp.bool] } [@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "()"
|
|
let t = { no_arg = false }
|
|
let%test _ = t_of_sexp sexp = t
|
|
let%test _ = sexp_of_t t = sexp
|
|
let sexp = Sexplib.Sexp.of_string "((no_arg))"
|
|
let t = { no_arg = true }
|
|
let%test _ = t_of_sexp sexp = t
|
|
let%test _ = sexp_of_t t = sexp
|
|
|
|
type t_allow_extra_fields = { no_arg : bool [@sexp.bool] }
|
|
[@@deriving sexp, sexp_grammar] [@@sexp.allow_extra_fields]
|
|
|
|
let%expect_test _ =
|
|
Expect_test_helpers_core.require_does_raise ~cr:CR_soon [%here] (fun () ->
|
|
let r = t_allow_extra_fields_of_sexp (Sexplib.Sexp.of_string "((no_arg true))") in
|
|
print_endline (Bool.to_string r.no_arg));
|
|
[%expect
|
|
{|
|
|
(Of_sexp_error
|
|
"ppx_sexp_test.ml.Boolean.t_allow_extra_fields_of_sexp: record conversion: a [sexp.bool] field was given a payload."
|
|
(invalid_sexp ((no_arg true))))
|
|
|}]
|
|
;;
|
|
end
|
|
|
|
module Inline = struct
|
|
type t = A of int list [@sexp.list] [@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "(A 1 2 3)"
|
|
let t = A [ 1; 2; 3 ]
|
|
let%test _ = t_of_sexp sexp = t
|
|
let%test _ = sexp_of_t t = sexp
|
|
|
|
type u = [ `A of int list [@sexp.list] ] [@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "(A 1 2 3)"
|
|
let u = `A [ 1; 2; 3 ]
|
|
let%test _ = u_of_sexp sexp = u
|
|
let%test _ = sexp_of_u u = sexp
|
|
end
|
|
|
|
module Variance = struct
|
|
type (+'a, -'b, 'c, +_, -_, _) t [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Clash = struct
|
|
(* Same name for type-var and type-name; must be careful when introducing rigid type names. *)
|
|
type 'hey hey = Hey of 'hey [@@deriving sexp, sexp_grammar]
|
|
type 'hey rigid_hey = Hey of 'hey [@@deriving sexp, sexp_grammar]
|
|
type ('foo, 'rigid_foo) foo = Foo of 'foo [@@deriving sexp, sexp_grammar]
|
|
type 'rigid_bar rigid_rigid_bar = Bar [@@deriving sexp, sexp_grammar]
|
|
end
|
|
|
|
module Applicative_functor_types = struct
|
|
module Bidirectional_map = struct
|
|
type ('k1, 'k2) t
|
|
|
|
module S (K1 : sig
|
|
type t
|
|
end) (K2 : sig
|
|
type t
|
|
end) =
|
|
struct
|
|
type nonrec t = (K1.t, K2.t) t
|
|
end
|
|
|
|
module type Of_sexpable = sig
|
|
type t [@@deriving of_sexp, sexp_grammar]
|
|
end
|
|
|
|
let s__t_of_sexp
|
|
(type k1 k2)
|
|
(module K1 : Of_sexpable with type t = k1)
|
|
(module K2 : Of_sexpable with type t = k2)
|
|
(_ : Sexp.t)
|
|
: (k1, k2) t
|
|
=
|
|
assert false
|
|
;;
|
|
|
|
(* You would actually have to write this manually for functors. *)
|
|
let s__t_sexp_grammar
|
|
(type k1 k2)
|
|
(module K1 : Of_sexpable with type t = k1)
|
|
(module K2 : Of_sexpable with type t = k2)
|
|
=
|
|
[%sexp_grammar: (K1.t * K2.t) list]
|
|
;;
|
|
end
|
|
|
|
module Int = struct
|
|
type t = int [@@deriving of_sexp, sexp_grammar]
|
|
end
|
|
|
|
module String = struct
|
|
type t = string [@@deriving of_sexp, sexp_grammar]
|
|
end
|
|
|
|
module M : sig
|
|
type t = Bidirectional_map.S(String)(Int).t [@@deriving of_sexp, sexp_grammar]
|
|
end = struct
|
|
type t = Bidirectional_map.S(String)(Int).t [@@deriving of_sexp, sexp_grammar]
|
|
end
|
|
end
|
|
|
|
module Type_extensions = struct
|
|
let _ = ([%sexp_of: int] : [%sexp_of: int])
|
|
let _ = ([%of_sexp: int] : [%of_sexp: int])
|
|
end
|
|
|
|
module Allow_extra_fields = struct
|
|
let should_raise f x =
|
|
try
|
|
ignore (f x);
|
|
false
|
|
with
|
|
| _ -> true
|
|
;;
|
|
|
|
module M1 = struct
|
|
type t1 = { a : int } [@@deriving sexp]
|
|
type t2 = t1 = { a : int } [@@deriving sexp, sexp_grammar] [@@sexp.allow_extra_fields]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "((a 1))"
|
|
let sexp_extra = Sexplib.Sexp.of_string "((a 1)(b 2))"
|
|
let%test _ = t2_of_sexp sexp = t2_of_sexp sexp_extra
|
|
let%test _ = t1_of_sexp sexp = t2_of_sexp sexp
|
|
let%test _ = should_raise t1_of_sexp sexp_extra
|
|
|
|
let%expect_test _ =
|
|
Expect_test_helpers_core.require_does_raise ~cr:CR_soon [%here] (fun () ->
|
|
t2_of_sexp (Sexplib.Sexp.of_string "((a 1)(a))"));
|
|
[%expect
|
|
{|
|
|
(Of_sexp_error
|
|
"ppx_sexp_test.ml.Allow_extra_fields.M1.t2_of_sexp: duplicate fields: a"
|
|
(invalid_sexp ((a 1) (a))))
|
|
|}]
|
|
;;
|
|
end
|
|
|
|
module M2 = struct
|
|
type t1 = A of { a : int list } [@@deriving sexp]
|
|
|
|
type t2 = t1 = A of { a : int list } [@sexp.allow_extra_fields]
|
|
[@@deriving sexp, sexp_grammar]
|
|
|
|
let sexp = Sexplib.Sexp.of_string "(A (a (0)))"
|
|
let sexp_extra = Sexplib.Sexp.of_string "(A (a (0))(b 2))"
|
|
let%test _ = t2_of_sexp sexp = t2_of_sexp sexp_extra
|
|
let%test _ = t1_of_sexp sexp = t2_of_sexp sexp
|
|
let%test _ = should_raise t1_of_sexp sexp_extra
|
|
end
|
|
end
|
|
|
|
module Default_values_and_polymorphism = struct
|
|
type t =
|
|
{ a : int list [@sexp.list]
|
|
; b : 'b. 'b -> int
|
|
}
|
|
[@@deriving of_sexp]
|
|
end
|