module Language.Haskell.Lexer.Position where

-- | The posisiotn within a file.
data Pos = Pos { Pos -> Int
char, Pos -> Int
line, Pos -> Int
column :: !Int } deriving (Int -> Pos -> ShowS
[Pos] -> ShowS
Pos -> String
(Int -> Pos -> ShowS)
-> (Pos -> String) -> ([Pos] -> ShowS) -> Show Pos
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Pos] -> ShowS
$cshowList :: [Pos] -> ShowS
show :: Pos -> String
$cshow :: Pos -> String
showsPrec :: Int -> Pos -> ShowS
$cshowsPrec :: Int -> Pos -> ShowS
Show)

-- | The line and column numbers of a position.
simpPos :: Pos -> (Int,Int)
simpPos :: Pos -> (Int, Int)
simpPos (Pos _ l :: Int
l c :: Int
c) = (Int
l,Int
c)

-- Some functions still put fake char positions in Pos values, so...
instance Eq Pos where p1 :: Pos
p1 == :: Pos -> Pos -> Bool
== p2 :: Pos
p2 = Pos -> (Int, Int)
simpPos Pos
p1 (Int, Int) -> (Int, Int) -> Bool
forall a. Eq a => a -> a -> Bool
== Pos -> (Int, Int)
simpPos Pos
p2
instance Ord Pos where compare :: Pos -> Pos -> Ordering
compare p1 :: Pos
p1 p2 :: Pos
p2 = (Int, Int) -> (Int, Int) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Pos -> (Int, Int)
simpPos Pos
p1) (Pos -> (Int, Int)
simpPos Pos
p2)

-- | The first column is designated column 1, not 0.
startPos :: Pos
startPos :: Pos
startPos = $WPos :: Int -> Int -> Int -> Pos
Pos { char :: Int
char = 0, line :: Int
line = 1, column :: Int
column = 1 }

-- | Advance position by a string.
nextPos :: Pos -> String -> Pos
nextPos :: Pos -> String -> Pos
nextPos = (Pos -> Char -> Pos) -> Pos -> String -> Pos
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Pos -> Char -> Pos
nextPos1

-- | Advance position by a single character.
nextPos1 :: Pos -> Char -> Pos
nextPos1 :: Pos -> Char -> Pos
nextPos1 (Pos n :: Int
n y :: Int
y x :: Int
x) c :: Char
c =
    case Char
c of
      -- The characters newline, return, linefeed, and formfeed, all start
      -- a new line.
      '\CR' -> Int -> Int -> Int -> Pos
Pos (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) (Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) 1
      '\LF' -> Int -> Int -> Int -> Pos
Pos (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) (Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) 1
      '\FF' -> Int -> Int -> Int -> Pos
Pos (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) (Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) 1
      -- Tab stops are 8 characters apart.
      -- A tab character causes the insertion of enough spaces to align the
      -- current position with the next tab stop.
      -- + (not in the report) the first tab stop is column 1.
      '\t'  -> Int -> Int -> Int -> Pos
Pos (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) Int
y (Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
+8Int -> Int -> Int
forall a. Num a => a -> a -> a
-(Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
-1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` 8)
      _ -> Int -> Int -> Int -> Pos
Pos (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) Int
y (Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
+1)