Writing my own type-deriver

ppx
core

#1

Hi!

I am trying to hook into the compilation process of my code to generate some additional files, in a way similar to ppx_deriving. Now it looks like ppx_type_conv is the easiest way to do so, but I can’t get my deriver to be picked by ppx_driver, when compiling ppx_type_conv complains: rror: ppx_type_conv: 'foo' is not a supported type type-conv generator.

My ppx_foo_conv looks like this:

open Ppx_type_conv.Std
open Ppx_core

let name = "foo"

let () =
  Type_conv.add name
  ~extension:(fun ~loc ~path:_ ty -> [%expr ()])
  |> Type_conv.ignore

My example.ml looks like this:

type foo = {
  bar: int;
  baz: string;
} [@@deriving flow]

type qux = {
  quux: foo;
  corge: string;
} [@@deriving flow]

all of this is held together by jbuild:

(library
 ((name ppx_foo_conv)
  (public_name ppx_foo_conv)
  (kind ppx_deriver)
  (modules ppx_foo_conv)
  (libraries (ppx_core ppx_type_conv ppx_driver))
  (preprocess (pps (ppx_metaquot ppx_driver.runner)))))

(executable
 ((name example)
  (public_name example)
  (modules example)
  (preprocess (pps (ppx_foo_conv ppx_driver.runner)))))

(jbuild_version 1)

When I run ppx.exe -print-transformations I do see

ppx_type_conv.flow
type_conv

So apparently it registered something, but I am an a loss how to tell @@deriving to use it.

Anybody has an idea how I can get this to work?


#2

Yes, your foo/flow deriver is actually registered.
The problem is that it is defined as an “extension”, but then used
as a “str_type_decl”. Your registration should look like:

Type_conv.add name ~str_type_decl:(...)

Hope this helps,

Xavier


#3

Thanks @xclerc, this is exactly what I was doing wrong. Now that I used ~str_type_decl it hooks up exactly at the right point.

This leads me to another question: what are all of the options I can set? I can see these:

  • str_type_ext which is somehow an extension for a type struct I would assume, but what is an extension in this context?
  • str_exception is something like exception Foo [@deriving myderiver]?
  • sig_type_decl that’s something about signatures?
  • sig_exception something about exception signatures?
  • extension I would assume is something standalone like [@@@deriving myderiver], but I don’t know what core_type would be passed to it.

I have to admit, this library seems immensely useful. I can think of a number of useful things how I could generate code using it.


#4

Here are the kinds of generators that can be registered:

  • str_type_decl;
  • str_type_ext;
  • str_exception;
  • sig_type_decl;
  • sig_type_ext;
  • sig_exception;
  • extension.

The str_xyz generators are for structures/implementations, while the sig_xyz generators are for signatures/interfaces. extension can be used only in structures (it generates an expression).

Then, xyz_type_decl is for type declarations (i.e. type t = (…) [@@deriving foo]), xyz_exception is for exception declarations (i.e. exception E [@@deriving foo]), and xyz_type_ext is for type extensions (i.e. type t += A [@@deriving foo] after type t = ..). Finally, extension is expected to be used like that: let _ = [%foo : t].

Hope this helps,

Xavier