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 (SpanOrLoc -> SpanOrLoc -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SpanOrLoc -> SpanOrLoc -> Bool
$c/= :: SpanOrLoc -> SpanOrLoc -> Bool
== :: SpanOrLoc -> SpanOrLoc -> Bool
$c== :: SpanOrLoc -> SpanOrLoc -> Bool
Eq, Eq SpanOrLoc
SpanOrLoc -> SpanOrLoc -> Bool
SpanOrLoc -> SpanOrLoc -> Ordering
SpanOrLoc -> SpanOrLoc -> SpanOrLoc
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SpanOrLoc -> SpanOrLoc -> SpanOrLoc
$cmin :: SpanOrLoc -> SpanOrLoc -> SpanOrLoc
max :: SpanOrLoc -> SpanOrLoc -> SpanOrLoc
$cmax :: SpanOrLoc -> SpanOrLoc -> SpanOrLoc
>= :: SpanOrLoc -> SpanOrLoc -> Bool
$c>= :: SpanOrLoc -> SpanOrLoc -> Bool
> :: SpanOrLoc -> SpanOrLoc -> Bool
$c> :: SpanOrLoc -> SpanOrLoc -> Bool
<= :: SpanOrLoc -> SpanOrLoc -> Bool
$c<= :: SpanOrLoc -> SpanOrLoc -> Bool
< :: SpanOrLoc -> SpanOrLoc -> Bool
$c< :: SpanOrLoc -> SpanOrLoc -> Bool
compare :: SpanOrLoc -> SpanOrLoc -> Ordering
$ccompare :: SpanOrLoc -> SpanOrLoc -> Ordering
Ord)

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

span :: Span -> SpanOrLoc
span :: Span -> SpanOrLoc
span = Span -> SpanOrLoc
Span

loc :: Loc -> SpanOrLoc
loc :: Loc -> SpanOrLoc
loc = Loc -> SpanOrLoc
Loc

spanOrLoc :: (Span -> a) -> (Loc -> a) -> SpanOrLoc -> a
spanOrLoc :: forall a. (Span -> a) -> (Loc -> a) -> SpanOrLoc -> a
spanOrLoc Span -> a
f Loc -> a
_ (Span Span
x) = Span -> a
f Span
x
spanOrLoc Span -> a
_ Loc -> a
f (Loc Loc
x) = Loc -> a
f Loc
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 :: Loc -> Loc -> SpanOrLoc
fromTo Loc
a Loc
b =
  forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Loc -> SpanOrLoc
Loc Loc
a) Span -> SpanOrLoc
Span (Loc -> Loc -> Maybe Span
Span.fromToMay Loc
a Loc
b)

start :: SpanOrLoc -> Loc
start :: SpanOrLoc -> Loc
start = forall a. (Span -> a) -> (Loc -> a) -> SpanOrLoc -> a
spanOrLoc Span -> Loc
Span.start forall a. a -> a
id

end :: SpanOrLoc -> Loc
end :: SpanOrLoc -> Loc
end = forall a. (Span -> a) -> (Loc -> a) -> SpanOrLoc -> a
spanOrLoc Span -> Loc
Span.end forall a. a -> a
id