{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
module Language.Haskell.GHC.ExactPrint.Transform
(
Transform
, TransformT(..)
, runTransform
, runTransformFrom
, runTransformFromT
, logTr
, logDataWithAnnsTr
, getAnnsT, putAnnsT, modifyAnnsT
, uniqueSrcSpanT
, cloneT
, graftT
, getEntryDPT
, setEntryDPT
, transferEntryDPT
, setPrecedingLinesDeclT
, setPrecedingLinesT
, addSimpleAnnT
, addTrailingCommaT
, removeTrailingCommaT
, HasTransform (..)
, HasDecls (..)
, hasDeclsSybTransform
, hsDeclsGeneric
, hsDeclsPatBind, hsDeclsPatBindD
, replaceDeclsPatBind, replaceDeclsPatBindD
, modifyDeclsT
, modifyValD
, hsDeclsValBinds, replaceDeclsValbinds
, insertAtStart
, insertAtEnd
, insertAfter
, insertBefore
, balanceComments
, balanceTrailingComments
, moveTrailingComments
, captureOrder
, captureOrderAnnKey
, isUniqueSrcSpan
, mergeAnns
, mergeAnnList
, setPrecedingLinesDecl
, setPrecedingLines
, getEntryDP
, setEntryDP
, transferEntryDP
, addTrailingComma
, wrapSig, wrapDecl
, decl2Sig, decl2Bind
) where
import Language.Haskell.GHC.ExactPrint.Types
import Language.Haskell.GHC.ExactPrint.Utils
#if __GLASGOW_HASKELL__ > 804
import Control.Monad.Fail
#endif
import Control.Monad.RWS
import qualified Bag as GHC
import qualified FastString as GHC
import qualified GHC as GHC hiding (parseModule)
import qualified Data.Generics as SYB
import Data.Data
import Data.List
import Data.Maybe
import qualified Data.Map as Map
import Data.Functor.Identity
import Control.Monad.State
import Control.Monad.Writer
type Transform = TransformT Identity
newtype TransformT m a = TransformT { runTransformT :: RWST () [String] (Anns,Int) m a }
deriving (Monad,Applicative,Functor
,MonadReader ()
,MonadWriter [String]
,MonadState (Anns,Int)
,MonadTrans
#if __GLASGOW_HASKELL__ > 804
,MonadFail
#endif
)
#if __GLASGOW_HASKELL__ > 804
instance MonadFail Identity where
fail x = Control.Monad.Fail.fail x
#endif
runTransform :: Anns -> Transform a -> (a,(Anns,Int),[String])
runTransform ans f = runTransformFrom 0 ans f
runTransformFrom :: Int -> Anns -> Transform a -> (a,(Anns,Int),[String])
runTransformFrom seed ans f = runRWS (runTransformT f) () (ans,seed)
runTransformFromT :: Int -> Anns -> TransformT m a -> m (a,(Anns,Int),[String])
runTransformFromT seed ans f = runRWST (runTransformT f) () (ans,seed)
logTr :: (Monad m) => String -> TransformT m ()
logTr str = tell [str]
logDataWithAnnsTr :: (Monad m) => (SYB.Data a) => String -> a -> TransformT m ()
logDataWithAnnsTr str ast = do
anns <- getAnnsT
logTr $ str ++ showAnnData anns 0 ast
getAnnsT :: (Monad m) => TransformT m Anns
getAnnsT = gets fst
putAnnsT :: (Monad m) => Anns -> TransformT m ()
putAnnsT ans = do
(_,col) <- get
put (ans,col)
modifyAnnsT :: (Monad m) => (Anns -> Anns) -> TransformT m ()
modifyAnnsT f = do
ans <- getAnnsT
putAnnsT (f ans)
uniqueSrcSpanT :: (Monad m) => TransformT m GHC.SrcSpan
uniqueSrcSpanT = do
(an,col) <- get
put (an,col + 1 )
let pos = GHC.mkSrcLoc (GHC.mkFastString "ghc-exactprint") (-1) col
return $ GHC.mkSrcSpan pos pos
isUniqueSrcSpan :: GHC.SrcSpan -> Bool
isUniqueSrcSpan ss = srcSpanStartLine ss == -1
cloneT :: (Data a,Monad m) => a -> TransformT m (a, [(GHC.SrcSpan, GHC.SrcSpan)])
cloneT ast = do
runWriterT $ SYB.everywhereM (return `SYB.ext2M` replaceLocated) ast
where
replaceLocated :: forall loc a m. (Typeable loc,Data a,Monad m)
=> (GHC.GenLocated loc a) -> WriterT [(GHC.SrcSpan, GHC.SrcSpan)] (TransformT m) (GHC.GenLocated loc a)
replaceLocated (GHC.L l t) = do
case cast l :: Maybe GHC.SrcSpan of
Just ss -> do
newSpan <- lift uniqueSrcSpanT
lift $ modifyAnnsT (\anns -> case Map.lookup (mkAnnKey (GHC.L ss t)) anns of
Nothing -> anns
Just an -> Map.insert (mkAnnKey (GHC.L newSpan t)) an anns)
tell [(ss, newSpan)]
return $ fromJust . cast $ GHC.L newSpan t
Nothing -> return (GHC.L l t)
graftT :: (Data a,Monad m) => Anns -> a -> TransformT m a
graftT origAnns = SYB.everywhereM (return `SYB.ext2M` replaceLocated)
where
replaceLocated :: forall loc a m. (Typeable loc, Data a, Monad m)
=> GHC.GenLocated loc a -> TransformT m (GHC.GenLocated loc a)
replaceLocated (GHC.L l t) = do
case cast l :: Maybe GHC.SrcSpan of
Just ss -> do
newSpan <- uniqueSrcSpanT
modifyAnnsT (\anns -> case Map.lookup (mkAnnKey (GHC.L ss t)) origAnns of
Nothing -> anns
Just an -> Map.insert (mkAnnKey (GHC.L newSpan t)) an anns)
return $ fromJust $ cast $ GHC.L newSpan t
Nothing -> return (GHC.L l t)
captureOrder :: (Data a) => GHC.Located a -> [GHC.Located b] -> Anns -> Anns
captureOrder parent ls ans = captureOrderAnnKey (mkAnnKey parent) ls ans
captureOrderAnnKey :: AnnKey -> [GHC.Located b] -> Anns -> Anns
captureOrderAnnKey parentKey ls ans = ans'
where
newList = map GHC.getLoc ls
reList = Map.adjust (\an -> an {annSortKey = Just newList }) parentKey
ans' = reList ans
decl2Bind :: GHC.LHsDecl name -> [GHC.LHsBind name]
#if __GLASGOW_HASKELL__ > 804
decl2Bind (GHC.L l (GHC.ValD _ s)) = [GHC.L l s]
#else
decl2Bind (GHC.L l (GHC.ValD s)) = [GHC.L l s]
#endif
decl2Bind _ = []
decl2Sig :: GHC.LHsDecl name -> [GHC.LSig name]
#if __GLASGOW_HASKELL__ > 804
decl2Sig (GHC.L l (GHC.SigD _ s)) = [GHC.L l s]
#else
decl2Sig (GHC.L l (GHC.SigD s)) = [GHC.L l s]
#endif
decl2Sig _ = []
wrapSig :: GHC.LSig GhcPs -> GHC.LHsDecl GhcPs
#if __GLASGOW_HASKELL__ > 804
wrapSig (GHC.L l s) = GHC.L l (GHC.SigD GHC.noExt s)
#else
wrapSig (GHC.L l s) = GHC.L l (GHC.SigD s)
#endif
wrapDecl :: GHC.LHsBind GhcPs -> GHC.LHsDecl GhcPs
#if __GLASGOW_HASKELL__ > 804
wrapDecl (GHC.L l s) = GHC.L l (GHC.ValD GHC.noExt s)
#else
wrapDecl (GHC.L l s) = GHC.L l (GHC.ValD s)
#endif
addSimpleAnnT :: (Data a,Monad m) => GHC.Located a -> DeltaPos -> [(KeywordId, DeltaPos)] -> TransformT m ()
addSimpleAnnT ast dp kds = do
let ann = annNone { annEntryDelta = dp
, annsDP = kds
}
modifyAnnsT (Map.insert (mkAnnKey ast) ann)
addTrailingCommaT :: (Data a,Monad m) => GHC.Located a -> TransformT m ()
addTrailingCommaT ast = do
modifyAnnsT (addTrailingComma ast (DP (0,0)))
removeTrailingCommaT :: (Data a,Monad m) => GHC.Located a -> TransformT m ()
removeTrailingCommaT ast = do
modifyAnnsT (removeTrailingComma ast)
getEntryDPT :: (Data a,Monad m) => GHC.Located a -> TransformT m DeltaPos
getEntryDPT ast = do
anns <- getAnnsT
return (getEntryDP anns ast)
setEntryDPT :: (Data a,Monad m) => GHC.Located a -> DeltaPos -> TransformT m ()
setEntryDPT ast dp = do
modifyAnnsT (setEntryDP ast dp)
transferEntryDPT :: (Data a,Data b,Monad m) => GHC.Located a -> GHC.Located b -> TransformT m ()
transferEntryDPT a b =
modifyAnnsT (transferEntryDP a b)
setPrecedingLinesDeclT :: (Monad m) => GHC.LHsDecl GhcPs -> Int -> Int -> TransformT m ()
setPrecedingLinesDeclT ld n c =
modifyAnnsT (setPrecedingLinesDecl ld n c)
setPrecedingLinesT :: (SYB.Data a,Monad m) => GHC.Located a -> Int -> Int -> TransformT m ()
setPrecedingLinesT ld n c =
modifyAnnsT (setPrecedingLines ld n c)
mergeAnns :: Anns -> Anns -> Anns
mergeAnns
= Map.union
mergeAnnList :: [Anns] -> Anns
mergeAnnList [] = error "mergeAnnList must have at lease one entry"
mergeAnnList (x:xs) = foldr mergeAnns x xs
setPrecedingLinesDecl :: GHC.LHsDecl GhcPs -> Int -> Int -> Anns -> Anns
setPrecedingLinesDecl ld n c ans = setPrecedingLines ld n c ans
setPrecedingLines :: (SYB.Data a) => GHC.Located a -> Int -> Int -> Anns -> Anns
setPrecedingLines ast n c anne = setEntryDP ast (DP (n,c)) anne
getEntryDP :: (Data a) => Anns -> GHC.Located a -> DeltaPos
getEntryDP anns ast =
case Map.lookup (mkAnnKey ast) anns of
Nothing -> DP (0,0)
Just ann -> annTrueEntryDelta ann
setEntryDP :: (Data a) => GHC.Located a -> DeltaPos -> Anns -> Anns
setEntryDP ast dp anns =
case Map.lookup (mkAnnKey ast) anns of
Nothing -> Map.insert (mkAnnKey ast) (annNone { annEntryDelta = dp}) anns
Just ann -> Map.insert (mkAnnKey ast) (ann' { annEntryDelta = annCommentEntryDelta ann' dp}) anns
where
ann' = setCommentEntryDP ann dp
setCommentEntryDP :: Annotation -> DeltaPos -> Annotation
setCommentEntryDP ann dp = ann'
where
ann' = case (annPriorComments ann) of
[] -> ann
[(pc,_)] -> ann { annPriorComments = [(pc,dp)] }
((pc,_):pcs) -> ann { annPriorComments = ((pc,dp):pcs) }
transferEntryDP :: (SYB.Data a, SYB.Data b) => GHC.Located a -> GHC.Located b -> Anns -> Anns
transferEntryDP a b anns = (const anns2) anns
where
maybeAnns = do
anA <- Map.lookup (mkAnnKey a) anns
anB <- Map.lookup (mkAnnKey b) anns
let anB' = Ann
{ annEntryDelta = DP (0,0)
, annPriorComments = annPriorComments anB
, annFollowingComments = annFollowingComments anB
, annsDP = annsDP anB
, annSortKey = annSortKey anB
, annCapturedSpan = annCapturedSpan anB
}
return ((Map.insert (mkAnnKey b) anB' anns),annLeadingCommentEntryDelta anA)
(anns',dp) = fromMaybe
(error $ "transferEntryDP: lookup failed (a,b)=" ++ show (mkAnnKey a,mkAnnKey b))
maybeAnns
anns2 = setEntryDP b dp anns'
addTrailingComma :: (SYB.Data a) => GHC.Located a -> DeltaPos -> Anns -> Anns
addTrailingComma a dp anns =
case Map.lookup (mkAnnKey a) anns of
Nothing -> anns
Just an ->
case find isAnnComma (annsDP an) of
Nothing -> Map.insert (mkAnnKey a) (an { annsDP = annsDP an ++ [(G GHC.AnnComma,dp)]}) anns
Just _ -> anns
where
isAnnComma (G GHC.AnnComma,_) = True
isAnnComma _ = False
removeTrailingComma :: (SYB.Data a) => GHC.Located a -> Anns -> Anns
removeTrailingComma a anns =
case Map.lookup (mkAnnKey a) anns of
Nothing -> anns
Just an ->
case find isAnnComma (annsDP an) of
Nothing -> anns
Just _ -> Map.insert (mkAnnKey a) (an { annsDP = filter (not.isAnnComma) (annsDP an) }) anns
where
isAnnComma (G GHC.AnnComma,_) = True
isAnnComma _ = False
balanceComments :: (Data a,Data b,Monad m) => GHC.Located a -> GHC.Located b -> TransformT m ()
balanceComments first second = do
case cast first :: Maybe (GHC.LHsDecl GhcPs) of
#if __GLASGOW_HASKELL__ > 804
Just (GHC.L l (GHC.ValD _ fb@(GHC.FunBind{}))) -> do
#else
Just (GHC.L l (GHC.ValD fb@(GHC.FunBind{}))) -> do
#endif
balanceCommentsFB (GHC.L l fb) second
_ -> case cast first :: Maybe (GHC.LHsBind GhcPs) of
Just fb'@(GHC.L _ (GHC.FunBind{})) -> do
balanceCommentsFB fb' second
_ -> balanceComments' first second
balanceComments' :: (Data a,Data b,Monad m) => GHC.Located a -> GHC.Located b -> TransformT m ()
balanceComments' first second = do
let
k1 = mkAnnKey first
k2 = mkAnnKey second
moveComments p ans = ans'
where
an1 = gfromJust "balanceComments' k1" $ Map.lookup k1 ans
an2 = gfromJust "balanceComments' k2" $ Map.lookup k2 ans
cs1f = annFollowingComments an1
cs2b = annPriorComments an2
(move,stay) = break p cs2b
an1' = an1 { annFollowingComments = cs1f ++ move}
an2' = an2 { annPriorComments = stay}
ans' = Map.insert k1 an1' $ Map.insert k2 an2' ans
simpleBreak (_,DP (r,_c)) = r > 0
modifyAnnsT (moveComments simpleBreak)
balanceCommentsFB :: (Data b,Monad m) => GHC.LHsBind GhcPs -> GHC.Located b -> TransformT m ()
#if __GLASGOW_HASKELL__ > 804
balanceCommentsFB (GHC.L _ (GHC.FunBind _ _ (GHC.MG _ (GHC.L _ matches) _) _ _)) second = do
#elif __GLASGOW_HASKELL__ > 710
balanceCommentsFB (GHC.L _ (GHC.FunBind _ (GHC.MG (GHC.L _ matches) _ _ _) _ _ _)) second = do
#else
balanceCommentsFB (GHC.L _ (GHC.FunBind _ _ (GHC.MG matches _ _ _) _ _ _)) second = do
#endif
balanceComments' (last matches) second
balanceCommentsFB f s = balanceComments' f s
balanceTrailingComments :: (Monad m) => (Data a,Data b) => GHC.Located a -> GHC.Located b
-> TransformT m [(Comment, DeltaPos)]
balanceTrailingComments first second = do
let
k1 = mkAnnKey first
k2 = mkAnnKey second
moveComments p ans = (ans',move)
where
an1 = gfromJust "balanceTrailingComments k1" $ Map.lookup k1 ans
an2 = gfromJust "balanceTrailingComments k2" $ Map.lookup k2 ans
cs1f = annFollowingComments an1
(move,stay) = break p cs1f
an1' = an1 { annFollowingComments = stay }
ans' = Map.insert k1 an1' $ Map.insert k2 an2 ans
simpleBreak (_,DP (r,_c)) = r > 0
ans <- getAnnsT
let (ans',mov) = moveComments simpleBreak ans
putAnnsT ans'
return mov
moveTrailingComments :: (Data a,Data b)
=> GHC.Located a -> GHC.Located b -> Transform ()
moveTrailingComments first second = do
let
k1 = mkAnnKey first
k2 = mkAnnKey second
moveComments ans = ans'
where
an1 = gfromJust "moveTrailingComments k1" $ Map.lookup k1 ans
an2 = gfromJust "moveTrailingComments k2" $ Map.lookup k2 ans
cs1f = annFollowingComments an1
cs2f = annFollowingComments an2
an1' = an1 { annFollowingComments = [] }
an2' = an2 { annFollowingComments = cs1f ++ cs2f }
ans' = Map.insert k1 an1' $ Map.insert k2 an2' ans
modifyAnnsT moveComments
insertAt :: (HasDecls (GHC.Located ast))
=> (GHC.LHsDecl GhcPs
-> [GHC.LHsDecl GhcPs]
-> [GHC.LHsDecl GhcPs])
-> GHC.Located ast
-> GHC.LHsDecl GhcPs
-> Transform (GHC.Located ast)
insertAt f t decl = do
oldDecls <- hsDecls t
replaceDecls t (f decl oldDecls)
insertAtStart, insertAtEnd :: (HasDecls (GHC.Located ast))
=> GHC.Located ast
-> GHC.LHsDecl GhcPs
-> Transform (GHC.Located ast)
insertAtStart = insertAt (:)
insertAtEnd = insertAt (\x xs -> xs ++ [x])
insertAfter, insertBefore :: (HasDecls (GHC.Located ast))
=> GHC.Located old
-> GHC.Located ast
-> GHC.LHsDecl GhcPs
-> Transform (GHC.Located ast)
insertAfter (GHC.getLoc -> k) = insertAt findAfter
where
findAfter x xs =
let (fs, b:bs) = span (\(GHC.L l _) -> l /= k) xs
in fs ++ (b : x : bs)
insertBefore (GHC.getLoc -> k) = insertAt findBefore
where
findBefore x xs =
let (fs, bs) = span (\(GHC.L l _) -> l /= k) xs
in fs ++ (x : bs)
class (Data t) => HasDecls t where
hsDecls :: (Monad m) => t -> TransformT m [GHC.LHsDecl GhcPs]
replaceDecls :: (Monad m) => t -> [GHC.LHsDecl GhcPs] -> TransformT m t
instance HasDecls GHC.ParsedSource where
hsDecls (GHC.L _ (GHC.HsModule _mn _exps _imps decls _ _)) = return decls
replaceDecls m@(GHC.L l (GHC.HsModule mn exps imps _decls deps haddocks)) decls
= do
logTr "replaceDecls LHsModule"
modifyAnnsT (captureOrder m decls)
return (GHC.L l (GHC.HsModule mn exps imps decls deps haddocks))
instance HasDecls (GHC.LMatch GhcPs (GHC.LHsExpr GhcPs)) where
#if __GLASGOW_HASKELL__ > 804
hsDecls d@(GHC.L _ (GHC.Match _ _ _ (GHC.GRHSs _ _ (GHC.L _ lb)))) = do
#elif __GLASGOW_HASKELL__ >= 804
hsDecls d@(GHC.L _ (GHC.Match _ _ (GHC.GRHSs _ (GHC.L _ lb)))) = do
#elif __GLASGOW_HASKELL__ >= 800
hsDecls d@(GHC.L _ (GHC.Match _ _ _ (GHC.GRHSs _ (GHC.L _ lb)))) = do
#elif __GLASGOW_HASKELL__ >= 710
hsDecls d@(GHC.L _ (GHC.Match _ _ _ (GHC.GRHSs _ lb))) = do
#else
hsDecls d@(GHC.L _ (GHC.Match _ _ _ (GHC.GRHSs _ lb))) = do
#endif
decls <- hsDeclsValBinds lb
orderedDecls d decls
#if __GLASGOW_HASKELL__ > 804
hsDecls (GHC.L _ (GHC.Match _ _ _ (GHC.XGRHSs _))) = return []
hsDecls (GHC.L _ (GHC.XMatch _)) = return []
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDecls m@(GHC.L l (GHC.Match xm c p (GHC.GRHSs xr rhs binds))) []
#elif __GLASGOW_HASKELL__ >= 804
replaceDecls m@(GHC.L l (GHC.Match c p (GHC.GRHSs rhs binds))) []
#else
replaceDecls m@(GHC.L l (GHC.Match mf p t (GHC.GRHSs rhs binds))) []
#endif
= do
logTr "replaceDecls LMatch"
let
noWhere (G GHC.AnnWhere,_) = False
noWhere _ = True
removeWhere mkds =
case Map.lookup (mkAnnKey m) mkds of
Nothing -> error "wtf"
Just ann -> Map.insert (mkAnnKey m) ann1 mkds
where
ann1 = ann { annsDP = filter noWhere (annsDP ann)
}
modifyAnnsT removeWhere
#if __GLASGOW_HASKELL__ <= 710
binds' <- replaceDeclsValbinds binds []
#else
binds'' <- replaceDeclsValbinds (GHC.unLoc binds) []
let binds' = GHC.L (GHC.getLoc binds) binds''
#endif
#if __GLASGOW_HASKELL__ > 804
return (GHC.L l (GHC.Match xm c p (GHC.GRHSs xr rhs binds')))
#elif __GLASGOW_HASKELL__ >= 804
return (GHC.L l (GHC.Match c p (GHC.GRHSs rhs binds')))
#else
return (GHC.L l (GHC.Match mf p t (GHC.GRHSs rhs binds')))
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDecls m@(GHC.L l (GHC.Match xm c p (GHC.GRHSs xr rhs binds))) newBinds
#elif __GLASGOW_HASKELL__ >= 804
replaceDecls m@(GHC.L l (GHC.Match c p (GHC.GRHSs rhs binds))) newBinds
#else
replaceDecls m@(GHC.L l (GHC.Match mf p t (GHC.GRHSs rhs binds))) newBinds
#endif
= do
logTr "replaceDecls LMatch"
#if __GLASGOW_HASKELL__ <= 710
case binds of
#else
case GHC.unLoc binds of
#endif
#if __GLASGOW_HASKELL__ > 804
GHC.EmptyLocalBinds{} -> do
#else
GHC.EmptyLocalBinds -> do
#endif
let
addWhere mkds =
case Map.lookup (mkAnnKey m) mkds of
Nothing -> error "wtf"
Just ann -> Map.insert (mkAnnKey m) ann1 mkds
where
ann1 = ann { annsDP = annsDP ann ++ [(G GHC.AnnWhere,DP (1,2))]
}
modifyAnnsT addWhere
modifyAnnsT (setPrecedingLines (ghead "LMatch.replaceDecls" newBinds) 1 4)
toMove <- balanceTrailingComments m m
insertCommentBefore (mkAnnKey m) toMove (matchApiAnn GHC.AnnWhere)
_ -> return ()
modifyAnnsT (captureOrderAnnKey (mkAnnKey m) newBinds)
#if __GLASGOW_HASKELL__ <= 710
binds' <- replaceDeclsValbinds binds newBinds
#else
binds'' <- replaceDeclsValbinds (GHC.unLoc binds) newBinds
let binds' = GHC.L (GHC.getLoc binds) binds''
#endif
#if __GLASGOW_HASKELL__ > 804
return (GHC.L l (GHC.Match xm c p (GHC.GRHSs xr rhs binds')))
#elif __GLASGOW_HASKELL__ >= 804
return (GHC.L l (GHC.Match c p (GHC.GRHSs rhs binds')))
#else
return (GHC.L l (GHC.Match mf p t (GHC.GRHSs rhs binds')))
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDecls (GHC.L _ (GHC.Match _ _ _ (GHC.XGRHSs _))) _ = error "replaceDecls"
replaceDecls (GHC.L _ (GHC.XMatch _)) _ = error "replaceDecls"
#endif
instance HasDecls (GHC.LHsExpr GhcPs) where
#if __GLASGOW_HASKELL__ > 804
hsDecls ls@(GHC.L _ (GHC.HsLet _ (GHC.L _ decls) _ex)) = do
#elif __GLASGOW_HASKELL__ > 710
hsDecls ls@(GHC.L _ (GHC.HsLet (GHC.L _ decls) _ex)) = do
#else
hsDecls ls@(GHC.L _ (GHC.HsLet decls _ex)) = do
#endif
ds <- hsDeclsValBinds decls
orderedDecls ls ds
hsDecls _ = return []
#if __GLASGOW_HASKELL__ > 804
replaceDecls e@(GHC.L l (GHC.HsLet x decls ex)) newDecls
#else
replaceDecls e@(GHC.L l (GHC.HsLet decls ex)) newDecls
#endif
= do
logTr "replaceDecls HsLet"
modifyAnnsT (captureOrder e newDecls)
#if __GLASGOW_HASKELL__ <= 710
decls' <- replaceDeclsValbinds decls newDecls
#else
decls'' <- replaceDeclsValbinds (GHC.unLoc decls) newDecls
let decls' = GHC.L (GHC.getLoc decls) decls''
#endif
#if __GLASGOW_HASKELL__ > 804
return (GHC.L l (GHC.HsLet x decls' ex))
#else
return (GHC.L l (GHC.HsLet decls' ex))
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDecls (GHC.L l (GHC.HsPar x e)) newDecls
#else
replaceDecls (GHC.L l (GHC.HsPar e)) newDecls
#endif
= do
logTr "replaceDecls HsPar"
e' <- replaceDecls e newDecls
#if __GLASGOW_HASKELL__ > 804
return (GHC.L l (GHC.HsPar x e'))
#else
return (GHC.L l (GHC.HsPar e'))
#endif
replaceDecls old _new = error $ "replaceDecls (GHC.LHsExpr GhcPs) undefined for:" ++ showGhc old
hsDeclsPatBindD :: (Monad m) => GHC.LHsDecl GhcPs -> TransformT m [GHC.LHsDecl GhcPs]
#if __GLASGOW_HASKELL__ > 804
hsDeclsPatBindD (GHC.L l (GHC.ValD _ d)) = hsDeclsPatBind (GHC.L l d)
#else
hsDeclsPatBindD (GHC.L l (GHC.ValD d)) = hsDeclsPatBind (GHC.L l d)
#endif
hsDeclsPatBindD x = error $ "hsDeclsPatBindD called for:" ++ showGhc x
hsDeclsPatBind :: (Monad m) => GHC.LHsBind GhcPs -> TransformT m [GHC.LHsDecl GhcPs]
#if __GLASGOW_HASKELL__ > 804
hsDeclsPatBind d@(GHC.L _ (GHC.PatBind _ _ (GHC.GRHSs _ _grhs (GHC.L _ lb)) _)) = do
#elif __GLASGOW_HASKELL__ > 710
hsDeclsPatBind d@(GHC.L _ (GHC.PatBind _ (GHC.GRHSs _grhs (GHC.L _ lb)) _ _ _)) = do
#else
hsDeclsPatBind d@(GHC.L _ (GHC.PatBind _ (GHC.GRHSs _grhs lb) _ _ _)) = do
#endif
decls <- hsDeclsValBinds lb
orderedDecls d decls
hsDeclsPatBind x = error $ "hsDeclsPatBind called for:" ++ showGhc x
replaceDeclsPatBindD :: (Monad m) => GHC.LHsDecl GhcPs -> [GHC.LHsDecl GhcPs]
-> TransformT m (GHC.LHsDecl GhcPs)
#if __GLASGOW_HASKELL__ > 804
replaceDeclsPatBindD (GHC.L l (GHC.ValD x d)) newDecls = do
(GHC.L _ d') <- replaceDeclsPatBind (GHC.L l d) newDecls
return (GHC.L l (GHC.ValD x d'))
#else
replaceDeclsPatBindD (GHC.L l (GHC.ValD d)) newDecls = do
(GHC.L _ d') <- replaceDeclsPatBind (GHC.L l d) newDecls
return (GHC.L l (GHC.ValD d'))
#endif
replaceDeclsPatBindD x _ = error $ "replaceDeclsPatBindD called for:" ++ showGhc x
replaceDeclsPatBind :: (Monad m) => GHC.LHsBind GhcPs -> [GHC.LHsDecl GhcPs]
-> TransformT m (GHC.LHsBind GhcPs)
#if __GLASGOW_HASKELL__ > 804
replaceDeclsPatBind p@(GHC.L l (GHC.PatBind x a (GHC.GRHSs xr rhss binds) b)) newDecls
#else
replaceDeclsPatBind p@(GHC.L l (GHC.PatBind a (GHC.GRHSs rhss binds) b c d)) newDecls
#endif
= do
logTr "replaceDecls PatBind"
#if __GLASGOW_HASKELL__ <= 710
case binds of
#else
case GHC.unLoc binds of
#endif
#if __GLASGOW_HASKELL__ > 804
GHC.EmptyLocalBinds{} -> do
#else
GHC.EmptyLocalBinds -> do
#endif
let
addWhere mkds =
case Map.lookup (mkAnnKey p) mkds of
Nothing -> error "wtf"
Just ann -> Map.insert (mkAnnKey p) ann1 mkds
where
ann1 = ann { annsDP = annsDP ann ++ [(G GHC.AnnWhere,DP (1,2))]
}
modifyAnnsT addWhere
modifyAnnsT (setPrecedingLines (ghead "LMatch.replaceDecls" newDecls) 1 4)
_ -> return ()
modifyAnnsT (captureOrderAnnKey (mkAnnKey p) newDecls)
#if __GLASGOW_HASKELL__ <= 710
binds' <- replaceDeclsValbinds binds newDecls
#else
binds'' <- replaceDeclsValbinds (GHC.unLoc binds) newDecls
let binds' = GHC.L (GHC.getLoc binds) binds''
#endif
#if __GLASGOW_HASKELL__ > 804
return (GHC.L l (GHC.PatBind x a (GHC.GRHSs xr rhss binds') b))
#else
return (GHC.L l (GHC.PatBind a (GHC.GRHSs rhss binds') b c d))
#endif
replaceDeclsPatBind x _ = error $ "replaceDeclsPatBind called for:" ++ showGhc x
instance HasDecls (GHC.LStmt GhcPs (GHC.LHsExpr GhcPs)) where
#if __GLASGOW_HASKELL__ > 804
hsDecls ls@(GHC.L _ (GHC.LetStmt _ (GHC.L _ lb))) = do
#elif __GLASGOW_HASKELL__ > 710
hsDecls ls@(GHC.L _ (GHC.LetStmt (GHC.L _ lb))) = do
#else
hsDecls ls@(GHC.L _ (GHC.LetStmt lb)) = do
#endif
decls <- hsDeclsValBinds lb
orderedDecls ls decls
#if __GLASGOW_HASKELL__ > 804
hsDecls (GHC.L _ (GHC.LastStmt _ e _ _)) = hsDecls e
#elif __GLASGOW_HASKELL__ >= 804
hsDecls (GHC.L _ (GHC.LastStmt e _ _)) = hsDecls e
#elif __GLASGOW_HASKELL__ > 800
hsDecls (GHC.L _ (GHC.LastStmt e _ _)) = hsDecls e
#elif __GLASGOW_HASKELL__ > 710
hsDecls (GHC.L _ (GHC.LastStmt e _ _)) = hsDecls e
#else
hsDecls (GHC.L _ (GHC.LastStmt e _)) = hsDecls e
#endif
#if __GLASGOW_HASKELL__ > 804
hsDecls (GHC.L _ (GHC.BindStmt _ _pat e _ _)) = hsDecls e
#elif __GLASGOW_HASKELL__ > 710
hsDecls (GHC.L _ (GHC.BindStmt _pat e _ _ _)) = hsDecls e
#else
hsDecls (GHC.L _ (GHC.BindStmt _pat e _ _)) = hsDecls e
#endif
#if __GLASGOW_HASKELL__ > 804
hsDecls (GHC.L _ (GHC.BodyStmt _ e _ _)) = hsDecls e
#else
hsDecls (GHC.L _ (GHC.BodyStmt e _ _ _)) = hsDecls e
#endif
hsDecls _ = return []
#if __GLASGOW_HASKELL__ > 804
replaceDecls s@(GHC.L l (GHC.LetStmt x lb)) newDecls
#else
replaceDecls s@(GHC.L l (GHC.LetStmt lb)) newDecls
#endif
= do
modifyAnnsT (captureOrder s newDecls)
#if __GLASGOW_HASKELL__ <= 710
lb' <- replaceDeclsValbinds lb newDecls
#else
lb'' <- replaceDeclsValbinds (GHC.unLoc lb) newDecls
let lb' = GHC.L (GHC.getLoc lb) lb''
#endif
#if __GLASGOW_HASKELL__ > 804
return (GHC.L l (GHC.LetStmt x lb'))
#else
return (GHC.L l (GHC.LetStmt lb'))
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDecls (GHC.L l (GHC.LastStmt x e d se)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.LastStmt x e' d se))
#elif __GLASGOW_HASKELL__ > 710
replaceDecls (GHC.L l (GHC.LastStmt e d se)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.LastStmt e' d se))
#else
replaceDecls (GHC.L l (GHC.LastStmt e se)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.LastStmt e' se))
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDecls (GHC.L l (GHC.BindStmt x pat e a b)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.BindStmt x pat e' a b))
#elif __GLASGOW_HASKELL__ > 710
replaceDecls (GHC.L l (GHC.BindStmt pat e a b c)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.BindStmt pat e' a b c))
#else
replaceDecls (GHC.L l (GHC.BindStmt pat e a b)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.BindStmt pat e' a b))
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDecls (GHC.L l (GHC.BodyStmt x e a b)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.BodyStmt x e' a b))
#else
replaceDecls (GHC.L l (GHC.BodyStmt e a b c)) newDecls
= do
e' <- replaceDecls e newDecls
return (GHC.L l (GHC.BodyStmt e' a b c))
#endif
replaceDecls x _newDecls = return x
hasDeclsSybTransform :: (SYB.Data t2,Monad m)
=> (forall t. HasDecls t => t -> m t)
-> (GHC.LHsBind GhcPs -> m (GHC.LHsBind GhcPs))
-> t2
-> m t2
hasDeclsSybTransform workerHasDecls workerBind t = trf t
where
trf = SYB.mkM parsedSource
`SYB.extM` lmatch
`SYB.extM` lexpr
`SYB.extM` lstmt
`SYB.extM` lhsbind
`SYB.extM` lvald
parsedSource (p::GHC.ParsedSource) = workerHasDecls p
lmatch (lm::GHC.LMatch GhcPs (GHC.LHsExpr GhcPs))
= workerHasDecls lm
lexpr (le::GHC.LHsExpr GhcPs)
= workerHasDecls le
lstmt (d::GHC.LStmt GhcPs (GHC.LHsExpr GhcPs))
= workerHasDecls d
lhsbind (b@(GHC.L _ GHC.FunBind{}):: GHC.LHsBind GhcPs)
= workerBind b
lhsbind b@(GHC.L _ GHC.PatBind{})
= workerBind b
lhsbind x = return x
#if __GLASGOW_HASKELL__ > 804
lvald (GHC.L l (GHC.ValD x d)) = do
(GHC.L _ d') <- lhsbind (GHC.L l d)
return (GHC.L l (GHC.ValD x d'))
#else
lvald (GHC.L l (GHC.ValD d)) = do
(GHC.L _ d') <- lhsbind (GHC.L l d)
return (GHC.L l (GHC.ValD d'))
#endif
lvald x = return x
hsDeclsGeneric :: (SYB.Data t,Monad m) => t -> TransformT m [GHC.LHsDecl GhcPs]
hsDeclsGeneric t = q t
where
q = return []
`SYB.mkQ` parsedSource
`SYB.extQ` lmatch
`SYB.extQ` lexpr
`SYB.extQ` lstmt
`SYB.extQ` lhsbind
`SYB.extQ` lhsbindd
`SYB.extQ` llocalbinds
`SYB.extQ` localbinds
parsedSource (p::GHC.ParsedSource) = hsDecls p
lmatch (lm::GHC.LMatch GhcPs (GHC.LHsExpr GhcPs)) = hsDecls lm
lexpr (le::GHC.LHsExpr GhcPs) = hsDecls le
lstmt (d::GHC.LStmt GhcPs (GHC.LHsExpr GhcPs)) = hsDecls d
lhsbind :: (Monad m) => GHC.LHsBind GhcPs -> TransformT m [GHC.LHsDecl GhcPs]
#if __GLASGOW_HASKELL__ > 804
lhsbind (GHC.L _ (GHC.FunBind _ _ (GHC.MG _ (GHC.L _ matches) _) _ _)) = do
#elif __GLASGOW_HASKELL__ > 710
lhsbind (GHC.L _ (GHC.FunBind _ (GHC.MG (GHC.L _ matches) _ _ _) _ _ _)) = do
#else
lhsbind (GHC.L _ (GHC.FunBind _ _ (GHC.MG matches _ _ _) _ _ _)) = do
#endif
dss <- mapM hsDecls matches
return (concat dss)
lhsbind p@(GHC.L _ (GHC.PatBind{})) = do
hsDeclsPatBind p
lhsbind _ = return []
#if __GLASGOW_HASKELL__ > 804
lhsbindd (GHC.L l (GHC.ValD _ d)) = lhsbind (GHC.L l d)
#else
lhsbindd (GHC.L l (GHC.ValD d)) = lhsbind (GHC.L l d)
#endif
lhsbindd _ = return []
llocalbinds :: (Monad m) => GHC.Located (GHC.HsLocalBinds GhcPs) -> TransformT m [GHC.LHsDecl GhcPs]
llocalbinds (GHC.L _ ds) = localbinds ds
localbinds :: (Monad m) => GHC.HsLocalBinds GhcPs -> TransformT m [GHC.LHsDecl GhcPs]
localbinds d = hsDeclsValBinds d
orderedDecls :: (Data a,Monad m) => GHC.Located a -> [GHC.LHsDecl GhcPs] -> TransformT m [GHC.LHsDecl GhcPs]
orderedDecls parent decls = do
ans <- getAnnsT
case getAnnotationEP parent ans of
Nothing -> error $ "orderedDecls:no annotation for:" ++ showAnnData emptyAnns 0 parent
Just ann -> case annSortKey ann of
Nothing -> do
return decls
Just keys -> do
let ds = map (\s -> (GHC.getLoc s,s)) decls
ordered = map snd $ orderByKey ds keys
return ordered
hsDeclsValBinds :: (Monad m) => GHC.HsLocalBinds GhcPs -> TransformT m [GHC.LHsDecl GhcPs]
hsDeclsValBinds lb = case lb of
#if __GLASGOW_HASKELL__ > 804
GHC.HsValBinds _ (GHC.ValBinds _ bs sigs) -> do
let
bds = map wrapDecl (GHC.bagToList bs)
sds = map wrapSig sigs
return (bds ++ sds)
GHC.HsValBinds _ (GHC.XValBindsLR _) -> error $ "hsDecls.XValBindsLR not valid"
GHC.HsIPBinds {} -> return []
GHC.EmptyLocalBinds {} -> return []
GHC.XHsLocalBindsLR {} -> return []
#else
GHC.HsValBinds (GHC.ValBindsIn bs sigs) -> do
let
bds = map wrapDecl (GHC.bagToList bs)
sds = map wrapSig sigs
return (bds ++ sds)
GHC.HsValBinds (GHC.ValBindsOut _ _) -> error $ "hsDecls.ValbindsOut not valid"
GHC.HsIPBinds _ -> return []
GHC.EmptyLocalBinds -> return []
#endif
replaceDeclsValbinds :: (Monad m)
=> GHC.HsLocalBinds GhcPs -> [GHC.LHsDecl GhcPs]
-> TransformT m (GHC.HsLocalBinds GhcPs)
replaceDeclsValbinds _ [] = do
#if __GLASGOW_HASKELL__ > 804
return (GHC.EmptyLocalBinds GHC.noExt)
#else
return (GHC.EmptyLocalBinds)
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDeclsValbinds (GHC.HsValBinds _ _b) new
#else
replaceDeclsValbinds (GHC.HsValBinds _b) new
#endif
= do
logTr "replaceDecls HsLocalBinds"
let decs = GHC.listToBag $ concatMap decl2Bind new
let sigs = concatMap decl2Sig new
#if __GLASGOW_HASKELL__ > 804
return (GHC.HsValBinds GHC.noExt (GHC.ValBinds GHC.noExt decs sigs))
#else
return (GHC.HsValBinds (GHC.ValBindsIn decs sigs))
#endif
replaceDeclsValbinds (GHC.HsIPBinds {}) _new = error "undefined replaceDecls HsIPBinds"
#if __GLASGOW_HASKELL__ > 804
replaceDeclsValbinds (GHC.EmptyLocalBinds _) new
#else
replaceDeclsValbinds (GHC.EmptyLocalBinds) new
#endif
= do
logTr "replaceDecls HsLocalBinds"
let newBinds = map decl2Bind new
newSigs = map decl2Sig new
let decs = GHC.listToBag $ concat newBinds
let sigs = concat newSigs
#if __GLASGOW_HASKELL__ > 804
return (GHC.HsValBinds GHC.noExt (GHC.ValBinds GHC.noExt decs sigs))
#else
return (GHC.HsValBinds (GHC.ValBindsIn decs sigs))
#endif
#if __GLASGOW_HASKELL__ > 804
replaceDeclsValbinds (GHC.XHsLocalBindsLR _) _ = error "replaceDeclsValbinds. XHsLocalBindsLR"
#endif
type Decl = GHC.LHsDecl GhcPs
type Match = GHC.LMatch GhcPs (GHC.LHsExpr GhcPs)
modifyValD :: forall m t. (HasTransform m)
=> GHC.SrcSpan
-> Decl
-> (Match -> [Decl] -> m ([Decl], Maybe t))
-> m (Decl,Maybe t)
#if __GLASGOW_HASKELL__ > 804
modifyValD p pb@(GHC.L ss (GHC.ValD _ (GHC.PatBind {} ))) f =
#else
modifyValD p pb@(GHC.L ss (GHC.ValD (GHC.PatBind {} ))) f =
#endif
if ss == p
then do
ds <- liftT $ hsDeclsPatBindD pb
(ds',r) <- f (error "modifyValD.PatBind should not touch Match") ds
pb' <- liftT $ replaceDeclsPatBindD pb ds'
return (pb',r)
else return (pb,Nothing)
modifyValD p ast f = do
(ast',r) <- runStateT (SYB.everywhereM (SYB.mkM doModLocal) ast) Nothing
return (ast',r)
where
doModLocal :: Match -> StateT (Maybe t) m Match
doModLocal (match@(GHC.L ss _) :: Match) = do
let
if ss == p
then do
ds <- lift $ liftT $ hsDecls match
(ds',r) <- lift $ f match ds
put r
match' <- lift $ liftT $ replaceDecls match ds'
return match'
else return match
class (Monad m) => (HasTransform m) where
liftT :: Transform a -> m a
instance HasTransform (TransformT Identity) where
liftT = id
modifyDeclsT :: (HasDecls t,HasTransform m)
=> ([GHC.LHsDecl GhcPs] -> m [GHC.LHsDecl GhcPs])
-> t -> m t
modifyDeclsT action t = do
decls <- liftT $ hsDecls t
decls' <- action decls
liftT $ replaceDecls t decls'
matchApiAnn :: GHC.AnnKeywordId -> (KeywordId,DeltaPos) -> Bool
matchApiAnn mkw (kw,_)
= case kw of
(G akw) -> mkw == akw
_ -> False
insertCommentBefore :: (Monad m) => AnnKey -> [(Comment, DeltaPos)]
-> ((KeywordId, DeltaPos) -> Bool) -> TransformT m ()
insertCommentBefore key toMove p = do
let
doInsert ans =
case Map.lookup key ans of
Nothing -> error $ "insertCommentBefore:no AnnKey for:" ++ showGhc key
Just ann -> Map.insert key ann' ans
where
(before,after) = break p (annsDP ann)
ann' = ann { annsDP = before ++ (map comment2dp toMove) ++ after}
modifyAnnsT doInsert