smuggler2-0.3.4.1: src/Smuggler2/Anns.hs
-- |
-- Description: Utility functions for transforming and manipulating
-- 'ghc-exactprint' 'Language.Haskell.GHC.ExactPrint.Anns'
module Smuggler2.Anns
( mkLocWithAnns,
mkLoc,
mkParenT,
setAnnsForT,
swapEntryDPT,
)
where
import Data.Generics as SYB (Data)
import qualified Data.Map.Strict as Map (alter, fromList, insert, lookup, toList, union)
import Data.Maybe (fromMaybe)
import GHC (AnnKeywordId (AnnCloseP, AnnOpenP))
import GhcPlugins (GenLocated (L), Located)
import Language.Haskell.GHC.ExactPrint
( Annotation (annEntryDelta, annPriorComments, annsDP),
TransformT,
modifyAnnsT,
uniqueSrcSpanT,
)
import Language.Haskell.GHC.ExactPrint.Types (DeltaPos (..), KeywordId (G), annNone, mkAnnKey)
-- Inspired by retrie
-- | Generates a unique location and wraps the given ast chunk with that location
-- Also adds a DP and an annotation at that location
mkLocWithAnns :: (Data e, Monad m) => e -> DeltaPos -> [(KeywordId, DeltaPos)] -> TransformT m (Located e)
mkLocWithAnns e dp anns = do
le <- L <$> uniqueSrcSpanT <*> pure e
setAnnsForT le dp anns
-- | `mkLoc` generates a unique location and wraps the given ast chunk with that location
-- Also adds an empty annotation at that location
mkLoc :: (Data e, Monad m) => e -> TransformT m (Located e)
mkLoc e = mkLocWithAnns e (DP (0, 0)) []
-- | Add an open and close paren annotation to a located thing
mkParenT ::
(Data x, Monad m) =>
(Located x -> x) ->
Located x ->
TransformT m (Located x)
mkParenT k e = do
pe <- mkLoc (k e)
_ <- setAnnsForT pe (DP (0, 0)) [(G GHC.AnnOpenP, DP (0, 1)), (G GHC.AnnCloseP, DP (0, 1))]
swapEntryDPT e pe
return pe
-- | Set the `ghc-exactprint` annotations for a 'Located' thing
setAnnsForT ::
(Data e, Monad m) =>
Located e ->
DeltaPos ->
[(KeywordId, DeltaPos)] ->
TransformT m (Located e)
setAnnsForT e dp anns = modifyAnnsT (Map.alter f (mkAnnKey e)) >> return e
where
f Nothing = Just annNone {annEntryDelta = dp, annsDP = anns}
f (Just a) =
Just
a
{ annEntryDelta = dp,
annsDP =
Map.toList $
Map.union (Map.fromList anns) (Map.fromList (annsDP a))
}
-- | Swap two 'Located' things' relative position tage ('DeltaPos')
swapEntryDPT ::
(Data a, Data b, Monad m) => Located a -> Located b -> TransformT m ()
swapEntryDPT a b = modifyAnnsT $ \anns ->
let akey = mkAnnKey a
bkey = mkAnnKey b
aann = fromMaybe annNone $ Map.lookup akey anns
bann = fromMaybe annNone $ Map.lookup bkey anns
in Map.insert
akey
aann
{ annEntryDelta = annEntryDelta bann,
annPriorComments = annPriorComments bann
}
$ Map.insert
bkey
bann
{ annEntryDelta = annEntryDelta aann,
annPriorComments = annPriorComments aann
}
anns