Metaprogramming with PPX

PPX rewriters transform the AST at compile time, triggered by attributes [@...] and extension nodes [%...].

PPX rewriters transform the AST at compile time, triggered by attributes [@...] and extension nodes [%...].

38.1 Using derivers

(preprocess (pps ppx_deriving.show ppx_deriving.eq ppx_deriving.ord ppx_yojson_conv ppx_sexp_conv))
type color = Red | Green | Blue [@@deriving show, eq, ord]

type person = { name : string; age : int; tags : string list }
[@@deriving show, yojson]

let () =
  let p = { name = "Ann"; age = 30; tags = ["admin"] } in
  print_endline (show_person p);
  print_endline (Yojson.Safe.to_string (yojson_of_person p))

38.2 Popular PPXs

ppx_deriving (show, eq, ord, make, iter, map, fold) ppx_yojson_conv / ppx_deriving_yojson

ppx_compare, ppx_hash, ppx_fields_conv Jane Street derivers ppx_expect, ppx_inline_test let%bind, let%map ppx_regexp, ppx_string string interpolation, regexes

38.3 Attributes in core OCaml

let[@inline] f x = x + 1
let[@inline never] g x = x
let[@tail_mod_cons] rec map f = ...
let f x = (g [@tailcall]) x
let[@warning "-32"] unused = 1
[@@@warning "-27"]            (* floating attribute: file-wide *)
type t = { x : float } [@@unboxed]
external foo : int -> int = "c_foo" [@@noalloc]
val old : int -> int [@@deprecated "use new_fn"]
let[@ocaml.alert unsafe "explanation"] risky () = ()

38.4 Writing a PPX with ppxlib (overview)

Metaquot [%expr ...], [%pat? ...], [%type: ...] let you write AST fragments as OCaml syntax.

(* An extension [%today] that expands to a compile-time date string *)
open Ppxlib

let expand ~ctxt =
  let loc = Expansion_context.Extension.extension_point_loc ctxt in
  let t = Unix.localtime (Unix.time ()) in
  let s = Printf.sprintf "%04d-%02d-%02d" (t.tm_year + 1900) (t.tm_mon + 1) t.tm_mday in
  Ast_builder.Default.estring ~loc s

let ext = Extension.V3.declare "today" Extension.Context.expression Ast_pattern.(pstr nil) expand
let () = Driver.register_transformation ~rules:[ Context_free.Rule.extension ext ] "ppx_today"
(library (name ppx_today) (kind ppx_rewriter) (libraries ppxlib unix))