packages feed

swarm-0.6.0.0: src/swarm-doc/Swarm/Doc/Command.hs

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Auto-generation of command attributes matrix.
module Swarm.Doc.Command where

import Data.Aeson (ToJSON)
import Data.List.Extra (enumerate)
import Data.List.NonEmpty qualified as NE
import Data.Set (Set)
import Data.Set qualified as Set
import GHC.Generics (Generic)
import Servant.Docs qualified as SD
import Swarm.Doc.Util
import Swarm.Language.Pretty (unchainFun)
import Swarm.Language.Syntax
import Swarm.Language.Syntax.CommandMetadata
import Swarm.Language.Typecheck (inferConst)
import Swarm.Language.Types

data DerivedAttrs = DerivedAttrs
  { hasActorTarget :: Bool
  , pureComputation :: Bool
  , modifiesEnvironment :: Bool
  , modifiesRobot :: Bool
  , movesRobot :: Bool
  , returnsValue :: Bool
  , outputType :: String
  }
  deriving (Generic, ToJSON)

data CommandEntry = CommandEntry
  { cmd :: Const
  , effects :: Set CommandEffect
  , argTypes :: NE.NonEmpty Type
  , derivedAttrs :: DerivedAttrs
  }
  deriving (Generic, ToJSON)

newtype CommandCatalog = CommandCatalog
  { entries :: [CommandEntry]
  }
  deriving (Generic, ToJSON)

instance SD.ToSample CommandCatalog where
  toSamples _ = SD.noSamples

-- | Uses explicit effects documentation as well as
-- type signature information to compute various flags
mkEntry :: Const -> CommandEntry
mkEntry c =
  CommandEntry c cmdEffects rawArgs $
    DerivedAttrs
      { hasActorTarget = operatesOnActor inputArgs
      , pureComputation = Set.null cmdEffects
      , modifiesEnvironment = Mutation EntityChange `Set.member` cmdEffects
      , modifiesRobot = not . Set.disjoint cmdEffects . Set.fromList $ map (Mutation . RobotChange) enumerate
      , movesRobot = Mutation (RobotChange PositionChange) `Set.member` cmdEffects
      , returnsValue = theOutputType /= TyCmd TyUnit
      , outputType = show theOutputType
      }
 where
  cmdInfo = constInfo c
  cmdEffects = effectInfo $ constDoc cmdInfo

  getArgs ((Forall _ t)) = unchainFun t

  rawArgs = getArgs $ inferConst c

  inputArgs = NE.init rawArgs
  theOutputType = NE.last rawArgs

  operatesOnActor = elem TyActor

getCatalog :: CommandCatalog
getCatalog = CommandCatalog $ map mkEntry commands