We are happy to announce the first public release of ocamlgrep, a tool for structural grepping of OCaml code.
This tool has existed within the walls of LexiFi for a long time and we were keen on open-sourcing it, but it was not in a form that could be used by the wider public. Now, thanks to the work of @mjambon, we are able to to finally do so.
To install:
$ opam install ocamlgrep
The idea behind the tool is simple: you call it from within your Dune project[1] with a query (after having built all .cmt/.cmti artifacts, eg by doing dune build @check), and the tool returns the list of matches it can find in the source tree. A query is syntactically an OCaml expression, possibly with holes __ in it. Some examples follow to give an idea of how the tool is used in practice.
The following query searches for the anti-pattern List.rev e1 @ e2 (where e1 and e2 are arbitrary expressions.
$ ocamlgrep 'List.rev __ @ __`
Note that as the tool works at the level of the OCaml AST, it will also match expressions of the form (@) (e1 |> List.rev) e2, since they produce the same AST.
The syntax of type constraints (e : ty) is overloaded to impose a type condition on the search term. For example, the following search query looks for function calls where the first argument is an int and the second one a string.
$ ocamlgrep '__ (__ : int) (__ : string)'
The holes can be numbered, __1, __2, etc, to express repetitions of the same term. For example, the following query searches for a pattern matching on an option that sends Some x to Some x (ie reconstructing the same value):
$ ocamlgrep 'match __ with Some __1 -> Some __1 | None -> __'
We can also look for applications of the polymorphic operator = applied to float arguments:
$ ocamlgrep '(__ : float) = __'
Historically, this tool has been useful for large-scale refactorings and linting of our codebase. Nowadays, such refactorings can often be done using AI agents. However, the tool is still able to do things that seem a bit beyond of what AI agents can do today, eg to look for applications of polymorphic functions where one of the arguments is of a specific type. This was for example useful when migrating our codebase to no-flat-float-array mode, where we wanted to make sure that polymorphic array operations were not being applied to float array values.
Happy grepping!
Cheers,
Nicolas
Only Dune projects are supported for now. Adding support for other build systems should not be very hard, issues and/or PRs are welcome. ↩︎