g2-0.1.0.0: src/G2/Language/TypeEnv.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module G2.Language.TypeEnv
( TypeEnv
, nameModMatch
, argTypesTEnv
, dataCon
, boundIds
, isPolyAlgDataTy
, isDataTyCon
, isNewTyCon
, newTyConRepType
, typeStripCastType
, getDataCons
, baseDataCons
, getCastedAlgDataTy
, getAlgDataTy
, getDataCon
, getDataConNoType
, getDataConNameMod
, getDataConNameMod'
, dataConArgs
, dataConWithName
, dcName
, retypeAlgDataTy
, module G2.Language.AlgDataTy
) where
import G2.Language.AST
import G2.Language.Syntax
import G2.Language.Typing
import G2.Language.AlgDataTy
import Data.List
import qualified Data.Map as M
import Data.Maybe
-- | The type environment maps names of types to their appropriate types. However
-- our primary interest with these is for dealing with algebraic data types,
-- and we only store those information accordingly.
type TypeEnv = M.Map Name AlgDataTy
nameModMatch :: Name -> TypeEnv -> Maybe Name
nameModMatch (Name n m _ _) = find (\(Name n' m' _ _) -> n == n' && m == m' ) . M.keys
-- Returns a list of all argument function types in the type env
argTypesTEnv :: TypeEnv -> [Type]
argTypesTEnv = concatMap (evalASTs argTypesTEnv') . M.elems
argTypesTEnv' :: Type -> [Type]
argTypesTEnv' (TyFun t@(TyFun _ _) _) = [t]
argTypesTEnv' _ = []
dataCon :: AlgDataTy -> [DataCon]
dataCon (DataTyCon {data_cons = dc}) = dc
dataCon (NewTyCon {data_con = dc}) = [dc]
dataCon (TypeSynonym {}) = []
boundIds :: AlgDataTy -> [Id]
boundIds = bound_ids
dcName :: DataCon -> Name
dcName (DataCon n _) = n
isPolyAlgDataTy :: AlgDataTy -> Bool
isPolyAlgDataTy = not . null . bound_ids
isDataTyCon :: AlgDataTy -> Bool
isDataTyCon (DataTyCon {}) = True
isDataTyCon _ = False
isNewTyCon :: AlgDataTy -> Bool
isNewTyCon (NewTyCon {}) = True
isNewTyCon _ = False
newTyConRepType :: AlgDataTy -> Maybe Type
newTyConRepType (NewTyCon {rep_type = t}) = Just t
newTyConRepType _ = Nothing
typeStripCastType :: TypeEnv -> Type -> Type
typeStripCastType tenv t
| Just (adt, _) <- getCastedAlgDataTy t tenv
, Just rt <- newTyConRepType adt = rt
typeStripCastType _ t = t
getDataCons :: Name -> TypeEnv -> Maybe [DataCon]
getDataCons n tenv =
case M.lookup n tenv of
Just (DataTyCon _ dc) -> Just dc
Just (NewTyCon _ dc _) -> Just [dc]
Just (TypeSynonym _ (TyCon n' _)) -> getDataCons n' tenv
_ -> Nothing
baseDataCons :: [DataCon] -> [DataCon]
baseDataCons = filter baseDataCon
baseDataCon :: DataCon -> Bool
baseDataCon (DataCon _ t) = not $ hasTyFuns t
-- If the Type is a TyCon, (optionally) wrapped with TyApps,
-- returns the AlgDataTy of the Cast type, along with mappings from
-- the bound names of the cast type, to the types bound by the TyApps.
getCastedAlgDataTy :: Type -> TypeEnv -> Maybe (AlgDataTy, [(Id, Type)])
getCastedAlgDataTy t tenv
| TyCon n _ <- tyAppCenter t
, ts <- tyAppArgs t = getCastedAlgDataTy' n ts tenv
| otherwise = Nothing
-- TODO : CHECK CORRECTNESS OF BOUND ARGS
getCastedAlgDataTy' :: Name -> [Type] -> TypeEnv -> Maybe (AlgDataTy, [(Id, Type)])
getCastedAlgDataTy' n ts tenv =
case M.lookup n tenv of
Just (NewTyCon {rep_type = TyCon n' _}) -> getCastedAlgDataTy' n' ts tenv
Just (NewTyCon { }) -> Nothing
(Just dc@(DataTyCon { bound_ids = bi })) -> Just (dc, zip bi ts)
_ -> Nothing
getAlgDataTy :: Type -> TypeEnv -> Maybe (AlgDataTy, [(Id, Type)])
getAlgDataTy t tenv
| TyCon n _ <- tyAppCenter t
, ts <- tyAppArgs t = getAlgDataTy' n ts tenv
| otherwise = Nothing
getAlgDataTy' :: Name -> [Type] -> TypeEnv -> Maybe (AlgDataTy, [(Id, Type)])
getAlgDataTy' n ts tenv =
case M.lookup n tenv of
Just dc@(NewTyCon {bound_ids = bi}) -> Just (dc, zip bi ts)
Just dc@(DataTyCon { bound_ids = bi }) -> Just (dc, zip bi ts)
_ -> Nothing
getDataCon :: TypeEnv -> Name -> Name -> Maybe DataCon
getDataCon tenv adt dc =
let
adt' = M.lookup adt tenv
in
maybe Nothing (flip dataConWithName dc) adt'
getDataConNoType :: TypeEnv -> Name -> Maybe DataCon
getDataConNoType tenv n = find (\dc -> dcName dc == n) . concatMap dataCon $ M.elems tenv
getDataConNameMod :: TypeEnv -> Name -> Name -> Maybe DataCon
getDataConNameMod tenv (Name n m _ _) dc =
let
adt' = fmap snd $ find (\(Name n' m' _ _, _) -> n == n' && m == m') $ M.toList tenv
in
maybe Nothing (flip dataConWithNameMod dc) adt'
getDataConNameMod' :: TypeEnv -> Name -> Maybe DataCon
getDataConNameMod' tenv n = find (flip dataConHasNameMod n) $ concatMap dataCon $ M.elems tenv
dataConArgs :: DataCon -> [Type]
dataConArgs dc = anonArgumentTypes dc
dataConWithName :: AlgDataTy -> Name -> Maybe DataCon
dataConWithName (DataTyCon _ dcs) n = listToMaybe $ filter (flip dataConHasName n) dcs
dataConWithName _ _ = Nothing
dataConHasName :: DataCon -> Name -> Bool
dataConHasName (DataCon n _) n' = n == n'
dataConWithNameMod :: AlgDataTy -> Name -> Maybe DataCon
dataConWithNameMod (DataTyCon _ dcs) n = listToMaybe $ filter (flip dataConHasNameMod n) dcs
dataConWithNameMod _ _ = Nothing
dataConHasNameMod :: DataCon -> Name -> Bool
dataConHasNameMod (DataCon (Name n m _ _) _) (Name n' m' _ _) = n == n' && m == m'
retypeAlgDataTy :: [Type] -> AlgDataTy -> AlgDataTy
retypeAlgDataTy ts adt =
foldr (uncurry retype) adt $ zip (bound_ids adt) ts