module Language.MSH.CodeGen.PrimaryInstance (
genPrimaryInstance,
genIdentityInstance,
genParentalInstance
) where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Language.MSH.StateEnv
import Language.MSH.StateDecl
import Language.MSH.CodeGen.Shared (renameParent)
import Language.MSH.CodeGen.SharedInstance
import Language.MSH.CodeGen.Interop (parseType)
getBaseMonad :: Maybe String -> Type
getBaseMonad Nothing = ConT $ mkName "Identity"
getBaseMonad (Just p) = renameParent (\n -> n ++ "M") $ parseType p
genPrimaryInstance :: StateEnv -> Dec -> [Dec] -> StateDecl -> Q Dec
genPrimaryInstance env cls decs decl@(StateDecl {
stateName = name,
stateParams = vars,
stateData = ds,
stateParentN = mp,
stateMethods = methods
}) = do
let
cxt = []
cn = mkName $ name ++ "Like"
on = mkName name
sn = mkName $ name ++ "State"
bt = getBaseMonad mp
ty = foldl AppT (AppT (AppT (AppT (ConT cn) (ConT on)) (ConT sn)) bt) (map (VarT . mkName) vars)
fam = TySynInstD (mkName $ name ++ "St") $ TySynEqn [ConT on] (ConT sn)
invk <- genInvokeDef name
mods <- genFields decl PrimaryInst
ms <- genMethods PrimaryInst decl decl methods name
return $ InstanceD cxt ty ([fam,invk] ++ mods ++ ms)
genIdentityInstance :: StateEnv -> Dec -> [Dec] -> StateDecl -> Q Dec
genIdentityInstance env cls decs decl@(StateDecl {
stateName = name,
stateParams = vars,
stateData = ds,
stateParentN = mp,
stateMethods = methods
}) = do
let
cxt = []
cn = mkName $ name ++ "Like"
on = mkName name
sn = mkName $ name ++ "State"
bt = ConT $ mkName "Identity"
ty = foldl AppT (AppT (AppT (AppT (ConT cn) (ConT on)) (ConT sn)) bt) (map (VarT . mkName) vars)
fam = TySynInstD (mkName $ name ++ "St") $ TySynEqn [ConT on] (ConT sn)
invk <- genInvokeDef name
fs <- genFields decl IdentityInst
ms <- genMethods IdentityInst decl decl methods name
return $ InstanceD cxt ty ([fam,invk] ++ fs ++ ms)
genParentalInstance :: StateDecl -> StateDecl -> Q [Dec]
genParentalInstance sub parent = do
let
cxt = []
cn = mkName $ (stateName parent) ++ "Like"
on = mkName (stateName sub)
sn = mkName $ (stateName sub) ++ "State"
bt = getBaseMonad (stateParentN sub)
ps = map (VarT . mkName) (stateParams parent)
ty = foldl AppT (ConT cn) ([ConT on, ConT sn, bt] ++ ps)
idty = foldl AppT (ConT cn) ([ConT on, ConT sn, ConT $ mkName "Identity"] ++ ps)
fs <- genFields parent SecondaryInst
ms <- genMethods SecondaryInst parent sub (stateMethods sub) (stateName parent)
ifs <- genFields parent IdentityInst
ims <- genMethods IdentityInst parent sub (stateMethods sub) (stateName parent)
rs <- case stateParent parent of
Nothing -> return []
(Just p) -> genParentalInstance sub p
return $ [InstanceD cxt ty (fs ++ ms)
, InstanceD cxt idty (ifs ++ ims)] ++ rs