module Data.Loc (
Pos(..),
posFile,
posLine,
posCol,
posCoff,
startPos,
linePos,
advancePos,
displayPos,
displaySPos,
Loc(..),
locStart,
locEnd,
(<-->),
displayLoc,
displaySLoc,
SrcLoc(..),
srclocOf,
srcspan,
IsLocation(..),
noLoc,
Located(..),
Relocatable(..),
L(..),
unLoc
) where
import Data.Data (Data(..))
import Data.Typeable (Typeable(..))
import Data.List (foldl')
import Data.Monoid (Monoid(..))
#if MIN_VERSION_base(4,9,0) && !(MIN_VERSION_base(4,11,0))
import Data.Semigroup (Semigroup(..))
#endif
data Pos =
Pos !FilePath
!Int
!Int
!Int
deriving (Eq, Read, Show, Data, Typeable)
instance Ord Pos where
compare (Pos f1 l1 c1 _) (Pos f2 l2 c2 _) =
compare (f1, l1, c1) (f2, l2, c2)
posFile :: Pos -> FilePath
posFile (Pos f _ _ _) = f
posLine :: Pos -> Int
posLine (Pos _ l _ _) = l
posCol :: Pos -> Int
posCol (Pos _ _ c _) = c
posCoff :: Pos -> Int
posCoff (Pos _ _ _ coff) = coff
startPos :: FilePath -> Pos
startPos f = Pos f startLine startCol startCoff
startLine :: Int
startLine = 1
startCol :: Int
startCol = 1
startCoff :: Int
startCoff = 0
linePos :: FilePath -> Int -> Pos
linePos f l = Pos f l startCol startCoff
advancePos :: Pos -> Char -> Pos
advancePos (Pos f l _ coff) '\n' = Pos f (l+1) startCol (coff + 1)
advancePos (Pos f l c coff) '\t' = Pos f l nextTabStop (coff + 1)
where nextTabStop = ((c+7) `div` 8) * 8 + 1
advancePos (Pos f l c coff) _ = Pos f l (c + 1) (coff + 1)
data Loc = NoLoc
|
Loc !Pos
!Pos
deriving (Eq, Read, Show, Data, Typeable)
locStart :: Loc -> Loc
locStart NoLoc = NoLoc
locStart (Loc p _) = Loc p p
locEnd :: Loc -> Loc
locEnd NoLoc = NoLoc
locEnd (Loc _ p) = Loc p p
locAppend :: Loc -> Loc -> Loc
locAppend NoLoc l = l
locAppend l NoLoc = l
locAppend (Loc b1 e1) (Loc b2 e2) = Loc (min b1 b2) (max e1 e2)
#if MIN_VERSION_base(4,9,0)
instance Semigroup Loc where
(<>) = locAppend
#endif
instance Monoid Loc where
mempty = NoLoc
#if !(MIN_VERSION_base(4,11,0))
mappend = locAppend
#endif
(<-->) :: (Located a, Located b) => a -> b -> Loc
x <--> y = locOf x `mappend` locOf y
infixl 6 <-->
newtype SrcLoc = SrcLoc Loc
deriving (Monoid, Data, Typeable)
#if MIN_VERSION_base(4,9,0)
instance Semigroup SrcLoc where
SrcLoc l1 <> SrcLoc l2 = SrcLoc (l1 <> l2)
#endif
instance Eq SrcLoc where
_ == _ = True
instance Ord SrcLoc where
compare _ _ = EQ
instance Show SrcLoc where
showsPrec _ _ = showString "noLoc"
instance Read SrcLoc where
readsPrec p s =
readParen False
(\s -> [(SrcLoc NoLoc, s') |
("noLoc", s') <- lex s])
s
++
readParen (p > app_prec)
(\s -> [(SrcLoc l, s'') |
("SrcLoc", s') <- lex s,
(l, s'') <- readsPrec (app_prec+1) s'])
s
where
app_prec = 10
srclocOf :: Located a => a -> SrcLoc
srclocOf = fromLoc . locOf
srcspan :: (Located a, Located b) => a -> b -> SrcLoc
x `srcspan` y = SrcLoc (locOf x `mappend` locOf y)
infixl 6 `srcspan`
class IsLocation a where
fromLoc :: Loc -> a
fromPos :: Pos -> a
fromPos p = fromLoc (Loc p p)
instance IsLocation Loc where
fromLoc = id
instance IsLocation SrcLoc where
fromLoc = SrcLoc
noLoc :: IsLocation a => a
noLoc = fromLoc NoLoc
class Located a where
locOf :: a -> Loc
locOfList :: [a] -> Loc
locOfList xs = mconcat (map locOf xs)
instance Located a => Located [a] where
locOf = locOfList
instance Located a => Located (Maybe a) where
locOf Nothing = NoLoc
locOf (Just x) = locOf x
instance Located Pos where
locOf p = Loc p p
instance Located Loc where
locOf = id
instance Located SrcLoc where
locOf (SrcLoc loc) = loc
class Relocatable a where
reloc :: Loc -> a -> a
data L a = L Loc a
deriving (Functor, Data, Typeable)
unLoc :: L a -> a
unLoc (L _ a) = a
instance Eq x => Eq (L x) where
(L _ x) == (L _ y) = x == y
instance Ord x => Ord (L x) where
compare (L _ x) (L _ y) = compare x y
instance Show x => Show (L x) where
show (L _ x) = show x
instance Located (L a) where
locOf (L loc _) = loc
instance Relocatable (L a) where
reloc loc (L _ x) = L loc x
displayPos :: Pos -> String
displayPos p = displayLoc (Loc p p)
displaySPos :: Pos -> ShowS
displaySPos p = displaySLoc (Loc p p)
displayLoc :: Loc -> String
displayLoc loc = displaySLoc loc ""
displaySLoc :: Loc -> ShowS
displaySLoc NoLoc =
showString "<no location>"
displaySLoc (Loc p1@(Pos src line1 col1 _) (Pos _ line2 col2 _))
| (line1, col1) == (line2, col2) =
showString src . colon . shows line1 . colon . shows col1
| line1 == line2 =
showString src .
colon . shows line1 .
colon . shows col1 .
dash . shows col2
| otherwise =
showString src .
colon . shows line1 .
colon . shows col1 .
dash . shows line2 .
colon . shows col2
where
colon = (':' :)
dash = ('-' :)