module Language.MSH.CodeGen.Class where
import Control.Applicative ((<$>))
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Language.MSH.StateDecl
import Language.MSH.StateEnv
import Language.MSH.CodeGen.Shared
import Language.MSH.CodeGen.Interop
import Language.MSH.CodeGen.Inheritance
data SCV = SCV {
scvObject :: Name,
scvState :: Name,
scvMonad :: Name
}
genClassContext :: [String] -> Maybe Type -> SCV -> Q Cxt
genClassContext vars Nothing (SCV o s m) = do
let
cn = ConT $ mkName "Object"
fa = appN (VarT o) vars
sa = appN (VarT s) vars
ma = VarT m
return [foldl AppT cn [fa, sa, ma]]
genClassContext vars (Just p) (SCV o s m) = do
return [foldl AppT (ConT pcname) vars]
where
(Name pn _) = parentName p
pcname = mkName $ occString pn ++ "Like"
vars = [VarT o, VarT s, VarT m] ++ parentArgs p
genInvokeDecl :: [String] -> String -> SCV -> Q Dec
genInvokeDecl tyvars c (SCV o s m) = do
o' <- newName "o'"
d' <- newName "d'"
r <- newName "r"
let
name = mkName $ "_" ++ c ++ "_invoke"
cname = mkName $ c ++ "Like"
base = AppT (AppT (ConT (mkName "StateT")) (appN (VarT s) tyvars)) (VarT m)
ctx = [foldl AppT (ConT cname) ([VarT o', VarT d', base] ++ [VarT $ mkName n | n <- tyvars])]
ovs = appN (VarT o) tyvars
ovs' = appN (VarT o') tyvars
sigma = ovs' `arr` (ovs' `arr` AppT base (tuple [VarT r, ovs'])) `arr` ovs `arr` AppT (VarT m) (tuple [VarT r, ovs, ovs'])
ty = ForallT [PlainTV o', PlainTV d', PlainTV r] ctx sigma
return $ SigD name ty
getterName :: String -> String
getterName n = "_get_" ++ n
setterName :: String -> String
setterName n = "_set_" ++ n
fieldType :: Type -> Type -> Name -> Type -> Type
fieldType ovs svs m ft =
foldl AppT (ConT (mkName "Selector")) [PromotedT (mkName "Field"), ovs, svs, (VarT m), ft ]
genModDeclsFor :: SCV -> [String] -> StateMemberDecl -> Q [Dec]
genModDeclsFor (SCV o s m) vars (StateDataDecl field _ typ) = do
let
ft = parseType typ
ovs = appN (VarT o) vars
svs = appN (VarT s) vars
stt = AppT (AppT (ConT (mkName "StateT")) svs) (VarT m)
getterT = ovs `arr` AppT (VarT m) (tuple [ft, ovs])
getter = SigD (mkName (getterName field)) getterT
getterT' = AppT stt ft
getter' = SigD (mkName (getterName field ++ "'")) getterT'
setterT = ovs `arr` ft `arr` AppT (VarT m) (tuple [TupleT 0,ovs])
setter = SigD (mkName (setterName field)) setterT
setterT' = ft `arr` AppT stt (TupleT 0)
setter' = SigD (mkName (setterName field ++ "'")) setterT'
fieldT = fieldType ovs svs m ft
fieldS = SigD (mkName field) fieldT
return [getter,getter',setter,setter',fieldS]
genModsDecls :: SCV -> [String] -> [StateMemberDecl] -> Q [Dec]
genModsDecls scv vars fields = do
decls <- mapM (genModDeclsFor scv vars) fields
return $ concat decls
splitMethodType :: Type -> ([Type], Type)
splitMethodType (ForallT tvs cxt t) = splitMethodType t
splitMethodType (AppT (AppT ArrowT arg) ret) = (arg : args, ret')
where
(args,ret') = splitMethodType ret
splitMethodType rt = ([],rt)
methodType :: Type -> Type -> Name -> [Type] -> Type -> Type
methodType ovs svs m args rt = parameterise args st
where
st = foldl AppT (ConT (mkName "Selector")) [PromotedT (mkName "Method"), ovs, svs, VarT m, rt]
genMethodDecls' :: StateEnv -> Maybe String -> SCV -> [String] -> Name -> Type -> Q [Dec]
genMethodDecls' env mp (SCV o s m) vars name ty = do
let
ovs = appN (VarT o) vars
svs = appN (VarT s) vars
stt = AppT (AppT (ConT (mkName "StateT")) svs) (VarT m)
inty = ovs `arr` wrapMethodType False (\rt -> AppT (VarT m) (tuple [rt,ovs])) ty
internal = SigD (mkName $ "_ecall_" ++ nameBase name) inty
exty = wrapMethodType False (\rt -> AppT stt rt) ty
external = SigD (mkName $ "_icall_" ++ nameBase name) exty
(args,ret) = splitMethodType ty
mty = methodType ovs svs m args ret
method = SigD name mty
ov <- isInherited env mp name
if ov then return []
else return [external, internal, method]
genMethodDecls :: StateEnv -> Maybe String -> SCV -> [String] -> Dec -> Q [Dec]
genMethodDecls env mp scv vars (SigD name ty) =
genMethodDecls' env mp scv vars name ty
genMethodDecls _ _ _ _ _ = return []
genMethodsDecls :: StateEnv -> Maybe String -> SCV -> [String] -> [Dec] -> Q [Dec]
genMethodsDecls env mp scv vars ds = do
decls <- mapM (genMethodDecls env mp scv vars) ds
return $ concat decls
genStateClass :: StateEnv -> [TyVarBndr] -> [Dec] -> StateDecl -> Q Dec
genStateClass env tyvars fs (StateDecl {
stateName = name,
stateParams = vs,
stateParentN = p,
stateData = ds
}) = do
o <- newName "o"
s <- newName "s"
m <- newName "m"
let
fam = FamilyD TypeFam (mkName $ name ++ "St") ([PlainTV o] ) (Just (VarT $ mkName "p"))
scv = SCV o s m
cname = mkName $ name ++ "Like"
vars = [PlainTV o, PlainTV s, PlainTV m] ++ tyvars
deps = [FunDep [o] [s], FunDep [s] [o]]
cxt <- genClassContext vs (parseType <$> p) scv
inv <- genInvokeDecl vs name scv
mds <- genModsDecls scv vs ds
ms <- genMethodsDecls env p scv vs fs
return $ ClassD cxt cname vars deps ([fam,inv] ++ mds ++ ms)