-- | Computations in the vectorisation monad concerned with naming
--   and fresh variable generation.
module Vectorise.Monad.Naming
	( cloneName
	, cloneId
	, cloneVar
	, newExportedVar
	, newLocalVar
	, newLocalVars
	, newDummyVar
	, newTyVar)
where
import Vectorise.Monad.Base

import DsMonad
import Type
import Var
import Name
import SrcLoc
import Id
import FastString
import Control.Monad


-- Naming ---------------------------------------------------------------------	
-- | Clone a name, using the provide function to transform its `OccName`.	
cloneName :: (OccName -> OccName) -> Name -> VM Name
cloneName mk_occ name = liftM make (liftDs newUnique)
  where
    occ_name = mk_occ (nameOccName name)

    make u | isExternalName name = mkExternalName u (nameModule name)
                                                    occ_name
                                                    (nameSrcSpan name)
           | otherwise           = mkSystemName u occ_name


-- | Clone an `Id`, using the provided function to transform its `OccName`. 
cloneId :: (OccName -> OccName) -> Id -> Type -> VM Id
cloneId mk_occ id ty
  = do
      name <- cloneName mk_occ (getName id)
      let id' | isExportedId id = Id.mkExportedLocalId name ty
              | otherwise       = Id.mkLocalId         name ty
      return id'


-- | Make a fresh instance of this var, with a new unique.
cloneVar :: Var -> VM Var
cloneVar var = liftM (setIdUnique var) (liftDs newUnique)


-- | Make a fresh exported variable with the given type.
newExportedVar :: OccName -> Type -> VM Var
newExportedVar occ_name ty 
 = do mod <- liftDs getModuleDs
      u   <- liftDs newUnique

      let name = mkExternalName u mod occ_name noSrcSpan
      
      return $ Id.mkExportedLocalId name ty


-- | Make a fresh local variable with the given type.
--   The variable's name is formed using the given string as the prefix.
newLocalVar :: FastString -> Type -> VM Var
newLocalVar fs ty
 = do u <- liftDs newUnique
      return $ mkSysLocal fs u ty


-- | Make several fresh local varaiables with the given types.
--   The variable's names are formed using the given string as the prefix.
newLocalVars :: FastString -> [Type] -> VM [Var]
newLocalVars fs = mapM (newLocalVar fs)


-- | Make a new local dummy variable.
newDummyVar :: Type -> VM Var
newDummyVar = newLocalVar (fsLit "vv")


-- | Make a fresh type variable with the given kind.
--   The variable's name is formed using the given string as the prefix.
newTyVar :: FastString -> Kind -> VM Var
newTyVar fs k
 = do u <- liftDs newUnique
      return $ mkTyVar (mkSysTvName u fs) k