pax_global_header00006660000000000000000000000064146164733610014525gustar00rootroot0000000000000052 comment=394c0fe053bb7ccc90d90656db35b956ee98db3f ppx_sexp_value-0.17.0/000077500000000000000000000000001461647336100146545ustar00rootroot00000000000000ppx_sexp_value-0.17.0/.gitignore000066400000000000000000000000411461647336100166370ustar00rootroot00000000000000_build *.install *.merlin _opam ppx_sexp_value-0.17.0/.ocamlformat000066400000000000000000000000231461647336100171540ustar00rootroot00000000000000profile=janestreet ppx_sexp_value-0.17.0/CHANGES.md000066400000000000000000000003601461647336100162450ustar00rootroot00000000000000## v0.11 - Depend on ppxlib instead of (now deprecated) ppx\_core, ppx\_driver and ppx\_metaquot. ## 113.43.00 - Allow to use `sexp_option` in more places in ppx\_sexp\_value, to make it to display information only some of the time. ppx_sexp_value-0.17.0/CONTRIBUTING.md000066400000000000000000000044101461647336100171040ustar00rootroot00000000000000This repository contains open source software that is developed and maintained by [Jane Street][js]. Contributions to this project are welcome and should be submitted via GitHub pull requests. Signing contributions --------------------- We require that you sign your contributions. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below (from [developercertificate.org][dco]): ``` Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 1 Letterman Drive Suite D4700 San Francisco, CA, 94129 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` Then you just add a line to every git commit message: ``` Signed-off-by: Joe Smith ``` Use your real name (sorry, no pseudonyms or anonymous contributions.) If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with git commit -s. [dco]: http://developercertificate.org/ [js]: https://opensource.janestreet.com/ ppx_sexp_value-0.17.0/LICENSE.md000066400000000000000000000021461461647336100162630ustar00rootroot00000000000000The MIT License Copyright (c) 2015--2024 Jane Street Group, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ppx_sexp_value-0.17.0/Makefile000066400000000000000000000004031461647336100163110ustar00rootroot00000000000000INSTALL_ARGS := $(if $(PREFIX),--prefix $(PREFIX),) default: dune build install: dune install $(INSTALL_ARGS) uninstall: dune uninstall $(INSTALL_ARGS) reinstall: uninstall install clean: dune clean .PHONY: default install uninstall reinstall clean ppx_sexp_value-0.17.0/README.md000066400000000000000000000062061461647336100161370ustar00rootroot00000000000000ppx_sexp_value ============== A ppx rewriter that simplifies building s-expressions from ocaml values. Basic use --------- The building block of this preprocessor is the extension: ```ocaml [%sexp expr] ``` in expressions. It evaluates to an s-expression. This is done by recursing down the expression and converting all data constructors into s-expressions. If an expression with a type annotation is found, then the type is used to convert to s-expression. Expressions that are neither data constructors nor annotated with a type will be rejected. For instance: ```ocaml [%sexp { a = "hello" ; b = (Time.now () : Time.t) } ] ``` will be preprocessed into: ```ocaml List [List [Atom "a"; Atom "hello"]; List [Atom "b"; [%sexp_of: Time.t] (Time.now ())]; ] ``` This does not require a record with fields a and b to exist (and if one does exist, its sexp_of function will be ignored unless a type annotation is added around the record). One can annotate a record field with the attribute `[@sexp.option]` or with `[@sexp.omit_nil]` to achieve the same result as when using sexplib. They both have the same behavior inside tuples. Variant, polymorphic variants, tuples and lists are supported as well. Variants are analogous to records in that a type containing the variant does not have to exist unless a type annotation is added to the variant. Expressions with their evaluations ---------------------------------- It is sometimes convenient to include the expression itself in the s-expression. This is especially true for debugging, as it avoids having to think of a label for a value; one can simply use the expression itself. Ppx\_sexp\_value allows this by reserving the `~~` operator. Inside `[%sexp]`, `~~` is the same as `("", )`, where the type annotation in `` is stripped off in the s-expression (`~~` isn't allowed if `` is a data constructor). For instance: ```ocaml [%sexp (~~(x : int), ~~(y + z : int), "literal") ] ``` will be preprocessed into: ```ocaml List [List [Atom "x"; [%sexp_of: int] x]; List [Atom "y + z"; [%sexp_of: int] (y + z)]; [%sexp_of: string] "literal"; ] ``` Recommended use for errors -------------------------- This extension is primarily intended to build better errors, by making building errors easier and more readable, particularly when using records to add context: ```ocaml try Unix.rename ~src:tmpfile ~dst with exn -> raise_s [%sexp "Error while renaming file", { source = (tmpfile : string) ; dest = (dst : string) ; exn = (exn : exn ) } ] ``` Eagerness -------- The extension `[%lazy_sexp]` is additionally provided, which just wraps the generated code in `[lazy]` to delay computing and allocating of possibly large sexps. This is intended to be used with, for example, `[Error.of_lazy_sexp]`, where the error messages may be large, but are typically not used: ```ocaml let execute_query_exn ~database ~query = Database.execute_query ~database ~query |> Option.value_exn ~error: (Error.of_lazy_sexp [%lazy_sexp ("Query failed", { database : Database.t; query : Query.t })]) ``` ppx_sexp_value-0.17.0/dune000066400000000000000000000000001461647336100155200ustar00rootroot00000000000000ppx_sexp_value-0.17.0/dune-project000066400000000000000000000000211461647336100171670ustar00rootroot00000000000000(lang dune 3.11) ppx_sexp_value-0.17.0/example/000077500000000000000000000000001461647336100163075ustar00rootroot00000000000000ppx_sexp_value-0.17.0/example/dune000066400000000000000000000002551461647336100171670ustar00rootroot00000000000000(library (name example_ppx_sexp_value_lib) (libraries core core_unix.time_float_unix) (preprocess (pps ppx_sexp_value))) (alias (name DEFAULT) (deps example.ml.pp)) ppx_sexp_value-0.17.0/example/example.ml000066400000000000000000000010001461647336100202630ustar00rootroot00000000000000open Core module Unix = Core_unix module Time = Time_float_unix (* Examples from ../README.md *) let _basic_use = [%sexp { a = "hello"; b = (Time.now () : Time.t) }] let _expressions_with_their_evaluations ~x ~y ~z = [%sexp ~~(x : int), (y + z : int), "literal"] ;; let _recomended_use_for_errors ~tmpfile ~dst = try Unix.rename ~src:tmpfile ~dst with | exn -> raise_s [%sexp "Error while renaming file" , { source = (tmpfile : string); dest = (dst : string); exn : exn }] ;; ppx_sexp_value-0.17.0/example/example.mli000066400000000000000000000000001461647336100204330ustar00rootroot00000000000000ppx_sexp_value-0.17.0/ppx_sexp_value.opam000066400000000000000000000015661461647336100206040ustar00rootroot00000000000000opam-version: "2.0" version: "v0.17.0" maintainer: "Jane Street developers" authors: ["Jane Street Group, LLC"] homepage: "https://github.com/janestreet/ppx_sexp_value" bug-reports: "https://github.com/janestreet/ppx_sexp_value/issues" dev-repo: "git+https://github.com/janestreet/ppx_sexp_value.git" doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/ppx_sexp_value/index.html" license: "MIT" build: [ ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "5.1.0"} "base" {>= "v0.17" & < "v0.18"} "ppx_here" {>= "v0.17" & < "v0.18"} "ppx_sexp_conv" {>= "v0.17" & < "v0.18"} "dune" {>= "3.11.0"} "ppxlib" {>= "0.28.0"} ] available: arch != "arm32" & arch != "x86_32" synopsis: "A ppx rewriter that simplifies building s-expressions from ocaml values" description: " Part of the Jane Street's PPX rewriters collection. " ppx_sexp_value-0.17.0/src/000077500000000000000000000000001461647336100154435ustar00rootroot00000000000000ppx_sexp_value-0.17.0/src/dune000066400000000000000000000003571461647336100163260ustar00rootroot00000000000000(library (name ppx_sexp_value) (public_name ppx_sexp_value) (kind ppx_rewriter) (ppx_runtime_libraries ppx_sexp_conv.runtime-lib) (libraries base ppxlib ppx_sexp_conv.expander ppx_here.expander) (preprocess (pps ppxlib.metaquot))) ppx_sexp_value-0.17.0/src/ppx_sexp_value.ml000066400000000000000000000173071461647336100210470ustar00rootroot00000000000000open Base open Ppxlib open Ast_builder.Default let omit_nil = Attribute.declare "sexp_value.sexp.omit_nil" Attribute.Context.core_type Ast_pattern.(pstr nil) () ;; let option = Attribute.declare "sexp_value.sexp.option" Attribute.Context.core_type Ast_pattern.(pstr nil) () ;; let sexp_atom ~loc x = [%expr Ppx_sexp_conv_lib.Sexp.Atom [%e x]] let sexp_list ~loc x = [%expr Ppx_sexp_conv_lib.Sexp.List [%e x]] let rec list_and_tail_of_ast_list rev_el e = match e.pexp_desc with | Pexp_construct ({ txt = Lident "::"; _ }, Some { pexp_desc = Pexp_tuple [ hd; tl ]; _ }) -> list_and_tail_of_ast_list (hd :: rev_el) tl | Pexp_construct ({ txt = Lident "[]"; _ }, None) -> List.rev rev_el, None | _ -> List.rev rev_el, Some e ;; let sexp_of_constant ~loc const = let f typ = eapply ~loc (evar ~loc ("Ppx_sexp_conv_lib.Conv.sexp_of_" ^ typ)) [ pexp_constant ~loc const ] in match const with | Pconst_integer _ -> f "int" | Pconst_char _ -> f "char" | Pconst_string _ -> f "string" | Pconst_float _ -> f "float" ;; type omittable_sexp = | Present of expression | Optional of (Location.t * string) * expression * (expression -> expression) (* In [Optional (_, e, k)], [e] is an ast whose values have type ['a option], and [k] is a function from ast of type ['a] to ast of type [Sexp.t]. The None case should not be displayed, and the [a] in the Some case should be displayed by calling [k] on it. *) | Omit_nil of Location.t * expression * (expression -> expression) (* In [Omit_nil (_, e, k)], [e] is an ast of type [Sexp.t], and [k] if a function ast of type [Sexp.t] and returns an other [Sexp.t]. When [e] is [List []], it should be not displayed. Otherwise [e] should be displayed by calling [k] on it. *) let wrap_sexp_if_present omittable_sexp ~f = match omittable_sexp with | Optional (loc, e, k) -> Optional (loc, e, fun e -> f (k e)) | Present e -> Present (f e) | Omit_nil (loc, e, k) -> Omit_nil (loc, e, fun e -> f (k e)) ;; let sexp_of_constraint ~loc expr ctyp = match ctyp with | [%type: [%t? ty] option] when Option.is_some (Attribute.get option ctyp) -> let sexp_of = Ppx_sexp_conv_expander.Sexp_of.core_type ty in Optional ((loc, "[@sexp.optional]"), expr, fun expr -> eapply ~loc sexp_of [ expr ]) | _ -> let expr = let sexp_of = Ppx_sexp_conv_expander.Sexp_of.core_type ctyp in eapply ~loc sexp_of [ expr ] in (match Attribute.get omit_nil ctyp with | Some () -> Omit_nil (loc, expr, Fn.id) | None -> Present expr) ;; let rec sexp_of_expr expr = match omittable_sexp_of_expr expr with | Present v -> v | Optional ((loc, s), _, _) -> Location.raise_errorf ~loc "ppx_sexp_value: cannot handle %s in this context" s | Omit_nil (loc, _, _) -> Location.raise_errorf ~loc "ppx_sexp_value: cannot handle [@omit_nil] in this context" and omittable_sexp_of_expr expr = let loc = { expr.pexp_loc with loc_ghost = true } in wrap_sexp_if_present ~f:(fun new_expr -> { new_expr with pexp_attributes = expr.pexp_attributes }) (match expr.pexp_desc with | Pexp_ifthenelse (e1, e2, e3) -> Present { expr with pexp_desc = Pexp_ifthenelse ( e1 , sexp_of_expr e2 , match e3 with | None -> None | Some e -> Some (sexp_of_expr e) ) } | Pexp_constraint (expr, ctyp) -> sexp_of_constraint ~loc expr ctyp | Pexp_construct ({ txt = Lident "[]"; _ }, None) | Pexp_construct ({ txt = Lident "::"; _ }, Some { pexp_desc = Pexp_tuple [ _; _ ]; _ }) -> let el, tl = list_and_tail_of_ast_list [] expr in let el = List.map el ~f:omittable_sexp_of_expr in let tl = match tl with | None -> [%expr []] | Some e -> [%expr match [%e sexp_of_expr e] with | Ppx_sexp_conv_lib.Sexp.List l -> l | Ppx_sexp_conv_lib.Sexp.Atom _ as sexp -> [ sexp ]] in Present (sexp_of_omittable_sexp_list loc el ~tl) | Pexp_constant const -> Present (sexp_of_constant ~loc const) | Pexp_extension ({ txt = "here"; _ }, PStr []) -> Present (sexp_atom ~loc (Ppx_here_expander.lift_position_as_string ~loc)) | Pexp_extension ({ txt = "string"; _ }, _) -> Present (sexp_atom ~loc expr) | Pexp_construct ({ txt = Lident "()"; _ }, None) -> Present (sexp_list ~loc (elist ~loc [])) | Pexp_construct ({ txt = Lident constr; _ }, None) | Pexp_variant (constr, None) -> Present (sexp_atom ~loc (estring ~loc constr)) | Pexp_construct ({ txt = Lident constr; _ }, Some arg) | Pexp_variant (constr, Some arg) -> let k hole = sexp_list ~loc (elist ~loc [ sexp_atom ~loc (estring ~loc constr); hole ]) in wrap_sexp_if_present (omittable_sexp_of_expr arg) ~f:k | Pexp_tuple el -> let el = List.map el ~f:omittable_sexp_of_expr in Present (sexp_of_omittable_sexp_list loc el ~tl:(elist ~loc [])) | Pexp_record (fields, None) -> Present (sexp_of_record ~loc fields) | Pexp_apply ( { pexp_desc = Pexp_ident { txt = Lident "~~"; _ }; _ } , [ (Nolabel, { pexp_desc = Pexp_constraint (expr, ctyp); _ }) ] ) -> let expr_str = Pprintast.string_of_expression expr in let k hole = sexp_list ~loc (elist ~loc [ sexp_atom ~loc (estring ~loc expr_str); hole ]) in wrap_sexp_if_present (sexp_of_constraint ~loc expr ctyp) ~f:k | _ -> Location.raise_errorf ~loc "ppx_sexp_value: don't know how to handle this construct") and sexp_of_omittable_sexp_list loc el ~tl = let l = List.fold_left (List.rev el) ~init:tl ~f:(fun acc e -> match e with | Present e -> [%expr [%e e] :: [%e acc]] | Optional (_, v_opt, k) -> (* We match simultaneously on the head and tail in the generated code to avoid changing their respective typing environments. *) [%expr match [%e v_opt], [%e acc] with | None, tl -> tl | Some v, tl -> [%e k [%expr v]] :: tl] | Omit_nil (_, e, k) -> [%expr match [%e e], [%e acc] with | Ppx_sexp_conv_lib.Sexp.List [], tl -> tl | v, tl -> [%e k [%expr v]] :: tl]) in sexp_list ~loc l and sexp_of_record ~loc fields = sexp_of_omittable_sexp_list loc ~tl:(elist ~loc []) (List.map fields ~f:(fun (id, e) -> let e = match e.pexp_desc with | Pexp_constraint (e', c) when Location.compare_pos id.loc.loc_start e.pexp_loc.loc_start = 0 && Location.compare e.pexp_loc e'.pexp_loc = 0 -> (* { foo : int } *) { e with pexp_desc = Pexp_constraint ({ e' with pexp_loc = id.loc }, c) } | _ -> e in let loc = { id.loc with loc_end = e.pexp_loc.loc_end; loc_ghost = true } in let name = String.concat ~sep:"." (Longident.flatten_exn id.txt) in let k hole = sexp_list ~loc (elist ~loc [ sexp_atom ~loc (estring ~loc:{ id.loc with loc_ghost = true } name) ; hole ]) in wrap_sexp_if_present (omittable_sexp_of_expr e) ~f:k)) ;; let () = Driver.register_transformation "sexp_value" ~extensions: [ Extension.declare "sexp" Extension.Context.expression Ast_pattern.(pstr (pstr_eval __ nil ^:: nil)) (fun ~loc:_ ~path:_ e -> sexp_of_expr e) ; Extension.declare "lazy_sexp" Extension.Context.expression Ast_pattern.(pstr (pstr_eval __ nil ^:: nil)) (fun ~loc ~path:_ e -> [%expr lazy [%e sexp_of_expr e]]) ] ;; ppx_sexp_value-0.17.0/src/ppx_sexp_value.mli000066400000000000000000000000001461647336100211760ustar00rootroot00000000000000ppx_sexp_value-0.17.0/test/000077500000000000000000000000001461647336100156335ustar00rootroot00000000000000ppx_sexp_value-0.17.0/test/dune000066400000000000000000000002531461647336100165110ustar00rootroot00000000000000(library (name test_ppx_sexp_value_lib) (libraries core) (preprocess (pps ppx_sexp_conv ppx_here ppx_assert ppx_sexp_value ppx_inline_test ppx_cold ppx_string))) ppx_sexp_value-0.17.0/test/test.ml000066400000000000000000000154411461647336100171510ustar00rootroot00000000000000open Core let%test_unit "polymorphic variant, variant, list, literal" = let module M = struct type normal_blop = Blop of int [@@deriving sexp_of] type variant_blop = [ `Message of string | `Blop of int ] [@@deriving sexp_of] end in [%test_result: Sexp.t] ~expect: (List [ M.sexp_of_variant_blop (`Message "string") ; M.sexp_of_variant_blop (`Blop 2) ; M.sexp_of_normal_blop (Blop 2) ]) [%sexp [ `Message "string"; `Blop 2; Blop 2 ]] ;; let%test_unit "record, if" = [%test_result: Sexp.t] ~expect: (List [ List [ Atom "message"; Atom "string" ]; List [ Atom "A.blop"; Atom "1" ] ]) [%sexp { message = "string"; A.blop = (if true then 1 else `two) }] ;; module A = struct type t = int [@@deriving sexp_of] end let a : A.t = 2 let%test_unit "tuple, explicit types" = [%test_result: Sexp.t] ~expect:(List [ Atom "2"; Atom "1" ]) [%sexp (a : A.t), (lazy 1 : int Lazy.t)] ;; let%test_unit "constructed list" = let int_list = [ 2; 3 ] in [%test_result: Sexp.t] ~expect:(List [ Atom "one"; Atom "2"; Atom "3" ]) [%sexp `one :: (int_list : int list)] ;; let%test_unit "strange case doesn't raise an exception" = [%test_result: Sexp.t] ~expect:(List [ Atom "A"; Atom "B" ]) [%sexp `A :: `B] ;; let%test_unit "sexp.option everywhere except record fields" = [%test_result: Sexp.t] ~expect: (List [ Atom "A"; List [ Atom "B"; Atom "1" ]; List [ Atom "Some \"D\""; Atom "D" ] ]) [%sexp `A , B (Some 1 : (int option[@sexp.option])) , C (None : (int option[@sexp.option])) , ~~(Some "D" : (string option[@sexp.option])) , ~~(None : (string option[@sexp.option]))] ;; let%test_module "optional record field via sexp.option" = (module struct let none = None let some x = Some x let%test_unit "absent" = [%test_result: Sexp.t] ~expect:(List [ List [ Atom "a"; Atom "1" ]; List [ Atom "c"; Atom "3" ] ]) [%sexp { a = 1; b = (none : (int option[@sexp.option])); c = 3 }] ;; let%test_unit "present" = [%test_result: Sexp.t] ~expect: (List [ List [ Atom "a"; Atom "1" ] ; List [ Atom "b"; Atom "2" ] ; List [ Atom "c"; Atom "3" ] ]) [%sexp { a = 1; b = (some 2 : (int option[@sexp.option])); c = 3 }] ;; let%test_unit "all absent" = [%test_result: Sexp.t] ~expect:(List []) [%sexp { a = (none : (int option[@sexp.option])) ; b = (none : (int option[@sexp.option])) }] ;; let%test_unit "tail as variable name" = let tail = Some [ "bar"; "bat" ] in [%test_result: Sexp.t] ~expect: (List [ List [ Atom "head"; Atom "foo" ] ; List [ Atom "tail"; List [ Atom "bar"; Atom "bat" ] ] ]) [%sexp { head = "foo"; tail : (string list option[@sexp.option]) }] ;; end) ;; let%test_unit "omit_nil" = let[@cold] check sexp str = [%test_result: string] (Sexp.to_string_hum sexp) ~expect:str in check [%sexp { a = ([ 1 ] : (int list[@omit_nil])) }] "((a (1)))"; check [%sexp { a = ([] : (int list[@omit_nil])) }] "()"; check [%sexp A, B ([ 1 ] : (int list[@omit_nil]))] "(A (B (1)))"; check [%sexp A, B ([] : (int list[@omit_nil]))] "(A)" ;; let%test_module "expressions and their evaluation" = (module struct let%test_unit "at toplevel" = let x = 1 in [%test_result: Sexp.t] ~expect:(List [ Atom "x"; Atom "1" ]) [%sexp ~~(x : int)] ;; let%test_unit "anywhere" = let x = 1 and y = 2 in [%test_result: Sexp.t] ~expect: (List [ Atom "message" ; List [ Atom "x"; Atom "1" ] ; List [ Atom "x + y"; Atom "3" ] ]) [%sexp "message", ~~(x : int), ~~(x + y : int)] ;; end) ;; let%test_unit "[%string]" = let b = "b" in [%test_result: Sexp.t] [%sexp [%string "a%{b}c"]] ~expect:[%sexp "abc"] ;; let _no_warnings_from_merlin_check_about_overlapping_locations = let module Foo = struct type t = [ `A ] let sexp_of_t _ = Sexp.Atom "A" end in let foo = `A in let maybe_foo = Some `A in ( [%sexp { foo : Foo.t }] , [%sexp { foo : [< `A ] }] , [%sexp { foo : [< Foo.t ] }] , [%sexp { maybe_foo : Foo.t option }] , [%sexp { maybe_foo : [< `A ] option }] , [%sexp { maybe_foo : [< Foo.t ] option }] ) ;; let%test_unit "[%sexp] is not lazy" = let side_effect = ref false in let _ = [%sexp (side_effect := true : unit)] in [%test_result: bool] ~expect:true !side_effect ;; let%test_unit "[%lazy_sexp] is lazy" = let side_effect = ref false in let delayed_sexp = [%lazy_sexp (side_effect := true : unit)] in [%test_result: bool] ~expect:false !side_effect; let _ = Lazy.force delayed_sexp in [%test_result: bool] ~expect:true !side_effect ;; let%test_module "[%lazy_sexp] output" = (module struct let%test_unit "polymorphic variant, variant, list, literal" = let module M = struct type normal_blop = Blop of int [@@deriving sexp_of] type variant_blop = [ `Message of string | `Blop of int ] [@@deriving sexp_of] end in [%test_result: Sexp.t] ~expect: (List [ M.sexp_of_variant_blop (`Message "string") ; M.sexp_of_variant_blop (`Blop 2) ; M.sexp_of_normal_blop (Blop 2) ]) [%sexp [ `Message "string"; `Blop 2; Blop 2 ]] ;; let%test_unit "record, if" = [%test_result: Sexp.t] ~expect: (List [ List [ Atom "message"; Atom "string" ]; List [ Atom "A.blop"; Atom "1" ] ]) [%sexp { message = "string"; A.blop = (if true then 1 else `two) }] ;; let%test_unit "tuple, explicit types" = [%test_result: Sexp.t] ~expect:(List [ Atom "2"; Atom "1" ]) [%sexp (a : A.t), (lazy 1 : int Lazy.t)] ;; let%test_unit "constructed list" = let int_list = [ 2; 3 ] in [%test_result: Sexp.t] ~expect:(List [ Atom "one"; Atom "2"; Atom "3" ]) [%sexp `one :: (int_list : int list)] ;; let%test_unit "strange case doesn't raise an exception" = [%test_result: Sexp.t] ~expect:(List [ Atom "A"; Atom "B" ]) [%sexp `A :: `B] ;; let%test_unit "sexp.option everywhere except record fields" = [%test_result: Sexp.t] ~expect: (List [ Atom "A" ; List [ Atom "B"; Atom "1" ] ; List [ Atom "Some \"D\""; Atom "D" ] ]) [%sexp `A , B (Some 1 : (int option[@sexp.option])) , C (None : (int option[@sexp.option])) , ~~(Some "D" : (string option[@sexp.option])) , ~~(None : (string option[@sexp.option]))] ;; end) ;; ppx_sexp_value-0.17.0/test/test.mli000066400000000000000000000000551461647336100173150ustar00rootroot00000000000000(*_ This signature is deliberately empty. *)