packages feed

loc-0.2.0.0: src/Data/Loc/SpanOrLoc.hs

module Data.Loc.SpanOrLoc
  ( SpanOrLoc,

    -- * Constructing
    span,
    loc,
    fromTo,

    -- * Deconstructing
    spanOrLoc,

    -- * Querying
    start,
    end,
  )
where

import Data.Loc.Internal.Prelude
import Data.Loc.Loc (Loc)
import Data.Loc.Loc qualified as Loc
import Data.Loc.Span (Span)
import Data.Loc.Span qualified as Span

-- | A 'SpanOrLoc' consists of a start location and an end location
--
-- The end location must be greater than or equal to the start location;
-- in other words, backwards spans are not permitted.
--
-- If the start and end location are the same, then the value is a 'Loc'.
-- If they differ, then the value is a 'Span'.
data SpanOrLoc = Span Span | Loc Loc
  deriving (Eq, Ord)

instance Show SpanOrLoc where
  showsPrec i = \case
    Span x -> Span.spanShowsPrec i x
    Loc x -> Loc.locShowsPrec i x

span :: Span -> SpanOrLoc
span = Span

loc :: Loc -> SpanOrLoc
loc = Loc

spanOrLoc :: (Span -> a) -> (Loc -> a) -> SpanOrLoc -> a
spanOrLoc f _ (Span x) = f x
spanOrLoc _ f (Loc x) = f x

-- | Construct a 'SpanOrLoc' from two 'Loc's
--
-- If the two locs are not equal, the lesser loc will be the start,
-- and the greater loc will be the end.
fromTo :: Loc -> Loc -> SpanOrLoc
fromTo a b =
  maybe (Loc a) Span (Span.fromToMay a b)

start :: SpanOrLoc -> Loc
start = spanOrLoc Span.start id

end :: SpanOrLoc -> Loc
end = spanOrLoc Span.end id