Documentation for @@deriving_inline

In the readme of base and ppxlib, there are mentions of a @@deriving_inline annotation. If I understand correctly, it allows to skip the work of deriving if there is some code before an @@@end annotation. The piece that I didn’t find, is how to do the promotion so that the space between deriving and end is populated. Or how to turn a normal @@deriving annotation into @@deriving_inline ... @@@end?

Is there any documentation about that feature? Or does it rely on internal JSC tools that aren’t open source?

The goal is to use it in merlin, on the lsp part. But it would be very interesting to do that on almost all the libraries that are depending on ppx_deriving, especially given the instability of the ppx world.


It looks related to ppx_jane. But it doesn’t tell much about the workflow to follow.

And one more question (sorry for the spam): does it work with all the ppx_deriving plugins? I’m thinking of ppx_deriving_yojson in particular. As the diff generated when ppx_jane is added as a ppx isn’t complete for yojson but is complete for sexp.

$ dune build
Done: 1373/1395 (jobs: 1)File "src/lsp/protocol.ml", line 1, characters 0-0:
        diff (internal) (exit 1)
(cd _build/default && /usr/bin/diff -u src/lsp/protocol.ml src/lsp/protocol.ml.ppx-corrected)
--- src/lsp/protocol.ml	2019-03-12 16:00:54.047782908 +0000
+++ src/lsp/protocol.ml.ppx-corrected	2019-03-12 16:00:54.087783172 +0000
@@ -15,6 +15,90 @@
   line: zero_based_int;
   character: zero_based_int;
 } [@@deriving_inline sexp]
+let _ = fun (_ : position) -> ()
+let position_of_sexp : Ppx_sexp_conv_lib.Sexp.t -> position =
+  let _tp_loc = "src/lsp/protocol.ml.position" in
+  function
+  | Ppx_sexp_conv_lib.Sexp.List field_sexps as sexp ->
+      let line_field = ref None
+      and character_field = ref None
+      and duplicates = ref []
+      and extra = ref [] in
+      let rec iter =
+        function
+        | (Ppx_sexp_conv_lib.Sexp.List ((Ppx_sexp_conv_lib.Sexp.Atom
+            field_name)::_field_sexp::[]))::tail ->
+            ((match field_name with
+              | "line" ->
+                  (match !line_field with
+                   | None ->
+                       let fvalue = zero_based_int_of_sexp _field_sexp in
+                       line_field := (Some fvalue)
+                   | Some _ -> duplicates := (field_name :: (!duplicates)))
+              | "character" ->
+                  (match !character_field with
+                   | None ->
+                       let fvalue = zero_based_int_of_sexp _field_sexp in
+                       character_field := (Some fvalue)
+                   | Some _ -> duplicates := (field_name :: (!duplicates)))
+              | _ ->
+                  if !Ppx_sexp_conv_lib.Conv.record_check_extra_fields
+                  then extra := (field_name :: (!extra))
+                  else ());
+             iter tail)
+        | (Ppx_sexp_conv_lib.Sexp.List ((Ppx_sexp_conv_lib.Sexp.Atom
+            field_name)::[]))::tail ->
+            ((let _ = field_name in
+              if !Ppx_sexp_conv_lib.Conv.record_check_extra_fields
+              then extra := (field_name :: (!extra))
+              else ());
+             iter tail)
+        | (Ppx_sexp_conv_lib.Sexp.Atom _|Ppx_sexp_conv_lib.Sexp.List _ as
+             sexp)::_
+            ->
+            Ppx_sexp_conv_lib.Conv_error.record_only_pairs_expected _tp_loc
+              sexp
+        | [] -> () in
+      (iter field_sexps;
+       (match !duplicates with
+        | _::_ ->
+            Ppx_sexp_conv_lib.Conv_error.record_duplicate_fields _tp_loc
+              (!duplicates) sexp
+        | [] ->
+            (match !extra with
+             | _::_ ->
+                 Ppx_sexp_conv_lib.Conv_error.record_extra_fields _tp_loc
+                   (!extra) sexp
+             | [] ->
+                 (match ((!line_field), (!character_field)) with
+                  | (Some line_value, Some character_value) ->
+                      { line = line_value; character = character_value }
+                  | _ ->
+                      Ppx_sexp_conv_lib.Conv_error.record_undefined_elements
+                        _tp_loc sexp
+                        [((Ppx_sexp_conv_lib.Conv.(=) (!line_field) None),
+                           "line");
+                        ((Ppx_sexp_conv_lib.Conv.(=) (!character_field) None),
+                          "character")]))))
+  | Ppx_sexp_conv_lib.Sexp.Atom _ as sexp ->
+      Ppx_sexp_conv_lib.Conv_error.record_list_instead_atom _tp_loc sexp
+let _ = position_of_sexp
+let sexp_of_position : position -> Ppx_sexp_conv_lib.Sexp.t =
+  function
+  | { line = v_line; character = v_character } ->
+      let bnds = [] in
+      let bnds =
+        let arg = sexp_of_zero_based_int v_character in
+        (Ppx_sexp_conv_lib.Sexp.List
+           [Ppx_sexp_conv_lib.Sexp.Atom "character"; arg])
+          :: bnds in
+      let bnds =
+        let arg = sexp_of_zero_based_int v_line in
+        (Ppx_sexp_conv_lib.Sexp.List
+           [Ppx_sexp_conv_lib.Sexp.Atom "line"; arg])
+          :: bnds in
+      Ppx_sexp_conv_lib.Sexp.List bnds
+let _ = sexp_of_position
 [@@@end]
 
 type range = {
$ dune build
Done: 1373/1395 (jobs: 1)File "src/lsp/protocol.ml", line 1, characters 0-0:
        diff (internal) (exit 1)
(cd _build/default && /usr/bin/diff -u src/lsp/protocol.ml src/lsp/protocol.ml.ppx-corrected)
--- src/lsp/protocol.ml	2019-03-12 15:58:26.258852762 +0000
+++ src/lsp/protocol.ml.ppx-corrected	2019-03-12 15:58:26.294852977 +0000
@@ -15,6 +15,7 @@
   line: zero_based_int;
   character: zero_based_int;
 } [@@deriving_inline yojson { strict = false }]
