Posted at

nom5のトレースライブラリnom-tracable


はじめに

nomはRustのパーサコンビネータライブラリです。nomで使えるトレース出力用のクレートとしてはnom-traceがあるのですが、これはnomがマクロベースだったころに作られたもので、関数ベースになったnom5ではちょっといまいちな感じです。

(使えなくはないのですが、パーサの名前を手打ちする必要があったりして大量に使うのは辛そうです)

というわけでnom5で使えるトレースライブラリを作ってみました。

https://github.com/dalance/nom-tracable


トレースの例

こんな感じのトレースを出力できます。特徴としては


  • 呼び出し側と戻り側の両方をトレースできる(->が呼び出し、<-が戻り)

  • 戻り側は成功・失敗を色付けする(緑が成功、赤が失敗)

  • 特定のパーサを折りたためる(+がそれ以下のパーサ呼び出しを折りたたんでいる箇所)

  • パーサ呼び出し回数のヒストグラムを表示できる

という感じです。


使い方

dependenciesに追加して、


Cargo.toml

[dependencies]

nom-tracable = "0.4.0"

パーサの入力型を定義します。

type Span<'a> = LocatedSpanEx<&'a str, TracableInfo>;

トレーサはパーサの呼び出し階層などの情報をこの入力型で持ちまわすので、単純な&strなどは使えません。

定義した入力型を使ってnom5のパーサ関数を定義して、#[tracable_parser]アトリビュートを付けます。

#[tracable_parser]

pub fn term_internal(s: Span) -> IResult<Span, String> {
let (s, x) = char('1')(s)?;
Ok((s, x.to_string()))
}

あとはコンパイル時に--features traceを指定するとトレース出力できます。

$ cargo run --features trace

featureを指定しない場合はトレース関連のコードは生成されないので、パフォーマンスへの影響はありません。

完全なソースコード例は以下にあります。

https://github.com/dalance/nom-tracable/blob/master/nom-tracable/examples/example.rs