module FreeC.IR.TypeSynExpansion
(
expandAllTypeSynonymsInDecl
, expandAllTypeSynonymsInDeclWhere
, expandAllTypeSynonymsInConDecl
, expandAllTypeSynonymsInConDeclWhere
, expandTypeSynonym
, expandAllTypeSynonyms
, expandAllTypeSynonymsWhere
, expandTypeSynonyms
, expandTypeSynonymsWhere
, expandTypeSynonymAt
) where
import Control.Applicative ( (<|>) )
import Control.Monad.Trans.Maybe ( MaybeT(..) )
import Data.Maybe ( fromMaybe )
import FreeC.Environment
import FreeC.IR.Subst
import FreeC.IR.Subterm
import qualified FreeC.IR.Syntax as IR
import FreeC.Monad.Class.Hoistable ( hoistMaybe )
import FreeC.Monad.Converter
expandAllTypeSynonymsInDecl :: IR.TypeDecl -> Converter IR.TypeDecl
expandAllTypeSynonymsInDecl = expandAllTypeSynonymsInDeclWhere (const True)
expandAllTypeSynonymsInDeclWhere
:: (IR.QName -> Bool) -> IR.TypeDecl -> Converter IR.TypeDecl
expandAllTypeSynonymsInDeclWhere predicate
(IR.TypeSynDecl srcSpan declIdent typeVarDecls typeExpr) = do
typeExpr' <- expandAllTypeSynonymsWhere predicate typeExpr
return (IR.TypeSynDecl srcSpan declIdent typeVarDecls typeExpr')
expandAllTypeSynonymsInDeclWhere predicate
(IR.DataDecl srcSpan declIdent typeVarDecls conDecls) = do
conDecls' <- mapM (expandAllTypeSynonymsInConDeclWhere predicate) conDecls
return (IR.DataDecl srcSpan declIdent typeVarDecls conDecls')
expandAllTypeSynonymsInConDecl :: IR.ConDecl -> Converter IR.ConDecl
expandAllTypeSynonymsInConDecl = expandAllTypeSynonymsInConDeclWhere
(const True)
expandAllTypeSynonymsInConDeclWhere
:: (IR.QName -> Bool) -> IR.ConDecl -> Converter IR.ConDecl
expandAllTypeSynonymsInConDeclWhere predicate
(IR.ConDecl srcSpan declIdent argTypes) = do
argTypes' <- mapM (expandAllTypeSynonymsWhere predicate) argTypes
return (IR.ConDecl srcSpan declIdent argTypes')
expandTypeSynonym :: IR.Type -> Converter IR.Type
expandTypeSynonym = expandTypeSynonyms 1
expandAllTypeSynonyms :: IR.Type -> Converter IR.Type
expandAllTypeSynonyms = expandAllTypeSynonymsWhere (const True)
expandAllTypeSynonymsWhere
:: (IR.QName -> Bool) -> IR.Type -> Converter IR.Type
expandAllTypeSynonymsWhere = expandTypeSynonymsWhere (-1)
expandTypeSynonyms :: Int -> IR.Type -> Converter IR.Type
expandTypeSynonyms = flip expandTypeSynonymsWhere (const True)
expandTypeSynonymsWhere
:: Int -> (IR.QName -> Bool) -> IR.Type -> Converter IR.Type
expandTypeSynonymsWhere maxDepth predicate t0
| maxDepth == 0 = return t0
| otherwise = do
t0' <- expandTypeSynonyms' t0 []
return (fromMaybe t0 t0')
where
expandTypeSynonyms' :: IR.Type -> [IR.Type] -> Converter (Maybe IR.Type)
expandTypeSynonyms' (IR.TypeCon _ typeConName) args = do
mTypeSynonym <- inEnv $ lookupTypeSynonym typeConName
case mTypeSynonym of
Just (typeVars, typeExpr)
| predicate typeConName -> do
let subst = composeSubsts
(zipWith (singleSubst . IR.UnQual . IR.Ident) typeVars args)
typeExpr' = applySubst subst typeExpr
Just <$> expandTypeSynonymsWhere (maxDepth - 1) predicate typeExpr'
_ -> return Nothing
expandTypeSynonyms' (IR.TypeApp srcSpan t1 t2) args = do
t2' <- expandTypeSynonymsWhere (maxDepth - 1) predicate t2
let args' = t2' : args
t1' <- expandTypeSynonyms' t1 args'
return (t1' <|> Just (IR.typeApp srcSpan t1 args'))
expandTypeSynonyms' (IR.FuncType srcSpan t1 t2) _ = do
t1' <- expandTypeSynonymsWhere (maxDepth - 1) predicate t1
t2' <- expandTypeSynonymsWhere (maxDepth - 1) predicate t2
return (Just (IR.FuncType srcSpan t1' t2'))
expandTypeSynonyms' (IR.TypeVar _ _) _ = return Nothing
expandTypeSynonymAt :: Pos -> IR.Type -> Converter IR.Type
expandTypeSynonymAt pos typeExpr = case parentPos pos of
Just pos' | maybe False isTypeApp (selectSubterm typeExpr pos') ->
expandTypeSynonymAt pos' typeExpr
_ -> fmap (fromMaybe typeExpr) $ runMaybeT $ do
subterm <- hoistMaybe $ selectSubterm typeExpr pos
subterm' <- lift $ expandTypeSynonym subterm
hoistMaybe $ replaceSubterm typeExpr pos subterm'
where
isTypeApp :: IR.Type -> Bool
isTypeApp (IR.TypeApp _ _ _) = True
isTypeApp _ = False