g2-0.1.0.0: src/G2/Language/Naming.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module G2.Language.Naming
( nameOcc
, nameModule
, nameLoc
, NameGen
, Named (names, rename, renames)
, doRename
, doRenames
, renameAll
, nameToStr
, strToName
, mkNameGen
, varIds
, varNames
, exprNames
, typeNames
, renameExprs
, renameExpr
, renameVars
, freshSeededString
, freshSeededStrings
, freshName
, freshNames
, freshSeededName
, freshSeededNames
, freshId
, freshSeededId
, freshIds
, freshVar
, childrenNames
, mapNG
) where
import G2.Language.AST
import G2.Language.KnownValues
import G2.Language.Syntax
import G2.Language.TypeEnv
import Data.Data (Data, Typeable)
import Data.Hashable
import qualified Data.HashMap.Lazy as HM
import qualified Data.HashSet as HS
import Data.List
import Data.List.Utils
import qualified Data.Map as M
import qualified Data.Text as T
import Data.Tuple
nameOcc :: Name -> T.Text
nameOcc (Name occ _ _ _) = occ
nameModule :: Name -> Maybe T.Text
nameModule (Name _ mb _ _) = mb
nameLoc :: Name -> Maybe Span
nameLoc (Name _ _ _ s) = s
-- | Allows the creation of fresh `Name`s.
data NameGen = NameGen { max_uniq :: (HM.HashMap (T.Text, Maybe T.Text) Int)
, dc_children :: (HM.HashMap Name [Name]) }
deriving (Show, Eq, Read, Typeable, Data)
-- nameToStr relies on NameCleaner eliminating all '_', to preserve uniqueness
-- | Converts a name to a string, which is useful to interact with solvers.
nameToStr :: Name -> String
nameToStr (Name n (Just m) i _) = T.unpack n ++ "_m_" ++ T.unpack m ++ "_" ++ show i
nameToStr (Name n Nothing i _) = T.unpack n ++ "_n__" ++ show i
-- | Converts a string generated by nameToStr to a name.
-- Loses location information
strToName :: String -> Name
strToName str =
let
(n, _:q:_:mi) = breakList (\s -> isPrefixOf "_m_" s || isPrefixOf "_n_" s) str
(m, _:i) = break ((==) '_') mi
m' = if q == 'm' then Just m else Nothing
in
Name (T.pack n) (fmap T.pack m') (read i :: Int) Nothing
-- | Initializes a `NameGen`. The returned `NameGen` is guarenteed to not give any `Name`
-- in the given `Named` type.
mkNameGen :: Named n => n -> NameGen
mkNameGen nmd =
let
allNames = names nmd
in
NameGen {
max_uniq = HM.fromListWith max $ map (\(Name n m i _) -> ((n, m), i + 1)) allNames
-- (foldr (\(Name n m i _) hm -> HM.insertWith max (n, m) (i + 1) hm)
-- HM.empty allNames
-- )
, dc_children = HM.empty
}
-- | Returns all @Var@ Ids in an ASTContainer
varIds :: (ASTContainer m Expr) => m -> [Id]
varIds = evalASTs varIds'
varIds' :: Expr -> [Id]
varIds' (Var i) = [i]
varIds' _ = []
varNames :: (ASTContainer m Expr) => m -> [Name]
varNames = map idName . varIds
-- Returns every `Name` that appears in an `Expr`, but ignores those only in `Type`s.
exprNames :: (ASTContainer m Expr) => m -> [Name]
exprNames = evalASTs exprTopNames
exprTopNames :: Expr -> [Name]
exprTopNames (Var var) = [idName var]
exprTopNames (Data dc) = dataConName dc
exprTopNames (Lam _ b _) = [idName b]
exprTopNames (Let kvs _) = map (idName . fst) kvs
exprTopNames (Case _ cvar as) = idName cvar :
concatMap (\(Alt am _) -> altMatchNames am)
as
exprTopNames (Assume (Just is) _ _) = [funcName is]
exprTopNames (Assert (Just is) _ _) = [funcName is]
exprTopNames _ = []
altMatchNames :: AltMatch -> [Name]
altMatchNames (DataAlt dc i) = dataConName dc ++ (map idName i)
altMatchNames _ = []
dataConName :: DataCon -> [Name]
dataConName (DataCon n _) = [n]
typeNames :: (ASTContainer m Type) => m -> [Name]
typeNames = evalASTs typeTopNames
typeTopNames :: Type -> [Name]
typeTopNames (TyVar i) = [idName i]
typeTopNames (TyCon n _) = [n]
typeTopNames (TyForAll (NamedTyBndr v) _) = [idName v]
typeTopNames _ = []
doRename :: Named a => Name -> NameGen -> a -> (a, NameGen)
doRename n ngen x = (rename n n' x, ngen')
where (n', ngen') = freshSeededName n ngen
doRenames :: Named a => [Name] -> NameGen -> a -> (a, NameGen)
doRenames ns ng e =
let
(ns', ng') = freshSeededNames ns ng
hm = HM.fromList $ zip ns ns'
in
(renames hm e, ng')
renameAll :: (Named a) => a -> NameGen -> (a, NameGen)
renameAll x ng =
let
old = nub $ names x
in
doRenames old ng x
-- | Types that contain `Name`@s@
class Named a where
names :: a -> [Name]
rename :: Name -> Name -> a -> a
renames :: HM.HashMap Name Name -> a -> a
renames hm e = HM.foldrWithKey (\k v -> rename k v) e hm
instance Named Name where
{-# INLINE names #-}
names n = [n]
{-# INLINE rename #-}
rename old (Name nn nm ni _) n@(Name _ _ _ l) = if old == n then Name nn nm ni l else n
{-# INLINE renames #-}
renames hm n@(Name _ _ _ l) =
case HM.lookupDefault n n hm of
Name n' m' i _ -> Name n' m' i l
instance Named Id where
{-# INLINE names #-}
names (Id n t) = n:names t
{-# INLINE rename #-}
rename old new (Id n t) = Id (rename old new n) (rename old new t)
{-# INLINE renames #-}
renames hm (Id n t) = Id (renames hm n) (renames hm t)
instance Named Expr where
names = eval go
where
go :: Expr -> [Name]
go (Var i) = names i
go (Prim _ t) = names t
go (Data d) = names d
go (Lam _ i _) = names i
go (Let b _) = concatMap (names . fst) b
go (Case _ i a) = names i ++ concatMap (names . altMatch) a
go (Type t) = names t
go (Cast _ c) = names c
go (Coercion c) = names c
go (Tick t _) = names t
go (SymGen t) = names t
go (Assume is _ _) = names is
go (Assert is _ _) = names is
go _ = []
rename old new = modify go
where
go :: Expr -> Expr
go (Var i) = Var (rename old new i)
go (Data d) = Data (rename old new d)
go (Lam u i e) = Lam u (rename old new i) e
go (Let b e) =
let b' = map (\(n, e') -> (rename old new n, e')) b
in Let b' e
go (Case e i a) =
Case e (rename old new i) (map goAlt a)
go (Type t) = Type (rename old new t)
go (Cast e c) = Cast e (rename old new c)
go (Coercion c) = Coercion (rename old new c)
go (Tick t e) = Tick (rename old new t) e
go (SymGen t) = SymGen (rename old new t)
go (Assume is e e') = Assume (rename old new is) e e'
go (Assert is e e') = Assert (rename old new is) e e'
go e = e
goAlt :: Alt -> Alt
goAlt (Alt am e) = Alt (rename old new am) e
renames hm = modify go
where
go :: Expr -> Expr
go (Var i) = Var (renames hm i)
go (Data d) = Data (renames hm d)
go (Lam u i e) = Lam u (renames hm i) e
go (Let b e) =
let b' = map (\(n, e') -> (renames hm n, e')) b
in Let b' e
go (Case e i a) = Case e (renames hm i) (map goAlt a)
go (Type t) = Type (renames hm t)
go (Cast e c) = Cast e (renames hm c)
go (Coercion c) = Coercion (renames hm c)
go (Tick t e) = Tick (renames hm t) e
go (SymGen t) = SymGen (renames hm t)
go (Assume is e e') = Assume (renames hm is) e e'
go (Assert is e e') = Assert (renames hm is) e e'
go e = e
goAlt :: Alt -> Alt
goAlt (Alt am e) = Alt (renames hm am) e
renameExprs :: ASTContainer m Expr => [(Name, Name)] -> m -> m
renameExprs n a = foldr (\(old, new) -> renameExpr old new) a n
-- | Rename only the names in an `Expr` that are the `Name` of an `Id`/`Let`/`Data`/`Case` Binding.
-- Does not change Types.
renameExpr :: ASTContainer m Expr => Name -> Name -> m -> m
renameExpr old new = modifyASTs (renameExpr' old new)
renameExpr' :: Name -> Name -> Expr -> Expr
renameExpr' old new (Var i) = Var (renameExprId old new i)
renameExpr' old new (Data d) = Data (renameExprDataCon old new d)
renameExpr' old new (Lam u i e) = Lam u (renameExprId old new i) e
renameExpr' old new (Let b e) = Let (map (\(b', e') -> (renameExprId old new b', e')) b) e
renameExpr' old new (Case e i a) = Case e (renameExprId old new i) $ map (renameExprAlt old new) a
renameExpr' old new (Assume is e e') = Assume (fmap (rename old new) is) e e'
renameExpr' old new (Assert is e e') = Assert (fmap (rename old new) is) e e'
renameExpr' _ _ e = e
-- | Renames only the @Vars@ in an `Expr`.
renameVars :: ASTContainer m Expr => Name -> Name -> m -> m
renameVars old new = modifyASTs (renameVars' old new)
renameVars' :: Name -> Name -> Expr -> Expr
renameVars' old new (Var i) = Var (renameExprId old new i)
renameVars' old new (Lam u i e) = Lam u (renameExprId old new i) e
renameVars' old new (Let b e) = Let (map (\(b', e') -> (renameExprId old new b', e')) b) e
renameVars' old new (Case e i a) = Case e (renameExprId old new i) $ map (renameExprAltIds old new) a
renameVars' old new (Assert is e e') = Assert (fmap (rename old new) is) e e'
renameVars' _ _ e = e
renameExprId :: Name -> Name -> Id -> Id
renameExprId old new (Id n t) = Id (rename old new n) t
renameExprDataCon :: Name -> Name -> DataCon -> DataCon
renameExprDataCon old new (DataCon n t) = DataCon (rename old new n) t
renameExprAlt :: Name -> Name -> Alt -> Alt
renameExprAlt old new (Alt (DataAlt dc is) e) =
let
dc' = renameExprDataCon old new dc
is' = map (renameExprId old new) is
in
Alt (DataAlt dc' is') e
renameExprAlt _ _ a = a
renameExprAltIds :: Name -> Name -> Alt -> Alt
renameExprAltIds old new (Alt (DataAlt dc is) e) =
let
is' = map (renameExprId old new) is
in
Alt (DataAlt dc is') e
renameExprAltIds _ _ a = a
instance Named Type where
names = eval go
where
go (TyVar i) = idNamesInType i
go (TyCon n _) = [n]
go (TyForAll b _) = tyBinderNamesInType b
go _ = []
rename old new = modify go
where
go :: Type -> Type
go (TyVar i) = TyVar (renameIdInType old new i)
go (TyCon n ts) = TyCon (rename old new n) ts
go (TyForAll tb t) = TyForAll (renameTyBinderInType old new tb) t
go t = t
renames hm = modify go
where
go :: Type -> Type
go (TyVar i) = TyVar (renamesIdInType hm i)
go (TyCon n ts) = TyCon (renames hm n) ts
go (TyForAll tb t) = TyForAll (renamesTyBinderInType hm tb) t
go t = t
-- We don't want both modify and go to recurse on the Type's in TyBinders or Ids
-- so we introduce functions to collect or rename only the Names directly in those types
tyBinderNamesInType :: TyBinder -> [Name]
tyBinderNamesInType (NamedTyBndr i) = idNamesInType i
tyBinderNamesInType _ = []
idNamesInType :: Id -> [Name]
idNamesInType (Id n _) = [n]
renameTyBinderInType :: Name -> Name -> TyBinder -> TyBinder
renameTyBinderInType old new (NamedTyBndr i) = NamedTyBndr $ renameIdInType old new i
renameTyBinderInType _ _ tyb = tyb
renameIdInType :: Name -> Name -> Id -> Id
renameIdInType old new (Id n t) = Id (rename old new n) t
renamesTyBinderInType :: HM.HashMap Name Name -> TyBinder -> TyBinder
renamesTyBinderInType hm (NamedTyBndr i) = NamedTyBndr $ renamesIdInType hm i
renamesTyBinderInType _ tyb = tyb
renamesIdInType :: HM.HashMap Name Name -> Id -> Id
renamesIdInType hm (Id n t) = Id (renames hm n) t
instance Named Alt where
{-# INLINE names #-}
names (Alt am e) = names am ++ names e
{-# INLINE rename #-}
rename old new (Alt am e) = Alt (rename old new am) (rename old new e)
{-# INLINE renames #-}
renames hm (Alt am e) = Alt (renames hm am) (renames hm e)
instance Named DataCon where
{-# INLINE names #-}
names (DataCon n t) = n:names t
{-# INLINE rename #-}
rename old new (DataCon n t) =
DataCon (rename old new n) (rename old new t)
{-# INLINE renames #-}
renames hm (DataCon n t) =
DataCon (renames hm n) (renames hm t)
instance Named AltMatch where
{-# INLINE names #-}
names (DataAlt dc i) = names dc ++ names i
names _ = []
{-# INLINE rename #-}
rename old new (DataAlt dc i) =
DataAlt (rename old new dc) (rename old new i)
rename _ _ am = am
{-# INLINE renames #-}
renames hm (DataAlt dc i) =
DataAlt (renames hm dc) (renames hm i)
renames _ am = am
instance Named TyBinder where
names (AnonTyBndr t) = names t
names (NamedTyBndr i) = names i
rename old new (AnonTyBndr t) = AnonTyBndr (rename old new t)
rename old new (NamedTyBndr i) = NamedTyBndr (rename old new i)
renames hm (AnonTyBndr t) = AnonTyBndr (renames hm t)
renames hm (NamedTyBndr i) = NamedTyBndr (renames hm i)
instance Named Coercion where
names (t1 :~ t2) = names t1 ++ names t2
rename old new (t1 :~ t2) = rename old new t1 :~ rename old new t2
renames hm (t1 :~ t2) = renames hm t1 :~ renames hm t2
instance Named Tickish where
names (Breakpoint _) = []
names (NamedLoc n) = [n]
rename _ _ bp@(Breakpoint _) = bp
rename old new (NamedLoc n) = NamedLoc $ rename old new n
renames _ bp@(Breakpoint _) = bp
renames hm (NamedLoc n) = NamedLoc $ renames hm n
instance Named RewriteRule where
names (RewriteRule { ru_head = h
, ru_rough = rs
, ru_bndrs = b
, ru_args = as
, ru_rhs = rhs}) =
h:names rs ++ names b ++ names as ++ names rhs
rename old new (RewriteRule { ru_name = n
, ru_head = h
, ru_rough = rs
, ru_bndrs = b
, ru_args = as
, ru_rhs = rhs}) =
RewriteRule { ru_name = n
, ru_head = rename old new h
, ru_rough = rename old new rs
, ru_bndrs = rename old new b
, ru_args = rename old new as
, ru_rhs = rename old new rhs}
renames hm (RewriteRule { ru_name = n
, ru_head = h
, ru_rough = rs
, ru_bndrs = b
, ru_args = as
, ru_rhs = rhs}) =
RewriteRule { ru_name = n
, ru_head = renames hm h
, ru_rough = renames hm rs
, ru_bndrs = renames hm b
, ru_args = renames hm as
, ru_rhs = renames hm rhs}
instance Named FuncCall where
names (FuncCall {funcName = n, arguments = as, returns = r}) = n:names as ++ names r
rename old new (FuncCall {funcName = n, arguments = as, returns = r}) =
FuncCall {funcName = rename old new n, arguments = rename old new as, returns = rename old new r}
renames hm (FuncCall {funcName = n, arguments = as, returns = r} ) =
FuncCall {funcName = renames hm n, arguments = renames hm as, returns = renames hm r}
instance Named AlgDataTy where
names (DataTyCon ns dc) = names ns ++ names dc
names (NewTyCon ns dc rt) = names ns ++ names dc ++ names rt
names (TypeSynonym is st) = names is ++ names st
rename old new (DataTyCon n dc) = DataTyCon (rename old new n) (rename old new dc)
rename old new (NewTyCon n dc rt) = NewTyCon (rename old new n) (rename old new dc) (rename old new rt)
rename old new (TypeSynonym is st) = (TypeSynonym (rename old new is) (rename old new st))
renames hm (DataTyCon n dc) = DataTyCon (renames hm n) (renames hm dc)
renames hm (NewTyCon n dc rt) = NewTyCon (renames hm n) (renames hm dc) (renames hm rt)
renames hm (TypeSynonym is st) = TypeSynonym (renames hm is) (renames hm st)
instance Named KnownValues where
names (KnownValues {
dcInt = dI
, dcFloat = dF
, dcDouble = dD
, dcInteger = dI2
, dcChar = dcCh
, tyInt = tI
, tyFloat = tF
, tyDouble = tD
, tyInteger = tI2
, tyChar = tCh
, tyBool = tB
, dcTrue = dcT
, dcFalse = dcF
, tyList = tList
, dcCons = tCons
, dcEmpty = tEmp
, eqTC = eqT
, numTC = numT
, ordTC = ordT
, integralTC = integralT
, eqFunc = eqF
, neqFunc = neqF
, plusFunc = plF
, minusFunc = minusF
, timesFunc = tmsF
, divFunc = divF
, negateFunc = negF
, modFunc = modF
, fromIntegerFunc = fromIntegerF
, toIntegerFunc = toIntegerF
, geFunc = geF
, gtFunc = gtF
, ltFunc = ltF
, leFunc = leF
, structEqTC = seT
, structEqFunc = seF
, andFunc = andF
, orFunc = orF
, patErrorFunc = patE
}) =
[dI, dF, dD, dI2, dcCh, tI, tI2, tF, tD, tCh, tB, dcT, dcF, tList, tCons, tEmp
, eqT, numT, ordT, integralT, eqF, neqF, plF, minusF, tmsF, divF, negF, modF, fromIntegerF, toIntegerF
, geF, gtF, ltF, leF, seT, seF
, andF, orF, patE]
rename old new (KnownValues {
dcInt = dI
, dcFloat = dF
, dcDouble = dD
, dcInteger = dI2
, dcChar = dcCh
, tyInt = tI
, tyFloat = tF
, tyDouble = tD
, tyInteger = tI2
, tyChar = tCh
, tyBool = tB
, dcTrue = dcT
, dcFalse = dcF
, tyList = tList
, dcCons = tCons
, dcEmpty = tEmp
, eqTC = eqT
, numTC = numT
, ordTC = ordT
, integralTC = integralT
, eqFunc = eqF
, neqFunc = neqF
, plusFunc = plF
, minusFunc = minusF
, timesFunc = tmsF
, divFunc = divF
, negateFunc = negF
, modFunc = modF
, fromIntegerFunc = fromIntegerF
, toIntegerFunc = toIntegerF
, geFunc = geF
, gtFunc = gtF
, ltFunc = ltF
, leFunc = leF
, structEqTC = seT
, structEqFunc = seF
, andFunc = andF
, orFunc = orF
, patErrorFunc = patE
}) =
(KnownValues {
dcInt = rename old new dI
, dcFloat = rename old new dF
, dcDouble = rename old new dD
, dcInteger = rename old new dI2
, dcChar = rename old new dcCh
, tyInt = rename old new tI
, tyFloat = rename old new tF
, tyDouble = rename old new tD
, tyInteger = rename old new tI2
, tyChar = rename old new tCh
, tyBool = rename old new tB
, dcTrue = rename old new dcT
, dcFalse = rename old new dcF
, tyList = rename old new tList
, dcCons = rename old new tCons
, dcEmpty = rename old new tEmp
, eqTC = rename old new eqT
, numTC = rename old new numT
, ordTC = rename old new ordT
, integralTC = rename old new integralT
, eqFunc = rename old new eqF
, neqFunc = rename old new neqF
, plusFunc = rename old new plF
, minusFunc = rename old new minusF
, timesFunc = rename old new tmsF
, divFunc = rename old new divF
, negateFunc = rename old new negF
, modFunc = rename old new modF
, fromIntegerFunc = rename old new fromIntegerF
, toIntegerFunc = rename old new toIntegerF
, geFunc = rename old new geF
, gtFunc = rename old new gtF
, ltFunc = rename old new ltF
, leFunc = rename old new leF
, structEqTC = rename old new seT
, structEqFunc = rename old new seF
, andFunc = rename old new andF
, orFunc = rename old new orF
, patErrorFunc = rename old new patE
})
instance Named a => Named [a] where
{-# INLINE names #-}
names = foldMap names
{-# INLINE rename #-}
rename old new = fmap (rename old new)
{-# INLINE renames #-}
renames hm = fmap (renames hm)
instance Named a => Named (Maybe a) where
{-# INLINE names #-}
names = foldMap names
{-# INLINE rename #-}
rename old new = fmap (rename old new)
{-# INLINE renames #-}
renames hm = fmap (renames hm)
instance Named a => Named (M.Map k a) where
{-# INLINE names #-}
names = foldMap names
{-# INLINE rename #-}
rename old new = fmap (rename old new)
{-# INLINE renames #-}
renames hm = fmap (renames hm)
instance Named a => Named (HM.HashMap k a) where
{-# INLINE names #-}
names = foldMap names
{-# INLINE rename #-}
rename old new = fmap (rename old new)
{-# INLINE renames #-}
renames hm = fmap (renames hm)
instance Named () where
{-# INLINE names #-}
names _ = []
{-# INLINE rename #-}
rename _ _ = id
{-# INLINE renames #-}
renames _ = id
instance (Named s, Hashable s, Eq s) => Named (HS.HashSet s) where
{-# INLINE names #-}
names = names . HS.toList
{-# INLINE rename #-}
rename old new = HS.map (rename old new)
{-# INLINE renames #-}
renames hm = HS.map (renames hm)
instance (Named a, Named b) => Named (a, b) where
names (a, b) = names a ++ names b
rename old new (a, b) = (rename old new a, rename old new b)
renames hm (a, b) = (renames hm a, renames hm b)
instance (Named a, Named b, Named c) => Named (a, b, c) where
names (a, b, c) = names a ++ names b ++ names c
rename old new (a, b, c) = (rename old new a, rename old new b, rename old new c)
renames hm (a, b, c) = (renames hm a, renames hm b, renames hm c)
instance (Named a, Named b, Named c, Named d) => Named (a, b, c, d) where
names (a, b, c, d) = names a ++ names b ++ names c ++ names d
rename old new (a, b, c, d) = (rename old new a, rename old new b, rename old new c, rename old new d)
renames hm (a, b, c, d) = (renames hm a, renames hm b, renames hm c, renames hm d)
instance (Named a, Named b, Named c, Named d, Named e) => Named (a, b, c, d, e) where
names (a, b, c, d, e) = names a ++ names b ++ names c ++ names d ++ names e
rename old new (a, b, c, d, e) = (rename old new a, rename old new b, rename old new c, rename old new d, rename old new e)
renames hm (a, b, c, d, e) = (renames hm a, renames hm b, renames hm c, renames hm d, renames hm e)
instance Named Int where
{-# INLINE names #-}
names _ = []
{-# INLINE rename #-}
rename _ _ = id
instance Named T.Text where
{-# INLINE names #-}
names _ = []
{-# INLINE rename #-}
rename _ _ = id
freshSeededString :: T.Text -> NameGen -> (Name, NameGen)
freshSeededString t = freshSeededName (Name t Nothing 0 Nothing)
freshSeededStrings :: [T.Text] -> NameGen -> ([Name], NameGen)
freshSeededStrings t = freshSeededNames (map (\t' -> Name t' Nothing 0 Nothing) t)
freshSeededName :: Name -> NameGen -> (Name, NameGen)
freshSeededName (Name n m _ l) (NameGen { max_uniq = hm, dc_children = chm }) =
(Name n m i' l, NameGen hm' chm)
where
i' = HM.lookupDefault 0 (n, m) hm
hm' = HM.insert (n, m) (i' + 1) hm
freshSeededNames :: [Name] -> NameGen -> ([Name], NameGen)
freshSeededNames [] r = ([], r)
freshSeededNames (n:ns) r = (n':ns', ngen'')
where (n', ngen') = freshSeededName n r
(ns', ngen'') = freshSeededNames ns ngen'
freshName :: NameGen -> (Name, NameGen)
freshName ngen = freshSeededName seed ngen
where
seed = Name "fs?" Nothing 0 Nothing
freshNames :: Int -> NameGen -> ([Name], NameGen)
freshNames i ngen = freshSeededNames (replicate i (Name "fs?" Nothing 0 Nothing)) ngen
freshId :: Type -> NameGen -> (Id, NameGen)
freshId = freshSeededId (Name "fs?" Nothing 0 Nothing)
freshIds :: [Type] -> NameGen -> ([Id], NameGen)
freshIds ts ngen =
let
(ns, ngen') = freshNames (length ts) ngen
in
(map (uncurry Id) (zip ns ts), ngen')
freshSeededId :: Named a => a -> Type -> NameGen -> (Id, NameGen)
freshSeededId x t ngen =
let
(n, ngen') = freshSeededName (head $ names x) ngen
in
(Id n t, ngen')
freshVar :: Type -> NameGen -> (Expr, NameGen)
freshVar t ngen =
let
(i, ngen') = freshId t ngen
in
(Var i, ngen')
-- | Given the name n of a datacon, and some names for it's children,
-- returns new names ns for the children
-- Returns a new NameGen that will always return the same ns for that n
-- If this is called with different length ns's, the shorter will be the prefix
-- of the longer
childrenNames :: Name -> [Name] -> NameGen -> ([Name], NameGen)
childrenNames n ns ng@(NameGen { dc_children = chm }) =
case HM.lookup n chm of
Just ens' -> childrenNamesExisting n ns ens' ng
Nothing -> childrenNamesNew n ns ng-- []
childrenNamesExisting :: Name -> [Name] -> [Name] -> NameGen -> ([Name], NameGen)
childrenNamesExisting n ns ens ng =
let
(fns, NameGen hm chm) = freshSeededNames (drop (length ens) ns) ng
ns' = ens ++ fns
chm' = HM.insert n ns' chm
in
case length ns `compare` length ens of
LT -> (take (length ns) ens, ng)
EQ -> (ens, ng)
GT -> (ns', NameGen hm chm')
childrenNamesNew :: Name -> [Name] -> NameGen -> ([Name], NameGen)
childrenNamesNew n ns ng =
let
(fns, NameGen hm chm) = freshSeededNames ns ng
chm' = HM.insert n fns chm
in
(fns, NameGen hm chm')
-- | Allows mapping, while passing a NameGen along
mapNG :: (a -> NameGen -> (b, NameGen)) -> [a] -> NameGen -> ([b], NameGen)
mapNG f xs ng = swap $ mapAccumR (\xs' ng' -> swap $ f ng' xs') ng xs -- mapNG' f (reverse xs) ng []
{-# INLINE mapNG #-}
-- mapNG' :: (a -> NameGen -> (b, NameGen)) -> [a] -> NameGen -> [b] -> ([b], NameGen)
-- mapNG' _ [] ng xs = (xs, ng)
-- mapNG' f (x:xs) ng xs' =
-- let
-- (x', ng') = f x ng
-- in
-- mapNG' f xs ng' (x':xs')