Search code examples
ocamlreasonppx

What are PPXes?


In many projects using ReasonML, the acronym PPX is often used, but rarely explained.

What are PPXes?

Why does ReasonML need them?


Solution

  • A PPX (Preprocessor extension) is an Abstract Syntax Tree (AST) rewriter. Essentially just a function ast => ast.

    The AST is a representation of the syntax, the tree data structure that results from parsing the source code. Since a PPX can only accept and return this AST, it is restricted to the existing OCaml/ReasonML syntax. However, it can reinterpret the syntax, and it can embed a completely different syntax in a string, enabling a limited and encapsulated form of syntax extension.

    PPXes are also not allowed to rewrite the entire AST. They are restricted to nodes that have been tagged by the user using either attributes ([@...)), which are associated with existing nodes, or extension nodes ([%...]) which are stand-alone AST nodes. A PPX will register one or more hooks that will receive the AST associated with them as they are encountered by the compiler, and can the transform these pieces of AST before the compiler continues onto the its phase.

    Examples

    ppx_deriving is perhaps the most widely used PPX. It allows certain functionality to be "derived" from type signatures. For example:

    [@deriving show]
    type t = {
      foo: int,
      bar: string,
    };
    

    will generate a show function (as well as a few others) that when given a value of type t will return a pretty-printed string representation of it.

    ppx_bx_css and styled-ppx are both PPXes that parse CSS into some OCaml/ReasonML data structure to be used with various CSS-in-JS libraries. These embed the CSS syntax in a quoted string which, for this purpose at least, is just an ordinary string that allows line breaks and does not require escaping of " and \.

      [%style
        {|
          color: red;
          margin: auto 0 10px 1em;
          width: 70%;
          background: url(http://example.com/test.jpg)
        |}
      ];