module RefacWhereLet(whereToLet) where import PrettyPrint import PosSyntax import AbstractIO import Maybe import TypedIds import UniqueNames hiding (srcLoc) import PNT import TiPNT import List import RefacUtils hiding (getParams) import PFE0 (findFile) import MUtils (( # )) import RefacLocUtils import System import IO {- This refactoring converts a where into a let. Could potentially narrow the scrope of those involved bindings. Copyright : (c) Christopher Brown 2008 Maintainer : cmb21@kent.ac.uk Stability : provisional Portability : portable -} whereToLet args = do let fileName = ghead "filename" args --fileName'= moduleName fileName --modName = Module fileName' row = read (args!!1)::Int col = read (args!!2)::Int modName <-fileNameToModName fileName (inscps, exps, mod, tokList)<-parseSourceFile fileName let pnt = locToPNT fileName (row, col) mod if not (checkInFun pnt mod) then error "Please select a definition within a where clause!" else do if (pnt /= defaultPNT) then do ((_,m), (newToks, newMod))<-applyRefac (doWhereToLet pnt) (Just (inscps, exps, mod, tokList)) fileName writeRefactoredFiles False [((fileName,m), (newToks,newMod))] AbstractIO.putStrLn "Completed.\n" else error "\nInvalid cursor position!" doWhereToLet pnt (_,_,t) = do mod <- convertToWhere pnt t return mod convertToWhere pnt t = applyTP (full_tdTP (idTP `adhocTP` conInMatch `adhocTP` conInPat `adhocTP` conInAlt )) t where conInMatch (match@(HsMatch loc name pats (HsBody e) ds)::HsMatchP) | canBeConverted ds pnt = do let decl = definingDecls [pNTtoPN pnt] ds True True let updateRHS = (Exp (HsLet decl e)) ds' <- rmDecl (pNTtoPN pnt) True ds -- we need to check that nothing else in the where -- clause depends on this entity... allDecs <- mapM hsFreeAndDeclaredPNs ds' if (declToPName2 $ ghead "conInMatch" decl) `elem` (concat (map fst allDecs)) then error "Entity cannot be converted as another declaration in the where clause depends on it!" else do e' <- update e updateRHS e return (HsMatch loc name pats (HsBody e') ds') conInMatch (match@(HsMatch loc name pats g@(HsGuard e) ds)::HsMatchP) | canBeConverted ds pnt = do let decl = definingDecls [pNTtoPN pnt] ds True True let updateRHS = (HsBody (Exp (HsLet decl (rmGuard g)))) ds' <- rmDecl (pNTtoPN pnt) True ds allDecs <- mapM hsFreeAndDeclaredPNs ds' if (declToPName2 $ ghead "conInMatch Guard" decl) `elem` (concat (map fst allDecs)) then error "Entity cannot be converted as another declaration in the where clause depends on it!" else do e' <- update g updateRHS g return (HsMatch loc name pats e' ds') conInMatch x = return x conInPat (pat@(Dec (HsPatBind loc p (HsBody e) ds))::HsDeclP) | canBeConverted ds pnt = do let decl = definingDecls [pNTtoPN pnt] ds True True let updateRHS = (Exp (HsLet decl e)) ds' <- rmDecl (pNTtoPN pnt) True ds allDecs <- mapM hsFreeAndDeclaredPNs ds' if (declToPName2 $ ghead "conInPat" decl) `elem` (concat (map fst allDecs)) then error "Entity cannot be converted as another declaration in the where clause depends on it!" else do e' <- update e updateRHS e return (Dec (HsPatBind loc p (HsBody e') ds')) conInPat (pat@(Dec (HsPatBind loc p g@(HsGuard e) ds))::HsDeclP) | canBeConverted ds pnt = do let decl = definingDecls [pNTtoPN pnt] ds True True let updateRHS = (HsBody (Exp (HsLet decl (rmGuard g)))) ds' <- rmDecl (pNTtoPN pnt) True ds allDecs <- mapM hsFreeAndDeclaredPNs ds' if (declToPName2 $ ghead "conInPat" decl) `elem` (concat (map fst allDecs)) then error "Entity cannot be converted as another declaration in the where clause depends on it!" else do e' <- update g updateRHS g return (Dec (HsPatBind loc p e' ds')) conInPat x = return x conInAlt (alt@(HsAlt loc p (HsBody e) ds)::HsAltP) | canBeConverted ds pnt = do let decl = definingDecls [pNTtoPN pnt] ds True True let updateRHS = (Exp (HsLet decl e)) ds' <- rmDecl (pNTtoPN pnt) True ds e' <- update e updateRHS e return (HsAlt loc p (HsBody e') ds') conInAlt (alt@(HsAlt loc p g@(HsGuard e) ds)::HsAltP) | canBeConverted ds pnt = do let decl = definingDecls [pNTtoPN pnt] ds True True let updateRHS = (HsBody (Exp (HsLet decl (rmGuard g)))) ds' <- rmDecl (pNTtoPN pnt) True ds e' <- updateGuardAlt g updateRHS g return (HsAlt loc p e' ds') conInAlt x = return x updateGuardAlt oldRhs newRhs t = applyTP (once_tdTP (failTP `adhocTP` inRhs)) t where inRhs (r::RhsP) | r == oldRhs && srcLocs r == srcLocs oldRhs = do (newRhs',_) <- updateToks oldRhs newRhs prettyprintGuardsAlt return newRhs' inRhs r = mzero rmGuard ((HsGuard gs)::RhsP) = let (_,e1,e2)=glast "guardToIfThenElse" gs in if ((pNtoName.expToPN) e1)=="otherwise" then (foldl mkIfThenElse e2 (tail(reverse gs))) else (foldl mkIfThenElse defaultElse (reverse gs)) mkIfThenElse e (_,e1, e2)=(Exp (HsIf e1 e2 e)) defaultElse=(Exp (HsApp (Exp (HsId (HsVar (PNT (PN (UnQual "error") (G (PlainModule "Prelude") "error" (N (Just loc0)))) Value (N (Just loc0)))))) (Exp (HsLit loc0 (HsString "UnMatched Pattern"))))) canBeConverted :: [HsDeclP] -> PNT -> Bool canBeConverted ds pnt = pnt `elem` map declToPNT ds checkInFun :: Term t => PNT -> t -> Bool checkInFun pnt t = checkInMatch pnt t || checkInPat pnt t || checkInAlt pnt t where checkInAlt pnt t = fromMaybe (False) (applyTU (once_tdTU (failTU `adhocTU` inAlt)) t) checkInPat pnt t = fromMaybe (False) (applyTU (once_tdTU (failTU `adhocTU` inPat)) t) checkInMatch pnt t = fromMaybe (False) (applyTU (once_tdTU (failTU `adhocTU` inMatch)) t) inAlt (alt@(HsAlt loc p rhs ds)::HsAltP) | findPNT pnt ds = Just True inAlt _ = Nothing --The selected sub-expression is in the rhs of a match inMatch (match@(HsMatch loc1 _ pats rhs ds)::HsMatchP) | findPNT pnt ds = Just True inMatch _ = Nothing --The selected sub-expression is in the rhs of a pattern-binding inPat (pat@(Dec (HsPatBind loc1 ps rhs ds))::HsDeclP) | findPNT pnt ds = Just True inPat _ = Nothing