packages feed

ariadne-0.1: Ariadne/SrcMap.hs

-- | A map indexed by 'SrcSpan' and addressable by 'SrcLoc'.
--
-- Notes:
--
-- * the 'srcFilename' component is ignored
--
-- * when some of the inserted intervals are overlapping, the behaviour is
-- undefined
{-# LANGUAGE ViewPatterns #-}
module Ariadne.SrcMap
  ( SrcMap
  , insert
  , lookup
  , union
  , empty
  , singleton
  ) where

import Prelude hiding (lookup)
import Language.Haskell.Exts.SrcLoc hiding (Loc(..))
import qualified Data.Map as Map
import Data.Monoid

-- | @Loc line column@
data Loc = Loc !Int !Int
  deriving (Eq, Ord, Show)

newtype SrcMap a =
  SrcMap
  { unSrcMap :: Map.Map {- end -} Loc ({- start -} Loc, a)
  } deriving Show

instance Monoid (SrcMap a) where
  mempty = empty
  mappend = union

spanStart, spanEnd :: SrcSpan -> Loc
spanStart = uncurry Loc . srcSpanStart
spanEnd = uncurry Loc . srcSpanEnd

fromSrcLoc :: SrcLoc -> Loc
fromSrcLoc SrcLoc { srcLine = line, srcColumn = col } = Loc line col

insert :: SrcSpan -> a -> SrcMap a -> SrcMap a
insert span value (SrcMap m) =
  SrcMap $ Map.insert (spanEnd span) (spanStart span, value) m

lookup :: SrcLoc -> SrcMap a -> Maybe a
lookup (fromSrcLoc -> loc) (SrcMap map) =
  case Map.split loc map of
    (_less, greater)
      | Map.null greater -> Nothing
      | otherwise ->
        case Map.findMin greater of
         (_, (start, value))
          | start <= loc -> Just value
          | otherwise -> Nothing

union :: SrcMap a -> SrcMap a -> SrcMap a
union (SrcMap a) (SrcMap b) = SrcMap (a `Map.union` b)

empty :: SrcMap a
empty = SrcMap Map.empty

singleton :: SrcSpan -> a -> SrcMap a
singleton span value = insert span value empty