HaRe-0.8.0.0: src/Language/Haskell/Refact/Refactoring/Case.hs
{-# LANGUAGE StandaloneDeriving #-}
module Language.Haskell.Refact.Refactoring.Case(ifToCase) 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
-- To be moved into HaRe 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
-- import Debug.Trace
-- ---------------------------------------------------------------------
-- | Convert an if expression to a case expression
ifToCase :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> SimpPos -> IO [FilePath]
ifToCase settings opts fileName beginPos endPos = do
absFileName <- canonicalizePath fileName
runRefacSession settings opts (comp absFileName beginPos endPos)
comp :: FilePath -> SimpPos -> SimpPos -> RefactGhc [ApplyRefacResult]
comp fileName beginPos endPos = do
parseSourceFileGhc fileName
parsed <- getRefactParsed
oldAnns <- liftT getAnnsT
logm $ "Case.comp:parsed=" ++ (showAnnData oldAnns 0 parsed) -- ++AZ++
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!" -- (show (beginPos,endPos,fileName)) ++ "]:" ++ (SYB.showData SYB.Parser 0 $ ast)
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
-- |Actually do the transformation
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 -- HaRe:-1:1
trueMatchLoc <- liftT uniqueSrcSpanT -- HaRe:-1:2
trueLoc1 <- liftT uniqueSrcSpanT -- HaRe:-1:3
trueLoc <- liftT uniqueSrcSpanT -- HaRe:-1:4
trueRhsLoc <- liftT uniqueSrcSpanT -- HaRe:-1:5
falseLoc1 <- liftT uniqueSrcSpanT -- HaRe:-1:6
falseLoc <- liftT uniqueSrcSpanT -- HaRe:-1:7
falseMatchLoc <- liftT uniqueSrcSpanT -- HaRe:-1:8
falseRhsLoc <- liftT uniqueSrcSpanT -- HaRe:-1:9
let trueName = mkRdrName "True"
let falseName = mkRdrName "False"
let ret = GHC.L caseLoc (GHC.HsCase e1
(GHC.MG
[
(GHC.L trueMatchLoc $ GHC.Match
Nothing
[
GHC.L trueLoc1 $ GHC.ConPatIn (GHC.L trueLoc trueName) (GHC.PrefixCon [])
]
Nothing
(GHC.GRHSs
[
GHC.L trueRhsLoc $ GHC.GRHS [] e2
] GHC.EmptyLocalBinds)
)
, (GHC.L falseMatchLoc $ GHC.Match
Nothing
[
GHC.L falseLoc1 $ GHC.ConPatIn (GHC.L falseLoc falseName) (GHC.PrefixCon [])
]
Nothing
(GHC.GRHSs
[
GHC.L falseRhsLoc $ GHC.GRHS [] e3
] 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
-- AZ:TODO: under some circumstances the GRHS annotations need LineSame, in others LineChanged.
let ifDelta = gfromJust "Case.ifDelta" $ lookup (G GHC.AnnIf) (annsDP annIf)
-- let ifSpanEntry = gfromJust "Case.ifSpanEntry" $ lookup (AnnSpanEntry) (annsDP annIf)
let anne2' =
[
( AnnKey caseLoc (CN "HsCase"), annIf { annsDP = [ (G GHC.AnnCase, ifDelta)
, (G GHC.AnnOf, DP (0,1))]
} )
-- , ( AnnKey caseVirtualLoc (CN "(:)"), Ann (DP (1,newCol)) (ColDelta newCol) (DP (1,newCol)) [] [(DP (1,0))])
, ( 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
-- ---------------------------------------------------------------------
-- EOF