[ANN] menhirformat 0.1.0

Hello,

I’m glad to announce the first release of menhirformat, a command line tool that formats and indents Menhir and ocamllex source code. It uses the ocamlformat RPC to pretty-print the OCaml sections of your lexers and parsers; it also tries its best to preserve the original location of your comments (still needs work in regard to this though!).

This is a satellite project of my ongoing and considerably larger effort to add LSP support to these two OCaml dialects, menhir-lsp. The formatting functionality was originally embedded into the LSP server to handle document formatting requests, and I split it out as a standalone application after this issue.

You can try it out with opam install menhirformat. The CLI is highly inspired by ocamlformat’s and takes the file to format as argument, e.g. menhirformat calc.mly. It exposes a small configuration by which your can tweak the formatter’s behavior; read on the available options with menhirformat --help.

You may also integrate it in your dune project by setting up dialects for Menhir and ocamllex:

(dialect
 (name menhir)
 (implementation
  (extension mly)
  (format
   (run menhirformat %{input-file}))))

(dialect
 (name ocamllex)
 (implementation
  (extension mll)
  (format
   (run menhirformat %{input-file}))))

Then running dune build @fmt will format your project’s .mll and .mly files and display a diff.

As someone who can’t live without format-on-save in their IDE, I was really missing a formatter for Menhir and ocamllex files in the OCaml ecosystem. I hope menhirformat fills that void.

I’m interested in opinions about the quality of the output and also in suggestions for other customization points of the configuration. Please share below or through a GitHub issue!

Enjoy!

Do you have the same safety check as ocamlformat, checking that the formatted code parse to the same ast ? How are comments formatted (and code block inside comment) ? How do you make ocamlformat handle special dollar vraiable ($1, $ $startpos(..))

I m happy to see formatting for mly and mll but I’m surprised to see it as a separate logic from ocamlformat.

(I’ve worded on adding support in ocamlformat earlier this year, but it s still wip, draft mll support is Add ocamllex (.mll) file formatting support by hhugo · Pull Request #2792 · ocaml-ppx/ocamlformat · GitHub)

Do you have the same safety check as ocamlformat, checking that the formatted code parse to the same ast ?

No…

I’ve only done expect-style unit testing, so freezing certain outputs that look stylistically nice and syntactically correct, but no formal checks yet.

How are comments formatted (and code block inside comment) ?

It doesn’t go inside comments right now, they are treated as plaintext and their content is copied verbatim on the output PPrint document. As for the comment placement, I borrowed ocf’s code that collects them from the lexer, and I DIY’d the logic that glues them back to the AST nodes based on distances and relative positions (here in this module, it’s pretty ugly, and scales poorly with the number of comments and the depth of the tree).

How do you make ocamlformat handle special dollar vraiable ($1, $ $startpos(..))

It’s a hack, but I feed ocamlformat the same code that Menhir’s lexer produces, which is the pure OCaml code that ends up in the generated parser implementation. After ocf does its job I restore the dollar keywords and variables with simple string substitutions. It’s pretty unsafe and breaks down if you name your producers things like _0, _1 or _startpos_1_; it is done here.

First two are actual issues that demand a better study of ocamlformat’s source code on my part. Thank you for pointing them out!