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