Git Product home page Git Product logo

ppx_deriving's People

Contributors

andrewray avatar anmonteiro avatar avsm avatar c-cube avatar copy avatar darioteixeira avatar drup avatar elliottcable avatar emillon avatar gasche avatar jaredly avatar jeremiedimino avatar kit-ty-kate avatar labichn avatar nathanreb avatar paurkedal avatar pqwy avatar rgrinberg avatar runoshun avatar shonfeder avatar sim642 avatar stevejb71 avatar thierry-martinez avatar twinside avatar vbmithr avatar whitequark avatar xvilka avatar ygrek avatar zepalmer avatar zoggy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ppx_deriving's Issues

Error with ppx_deriving when installing nanomq

Incompatibiliy between Ppx_deriving_runtime.string and string when installing nanomq

#=== ERROR while installing nanomsg.1.0 =======================================#
# opam-version 1.2.2
# os           linux
# command      ocaml pkg/build.ml native=true native-dynlink=true lwt=true ounit=true
# path         /home/sapristi/.opam/system/build/nanomsg.1.0
# compiler     system (4.02.3)
# exit-code    10
# env-file     /home/sapristi/.opam/system/build/nanomsg.1.0/nanomsg-13706-ad8886.env
# stdout-file  /home/sapristi/.opam/system/build/nanomsg.1.0/nanomsg-13706-ad8886.out
# stderr-file  /home/sapristi/.opam/system/build/nanomsg.1.0/nanomsg-13706-ad8886.err
### stdout ###
# [...]
# ocamlfind ocamlc -c -g -bin-annot -safe-string -package containers.bigarray -package ipaddr -package containers -package lwt.unix -package lwt.ppx -package ctypes -package ppx_deriving.std -I lib -I lib_test -o lib/nanomsg_lwt.cmi lib/nanomsg_lwt.mli
# ocamlfind ocamlc -c -g -bin-annot -safe-string -package containers.bigarray -package ctypes.foreign -package ipaddr -package containers -package lwt.unix -package lwt.ppx -package oUnit -I lib_test -I lib -o lib_test/suite.cmo lib_test/suite.ml
# + ocamlfind ocamlc -c -g -bin-annot -safe-string -package containers.bigarray -package ctypes.foreign -package ipaddr -package containers -package lwt.unix -package lwt.ppx -package oUnit -I lib_test -I lib -o lib_test/suite.cmo lib_test/suite.ml
# File "lib_test/suite.ml", line 29, characters 13-40:
# Error: This expression has type
#          Nanomsg.Addr.connect Nanomsg.Addr.t -> Ppx_deriving_runtime.string
#        but an expression was expected of type
#          Nanomsg.Addr.connect Nanomsg.Addr.t -> string
#        Type Ppx_deriving_runtime.string is not compatible with type string 
# Command exited with code 2.```

Documentation for provided plugins?

Although the README.md suggests that one should read through the included plugins in order to learn how to develop a new one, the included plugins are somewhat lacking in documentation (from what I can tell), which may be raising the entry barrier for plugin development. I would submit a PR with some in-code comments, but I'm not entirely certain that I understand ppx_deriving well enough to do this. Would it be possible to come up with more user-friendly plugin development information?

Allow ignoring/eliding fields in the standard derivers

It would be nice to be able to write:

type t = {
  id : int;
  meta : string [@ord.ignore] [@show.elide];
} [@@deriving ord, show]

to support something similar to:

assert (equal { id = 1; meta = "foo" } { id = 1; meta = "bar" });
assert ("{ id = 1; meta = ... }" = show { id = 1; meta = "elide me" });

deriving show recursive, polymorphic types

When you try to derive for a type like:

type foo = F of int | B of int bar | C of float bar
type 'a bar = { x : 'a ; r : Foo } 

You will end up with recursive functions:

let rec pp_foo ...
and pp_bar poly_a ...

However, the recursive binding does not allow for multiple instantiations of the polymorphic argument. Hence, you should probably move that out of the recursive group.

"show cannot be derived for int" for records

