module Model
( Class (..)
, Attribute (..)
, StateChart (..)
, State (..)
, Transition (..)
-- , Connector (..)
-- , ConnectorType (..)
, Name
, Id
, Code
, parseModel
) where
import Data.List
import Rhapsody
type Name = String
type Id = String
type Code = String
data Class = Class Name [Attribute] [StateChart] deriving Show
data StateChart = StateChart Name [State] [Transition] deriving Show
data Attribute = Attribute
{ attrName :: Name
, attrType :: String
, attrInit :: Maybe String
} deriving Show
data State = State
{ stateName :: Name
, stateId :: Id
, stateParent :: Maybe Id
, stateDefaultTrans :: Maybe Id
, stateEntryAction :: Maybe Code
, stateExitAction :: Maybe Code
} deriving Show
{-
data Connector = Connector
{ connectorName :: Name
, connectorId :: Id
, connectorParent :: Id
, connectorType :: ConnectorType
} deriving Show
data ConnectorType = Junction | Condition deriving Show
-}
data Transition = Transition
{ transitionName :: Name
, transitionId :: Id
, transitionTimeout :: Maybe Code
, transitionGuard :: Maybe Code
, transitionAction :: Maybe Code
, transitionSource :: Maybe Id
, transitionTarget :: Id
} deriving Show
parseModel :: Record -> [Class]
parseModel file = map parseClass $ containerRecords "Classes" file
parseClass :: Record -> Class
parseClass a = Class (head $ values "_name" a) (map parseAttribute $ containerRecords "Attrs" a) (map parseStateChart $ containerRecords "StateCharts" a)
parseAttribute :: Record -> Attribute
parseAttribute a = Attribute
{ attrName = value "_name" a
, attrType = value "_name" $ head $ records "_typeOf" a
, attrInit = case containerRecords "ValueSpecifications" a of
[] -> Nothing
[a] -> Just $ value "_value" a
_ -> error "too many value specifications"
}
parseStateChart :: Record -> StateChart
parseStateChart a = if not $ null $ containerRecords "Connectors" a then error "connectors not supported" else StateChart
(value "_name" a)
(map parseState $ containerRecords "States" a)
(map parseTransition $ containerRecords "Transitions" a)
parseState :: Record -> State
parseState a = if values "_stateType" a == ["And"] then error $ "and state not supported: " ++ value "_name" a else State
{ stateName = value "_name" a
, stateId = ident "_id" a
, stateParent = maybeList $ ident "_parent" a
, stateDefaultTrans = maybeList $ ident "_defaultTrans" a
, stateEntryAction = maybeList $ body "_entryAction" a
, stateExitAction = maybeList $ body "_exitAction" a
}
{-
parseConnector :: Record -> Connector
parseConnector a = Connector
{ connectorName = value "_name" a
, connectorId = ident "_id" a
, connectorParent = ident "_parent" a
, connectorType = case value "_connectorType" a of
"Junction" -> Junction
"Condition" -> Condition
--"Fork" -> Fork
--"Join" -> Join
a -> error $ "unknown connector type: " ++ a
}
-}
parseTransition :: Record -> Transition
parseTransition a = Transition
{ transitionName = value "_name" a
, transitionId = ident "_id" a
, transitionTimeout = timeout
, transitionGuard = maybeList $ if guard == "else" then error "else guards not supported" else guard
, transitionAction = maybeList $ body "_itsAction" label
, transitionSource = maybeList $ ident "_itsSource" a
, transitionTarget = ident "_itsTarget" a
}
where
label = head $ records "_itsLabel" a
timeout = case body "_itsTrigger" label of
a | isPrefixOf "tm(" a -> Just $ drop 3 $ init a
| null a -> Nothing
| otherwise -> error $ "not supported non tm() events: " ++ a
guard = body "_itsGuard" label
maybeList :: [a] -> Maybe [a]
maybeList a = if null a then Nothing else Just a