module Text.Parsec.Pos
    ( SourceName, Line, Column
    , SourcePos
    , sourceLine, sourceColumn, sourceName
    , incSourceLine, incSourceColumn
    , setSourceLine, setSourceColumn, setSourceName
    , newPos, initialPos
    , updatePosChar, updatePosString
    ) where
#ifdef BASE3
import Data.Generics
#else
import Data.Data (Data)
import Data.Typeable (Typeable)
#endif
type SourceName = String
type Line       = Int
type Column     = Int
data SourcePos  = SourcePos SourceName !Line !Column
    deriving ( Eq, Ord, Data, Typeable)
newPos :: SourceName -> Line -> Column -> SourcePos
newPos name line column
    = SourcePos name line column
initialPos :: SourceName -> SourcePos
initialPos name
    = newPos name 1 1
sourceName :: SourcePos -> SourceName
sourceName (SourcePos name _line _column) = name
sourceLine :: SourcePos -> Line
sourceLine (SourcePos _name line _column) = line
sourceColumn :: SourcePos -> Column
sourceColumn (SourcePos _name _line column) = column
incSourceLine :: SourcePos -> Line -> SourcePos
incSourceLine (SourcePos name line column) n = SourcePos name (line+n) column
incSourceColumn :: SourcePos -> Column -> SourcePos
incSourceColumn (SourcePos name line column) n = SourcePos name line (column+n)
setSourceName :: SourcePos -> SourceName -> SourcePos
setSourceName (SourcePos _name line column) n = SourcePos n line column
setSourceLine :: SourcePos -> Line -> SourcePos
setSourceLine (SourcePos name _line column) n = SourcePos name n column
setSourceColumn :: SourcePos -> Column -> SourcePos
setSourceColumn (SourcePos name line _column) n = SourcePos name line n
updatePosString :: SourcePos -> String -> SourcePos
updatePosString pos string
    = foldl updatePosChar pos string
updatePosChar   :: SourcePos -> Char -> SourcePos
updatePosChar (SourcePos name line column) c
    = case c of
        '\n' -> SourcePos name (line+1) 1
        '\t' -> SourcePos name line (column + 8  ((column1) `mod` 8))
        _    -> SourcePos name line (column + 1)
instance Show SourcePos where
  show (SourcePos name line column)
    | null name = showLineColumn
    | otherwise = "\"" ++ name ++ "\" " ++ showLineColumn
    where
      showLineColumn    = "(line " ++ show line ++
                          ", column " ++ show column ++
                          ")"