packages feed

ddc-source-tetra-0.4.3.1: DDC/Source/Tetra/Env.hs

-- | Source Tetra primitive type and kind environments.
module DDC.Source.Tetra.Env
        ( Env           (..)

        , Presence      (..)
        , takePresent

        , empty
        , union, unions

          -- ** Type Variables
        , singletonTyVar, singletonTyVar'
        , extendTyVar
        , extendTyVar',   extendsTyVar'
        , lookupTyVar
        , tyStackDepth

          -- ** Data Constructors
        , singletonDaCon
        , extendDaCon
        , lookupDaCon

          -- ** Term Variables
        , singletonDaVar
        , singletonDaVar'
        , extendDaVar,   extendsDaVar
        , extendDaVar'
        , extendDaVarMT, extendsDaVarMT
        , lookupDaVar
        , daStackDepth

          -- * Primitive Kinds and Types.
        , kindOfPrimType
        , typeOfPrimVal
        , typeOfPrimLit)
where
import DDC.Source.Tetra.Prim
import DDC.Source.Tetra.Exp.Source
import Data.Map                         (Map)
import Data.Sequence                    (Seq)
import Data.Text                        (Text)
import qualified Data.List              as List
import qualified Data.Map.Strict        as Map
import qualified Data.Sequence          as Seq


---------------------------------------------------------------------------------------------------
data Env
        = Env
        { -- | Map names of type constructors to their kinds.
          envTyCon      :: Map Text Type

          -- | Map names of variables to their kinds.
        , envTyVar      :: Map Text (Maybe Type)

          -- | Stack of kinds of deBruijn indexed type variables.
        , envTyStack    :: Seq (Maybe Type)
          
          -- | Map names of data constructors to their types.
        , envDaCon      :: Map Text Type 

          -- | Map names of term variables to their types.
        , envDaVar      :: Map Text (Maybe Type)

          -- | Stack of types of deBruijn indexed term variables.
        , envDaStack    :: Seq (Maybe Type) }


-- | Presence of a variable in the environment.
data Presence a
        -- | Variable is not present in environment.
        = Absent

        -- | Variable is present but we don't have a type for it.
        | Unknown

        -- | Variable is present in the environment with this information.
        | Present  a
        deriving Show


-- | Yield `Just` for a `Present` and `Nothing` for the others.
takePresent :: Presence a -> Maybe a
takePresent pp
 = case pp of
        Absent          -> Nothing
        Unknown         -> Nothing
        Present x       -> Just x


-- | An empty environment.
empty :: Env
empty 
        = Env
        { envTyCon      = Map.empty
        , envTyVar      = Map.empty
        , envTyStack    = Seq.empty
        , envDaCon      = Map.empty
        , envDaVar      = Map.empty
        , envDaStack    = Seq.empty }


-- | Take the right biased union of two environments.
union :: Env -> Env -> Env
union env1 env2
        = Env
        { envTyCon      = Map.union (envTyCon env1) (envTyCon env2)
        , envTyVar      = Map.union (envTyVar env1) (envTyVar env2)
        , envTyStack    = envTyStack env1 Seq.>< envTyStack env2

        , envDaCon      = Map.union (envDaCon env1) (envDaCon env2)
        , envDaVar      = Map.union (envDaVar env1) (envDaVar env2) 
        , envDaStack    = envDaStack env1 Seq.>< envDaStack env2 }


-- | Take the right biased union of a list of type environments.
unions :: [Env] -> Env
unions envs
        = List.foldl' union empty envs


---------------------------------------------------------------------------------------------------
-- | Extend the environment with the kind for a type variable.
extendTyVar :: Bind -> Type -> Env -> Env
extendTyVar b k env
 = case b of
        BNone   -> env
        BAnon   -> env { envTyStack = (envTyStack env) Seq.|> (Just k) }
        BName n -> env { envTyVar   = Map.insert n (Just k) (envTyVar env) }


-- | Extend the environment with a type variable where we don't know its kind.
extendTyVar' :: Bind -> Env -> Env
extendTyVar' b env
 = case b of
        BNone   -> env
        BAnon   -> env { envTyStack = (envTyStack env) Seq.|> Nothing }
        BName n -> env { envTyVar   = Map.insert n Nothing (envTyVar env) }


-- | Extend the environment with some type variables where we don't know their kinds.
extendsTyVar' :: [Bind] -> Env -> Env
extendsTyVar' bs env
 = List.foldl' (flip extendTyVar') env bs


-- | Yield an environment containing a single type variable.
singletonTyVar' :: Bind -> Env
singletonTyVar' b 
 = extendTyVar' b empty

-- | Yield an environment containing the kind for a single type variable.
singletonTyVar :: Bind -> Type -> Env
singletonTyVar b t
 = extendTyVar b t empty



-- | Lookup the kind of the given type variable.
lookupTyVar :: Env -> Bound -> Presence Type
lookupTyVar env u
 = case u of
        UName tx
         -> case Map.lookup tx (envTyVar env) of
                Nothing         -> Absent
                Just Nothing    -> Unknown
                Just (Just t)   -> Present t

        UIx i
         |  i >= Seq.length (envTyStack env)  
         -> Absent

         | otherwise
         -> case Seq.index (envTyStack env) i of
                Nothing -> Unknown
                Just t  -> Present t

        UHole
         -> Unknown
        

