OCaml の ppx で構文拡張されたコードを、前処理・展開したソースコードを得る方法について。
OCaml は ppx という構文拡張で多くの有用な機能を実現しています。例えば ppx_deriving など。 新しい ppx を使う前に、どのようなコードを生成するか見ておきたくなることがあります。また ppx を開発していると、型が合わない構文木を生成してしまうことがたまにあり、デバッグのため生成された構文木をチェックする必要があります。
この記事の内容は OCaml 日本語 Slack で @camloeba さんと @_smorimoto さんから教わった内容をベースにしています。ありがとうございます!
方法1: ppxfind
最も簡単なのは、 ppxfind です。 findlib 経由でインストールされた ppx (ほとんどのppxはそうなっているはず) について、コマンド一発で展開後のソースが得られます。 opam install ppxfind
でインストールしたのち、
> ppxfind -help
ppxfind [options] ppx1,ppx2,... [ppx-options] [file]
-legacy Use the legacy ppx system
-debug Enable debug messages
-help Display this list of options
--help Display this list of options
でヘルプが見れ、この通りに使えばよいです。 例えば ppx_deriving
を適用したい場合は、
> ppxfind ppx_deriving foobar.ml
のようにします。
方法2: X.pp.ml を -dsource で変換
dune を使っている場合は _build/default/path/to/XX.pp.ml
に前処理後のソースコードがバイナリ表現で生成されています。 ocamlc
の undocumented な機能である -dsource
を使えば、このファイルをプレーンテキストに変換できます。
> ocamlc -dsource _build/default/foobar.pp.ml -stop-after parsing
方法3: ocamlmerlin を使う
dune を使っているなら ocamlmerlin も使っていると思います。その場合、 .merlin
にプリプロセッサの情報が残っているので、それを利用して展開することもできます:
FILE=path/to/file.ml
> cat $FILE | ocamlmerlin single dump -what ppxed-source -filename $FILE |jq -r '.value'