-- Simple data type to keep track of character positions
-- within a text file or other text stream.
module Text.Packrat.Pos where


data Pos = Pos { Pos -> String
posFile  :: !String
               , Pos -> Int
posLine  :: !Int
               , Pos -> Int
posCol   :: !Int
               }

nextPos :: Pos -> Char -> Pos
nextPos :: Pos -> Char -> Pos
nextPos (Pos String
file Int
line Int
col) Char
c
    | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n' = String -> Int -> Int -> Pos
Pos String
file (Int
line Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
1
    | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\t' = String -> Int -> Int -> Pos
Pos String
file Int
line ((Int -> Int -> Int
forall a. Integral a => a -> a -> a
div (Int
col Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int
8) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
    | Bool
otherwise = String -> Int -> Int -> Pos
Pos String
file Int
line (Int
col Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)

instance Eq Pos where
    Pos String
f1 Int
l1 Int
c1 == :: Pos -> Pos -> Bool
== Pos String
f2 Int
l2 Int
c2 =
         String
f1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
f2 Bool -> Bool -> Bool
&& Int
l1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
l2 Bool -> Bool -> Bool
&& Int
c1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
c2

instance Ord Pos where
    Pos String
_ Int
l1 Int
c1 <= :: Pos -> Pos -> Bool
<= Pos String
_ Int
l2 Int
c2 =
         (Int
l1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
l2) Bool -> Bool -> Bool
|| (Int
l1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
l2 Bool -> Bool -> Bool
&& Int
c1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
c2)

instance Show Pos where
    show :: Pos -> String
show (Pos String
file Int
line Int
col) = String
file String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
":" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
line String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
":" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
col


showPosRel :: Pos -> Pos -> String
showPosRel :: Pos -> Pos -> String
showPosRel (Pos String
file Int
line Int
_) (Pos String
file' Int
line' Int
col')
    | String
file String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
file' =
        if (Int
line Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
line')
        then String
"column " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
col'
        else String
"line " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
line' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
", column " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
col'
    | Bool
otherwise = Pos -> String
forall a. Show a => a -> String
show (String -> Int -> Int -> Pos
Pos String
file' Int
line' Int
col')