-- | Get the depth of the type stack.
tyStackDepth :: Env -> Int
tyStackDepth env = Seq.length (envTyStack env)


---------------------------------------------------------------------------------------------------
-- | Extend the environment with the type of a data constructor.
extendDaCon :: DaConBind -> Type -> Env -> Env
extendDaCon (DaConBindName tx) t env
 = env { envDaCon = Map.insert tx t (envDaCon env) }


-- | Yield an environment containing the type of a single data constructor.
singletonDaCon :: DaConBind -> Type -> Env
singletonDaCon dc t 
 = extendDaCon dc t empty


-- | Lookup the type of a data constructor.
lookupDaCon :: DaConBound -> Env -> Maybe Type
lookupDaCon dc env
 = case dc of
        DaConBoundName tx       -> Map.lookup tx (envDaCon env)
        DaConBoundLit  lit      -> Just (typeOfPrimLit lit)


---------------------------------------------------------------------------------------------------
-- | Extend the environment with the type of a term variable.
extendDaVar :: Bind -> Type -> Env -> Env
extendDaVar b t env
 = case b of
        BNone   -> env
        BAnon   -> env { envDaStack = (envDaStack env) Seq.|> (Just t) }
        BName n -> env { envDaVar   = Map.insert n (Just t) (envDaVar env) }


-- | Extend the environment with the types of some term variables.
extendsDaVar :: [(Bind, Type)] -> Env -> Env
extendsDaVar bxs env
 = List.foldl' (\env' (b, t) -> extendDaVar b t env') env bxs


-- | Extend the environment with a term variable where we don't know it's type.
extendDaVar' :: Bind -> Env -> Env
extendDaVar' b env
 = case b of
        BNone   -> env
        BAnon   -> env { envDaStack = (envDaStack env) Seq.|> Nothing }
        BName n -> env { envDaVar   = Map.insert n Nothing (envDaVar env) }


-- | Like `extendDaVar` but take a `BindVarMT`
extendDaVarMT :: BindVarMT -> Env -> Env
extendDaVarMT xb env
 = case xb of
        XBindVarMT b Nothing    -> extendDaVar' b env
        XBindVarMT b (Just t)   -> extendDaVar  b t env


-- | Like `extendDaVarMT` but take a list of `BindVarMT`
extendsDaVarMT :: [BindVarMT] -> Env -> Env
extendsDaVarMT bs env
 = List.foldl' (flip extendDaVarMT) env bs


-- | Yield an environment containing the type for a single term variable.
singletonDaVar :: Bind -> Type -> Env
singletonDaVar b t
 = extendDaVar b t empty


-- | Yield an environment containing a single term variable where we don't know its type.
singletonDaVar' :: Bind -> Env
singletonDaVar' b 
 = extendDaVar' b empty


-- | Lookup the kind of the given type variable.
lookupDaVar :: Env -> Bound -> Presence Type
lookupDaVar env u
 = case u of
        UName tx
         -> case Map.lookup tx (envDaVar env) of
                Nothing         -> Absent
                Just Nothing    -> Unknown
                Just (Just t)   -> Present t

        UIx i
         |  i >= Seq.length (envDaStack env)  
         -> Absent

         |  otherwise    
         -> case Seq.index (envDaStack env) i of
                Nothing -> Unknown
                Just t  -> Present t

        UHole
         -> Unknown
        

-- | Get the depth of the type stack.
daStackDepth :: Env -> Int
daStackDepth env = Seq.length (envDaStack env)


---------------------------------------------------------------------------------------------------
-- | Take the kind of a primitive type.
kindOfPrimType :: PrimType -> Maybe Type
kindOfPrimType tt
 = case tt of
        PrimTypeSoCon _         -> Nothing
        PrimTypeKiCon _         -> Nothing
        PrimTypeTwCon _         -> Nothing
        PrimTypeTcCon _         -> Nothing
        PrimTypeTyCon tc        -> Just (kindPrimTyCon tc)
        PrimTypeTyConTetra tc   -> Just (kindPrimTyConTetra tc)


-- | Take the type of a primitive name.
typeOfPrimVal  :: PrimVal -> Type
typeOfPrimVal dc
 = case dc of
        PrimValLit      l       -> typeOfPrimLit l
        PrimValArith    p       -> typePrimArith Source p
        PrimValCast     p       -> typePrimCast  Source p
        PrimValError    p       -> typeOpError   Source p
        PrimValVector   p       -> typeOpVector  Source p
        PrimValFun      p       -> typeOpFun     Source p


-- | Take the type of a primitive literal.
typeOfPrimLit   :: PrimLit -> Type
typeOfPrimLit pl
 = case pl of
        PrimLitBool     _       -> TBool
        PrimLitNat      _       -> TNat
        PrimLitInt      _       -> TInt
        PrimLitSize     _       -> TSize
        PrimLitFloat    _ bits  -> TFloat bits
        PrimLitWord     _ bits  -> TWord  bits
        PrimLitChar     _       -> TWord  32
        PrimLitTextLit  _       -> TTextLit