text-loc-0.1: src/Text/Loc.hs
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
-- | This modules provides data types that describe line-column locations
-- within a text.
module Text.Loc
( HasLoc(..)
, LocLens(..)
, Span(..)
, SpannedLoc(..)
, locStart
, locEnd
, spanOf
, startOf
, endOf
, SpannedLens(..)
, lStart
, lEnd
, lSpanOf
, lEndOf
, lStartOf
, Located(..)
, LineCol(..)
, nextLine
, nextCol
, LineColLoc(..)
, locLine
, locCol
, lineColOf
, lineOf
, colOf
, LineColLens(..)
, lLine
, lCol
, lLineColOf
, lLineOf
, lColOf
, SrcLoc(..)
, srcOf
, SrcLens(..)
, lSrcOf
, InSrc(..)
, FromLoc(..)
, fromOf
, FromLens(..)
, lFromOf
, Nested(..)
) where
import GHC.Generics (Generic)
import Data.Typeable (Typeable)
import Data.Foldable (Foldable)
import Data.Traversable (Traversable)
import Data.Hashable (Hashable(..))
import Data.Word (Word)
-- | Values with associated source locations.
class HasLoc α where
type LocOf α
locOf ∷ α → LocOf α
-- | Values with editable associated source locations.
class HasLoc α ⇒ LocLens α where
lLocOf ∷ Functor f ⇒ (LocOf α → f (LocOf α)) → α → f α
-- | A region of text between two locations.
data Span l = Span l l
deriving (Typeable, Generic, Show, Read, Eq, Ord,
Functor, Foldable, Traversable)
instance Hashable l ⇒ Hashable (Span l) where
hashWithSalt salt (Span s e) = hashWithSalt salt (s, e)
{-# INLINE hashWithSalt #-}
instance HasLoc (Span l) where
type LocOf (Span l) = Span l
locOf = id
{-# INLINE locOf #-}
instance LocLens (Span l) where
lLocOf = id
{-# INLINE lLocOf #-}
-- | Spanned locations.
class SpannedLoc l where
type SpanLoc l
locSpan ∷ l → Span (SpanLoc l)
instance SpannedLoc (Span l) where
type SpanLoc (Span l) = l
locSpan = id
{-# INLINE locSpan #-}
-- | The start of a span.
locStart ∷ SpannedLoc l ⇒ l → SpanLoc l
locStart l = let Span s _ = locSpan l in s
{-# INLINE locStart #-}
-- | The end of a span.
locEnd ∷ SpannedLoc l ⇒ l → SpanLoc l
locEnd l = let Span _ e = locSpan l in e
{-# INLINE locEnd #-}
-- | The span of the associated location.
spanOf ∷ (HasLoc α, SpannedLoc (LocOf α)) ⇒ α → Span (SpanLoc (LocOf α))
spanOf = locSpan . locOf
{-# INLINE spanOf #-}
-- | The start of the associated location.
startOf ∷ (HasLoc α, SpannedLoc (LocOf α)) ⇒ α → SpanLoc (LocOf α)
startOf = locStart . locOf
{-# INLINE startOf #-}
-- | The end of the associated location.
endOf ∷ (HasLoc α, SpannedLoc (LocOf α)) ⇒ α → SpanLoc (LocOf α)
endOf = locEnd . locOf
{-# INLINE endOf #-}
-- | Editable spanned locations.
class SpannedLoc l ⇒ SpannedLens l where
lSpan ∷ Functor f ⇒ (Span (SpanLoc l) → f (Span (SpanLoc l))) → l → f l
instance SpannedLens (Span l) where
lSpan = id
{-# INLINE lSpan #-}
-- | Provides access to the start of a location.
lStart ∷ (Functor f, SpannedLens l) ⇒ (SpanLoc l → f (SpanLoc l)) → l → f l
lStart f = lSpan (\(Span s e) → fmap (flip Span e) (f s))
{-# INLINE lStart #-}
-- | Provides access to the end of a location.
lEnd ∷ (Functor f, SpannedLens l) ⇒ (SpanLoc l → f (SpanLoc l)) → l → f l
lEnd f = lSpan (\(Span s e) → fmap (Span s) (f e))
{-# INLINE lEnd #-}
-- | Provides access to the span of the associated location.
lSpanOf ∷ (Functor f, LocLens α, SpannedLens (LocOf α))
⇒ (Span (SpanLoc (LocOf α)) → f (Span (SpanLoc (LocOf α)))) → α → f α
lSpanOf = lLocOf . lSpan
{-# INLINE lSpanOf #-}
-- | Provides access to the start of the associated location.
lStartOf ∷ (Functor f, LocLens α, SpannedLens (LocOf α))
⇒ (SpanLoc (LocOf α) → f (SpanLoc (LocOf α))) → α → f α
lStartOf = lLocOf . lStart
{-# INLINE lStartOf #-}
-- | Provides access to the end of the associated location.
lEndOf ∷ (Functor f, LocLens α, SpannedLens (LocOf α))
⇒ (SpanLoc (LocOf α) → f (SpanLoc (LocOf α))) → α → f α
lEndOf = lLocOf . lEnd
{-# INLINE lEndOf #-}
-- | A simple way to attach location to a value.
data Located l α = Located { locAt ∷ l
, locVal ∷ α }
deriving (Typeable, Generic, Show, Read,
Functor, Foldable, Traversable)
instance (Hashable l, Hashable α) ⇒ Hashable (Located l α) where
hashWithSalt salt (Located l a) = hashWithSalt salt (l, a)
{-# INLINE hashWithSalt #-}
instance HasLoc (Located l α) where
type LocOf (Located l α) = l
locOf = locAt
{-# INLINE locOf #-}
instance LocLens (Located l α) where
lLocOf f (Located l a) = fmap (flip Located a) (f l)
{-# INLINE lLocOf #-}
-- | Line-column location within a text.
data LineCol = LineCol {-# UNPACK #-} !Word {-# UNPACK #-} !Word
deriving (Typeable, Generic, Show, Read, Eq, Ord, Bounded)
instance Hashable LineCol where
hashWithSalt salt (LineCol l c) = hashWithSalt salt (l, c)
{-# INLINE hashWithSalt #-}
instance HasLoc LineCol where
type LocOf LineCol = LineCol
locOf = id
{-# INLINE locOf #-}
-- | The location of the start of the next line.
nextLine ∷ LineCol → LineCol
nextLine (LineCol l _) = LineCol (l + 1) 1
{-# INLINE nextLine #-}
-- | The location of the next column.
nextCol ∷ LineCol → LineCol
nextCol (LineCol l c) = LineCol l (c + 1)
{-# INLINE nextCol #-}
-- | Locations with line and column numbers.
class LineColLoc l where
locLineCol ∷ l → LineCol
instance LineColLoc LineCol where
locLineCol = id
{-# INLINE locLineCol #-}
-- | The line number of a location.
locLine ∷ LineColLoc l ⇒ l → Word
locLine l = let LineCol ln _ = locLineCol l in ln
{-# INLINE locLine #-}
-- | The column number of a location.
locCol ∷ LineColLoc l ⇒ l → Word
locCol l = let LineCol _ c = locLineCol l in c
{-# INLINE locCol #-}
-- | The line-column numbers of the associated location.
lineColOf ∷ (HasLoc α, LineColLoc (LocOf α)) ⇒ α → LineCol
lineColOf = locLineCol . locOf
{-# INLINE lineColOf #-}
-- | The line number of the associated location.
lineOf ∷ (HasLoc α, LineColLoc (LocOf α)) ⇒ α → Word
lineOf = locLine . lineColOf
{-# INLINE lineOf #-}
-- | The column number of the associated location.
colOf ∷ (HasLoc α, LineColLoc (LocOf α)) ⇒ α → Word
colOf = locCol . lineColOf
{-# INLINE colOf #-}
-- | Locations with editable line and column numbers.
class LineColLens l where
lLineCol ∷ Functor f ⇒ (LineCol → f LineCol) → l → f l
instance LineColLens LineCol where
lLineCol = id
{-# INLINE lLineCol #-}
-- | Provides access to the line number of a location.
lLine ∷ (Functor f, LineColLens l) ⇒ (Word → f Word) → l → f l
lLine f = lLineCol (\(LineCol l c) → fmap (flip LineCol c) (f l))
{-# INLINE lLine #-}
-- | Provides access to the column number of a location.
lCol ∷ (Functor f, LineColLens l) ⇒ (Word → f Word) → l → f l
lCol f = lLineCol (\(LineCol l c) → fmap (LineCol l) (f c))
{-# INLINE lCol #-}
-- | Provides access to the line-column numbers of the associated location.
lLineColOf ∷ (Functor f, LocLens α, LineColLens (LocOf α))
⇒ (LineCol → f LineCol) → α → f α
lLineColOf = lLocOf . lLineCol
{-# INLINE lLineColOf #-}
-- | Provides access to the line number of the associated location.
lLineOf ∷ (Functor f, LocLens α, LineColLens (LocOf α))
⇒ (Word → f Word) → α → f α
lLineOf = lLocOf . lLine
{-# INLINE lLineOf #-}
-- | Provides access to the column number of the associated location.
lColOf ∷ (Functor f, LocLens α, LineColLens (LocOf α))
⇒ (Word → f Word) → α → f α
lColOf = lLocOf . lCol
{-# INLINE lColOf #-}
-- | Locations with a source (e.g. file name).
class SrcLoc l where
type LocSrc l
locSrc ∷ l → LocSrc l
-- | The source of the associated location.
srcOf ∷ (HasLoc α, SrcLoc (LocOf α)) ⇒ α → LocSrc (LocOf α)
srcOf = locSrc . locOf
{-# INLINE srcOf #-}
-- | Locations with editable source (e.g. file name).
class SrcLoc l ⇒ SrcLens l where
lSrc ∷ Functor f ⇒ (LocSrc l → f (LocSrc l)) → l → f l
-- | Provides access to the source of the associated location.
lSrcOf ∷ (Functor f, LocLens α, SrcLens (LocOf α))
⇒ (LocSrc (LocOf α) → f (LocSrc (LocOf α))) → α → f α
lSrcOf = lLocOf . lSrc
{-# INLINE lSrcOf #-}
-- | A simple way to add source to a location.
data InSrc s l = InSrc { srcSrc ∷ s
, srcLoc ∷ l }
deriving (Typeable, Generic, Show, Read, Eq, Ord)
instance (Hashable s, Hashable l) ⇒ Hashable (InSrc s l) where
hashWithSalt salt (InSrc s l) = hashWithSalt salt (s, l)
{-# INLINE hashWithSalt #-}
instance HasLoc (InSrc s l) where
type LocOf (InSrc s l) = InSrc s l
locOf = id
{-# INLINE locOf #-}
instance LocLens (InSrc s l) where
lLocOf = id
{-# INLINE lLocOf #-}
instance SpannedLoc l ⇒ SpannedLoc (InSrc s l) where
type SpanLoc (InSrc s l) = InSrc s (SpanLoc l)
locSpan (InSrc s l) = fmap (InSrc s) (locSpan l)
{-# INLINE locSpan #-}
instance SpannedLens l ⇒ SpannedLens (InSrc s l) where
lSpan f (InSrc s l) =
fmap (InSrc s) (lSpan (fmap (fmap srcLoc) . f . fmap (InSrc s)) l)
{-# INLINE lSpan #-}
instance LineColLoc l ⇒ LineColLoc (InSrc s l) where
locLineCol = locLineCol . srcLoc
{-# INLINE locLineCol #-}
instance LineColLens l ⇒ LineColLens (InSrc s l) where
lLineCol f (InSrc s l) = fmap (InSrc s) (lLineCol f l)
{-# INLINE lLineCol #-}
instance SrcLoc (InSrc s l) where
type LocSrc (InSrc s l) = s
locSrc = srcSrc
{-# INLINE locSrc #-}
instance SrcLens (InSrc s l) where
lSrc f (InSrc s l) = fmap (flip InSrc l) (f s)
{-# INLINE lSrc #-}
-- | Locations that have parent locations.
class FromLoc l where
type LocFrom l
locFrom ∷ l → LocFrom l
instance FromLoc l ⇒ FromLoc (InSrc s l) where
type LocFrom (InSrc s l) = LocFrom l
locFrom = locFrom . srcLoc
{-# INLINE locFrom #-}
instance FromLens l ⇒ FromLens (InSrc s l) where
lFrom f (InSrc s l) = fmap (InSrc s) (lFrom f l)
{-# INLINE lFrom #-}
-- | The parent of the associated location.
fromOf ∷ (HasLoc α, FromLoc (LocOf α)) ⇒ α → LocFrom (LocOf α)
fromOf = locFrom . locOf
{-# INLINE fromOf #-}
-- | Locations with editable parent locations.
class FromLoc l ⇒ FromLens l where
lFrom ∷ Functor f ⇒ (LocFrom l → f (LocFrom l)) → l → f l
-- | Provides access to the parent of the associated location.
lFromOf ∷ (Functor f, LocLens α, FromLens (LocOf α))
⇒ (LocFrom (LocOf α) → f (LocFrom (LocOf α))) → α → f α
lFromOf = lLocOf . lFrom
{-# INLINE lFromOf #-}
-- | A simple way to nest a location.
data Nested l p = Nested { nestedLoc ∷ l
, nestedFrom ∷ p }
deriving (Typeable, Generic, Show, Read)
instance (Hashable l, Hashable p) ⇒ Hashable (Nested l p) where
hashWithSalt salt (Nested l p) = hashWithSalt salt (l, p)
{-# INLINE hashWithSalt #-}
instance HasLoc (Nested l p) where
type LocOf (Nested l p) = Nested l p
locOf = id
{-# INLINE locOf #-}
instance LocLens (Nested l p) where
lLocOf = id
{-# INLINE lLocOf #-}
instance SpannedLoc l ⇒ SpannedLoc (Nested l p) where
type SpanLoc (Nested l p) = Nested (SpanLoc l) p
locSpan (Nested l p) = fmap (flip Nested p) (locSpan l)
{-# INLINE locSpan #-}
instance SpannedLens l ⇒ SpannedLens (Nested l p) where
lSpan f (Nested l p) =
fmap (flip Nested p)
(lSpan (fmap (fmap nestedLoc) . f . fmap (flip Nested p)) l)
{-# INLINE lSpan #-}
instance LineColLoc l ⇒ LineColLoc (Nested l p) where
locLineCol = locLineCol . nestedLoc
{-# INLINE locLineCol #-}
instance LineColLens l ⇒ LineColLens (Nested l p) where
lLineCol f (Nested l p) = fmap (flip Nested p) (lLineCol f l)
{-# INLINE lLineCol #-}
instance SrcLoc l ⇒ SrcLoc (Nested l p) where
type LocSrc (Nested l p) = LocSrc l
locSrc = locSrc . nestedLoc
{-# INLINE locSrc #-}
instance SrcLens l ⇒ SrcLens (Nested l p) where
lSrc f (Nested l p) = fmap (flip Nested p) (lSrc f l)
{-# INLINE lSrc #-}
instance FromLoc (Nested l p) where
type LocFrom (Nested l p) = p
locFrom = nestedFrom
{-# INLINE locFrom #-}
instance FromLens (Nested l p) where
lFrom f (Nested l p) = fmap (Nested l) (f p)
{-# INLINE lFrom #-}