Text.Parsec.Pos
Text.Prasec.Pos では入力文字列が Parsec でパースされるときの位置情報をあらわすデータ型 SourcePos が定義されている。SourcePos に関する関数はすべて Text.Parsec.Pos モジュールで完結しているので、このモジュールをインポートするだけで ghci で試してみることができる。Prelude> import Text.Parsec.Pos Prelude Text.Parsec.Pos> :set prompt "Parsec> " Parsec>
Text.Parsec.Pos モジュールの概要
Text.Source.Pos モジュールの概要は :browse コマンドで得られる。
Parsec> :browse Text.Parsec.Pos type Column = Int type Line = Int type SourceName = String data SourcePos = Text.Parsec.Pos.SourcePos SourceName {-# UNPACK #-}Line {-# UNPACK #-}Column incSourceColumn :: SourcePos -> Column -> SourcePos incSourceLine :: SourcePos -> Line -> SourcePos initialPos :: SourceName -> SourcePos newPos :: SourceName -> Line -> Column -> SourcePos setSourceColumn :: SourcePos -> Column -> SourcePos setSourceLine :: SourcePos -> Line -> SourcePos setSourceName :: SourcePos -> SourceName -> SourcePos sourceColumn :: SourcePos -> Column sourceLine :: SourcePos -> Line sourceName :: SourcePos -> SourceName updatePosChar :: SourcePos -> Char -> SourcePos updatePosString :: SourcePos -> String -> SourcePos
SourcePos のデータ構造
SourcePos のデータ構造は、
SourcePos SourceName Line Column
である。SourceName は String 型の別名で、Line と Column は Int 型の別名である。いずれも type 宣言で定義されている。
SourcePosの作成
SourcePos の作成は newPos 関数で行える。引数には、ソース名、Line 番号、Column 番号を与える。SourcePos データ型は Show クラスのインスタンスなので、ghci で表示できる。
Parsec> pos = newPos "foo" 1 2 Parsec> pos "foo" (line 1, column 2)
SourcePos の初期値は initialPos 関数で作れる。
Parsec> initialPos "bar" "bar" (line 1, column 1)
SourcePos を操作する関数
SourcePos を操作する関数には次のようなものがある。
incSourceColumn 関数は Column 番号を引数の番号分増やす。
Parsec> incSourceColumn pos 3 "foo" (line 1, column 5)
incSourceLine 関数は Line 番号を引数の番号分増やす。
Parsec> incSourceLine pos 3 "foo" (line 4, column 2)
setSourceColumn 関数は Coulumn 番号を引数の番号で置き換える。
Parsec> setSourceColumn pos 10 "foo" (line 1, column 10)
setSourceLine 関数は Line 番号を引数の番号で置き換える。
Parsec> setSourceLine pos 10 "foo" (line 10, column 2)
setSourceName 関数は SourceName を引数の文字列で置き換える。
Parsec> setSourceName pos "bar" "bar" (line 1, column 2)
sourceColunm 関数は SourcePos の Column 番号を得る。
Parsec> sourceColumn pos 2
sourceLine 関数は SourcePos の Line 番号を得る。
Parsec> sourceLine pos 1
sourceName 関数は SourcePos の SourceName を得る。
Parsec> sourceName pos "foo"
updatePosChar 関数は Char の分だけ Column 番号を増やす。
Parsec> updatePosChar pos 'a' "foo" (line 1, column 3)
updatePosString 関数は String の分だけ Column 番号を増やす。
Parsec> updatePosString pos "baz" "foo" (line 1, column 5)
ParseError 中の SourcePos
SourcePos は ParseError 例外のフィールドに入っており、errorPos で取り出すことができる。
Parsec> :m + Text.Parsec Text.Parsec.Error Parsec> (Left pe) = runParser letter () "SourceName" "123" Parsec> pe "SourceName" (line 1, column 1): unexpected "1" expecting letter Parsec> errorPos pe "SourceName" (line 1, column 1)
SourcePos は入力文字列のどの位置で Parsec によるパースが行われるかを示す。これはパースエラーのときの ParseError 例外にも含まれていて、パースエラーがどこで起こったかを示している。
SoucePos のような意味的にまとまったデータは代数的データ型にしておくと可読性も保守性もいいようだ。また、ネット上の Hackage は関数の説明から簡単にソースにアクセスできるのでデータ構造の詳細を知るのに便利だ。