Skip to content

Format Fmt code generation quickstart

Brian Ward edited this page Feb 28, 2022 · 9 revisions

Overview

We make extensive use of the Format[0] module via the Fmt[1] API. As such, you'll need to understand the %a and @ notation from [0], especially the section headed "Formatted pretty-printing." Then, we use functions like pf and strf from the Fmt library[1]. On top of that, the @ pretty-printing specifiers all actually correspond 1-to-1 with commands like open_box from the Format library[0]. The boxing system is best described in this explainer pdf [2], particularly Section 3 ("Format basics"). It's worth noting that someone was able to make a decent-looking pretty-printer for a subset of Javascript[3] that might serve as a good reference.

Quick example with most of the scariest parts explained

Let's break down this line:

      pf ppf "@[<hov>template <%a>@]@ " (list ~sep:comma string) templates

First, we should note that we've got the Fmt module opened sometimes, which is where pf, list, comma, and string are coming from.

  • pf is basically the abbreviation for fprintf. It's ubiquitous - it just means to print to some formatter output (typically written ppf) the format string that follows (the one in quotes following).
  • ppf is the output formatter - this could be Fmt.stdout or a string buffer.
  • @[<hov> ... @] is the syntax for opening (and @] for closing) a "box." Boxes are a formatter concept that allows us to deal with indentation - everything in the box shares the same indentation. (see Format Unraveled or one of the other docs for more details). So in Format strings, you can use @[ to open and @] to close a box. You can also pass parameters to the opening of the box, which is what this <hov> is doing. That's telling it to use a horizontal-or-vertical box, which follows some slightly complicated rules but essentially means it tries to flow text across a fixed-width page sort of the way you'd expect - filling up each line before continuing to the next line.
  • template < - this is just a string. It will print the string "template <"
  • %a this is the core of Ocaml's Format system (which Fmt is a wrapper for). This is the compositional format string. So if you're familiar with C style printf, you know that %d will require one integer argument to follow. OCaml Format also allows %d and %s and all of those from C, but it adds %a, and %a breaks the pattern as it requires two arguments to follow it. The first of those will itself be another formatter (hence the compositionality) and then the second will be the argument to that formatter. Here, those are (list ~sep:comma string) and templates (just a variable here, containing a list of strings).
  • > here is just the string ">"
  • @ here is a "space break" - just outputs a break that will be one space long but could also lead to cutting over to the next line in e.g. an hov box. There are a bunch of other breaks you can make that start with @ - you may also see @, or @;. See the Format library doc for more info.
  • (list ~sep:comma string) This constructs a formatter using the Fmt API.
    • Fmt.list here takes a separator argument and another formatter to compose a formatter that operates over lists of the underlying formatter, separated whatever formatter you pass into sep.
    • ~sep is the syntax for named arguments in ocaml, this one is named sep.
    • comma is a built-in Fmt formatter that just prints a ",@ " no matter what is passed in.
    • string is a Fmt builtin and, given a format output and a string, outputs the string. It's probably the simplest possible formatter. So the parenthesized expression expects a format output ("ppf") and a list of strings, and it will comma separate them.
  • templates - just a variable containing a list of strings.