packages feed

lhc-0.10: src/Grin/Stage2/Rename.hs

module Grin.Stage2.Rename
    ( rename
    ) where

import Control.Monad.State.Strict
import qualified Data.Map as Map

import Grin.Stage2.Types

rename :: Grin -> Grin
rename grin = evalState (renameGrin grin) emptyState
    where emptyState = S { stateUnique = 1
                         , stateSubst  = Map.empty }


type M a = State S a
-- The substitution map could just as easily be a reader.
data S = S { stateUnique :: !Int
           , stateSubst  :: Map.Map Renamed Renamed
           }

renameGrin :: Grin -> M Grin
renameGrin grin
    = do mapM_ (bind . nodeName) (grinNodes grin)
         mapM_ (bind . cafName) (grinCAFs grin)
         forM_ (grinFunctions grin) $ \func -> do bind (funcDefName func)
                                                  mapM_ bind (funcDefArgs func)
         defs <- mapM renameFuncDef (grinFunctions grin)
         nodes <- mapM renameNode (grinNodes grin)
         cafs <- mapM renameCAF (grinCAFs grin)
         entryPoint <- newName (grinEntryPoint grin)
         newUnique <- gets stateUnique
         return Grin { grinNodes = nodes
                     , grinCAFs  = cafs
                     , grinFunctions = defs
                     , grinEntryPoint = entryPoint
                     , grinUnique = newUnique }

renameFuncDef :: FuncDef -> M FuncDef
renameFuncDef def
    = do name <- newName (funcDefName def)
         args <- mapM newName (funcDefArgs def)
         body <- renameExpression (funcDefBody def)
         return FuncDef{ funcDefName = name
                       , funcDefReturns = funcDefReturns def
                       , funcDefArgs = args
                       , funcDefBody = body }

renameExpression :: Expression -> M Expression
renameExpression (e1 :>>= binds :-> e2)
    = do e1' <- renameExpression e1
         binds' <- mapM bind binds
         e2' <- renameExpression e2
         return (e1' :>>= binds' :-> e2')
renameExpression (Application fn args)
    = liftM2 Application (newName fn) (mapM newName args)
renameExpression (Case scrut alts)
    = do scrut' <- newName scrut
         alts' <- mapM renameAlt alts
         return $ Case scrut' alts'
renameExpression (Fetch nth ptr)
    = liftM (Fetch nth) (newName ptr)
renameExpression (Store args)
    = liftM Store (mapM newName args)
renameExpression (StoreHole size)
    = return $ StoreHole size
renameExpression (Unit args)
    = liftM Unit (mapM newName args)
renameExpression (Constant val)
    = liftM Constant (renameValue val)

renameAlt :: Alt -> M Alt
renameAlt (cond :> branch)
    = do cond' <- renameValue cond
         branch' <- renameExpression branch
         return (cond' :> branch')

renameValue :: Value -> M Value
renameValue (Node node nt missing_args)
    = do node' <- newName node
         return $ Node node' nt missing_args
renameValue value = return value

renameNode :: NodeDef -> M NodeDef
renameNode node
    = do name <- newName (nodeName node)
         return node{nodeName = name}

renameCAF :: CAF -> M CAF
renameCAF caf
    = do name  <- newName (cafName caf)
         value <- renameValue (cafValue caf)
         return CAF{ cafName  = name
                   , cafValue = value }

bind :: Renamed -> M Renamed
bind name | isBuiltin name || isExternal name
    = return name
bind name
    = do uid <- newUnique
         s <- get
         when (name `Map.member` stateSubst s) $ error $ "Grin.Stage2.Rename.bind: Duplication of (supposedly) unique identifier: " ++ show name
         let newName = genNewName name uid
         put s { stateSubst = Map.insert name newName (stateSubst s) }
         return newName

newName :: Renamed -> M Renamed
newName oldName | isBuiltin oldName || isExternal oldName = return oldName
newName oldName@(Aliased (-1) _) = return oldName
newName oldName
    = do subst <- gets stateSubst
         case Map.lookup oldName subst of
           Nothing  -> error $ "Grin.Stage2.Rename.newName: Unbound variable: " ++ show oldName
           Just new -> return new

newUnique :: M Int
newUnique = do s <- get
               let unique = stateUnique s
               put s{stateUnique = unique + 1}
               return unique

genNewName (Aliased _uid name) uid = Aliased uid name
genNewName (Anonymous _uid) uid = Anonymous uid
genNewName other _uid = other