+let _ = fun (_ : position) -> ()
 [@@@end]
 
 type range = {

I actually wrote some doc for this :slight_smile: It is not yet released, but you can see it there: https://github.com/ocaml-ppx/ppxlib/blob/manual/doc/ppx-for-end-users.rst#deriving_inline

[@@deriving_inline ...] only works for plugins using ppxlib.

1 Like

@jeremiedimino any reason why you are doing this in .rst files ?

Come to the .mld side… this documentation will then naturally show up in the users’ personal documentation sets along side the API here https://b0-system.github.io/odig/doc/ppxlib/

1 Like

Yes, it’s the format readthedocs uses

I see, it allows to make docs harder for users to find and prevents from checking the links you may be doing in the API. Makes sense.

When the website looks as good as readthedocs I’ll consider switching

1 Like

If you don’t like the look be my guest. No one’s forcing you to look at something you dislike. Everyone gets to read it the way it wants.

Note that using .mld files is not about this “website” in particular (which is just a demo output of odig on a best-effort sample of the opam repository). Ultimately it’s about docs.ocaml.org and easy and uniform access to information for the end-users of OCaml and its eco-system — but I know you people from companies tend to have your own information systems so I understand you may not care.

In any case I would suggest you at least update your opam metadata to point to your readthedocs documentation so that end-users can odig browse online-doc ppxlib to fall on it, though https://ppxlib.readthedocs.io/en/latest/ looks rather empty at the moment.

1 Like

Look, you are being condescending so I am not interested in pursuing this conversation. Additionally, this is a thread about deriving_inline, so let’s not turn it into a debate about documentation tools

With my forum moderator hat on, your sarcasm is unwarranted and unnecessary here Daniel. The odig styles you are reference are about one week old. Do you expect all other maintainers to suddenly leap in and convert their code to your format overnight? If you feel strongly about it, then submit a PR to the other project, write up your recommended style and create a fresh thread about it.

2 Likes

This has nothing to do with my format or odig styles. My sarcasm was an answer to the equally sarcastic and little motivated answer @jeremiedimino made here after I politely suggested to consider .mld files.