Parsec 入門


Parsec エラーメッセージ

<?>

Parsecでパーサのマッチエラーが起きると、エラーの場所と種類を示すエラーメッセージが表示され、処理が中断する。
Prelude Text.Parsec> parseTest (string "foo") "bar"
parse error at (line 1, column 1):
unexpected "b"
expecting "foo"

最後の expecting "foo" は "foo" というパターンをマッチさせようとしていたというパーサの性質を述べているが、これをユーザで変更できる。数式処理の場合、パターンマッチが term で起きたと表示したい場合がある。そういうときは、パーサのあとに <?> とエラーメッセージを続けるとよい。

Prelude Text.Parsec> parseTest (string "foo" <?> "term") "bar"
parse error at (line 1, column 1):
unexpected "b"
expecting term

label

label は <?> の前置記法だ。

Prelude Text.Parsec> parseTest (label (string "foo") "term") "bar"
parse error at (line 1, column 1):
unexpected "b"
expecting term

labels

labels は複数のエラーメッセジを表示できる。

Prelude Text.Parsec> parseTest (labels (string "foo") ["term", "foo"]) "bar"
parse error at (line 1, column 1):
unexpected "b"
expecting foo or term

unexpected

unexpected はパースの途中で例外を発生させて処理を中断する。

Prelude Text.Parsec> parseTest (string "foo" >> unexpected "Error" >> string
 "bar") "foo bar"
parse error at (line 1, column 4):
unexpected Error

おそらくソフトウェア的に例外を発生させる手段だと思われるが、詳細は不明。

ParseError String

parse 関数でパースを実行するときは、パースエラーの内容は Left のコンテナに ParseError String 型の値を入れて返す。

Prelude Text.Parsec> parse (string "foo") "SourceName" "bar"
Left "SourceName" (line 1, column 1):
unexpected "b"
expecting "foo"

戻り値の型を表示させると例外の型が分かる。

Prelude Text.Parsec> :t parse (string "foo") "SourceName" "bar"
parse (string "foo") "SourceName" "bar" :: Either ParseError String

戻り値の Either 型のデータからは、パターンマッチでコンテナの中のデータを取り出すことができる。

Prelude Text.Parsec> (Left qux) = buz
Prelude Text.Parsec> :t qux
qux :: ParseError
Prelude Text.Parsec> errorPos qux
"SourceName" (line 1, column 1)

Text.Parsec.Error

Left データコンストラクタの中には ParseError 型のデータが入っている。Text.Parsec.Error モジュールには ParseError データ型のフィールドからフィールド値を取り出す errorPos, errorMessages, errorIsUnknown の3つの関数が定義されている。

Prelude Text.Parsec> import Text.Parsec.Error
Prelude Text.Parsec Text.Parsec.Error> map messageString $ errorMessages qux
["\"b\"","\"foo\""]
Prelude Text.Parsec Text.Parsec.Error> errorIsUnknown qux
False

おそらく ParseError 型の例外を使っていろいろな例外処理を行うことができるのだろうが、詳細は不明だ。