swarm-0.7.0.0: src/swarm-scenario/Swarm/Game/Scenario/Objective/Validation.hs
{-# LANGUAGE OverloadedStrings #-}
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Validity checking for 'Objective' prerequisites
module Swarm.Game.Scenario.Objective.Validation where
import Control.Lens (view, (^.))
import Control.Monad (forM_, unless)
import Data.Foldable (for_, toList)
import Data.Maybe (fromMaybe, mapMaybe)
import Data.Set qualified as Set
import Data.Text qualified as T
import Swarm.Game.Scenario.Objective
import Swarm.Game.Scenario.Objective.Graph
import Swarm.Util (failT, quote)
import Swarm.Util.Graph
-- | Performs monadic validation before returning
-- the "pure" construction of a wrapper record.
-- This validation entails:
--
-- 1. Ensuring that all goal references utilized in prerequisites
-- actually exist
-- 2. Ensuring that the graph of dependencies is acyclic.
validateObjectives ::
MonadFail m =>
[Objective] ->
m [Objective]
validateObjectives objectives = do
for_ objectives $ \x -> forM_ (x ^. objectivePrerequisite) $ \p ->
let refs = Set.fromList $ toList $ logic p
remaining = Set.difference refs allIds
in unless (null remaining) $
failT
[ "Reference to undefined objective(s)"
, T.intercalate ", " (map quote $ Set.toList remaining) <> "."
, "Defined are:"
, T.intercalate ", " (map quote $ Set.toList allIds)
]
either (fail . T.unpack) return $
failOnCyclicGraph "Prerequisites" (fromMaybe "N/A" . view objectiveId) edges
return objectives
where
edges = makeGraphEdges objectives
allIds = Set.fromList $ mapMaybe (view objectiveId) objectives