module FreeC.Backend.Agda.Converter.TypeDecl ( convertTypeDecls ) where
import Data.List.Extra ( snoc )
import qualified FreeC.Backend.Agda.Base as Agda.Base
import FreeC.Backend.Agda.Converter.Arg ( convertTypeVarDecl )
import FreeC.Backend.Agda.Converter.Free
import FreeC.Backend.Agda.Converter.Size
import FreeC.Backend.Agda.Converter.Type ( convertLiftedConType )
import qualified FreeC.Backend.Agda.Syntax as Agda
import FreeC.Environment.Fresh ( freshAgdaVar )
import FreeC.Environment.LookupOrFail
import FreeC.IR.DependencyGraph
import FreeC.IR.SrcSpan ( SrcSpan(NoSrcSpan) )
import qualified FreeC.IR.Syntax as IR
import FreeC.LiftedIR.Converter.Type ( liftConArgType, liftType' )
import FreeC.Monad.Converter ( Converter, localEnv )
import FreeC.Monad.Reporter
( Message(Message), Severity(Error), reportFatal )
convertTypeDecls
:: DependencyComponent IR.TypeDecl -> Converter [Agda.Declaration]
convertTypeDecls comp = case comp of
NonRecursive decl -> convertTypeDecl decl False
Recursive [decl] -> convertTypeDecl decl True
Recursive ds -> reportFatal
$ Message (IR.typeDeclSrcSpan $ head ds) Error
$ "Mutual recursive data types are not supported by the Agda back end "
++ "at the moment."
convertTypeDecl :: IR.TypeDecl -> Bool -> Converter [Agda.Declaration]
convertTypeDecl (IR.TypeSynDecl srcSpan _ _ _) _ = reportFatal
$ Message srcSpan Error
$ "Type synonyms are not supported by the Agda back end at the moment."
convertTypeDecl (IR.DataDecl _ ident tVars constrs) isRec = (:)
<$> convertDataDecl ident tVars constrs isRec
<*> mapM generateSmartConDecl constrs
convertDataDecl :: IR.DeclIdent
-> [IR.TypeVarDecl]
-> [IR.ConDecl]
-> Bool
-> Converter Agda.Declaration
convertDataDecl ident@(IR.DeclIdent srcSpan name) typeVars constrs isRec
= localEnv
$ freeDataDecl <$> lookupUnQualAgdaIdentOrFail srcSpan IR.TypeScope name
<*> mapM convertTypeVarDecl typeVars
<*> pure universe
<*> convertConDecls ident typeVars constrs
where
universe
= if isRec then Agda.hiddenArg_ size `Agda.fun` Agda.set else Agda.set
convertConDecls
:: IR.DeclIdent
-> [IR.TypeVarDecl]
-> [IR.ConDecl]
-> Converter [Agda.Declaration]
convertConDecls (IR.DeclIdent srcSpan ident) typeVars
= mapM $ convertConDecl ident constructedType
where
constructedType = IR.typeApp NoSrcSpan (IR.TypeCon srcSpan ident)
$ map IR.typeVarDeclToType typeVars
convertConDecl
:: IR.QName -> IR.Type -> IR.ConDecl -> Converter Agda.Declaration
convertConDecl ident retType (IR.ConDecl _ (IR.DeclIdent srcSpan name) argTypes)
= do
argTypes' <- mapM (liftConArgType ident) argTypes
retType' <- liftType' retType
Agda.funcSig <$> lookupUnQualAgdaIdentOrFail srcSpan IR.ValueScope name
<*> convertLiftedConType argTypes' retType'
generateSmartConDecl :: IR.ConDecl -> Converter Agda.Declaration
generateSmartConDecl (IR.ConDecl _ (IR.DeclIdent srcSpan name) argTypes) = do
smartName <- lookupUnQualAgdaSmartIdentOrFail srcSpan name
patternDecl smartName (replicate (length argTypes) "x") $ \vars -> do
normalName <- Agda.IdentP <$> lookupAgdaValIdentOrFail srcSpan name
let pureVal = foldl Agda.appP normalName vars
return (Agda.IdentP (Agda.qname' Agda.Base.pure) `Agda.appP` pureVal)
freeDataDecl :: Agda.Name
-> [Agda.Name]
-> Agda.Expr
-> [Agda.Declaration]
-> Agda.Declaration
freeDataDecl dataName typeNames = Agda.dataDecl dataName
(freeArgBinder `snoc` Agda.binding typeNames Agda.set)
patternDecl
:: Agda.Name
-> [String]
-> ([Agda.Pattern] -> Converter Agda.Pattern)
-> Converter Agda.Declaration
patternDecl name vars k = localEnv $ do
names <- mapM freshAgdaVar vars
let decls = map (Agda.Arg Agda.defaultArgInfo . Agda.unqualify) names
varPatterns = map Agda.IdentP names
Agda.patternSyn name decls <$> k varPatterns