packages feed

spectacle-1.0.0: src/Language/Spectacle/Model/ModelAction.hs

-- |
--
-- @since 1.0.0
module Language.Spectacle.Model.ModelAction
  ( -- * Model Action
    ModelAction (ModelAction),
    modelActionName,
    getModelAction,

    -- ** Construction
    fromActionSpec,

    -- ** Deconstruction
    runModelAction,
  )
where

import Control.Monad.Except (MonadError, throwError)
import Data.Hashable (Hashable)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import Lens.Micro ((^.))

import Data.Type.Rec (HasDict)
import Data.World (World, worldValues)
import Language.Spectacle.AST (Action)
import Language.Spectacle.AST.Action (runExceptionalAction)
import Language.Spectacle.Exception.RuntimeException (RuntimeException)
import Language.Spectacle.Model.ModelError
  ( ModelError (RuntimeError),
  )

-- ---------------------------------------------------------------------------------------------------------------------

data ModelAction ctx = ModelAction
  { modelActionName :: String
  , getModelAction :: World ctx -> Either RuntimeException (Set (World ctx))
  }

runModelAction :: MonadError (ModelError ctx) m => World ctx -> ModelAction ctx -> m (Set (World ctx))
runModelAction world action =
  case getModelAction action world of
    Left err -> throwError (RuntimeError err)
    Right worlds -> pure worlds

fromActionSpec :: HasDict Hashable ctx => Map String (Action ctx Bool) -> [ModelAction ctx]
fromActionSpec =
  Map.foldMapWithKey \name action ->
    let runner world = runExceptionalAction (world ^. worldValues) action
     in [ModelAction name runner]