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 型の例外を使っていろいろな例外処理を行うことができるのだろうが、詳細は不明だ。