combine を使ったときに、例えば識別子のパース時に予約語を弾く方法。
最初は and_then を使うのかと思ったのだけど、 エラーの型指定がえらく面倒 だったので諦め。というか、なんか絶対違うだろうと思って別の方法を模索。
Parser のドキュメントに以下の例がある。これだ。
digit() .then(|d| { if d == '9' { value(9).left() } else { unexpected_any(d).message("Not a nine").right() } })
ということで、 then を使うと Parser を返す処理を書けるので、ここで unexpected_any を使って失敗させてやればよい。
ちょっとこのコードを見てぎょっとするのは left() と right() だが、これは if で分岐するパーサの戻り値が違うため。 rust ではよくみるやつだが、 combine のパーサコンビネータは Parser トレイトを持つメソッドごとの独自の型 Value<I, T> や Unexpected<I, T> を返す。ということで Either にまとめれば型を混ぜて1つにできてハッピーなのだが、次に、どっちを left にしてどっちを right にするのがいいのかという疑問が出てくる。
正解は実はどちらでもよくて、これはエラーを表す Either ではないので、 right が正常処理というような意味はない。どちらでもいいから、入っているパーサーを実行するだけである。実際、 Either の Parser トレイトの実装を見ると以下のようになっている。
impl<L, R> Parser for Either<L, R> where L: Parser, R: Parser<Input = L::Input, Output = L::Output>, { ..snip.. fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<Self::Output, Self::Input> { match *self { Either::Left(ref mut x) => x.parse_lazy(input), Either::Right(ref mut x) => x.parse_lazy(input), } } ..snip.. }
R: Parser<Input = L::Input, Output = L::Output> の制約は、2つのパーサの入出力が揃っていないとまずいことを表す。