I'm playing around with @camlspotter's TyPPX library. With a ppx preprocessor that depends on TyPPX (an identity mapper is sufficient to reproduce this) and ppx_deriving in the same project, I get show cannot be derived for int for records:

type a = { b : int }
  [@@deriving show]

Strangely, this

type c = int
  [@@deriving show]

compiles and works fine.

show: missing parentheses around constructors

Right now, only constructors with one argument have parenthesis around them. Omitting parenthesis is ok for nullary constructors, but shouldn't be for n-ary ones (as the the output can no longer simply be pasted into the top-level):

type t = A | B of t | C of t*t [@@deriving show];;
show @@ A;; (* A *)
show @@ B A;; (* (B A) *)
show @@ C (A, A);; (* C (A, A) but should be (C (A, A)) *)
show @@ B (C (A, A));; (* (B C (A, A)) <- problem *)

Object support ?

Not sure how this would actually work, but it would be nice to have at least a pretty printer for object via ppx_deriving.

deriving first-class variant constructors/field accessor

In a similar way to variantslib and fieldslib, be able to generate functions:

type foo =
  | A of int
  | B of string * foo
  [@@deriving variants];;

(* generated *)
val a : int -> foo
val b : string -> foo -> foo

and

type space_point = {
  x : int;
  y : int;
  history : space_point list;
} [@@deriving fields];;

(* generated *)
val x : space_point -> int
val y : space_point -> int
val history : space_point -> space_point list

deriving 'eq' generates warning

utop # type t = [ `A ] [@@deriving eq];;
Characters 0-31:                                                                                                                                                                                                                                                                                                            
Warning 11: this match case is unused.                                                                                                                                                                                                                                                                                      
type t = [ `A ]                                                                                                                                                                                                                                                                                                             
val equal : t -> t -> bool = <fun>

(It does not happen with yojson, or show)

Show: [@printer] not considered in variants

Consider the following code (printer_variant.ml):

type t =
  | First [@printer fun fmt _ -> Format.fprintf fmt "first case"]
  | Second
      [@@deriving show]

let () =
  Format.printf "%a, %a@." pp First pp Second

Extrapolating from the documentation, I expect the output to be "first case, Printer_variant.Second". But:

$ ./printer_variant 
Printer_variant.First, Printer_variant.Second

Would it be possible to support adding [@printer] attributes to the cases of a variant type, so that the behavior matches my expectations?

Adding support for Big_int by default

The Big_int type from the standard library is a little bit "awkward", it doesn't fit in the standard convention. Would it be possible to have special cases to support this special case?

GADT support

As a wishlist entry.

Currently:

# type _ s = B : int -> int s | C : float -> float s [@@deriving Show];;
Error: This pattern matches values of type float s
but a pattern was expected which matches values of type int s
Type float is not compatible with type int

`eq` derived for `array` raises

# type x = int array [@@deriving eq] ;;
type x = int array
val equal_x : x -> x -> bool = <fun>
# equal_x [| |] [| |] ;;
Exception: Invalid_argument "index out of bounds".

Will PR a fix.

Assumption about List.map

The generated code uses List.map and expects a particular order for its arguments which is not the one used in Core_kernel or nonstd.

#require "ppx_deriving.show";;
type t = {x: string list} [@@deriving show];;
(*
type t = { x : bytes list; }
val pp : Format.formatter -> t -> unit = <fun>
val show : t -> bytes = <fun>
*)

module List = struct
  include ListLabels
  let map l ~f = map ~f l
end
type t = {x: string list} [@@deriving show];;
(*
Error: This expression should not be a function, the expected type is
'a list
*)

I recommend generating code that uses ListLabels.map directly, it's much less likely that anyone will override that name, and using labels will make much better error messages anyway.

Edit: comments, formatting and typos

Shouldn't "create" be "make"?

This may be an exercise in bikeshedding, but naming constructors make seems to be a more common practice. Is there a particular reason why ppx_deriving chose create?

ppx_deriving_command_line

That would be cool maybe (just thinking out “loud”):

type cmd1 = {arg1: string option; arg2: int} [@@deriving command_line]
type cmd2 = 
  {arg1: string [@short_name "a" ]; 
   arg2: int option;
   arg3: more_complex [@of_string some_fun]
   anonymous: string list}
  [@@deriving command_line]
type super_command = [
  | `cmd1 of cmd1
  | `cmd2 of cmd2
]
[@@deriving command_line]
type global_options = {foo: string option; bar: [`A | `B | `C] option}
[@@deriving command_line]
type t = (global_options * super_command)
[@@deriving command_line {master = true}]

