{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TemplateHaskellQuotes #-}
{-# LANGUAGE TypeApplications #-}
module Data.Morpheus.Execution.Internal.Declare
( declareType
, tyConArgs
)
where
import Data.Maybe ( maybe )
import Data.Text ( unpack )
import GHC.Generics ( Generic )
import Language.Haskell.TH
import Data.Morpheus.Execution.Internal.Utils
( nameSpaceType
, nameSpaceWith
)
import Data.Morpheus.Types.Internal.AST
( DataField(..)
, DataTypeKind(..)
, DataTypeKind(..)
, TypeRef(..)
, TypeWrapper(..)
, isOutputObject
, isSubscription
, ConsD(..)
, TypeD(..)
, Key
, isOutputObject
)
import Data.Morpheus.Types.Internal.Resolving
( UnSubResolver )
type Arrow = (->)
m_ :: Key
m_ = "m"
declareTypeRef :: Bool -> TypeRef -> Type
declareTypeRef isSub TypeRef { typeConName, typeWrappers, typeArgs } = wrappedT
typeWrappers
where
wrappedT :: [TypeWrapper] -> Type
wrappedT (TypeList : xs) = AppT (ConT ''[]) $ wrappedT xs
wrappedT (TypeMaybe : xs) = AppT (ConT ''Maybe) $ wrappedT xs
wrappedT [] = decType typeArgs
typeName = ConT (mkName $ unpack typeConName)
decType _ | isSub =
AppT typeName (AppT (ConT ''UnSubResolver) (VarT $ mkName $ unpack m_))
decType (Just par) = AppT typeName (VarT $ mkName $ unpack par)
decType _ = typeName
tyConArgs :: DataTypeKind -> [Key]
tyConArgs kindD | isOutputObject kindD || kindD == KindUnion = [m_]
| otherwise = []
declareType :: Bool -> Maybe DataTypeKind -> [Name] -> TypeD -> Dec
declareType namespace kindD derivingList TypeD { tName, tCons, tNamespace } =
DataD [] (genName tName) tVars Nothing (map cons tCons)
$ map derive (''Generic : derivingList)
where
genName = mkName . unpack . nameSpaceType tNamespace
tVars = maybe [] (declareTyVar . tyConArgs) kindD
where declareTyVar = map (PlainTV . mkName . unpack)
defBang = Bang NoSourceUnpackedness NoSourceStrictness
derive className = DerivClause Nothing [ConT className]
cons ConsD { cName, cFields } = RecC (genName cName)
(map declareField cFields)
where
declareField DataField { fieldName, fieldArgsType, fieldType } =
(fName, defBang, fiType)
where
fName | namespace = mkName $ unpack (nameSpaceWith tName fieldName)
| otherwise = mkName (unpack fieldName)
fiType = genFieldT fieldArgsType
where
monadVar = VarT $ mkName $ unpack m_
genFieldT Nothing
| (isOutputObject <$> kindD) == Just True = AppT monadVar result
| otherwise = result
genFieldT (Just argsTypeName) = AppT
(AppT arrowType argType)
(AppT monadVar result)
where
argType = ConT $ mkName (unpack argsTypeName)
arrowType = ConT ''Arrow
result = declareTypeRef (maybe False isSubscription kindD) fieldType