packages feed

swarm-0.5.0.0: src/Swarm/Language/Capability.hs

{-# LANGUAGE OverloadedStrings #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Capabilities needed to evaluate and execute programs.  Language
-- constructs or commands require certain capabilities, and in turn
-- capabilities are provided by various devices.  A robot must have an
-- appropriate device equipped in order to make use of each language
-- construct or command.
module Swarm.Language.Capability (
  Capability (..),
  capabilityName,
  constCaps,
) where

import Data.Aeson (FromJSONKey, ToJSONKey)
import Data.Char (toLower)
import Data.Data (Data)
import Data.Hashable (Hashable)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Yaml
import GHC.Generics (Generic)
import Swarm.Language.Syntax
import Swarm.Util (failT)
import Text.Read (readMaybe)
import Witch (from)
import Prelude hiding (lookup)

-- | Various capabilities which robots can have.
data Capability
  = -- | Be powered, i.e. execute anything at all
    CPower
  | -- | Execute the 'Move' command
    CMove
  | -- | Execute the 'Backup' command
    CBackup
  | -- | Execute the 'Path' command
    CPath
  | -- | Execute the 'Push' command
    CPush
  | -- | Execute the 'Stride' command
    CMovemultiple
  | -- | Execute the 'Move' command for a heavy robot
    CMoveheavy
  | -- | Execute the 'Turn' command
    --
    -- NOTE: using cardinal directions is separate 'COrient' capability
    CTurn
  | -- | Execute the 'Selfdestruct' command
    CSelfdestruct
  | -- | Execute the 'Grab' command
    CGrab
  | -- | Execute the 'Harvest' command
    CHarvest
  | -- | Execute the 'Ignite' command
    CIgnite
  | -- | Execute the 'Place' command
    CPlace
  | -- | Execute the 'Ping' command
    CPing
  | -- | Execute the 'Give' command
    CGive
  | -- | Execute the 'Equip' command
    CEquip
  | -- | Execute the 'Unequip' command
    CUnequip
  | -- | Execute the 'Make' command
    CMake
  | -- | Execute the 'Count' command
    CCount
  | -- | Execute the 'Scout' command. Reconnaissance along a line in a direction.
    CRecondir
  | -- | Execute the 'Build' command
    CBuild
  | -- | Execute the 'Salvage' command
    CSalvage
  | -- | Execute the 'Drill' command
    CDrill
  | -- | Execute the 'Waypoint' command
    CWaypoint
  | -- | Execute the 'Whereami' command
    CSenseloc
  | -- | Execute the 'Blocked' command
    CSensefront
  | -- | Execute the 'Ishere' and 'Isempty' commands
    CSensehere
  | -- | Execute the 'Detect' command
    CDetectloc
  | -- | Execute the 'Resonate' and 'Density' commands
    CDetectcount
  | -- | Execute the 'Sniff' command
    CDetectdistance
  | -- | Execute the 'Chirp' command
    CDetectdirection
  | -- | Execute the 'Watch' command
    CWakeself
  | -- | Execute the 'Scan' command
    CScan
  | -- | Execute the 'Random' command
    CRandom
  | -- | Execute the 'Appear' command
    CAppear
  | -- | Execute the 'Create' command
    CCreate
  | -- | Execute the 'Listen' command and passively log messages if also has 'CLog'
    CListen
  | -- | Execute the 'Log' command
    CLog
  | -- | Format values as text
    CFormat
  | -- | Split text into two pieces
    CConcat
  | -- | Join two text values into one
    CSplit
  | -- | Count the characters in a text value
    CCharcount
  | -- | Convert between characters/text and Unicode values
    CCode
  | -- | Don't drown in liquid
    CFloat
  | -- | Evaluate conditional expressions
    CCond
  | -- | Negate boolean value
    CNegation
  | -- | Evaluate comparison operations
    CCompare
  | -- | Use cardinal direction constants.
    COrient
  | -- | Evaluate arithmetic operations
    CArith
  | -- | Store and look up definitions in an environment
    CEnv
  | -- | Interpret lambda abstractions
    CLambda
  | -- | Enable recursive definitions
    CRecursion
  | -- | Execute the 'Reprogram' command
    CReprogram
  | -- | Execute the `meet` and `meetAll` commands.
    CMeet
  | -- | Capability to introspect and see its own name
    CWhoami
  | -- | Capability to set its own name
    CSetname
  | -- | Capability to move unrestricted to any place
    CTeleport
  | -- | Capability to run commands atomically
    CAtomic
  | -- | Capability to execute swap (grab and place atomically at the same time).
    CSwap
  | -- | Capability to obtain absolute time, namely via the `time` command.
    CTimeabs
  | -- | Capability to utilize relative passage of time, namely via the `wait` command.
    --   This is strictly weaker than "CTimeAbs".
    CTimerel
  | -- | Capability to execute `try`.
    CTry
  | -- | Capability for working with sum types.
    CSum
  | -- | Capability for working with product types.
    CProd
  | -- | Capability for working with record types.
    CRecord
  | -- | Debug capability.
    CDebug
  | -- | Capability to handle keyboard input.
    CHandleinput
  | -- | Capability to make other robots halt.
    CHalt
  | -- | God-like capabilities.  For e.g. commands intended only for
    --   checking challenge mode win conditions, and not for use by
    --   players.
    CGod
  deriving (Eq, Ord, Show, Read, Enum, Bounded, Generic, Hashable, Data, FromJSONKey, ToJSONKey)

capabilityName :: Capability -> Text
capabilityName = from @String . map toLower . drop 1 . show

instance ToJSON Capability where
  toJSON = String . capabilityName

instance FromJSON Capability where
  parseJSON = withText "Capability" tryRead
   where
    tryRead :: Text -> Parser Capability
    tryRead t = case readMaybe . from . T.cons 'C' . T.toTitle $ t of
      Just c -> return c
      Nothing -> failT ["Unknown capability", t]

-- | Capabilities needed to evaluate or execute a constant.
constCaps :: Const -> Maybe Capability
constCaps = \case
  -- ----------------------------------------------------------------
  -- Some built-in constants that don't require any special capability.
  Noop -> Nothing
  AppF -> Nothing
  Force -> Nothing
  Return -> Nothing
  Parent -> Nothing
  Base -> Nothing
  Setname -> Nothing
  Undefined -> Nothing
  Fail -> Nothing
  Has -> Nothing
  Equipped -> Nothing
  -- speaking is natural to robots (unlike listening)
  Say -> Nothing
  -- TODO: #495
  --   the require command will be inlined once the Issue is fixed
  --   so the capabilities of the run commands will be checked instead
  Run -> Nothing
  -- ----------------------------------------------------------------
  -- Some straightforward ones.
  Listen -> Just CListen
  Log -> Just CLog
  Selfdestruct -> Just CSelfdestruct
  Move -> Just CMove
  Backup -> Just CBackup
  Path -> Just CPath
  Push -> Just CPush
  Stride -> Just CMovemultiple
  Turn -> Just CTurn
  Grab -> Just CGrab
  Harvest -> Just CHarvest
  Ignite -> Just CIgnite
  Place -> Just CPlace
  Ping -> Just CPing
  Give -> Just CGive
  Equip -> Just CEquip
  Unequip -> Just CUnequip
  Make -> Just CMake
  Count -> Just CCount
  If -> Just CCond
  Blocked -> Just CSensefront
  Scan -> Just CScan
  Ishere -> Just CSensehere
  Isempty -> Just CSensehere
  Upload -> Just CScan
  Build -> Just CBuild
  Salvage -> Just CSalvage
  Reprogram -> Just CReprogram
  Meet -> Just CMeet
  MeetAll -> Just CMeet
  Drill -> Just CDrill
  Use -> Nothing -- Recipes alone shall dictate whether things can be "used"
  Neg -> Just CArith
  Add -> Just CArith
  Sub -> Just CArith
  Mul -> Just CArith
  Div -> Just CArith
  Exp -> Just CArith
  Whoami -> Just CWhoami
  Self -> Just CWhoami
  Swap -> Just CSwap
  Atomic -> Just CAtomic
  Instant -> Just CGod
  Time -> Just CTimeabs
  Wait -> Just CTimerel
  Scout -> Just CRecondir
  Whereami -> Just CSenseloc
  Waypoint -> Just CWaypoint
  Detect -> Just CDetectloc
  Resonate -> Just CDetectcount
  Density -> Just CDetectcount
  Sniff -> Just CDetectdistance
  Chirp -> Just CDetectdirection
  Watch -> Just CWakeself
  Heading -> Just COrient
  Key -> Just CHandleinput
  InstallKeyHandler -> Just CHandleinput
  Halt -> Just CHalt
  -- ----------------------------------------------------------------
  -- Text operations
  Format -> Just CFormat
  Concat -> Just CConcat
  Split -> Just CSplit
  Chars -> Just CCharcount
  CharAt -> Just CCode
  ToChar -> Just CCode
  -- ----------------------------------------------------------------
  -- Some God-like abilities.
  As -> Just CGod
  RobotNamed -> Just CGod
  RobotNumbered -> Just CGod
  Create -> Just CGod
  Surveil -> Just CGod
  -- ----------------------------------------------------------------
  -- arithmetic
  Eq -> Just CCompare
  Neq -> Just CCompare
  Lt -> Just CCompare
  Gt -> Just CCompare
  Leq -> Just CCompare
  Geq -> Just CCompare
  -- ----------------------------------------------------------------
  -- boolean logic
  And -> Just CCond
  Or -> Just CCond
  Not -> Just CNegation
  -- ----------------------------------------------------------------
  -- exceptions
  Try -> Just CTry
  -- ----------------------------------------------------------------
  -- type-level arithmetic
  Inl -> Just CSum
  Inr -> Just CSum
  Case -> Just CSum
  Fst -> Just CProd
  Snd -> Just CProd
  -- TODO: #563 pair syntax (1,2,3...) should require CProd too

  -- ----------------------------------------------------------------
  -- Some additional straightforward ones, which however currently
  -- cannot be used in classic mode since there is no craftable item
  -- which conveys their capability. TODO: #26
  Teleport -> Just CTeleport -- Some space-time machine like Tardis?
  Appear -> Just CAppear -- paint?
  Random -> Just CRandom -- randomness device (with bitcoins)?
  -- ----------------------------------------------------------------
  -- Some more constants which *ought* to have their own capability but
  -- currently don't.
  View -> Nothing -- TODO: #17 should require equipping an antenna
  Knows -> Nothing