and would generate a parse-command-line function:

val parse_t: ?argv:string array -> unit -> t

(or just a t CmdLiner.Term.t?)

Build method without OPAM

Could you detail how to build ppx_deriving without OPAM for ppl with OCaml on MinGW?

From opam file, it seems to be

$ sed -e 's/%{version}%/1.1/g' pkg/META.in > pkg/META
$ ocaml pkg/build.ml native=true native-dynlink=true

In my environment the above builds things fine. The hard part is the installation. I had to run ocamlifind manually getting the file information from ppx_deriving.install.

Thanks!

customize names of variants (or polymorphic variants)

utop # type tt = Machin | Chose [@printer fun fmt -> fprintf fmt "chose"] [@@deriving Show];
;                                                                                            
type tt = Machin | Chose                                                                     
val pp_tt : Format.formatter -> tt -> unit = <fun>                                           
val show_tt : tt -> bytes = <fun>  
utop # show_tt Chose;;                                                                       
- : bytes = "Chose"   

Printing recursive types

Is there a way to generate printers for recursive types?

For example,

type 'a exp = [
  | `Plus of 'a * 'a
  | `Num of int
] [@@deriving show]

let rec eval = function
  | `Plus (e1, e2) -> eval e1 + eval e2
  | `Num i -> i

;;

