module Language.Haskell.Refact.Refactoring.Case
( ifToCase
, compIfToCase
) where
import qualified Data.Generics as SYB
import qualified GHC.SYB.Utils as SYB
import qualified BasicTypes as GHC
import qualified GHC as GHC
import qualified Language.Haskell.GhcMod as GM (Options(..))
import Language.Haskell.Refact.API
import Language.Haskell.GHC.ExactPrint
import Language.Haskell.GHC.ExactPrint.Types
import Language.Haskell.GHC.ExactPrint.Utils
import System.Directory
import qualified Data.Map as Map
ifToCase :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> SimpPos -> IO [FilePath]
ifToCase settings opts fileName beginPos endPos = do
absFileName <- canonicalizePath fileName
runRefacSession settings opts (compIfToCase absFileName beginPos endPos)
compIfToCase :: FilePath -> SimpPos -> SimpPos -> RefactGhc [ApplyRefacResult]
compIfToCase fileName beginPos endPos = do
parseSourceFileGhc fileName
parsed <- getRefactParsed
oldAnns <- liftT getAnnsT
logm $ "Case.compIfToCase:parsed=" ++ (showAnnData oldAnns 0 parsed)
let expr = locToExp beginPos endPos parsed
case expr of
Just exp1@(GHC.L _ (GHC.HsIf _ _ _ _))
-> do (refactoredMod,_) <- applyRefac (doIfToCaseInternal exp1) RSAlreadyLoaded
return [refactoredMod]
_ -> error $ "You haven't selected an if-then-else expression!"
doIfToCaseInternal ::
GHC.Located (GHC.HsExpr GHC.RdrName)
-> RefactGhc ()
doIfToCaseInternal expr = do
rs <- getRefactParsed
reallyDoIfToCase expr rs
reallyDoIfToCase ::
GHC.Located (GHC.HsExpr GHC.RdrName)
-> GHC.ParsedSource
-> RefactGhc ()
reallyDoIfToCase expr p = do
p2 <- SYB.everywhereMStaged SYB.Parser (SYB.mkM inExp) p
putRefactParsed p2 mempty
return ()
where
inExp :: (GHC.Located (GHC.HsExpr GHC.RdrName)) -> RefactGhc (GHC.Located (GHC.HsExpr GHC.RdrName))
inExp exp1@(GHC.L _ (GHC.HsIf _se (GHC.L _ _) (GHC.L _ _) (GHC.L _ _)))
| sameOccurrence expr exp1
= do
newExp <- ifToCaseTransform exp1
return newExp
inExp e = return e
ifToCaseTransform :: GHC.Located (GHC.HsExpr GHC.RdrName)
-> RefactGhc (GHC.Located (GHC.HsExpr GHC.RdrName))
ifToCaseTransform li@(GHC.L _ (GHC.HsIf _se e1 e2 e3)) = do
caseLoc <- liftT uniqueSrcSpanT
trueMatchLoc <- liftT uniqueSrcSpanT
trueLoc1 <- liftT uniqueSrcSpanT
trueLoc <- liftT uniqueSrcSpanT
trueRhsLoc <- liftT uniqueSrcSpanT
falseLoc1 <- liftT uniqueSrcSpanT
falseLoc <- liftT uniqueSrcSpanT
falseMatchLoc <- liftT uniqueSrcSpanT
falseRhsLoc <- liftT uniqueSrcSpanT
#if __GLASGOW_HASKELL__ > 710
matchesLoc <- liftT uniqueSrcSpanT
lbTrueLoc <- liftT uniqueSrcSpanT
lbFalseLoc <- liftT uniqueSrcSpanT
#endif
let trueName = mkRdrName "True"
let falseName = mkRdrName "False"
let ret = GHC.L caseLoc (GHC.HsCase e1
(GHC.MG
(
#if __GLASGOW_HASKELL__ > 710
GHC.L matchesLoc
#endif
[
(GHC.L trueMatchLoc $ GHC.Match
#if __GLASGOW_HASKELL__ <= 710
Nothing
#else
GHC.NonFunBindMatch
#endif
[
GHC.L trueLoc1 $ GHC.ConPatIn (GHC.L trueLoc trueName) (GHC.PrefixCon [])
]
Nothing
(GHC.GRHSs
[
GHC.L trueRhsLoc $ GHC.GRHS [] e2
]
(
#if __GLASGOW_HASKELL__ > 710
GHC.L lbTrueLoc
#endif
GHC.EmptyLocalBinds))
)
, (GHC.L falseMatchLoc $ GHC.Match
#if __GLASGOW_HASKELL__ <= 710
Nothing
#else
GHC.NonFunBindMatch
#endif
[
GHC.L falseLoc1 $ GHC.ConPatIn (GHC.L falseLoc falseName) (GHC.PrefixCon [])
]
Nothing
(GHC.GRHSs
[
GHC.L falseRhsLoc $ GHC.GRHS [] e3
]
(
#if __GLASGOW_HASKELL__ > 710
GHC.L lbFalseLoc
#endif
GHC.EmptyLocalBinds))
)
]) [] GHC.placeHolderType GHC.FromSource))
oldAnns <- liftT $ getAnnsT
let annIf = gfromJust "Case.annIf" $ getAnnotationEP li oldAnns
let annThen = gfromJust "Case.annThen" $ getAnnotationEP e2 oldAnns
let annElse = gfromJust "Case.annElse" $ getAnnotationEP e3 oldAnns
logm $ "Case:annIf=" ++ show annIf
logm $ "Case:annThen=" ++ show annThen
logm $ "Case:annElse=" ++ show annElse
let ifDelta = gfromJust "Case.ifDelta" $ lookup (G GHC.AnnIf) (annsDP annIf)
let anne2' =
[
( AnnKey caseLoc (CN "HsCase"), annIf { annsDP = [ (G GHC.AnnCase, ifDelta)
, (G GHC.AnnOf, DP (0,1))]
} )
, ( AnnKey trueMatchLoc (CN "Match"), Ann (DP (1,2)) [] [] [] Nothing Nothing )
, ( AnnKey trueLoc1 (CN "ConPatIn"), Ann (DP (0,0)) [] [] [] Nothing Nothing )
, ( AnnKey trueLoc (CN "Unqual"), Ann (DP (0,0)) [] [] [(G GHC.AnnVal, DP (0,0))] Nothing Nothing)
, ( AnnKey trueRhsLoc (CN "GRHS"), Ann (DP (0,2)) [] [] [(G GHC.AnnRarrow, DP (0,0))] Nothing Nothing)
, ( AnnKey falseMatchLoc (CN "Match"), Ann (DP (1,0)) [] [] [] Nothing Nothing)
, ( AnnKey falseLoc1 (CN "ConPatIn"), Ann (DP (0,0)) [] [] [] Nothing Nothing)
, ( AnnKey falseLoc (CN "Unqual"), Ann (DP (0,0)) [] [] [(G GHC.AnnVal, DP (0,0))] Nothing Nothing)
, ( AnnKey falseRhsLoc (CN "GRHS"), Ann (DP (0,1)) [] [] [(G GHC.AnnRarrow, DP (0,0))] Nothing Nothing)
]
liftT $ putAnnsT (oldAnns `Map.union` (Map.fromList anne2'))
return ret
ifToCaseTransform x = return x