module FreeC.LiftedIR.Converter.Type
( liftFuncArgTypes
, liftConArgType
, liftVarPatType
, liftType
, liftType'
) where
import Data.Bool ( bool )
import FreeC.IR.SrcSpan ( SrcSpan(NoSrcSpan) )
import qualified FreeC.IR.Syntax as IR
import qualified FreeC.LiftedIR.Syntax as LIR
import FreeC.Monad.Converter ( Converter )
import FreeC.Monad.Reporter
( Message(Message), Severity(Error, Internal), reportFatal )
liftFuncArgTypes
:: Maybe Int
-> [IR.VarPat]
-> Converter [LIR.Type]
liftFuncArgTypes = maybe liftNonRecFuncArgTypes liftRecFuncArgTypes
liftNonRecFuncArgTypes :: [IR.VarPat] -> Converter [LIR.Type]
liftNonRecFuncArgTypes = mapM $ \pat ->
let err = reportFatal
$ Message (IR.varPatSrcSpan pat) Internal
$ "Expected variable pattern to have a type annotation."
in liftVarPatType pat >>= maybe err return
liftRecFuncArgTypes :: Int -> [IR.VarPat] -> Converter [LIR.Type]
liftRecFuncArgTypes decIndex args = do
convArgs <- liftNonRecFuncArgTypes args
let (startArgs, decArg : endArgs) = splitAt decIndex convArgs
decArg' <- markOutermostDecreasing decArg
return $ startArgs ++ (decArg' : endArgs)
liftVarPatType :: IR.VarPat -> Converter (Maybe LIR.Type)
liftVarPatType (IR.VarPat _ _ patType strict) = mapM
(bool liftType liftType' strict) patType
liftConArgType :: IR.QName -> IR.Type -> Converter LIR.Type
liftConArgType ident t = markAllDec ident <$> liftType t
liftType :: IR.Type -> Converter LIR.Type
liftType t = LIR.FreeTypeCon NoSrcSpan <$> liftType' t
liftType' :: IR.Type -> Converter LIR.Type
liftType' = flip liftTypeApp' []
liftTypeApp' :: IR.Type -> [IR.Type] -> Converter LIR.Type
liftTypeApp' (IR.TypeCon srcSpan name) ts
= LIR.TypeCon srcSpan name <$> mapM liftType' ts <*> return False
liftTypeApp' (IR.TypeVar srcSpan name) [] = return $ LIR.TypeVar srcSpan name
liftTypeApp' (IR.TypeApp _ l r) ts = liftTypeApp' l (r : ts)
liftTypeApp' (IR.FuncType srcSpan l r) []
= LIR.FuncType srcSpan <$> liftType l <*> liftType r
liftTypeApp' _ (_ : _) = reportFatal
$ Message NoSrcSpan Internal
$ "Only type constructors can be applied!"
markAllDec :: LIR.TypeConName -> LIR.Type -> LIR.Type
markAllDec _ (LIR.TypeVar srcSpan name) = LIR.TypeVar srcSpan name
markAllDec decName (LIR.FuncType srcSpan l r) = LIR.FuncType srcSpan
(markAllDec decName l) (markAllDec decName r)
markAllDec decName (LIR.FreeTypeCon srcSpan t)
= LIR.FreeTypeCon srcSpan $ markAllDec decName t
markAllDec decName (LIR.TypeCon srcSpan name ts dec) = LIR.TypeCon srcSpan name
(markAllDec decName `fmap` ts) (name == decName || dec)
markOutermostDecreasing :: LIR.Type -> Converter LIR.Type
markOutermostDecreasing (LIR.TypeCon srcSpan name ts _)
= return $ LIR.TypeCon srcSpan name ts True
markOutermostDecreasing (LIR.FreeTypeCon srcSpan t)
= LIR.FreeTypeCon srcSpan <$> markOutermostDecreasing t
markOutermostDecreasing _ = reportFatal
$ Message NoSrcSpan Error
$ "Outermost type of decreasing argument is not a "
++ "type constructor application."