let ast = (`Plus (`Plus (`Num 1, `Num 2), `Plus (`Num 3, `Num 4))) in
let result = eval ast in
print_endline @@ show_magic @@ ast;
print_endline @@ string_of_int @@ result;

I'm guessing the printer would look something like eval, but would compose a given pp function. Don't understand ppx_deriving well enough to know how difficult this is though.

Deriving for a module with the same name as a standard library module

In ppx_deriving 2.2., it was possible to apply @@deriving on a module that happens to have the same name as a standard library module, e.g.:

module List = struct
    type 'a t = [`Cons of 'a | `Nil] [@@deriving show]
end
type 'a t = 'a List.t option [@@deriving show]

However, this results in an error in ppx_deriving 3.0:

ocamlfind ocamlc -c -package 'ppx_deriving.std' test.ml
File "test.ml", line 4, characters 0-46:
Error: Unbound value List.pp

Looking at the output of ppx_tools/rewriter, it appears that Ppx_deriving_runtime.List is shadowing the user-defined List module:

module List = struct ... end
let rec pp : ... =
  ((let open! Ppx_deriving_runtime in
      fun poly_a  ->
        fun fmt  ->
          function
          | None  -> Format.pp_print_string fmt "None"
          | Some x ->
              (Format.pp_print_string fmt "(Some ";
               (List.pp (fun fmt  -> poly_a fmt) fmt) x;
               Format.pp_print_string fmt ")"))[@ocaml.warning "-A"])
and ...

regression with 4.02.2 regarding attributes

Looks like attributes are ignored in 4.02.2:

#require "ppx_deriving.show";;
type foo = { bar : int [@opaque] } ;;
show_foo {bar=1};;

expect: { bar = <opaque>"}
got: { bar = 1 }

Derive visitors

I would like to be able to derive visitors, in the style of Ast_mapper.

Given a set of type in a type ... and ... declaration, a visitor would be a record with one field per type and a field for each external type used in the type declarations.

Build error with latest master ppx_deriving, ppx_protobuf + opam 1.2.0

I can't build the latest of ppx_deriving and ppx_protobuf.

$ opam pin -k git add ppx_deriving_protobuf ppx_deriving_protobuf
[NOTE] Package ppx_deriving_protobuf is already pinned to /home/cpiccion/workspace/ppx_deriving_protobuf. This will reset metadata.
Proceed ? [Y/n] y

[ppx_deriving_protobuf] Fetching /home/cpiccion/workspace/ppx_deriving_protobuf
Installing new package description for ppx_deriving_protobuf from /home/cpiccion/workspace/ppx_deriving_protobuf/opam

ppx_deriving_protobuf needs to be installed.
The following dependencies couldn't be met:

  • ppx_deriving_protobuf -> ppx_deriving < 0.3
    Your request can't be satisfied:
  • ppx_deriving<0.3 is not available because the package is pinned to /home/cpiccion/workspace/ppx_deriving.

No solution found, exiting
[NOTE] Pinning command successful, but your installed packages may be out of sync.

However, I have ppx_deriving pinned to .3 via github:

$ opam pin list
ppx_deriving.0.3 git /home/cpiccion/workspace/ppx_deriving
ppx_deriving_protobuf.1.0.0 git /home/cpiccion/workspace/ppx_deriving_protobuf

`ppx_deriving.make` not found by ocamlfind

The package descriptor for the new make plug-in is missing (should be in pkg/META.in). This causes the following error when ppx_deriving.std is referenced:

ocamlfind: Package ppx_deriving.make' not found - required byppx_deriving.std'

Pull request incoming.

Derive hash

I have found ord and eq very useful, specially with the capability of providing custom functions. In the same fashion it would be great having a deriving hash to be used with Hashtbl.Make.

cannot derive recursive modules with multiple type parameters

utop # module rec Foo : sig type ('a,'b) t = ('b, 'a) Bar.t end = 
struct type ('a,'b) t = ('b,'a) Bar.t end 
and Bar : sig type ('b, 'a) t = 'b * 'a  end = struct type ('b,'a) t = 'b * 'a end;;
module rec Foo : sig type ('a, 'b) t = ('b, 'a) Bar.t end and Bar : sig type ('b, 'a) t = 'b * 'a end

utop # module rec Foo : sig type ('a,'b) t = ('b, 'a) Bar.t [@@deriving show] end = 
struct type ('a,'b) t = ('b,'a) Bar.t [@@deriving show] end 
and Bar : sig type ('b, 'a) t = 'b * 'a [@@deriving show] end = 
struct type ('b,'a) t = 'b * 'a [@@deriving show] end;;
Error: Signature mismatch:                                                                                                                                                                                                              ...                                                                                                                                                                                                                              Values do not match:
         val pp :
           (Format.formatter -> 'a -> unit) ->
           (Format.formatter -> 'b -> unit) ->
           Format.formatter -> ('b, 'a) Bar.t -> unit
       is not included in
         val pp :
           (Format.formatter -> 'b -> unit) ->
           (Format.formatter -> 'a -> unit) ->
           Format.formatter -> ('a, 'b) t -> unit

ocamlfind ocamldep dependencies

I have some trouble understanding what looks like an issue with the ppx_deriving ocamlfind package.

ocamlfind ocamldep -package X ... -package Z -modules myfile.mli outputs a proper list of depencides, e.g.,

myfile.mli:  Format Hex  Z

while

ocamlfind ocamldep -package X ... -package Z -package ppx_deriving -modules myfile.mli produces an empty dependency list for myfile.mli.

Would you have any idea about what's going on?

Feature request: constructor deriving

Basically, this is the use case: https://github.com/Drup/Syndic/blob/0e494be62e673888cb2245db29b62129206bf25f/lib/syndic_atom.ml#L1053-L1059

Features:

  • fields that are optional (options, lists, [@default <bla>], ...) are in an optional argument
  • main field ([@main] ?) is without label, the rest are with labels. If there is no main field, the function ends by ().
  • offer the possibility to split tuples (use is ~hd + ?tl for foo * foo list (list with at least one element)).

I don't see anything else right now.

Improve locations for external functions

For example:

type t = { 
  foo : Foo.t option
} [@@deriving show]

The generated identifier Foo.to_string could be located either to the foo field or to the Foo.t type.
It would help with big records (No, I didn't wrote this monstrosity).

Recursive application of the mapper

I think there should be a way to apply the deriving-mapper to expression-valued attributes. Maybe as an alternative Arg.expr or by exposing the mapper as a global?

My motivation is that I wrote a syntax extension to generate random instances of types. The derived-from type takes an attribute [@random ...] to override with custom generator code, where I need reliable way to refer to generators for parameters or the type itself, e.g. in

type 'a term =
  | Var of 'a
  | App  [@weight 0.5] of 'a term * 'a term
  | Lam of ('a * 'a term) [@random random_lambda [%random: 'a term]]
  [@@deriving random]

In other cases random_lambda might use just [%random: 'a]. The internal name poly_a is needed in either case, which makes me think the best way to refer to it is to use [%random: ...]. I could systematically apply all parameter generators to the custom generator and use:

  | Lam of ('a * 'a term) [@random random_lambda random_term]

In my opinion, explicit arguments are nicer.

Handle Lazy.t in show.

The sensible handling would be to test if it's evaluated (with Lazy.is_val) and print it or <not evaluated>.

Error location

If I use [%derive.show: statement list] and that statement is not found, the error is the following:

File "_none_", line 1:
Error: Unbound value pp_statement

MinGW build failure

With MinGW OCaml, the build command ocaml pkg/build.ml native=true native-dynlink=true fails as follows:

Solver failed:
  Ocamlbuild knows of no rules that apply to a target named src/ppx_deriving.lib. This can happen if you ask Ocamlbuild to build a target with the wrong extension (e.g. .opt instead of .native) or if the source files live in directories that have not been specified as include directories.
Backtrace:
  - Failed to build the target src/ppx_deriving.lib
      - Building src/ppx_deriving.lib

I guess this is since MinGW OCaml uses a cross compiler for MinGW which produces library files with *.a instead of *.lib. The following quick but not entirely correct patch againnst topkg.ml fixed the issue:

--- a/pkg/topkg.ml
+++ b/pkg/topkg.ml
@@ -152,7 +152,7 @@ end
 module Exts : Exts = struct
   let interface = [".mli"; ".cmi"; ".cmti"]
   let interface_opt = ".cmx" :: interface
-  let c_library = if Sys.win32 then [".lib"] else [".a"]
+  let c_library = [".a"]
   let c_dll_library = if Sys.win32 then [".dll"] else [".so"]
   let library = [".cma"; ".cmxa"; ".cmxs"] @ c_library
   let module_library = (interface_opt @ library)

To fix the issue properly, I guess you need to find which C compiler OCaml actually executes.

qualified attributes don't seem to work

Simple example:

type foo = { x:int [@compare (fun i j -> 0)] } [@@deriving ord];;
compare_foo {x=1} {x=2};;  (* ok, returns 0 *)

type foo = { x:int [@ord.compare (fun i j -> 0)] } [@@deriving ord];;
compare_foo {x=1} {x=2};;  (* not ok, returns -1, should return 0? *)

Compiler-libs Btype.hash_variant

Sometimes it's convenient to serialize a polymorphic variant using it's hash value. Unfortunately Btype.hash_variant is not accessible from a ppx_deriving plugin. And I cannot dynload ocamlcommon.cma because it uses unsafe features. Do you know the way to calculate hash value without copy&paste from btype.ml?

add version field to opam file

I recommend adding version: "dev" to the opam file. Currently, if you pin, opam still reports the version as 0.3, which is slightly unintuitive. Adding this line will cause the version to be called "dev".

merlin

I don't know if it is linked with #42 but since 2.1 ppx_deriving doesn't work inside merlin anymore (work with ocamlfind directly).

It seems to be linked with the renaming of the command since the following hack fix the problem, after installation:

  • in META: replace ppx = "./ppx_deriving_main" by ppx = "./ppx_deriving"
  • create a symlink from ppx_deriving_main to ppx_deriving

Perhaps the bug is in merlin.

Change Arg to use Result

There's no need for the

[`Ok of 'a | `Error of string]

polymorphic variant as result is available in 4.03 and as a findlib packages for earlier OCaml's.

Is there anyway to make this transition without breaking a bunch of code?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.