{-# LANGUAGE CPP #-} module Language.Haskell.Refact.Utils.Transform ( addSimpleImportDecl , wrapInLambda , wrapInPars , wrapInParsWithDPs , addNewLines , locate , removePars ) where import qualified GHC as GHC import qualified BasicTypes as GHC import qualified Data.Map as Map import Data.Data import Language.Haskell.GHC.ExactPrint import Language.Haskell.GHC.ExactPrint.Types import Language.Haskell.Refact.Utils.Monad import Language.Haskell.Refact.Utils.MonadFunctions import Language.Haskell.Refact.Utils.TypeUtils import Language.Haskell.Refact.Utils.Synonyms import Language.Haskell.Refact.Utils.ExactPrint -- The goal of this module is to provide basic transformations of the ast and -- annotations that are useful in multiple refactorings --Takes in a string corresponding to the module name to be imported --Adds the import declaration at the end of that module's imports addSimpleImportDecl :: String -> RefactGhc () addSimpleImportDecl modName = do let modNm' = GHC.mkModuleName modName parsed <- getRefactParsed newP <- addImportDecl parsed modNm' Nothing False False False Nothing False [] currAnns <- fetchAnnsFinal putRefactParsed newP currAnns --Takes in a lhs pattern and a rhs. Wraps those in a lambda and adds the annotations associated with the lambda. Returns the new located lambda expression wrapInLambda :: String -> GHC.LPat GHC.RdrName -> ParsedGRHSs -> RefactGhc (GHC.LHsExpr GHC.RdrName) wrapInLambda funNm varPat rhs = do match@(GHC.L l match') <- mkMatch varPat rhs --logm $ "Match: " ++ (SYB.showData SYB.Parser 3 match) #if __GLASGOW_HASKELL__ <= 710 let mg = GHC.MG [match] [] GHC.PlaceHolder GHC.Generated #else lMatchLst <- locate [match] let mg = GHC.MG lMatchLst [] GHC.PlaceHolder GHC.Generated #endif currAnns <- fetchAnnsFinal --logm $ "Anns :" ++ (show $ getAllAnns currAnns match) let l_lam = (GHC.L l (GHC.HsLam mg)) key = mkAnnKey l_lam dp = [(G GHC.AnnLam, DP (0,0))] newAnn = annNone {annsDP = dp} setRefactAnns $ Map.insert key newAnn currAnns par_lam <- wrapInPars l_lam return par_lam --This function makes a match suitable for use inside of a lambda expression. Should change name or define it elsewhere to show that this is not a general-use function. mkMatch :: GHC.LPat GHC.RdrName -> GHC.GRHSs GHC.RdrName (GHC.LHsExpr GHC.RdrName) -> RefactGhc (GHC.LMatch GHC.RdrName (GHC.LHsExpr GHC.RdrName)) mkMatch varPat rhs = do #if __GLASGOW_HASKELL__ <= 710 lMatch@(GHC.L l m) <- locate (GHC.Match Nothing [varPat] Nothing rhs) #else lMatch@(GHC.L l m) <- locate (GHC.Match GHC.NonFunBindMatch [varPat] Nothing rhs) #endif let dp = [(G GHC.AnnRarrow, DP (0,1))] newAnn = annNone {annsDP = dp, annEntryDelta = DP (0,-1)} zeroDP varPat addAnn lMatch newAnn return lMatch wrapInParsWithDPs :: DeltaPos -> DeltaPos -> GHC.LHsExpr GHC.RdrName -> RefactGhc (GHC.LHsExpr GHC.RdrName) wrapInParsWithDPs openDP closeDP expr = do newAst <- locate (GHC.HsPar expr) let dp = [(G GHC.AnnOpenP, openDP), (G GHC.AnnCloseP, closeDP)] newAnn = annNone {annsDP = dp} addAnn newAst newAnn return newAst --Wraps a given expression in parenthesis and add the appropriate annotations, returns the modified ast chunk. wrapInPars :: GHC.LHsExpr GHC.RdrName -> RefactGhc (GHC.LHsExpr GHC.RdrName) wrapInPars = wrapInParsWithDPs (DP (0,1)) (DP (0,0)) --Does the opposite of wrapInPars removePars :: ParsedLExpr -> RefactGhc ParsedLExpr removePars (GHC.L _ (GHC.HsPar expr)) = do setDP (DP (0,1)) expr return expr removePars expr = return expr --Takes a piece of AST and adds an n row offset addNewLines :: (Data a) => Int -> GHC.Located a -> RefactGhc () addNewLines n ast = do currAnns <- fetchAnnsFinal let key = mkAnnKey ast mv = Map.lookup key currAnns case mv of Nothing -> return () Just v -> do let (DP (row,col)) = annEntryDelta v newDP = (DP (row+n,col)) newAnn = v {annEntryDelta = newDP} newAnns = Map.insert key newAnn currAnns setRefactAnns newAnns