    module UU.Scanner.Position where

    type Line     = Int
    type Column   = Int
    type Filename = String

    class Position p where
      line   :: p -> Line
      column :: p -> Column
      file   :: p -> Filename

    instance Position Pos where
       line   (Pos l _ _) = l
       column (Pos _ c _) = c
       file   (Pos _ _ f) = f

    data Pos = Pos !Line !Column Filename

    instance Show Pos where
      show (Pos l c f) | l == (-1) = ""
                       | otherwise = let file = if null f then "" else show f
                                         lc = "(line " ++ show l ++ ", column " ++ show c ++")"
                                     in file ++ lc
    initPos :: FilePath -> Pos
    initPos fn = Pos 1 1 fn

    noPos :: Pos
    noPos = Pos (-1) (-1) ""

    advl ::  Line -> Pos ->Pos
    advl i (Pos l c f) = (Pos (l+i) 1 f)

    advc :: Column -> Pos ->  Pos
    advc i (Pos l c f) = (Pos l (c+i) f)

    adv :: Pos -> Char -> Pos
    adv pos c = case c of
      '\t' -> advc (tabWidth (column pos)) pos
      '\n' -> advl 1 pos
      _    -> advc 1 pos

    updPos :: Char -> Pos -> Pos
    updPos x = case x of
     '\n' -> newl
     '\t' -> tab
     _    -> advc 1

    tab              :: Pos -> Pos
    tab  (Pos l c f) =  Pos l (c+tabWidth c) f

    newl :: Pos ->Pos
    newl =  advl 1

    tabWidth :: Column -> Int
    tabWidth c = 8 - ((c-1) `mod` 8)

    updPos' :: Char -> Pos -> (Pos -> a) -> a
    updPos' c p cont = p `seq` cont (updPos c p)

    advc' :: Int -> Pos -> (Pos -> a) -> a
    advc' i p cont = p `seq` cont (advc i p)

    tab' :: Pos -> (Pos -> a) -> a
    tab'  p cont = p `seq` cont (tab p)

    newl' :: Pos -> (Pos -> a) -> a
    newl' p cont = p `seq` cont (newl p)