module FreeC.Backend.Agda.Converter.Type
( convertLiftedFuncType
, convertLiftedConType
) where
import Prelude hiding ( pi )
import Data.Bool ( bool )
import FreeC.Backend.Agda.Converter.Free
( addPartial, applyFreeArgs, free )
import FreeC.Backend.Agda.Converter.Size ( up )
import qualified FreeC.Backend.Agda.Syntax as Agda
import FreeC.Environment.Fresh ( freshAgdaVar )
import FreeC.Environment.LookupOrFail ( lookupAgdaIdentOrFail )
import FreeC.IR.SrcSpan ( SrcSpan(NoSrcSpan) )
import qualified FreeC.IR.Syntax as IR
import qualified FreeC.LiftedIR.Syntax as LIR
import FreeC.LiftedIR.Syntax.Type ( decreasing )
import FreeC.Monad.Converter ( Converter, localEnv )
convertLiftedFuncType :: Bool -> [LIR.Type] -> LIR.Type -> Converter Agda.Expr
convertLiftedFuncType isPartial argTypes retType = if any decreasing argTypes
then pi "i"
$ \i -> partial <$> convertLiftedType (Just $ Agda.hiddenArg_ i) funcType
else partial <$> convertLiftedType' funcType
where
funcType = LIR.funcType NoSrcSpan argTypes retType
partial = bool id addPartial isPartial
convertLiftedConType :: [LIR.Type] -> LIR.Type -> Converter Agda.Expr
convertLiftedConType argTypes retType = if any decreasing argTypes
then convertLiftedRecConType argTypes retType
else convertLiftedType' $ LIR.funcType NoSrcSpan argTypes retType
convertLiftedRecConType :: [LIR.Type] -> LIR.Type -> Converter Agda.Expr
convertLiftedRecConType argTypes retType = pi "i" $ \i -> do
retType' <- convertLiftedType' retType
foldr Agda.fun (Agda.app retType' $ Agda.hiddenArg_ $ up i)
<$> mapM (convertLiftedType $ Just $ Agda.hiddenArg_ i) argTypes
convertLiftedType :: Maybe Agda.Expr -> LIR.Type -> Converter Agda.Expr
convertLiftedType _ (LIR.TypeVar srcSpan name) = Agda.Ident
<$> lookupAgdaIdentOrFail srcSpan IR.TypeScope (IR.UnQual $ IR.Ident name)
convertLiftedType i (LIR.TypeCon srcSpan name typeArgs dec) = do
typeArgs' <- mapM (convertLiftedType i) typeArgs
constr <- applyFreeArgs <$> lookupAgdaIdentOrFail srcSpan IR.TypeScope name
let type' = foldl Agda.app constr typeArgs'
if dec
then Agda.app type'
<$> maybe (fail "No Size annotation declared!") return i
else return type'
convertLiftedType i (LIR.FuncType _ l r)
= Agda.fun <$> convertLiftedType i l <*> convertLiftedType i r
convertLiftedType i (LIR.FreeTypeCon _ t)
= free <$> convertLiftedType i t
convertLiftedType' :: LIR.Type -> Converter Agda.Expr
convertLiftedType' = convertLiftedType Nothing
pi :: String
-> (Agda.Expr -> Converter Agda.Expr)
-> Converter Agda.Expr
pi name k = localEnv $ do
var <- freshAgdaVar name
Agda.pi [Agda.unqualify var] <$> k (Agda.Ident var)