tilia-0.0.2.0: src/Tilia/Span.hs
-- | Regions of the input, and the questions asked about them.
module Tilia.Span
( Span (..),
mkSpan,
isSingleLine,
sameLine,
blankBetween,
meets,
covers,
startOf,
endOf,
startPoint,
endPoint,
)
where
-- | A region of the input.
data Span = Span
{ spanStartLine :: !Int,
spanStartColumn :: !Int,
spanEndLine :: !Int,
spanEndColumn :: !Int
}
deriving (Eq, Ord, Show)
-- | Build a 'Span' from start and end positions, each a line and a column.
mkSpan :: (Int, Int) -> (Int, Int) -> Span
mkSpan (sl, sc) (el, ec) = Span sl sc el ec
-- | The smallest span covering both arguments.
instance Semigroup Span where
a <> b =
Span
{ spanStartLine = min (spanStartLine a) (spanStartLine b),
spanStartColumn = case compare (spanStartLine a) (spanStartLine b) of
LT -> spanStartColumn a
GT -> spanStartColumn b
EQ -> min (spanStartColumn a) (spanStartColumn b),
spanEndLine = max (spanEndLine a) (spanEndLine b),
spanEndColumn = case compare (spanEndLine a) (spanEndLine b) of
GT -> spanEndColumn a
LT -> spanEndColumn b
EQ -> max (spanEndColumn a) (spanEndColumn b)
}
-- | Did this occupy a single line of the input?
isSingleLine :: Span -> Bool
isSingleLine s = spanStartLine s == spanEndLine s
-- | Did the second thing begin on the line the first thing ended on?
sameLine :: Maybe Span -> Maybe Span -> Bool
sameLine (Just a) (Just b) = spanEndLine a == spanStartLine b
sameLine _ _ = False
-- | Was there an empty line between the two?
blankBetween :: Maybe Span -> Maybe Span -> Bool
blankBetween (Just a) (Just b) = spanStartLine b > spanEndLine a + 1
blankBetween _ _ = False
-- | Do the two cover any of the same input?
--
-- Touching counts: a span ending where the next begins shares that
-- position, and the callers that ask this are asking whether the two are
-- looking at one thing, not whether either strictly contains the other.
meets :: Span -> Span -> Bool
meets a b = startPoint a <= endPoint b && startPoint b <= endPoint a
-- | Does the first cover all of the second?
covers :: Span -> Span -> Bool
covers a b = startPoint a <= startPoint b && endPoint b <= endPoint a
-- | A zero-width span at the start of the given one.
startOf :: Span -> Span
startOf s = at (spanStartLine s, spanStartColumn s)
-- | A zero-width span at the end of the given one.
endOf :: Span -> Span
endOf s = at (spanEndLine s, spanEndColumn s)
-- | A zero-width span at the given position.
at :: (Int, Int) -> Span
at position = mkSpan position position
-- | Where a span begins, as a position two of them may be compared by.
startPoint :: Span -> (Int, Int)
startPoint s = (spanStartLine s, spanStartColumn s)
-- | Where a span ends.
endPoint :: Span -> (Int, Int)
endPoint s = (spanEndLine s, spanEndColumn s)