Creating a ppx that transforms record updates

Shameless plug: it can be a nice example of application for opam - metapp!

The following example declares two “meta” functions update_mutable and update_immutable, and then shows a short example for their usage.

Edit: to use it, you just have to add (preprocess (pps metapp.ppx)) in the dune file.

[%%metadef
let extract_field_access (e: Ppxlib.expression):
      Ppxlib.expression * Ppxlib.Ast_helper.lid =
  match e.pexp_desc with
  | Pexp_field (expression, field) -> expression, field
  | _ ->
      Location.raise_errorf ~loc:e.pexp_loc "field access expected"

let update_mutable field_access =
  let record, field = extract_field_access field_access in
  [%e
    (* Binding [record] first to evaluate it only once *)
    let record = [%meta record] in
    fun value ->
      if [%meta Ppxlib.Ast_helper.Exp.field [%e record] field] != value then
        [%meta Ppxlib.Ast_helper.Exp.setfield [%e record] field [%e value]];
      record]

let update_immutable field_access =
  let record, field = extract_field_access field_access in
  [%e
    (* Binding [record] first to evaluate it only once *)
    let record = [%meta record] in
    fun value ->
    if [%meta Ppxlib.Ast_helper.Exp.field [%e record] field] != value then
      [%meta Ppxlib.Ast_helper.Exp.record [field, [%e value]]
        (Some [%e record])]
    else
      record]]

type a = int and b = bool

type t = {
    mutable a: a;
    b : b;
}

let () =
  let r = { a = 0; b = false } in
  ignore ([%meta update_mutable [%e r.a]] 1);
  assert (r.a = 1);
  let r' = [%meta update_immutable [%e r.b]] true in
  assert (r'.b = true)
4 Likes