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 -> Int
line   (Pos Int
l Int
_ Filename
_) = Int
l
   column :: Pos -> Int
column (Pos Int
_ Int
c Filename
_) = Int
c
   file :: Pos -> Filename
file   (Pos Int
_ Int
_ Filename
f) = Filename
f

data Pos = Pos !Line !Column Filename 

instance Show Pos where
  show :: Pos -> Filename
show (Pos Int
l Int
c Filename
f) | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== (-Int
1) = Filename
""
                   | Bool
otherwise = let file :: Filename
file = if Filename -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Filename
f then Filename
"" else ShowS
forall a. Show a => a -> Filename
show Filename
f
                                     lc :: Filename
lc = Filename
"(line " Filename -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Filename
forall a. Show a => a -> Filename
show Int
l Filename -> ShowS
forall a. [a] -> [a] -> [a]
++ Filename
", column " Filename -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Filename
forall a. Show a => a -> Filename
show Int
c Filename -> ShowS
forall a. [a] -> [a] -> [a]
++Filename
")"
                                 in Filename
file Filename -> ShowS
forall a. [a] -> [a] -> [a]
++ Filename
lc
initPos :: FilePath -> Pos
initPos :: Filename -> Pos
initPos Filename
fn = Int -> Int -> Filename -> Pos
Pos Int
1 Int
1 Filename
fn

noPos :: Pos
noPos :: Pos
noPos = Int -> Int -> Filename -> Pos
Pos (-Int
1) (-Int
1) Filename
""

advl ::  Line -> Pos ->Pos
advl :: Int -> Pos -> Pos
advl Int
i (Pos Int
l Int
c Filename
f) = (Int -> Int -> Filename -> Pos
Pos (Int
lInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
i) Int
1 Filename
f)

advc :: Column -> Pos ->  Pos
advc :: Int -> Pos -> Pos
advc Int
i (Pos Int
l Int
c Filename
f) = (Int -> Int -> Filename -> Pos
Pos Int
l (Int
cInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
i) Filename
f)

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

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

tab              :: Pos -> Pos
tab :: Pos -> Pos
tab  (Pos Int
l Int
c Filename
f) =  Int -> Int -> Filename -> Pos
Pos Int
l (Int
cInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int -> Int
tabWidth Int
c) Filename
f

newl :: Pos ->Pos
newl :: Pos -> Pos
newl =  Int -> Pos -> Pos
advl Int
1

tabWidth :: Column -> Int
tabWidth :: Int -> Int
tabWidth Int
c = Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- ((Int
cInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
8)


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

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

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

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