{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RecordWildCards #-}
module Cryptol.ModuleSystem.NamingEnv where
import Cryptol.ModuleSystem.Interface
import Cryptol.ModuleSystem.Name
import Cryptol.Parser.AST
import Cryptol.Parser.Name(isGeneratedName)
import Cryptol.Parser.Position
import qualified Cryptol.TypeCheck.AST as T
import Cryptol.Utils.PP
import Cryptol.Utils.Panic (panic)
import Data.List (nub)
import Data.Maybe (fromMaybe)
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Data.Semigroup
import MonadLib (runId,Id)
import GHC.Generics (Generic)
import Control.DeepSeq
import Prelude ()
import Prelude.Compat
data NamingEnv = NamingEnv { neExprs :: !(Map.Map PName [Name])
, neTypes :: !(Map.Map PName [Name])
} deriving (Show, Generic, NFData)
lookupValNames :: PName -> NamingEnv -> [Name]
lookupValNames qn ro = Map.findWithDefault [] qn (neExprs ro)
lookupTypeNames :: PName -> NamingEnv -> [Name]
lookupTypeNames qn ro = Map.findWithDefault [] qn (neTypes ro)
instance Semigroup NamingEnv where
l <> r =
NamingEnv { neExprs = Map.unionWith merge (neExprs l) (neExprs r)
, neTypes = Map.unionWith merge (neTypes l) (neTypes r) }
instance Monoid NamingEnv where
mempty =
NamingEnv { neExprs = Map.empty
, neTypes = Map.empty }
mappend l r = l <> r
mconcat envs =
NamingEnv { neExprs = Map.unionsWith merge (map neExprs envs)
, neTypes = Map.unionsWith merge (map neTypes envs) }
{-# INLINE mempty #-}
{-# INLINE mappend #-}
{-# INLINE mconcat #-}
merge :: [Name] -> [Name] -> [Name]
merge xs ys | xs == ys = xs
| otherwise = nub (xs ++ ys)
toPrimMap :: NamingEnv -> PrimMap
toPrimMap NamingEnv { .. } = PrimMap { .. }
where
entry n = case asPrim n of
Just p -> (p,n)
Nothing -> panic "toPrimMap" [ "Not a declared name?"
, show n
]
primDecls = Map.fromList [ entry n | ns <- Map.elems neExprs, n <- ns ]
primTypes = Map.fromList [ entry n | ns <- Map.elems neTypes, n <- ns ]
toNameDisp :: NamingEnv -> NameDisp
toNameDisp NamingEnv { .. } = NameDisp display
where
display mn ident = Map.lookup (mn,ident) names
names = Map.fromList
$ [ mkEntry (mn, nameIdent n) pn | (pn,ns) <- Map.toList neExprs
, n <- ns
, Declared mn _ <- [nameInfo n] ]
++ [ mkEntry (mn, nameIdent n) pn | (pn,ns) <- Map.toList neTypes
, n <- ns
, Declared mn _ <- [nameInfo n] ]
mkEntry key pn = (key,fmt)
where fmt = case getModName pn of
Just ns -> Qualified ns
Nothing -> UnQualified
visibleNames :: NamingEnv -> ( Set.Set Name
, Set.Set Name)
visibleNames NamingEnv { .. } = (types,decls)
where
types = Set.fromList [ n | [n] <- Map.elems neTypes ]
decls = Set.fromList [ n | [n] <- Map.elems neExprs ]
qualify :: ModName -> NamingEnv -> NamingEnv
qualify pfx NamingEnv { .. } =
NamingEnv { neExprs = Map.mapKeys toQual neExprs
, neTypes = Map.mapKeys toQual neTypes
}
where
toQual (Qual _ n) = Qual pfx n
toQual (UnQual n) = Qual pfx n
toQual n@NewName{} = n
filterNames :: (PName -> Bool) -> NamingEnv -> NamingEnv
filterNames p NamingEnv { .. } =
NamingEnv { neExprs = Map.filterWithKey check neExprs
, neTypes = Map.filterWithKey check neTypes
}
where
check :: PName -> a -> Bool
check n _ = p n
singletonT :: PName -> Name -> NamingEnv
singletonT qn tn = mempty { neTypes = Map.singleton qn [tn] }
singletonE :: PName -> Name -> NamingEnv
singletonE qn en = mempty { neExprs = Map.singleton qn [en] }
shadowing :: NamingEnv -> NamingEnv -> NamingEnv
shadowing l r = NamingEnv
{ neExprs = Map.union (neExprs l) (neExprs r)
, neTypes = Map.union (neTypes l) (neTypes r) }
travNamingEnv :: Applicative f => (Name -> f Name) -> NamingEnv -> f NamingEnv
travNamingEnv f ne = NamingEnv <$> neExprs' <*> neTypes'
where
neExprs' = traverse (traverse f) (neExprs ne)
neTypes' = traverse (traverse f) (neTypes ne)
data InModule a = InModule !ModName a
deriving (Functor,Traversable,Foldable,Show)
namingEnv' :: BindsNames a => a -> Supply -> (NamingEnv,Supply)
namingEnv' a supply = runId (runSupplyT supply (runBuild (namingEnv a)))
newTop :: FreshM m => ModName -> PName -> Maybe Fixity -> Range -> m Name
newTop ns thing fx rng = liftSupply (mkDeclared ns src (getIdent thing) fx rng)
where src = if isGeneratedName thing then SystemName else UserName
newLocal :: FreshM m => PName -> Range -> m Name
newLocal thing rng = liftSupply (mkParameter (getIdent thing) rng)
newtype BuildNamingEnv = BuildNamingEnv { runBuild :: SupplyT Id NamingEnv }
instance Semigroup BuildNamingEnv where
BuildNamingEnv a <> BuildNamingEnv b = BuildNamingEnv $
do x <- a
y <- b
return (mappend x y)
instance Monoid BuildNamingEnv where
mempty = BuildNamingEnv (pure mempty)
mappend = (<>)
mconcat bs = BuildNamingEnv $
do ns <- sequence (map runBuild bs)
return (mconcat ns)
class BindsNames a where
namingEnv :: a -> BuildNamingEnv
instance BindsNames NamingEnv where
namingEnv env = BuildNamingEnv (return env)
{-# INLINE namingEnv #-}
instance BindsNames a => BindsNames (Maybe a) where
namingEnv = foldMap namingEnv
{-# INLINE namingEnv #-}
instance BindsNames a => BindsNames [a] where
namingEnv = foldMap namingEnv
{-# INLINE namingEnv #-}
instance BindsNames (Schema PName) where
namingEnv (Forall ps _ _ _) = foldMap namingEnv ps
{-# INLINE namingEnv #-}
interpImport :: Import ->
IfaceDecls ->
NamingEnv
interpImport imp publicDecls = qualified
where
qualified | Just pfx <- iAs imp = qualify pfx restricted
| otherwise = restricted
restricted
| Just (Hiding ns) <- iSpec imp =
filterNames (\qn -> not (getIdent qn `elem` ns)) public
| Just (Only ns) <- iSpec imp =
filterNames (\qn -> getIdent qn `elem` ns) public
| otherwise = public
public = unqualifiedEnv publicDecls
unqualifiedEnv :: IfaceDecls -> NamingEnv
unqualifiedEnv IfaceDecls { .. } =
mconcat [ exprs, tySyns, ntTypes, absTys, ntExprs ]
where
toPName n = mkUnqual (nameIdent n)
exprs = mconcat [ singletonE (toPName n) n | n <- Map.keys ifDecls ]
tySyns = mconcat [ singletonT (toPName n) n | n <- Map.keys ifTySyns ]
ntTypes = mconcat [ singletonT (toPName n) n | n <- Map.keys ifNewtypes ]
absTys = mconcat [ singletonT (toPName n) n | n <- Map.keys ifAbstractTypes ]
ntExprs = mconcat [ singletonE (toPName n) n | n <- Map.keys ifNewtypes ]
modParamsNamingEnv :: IfaceParams -> NamingEnv
modParamsNamingEnv IfaceParams { .. } =
NamingEnv { neExprs = Map.fromList $ map fromFu $ Map.keys ifParamFuns
, neTypes = Map.fromList $ map fromTy $ Map.elems ifParamTypes
}
where
toPName n = mkUnqual (nameIdent n)
fromTy tp = let nm = T.mtpName tp
in (toPName nm, [nm])
fromFu f = (toPName f, [f])
data ImportIface = ImportIface Import Iface
instance BindsNames ImportIface where
namingEnv (ImportIface imp Iface { .. }) = BuildNamingEnv $
return (interpImport imp ifPublic)
{-# INLINE namingEnv #-}
instance BindsNames (InModule (Bind PName)) where
namingEnv (InModule ns b) = BuildNamingEnv $
do let Located { .. } = bName b
n <- newTop ns thing (bFixity b) srcRange
return (singletonE thing n)
instance BindsNames (TParam PName) where
namingEnv TParam { .. } = BuildNamingEnv $
do let range = fromMaybe emptyRange tpRange
n <- newLocal tpName range
return (singletonT tpName n)
instance BindsNames (Module PName) where
namingEnv Module { .. } = foldMap (namingEnv . InModule ns) mDecls
where
ns = thing mName
instance BindsNames (InModule (TopDecl PName)) where
namingEnv (InModule ns td) =
case td of
Decl d -> namingEnv (InModule ns (tlValue d))
DPrimType d -> namingEnv (InModule ns (tlValue d))
TDNewtype d -> namingEnv (InModule ns (tlValue d))
DParameterType d -> namingEnv (InModule ns d)
DParameterConstraint {} -> mempty
DParameterFun d -> namingEnv (InModule ns d)
Include _ -> mempty
instance BindsNames (InModule (PrimType PName)) where
namingEnv (InModule ns PrimType { .. }) =
BuildNamingEnv $
do let Located { .. } = primTName
nm <- newTop ns thing primTFixity srcRange
pure (singletonT thing nm)
instance BindsNames (InModule (ParameterFun PName)) where
namingEnv (InModule ns ParameterFun { .. }) = BuildNamingEnv $
do let Located { .. } = pfName
ntName <- newTop ns thing pfFixity srcRange
return (singletonE thing ntName)
instance BindsNames (InModule (ParameterType PName)) where
namingEnv (InModule ns ParameterType { .. }) = BuildNamingEnv $
do let Located { .. } = ptName
ntName <- newTop ns thing Nothing srcRange
return (singletonT thing ntName)
instance BindsNames (InModule (Newtype PName)) where
namingEnv (InModule ns Newtype { .. }) = BuildNamingEnv $
do let Located { .. } = nName
ntName <- newTop ns thing Nothing srcRange
return (singletonT thing ntName `mappend` singletonE thing ntName)
instance BindsNames (InModule (Decl PName)) where
namingEnv (InModule pfx d) = case d of
DBind b -> BuildNamingEnv $
do n <- mkName (bName b) (bFixity b)
return (singletonE (thing (bName b)) n)
DSignature ns _sig -> foldMap qualBind ns
DPragma ns _p -> foldMap qualBind ns
DType syn -> qualType (tsName syn) (tsFixity syn)
DProp syn -> qualType (psName syn) (psFixity syn)
DLocated d' _ -> namingEnv (InModule pfx d')
DPatBind _pat _e -> panic "ModuleSystem" ["Unexpected pattern binding"]
DFixity{} -> panic "ModuleSystem" ["Unexpected fixity declaration"]
where
mkName ln fx = newTop pfx (thing ln) fx (srcRange ln)
qualBind ln = BuildNamingEnv $
do n <- mkName ln Nothing
return (singletonE (thing ln) n)
qualType ln f = BuildNamingEnv $
do n <- mkName ln f
return (singletonT (thing ln) n)