hoop-0.3.0.0: src/Language/MSH/StateDecl.hs
--------------------------------------------------------------------------------
module Language.MSH.StateDecl (
module Language.MSH.MethodTable,
StateMod(..),
StateObjCtr(..),
StateMemberDecl(..),
StateDecl(..),
isBaseClass,
isAbstractClass,
isFinalClass,
ctrsForClass,
declByParent
) where
--------------------------------------------------------------------------------
import Prelude hiding ((<>))
import qualified Data.Map as M
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import qualified Language.Haskell.TH.Ppr as Ppr
import Language.MSH.MethodTable
import Language.MSH.Pretty
--------------------------------------------------------------------------------
-- | Enumerates class modifiers.
data StateMod = Abstract | Final deriving Show
-- | Enumerates object constructor types.
data StateObjCtr = DataCtr | StartCtr | MiddleCtr | EndCtr deriving Show
-- | Used to represent fields in state classes.
data StateMemberDecl = StateDataDecl {
-- | The name of the field.
stateDataName :: String,
-- | The (optional) expression which specifies the default value.
stateDataExpr :: Maybe String,
-- | The type of the field.
stateDataType :: String
} deriving Show
instance Pretty StateMemberDecl where
pp (StateDataDecl{..}) =
text stateDataName <+>
optionally stateDataExpr (\e -> text "=" <+> text e) <+>
text "::" <+>
text stateDataType
-- | Represents a state class definition.
data StateDecl = StateDecl {
-- | The class modifier, if any.
stateMod :: Maybe StateMod,
-- | The name of the class.
stateName :: String,
-- | The list of type parameters.
stateParams :: [String],
-- | The name of the parent class, if any.
stateParentN :: Maybe String,
-- | The type argument for the parent class.
stateParentPs :: [String],
-- | The parent class, once resolved.
stateParent :: Maybe StateDecl,
-- | The field declarations.
stateData :: [StateMemberDecl],
-- | The method signatures and definitions.
stateBody :: [Dec],
-- | The method table for this class, once computed.
stateMethods :: MethodTable
}
instance Pretty StateDecl where
pp (StateDecl{..}) =
text "CLASS" <+> parens (text stateName) <> colon $$ nest 4 (vcat [
optionally stateParentN (\p -> text "PARENT:" <+> text p <+> hsep (map text stateParentPs)),
optionally stateParent (\_ -> text "PARENT RESOLVED"),
optionally stateMod (\m -> text "MODIFIER:" <+> text (show m)),
text "PARAMS:" <+> hsep (map text stateParams),
text "DATA" <> colon $$ nest 4 (vcat (map pp stateData)),
text "BODY (TH AST)" <> colon $$ nest 4 (vcat (map (text . Ppr.pprint) stateBody)),
text "METHOD TABLE" <> colon $$ nest 4 (ppMethodTable stateMethods)
])
instance Show StateDecl where
show = render . pp
--------------------------------------------------------------------------------
-- | `isBaseClass` @class determines whether @class is a base class.
isBaseClass :: StateDecl -> Bool
isBaseClass (StateDecl { stateParentN = Nothing } ) = True
isBaseClass _ = False
-- | `isAbstractClass` @class determines whether @class is abstract.
isAbstractClass :: StateDecl -> Bool
isAbstractClass (StateDecl { stateMod = Just Abstract }) = True
isAbstractClass _ = False
-- | `isFinalClass` @class determines whether @class is final.
isFinalClass :: StateDecl -> Bool
isFinalClass (StateDecl { stateMod = Just Final }) = True
isFinalClass _ = False
-- | `declByParent' @name @class determines whether a method named @name
-- was declared by a parent of @class.
declByParent :: Name -> StateDecl -> Bool
declByParent _ (StateDecl { stateParent = Nothing }) = False
declByParent n (StateDecl { stateParent = (Just p) }) =
M.member (nameBase n) (methods $ stateMethods p) || declByParent n p
-- | `ctrsForClass` @dec returns a list of object states for the state class
-- described by @dec.
ctrsForClass :: StateDecl -> [StateObjCtr]
ctrsForClass (StateDecl { stateParentN = p, stateMod = m }) = case p of
Nothing -> case m of
Nothing -> [DataCtr, StartCtr]
(Just Abstract) -> [StartCtr]
(Just Final) -> [DataCtr]
(Just _) -> case m of
Nothing -> [DataCtr, StartCtr, MiddleCtr, EndCtr]
(Just Abstract) -> [StartCtr, MiddleCtr]
(Just Final) -> [DataCtr, EndCtr]