-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | 2D resource gathering game with programmable robots -- -- Swarm is a 2D programming and resource gathering game. Program your -- robots to explore the world and collect resources, which in turn -- allows you to build upgraded robots that can run more interesting and -- complex programs. See the README for more information and instructions -- on how to play or contribute! @package swarm @version 0.4 -- | A carrier for Accum effects. This carrier performs its append -- operations strictly and thus avoids the space leaks inherent in lazy -- writer monads. These appends are left-associative; as such, -- [] is a poor choice of monoid for computations that entail -- many calls to tell. The Seq or DList monoids -- may be a superior choice. module Control.Carrier.Accum.FixedStrict -- | Run an Accum effect with a Monoidal log, applying a -- continuation to the final log and result. -- --
--   runAccum w0 (pure a) = pure (w0, a)
--   
-- --
--   runAccum w0 (add w) = pure (w0 <> w, ())
--   
-- --
--   runAccum w0 (add w >> look) = pure (w0 <> w, w0 <> w)
--   
runAccum :: w -> AccumC w m a -> m (w, a) -- | Run a Accum effect (typically with a Monoidal log), -- producing the final log and discarding the result value. -- --
--   execAccum w = fmap fst . runAccum w
--   
execAccum :: Functor m => w -> AccumC w m a -> m w -- | Run a Accum effect (typically with a Monoidal log), -- producing the result value and discarding the final log. -- --
--   evalAccum w = fmap snd . runAccum w
--   
evalAccum :: Functor m => w -> AccumC w m a -> m a newtype AccumC w m a AccumC :: (w -> m (w, a)) -> AccumC w m a instance GHC.Base.Monoid w => Control.Monad.Trans.Class.MonadTrans (Control.Carrier.Accum.FixedStrict.AccumC w) instance GHC.Base.Functor m => GHC.Base.Functor (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (GHC.Base.Monad m, GHC.Base.Monoid w) => GHC.Base.Applicative (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (GHC.Base.Alternative m, GHC.Base.Monad m, GHC.Base.Monoid w) => GHC.Base.Alternative (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (GHC.Base.Monad m, GHC.Base.Monoid w) => GHC.Base.Monad (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (GHC.Base.MonadPlus m, GHC.Base.Monoid w) => GHC.Base.MonadPlus (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (Control.Monad.Fail.MonadFail m, GHC.Base.Monoid w) => Control.Monad.Fail.MonadFail (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (Control.Monad.Fix.MonadFix m, GHC.Base.Monoid w) => Control.Monad.Fix.MonadFix (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (Control.Monad.IO.Class.MonadIO m, GHC.Base.Monoid w) => Control.Monad.IO.Class.MonadIO (Control.Carrier.Accum.FixedStrict.AccumC w m) instance (Control.Algebra.Algebra sig m, GHC.Base.Monoid w) => Control.Algebra.Algebra (Control.Effect.Accum.Internal.Accum w Control.Effect.Sum.:+: sig) (Control.Carrier.Accum.FixedStrict.AccumC w m) -- | Simplification logic for boolean expressions that is not provided in -- the boolexpr package. module Data.BoolExpr.Simplify cannotBeTrue :: Ord a => BoolExpr a -> Bool replace :: Ord a => Map a Bool -> BoolExpr a -> BoolExpr a -- | Constants used throughout the UI and game module Swarm.Constant swarmRepoUrl :: Text wikiUrl :: Text wikiCheatSheet :: Text -- | A model for defining boolean expressions for Objective prerequisites. -- -- This model is intended to be user-facing in the .yaml files, and is -- distinct from that in BoolExpr. module Swarm.Game.Scenario.Objective.Logic type ObjectiveLabel = Text -- | In contrast with the BoolExpr type, And and Or -- can have one or more children instead of exactly two. data Prerequisite a And :: NonEmpty (Prerequisite a) -> Prerequisite a Or :: NonEmpty (Prerequisite a) -> Prerequisite a Not :: Prerequisite a -> Prerequisite a Id :: a -> Prerequisite a prerequisiteOptions :: Options toBoolExpr :: Prerequisite a -> BoolExpr a instance Data.Foldable.Foldable Swarm.Game.Scenario.Objective.Logic.Prerequisite instance GHC.Base.Functor Swarm.Game.Scenario.Objective.Logic.Prerequisite instance GHC.Generics.Generic (Swarm.Game.Scenario.Objective.Logic.Prerequisite a) instance GHC.Show.Show a => GHC.Show.Show (Swarm.Game.Scenario.Objective.Logic.Prerequisite a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Swarm.Game.Scenario.Objective.Logic.Prerequisite a) instance Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Scenario.Objective.Logic.Prerequisite Swarm.Game.Scenario.Objective.Logic.ObjectiveLabel) instance Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.Scenario.Objective.Logic.Prerequisite Swarm.Game.Scenario.Objective.Logic.ObjectiveLabel) module Swarm.Game.Scenario.Style data StyleFlag Standout :: StyleFlag Italic :: StyleFlag Strikethrough :: StyleFlag Underline :: StyleFlag ReverseVideo :: StyleFlag Blink :: StyleFlag Dim :: StyleFlag Bold :: StyleFlag styleFlagJsonOptions :: Options newtype HexColor HexColor :: Text -> HexColor data CustomAttr CustomAttr :: String -> Maybe HexColor -> Maybe HexColor -> Maybe (Set StyleFlag) -> CustomAttr [name] :: CustomAttr -> String [fg] :: CustomAttr -> Maybe HexColor [bg] :: CustomAttr -> Maybe HexColor [style] :: CustomAttr -> Maybe (Set StyleFlag) instance GHC.Generics.Generic Swarm.Game.Scenario.Style.StyleFlag instance GHC.Show.Show Swarm.Game.Scenario.Style.StyleFlag instance GHC.Classes.Ord Swarm.Game.Scenario.Style.StyleFlag instance GHC.Classes.Eq Swarm.Game.Scenario.Style.StyleFlag instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Style.HexColor instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Style.HexColor instance GHC.Generics.Generic Swarm.Game.Scenario.Style.HexColor instance GHC.Show.Show Swarm.Game.Scenario.Style.HexColor instance GHC.Classes.Eq Swarm.Game.Scenario.Style.HexColor instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Style.CustomAttr instance GHC.Generics.Generic Swarm.Game.Scenario.Style.CustomAttr instance GHC.Show.Show Swarm.Game.Scenario.Style.CustomAttr instance GHC.Classes.Eq Swarm.Game.Scenario.Style.CustomAttr instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Style.CustomAttr instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Style.StyleFlag instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Style.StyleFlag -- | Generic contexts (mappings from variables to other things, such as -- types, values, or capability sets) used throughout the codebase. module Swarm.Language.Context -- | We use Text values to represent variables. type Var = Text -- | A context is a mapping from variable names to things. newtype Ctx t Ctx :: Map Var t -> Ctx t [unCtx] :: Ctx t -> Map Var t -- | The empty context. empty :: Ctx t -- | A singleton context. singleton :: Var -> t -> Ctx t -- | Look up a variable in a context. lookup :: Var -> Ctx t -> Maybe t -- | Delete a variable from a context. delete :: Var -> Ctx t -> Ctx t -- | Get the list of key-value associations from a context. assocs :: Ctx t -> [(Var, t)] -- | Add a key-value binding to a context (overwriting the old one if the -- key is already present). addBinding :: Var -> t -> Ctx t -> Ctx t -- | Right-biased union of contexts. union :: Ctx t -> Ctx t -> Ctx t -- | Locally extend the context with an additional binding. withBinding :: MonadReader (Ctx t) m => Var -> t -> m a -> m a -- | Locally extend the context with an additional context of bindings. withBindings :: MonadReader (Ctx t) m => Ctx t -> m a -> m a instance Data.Aeson.Types.ToJSON.ToJSON t => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Context.Ctx t) instance Data.Aeson.Types.FromJSON.FromJSON t => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Context.Ctx t) instance GHC.Generics.Generic (Swarm.Language.Context.Ctx t) instance Data.Data.Data t => Data.Data.Data (Swarm.Language.Context.Ctx t) instance Data.Traversable.Traversable Swarm.Language.Context.Ctx instance Data.Foldable.Foldable Swarm.Language.Context.Ctx instance GHC.Base.Functor Swarm.Language.Context.Ctx instance GHC.Show.Show t => GHC.Show.Show (Swarm.Language.Context.Ctx t) instance GHC.Classes.Eq t => GHC.Classes.Eq (Swarm.Language.Context.Ctx t) instance GHC.Base.Semigroup (Swarm.Language.Context.Ctx t) instance GHC.Base.Monoid (Swarm.Language.Context.Ctx t) instance Control.Lens.Empty.AsEmpty (Swarm.Language.Context.Ctx t) -- | Types for the Swarm programming language and related utilities. module Swarm.Language.Types -- | Base types. data BaseTy -- | The void type, with no inhabitants. BVoid :: BaseTy -- | The unit type, with a single inhabitant. BUnit :: BaseTy -- | Signed, arbitrary-size integers. BInt :: BaseTy -- | Unicode strings. BText :: BaseTy -- | Directions. BDir :: BaseTy -- | Booleans. BBool :: BaseTy -- | Actors, i.e. anything that can do stuff. Internally, these are -- all just "robots", but we give them a more generic in-game name -- because they could represent other things like aliens, animals, seeds, -- ... BActor :: BaseTy -- | Keys, i.e. things that can be pressed on the keyboard BKey :: BaseTy -- | We use Text values to represent variables. type Var = Text -- | A "structure functor" encoding the shape of type expressions. Actual -- types are then represented by taking a fixed point of this functor. We -- represent types in this way, via a "two-level type", so that we can -- work with the unification-fd package (see -- https://byorgey.wordpress.com/2021/09/08/implementing-hindley-milner-with-the-unification-fd-library/). data TypeF t -- | A base type. TyBaseF :: BaseTy -> TypeF t -- | A type variable. TyVarF :: Var -> TypeF t -- | Commands, with return type. Note that commands form a monad. TyCmdF :: t -> TypeF t -- | Type of delayed computations. TyDelayF :: t -> TypeF t -- | Sum type. TySumF :: t -> t -> TypeF t -- | Product type. TyProdF :: t -> t -> TypeF t -- | Function type. TyFunF :: t -> t -> TypeF t -- | Record type. TyRcdF :: Map Var t -> TypeF t -- | Type is now defined as the fixed point of TypeF. It -- would be annoying to manually apply and match against Fix -- constructors everywhere, so we provide pattern synonyms that allow us -- to work with Type as if it were defined in a directly recursive -- way. type Type = Fix TypeF -- | Get all the type variables contained in a Type. tyVars :: Type -> Set Var pattern TyBase :: BaseTy -> Type pattern TyVar :: Var -> Type pattern TyVoid :: Type pattern TyUnit :: Type pattern TyInt :: Type pattern TyText :: Type pattern TyDir :: Type pattern TyBool :: Type pattern TyActor :: Type pattern TyKey :: Type pattern (:+:) :: Type -> Type -> Type infixr 5 :+: pattern (:*:) :: Type -> Type -> Type infixr 6 :*: pattern (:->:) :: Type -> Type -> Type infixr 1 :->: pattern TyRcd :: Map Var Type -> Type pattern TyCmd :: Type -> Type pattern TyDelay :: Type -> Type -- | UTypes are like Types, but also contain unification -- variables. UType is defined via UTerm, which is also a -- kind of fixed point (in fact, UType is the free monad -- over TypeF). -- -- Just as with Type, we provide a bunch of pattern synonyms for -- working with UType as if it were defined directly. type UType = UTerm TypeF IntVar pattern UTyBase :: BaseTy -> UType pattern UTyVar :: Var -> UType pattern UTyVoid :: UType pattern UTyUnit :: UType pattern UTyInt :: UType pattern UTyText :: UType pattern UTyDir :: UType pattern UTyBool :: UType pattern UTyActor :: UType pattern UTyKey :: UType pattern UTySum :: UType -> UType -> UType pattern UTyProd :: UType -> UType -> UType pattern UTyFun :: UType -> UType -> UType pattern UTyRcd :: Map Var UType -> UType pattern UTyCmd :: UType -> UType pattern UTyDelay :: UType -> UType -- | A generic fold for things defined via UTerm (including, -- in particular, UType). This probably belongs in the -- unification-fd package, but since it doesn't provide one, we -- define it here. ucata :: Functor t => (v -> a) -> (t a -> a) -> UTerm t v -> a -- | A quick-and-dirty method for turning an IntVar (used internally -- as a unification variable) into a unique variable name, by appending a -- number to the given name. mkVarName :: Text -> IntVar -> Var -- | A Poly t is a universally quantified t. The -- variables in the list are bound inside the t. For example, -- the type forall a. a -> a would be represented as -- Forall ["a"] (TyFun "a" "a"). data Poly t Forall :: [Var] -> t -> Poly t -- | A polytype without unification variables. type Polytype = Poly Type pattern PolyUnit :: Polytype -- | A polytype with unification variables. type UPolytype = Poly UType -- | A TCtx is a mapping from variables to polytypes. We generally -- get one of these at the end of the type inference process. type TCtx = Ctx Polytype -- | A UCtx is a mapping from variables to polytypes with -- unification variables. We generally have one of these while we are in -- the midst of the type inference process. type UCtx = Ctx UPolytype -- | In several cases we have two versions of something: a "normal" -- version, and a U version with unification variables in it -- (e.g. Type vs UType, Polytype vs -- UPolytype, TCtx vs UCtx). This class abstracts -- over the process of converting back and forth between them. -- -- In particular, WithU t represents the fact that the -- type t also has a U counterpart, with a way to -- convert back and forth. Note, however, that converting back may be -- "unsafe" in the sense that it requires an extra burden of proof to -- guarantee that it is used only on inputs that are safe. class WithU t where { -- | The associated "U-version" of the type t. type U t :: Type; } -- | Convert from t to its associated "U-version". This -- direction is always safe (we simply have no unification variables even -- though the type allows it). toU :: WithU t => t -> U t -- | Convert from the associated "U-version" back to t. -- Generally, this direction requires somehow knowing that there are no -- longer any unification variables in the value being converted. fromU :: WithU t => U t -> Maybe t instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Types.BaseTy instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Types.BaseTy instance GHC.Generics.Generic Swarm.Language.Types.BaseTy instance Data.Data.Data Swarm.Language.Types.BaseTy instance GHC.Show.Show Swarm.Language.Types.BaseTy instance GHC.Classes.Ord Swarm.Language.Types.BaseTy instance GHC.Classes.Eq Swarm.Language.Types.BaseTy instance Data.Aeson.Types.ToJSON.ToJSON t => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Types.TypeF t) instance Data.Aeson.Types.FromJSON.FromJSON t => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Types.TypeF t) instance Data.Data.Data t => Data.Data.Data (Swarm.Language.Types.TypeF t) instance Control.Unification.Types.Unifiable Swarm.Language.Types.TypeF instance GHC.Generics.Generic1 Swarm.Language.Types.TypeF instance GHC.Generics.Generic (Swarm.Language.Types.TypeF t) instance Data.Traversable.Traversable Swarm.Language.Types.TypeF instance Data.Foldable.Foldable Swarm.Language.Types.TypeF instance GHC.Base.Functor Swarm.Language.Types.TypeF instance GHC.Classes.Eq t => GHC.Classes.Eq (Swarm.Language.Types.TypeF t) instance GHC.Show.Show t => GHC.Show.Show (Swarm.Language.Types.TypeF t) instance Data.Aeson.Types.ToJSON.ToJSON t => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Types.Poly t) instance Data.Aeson.Types.FromJSON.FromJSON t => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Types.Poly t) instance GHC.Generics.Generic (Swarm.Language.Types.Poly t) instance Data.Data.Data t => Data.Data.Data (Swarm.Language.Types.Poly t) instance Data.Traversable.Traversable Swarm.Language.Types.Poly instance Data.Foldable.Foldable Swarm.Language.Types.Poly instance GHC.Base.Functor Swarm.Language.Types.Poly instance GHC.Classes.Eq t => GHC.Classes.Eq (Swarm.Language.Types.Poly t) instance GHC.Show.Show t => GHC.Show.Show (Swarm.Language.Types.Poly t) instance Data.Data.Data Swarm.Language.Types.Type instance Data.Data.Data Swarm.Language.Types.UType instance Data.Data.Data Control.Unification.IntVar.IntVar instance GHC.Generics.Generic Swarm.Language.Types.Type instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Types.Type instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Types.Type instance Swarm.Language.Types.WithU Swarm.Language.Types.Type instance (Swarm.Language.Types.WithU t, Data.Traversable.Traversable f) => Swarm.Language.Types.WithU (f t) instance Data.String.IsString Swarm.Language.Types.UType instance Data.String.IsString Swarm.Language.Types.Type instance GHC.Classes.Ord k => Control.Unification.Types.Unifiable (Data.Map.Internal.Map k) -- | Utilities related to type unification. module Swarm.Language.Typecheck.Unify -- | The result of doing a unification check on two types. data UnifyStatus -- | The two types are definitely not equal; they will never unify no -- matter how any unification variables get filled in. For example, (int -- * u0) and (u1 -> u2) are apart: the first is a product type and the -- second is a function type. Apart :: UnifyStatus -- | The two types might unify, depending on how unification variables get -- filled in, but we're not sure. For example, (int * u0) and (u1 * -- bool). MightUnify :: UnifyStatus -- | The two types are most definitely equal, and we don't need to bother -- generating a constraint to make them so. For example, (int * text) and -- (int * text). Equal :: UnifyStatus -- | Given two types, try hard to prove either that (1) they are -- Apart, i.e. cannot possibly unify, or (2) they are definitely -- Equal. In case (1), we can generate a much better error message -- at the instant the two types come together than we could if we threw a -- constraint into the unifier. In case (2), we don't have to bother with -- generating a trivial constraint. If we don't know for sure whether -- they will unify, return MightUnify. unifyCheck :: UType -> UType -> UnifyStatus instance GHC.Show.Show Swarm.Language.Typecheck.Unify.UnifyStatus instance GHC.Read.Read Swarm.Language.Typecheck.Unify.UnifyStatus instance GHC.Classes.Ord Swarm.Language.Typecheck.Unify.UnifyStatus instance GHC.Classes.Eq Swarm.Language.Typecheck.Unify.UnifyStatus instance GHC.Base.Semigroup Swarm.Language.Typecheck.Unify.UnifyStatus instance GHC.Base.Monoid Swarm.Language.Typecheck.Unify.UnifyStatus -- | Ensures that access to an IORef is read-only by hiding behind a -- newtype. module Swarm.ReadableIORef mkReadonly :: IORef a -> ReadableIORef a data ReadableIORef a readIORef :: ReadableIORef a -> IO a -- | Special border drawing functions that can include labels in more -- places than just the top center. module Swarm.TUI.Border -- | Labels for a horizontal border, with optional left, middle, and right -- labels. data HBorderLabels n -- | A plain horizontal border with no labels. plainHBorder :: HBorderLabels n leftLabel :: forall n_aXPL. Lens' (HBorderLabels n_aXPL) (Maybe (Widget n_aXPL)) centerLabel :: forall n_aXPL. Lens' (HBorderLabels n_aXPL) (Maybe (Widget n_aXPL)) rightLabel :: forall n_aXPL. Lens' (HBorderLabels n_aXPL) (Maybe (Widget n_aXPL)) -- | Labels for a rectangular border, with optional left, middle, and right -- labels on the top and bottom. data BorderLabels n -- | A plain rectangular border with no labels. plainBorder :: BorderLabels n topLabels :: forall n_aXPK. Lens' (BorderLabels n_aXPK) (HBorderLabels n_aXPK) bottomLabels :: forall n_aXPK. Lens' (BorderLabels n_aXPK) (HBorderLabels n_aXPK) -- | Draw a horizontal border with three optional labels. The left label -- (if present) will be placed two units away from the left end of the -- border, and the right label will be placed two units away from the -- right end. The center label, if present, will always be centered in -- the border overall, regardless of the width of the left and right -- labels. This ensures that when the labels change width, they do not -- cause the other labels to wiggle. hBorderWithLabels :: HBorderLabels n -> Widget n -- | Put a rectangular border around the specified widget with the -- specified label widgets placed around the border. borderWithLabels :: BorderLabels n -> Widget n -> Widget n -- | A special modified version of handleListEvent to deal with -- skipping over separators. module Swarm.TUI.List -- | Handle a list event, taking an extra predicate to identify which list -- elements are separators; separators will be skipped if possible. handleListEventWithSeparators :: (Foldable t, Splittable t, Ord n, Searchable t) => Event -> (e -> Bool) -> EventM n (GenericList n t e) () module Swarm.TUI.Model.Name data WorldEditorFocusable BrushSelector :: WorldEditorFocusable EntitySelector :: WorldEditorFocusable AreaSelector :: WorldEditorFocusable OutputPathSelector :: WorldEditorFocusable MapSaveButton :: WorldEditorFocusable ClearEntityButton :: WorldEditorFocusable data FocusablePanel -- | The panel containing the REPL. REPLPanel :: FocusablePanel -- | The panel containing the world view. WorldPanel :: FocusablePanel -- | The panel containing the world editor controls. WorldEditorPanel :: FocusablePanel -- | The panel showing robot info and inventory on the top left. RobotPanel :: FocusablePanel -- | The info panel on the bottom left. InfoPanel :: FocusablePanel data ScenarioConfigPanel ScenarioConfigFileSelector :: ScenarioConfigPanel ScenarioConfigPanelControl :: ScenarioConfigPanelFocusable -> ScenarioConfigPanel data ScenarioConfigPanelFocusable -- | The file selector for launching a scenario with a script ScriptSelector :: ScenarioConfigPanelFocusable SeedSelector :: ScenarioConfigPanelFocusable StartGameButton :: ScenarioConfigPanelFocusable data GoalWidget ObjectivesList :: GoalWidget GoalSummary :: GoalWidget -- | Clickable buttons in modal dialogs. data Button CancelButton :: Button KeepPlayingButton :: Button StartOverButton :: Button QuitButton :: Button NextButton :: Button -- | Name represents names to uniquely identify various components -- of the UI, such as forms, panels, caches, extents, lists, and buttons. data Name FocusablePanel :: FocusablePanel -> Name -- | An individual control within the world editor panel. WorldEditorPanelControl :: WorldEditorFocusable -> Name -- | The REPL input form. REPLInput :: Name -- | The render cache for the world view. WorldCache :: Name -- | The cached extent for the world view. WorldExtent :: Name -- | The cursor/viewCenter display in the bottom left of the World view WorldPositionIndicator :: Name -- | The list of possible entities to paint a map with. EntityPaintList :: Name -- | The entity paint item position in the EntityPaintList. EntityPaintListItem :: Int -> Name -- | The list of possible terrain materials. TerrainList :: Name -- | The terrain item position in the TerrainList. TerrainListItem :: Int -> Name -- | The list of inventory items for the currently focused robot. InventoryList :: Name -- | The inventory item position in the InventoryList. InventoryListItem :: Int -> Name -- | The list of main menu choices. MenuList :: Name -- | The list of achievements. AchievementList :: Name -- | An individual control within the scenario launch config panel ScenarioConfigControl :: ScenarioConfigPanel -> Name -- | The list of goals/objectives. GoalWidgets :: GoalWidget -> Name -- | The list of scenario choices. ScenarioList :: Name -- | The scrollable viewport for the info panel. InfoViewport :: Name -- | The scrollable viewport for any modal dialog. ModalViewport :: Name -- | A clickable button in a modal dialog. Button :: Button -> Name instance GHC.Enum.Enum Swarm.TUI.Model.Name.WorldEditorFocusable instance GHC.Enum.Bounded Swarm.TUI.Model.Name.WorldEditorFocusable instance GHC.Read.Read Swarm.TUI.Model.Name.WorldEditorFocusable instance GHC.Show.Show Swarm.TUI.Model.Name.WorldEditorFocusable instance GHC.Classes.Ord Swarm.TUI.Model.Name.WorldEditorFocusable instance GHC.Classes.Eq Swarm.TUI.Model.Name.WorldEditorFocusable instance GHC.Enum.Enum Swarm.TUI.Model.Name.FocusablePanel instance GHC.Enum.Bounded Swarm.TUI.Model.Name.FocusablePanel instance GHC.Read.Read Swarm.TUI.Model.Name.FocusablePanel instance GHC.Show.Show Swarm.TUI.Model.Name.FocusablePanel instance GHC.Classes.Ord Swarm.TUI.Model.Name.FocusablePanel instance GHC.Classes.Eq Swarm.TUI.Model.Name.FocusablePanel instance GHC.Enum.Enum Swarm.TUI.Model.Name.ScenarioConfigPanelFocusable instance GHC.Enum.Bounded Swarm.TUI.Model.Name.ScenarioConfigPanelFocusable instance GHC.Read.Read Swarm.TUI.Model.Name.ScenarioConfigPanelFocusable instance GHC.Show.Show Swarm.TUI.Model.Name.ScenarioConfigPanelFocusable instance GHC.Classes.Ord Swarm.TUI.Model.Name.ScenarioConfigPanelFocusable instance GHC.Classes.Eq Swarm.TUI.Model.Name.ScenarioConfigPanelFocusable instance GHC.Read.Read Swarm.TUI.Model.Name.ScenarioConfigPanel instance GHC.Show.Show Swarm.TUI.Model.Name.ScenarioConfigPanel instance GHC.Classes.Ord Swarm.TUI.Model.Name.ScenarioConfigPanel instance GHC.Classes.Eq Swarm.TUI.Model.Name.ScenarioConfigPanel instance GHC.Enum.Enum Swarm.TUI.Model.Name.GoalWidget instance GHC.Enum.Bounded Swarm.TUI.Model.Name.GoalWidget instance GHC.Read.Read Swarm.TUI.Model.Name.GoalWidget instance GHC.Show.Show Swarm.TUI.Model.Name.GoalWidget instance GHC.Classes.Ord Swarm.TUI.Model.Name.GoalWidget instance GHC.Classes.Eq Swarm.TUI.Model.Name.GoalWidget instance GHC.Enum.Enum Swarm.TUI.Model.Name.Button instance GHC.Enum.Bounded Swarm.TUI.Model.Name.Button instance GHC.Read.Read Swarm.TUI.Model.Name.Button instance GHC.Show.Show Swarm.TUI.Model.Name.Button instance GHC.Classes.Ord Swarm.TUI.Model.Name.Button instance GHC.Classes.Eq Swarm.TUI.Model.Name.Button instance GHC.Read.Read Swarm.TUI.Model.Name.Name instance GHC.Show.Show Swarm.TUI.Model.Name.Name instance GHC.Classes.Ord Swarm.TUI.Model.Name.Name instance GHC.Classes.Eq Swarm.TUI.Model.Name.Name -- | A small custom "panel widget" for use in the Swarm TUI. Panels draw a -- border around some content, with the color of the border depending on -- whether the panel is currently focused. Panels exist within a -- FocusRing such that the user can cycle between the panels -- (using e.g. the Tab key). module Swarm.TUI.Panel -- | Create a panel. panel :: Eq n => AttrName -> FocusRing n -> n -> BorderLabels n -> Widget n -> Widget n instance Brick.Widgets.Core.Named (Swarm.TUI.Panel.Panel n) n -- | A random collection of small, useful functions that are (or could be) -- used throughout the code base. module Swarm.Util -- | A convenient infix flipped version of fromMaybe: Just a ? b -- = a, and Nothing ? b = b. It can also be chained, as in -- x ? y ? z ? def, which takes the value inside the first -- Just, defaulting to def as a last resort. (?) :: Maybe a -> a -> a infixr 1 ? -- | Ensure the smaller value in a pair is the first element. sortPair :: Ord b => (b, b) -> (b, b) -- | Find the maximum of two values, comparing them according to a custom -- projection function. maxOn :: Ord b => (a -> b) -> a -> a -> a -- | Find the maximum of a list of numbers, defaulting to 0 if the list is -- empty. maximum0 :: (Num a, Ord a) => [a] -> a -- | Take the successor of an Enum type, wrapping around when it -- reaches the end. cycleEnum :: (Eq e, Enum e, Bounded e) => e -> e listEnums :: (Enum e, Bounded e) => [e] -- | Guaranteed to yield an element of the list indexWrapNonEmpty :: Integral b => NonEmpty a -> b -> a -- | Drop repeated elements that are adjacent to each other. -- --
--   >>> uniq []
--   []
--   
--   >>> uniq [1..5]
--   [1,2,3,4,5]
--   
--   >>> uniq (replicate 10 'a')
--   "a"
--   
--   >>> uniq "abbbccd"
--   "abcd"
--   
uniq :: Eq a => [a] -> [a] -- | Place the second element of the tuples into bins by the value of the -- first element. binTuples :: (Foldable t, Ord a) => t (a, b) -> Map a (NonEmpty b) -- | Count occurrences of a value histogram :: (Foldable t, Ord a) => t a -> Map a Int -- | Find a duplicate element within the list, if any exists. findDup :: Ord a => [a] -> Maybe a both :: Bifunctor p => (a -> d) -> p a a -> p d d allEqual :: Ord a => [a] -> Bool surfaceEmpty :: Alternative f => (a -> Bool) -> a -> f a applyWhen :: Bool -> (a -> a) -> a -> a -- | Safely attempt to read a file. readFileMay :: FilePath -> IO (Maybe String) -- | Safely attempt to (efficiently) read a file. readFileMayT :: FilePath -> IO (Maybe Text) -- | Recursively acquire all files in the given directory with the given -- extension, and their contents. acquireAllWithExt :: FilePath -> String -> IO [(FilePath, String)] -- | Predicate to test for characters which can be part of a valid -- identifier: alphanumeric, underscore, or single quote. -- --
--   >>> isIdentChar 'A' && isIdentChar 'b' && isIdentChar '9'
--   True
--   
--   >>> isIdentChar '_' && isIdentChar '\''
--   True
--   
--   >>> isIdentChar '$' || isIdentChar '.' || isIdentChar ' '
--   False
--   
isIdentChar :: Char -> Bool -- | replaceLast r t replaces the last word of t with -- r. -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> replaceLast "foo" "bar baz quux"
--   "bar baz foo"
--   
--   >>> replaceLast "move" "(make"
--   "(move"
--   
replaceLast :: Text -> Text -> Text -- | Fail with a Text-based message, made out of phrases to be joined by -- spaces. failT :: MonadFail m => [Text] -> m a -- | Show a value, but as Text. showT :: Show a => a -> Text -- | Show a value in all lowercase, but as Text. showLowT :: Show a => a -> Text -- | Reflow text by removing newlines and condensing whitespace. reflow :: Text -> Text -- | Surround some text in double quotes. quote :: Text -> Text -- | Surround some text in single quotes. squote :: Text -> Text -- | Surround some text in backticks. bquote :: Text -> Text -- | Surround some text in parentheses. parens :: Text -> Text -- | Surround some text in square brackets. brackets :: Text -> Text -- | Make a list of things with commas and the word "and". commaList :: [Text] -> Text -- | Prepend a noun with the proper indefinite article ("a" or "an"). indefinite :: Text -> Text -- | Prepend a noun with the proper indefinite article, and surround the -- noun in single quotes. indefiniteQ :: Text -> Text -- | Combine the subject word with the simple present tense of the verb. -- -- Only some irregular verbs are handled, but it should be enough to -- scrap some error message boilerplate and have fun! -- --
--   >>> :set -XOverloadedStrings
--   
--   >>> singularSubjectVerb "I" "be"
--   "I am"
--   
--   >>> singularSubjectVerb "he" "can"
--   "he can"
--   
--   >>> singularSubjectVerb "The target robot" "do"
--   "The target robot does"
--   
singularSubjectVerb :: Text -> Text -> Text -- | Pluralize a noun. plural :: Text -> Text -- | Either pluralize a noun or not, depending on the value of the number. number :: Int -> Text -> Text -- | Require that a Boolean value is True, or throw an exception. holdsOr :: Has (Throw e) sig m => Bool -> e -> m () -- | Require that a Maybe value is Just, or throw an -- exception. isJustOr :: Has (Throw e) sig m => Maybe a -> e -> m a -- | Require that an Either value is Right, or throw an -- exception based on the value in the Left. isRightOr :: Has (Throw e) sig m => Either b a -> (b -> e) -> m a -- | Require that a Validation value is Success, or throw an -- exception based on the value in the Failure. isSuccessOr :: Has (Throw e) sig m => Validation b a -> (b -> e) -> m a liftText :: Text -> Q Exp (%%=) :: Has (State s) sig m => Over p ((,) r) s s a b -> p a (r, b) -> m r infix 4 %%= (<%=) :: Has (State s) sig m => LensLike' ((,) a) s a -> (a -> a) -> m a infix 4 <%= (<+=) :: (Has (State s) sig m, Num a) => LensLike' ((,) a) s a -> a -> m a infix 4 <+= (<<.=) :: Has (State s) sig m => LensLike ((,) a) s s a b -> b -> m a infix 4 <<.= (<>=) :: (Has (State s) sig m, Semigroup a) => ASetter' s a -> a -> m () infix 4 <>= _NonEmpty :: Lens' (NonEmpty a) (a, [a]) -- | Remove any sets which are supersets of other sets. In other words, (1) -- no two sets in the output are in a subset relationship (2) every -- element in the input is a superset of some element in the output. -- --
--   >>> import qualified Data.Set as S
--   
--   >>> rss = map S.toList . S.toList . removeSupersets . S.fromList . map S.fromList
--   
-- --
--   >>> rss [[1,2,3], [1]]
--   [[1]]
--   
-- --
--   >>> rss [[1,2,3], [2,4], [2,3]]
--   [[2,3],[2,4]]
--   
-- --
--   >>> rss [[], [1], [2,3]]
--   [[]]
--   
-- --
--   >>> rss [[1,2], [1,3], [2,3]]
--   [[1,2],[1,3],[2,3]]
--   
removeSupersets :: Ord a => Set (Set a) -> Set (Set a) -- | Given a list of nonempty sets, find a hitting set, that is, a -- set which has at least one element in common with each set in the -- list. It is not guaranteed to be the smallest possible such -- set, because that is NP-hard. Instead, we use a greedy algorithm that -- will give us a reasonably small hitting set: first, choose all -- elements in singleton sets, since those must necessarily be chosen. -- Now take any sets which are still not hit, and find an element which -- occurs in the largest possible number of remaining sets. Add this -- element to the set of chosen elements, and filter out all the sets it -- hits. Repeat, choosing a new element to hit the largest number of -- unhit sets at each step, until all sets are hit. This algorithm -- produces a hitting set which might be larger than optimal by a factor -- of lg(m), where m is the number of sets in the input. -- --
--   >>> import qualified Data.Set as S
--   
--   >>> shs = smallHittingSet . map S.fromList
--   
-- --
--   >>> shs ["a"]
--   fromList "a"
--   
-- --
--   >>> shs ["ab", "b"]
--   fromList "b"
--   
-- --
--   >>> shs ["ab", "bc"]
--   fromList "b"
--   
-- --
--   >>> shs ["acd", "c", "aef", "a"]
--   fromList "ac"
--   
-- --
--   >>> shs ["abc", "abd", "acd", "bcd"]
--   fromList "cd"
--   
-- -- Here is an example of an input for which smallHittingSet does -- not produce a minimal hitting set. "bc" is also a hitting set -- and is smaller. b, c, and d all occur in exactly two sets, but d is -- unluckily chosen first, leaving "be" and "ac" unhit and necessitating -- choosing one more element from each. -- --
--   >>> shs ["bd", "be", "ac", "cd"]
--   fromList "cde"
--   
smallHittingSet :: Ord a => [Set a] -> Set a instance Data.Aeson.Types.FromJSON.FromJSON System.Clock.TimeSpec instance Data.Aeson.Types.ToJSON.ToJSON System.Clock.TimeSpec -- | Types and helper functions for working with directions module Swarm.Language.Direction -- | The type of directions. Used e.g. to indicate which way a robot -- will turn. data Direction DAbsolute :: AbsoluteDir -> Direction DRelative :: RelativeDir -> Direction -- | An absolute direction is one which is defined with respect to an -- external frame of reference; robots need a compass in order to use -- them. -- -- NOTE: These values are ordered by increasing angle according to the -- standard mathematical convention. That is, the right-pointing -- direction, East, is considered the "reference angle" and the order -- proceeds counter-clockwise. See -- https://en.wikipedia.org/wiki/Polar_coordinate_system#Conventions -- -- Do not alter this ordering, as there exist functions that depend on it -- (e.g. "nearestDirection" and "relativeTo"). data AbsoluteDir DEast :: AbsoluteDir DNorth :: AbsoluteDir DWest :: AbsoluteDir DSouth :: AbsoluteDir -- | A relative direction is one which is defined with respect to the -- robot's frame of reference; no special capability is needed to use -- them. data RelativeDir DPlanar :: PlanarRelativeDir -> RelativeDir DDown :: RelativeDir -- | Caution: Do not alter this ordering, as there exist functions that -- depend on it (e.g. "nearestDirection" and "relativeTo"). data PlanarRelativeDir DForward :: PlanarRelativeDir DLeft :: PlanarRelativeDir DBack :: PlanarRelativeDir DRight :: PlanarRelativeDir -- | Direction name is generated from the deepest nested data constructor -- e.g. DLeft becomes "left" directionSyntax :: Direction -> Text -- | Check if the direction is absolute (e.g. north or -- south). isCardinal :: Direction -> Bool allDirs :: [Direction] instance GHC.Enum.Bounded Swarm.Language.Direction.AbsoluteDir instance GHC.Enum.Enum Swarm.Language.Direction.AbsoluteDir instance Data.Hashable.Class.Hashable Swarm.Language.Direction.AbsoluteDir instance Data.Data.Data Swarm.Language.Direction.AbsoluteDir instance GHC.Generics.Generic Swarm.Language.Direction.AbsoluteDir instance GHC.Read.Read Swarm.Language.Direction.AbsoluteDir instance GHC.Show.Show Swarm.Language.Direction.AbsoluteDir instance GHC.Classes.Ord Swarm.Language.Direction.AbsoluteDir instance GHC.Classes.Eq Swarm.Language.Direction.AbsoluteDir instance GHC.Enum.Bounded Swarm.Language.Direction.PlanarRelativeDir instance GHC.Enum.Enum Swarm.Language.Direction.PlanarRelativeDir instance Data.Hashable.Class.Hashable Swarm.Language.Direction.PlanarRelativeDir instance Data.Data.Data Swarm.Language.Direction.PlanarRelativeDir instance GHC.Generics.Generic Swarm.Language.Direction.PlanarRelativeDir instance GHC.Read.Read Swarm.Language.Direction.PlanarRelativeDir instance GHC.Show.Show Swarm.Language.Direction.PlanarRelativeDir instance GHC.Classes.Ord Swarm.Language.Direction.PlanarRelativeDir instance GHC.Classes.Eq Swarm.Language.Direction.PlanarRelativeDir instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Direction.RelativeDir instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Direction.RelativeDir instance Data.Hashable.Class.Hashable Swarm.Language.Direction.RelativeDir instance Data.Data.Data Swarm.Language.Direction.RelativeDir instance GHC.Generics.Generic Swarm.Language.Direction.RelativeDir instance GHC.Read.Read Swarm.Language.Direction.RelativeDir instance GHC.Show.Show Swarm.Language.Direction.RelativeDir instance GHC.Classes.Ord Swarm.Language.Direction.RelativeDir instance GHC.Classes.Eq Swarm.Language.Direction.RelativeDir instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Direction.Direction instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Direction.Direction instance Data.Hashable.Class.Hashable Swarm.Language.Direction.Direction instance Data.Data.Data Swarm.Language.Direction.Direction instance GHC.Generics.Generic Swarm.Language.Direction.Direction instance GHC.Read.Read Swarm.Language.Direction.Direction instance GHC.Show.Show Swarm.Language.Direction.Direction instance GHC.Classes.Ord Swarm.Language.Direction.Direction instance GHC.Classes.Eq Swarm.Language.Direction.Direction instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Direction.PlanarRelativeDir instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Direction.PlanarRelativeDir instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Direction.AbsoluteDir instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Direction.AbsoluteDir instance Data.Aeson.Types.ToJSON.ToJSONKey Swarm.Language.Direction.AbsoluteDir instance Data.Aeson.Types.FromJSON.FromJSONKey Swarm.Language.Direction.AbsoluteDir -- | Abstract syntax for terms of the Swarm programming language. module Swarm.Language.Syntax -- | The type of directions. Used e.g. to indicate which way a robot -- will turn. data Direction DAbsolute :: AbsoluteDir -> Direction DRelative :: RelativeDir -> Direction -- | An absolute direction is one which is defined with respect to an -- external frame of reference; robots need a compass in order to use -- them. -- -- NOTE: These values are ordered by increasing angle according to the -- standard mathematical convention. That is, the right-pointing -- direction, East, is considered the "reference angle" and the order -- proceeds counter-clockwise. See -- https://en.wikipedia.org/wiki/Polar_coordinate_system#Conventions -- -- Do not alter this ordering, as there exist functions that depend on it -- (e.g. "nearestDirection" and "relativeTo"). data AbsoluteDir DEast :: AbsoluteDir DNorth :: AbsoluteDir DWest :: AbsoluteDir DSouth :: AbsoluteDir -- | A relative direction is one which is defined with respect to the -- robot's frame of reference; no special capability is needed to use -- them. data RelativeDir DPlanar :: PlanarRelativeDir -> RelativeDir DDown :: RelativeDir -- | Caution: Do not alter this ordering, as there exist functions that -- depend on it (e.g. "nearestDirection" and "relativeTo"). data PlanarRelativeDir DForward :: PlanarRelativeDir DLeft :: PlanarRelativeDir DBack :: PlanarRelativeDir DRight :: PlanarRelativeDir -- | Direction name is generated from the deepest nested data constructor -- e.g. DLeft becomes "left" directionSyntax :: Direction -> Text -- | Check if the direction is absolute (e.g. north or -- south). isCardinal :: Direction -> Bool allDirs :: [Direction] -- | Constants, representing various built-in functions and commands. -- -- IF YOU ADD A NEW CONSTANT, be sure to also update: 1. the -- constInfo function (below) 2. the capability checker -- (Swarm.Language.Capability) 3. the type checker -- (Swarm.Language.Typecheck) 4. the runtime -- (Swarm.Game.Step) 5. the emacs mode syntax highlighter -- (contribs/swarm-mode.el) -- -- GHC will warn you about incomplete pattern matches for the first four, -- and CI will warn you about the last, so in theory it's not really -- possible to forget. Note you do not need to update the parser or -- pretty-printer, since they are auto-generated from constInfo. data Const -- | Do nothing. This is different than Wait in that it does not -- take up a time step. Noop :: Const -- | Wait for a number of time steps without doing anything. Wait :: Const -- | Self-destruct. Selfdestruct :: Const -- | Move forward one step. Move :: Const -- | Move backward one step. Backup :: Const -- | Push an entity forward one step. Push :: Const -- | Move forward multiple steps. Stride :: Const -- | Turn in some direction. Turn :: Const -- | Grab an item from the current location. Grab :: Const -- | Harvest an item from the current location. Harvest :: Const -- | Try to place an item at the current location. Place :: Const -- | Give an item to another robot at the current location. Give :: Const -- | Equip a device on oneself. Equip :: Const -- | Unequip an equipped device, returning to inventory. Unequip :: Const -- | Make an item. Make :: Const -- | Sense whether we have a certain item. Has :: Const -- | Sense whether we have a certain device equipped. Equipped :: Const -- | Sense how many of a certain item we have. Count :: Const -- | Drill through an entity. Drill :: Const -- | Use an entity with another. Use :: Const -- | Construct a new robot. Build :: Const -- | Deconstruct an old robot. Salvage :: Const -- | Reprogram a robot that has executed it's command with a new command Reprogram :: Const -- | Emit a message. Say :: Const -- | Listen for a message from other robots. Listen :: Const -- | Emit a log message. Log :: Const -- | View a certain robot. View :: Const -- | Set what characters are used for display. Appear :: Const -- | Create an entity out of thin air. Only available in creative mode. Create :: Const -- | Tell a robot to halt. Halt :: Const -- | Get current time Time :: Const Scout :: Const -- | Get the current x, y coordinates Whereami :: Const -- | Get the x, y coordinates of a named waypoint, by index Waypoint :: Const -- | Locate the closest instance of a given entity within the rectangle -- specified by opposite corners, relative to the current location. Detect :: Const -- | Count the number of a given entity within the rectangle specified by -- opposite corners, relative to the current location. Resonate :: Const -- | Count the number entities within the rectangle specified by opposite -- corners, relative to the current location. Density :: Const -- | Get the distance to the closest instance of the specified entity. Sniff :: Const -- | Get the direction to the closest instance of the specified entity. Chirp :: Const -- | Register a location to interrupt a wait upon changes Watch :: Const -- | Register a (remote) location to interrupt a wait upon changes Surveil :: Const -- | Get the current heading. Heading :: Const -- | See if we can move forward or not. Blocked :: Const -- | Scan a nearby cell Scan :: Const -- | Upload knowledge to another robot Upload :: Const -- | See if a specific entity is here. Ishere :: Const -- | Check whether the current cell is empty Isempty :: Const -- | Get a reference to oneself Self :: Const -- | Get the robot's parent Parent :: Const -- | Get a reference to the base Base :: Const -- | Meet a nearby robot Meet :: Const -- | Meet all nearby robots MeetAll :: Const -- | Get the robot's display name Whoami :: Const -- | Set the robot's display name Setname :: Const -- | Get a uniformly random integer. Random :: Const -- | Run a program loaded from a file. Run :: Const -- | If-expressions. If :: Const -- | Left injection. Inl :: Const -- | Right injection. Inr :: Const -- | Case analysis on a sum type. Case :: Const -- | First projection. Fst :: Const -- | Second projection. Snd :: Const -- | Force a delayed evaluation. Force :: Const -- | Return for the cmd monad. Return :: Const -- | Try/catch block Try :: Const -- | Undefined Undefined :: Const -- | User error Fail :: Const -- | Logical negation. Not :: Const -- | Arithmetic negation. Neg :: Const -- | Logical equality comparison Eq :: Const -- | Logical unequality comparison Neq :: Const -- | Logical lesser-then comparison Lt :: Const -- | Logical greater-then comparison Gt :: Const -- | Logical lesser-or-equal comparison Leq :: Const -- | Logical greater-or-equal comparison Geq :: Const -- | Logical or. Or :: Const -- | Logical and. And :: Const -- | Arithmetic addition operator Add :: Const -- | Arithmetic subtraction operator Sub :: Const -- | Arithmetic multiplication operator Mul :: Const -- | Arithmetic division operator Div :: Const -- | Arithmetic exponentiation operator Exp :: Const -- | Turn an arbitrary value into a string Format :: Const -- | Concatenate string values Concat :: Const -- | Count number of characters. Chars :: Const -- | Split string into two parts. Split :: Const -- | Get the character at an index. CharAt :: Const -- | Create a singleton text value with the given character code. ToChar :: Const -- | Application operator - helps to avoid parentheses: f $ g $ h x = f -- (g (h x)) AppF :: Const -- | Swap placed entity with one in inventory. Essentially atomic grab and -- place. Swap :: Const -- | When executing atomic c, a robot will not be interrupted, -- that is, no other robots will execute any commands while the robot is -- executing c. Atomic :: Const -- | Like atomic, but with no restriction on program size. Instant :: Const -- | Create key values. Key :: Const -- | Install a new keyboard input handler. InstallKeyHandler :: Const -- | Teleport a robot to the given position. Teleport :: Const -- | Run a command as if you were another robot. As :: Const -- | Find an actor by name. RobotNamed :: Const -- | Find an actor by number. RobotNumbered :: Const -- | Check if an entity is known. Knows :: Const allConst :: [Const] data ConstInfo ConstInfo :: Text -> Int -> ConstMeta -> ConstDoc -> Tangibility -> ConstInfo [syntax] :: ConstInfo -> Text [fixity] :: ConstInfo -> Int [constMeta] :: ConstInfo -> ConstMeta [constDoc] :: ConstInfo -> ConstDoc [tangibility] :: ConstInfo -> Tangibility data ConstDoc ConstDoc :: Text -> Text -> ConstDoc [briefDoc] :: ConstDoc -> Text [longDoc] :: ConstDoc -> Text data ConstMeta -- | Function with arity of which some are commands ConstMFunc :: Int -> Bool -> ConstMeta -- | Unary operator with fixity and associativity. ConstMUnOp :: MUnAssoc -> ConstMeta -- | Binary operator with fixity and associativity. ConstMBinOp :: MBinAssoc -> ConstMeta -- | The meta type representing associativity of binary operator. data MBinAssoc -- | Left associative binary operator (see InfixL) L :: MBinAssoc -- | Non-associative binary operator (see InfixN) N :: MBinAssoc -- | Right associative binary operator (see InfixR) R :: MBinAssoc -- | The meta type representing associativity of unary operator. data MUnAssoc -- | Prefix unary operator (see Prefix) P :: MUnAssoc -- | Suffix unary operator (see Suffix) S :: MUnAssoc -- | Information about constants used in parsing and pretty printing. -- -- It would be more compact to represent the information by testing -- whether the constants are in certain sets, but using pattern matching -- gives us warning if we add more constants. constInfo :: Const -> ConstInfo -- | The arity of a constant, i.e. how many arguments it expects. -- The runtime system will collect arguments to a constant (see -- VCApp) until it has enough, then dispatch the constant's -- behavior. arity :: Const -> Int -- | Whether a constant represents a command. Constants which are -- not commands are functions which are interpreted as soon as -- they are evaluated. Commands, on the other hand, are not interpreted -- until being executed, that is, when meeting an FExec -- frame. When evaluated, commands simply turn into a VCApp. isCmd :: Const -> Bool -- | Function constants user can call with reserved words -- (wait,...). isUserFunc :: Const -> Bool -- | Whether the constant is an operator. Useful predicate for -- documentation. isOperator :: Const -> Bool -- | Whether the constant is a function which is interpreted as soon -- as it is evaluated, but *not* including operators. -- -- Note: This is used for documentation purposes and complements -- isCmd and isOperator in that exactly one will accept a -- given constant. isBuiltinFunction :: Const -> Bool -- | Whether the constant is a tangible command, that has an -- external effect on the world. At most one tangible command may be -- executed per tick. isTangible :: Const -> Bool -- | Whether the constant is a long command, that is, a tangible -- command which could require multiple ticks to execute. Such commands -- cannot be allowed in atomic blocks. isLong :: Const -> Bool -- | Maximum perception distance for chirp and sniff -- commands maxSniffRange :: Int32 maxScoutRange :: Int maxStrideRange :: Int -- | The surface syntax for the language, with location and type -- annotations. data Syntax' ty Syntax' :: SrcLoc -> Term' ty -> ty -> Syntax' ty [_sLoc] :: Syntax' ty -> SrcLoc [_sTerm] :: Syntax' ty -> Term' ty [_sType] :: Syntax' ty -> ty sLoc :: forall ty_a1sLY. Lens' (Syntax' ty_a1sLY) SrcLoc sTerm :: forall ty_a1sLY. Lens' (Syntax' ty_a1sLY) (Term' ty_a1sLY) sType :: forall ty_a1sLY. Lens' (Syntax' ty_a1sLY) ty_a1sLY type Syntax = Syntax' () pattern Syntax :: SrcLoc -> Term -> Syntax -- | A variable with associated source location, used for variable binding -- sites. (Variable occurrences are a bare TVar which gets wrapped in a -- Syntax node, so we don't need LocVar for those.) data LocVar LV :: SrcLoc -> Var -> LocVar [lvSrcLoc] :: LocVar -> SrcLoc [lvVar] :: LocVar -> Var data SrcLoc NoLoc :: SrcLoc -- | Half-open interval from start (inclusive) to end (exclusive) SrcLoc :: Int -> Int -> SrcLoc noLoc :: Term -> Syntax -- | Match an untyped term without its SrcLoc. pattern STerm :: Term -> Syntax pattern TRequirements :: Text -> Term -> Term -- | Match a TPair without syntax pattern TPair :: Term -> Term -> Term -- | Match a TLam without syntax pattern TLam :: Var -> Maybe Type -> Term -> Term -- | Match a TApp without syntax pattern TApp :: Term -> Term -> Term -- | Convenient infix pattern synonym for application. pattern (:$:) :: Term -> Syntax -> Term infixl 0 :$: -- | Match a TLet without syntax pattern TLet :: Bool -> Var -> Maybe Polytype -> Term -> Term -> Term -- | Match a TDef without syntax pattern TDef :: Bool -> Var -> Maybe Polytype -> Term -> Term -- | Match a TBind without syntax pattern TBind :: Maybe Var -> Term -> Term -> Term -- | Match a TDelay without syntax pattern TDelay :: DelayType -> Term -> Term -- | Match a TRcd without syntax pattern TRcd :: Map Var (Maybe Term) -> Term pattern TProj :: Term -> Var -> Term -- | Match a TAnnotate without syntax pattern TAnnotate :: Term -> Polytype -> Term -- | We use Text values to represent variables. type Var = Text -- | Different runtime behaviors for delayed expressions. data DelayType -- | A simple delay, implemented via a (non-memoized) VDelay -- holding the delayed expression. SimpleDelay :: DelayType -- | A memoized delay, implemented by allocating a mutable cell with the -- delayed expression and returning a reference to it. When the Maybe -- Var is Just, a recursive binding of the variable with a -- reference to the delayed expression will be provided while evaluating -- the delayed expression itself. Note that there is no surface syntax -- for binding a variable within a recursive delayed expression; the only -- way we can get Just here is when we automatically generate a -- delayed expression while interpreting a recursive let or -- def. MemoizedDelay :: Maybe Var -> DelayType -- | Terms of the Swarm language. data Term' ty -- | The unit value. TUnit :: Term' ty -- | A constant. TConst :: Const -> Term' ty -- | A direction literal. TDir :: Direction -> Term' ty -- | An integer literal. TInt :: Integer -> Term' ty -- | An antiquoted Haskell variable name of type Integer. TAntiInt :: Text -> Term' ty -- | A text literal. TText :: Text -> Term' ty -- | An antiquoted Haskell variable name of type Text. TAntiText :: Text -> Term' ty -- | A Boolean literal. TBool :: Bool -> Term' ty -- | A robot reference. These never show up in surface syntax, but are here -- so we can factor pretty-printing for Values through pretty-printing -- for Terms. TRobot :: Int -> Term' ty -- | A memory reference. These likewise never show up in surface syntax, -- but are here to facilitate pretty-printing. TRef :: Int -> Term' ty -- | Require a specific device to be installed. TRequireDevice :: Text -> Term' ty -- | Require a certain number of an entity. TRequire :: Int -> Text -> Term' ty -- | Primitive command to log requirements of a term. The Text field is to -- store the unaltered original text of the term, for use in displaying -- the log message (since once we get to execution time the original term -- may have been elaborated, e.g. force may have been added -- around some variables, etc.) SRequirements :: Text -> Syntax' ty -> Term' ty -- | A variable. TVar :: Var -> Term' ty -- | A pair. SPair :: Syntax' ty -> Syntax' ty -> Term' ty -- | A lambda expression, with or without a type annotation on the binder. SLam :: LocVar -> Maybe Type -> Syntax' ty -> Term' ty -- | Function application. SApp :: Syntax' ty -> Syntax' ty -> Term' ty -- | A (recursive) let expression, with or without a type annotation on the -- variable. The Bool indicates whether it is known to be -- recursive. SLet :: Bool -> LocVar -> Maybe Polytype -> Syntax' ty -> Syntax' ty -> Term' ty -- | A (recursive) definition command, which binds a variable to a value in -- subsequent commands. The Bool indicates whether the -- definition is known to be recursive. SDef :: Bool -> LocVar -> Maybe Polytype -> Syntax' ty -> Term' ty -- | A monadic bind for commands, of the form c1 ; c2 or x -- <- c1; c2. SBind :: Maybe LocVar -> Syntax' ty -> Syntax' ty -> Term' ty -- | Delay evaluation of a term, written {...}. Swarm is an eager -- language, but in some cases (e.g. for if statements and -- recursive bindings) we need to delay evaluation. The counterpart to -- {...} is force, where force {t} = t. Note -- that Force is just a constant, whereas SDelay has to be -- a special syntactic form so its argument can get special treatment -- during evaluation. SDelay :: DelayType -> Syntax' ty -> Term' ty -- | Record literals [x1 = e1, x2 = e2, x3, ...] Names x -- without an accompanying definition are sugar for writing x=x. SRcd :: Map Var (Maybe (Syntax' ty)) -> Term' ty -- | Record projection e.x SProj :: Syntax' ty -> Var -> Term' ty -- | Annotate a term with a type SAnnotate :: Syntax' ty -> Polytype -> Term' ty type Term = Term' () -- | COMPLETE pragma tells GHC using this set of pattern is complete for -- Term -- -- Make infix operation (e.g. 2 + 3) a curried function -- application (((+) 2) 3). mkOp :: Const -> Syntax -> Syntax -> Syntax -- | Make infix operation, discarding any syntax related location mkOp' :: Const -> Term -> Term -> Term -- | Turn function application chain into a list. -- --
--   >>> syntaxWrap f = fmap (^. sTerm) . f . Syntax NoLoc
--   
--   >>> syntaxWrap unfoldApps (mkOp' Mul (TInt 1) (TInt 2)) -- 1 * 2
--   TConst Mul :| [TInt 1,TInt 2]
--   
unfoldApps :: Syntax' ty -> NonEmpty (Syntax' ty) -- | Erase a type-annotated term to a bare term. erase :: Term' ty -> Term -- | Erase a Syntax tree annotated with SrcLoc and type -- information to a bare unannotated Term. eraseS :: Syntax' ty -> Term -- | Traversal over those subterms of a term which represent free -- variables. The S suffix indicates that it is a Traversal over -- the Syntax nodes (which contain type and source location info) -- containing free variables inside a larger Syntax value. Note -- that if you want to get the list of all Syntax nodes -- representing free variables, you can do so via toListOf -- freeVarsS. freeVarsS :: forall ty. Traversal' (Syntax' ty) (Syntax' ty) -- | Like freeVarsS, but traverse over the Terms containing -- free variables. More direct if you don't need to know the types or -- source locations of the variables. Note that if you want to get the -- list of all Terms representing free variables, you can do so -- via toListOf freeVarsT. freeVarsT :: forall ty. Traversal' (Syntax' ty) (Term' ty) -- | Traversal over the free variables of a term. Like freeVarsS and -- freeVarsT, but traverse over the variable names themselves. -- Note that if you want to get the set of all free variable names, you -- can do so via setOf freeVarsV. freeVarsV :: Traversal' (Syntax' ty) Var -- | Apply a function to all free occurrences of a particular variable. mapFreeS :: Var -> (Syntax' ty -> Syntax' ty) -> Syntax' ty -> Syntax' ty locVarToSyntax' :: LocVar -> ty -> Syntax' ty -- | Transform the AST into a Tree datatype. Useful for pretty-printing -- (e.g. via "Data.Tree.drawTree"). asTree :: Data a => Syntax' a -> Tree (Syntax' a) -- | Each constructor is a assigned a value of 1, plus any recursive syntax -- it entails. measureAstSize :: Data a => Syntax' a -> Int instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Syntax.Const instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Syntax.Const instance GHC.Generics.Generic Swarm.Language.Syntax.Const instance GHC.Show.Show Swarm.Language.Syntax.Const instance Data.Data.Data Swarm.Language.Syntax.Const instance GHC.Enum.Bounded Swarm.Language.Syntax.Const instance GHC.Enum.Enum Swarm.Language.Syntax.Const instance GHC.Classes.Ord Swarm.Language.Syntax.Const instance GHC.Classes.Eq Swarm.Language.Syntax.Const instance GHC.Show.Show Swarm.Language.Syntax.ConstDoc instance GHC.Classes.Ord Swarm.Language.Syntax.ConstDoc instance GHC.Classes.Eq Swarm.Language.Syntax.ConstDoc instance GHC.Show.Show Swarm.Language.Syntax.MBinAssoc instance GHC.Classes.Ord Swarm.Language.Syntax.MBinAssoc instance GHC.Classes.Eq Swarm.Language.Syntax.MBinAssoc instance GHC.Show.Show Swarm.Language.Syntax.MUnAssoc instance GHC.Classes.Ord Swarm.Language.Syntax.MUnAssoc instance GHC.Classes.Eq Swarm.Language.Syntax.MUnAssoc instance GHC.Show.Show Swarm.Language.Syntax.ConstMeta instance GHC.Classes.Ord Swarm.Language.Syntax.ConstMeta instance GHC.Classes.Eq Swarm.Language.Syntax.ConstMeta instance GHC.Enum.Enum Swarm.Language.Syntax.Length instance GHC.Enum.Bounded Swarm.Language.Syntax.Length instance GHC.Read.Read Swarm.Language.Syntax.Length instance GHC.Show.Show Swarm.Language.Syntax.Length instance GHC.Classes.Ord Swarm.Language.Syntax.Length instance GHC.Classes.Eq Swarm.Language.Syntax.Length instance GHC.Read.Read Swarm.Language.Syntax.Tangibility instance GHC.Show.Show Swarm.Language.Syntax.Tangibility instance GHC.Classes.Ord Swarm.Language.Syntax.Tangibility instance GHC.Classes.Eq Swarm.Language.Syntax.Tangibility instance GHC.Show.Show Swarm.Language.Syntax.ConstInfo instance GHC.Classes.Ord Swarm.Language.Syntax.ConstInfo instance GHC.Classes.Eq Swarm.Language.Syntax.ConstInfo instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Syntax.DelayType instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Syntax.DelayType instance GHC.Generics.Generic Swarm.Language.Syntax.DelayType instance Data.Data.Data Swarm.Language.Syntax.DelayType instance GHC.Show.Show Swarm.Language.Syntax.DelayType instance GHC.Classes.Eq Swarm.Language.Syntax.DelayType instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Syntax.SrcLoc instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Syntax.SrcLoc instance GHC.Generics.Generic Swarm.Language.Syntax.SrcLoc instance Data.Data.Data Swarm.Language.Syntax.SrcLoc instance GHC.Show.Show Swarm.Language.Syntax.SrcLoc instance GHC.Classes.Ord Swarm.Language.Syntax.SrcLoc instance GHC.Classes.Eq Swarm.Language.Syntax.SrcLoc instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Syntax.LocVar instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Syntax.LocVar instance GHC.Generics.Generic Swarm.Language.Syntax.LocVar instance Data.Data.Data Swarm.Language.Syntax.LocVar instance GHC.Show.Show Swarm.Language.Syntax.LocVar instance GHC.Classes.Ord Swarm.Language.Syntax.LocVar instance GHC.Classes.Eq Swarm.Language.Syntax.LocVar instance Data.Aeson.Types.ToJSON.ToJSON ty => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Syntax.Syntax' ty) instance Data.Aeson.Types.FromJSON.FromJSON ty => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Syntax.Syntax' ty) instance GHC.Generics.Generic (Swarm.Language.Syntax.Syntax' ty) instance Data.Data.Data ty => Data.Data.Data (Swarm.Language.Syntax.Syntax' ty) instance Data.Traversable.Traversable Swarm.Language.Syntax.Syntax' instance Data.Foldable.Foldable Swarm.Language.Syntax.Syntax' instance GHC.Base.Functor Swarm.Language.Syntax.Syntax' instance GHC.Show.Show ty => GHC.Show.Show (Swarm.Language.Syntax.Syntax' ty) instance GHC.Classes.Eq ty => GHC.Classes.Eq (Swarm.Language.Syntax.Syntax' ty) instance Data.Aeson.Types.ToJSON.ToJSON ty => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Syntax.Term' ty) instance Data.Aeson.Types.FromJSON.FromJSON ty => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Syntax.Term' ty) instance GHC.Generics.Generic (Swarm.Language.Syntax.Term' ty) instance Data.Data.Data ty => Data.Data.Data (Swarm.Language.Syntax.Term' ty) instance Data.Traversable.Traversable Swarm.Language.Syntax.Term' instance Data.Foldable.Foldable Swarm.Language.Syntax.Term' instance GHC.Base.Functor Swarm.Language.Syntax.Term' instance GHC.Show.Show ty => GHC.Show.Show (Swarm.Language.Syntax.Term' ty) instance GHC.Classes.Eq ty => GHC.Classes.Eq (Swarm.Language.Syntax.Term' ty) instance Data.Data.Data ty => Control.Lens.Plated.Plated (Swarm.Language.Syntax.Term' ty) instance Data.Data.Data ty => Control.Lens.Plated.Plated (Swarm.Language.Syntax.Syntax' ty) instance GHC.Base.Semigroup Swarm.Language.Syntax.SrcLoc instance GHC.Base.Monoid Swarm.Language.Syntax.SrcLoc instance Data.String.IsString Swarm.Language.Syntax.ConstDoc -- | A Module packages together a type-annotated syntax tree along -- with a context of top-level definitions. module Swarm.Language.Module -- | A module generally represents the result of performing type inference -- on a top-level expression, which in particular can contain definitions -- (TDef). A module contains the type-annotated AST of the -- expression itself, as well as the context giving the types of any -- defined variables. data Module s t Module :: Syntax' s -> Ctx t -> Module s t [moduleAST] :: Module s t -> Syntax' s [moduleCtx] :: Module s t -> Ctx t -- | A TModule is the final result of the type inference process on -- an expression: we get a polytype for the expression, and a context of -- polytypes for the defined variables. type TModule = Module Polytype Polytype -- | A UModule represents the type of an expression at some -- intermediate stage during the type inference process. We get a -- UType (not a UPolytype) for the expression, which -- may contain some free unification or type variables, as well as a -- context of UPolytypes for any defined variables. type UModule = Module UType UPolytype -- | The trivial module for a given AST, with the empty context. trivMod :: Syntax' s -> Module s t instance (Data.Aeson.Types.ToJSON.ToJSON t, Data.Aeson.Types.ToJSON.ToJSON s) => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Module.Module s t) instance (Data.Aeson.Types.FromJSON.FromJSON s, Data.Aeson.Types.FromJSON.FromJSON t) => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Module.Module s t) instance GHC.Generics.Generic (Swarm.Language.Module.Module s t) instance (Data.Data.Data s, Data.Data.Data t) => Data.Data.Data (Swarm.Language.Module.Module s t) instance GHC.Base.Functor (Swarm.Language.Module.Module s) instance (GHC.Classes.Eq s, GHC.Classes.Eq t) => GHC.Classes.Eq (Swarm.Language.Module.Module s t) instance (GHC.Show.Show s, GHC.Show.Show t) => GHC.Show.Show (Swarm.Language.Module.Module s t) -- | Term elaboration which happens after type checking. module Swarm.Language.Elaborate -- | Perform some elaboration / rewriting on a fully type-annotated term. -- This currently performs such operations as rewriting if -- expressions and recursive let expressions to use laziness -- appropriately. In theory it could also perform rewriting for -- overloaded constants depending on the actual type they are used at, -- but currently that sort of thing tends to make type inference fall -- over. elaborate :: Syntax' Polytype -> Syntax' Polytype wrapForce :: Var -> Syntax' Polytype -> Syntax' Polytype sForce :: Syntax' Polytype -- | 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 -- | Various capabilities which robots can have. data Capability -- | Be powered, i.e. execute anything at all CPower :: Capability -- | Execute the Move command CMove :: Capability -- | Execute the Backup command CBackup :: Capability -- | Execute the Push command CPush :: Capability -- | Execute the Stride command CMovemultiple :: Capability -- | Execute the Move command for a heavy robot CMoveheavy :: Capability -- | Execute the Turn command -- -- NOTE: using cardinal directions is separate COrient capability CTurn :: Capability -- | Execute the Selfdestruct command CSelfdestruct :: Capability -- | Execute the Grab command CGrab :: Capability -- | Execute the Harvest command CHarvest :: Capability -- | Execute the Place command CPlace :: Capability -- | Execute the Give command CGive :: Capability -- | Execute the Equip command CEquip :: Capability -- | Execute the Unequip command CUnequip :: Capability -- | Execute the Make command CMake :: Capability -- | Execute the Count command CCount :: Capability -- | Execute the Scout command. Reconnaissance along a line in a -- direction. CRecondir :: Capability -- | Execute the Build command CBuild :: Capability -- | Execute the Salvage command CSalvage :: Capability -- | Execute the Drill command CDrill :: Capability -- | Execute the Whereami command CSenseloc :: Capability -- | Execute the Blocked command CSensefront :: Capability -- | Execute the Ishere and Isempty commands CSensehere :: Capability -- | Execute the Detect command CDetectloc :: Capability -- | Execute the Resonate and Density commands CDetectcount :: Capability -- | Execute the Sniff command CDetectdistance :: Capability -- | Execute the Chirp command CDetectdirection :: Capability -- | Execute the Watch command CWakeself :: Capability -- | Execute the Scan command CScan :: Capability -- | Execute the Random command CRandom :: Capability -- | Execute the Appear command CAppear :: Capability -- | Execute the Create command CCreate :: Capability -- | Execute the Listen command and passively log messages if also -- has CLog CListen :: Capability -- | Execute the Log command CLog :: Capability -- | Format values as text CFormat :: Capability -- | Split text into two pieces CConcat :: Capability -- | Join two text values into one CSplit :: Capability -- | Count the characters in a text value CCharcount :: Capability -- | Convert between characters/text and Unicode values CCode :: Capability -- | Don't drown in liquid CFloat :: Capability -- | Evaluate conditional expressions CCond :: Capability -- | Negate boolean value CNegation :: Capability -- | Evaluate comparison operations CCompare :: Capability -- | Use cardinal direction constants. COrient :: Capability -- | Evaluate arithmetic operations CArith :: Capability -- | Store and look up definitions in an environment CEnv :: Capability -- | Interpret lambda abstractions CLambda :: Capability -- | Enable recursive definitions CRecursion :: Capability -- | Execute the Reprogram command CReprogram :: Capability -- | Execute the meet and meetAll commands. CMeet :: Capability -- | Capability to introspect and see its own name CWhoami :: Capability -- | Capability to set its own name CSetname :: Capability -- | Capability to move unrestricted to any place CTeleport :: Capability -- | Capability to run commands atomically CAtomic :: Capability -- | Capability to execute swap (grab and place atomically at the same -- time). CSwap :: Capability -- | Capability to obtain absolute time, namely via the time -- command. CTimeabs :: Capability -- | Capability to utilize relative passage of time, namely via the -- wait command. This is strictly weaker than CTimeAbs. CTimerel :: Capability -- | Capability to execute try. CTry :: Capability -- | Capability for working with sum types. CSum :: Capability -- | Capability for working with product types. CProd :: Capability -- | Capability for working with record types. CRecord :: Capability -- | Debug capability. CDebug :: Capability -- | Capability to handle keyboard input. CHandleinput :: Capability -- | Capability to make other robots halt. CHalt :: Capability -- | God-like capabilities. For e.g. commands intended only for checking -- challenge mode win conditions, and not for use by players. CGod :: Capability capabilityName :: Capability -> Text -- | Capabilities needed to evaluate or execute a constant. constCaps :: Const -> Maybe Capability instance Data.Aeson.Types.ToJSON.ToJSONKey Swarm.Language.Capability.Capability instance Data.Aeson.Types.FromJSON.FromJSONKey Swarm.Language.Capability.Capability instance Data.Data.Data Swarm.Language.Capability.Capability instance Data.Hashable.Class.Hashable Swarm.Language.Capability.Capability instance GHC.Generics.Generic Swarm.Language.Capability.Capability instance GHC.Enum.Bounded Swarm.Language.Capability.Capability instance GHC.Enum.Enum Swarm.Language.Capability.Capability instance GHC.Read.Read Swarm.Language.Capability.Capability instance GHC.Show.Show Swarm.Language.Capability.Capability instance GHC.Classes.Ord Swarm.Language.Capability.Capability instance GHC.Classes.Eq Swarm.Language.Capability.Capability instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Capability.Capability instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Capability.Capability -- | A requirement is something that is needed in order to successfully -- build a robot running a certain program. module Swarm.Language.Requirement -- | A requirement is something a robot must have when it is built. -- There are three types: - A robot can require a certain -- Capability, which should be fulfilled by equipping an -- appropriate device. - A robot can require a specific device, -- which should be equipped. - A robot can require some number of a -- specific entity in its inventory. data Requirement -- | Require a specific capability. This must be fulfilled by equipping an -- appropriate device. Requiring the same capability multiple times is -- the same as requiring it once. ReqCap :: Capability -> Requirement -- | Require a specific device to be equipped. Note that at this point it -- is only a name, and has not been resolved to an actual -- Entity. That's because programs have to be type- and -- capability-checked independent of an EntityMap. The name will -- be looked up at runtime, when actually executing a Build or -- Reprogram command, and an appropriate exception thrown if a -- device with the given name does not exist. -- -- Requiring the same device multiple times is the same as requiring it -- once. ReqDev :: Text -> Requirement -- | Require a certain number of a specific entity to be available in the -- inventory. The same comments apply re: resolving the entity name to an -- actual Entity. -- -- Inventory requirements are additive, that is, say, requiring 5 of -- entity e and later requiring 7 is the same as requiring 12. ReqInv :: Int -> Text -> Requirement -- | It is tempting to define Requirements = Set Requirement, but -- that would be wrong, since two identical ReqInv should have -- their counts added rather than simply being deduplicated. -- -- Since we will eventually need to deal with the different types of -- requirements separately, it makes sense to store them separately -- anyway. data Requirements Requirements :: Set Capability -> Set Text -> Map Text Int -> Requirements [capReqs] :: Requirements -> Set Capability [devReqs] :: Requirements -> Set Text [invReqs] :: Requirements -> Map Text Int -- | Create a Requirements set with a single Requirement. singleton :: Requirement -> Requirements -- | For convenience, create a Requirements set with a single -- Capability requirement. singletonCap :: Capability -> Requirements -- | For convenience, create a Requirements set with a single device -- requirement. singletonDev :: Text -> Requirements -- | For convenience, create a Requirements set with a single -- inventory requirement. singletonInv :: Int -> Text -> Requirements insert :: Requirement -> Requirements -> Requirements -- | A requirement context records the requirements for the definitions -- bound to variables. type ReqCtx = Ctx Requirements -- | Analyze a program to see what capabilities may be needed to execute -- it. Also return a capability context mapping from any variables -- declared via TDef to the capabilities needed by their -- definitions. -- -- Note that this is necessarily a conservative analysis, especially if -- the program contains conditional expressions. Some capabilities may -- end up not being actually needed if certain commands end up not being -- executed. However, the analysis should be safe in the sense that a -- robot with the indicated capabilities will always be able to run the -- given program. requirements :: ReqCtx -> Term -> (Requirements, ReqCtx) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Requirement.Requirement instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Requirement.Requirement instance Data.Data.Data Swarm.Language.Requirement.Requirement instance Data.Hashable.Class.Hashable Swarm.Language.Requirement.Requirement instance GHC.Generics.Generic Swarm.Language.Requirement.Requirement instance GHC.Read.Read Swarm.Language.Requirement.Requirement instance GHC.Show.Show Swarm.Language.Requirement.Requirement instance GHC.Classes.Ord Swarm.Language.Requirement.Requirement instance GHC.Classes.Eq Swarm.Language.Requirement.Requirement instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Requirement.Requirements instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Requirement.Requirements instance GHC.Generics.Generic Swarm.Language.Requirement.Requirements instance Data.Data.Data Swarm.Language.Requirement.Requirements instance GHC.Show.Show Swarm.Language.Requirement.Requirements instance GHC.Classes.Ord Swarm.Language.Requirement.Requirements instance GHC.Classes.Eq Swarm.Language.Requirement.Requirements instance GHC.Base.Semigroup Swarm.Language.Requirement.Requirements instance GHC.Base.Monoid Swarm.Language.Requirement.Requirements module Swarm.Language.Typed -- | A value, or a hole, or something else that has its type & -- requirements fixed data Typed v Typed :: v -> Polytype -> Requirements -> Typed v [_value] :: Typed v -> v [_polytype] :: Typed v -> Polytype [_requires] :: Typed v -> Requirements value :: forall v_a3dP3 v_a3e3W. Lens (Typed v_a3dP3) (Typed v_a3e3W) v_a3dP3 v_a3e3W polytype :: forall v_a3dP3. Lens' (Typed v_a3dP3) Polytype requires :: forall v_a3dP3. Lens' (Typed v_a3dP3) Requirements instance Data.Aeson.Types.ToJSON.ToJSON v => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Typed.Typed v) instance Data.Aeson.Types.FromJSON.FromJSON v => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Typed.Typed v) instance GHC.Generics.Generic (Swarm.Language.Typed.Typed v) instance GHC.Classes.Eq v => GHC.Classes.Eq (Swarm.Language.Typed.Typed v) instance GHC.Show.Show v => GHC.Show.Show (Swarm.Language.Typed.Typed v) -- | Data types and functions applicable across different scoring methods. module Swarm.Game.Scenario.Scoring.GenericMetrics -- | This is a subset of the ScenarioStatus type that excludes the -- NotStarted case. data Progress Attempted :: Progress Completed :: Progress untaggedJsonOptions :: Options data Metric a Metric :: Progress -> a -> Metric a getMetric :: Metric a -> a -- | This encodes the notion of "more play is better" for incomplete games -- (rationale: more play = more fun), whereas "smaller inputs are better" -- for completed games. -- -- Since Maybe has its own Ord instance where Nothing -- < Just x regardless of x, when we want to choose the -- minimum value we `fmap Down` to ensure that the Just is -- selected while inverting the ordering of the inner member. chooseBetter :: Ord a => (b -> Maybe a) -> Metric b -> Metric b -> Metric b instance GHC.Generics.Generic Swarm.Game.Scenario.Scoring.GenericMetrics.Progress instance GHC.Read.Read Swarm.Game.Scenario.Scoring.GenericMetrics.Progress instance GHC.Show.Show Swarm.Game.Scenario.Scoring.GenericMetrics.Progress instance GHC.Classes.Ord Swarm.Game.Scenario.Scoring.GenericMetrics.Progress instance GHC.Classes.Eq Swarm.Game.Scenario.Scoring.GenericMetrics.Progress instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Scenario.Scoring.GenericMetrics.Metric a) instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.Scenario.Scoring.GenericMetrics.Metric a) instance GHC.Generics.Generic (Swarm.Game.Scenario.Scoring.GenericMetrics.Metric a) instance GHC.Read.Read a => GHC.Read.Read (Swarm.Game.Scenario.Scoring.GenericMetrics.Metric a) instance GHC.Show.Show a => GHC.Show.Show (Swarm.Game.Scenario.Scoring.GenericMetrics.Metric a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Swarm.Game.Scenario.Scoring.GenericMetrics.Metric a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Swarm.Game.Scenario.Scoring.GenericMetrics.Metric a) instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Scoring.GenericMetrics.Progress instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Scoring.GenericMetrics.Progress -- | Locations and headings. module Swarm.Game.Location -- | A Location is a pair of (x,y) coordinates, both up to 32 bits. The -- positive x-axis points east and the positive y-axis points north. -- These are the coordinates that are shown to players. -- -- See also the Coords type defined in Swarm.Game.World, -- which use a (row, column) format instead, which is more convenient for -- internal use. The Swarm.Game.World module also defines -- conversions between Location and Coords. type Location = Point V2 Int32 -- | A convenient way to pattern-match on Location values. pattern Location :: Int32 -> Int32 -> Location -- | A Heading is a 2D vector, with 32-bit coordinates. -- -- Location and Heading are both represented using types -- from the linear package, so they can be manipulated using a -- large number of operators from that package. For example: -- -- type Heading = V2 Int32 -- | The applyTurn function gives the meaning of each -- Direction by turning relative to the given heading or by -- turning to an absolute heading applyTurn :: Direction -> Heading -> Heading -- | Example: DWest relativeTo DSouth == DRight relativeTo :: AbsoluteDir -> AbsoluteDir -> PlanarRelativeDir -- | Possibly convert a heading into a Direction---that is, if the -- vector happens to be a unit vector in one of the cardinal directions. toDirection :: Heading -> Maybe Direction -- | Logic adapted from: -- https://gamedev.stackexchange.com/questions/49290/#comment213403_49300 nearestDirection :: Heading -> AbsoluteDir -- | Convert a Direction into a corresponding heading. Note that -- this only does something reasonable for DNorth, DSouth, -- DEast, and DWest---other Directions return the -- zero vector. fromDirection :: Direction -> Heading -- | Check if the direction is absolute (e.g. north or -- south). isCardinal :: Direction -> Bool -- | The cardinal direction north = V2 0 1. north :: Heading -- | The cardinal direction south = V2 0 (-1). south :: Heading -- | The cardinal direction east = V2 1 0. east :: Heading -- | The cardinal direction west = V2 (-1) 0. west :: Heading -- | Manhattan distance between world locations. manhattan :: Location -> Location -> Int32 -- | Euclidean distance between world locations. euclidean :: Location -> Location -> Double -- | Get elements that are in manhattan distance from location. -- --
--   >>> v2s i = [(p, manhattan origin p) | x <- [-i..i], y <- [-i..i], let p = Location x y]
--   
--   >>> v2s 0
--   [(P (V2 0 0),0)]
--   
--   >>> map (\i -> length (getElemsInArea origin i (Map.fromList $ v2s i))) [0..8]
--   [1,5,13,25,41,61,85,113,145]
--   
-- -- The last test is the sequence "Centered square numbers": -- https://oeis.org/A001844 getElemsInArea :: Location -> Int32 -> Map Location e -> [e] -- | An affine space is roughly a vector space in which we have forgotten -- or at least pretend to have forgotten the origin. -- --
--   a .+^ (b .-. a)  =  b@
--   (a .+^ u) .+^ v  =  a .+^ (u ^+^ v)@
--   (a .-. b) ^+^ v  =  (a .+^ v) .-. q@
--   
class Additive Diff p => Affine (p :: Type -> Type) where { type family Diff (p :: Type -> Type) :: Type -> Type; } -- | Get the difference between two points as a vector offset. (.-.) :: (Affine p, Num a) => p a -> p a -> Diff p a -- | Add a vector offset to a point. (.+^) :: (Affine p, Num a) => p a -> Diff p a -> p a -- | Subtract a vector offset from a point. (.-^) :: (Affine p, Num a) => p a -> Diff p a -> p a infixl 6 .-. infixl 6 .+^ infixl 6 .-^ -- | A handy wrapper to help distinguish points from vectors at the type -- level newtype Point (f :: Type -> Type) a P :: f a -> Point (f :: Type -> Type) a -- | Vector spaces have origins. origin :: forall (f :: Type -> Type) a. (Additive f, Num a) => Point f a instance Data.Aeson.Types.ToJSON.ToJSON (Linear.V2.V2 GHC.Int.Int32) instance Data.Aeson.Types.FromJSON.FromJSON (Linear.V2.V2 GHC.Int.Int32) instance Data.Aeson.Types.FromJSON.FromJSONKey (Linear.V2.V2 GHC.Int.Int32) instance Data.Aeson.Types.ToJSON.ToJSONKey (Linear.V2.V2 GHC.Int.Int32) instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Location.Location instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Location.Location -- | World coordinates. module Swarm.Game.World.Coords -- | World coordinates use (row,column) format, with the row increasing as -- we move down the screen. We use this format for indexing worlds -- internally, since it plays nicely with things like drawing the screen, -- and reading maps from configuration files. The locToCoords and -- coordsToLoc functions convert back and forth between this type -- and Location, which is used when presenting coordinates -- externally to the player. newtype Coords Coords :: (Int32, Int32) -> Coords [unCoords] :: Coords -> (Int32, Int32) -- | Convert an external (x,y) location to an internal Coords value. locToCoords :: Location -> Coords -- | Convert an internal Coords value to an external (x,y) location. coordsToLoc :: Coords -> Location -- | Represents the top-left and bottom-right coordinates of a bounding -- rectangle of cells in the world map type BoundsRectangle = (Coords, Coords) instance GHC.Generics.Generic Swarm.Game.World.Coords.Coords instance GHC.Ix.Ix Swarm.Game.World.Coords.Coords instance GHC.Show.Show Swarm.Game.World.Coords.Coords instance GHC.Classes.Ord Swarm.Game.World.Coords.Coords instance GHC.Classes.Eq Swarm.Game.World.Coords.Coords instance Control.Lens.Wrapped.Rewrapped Swarm.Game.World.Coords.Coords t instance Control.Lens.Wrapped.Wrapped Swarm.Game.World.Coords.Coords module Swarm.Game.Universe data SubworldName DefaultRootSubworld :: SubworldName SubworldName :: Text -> SubworldName renderWorldName :: SubworldName -> Text -- | The swarm universe consists of locations indexed by subworld. Not only -- is this datatype useful for planar (2D) coordinates, but is also used -- for named waypoints. data Cosmic a Cosmic :: SubworldName -> a -> Cosmic a [_subworld] :: Cosmic a -> SubworldName [_planar] :: Cosmic a -> a subworld :: forall a_a3lgg. Lens' (Cosmic a_a3lgg) SubworldName planar :: forall a_a3lgg a_a3lCq. Lens (Cosmic a_a3lgg) (Cosmic a_a3lCq) a_a3lgg a_a3lCq defaultCosmicLocation :: Cosmic Location data DistanceMeasure b Measurable :: b -> DistanceMeasure b InfinitelyFar :: DistanceMeasure b -- | Returns InfinitelyFar if not within the same subworld. cosmoMeasure :: (a -> a -> b) -> Cosmic a -> Cosmic a -> DistanceMeasure b offsetBy :: Cosmic Location -> V2 Int32 -> Cosmic Location instance GHC.Classes.Ord b => GHC.Classes.Ord (Swarm.Game.Universe.DistanceMeasure b) instance GHC.Classes.Eq b => GHC.Classes.Eq (Swarm.Game.Universe.DistanceMeasure b) instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.Universe.Cosmic a) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Universe.SubworldName instance GHC.Generics.Generic Swarm.Game.Universe.SubworldName instance GHC.Classes.Ord Swarm.Game.Universe.SubworldName instance GHC.Classes.Eq Swarm.Game.Universe.SubworldName instance GHC.Show.Show Swarm.Game.Universe.SubworldName instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Universe.Cosmic a) instance GHC.Generics.Generic (Swarm.Game.Universe.Cosmic a) instance GHC.Base.Functor Swarm.Game.Universe.Cosmic instance GHC.Classes.Ord a => GHC.Classes.Ord (Swarm.Game.Universe.Cosmic a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Swarm.Game.Universe.Cosmic a) instance GHC.Show.Show a => GHC.Show.Show (Swarm.Game.Universe.Cosmic a) instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Universe.SubworldName module Swarm.Game.Scenario.Topography.Area data AreaDimensions AreaDimensions :: Int32 -> Int32 -> AreaDimensions [rectWidth] :: AreaDimensions -> Int32 [rectHeight] :: AreaDimensions -> Int32 renderRectDimensions :: AreaDimensions -> String invertY :: V2 Int32 -> V2 Int32 -- | Incorporates an offset by -1, since the area is "inclusive" of the -- lower-right coordinate. Inverse of "cornersToArea". upperLeftToBottomRight :: AreaDimensions -> Location -> Location -- | Converts the displacement vector between the two diagonal corners of -- the rectangle into an AreaDimensions record. Adds one to both -- dimensions since the corner coordinates are "inclusive". Inverse of -- "upperLeftToBottomRight". cornersToArea :: Location -> Location -> AreaDimensions isEmpty :: AreaDimensions -> Bool getAreaDimensions :: [[a]] -> AreaDimensions module Swarm.Game.Scenario.Topography.Placement newtype StructureName StructureName :: Text -> StructureName -- | Orientation transformations are applied before translation. data Orientation Orientation :: AbsoluteDir -> Bool -> Orientation -- | e.g. For East, rotates 270 degrees. [up] :: Orientation -> AbsoluteDir -- | vertical flip, applied before rotation [flipped] :: Orientation -> Bool defaultOrientation :: Orientation -- | This is the point-wise equivalent of "applyOrientationTransform" reorientWaypoint :: Orientation -> AreaDimensions -> Location -> Location -- | affine transformation applyOrientationTransform :: Orientation -> [[a]] -> [[a]] data Placement Placement :: StructureName -> Location -> Orientation -> Placement [src] :: Placement -> StructureName [offset] :: Placement -> Location [orient] :: Placement -> Orientation instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Placement.StructureName instance GHC.Generics.Generic Swarm.Game.Scenario.Topography.Placement.StructureName instance GHC.Show.Show Swarm.Game.Scenario.Topography.Placement.StructureName instance GHC.Classes.Ord Swarm.Game.Scenario.Topography.Placement.StructureName instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Placement.StructureName instance GHC.Show.Show Swarm.Game.Scenario.Topography.Placement.Orientation instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Placement.Orientation instance GHC.Show.Show Swarm.Game.Scenario.Topography.Placement.Placement instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Placement.Placement instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Placement.Placement instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Placement.Orientation module Swarm.Game.Scenario.Topography.Navigation.Waypoint -- | Indicates which structure something came from for debugging purposes. data Originated a Originated :: Maybe Placement -> a -> Originated a [parent] :: Originated a -> Maybe Placement [value] :: Originated a -> a newtype WaypointName WaypointName :: Text -> WaypointName -- | Metadata about a waypoint data WaypointConfig WaypointConfig :: WaypointName -> Bool -> WaypointConfig [wpName] :: WaypointConfig -> WaypointName -- | Enforce global uniqueness of this waypoint [wpUnique] :: WaypointConfig -> Bool parseWaypointConfig :: Object -> Parser WaypointConfig -- | A parent world shouldn't have to know the exact layout of a subworld -- to specify where exactly a portal will deliver a robot to within the -- subworld. Therefore, we define named waypoints in the subworld and the -- parent world must reference them by name, rather than by coordinate. data Waypoint Waypoint :: WaypointConfig -> Location -> Waypoint [wpConfig] :: Waypoint -> WaypointConfig [wpLoc] :: Waypoint -> Location -- | Basically "fmap" for the Location field modifyLocation :: (Location -> Location) -> Waypoint -> Waypoint -- | Translation by a vector offsetWaypoint :: V2 Int32 -> Waypoint -> Waypoint instance GHC.Base.Functor Swarm.Game.Scenario.Topography.Navigation.Waypoint.Originated instance GHC.Classes.Eq a => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.Navigation.Waypoint.Originated a) instance GHC.Show.Show a => GHC.Show.Show (Swarm.Game.Scenario.Topography.Navigation.Waypoint.Originated a) instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointName instance GHC.Generics.Generic Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointName instance GHC.Classes.Ord Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointName instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointName instance GHC.Show.Show Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointName instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointConfig instance GHC.Show.Show Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointConfig instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Navigation.Waypoint.Waypoint instance GHC.Show.Show Swarm.Game.Scenario.Topography.Navigation.Waypoint.Waypoint instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Navigation.Waypoint.Waypoint instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Navigation.Waypoint.WaypointConfig module Swarm.Game.Scenario.Topography.Navigation.Portal type WaypointMap = Map WaypointName (NonEmpty Location) data AnnotatedDestination a AnnotatedDestination :: Bool -> Direction -> Cosmic a -> AnnotatedDestination a [enforceConsistency] :: AnnotatedDestination a -> Bool [reorientation] :: AnnotatedDestination a -> Direction [destination] :: AnnotatedDestination a -> Cosmic a -- | Parameterized on waypoint dimensionality -- (additionalDimension) and on the portal location -- specification method (portalExitLoc). == -- additionalDimension As a member of the -- WorldDescription, waypoints are only known within a a single -- subworld, so additionalDimension is Identity for the -- map of waypoint names to planar locations. At the Scenario level, in -- contrast, we have access to all subworlds, so we nest this map to -- planar locations in additional mapping layer by subworld. == -- portalExitLoc At the subworld parsing level, we only can -- obtain the planar location for portal entrances, but the -- exits remain as waypoint names. At the Scenario-parsing level, -- we finally have access to the waypoints across all subworlds, and can -- therefore translate the portal exits to concrete planar locations. data Navigation additionalDimension portalExitLoc Navigation :: additionalDimension WaypointMap -> Map (Cosmic Location) (AnnotatedDestination portalExitLoc) -> Navigation additionalDimension portalExitLoc -- | Note that waypoints defined at the "root" level are still relative to -- the top-left corner of the map rectangle; they are not in absolute -- world coordinates (as with applying the "ul" offset). [waypoints] :: Navigation additionalDimension portalExitLoc -> additionalDimension WaypointMap [portals] :: Navigation additionalDimension portalExitLoc -> Map (Cosmic Location) (AnnotatedDestination portalExitLoc) data PortalExit PortalExit :: WaypointName -> Maybe SubworldName -> PortalExit [exit] :: PortalExit -> WaypointName -- | Note: Nothing indicates that references a waypoint within the -- same subworld. [subworldName] :: PortalExit -> Maybe SubworldName data Portal Portal :: WaypointName -> PortalExit -> Bool -> PlanarRelativeDir -> Portal [entrance] :: Portal -> WaypointName [exitInfo] :: Portal -> PortalExit [consistent] :: Portal -> Bool [reorient] :: Portal -> PlanarRelativeDir failUponDuplication :: (MonadFail m, Show a, Show b) => Text -> Map a (NonEmpty b) -> m () failWaypointLookup :: MonadFail m => WaypointName -> Maybe a -> m a -- | The following constraints must be enforced: * portals based on plural -- waypoint multiplicity can have multiple entrances but only a single -- exit * no two portals share the same entrance location * waypoint -- uniqueness within a subworld when the unique flag is -- specified -- --

Data flow:

-- -- Waypoints are defined within a subworld and are namespaced by it. -- Optional intra-subworld uniqueness of Waypoints is enforced at -- WorldDescription parse time. Portals are declared within a subworld. -- The portal entrance must be a waypoint within this subworld. They can -- reference waypoints in other subworlds as exits, but these references -- are not validated until the Scenario parse level. -- -- validatePartialNavigation :: (MonadFail m, Traversable t) => SubworldName -> Location -> [Originated Waypoint] -> t Portal -> m (Navigation Identity WaypointName) validatePortals :: MonadFail m => Navigation (Map SubworldName) WaypointName -> m (Map (Cosmic Location) (AnnotatedDestination Location)) -- | A portal can be marked as "consistent", meaning that it represents a -- conventional physical passage rather than a "magical" teleportation. -- -- If there exists more than one "consistent" portal between the same two -- subworlds, then the portal locations must be spatially consistent -- between the two worlds. I.e. the space comprising the two subworlds -- forms a "conservative vector field". -- -- Verifying this is simple: For all of the portals between Subworlds A -- and B: * The coordinates of all "consistent" portal locations in -- Subworld A are subtracted from the corresponding coordinates in -- Subworld B. It does not matter which are exits vs. entrances. * The -- resulting "vector" from every pair must be equal. ensureSpatialConsistency :: MonadFail m => [(Cosmic Location, AnnotatedDestination Location)] -> m () -- | An implementation of sequenceA for Signed that does not -- require an Applicative instance for the inner Functor. -- --

Discussion

-- -- Compare to the Traversable instance of Signed: -- instance Traversable Signed where traverse f (Positive x) = Positive -- $ f x traverse f (Negative x) = Negative $ f x -- -- if we were to substitute id for f: traverse id (Positive -- x) = Positive $ id x traverse id (Negative x) = Negative -- $ id x our implementation essentially becomes -- traverse id. -- -- However, we cannot simply write our implementation as traverse -- id, because the traverse function has an -- Applicative constraint, which is superfluous for our purpose. -- -- Perhaps there is an opportunity to invent a typeclass for datatypes -- which consist exclusively of unary (or more ambitiously, non-nullary?) -- data constructors, for which a less-constrained sequence -- function could be automatically derived. Compare to the -- Comonad class and its extract function. sequenceSigned :: Functor f => Signed (f a) -> f (Signed a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.Navigation.Portal.AnnotatedDestination a) instance GHC.Show.Show a => GHC.Show.Show (Swarm.Game.Scenario.Topography.Navigation.Portal.AnnotatedDestination a) instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Navigation.Portal.PortalExit instance GHC.Generics.Generic Swarm.Game.Scenario.Topography.Navigation.Portal.PortalExit instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Navigation.Portal.PortalExit instance GHC.Show.Show Swarm.Game.Scenario.Topography.Navigation.Portal.PortalExit instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.Navigation.Portal.Portal instance GHC.Show.Show Swarm.Game.Scenario.Topography.Navigation.Portal.Portal instance (GHC.Classes.Eq (a Swarm.Game.Scenario.Topography.Navigation.Portal.WaypointMap), GHC.Classes.Eq b) => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.Navigation.Portal.Navigation a b) instance (GHC.Show.Show (a Swarm.Game.Scenario.Topography.Navigation.Portal.WaypointMap), GHC.Show.Show b) => GHC.Show.Show (Swarm.Game.Scenario.Topography.Navigation.Portal.Navigation a b) instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Topography.Navigation.Portal.Portal -- | Definitions of all possible achievements. module Swarm.Game.Achievement.Definitions data ExpectedEffort Trivial :: ExpectedEffort Easy :: ExpectedEffort Moderate :: ExpectedEffort Gruelling :: ExpectedEffort data Quotation Quotation :: Text -> Text -> Quotation [attribution] :: Quotation -> Text [content] :: Quotation -> Text data FlavorText Freeform :: Text -> FlavorText FTQuotation :: Quotation -> FlavorText data AchievementInfo AchievementInfo :: Text -> Maybe FlavorText -> Text -> ExpectedEffort -> Bool -> AchievementInfo -- | Guidelines: * prefer puns, pop culture references, etc. * should be a -- phrase in Title Case. * For achievements that are "obfuscated", this -- can be a vague "clue" as to what the attainment entails. [title] :: AchievementInfo -> Text -- | Explain the reference, e.g. in the form of a full quote from a movie, -- or something you might find in a fortune cookie [humorousElaboration] :: AchievementInfo -> Maybe FlavorText -- | Precisely what must be done to obtain this achievement. [attainmentProcess] :: AchievementInfo -> Text [effort] :: AchievementInfo -> ExpectedEffort -- | Hides the attainment process until after the achievement is attained. -- Best when the title + elaboration constitute a good clue. [isObfuscated] :: AchievementInfo -> Bool data CategorizedAchievement GlobalAchievement :: GlobalAchievement -> CategorizedAchievement GameplayAchievement :: GameplayAchievement -> CategorizedAchievement categorizedAchievementJsonOptions :: Options -- | Achievements that entail some aggregate of actions across scenarios data GlobalAchievement CompletedSingleTutorial :: GlobalAchievement CompletedAllTutorials :: GlobalAchievement LookedAtAboutScreen :: GlobalAchievement -- | Achievements obtained while playing a single scenario data GameplayAchievement CraftedBitcoin :: GameplayAchievement RobotIntoWater :: GameplayAchievement AttemptSelfDestructBase :: GameplayAchievement DestroyedBase :: GameplayAchievement LoseScenario :: GameplayAchievement GetDisoriented :: GameplayAchievement listAchievements :: [CategorizedAchievement] instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Definitions.ExpectedEffort instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Definitions.ExpectedEffort instance GHC.Generics.Generic Swarm.Game.Achievement.Definitions.ExpectedEffort instance GHC.Enum.Enum Swarm.Game.Achievement.Definitions.ExpectedEffort instance GHC.Enum.Bounded Swarm.Game.Achievement.Definitions.ExpectedEffort instance GHC.Show.Show Swarm.Game.Achievement.Definitions.ExpectedEffort instance GHC.Classes.Ord Swarm.Game.Achievement.Definitions.ExpectedEffort instance GHC.Classes.Eq Swarm.Game.Achievement.Definitions.ExpectedEffort instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Definitions.Quotation instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Definitions.Quotation instance GHC.Generics.Generic Swarm.Game.Achievement.Definitions.Quotation instance GHC.Show.Show Swarm.Game.Achievement.Definitions.Quotation instance GHC.Classes.Eq Swarm.Game.Achievement.Definitions.Quotation instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Definitions.FlavorText instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Definitions.FlavorText instance GHC.Generics.Generic Swarm.Game.Achievement.Definitions.FlavorText instance GHC.Show.Show Swarm.Game.Achievement.Definitions.FlavorText instance GHC.Classes.Eq Swarm.Game.Achievement.Definitions.FlavorText instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Definitions.AchievementInfo instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Definitions.AchievementInfo instance GHC.Generics.Generic Swarm.Game.Achievement.Definitions.AchievementInfo instance GHC.Show.Show Swarm.Game.Achievement.Definitions.AchievementInfo instance GHC.Classes.Eq Swarm.Game.Achievement.Definitions.AchievementInfo instance GHC.Generics.Generic Swarm.Game.Achievement.Definitions.GlobalAchievement instance GHC.Enum.Enum Swarm.Game.Achievement.Definitions.GlobalAchievement instance GHC.Enum.Bounded Swarm.Game.Achievement.Definitions.GlobalAchievement instance GHC.Show.Show Swarm.Game.Achievement.Definitions.GlobalAchievement instance GHC.Classes.Ord Swarm.Game.Achievement.Definitions.GlobalAchievement instance GHC.Classes.Eq Swarm.Game.Achievement.Definitions.GlobalAchievement instance GHC.Generics.Generic Swarm.Game.Achievement.Definitions.GameplayAchievement instance GHC.Enum.Enum Swarm.Game.Achievement.Definitions.GameplayAchievement instance GHC.Enum.Bounded Swarm.Game.Achievement.Definitions.GameplayAchievement instance GHC.Show.Show Swarm.Game.Achievement.Definitions.GameplayAchievement instance GHC.Classes.Ord Swarm.Game.Achievement.Definitions.GameplayAchievement instance GHC.Classes.Eq Swarm.Game.Achievement.Definitions.GameplayAchievement instance GHC.Generics.Generic Swarm.Game.Achievement.Definitions.CategorizedAchievement instance GHC.Show.Show Swarm.Game.Achievement.Definitions.CategorizedAchievement instance GHC.Classes.Ord Swarm.Game.Achievement.Definitions.CategorizedAchievement instance GHC.Classes.Eq Swarm.Game.Achievement.Definitions.CategorizedAchievement instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Definitions.CategorizedAchievement instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Definitions.CategorizedAchievement instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Definitions.GameplayAchievement instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Definitions.GameplayAchievement instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Definitions.GlobalAchievement instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Definitions.GlobalAchievement -- | Flavor text about all defined achievements. module Swarm.Game.Achievement.Description describe :: CategorizedAchievement -> AchievementInfo -- | Metadata about achievements that the player has obtained module Swarm.Game.Achievement.Attainment data Attainment Attainment :: CategorizedAchievement -> Maybe FilePath -> ZonedTime -> Attainment [_achievement] :: Attainment -> CategorizedAchievement -- | from which scenario was it obtained? [_maybeScenarioPath] :: Attainment -> Maybe FilePath [_obtainedAt] :: Attainment -> ZonedTime obtainedAt :: Lens' Attainment ZonedTime maybeScenarioPath :: Lens' Attainment (Maybe FilePath) achievement :: Lens' Attainment CategorizedAchievement achievementJsonOptions :: Options instance GHC.Classes.Eq Swarm.Game.Achievement.Attainment.Attainment instance GHC.Classes.Ord Swarm.Game.Achievement.Attainment.Attainment instance GHC.Base.Semigroup Swarm.Game.Achievement.Attainment.Attainment instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Achievement.Attainment.Attainment instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Achievement.Attainment.Attainment instance GHC.Generics.Generic Swarm.Game.Achievement.Attainment.Attainment -- | Custom extension of Semigroup to Monoid that adds -- identity + annihilator elements. module Swarm.Util.Erasable -- | Extend a semigroup to a monoid by adding an identity (ENothing) -- and an annihilator (EErase). That is, -- -- -- -- This allows us to "erase" previous values by combining with -- EErase. The erasableToMaybe function turns an -- Erasable into a Maybe by collapsing ENothing and -- EErase both back into Nothing. data Erasable e ENothing :: Erasable e EErase :: Erasable e EJust :: e -> Erasable e -- | Generic eliminator for Erasable values. erasable :: a -> a -> (e -> a) -> Erasable e -> a -- | Convert an Erasable value to Maybe, turning both -- ENothing and EErase into Nothing. erasableToMaybe :: Erasable e -> Maybe e -- | Inject a Maybe value into Erasable using ENothing -- and EJust. maybeToErasable :: Maybe e -> Erasable e instance GHC.Base.Functor Swarm.Util.Erasable.Erasable instance GHC.Classes.Ord e => GHC.Classes.Ord (Swarm.Util.Erasable.Erasable e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Swarm.Util.Erasable.Erasable e) instance GHC.Show.Show e => GHC.Show.Show (Swarm.Util.Erasable.Erasable e) instance GHC.Base.Semigroup e => GHC.Base.Semigroup (Swarm.Util.Erasable.Erasable e) instance GHC.Base.Semigroup e => GHC.Base.Monoid (Swarm.Util.Erasable.Erasable e) -- | Lens generation utilities. module Swarm.Util.Lens -- | Generate lenses but with no type signatures, so we can explicitly give -- type signatures and attach custom Haddock documentation to them. makeLensesNoSigs :: Name -> DecsQ -- | Generate lenses for the fields of a record type (with no type -- signatures), except for a given list of excluded fields. -- -- Especially useful in conjunction with the design pattern described in -- https://byorgey.wordpress.com/2021/09/17/automatically-updated-cached-views-with-lens/ makeLensesExcluding :: [Name] -> Name -> DecsQ module Swarm.TUI.Model.Repl -- | An item in the REPL history. data REPLHistItem -- | Something entered by the user. REPLEntry :: Text -> REPLHistItem -- | A response printed by the system. REPLOutput :: Text -> REPLHistItem -- | Get the text of REPL input/output. replItemText :: REPLHistItem -> Text -- | Useful helper function to filter out REPL output. isREPLEntry :: REPLHistItem -> Bool -- | Useful helper function to only get user input text. getREPLEntry :: REPLHistItem -> Maybe Text -- | History of the REPL with indices (0 is first entry) to the current -- line and to the first entry since loading saved history. We also -- (ab)use the length of the REPL as the index of current input line, -- since that number is one past the index of last entry. data REPLHistory -- | The current index in the REPL history (if the user is going back -- through the history using up/down keys). replIndex :: Lens' REPLHistory Int -- | Current number lines of the REPL history - (ab)used as index of input -- buffer. replLength :: REPLHistory -> Int -- | Note: Instead of adding a dedicated field to the REPLHistory record, -- an early attempt entailed checking for: -- -- _replIndex > _replStart -- -- However, executing an initial script causes a REPLOutput to be -- appended to the REPL history, which increments the replIndex, and thus -- makes the Index greater than the Start even though the player has -- input not commands into the REPL. -- -- Therefore, a dedicated boolean is introduced into REPLHistory which -- simply latches True when the user has input a command. -- -- An alternative is described here: -- https://github.com/swarm-game/swarm/pull/974#discussion_r1112380380 replHasExecutedManualInput :: Lens' REPLHistory Bool -- | Sequence of REPL inputs and outputs, oldest entry is leftmost. replSeq :: Lens' REPLHistory (Seq REPLHistItem) -- | Create new REPL history (i.e. from loaded history file lines). newREPLHistory :: [REPLHistItem] -> REPLHistory -- | Add new REPL input - the index must have been pointing one past the -- last element already, so we increment it to keep it that way. addREPLItem :: REPLHistItem -> REPLHistory -> REPLHistory -- | Point the start of REPL history after current last line. See -- replStart. restartREPLHistory :: REPLHistory -> REPLHistory -- | Get the latest N items in history, starting with the oldest one. -- -- This is used to show previous REPL lines in UI, so we need the items -- sorted in the order they were entered and will be drawn top to bottom. getLatestREPLHistoryItems :: Int -> REPLHistory -> [REPLHistItem] moveReplHistIndex :: TimeDir -> Text -> REPLHistory -> REPLHistory getCurrentItemText :: REPLHistory -> Maybe Text replIndexIsAtInput :: REPLHistory -> Bool data TimeDir Newer :: TimeDir Older :: TimeDir -- | This data type tells us how to interpret the text typed by the player -- at the prompt (which is stored in Editor). data REPLPrompt -- | Interpret the prompt text as a regular command. The list is for -- potential completions, which we can cycle through by hitting Tab -- repeatedly CmdPrompt :: [Text] -> REPLPrompt -- | Interpret the prompt text as "search this text in history" SearchPrompt :: REPLHistory -> REPLPrompt -- | Given some text, removes the REPLEntry within REPLHistory which is -- equal to that. This is used when the user enters in search mode and -- want to traverse the history. If a command has been used many times, -- the history will be populated with it causing the effect that search -- command always finds the same command. removeEntry :: Text -> REPLHistory -> REPLHistory data REPLState -- | What is being done with user input to the REPL panel? data ReplControlMode -- | The user is typing at the REPL. Typing :: ReplControlMode -- | The user is driving the base using piloting mode. Piloting :: ReplControlMode -- | A custom user key handler is processing user input. Handling :: ReplControlMode -- | The way we interpret text typed by the player in the REPL prompt. replPromptType :: Lens' REPLState REPLPrompt -- | The prompt where the user can type input at the REPL. replPromptEditor :: Lens' REPLState (Editor Text Name) -- | Convinience lens to get text from editor and replace it with new one -- that has the provided text. replPromptText :: Lens' REPLState Text -- | Whether the prompt text is a valid Term. replValid :: Lens' REPLState Bool -- | The last thing the user has typed which isn't part of the history. -- This is used to restore the repl form after the user visited the -- history. replLast :: Lens' REPLState Text -- | The type of the current REPL input which should be displayed to the -- user (if any). replType :: Lens' REPLState (Maybe Polytype) -- | The current REPL control mode, i.e. how user input to the REPL panel -- is being handled. replControlMode :: Lens' REPLState ReplControlMode -- | History of things the user has typed at the REPL, interleaved with -- outputs the system has generated. replHistory :: Lens' REPLState REPLHistory newREPLEditor :: Text -> Editor Text Name initREPLState :: REPLHistory -> REPLState defaultPrompt :: REPLPrompt -- | Get the last REPLEntry in REPLHistory matching the given text lastEntry :: Text -> REPLHistory -> Maybe Text instance GHC.Show.Show Swarm.TUI.Model.Repl.TimeDir instance GHC.Classes.Ord Swarm.TUI.Model.Repl.TimeDir instance GHC.Classes.Eq Swarm.TUI.Model.Repl.TimeDir instance GHC.Enum.Enum Swarm.TUI.Model.Repl.ReplControlMode instance GHC.Enum.Bounded Swarm.TUI.Model.Repl.ReplControlMode instance GHC.Classes.Eq Swarm.TUI.Model.Repl.ReplControlMode instance GHC.Read.Read Swarm.TUI.Model.Repl.REPLHistItem instance GHC.Show.Show Swarm.TUI.Model.Repl.REPLHistItem instance GHC.Classes.Ord Swarm.TUI.Model.Repl.REPLHistItem instance GHC.Classes.Eq Swarm.TUI.Model.Repl.REPLHistItem instance GHC.Show.Show Swarm.TUI.Model.Repl.REPLHistory instance Servant.Docs.Internal.ToSample Swarm.TUI.Model.Repl.REPLHistItem instance Data.Aeson.Types.ToJSON.ToJSON Swarm.TUI.Model.Repl.REPLHistItem -- | Parsing utilities for Swarm. module Swarm.Util.Parse -- | Run a parser "fully", consuming leading whitespace and ensuring that -- the parser extends all the way to eof. fully :: MonadParsec e s f => f () -> f a -> f a -- | Run a parser "fully", consuming leading whitespace (including the -- possibility that the input is nothing but whitespace) and ensuring -- that the parser extends all the way to eof. fullyMaybe :: MonadParsec e s f => f () -> f a -> f (Maybe a) -- | Parser for the Swarm language. Note, you probably don't want to use -- this directly, unless there is a good reason to parse a term without -- also type checking it; use processTerm instead, which parses, -- typechecks, elaborates, and capability checks a term all at once. module Swarm.Language.Parse -- | List of reserved words that cannot be used as variable names. reservedWords :: [Text] type Parser = ReaderT Antiquoting (Parsec Void Text) -- | Parse a Swarm language polytype, which starts with an optional -- quanitifation (forall followed by one or more variables and a -- period) followed by a type. Note that anything accepted by -- parseType is also accepted by parsePolytype. parsePolytype :: Parser Polytype -- | Parse a Swarm language (mono)type. parseType :: Parser Type -- | Parse a Swarm language term. parseTerm :: Parser Syntax -- | Precedences and parsers of binary operators. -- --
--   >>> Map.map length binOps
--   fromList [(0,1),(2,1),(3,1),(4,6),(6,3),(7,2),(8,1)]
--   
binOps :: Map Int [Operator Parser Syntax] -- | Precedences and parsers of unary operators (currently only -- Neg). -- --
--   >>> Map.map length unOps
--   fromList [(7,1)]
--   
unOps :: Map Int [Operator Parser Syntax] -- | Run a parser on some input text, returning either the result or a -- pretty-printed parse error message. runParser :: Parser a -> Text -> Either Text a -- | A utility for running a parser in an arbitrary MonadFail (which -- is going to be the TemplateHaskell Q monad --- see -- Swarm.Language.Parse.QQ), with a specified source position. runParserTH :: (Monad m, MonadFail m) => (String, Int, Int) -> Parser a -> String -> m a -- | Parse some input Text completely as a Term, consuming -- leading whitespace and ensuring the parsing extends all the way to the -- end of the input Text. Returns either the resulting Term -- (or Nothing if the input was only whitespace) or a -- pretty-printed parse error message. readTerm :: Text -> Either Text (Maybe Syntax) -- | A lower-level readTerm which returns the megaparsec bundle -- error for precise error reporting. readTerm' :: Text -> Either ParserError (Maybe Syntax) -- | A utility for converting a ParserError into a one line message: -- line-nr: error-msg showShortError :: ParserError -> String -- | A utility for converting a ParseError into a range and error message. showErrorPos :: ParserError -> ((Int, Int), (Int, Int), Text) -- | A utility for converting a SrcLoc into a range getLocRange :: Text -> (Int, Int) -> ((Int, Int), (Int, Int)) unTuple :: Syntax' ty -> [Syntax' ty] instance GHC.Show.Show Swarm.Language.Parse.Antiquoting instance GHC.Classes.Ord Swarm.Language.Parse.Antiquoting instance GHC.Classes.Eq Swarm.Language.Parse.Antiquoting instance GHC.Show.Show Swarm.Language.Parse.Stmt -- | A quasiquoter for Swarm polytypes. module Swarm.Language.Parse.QQ -- | A quasiquoter for Swarm polytypes, so we can conveniently write them -- down using concrete syntax and have them parsed into abstract syntax -- at compile time. This is used, for example, in writing down the -- concrete types of constants (see Swarm.Language.Typecheck). tyQ :: QuasiQuoter -- | Type inference for the Swarm language. For the approach used here, see -- https://byorgey.wordpress.com/2021/09/08/implementing-hindley-milner-with-the-unification-fd-library/ -- . module Swarm.Language.Typecheck -- | A type error along with various contextual information to help us -- generate better error messages. data ContextualTypeErr CTE :: SrcLoc -> TCStack -> TypeErr -> ContextualTypeErr [cteSrcLoc] :: ContextualTypeErr -> SrcLoc [cteStack] :: ContextualTypeErr -> TCStack [cteTypeErr] :: ContextualTypeErr -> TypeErr -- | Errors that can occur during type checking. The idea is that each -- error carries information that can be used to help explain what went -- wrong (though the amount of information carried can and should be very -- much improved in the future); errors can then separately be -- pretty-printed to display them to the user. data TypeErr -- | An undefined variable was encountered. UnboundVar :: Var -> TypeErr -- | A Skolem variable escaped its local context. EscapedSkolem :: Var -> TypeErr -- | Occurs check failure, i.e. infinite type. Infinite :: IntVar -> UType -> TypeErr -- | Error generated by the unifier. UnifyErr :: TypeF UType -> TypeF UType -> TypeErr -- | Type mismatch caught by unifyCheck. The given term was expected -- to have a certain type, but has a different type instead. Mismatch :: Maybe Syntax -> TypeJoin -> TypeErr -- | Lambda argument type mismatch. LambdaArgMismatch :: TypeJoin -> TypeErr -- | Record field mismatch, i.e. based on the expected type we were -- expecting a record with certain fields, but found one with a different -- field set. FieldsMismatch :: Join (Set Var) -> TypeErr -- | A definition was encountered not at the top level. DefNotTopLevel :: Term -> TypeErr -- | A term was encountered which we cannot infer the type of. This should -- never happen. CantInfer :: Term -> TypeErr -- | We can't infer the type of a record projection r.x if we -- don't concretely know the type of the record r. CantInferProj :: Term -> TypeErr -- | An attempt to project out a nonexistent field UnknownProj :: Var -> Term -> TypeErr -- | An invalid argument was provided to atomic. InvalidAtomic :: InvalidAtomicReason -> Term -> TypeErr -- | Some unification variables ended up in a type, probably due to -- impredicativity. See -- https://github.com/swarm-game/swarm/issues/351 . Impredicative :: TypeErr -- | Various reasons the body of an atomic might be invalid. data InvalidAtomicReason -- | The argument has too many tangible commands. TooManyTicks :: Int -> InvalidAtomicReason -- | The argument uses some way to duplicate code: def, -- let, or lambda. AtomicDupingThing :: InvalidAtomicReason -- | The argument referred to a variable with a non-simple type. NonSimpleVarType :: Var -> UPolytype -> InvalidAtomicReason -- | The argument had a nested atomic NestedAtomic :: InvalidAtomicReason -- | The argument contained a long command LongConst :: InvalidAtomicReason -- | The source of a type during typechecking. data Source -- | An expected type that was "pushed down" from the context. Expected :: Source -- | An actual/inferred type that was "pulled up" from a term. Actual :: Source -- | Generic eliminator for Source. Choose the first argument if the -- Source is Expected, and the second argument if -- Actual. withSource :: Source -> a -> a -> a -- | A "join" where an expected thing meets an actual thing. data Join a -- | Convert a Join into a pair of (expected, actual). getJoin :: Join a -> (a, a) -- | A frame to keep track of something we were in the middle of doing -- during typechecking. data TCFrame -- | Checking a definition. [TCDef] :: Var -> TCFrame -- | Inferring the LHS of a bind. [TCBindL] :: TCFrame -- | Inferring the RHS of a bind. [TCBindR] :: TCFrame -- | A typechecking stack frame together with the relevant SrcLoc. data LocatedTCFrame LocatedTCFrame :: SrcLoc -> TCFrame -> LocatedTCFrame -- | A typechecking stack keeps track of what we are currently in the -- middle of doing during typechecking. type TCStack = [LocatedTCFrame] -- | Push a frame on the typechecking stack within a local TC -- computation. withFrame :: SrcLoc -> TCFrame -> TC a -> TC a -- | Get the current typechecking stack. getTCStack :: TC TCStack -- | The concrete monad used for type checking. IntBindingT is a -- monad transformer provided by the unification-fd library -- which supports various operations such as generating fresh variables -- and unifying things. type TC = ReaderT UCtx (ReaderT TCStack (ExceptT ContextualTypeErr (IntBindingT TypeF Identity))) -- | Run a top-level inference computation, returning either a -- TypeErr or a fully resolved TModule. runTC :: TCtx -> TC UModule -> Either ContextualTypeErr TModule -- | Generate a fresh unification variable. fresh :: TC UType -- | Perform a substitution over a UType, substituting for both type -- and unification variables. Note that since UTypes do not have -- any binding constructs, we don't have to worry about ignoring bound -- variables; all variables in a UType are free. substU :: Map (Either Var IntVar) UType -> UType -> UType -- | unify t expTy actTy ensures that the given two types are -- equal. If we know the actual term t which is supposed to have -- these types, we can use it to generate better error messages. -- -- We first do a quick-and-dirty check to see whether we know for sure -- the types either are or cannot be equal, generating an equality -- constraint for the unifier as a last resort. unify :: Maybe Syntax -> TypeJoin -> TC UType -- | unification-fd provides a function applyBindings which -- fully substitutes for any bound unification variables (for efficiency, -- it does not perform such substitution as it goes along). The -- HasBindings class is for anything which has unification -- variables in it and to which we can usefully apply -- applyBindings. class HasBindings u applyBindings :: HasBindings u => u -> TC u -- | To instantiate a UPolytype, we generate a fresh -- unification variable for each variable bound by the Forall, and -- then substitute them throughout the type. instantiate :: UPolytype -> TC UType -- | skolemize is like instantiate, except we substitute -- fresh type variables instead of unification variables. Such -- variables cannot unify with anything other than themselves. This is -- used when checking something with a polytype explicitly specified by -- the user. skolemize :: UPolytype -> TC UType -- | generalize is the opposite of instantiate: add a -- Forall which closes over all free type and unification -- variables. -- -- Pick nice type variable names instead of reusing whatever fresh names -- happened to be used for the free variables. generalize :: UType -> TC UPolytype -- | Top-level type inference function: given a context of definition types -- and a top-level term, either return a type error or its type as a -- TModule. inferTop :: TCtx -> Syntax -> Either ContextualTypeErr TModule -- | Infer the signature of a top-level expression which might contain -- definitions. inferModule :: Syntax -> TC UModule -- | Infer the type of a term which does not contain definitions, returning -- a type-annotated term. -- -- The only cases explicitly handled in infer are those where -- pushing an expected type down into the term can't possibly help, e.g. -- most primitives, function application, and binds. -- -- For most everything else we prefer check because it can often -- result in better and more localized type error messages. infer :: Syntax -> TC (Syntax' UType) -- | Infer the type of a constant. inferConst :: Const -> Polytype -- | check t ty checks that t has type ty, -- returning a type-annotated AST if so. -- -- We try to stay in checking mode as far as possible, decomposing the -- expected type as we go and pushing it through the recursion. check :: Syntax -> UType -> TC (Syntax' UType) -- | A simple type is a sum or product of base types. isSimpleUType :: UType -> Bool instance GHC.Show.Show Swarm.Language.Typecheck.TCFrame instance GHC.Show.Show Swarm.Language.Typecheck.LocatedTCFrame instance GHC.Enum.Enum Swarm.Language.Typecheck.Source instance GHC.Enum.Bounded Swarm.Language.Typecheck.Source instance GHC.Classes.Ord Swarm.Language.Typecheck.Source instance GHC.Classes.Eq Swarm.Language.Typecheck.Source instance GHC.Show.Show Swarm.Language.Typecheck.Source instance GHC.Show.Show Swarm.Language.Typecheck.InvalidAtomicReason instance GHC.Show.Show Swarm.Language.Typecheck.TypeErr instance GHC.Show.Show Swarm.Language.Typecheck.ContextualTypeErr instance GHC.Classes.Ord Control.Unification.IntVar.IntVar instance Swarm.Language.Typecheck.FreeVars Swarm.Language.Types.UType instance Swarm.Language.Typecheck.FreeVars t => Swarm.Language.Typecheck.FreeVars (Swarm.Language.Types.Poly t) instance Swarm.Language.Typecheck.FreeVars Swarm.Language.Types.UCtx instance Swarm.Language.Typecheck.HasBindings Swarm.Language.Types.UType instance Swarm.Language.Typecheck.HasBindings Swarm.Language.Types.UPolytype instance Swarm.Language.Typecheck.HasBindings Swarm.Language.Types.UCtx instance (Swarm.Language.Typecheck.HasBindings u, Data.Data.Data u) => Swarm.Language.Typecheck.HasBindings (Swarm.Language.Syntax.Term' u) instance (Swarm.Language.Typecheck.HasBindings u, Data.Data.Data u) => Swarm.Language.Typecheck.HasBindings (Swarm.Language.Syntax.Syntax' u) instance Swarm.Language.Typecheck.HasBindings Swarm.Language.Module.UModule instance Control.Unification.Types.Fallible Swarm.Language.Types.TypeF Control.Unification.IntVar.IntVar Swarm.Language.Typecheck.ContextualTypeErr instance GHC.Show.Show a => GHC.Show.Show (Swarm.Language.Typecheck.Join a) -- | Pretty-printing for the Swarm language. module Swarm.Language.Pretty -- | Type class for things that can be pretty-printed, given a precedence -- level of their context. class PrettyPrec a prettyPrec :: PrettyPrec a => Int -> a -> Doc ann -- | Pretty-print a thing, with a context precedence level of zero. ppr :: PrettyPrec a => a -> Doc ann -- | Render a pretty-printed document as Text. docToText :: Doc a -> Text -- | Pretty-print something and render it as Text. prettyText :: PrettyPrec a => a -> Text -- | Render a pretty-printed document as a String. docToString :: Doc a -> String -- | Pretty-print something and render it as a String. prettyString :: PrettyPrec a => a -> String -- | Optionally surround a document with parentheses depending on the -- Bool argument. pparens :: Bool -> Doc ann -> Doc ann -- | Surround a document with backticks. bquote :: Doc ann -> Doc ann -- | Turn a Show instance into a Doc, lowercasing it in the -- process. prettyShowLow :: Show a => a -> Doc ann data BulletList i BulletList :: (forall a. Doc a) -> [i] -> BulletList i [bulletListHeader] :: BulletList i -> forall a. Doc a [bulletListItems] :: BulletList i -> [i] -- | We can use the Wildcard value to replace unification variables -- when we don't care about them, e.g. to print out the shape of a type -- like (_ -> _) * _ data Wildcard Wildcard :: Wildcard prettyBinding :: (Pretty a, PrettyPrec b) => (a, b) -> Doc ann prettyEquality :: (Pretty a, PrettyPrec b) => (a, Maybe b) -> Doc ann prettyTuple :: Term -> Doc a prettyPrecApp :: Int -> Term -> Term -> Doc a appliedTermPrec :: Term -> Int -- | Format a ContextualTypeError for the user and render it as -- Text. prettyTypeErrText :: Text -> ContextualTypeErr -> Text -- | Format a ContextualTypeError for the user. prettyTypeErr :: Text -> ContextualTypeErr -> Doc ann -- | Given a type and its source, construct an appropriate description of -- it to go in a type mismatch error message. typeDescription :: Source -> UType -> Doc a -- | Check whether a type contains any unification variables at all. hasAnyUVars :: UType -> Bool -- | Check whether a type consists of a top-level type constructor -- immediately applied to unification variables. isTopLevelConstructor :: UType -> Maybe (TypeF ()) -- | Return an English noun phrase describing things with the given -- top-level type constructor. tyNounPhrase :: TypeF () -> Doc a -- | Return an English noun phrase describing things with the given base -- type. baseTyNounPhrase :: BaseTy -> Doc a -- | Generate an appropriate message when the sets of fields in two record -- types do not match, explaining which fields are extra and which are -- missing. fieldMismatchMsg :: Set Var -> Set Var -> Doc a instance GHC.Show.Show Swarm.Language.Pretty.Wildcard instance GHC.Classes.Ord Swarm.Language.Pretty.Wildcard instance GHC.Classes.Eq Swarm.Language.Pretty.Wildcard instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Pretty.Wildcard instance Swarm.Language.Pretty.PrettyPrec i => Swarm.Language.Pretty.PrettyPrec (Swarm.Language.Pretty.BulletList i) instance Swarm.Language.Pretty.PrettyPrec Data.Text.Internal.Text instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Types.BaseTy instance Swarm.Language.Pretty.PrettyPrec Control.Unification.IntVar.IntVar instance Swarm.Language.Pretty.PrettyPrec (t (Data.Functor.Fixedpoint.Fix t)) => Swarm.Language.Pretty.PrettyPrec (Data.Functor.Fixedpoint.Fix t) instance (Swarm.Language.Pretty.PrettyPrec (t (Control.Unification.Types.UTerm t v)), Swarm.Language.Pretty.PrettyPrec v) => Swarm.Language.Pretty.PrettyPrec (Control.Unification.Types.UTerm t v) instance Swarm.Language.Pretty.PrettyPrec t => Swarm.Language.Pretty.PrettyPrec (Swarm.Language.Types.TypeF t) instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Types.Polytype instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Types.UPolytype instance Swarm.Language.Pretty.PrettyPrec t => Swarm.Language.Pretty.PrettyPrec (Swarm.Language.Context.Ctx t) instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Direction.Direction instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Capability.Capability instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Syntax.Const instance Swarm.Language.Pretty.PrettyPrec (Swarm.Language.Syntax.Syntax' ty) instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Syntax.Term instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Typecheck.TypeErr instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Typecheck.InvalidAtomicReason instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Typecheck.LocatedTCFrame instance Swarm.Language.Pretty.PrettyPrec Swarm.Language.Typecheck.TCFrame -- | A data type to represent system failures. -- -- These failures are often not fatal and serve to create common -- infrastructure for logging. module Swarm.Game.Failure data SystemFailure AssetNotLoaded :: Asset -> FilePath -> LoadingFailure -> SystemFailure ScenarioNotFound :: FilePath -> SystemFailure OrderFileWarning :: FilePath -> OrderFileWarning -> SystemFailure CustomFailure :: Text -> SystemFailure data AssetData AppAsset :: AssetData NameGeneration :: AssetData Entities :: AssetData Recipes :: AssetData Worlds :: AssetData Scenarios :: AssetData Script :: AssetData data Asset Achievement :: Asset Data :: AssetData -> Asset History :: Asset Save :: Asset data Entry Directory :: Entry File :: Entry data LoadingFailure DoesNotExist :: Entry -> LoadingFailure EntryNot :: Entry -> LoadingFailure CanNotParseYaml :: ParseException -> LoadingFailure CanNotParseMegaparsec :: ParseErrorBundle Text Void -> LoadingFailure DoesNotTypecheck :: Text -> LoadingFailure Duplicate :: AssetData -> Text -> LoadingFailure CustomMessage :: Text -> LoadingFailure data OrderFileWarning NoOrderFile :: OrderFileWarning MissingFiles :: NonEmpty FilePath -> OrderFileWarning DanglingFiles :: NonEmpty FilePath -> OrderFileWarning instance GHC.Show.Show Swarm.Game.Failure.AssetData instance GHC.Classes.Eq Swarm.Game.Failure.AssetData instance GHC.Show.Show Swarm.Game.Failure.Asset instance GHC.Classes.Eq Swarm.Game.Failure.Asset instance GHC.Show.Show Swarm.Game.Failure.Entry instance GHC.Classes.Eq Swarm.Game.Failure.Entry instance GHC.Show.Show Swarm.Game.Failure.LoadingFailure instance GHC.Show.Show Swarm.Game.Failure.OrderFileWarning instance GHC.Classes.Eq Swarm.Game.Failure.OrderFileWarning instance GHC.Show.Show Swarm.Game.Failure.SystemFailure instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.Failure.SystemFailure instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.Failure.OrderFileWarning instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.Failure.LoadingFailure instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.Failure.Entry instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.Failure.Asset instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.Failure.AssetData -- | fused-effect utilities for Swarm. module Swarm.Util.Effect -- | Transform a Throw e1 constraint into a Throw e2 -- constraint, by supplying an adapter function of type (e1 -> -- e2). withThrow :: Has (Throw e2) sig m => (e1 -> e2) -> ThrowC e1 m a -> m a -- | Transform a Throw e constrint into a concrete Maybe, -- discarding the error. throwToMaybe :: forall e m a. Functor m => ThrowC e m a -> m (Maybe a) -- | Transform a Throw e constrint into a concrete Maybe, -- logging any error as a warning. throwToWarning :: Has (Accum (Seq e)) sig m => ThrowC e m a -> m (Maybe a) -- | Run a computation with an Accum effect (typically -- accumulating a list of warnings), ignoring the accumulated value. ignoreWarnings :: forall e m a. (Monoid e, Functor m) => AccumC e m a -> m a -- | Convert a fused-effects style computation using a Throw e -- constraint into an ExceptT computation. This is mostly a stub -- to convert from one style to the other while we are in the middle of -- incrementally converting. Eventually this should not be needed. asExceptT :: ThrowC e m a -> ExceptT e m a -- | Log a single failure as a warning. warn :: Has (Accum (Seq w)) sig m => w -> m () -- | A version of traverse/mapM that also accumulates -- warnings. -- -- Note that we can't generalize this to work over any Traversable -- because it also needs to have a notion of "filtering". -- Witherable provides exactly the right abstraction. traverseW :: (Has (Accum (Seq w)) sig m, Witherable t) => (a -> m (Either w b)) -> t a -> m (t b) -- | Flipped version of traverseW for convenience. forMW :: (Has (Accum (Seq w)) sig m, Witherable t) => t a -> (a -> m (Either w b)) -> m (t b) simpleErrorHandle :: ThrowC SystemFailure IO a -> IO a -- | Various utilities related to loading game data files. module Swarm.Game.ResourceLoading -- | Get subdirectory from swarm data directory. -- -- This will first look in Cabal generated path and then try a `data` -- directory in XdgData path. -- -- The idea is that when installing with Cabal/Stack the first is -- preferred, but when the players install a binary they need to extract -- the `data` archive to the XDG directory. getDataDirSafe :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => AssetData -> FilePath -> m FilePath -- | Get file from swarm data directory. -- -- See the note in getDataDirSafe. getDataFileNameSafe :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => AssetData -> FilePath -> m FilePath -- | Get a nice message suggesting to download `data` directory to -- XdgData. dataNotFound :: FilePath -> IO LoadingFailure -- | Get path to swarm data, optionally creating necessary directories. -- This could fail if user has bad permissions on his own $HOME or -- $XDG_DATA_HOME which is unlikely. getSwarmXdgDataSubdir :: Bool -> FilePath -> IO FilePath getSwarmXdgDataFile :: Bool -> FilePath -> IO FilePath -- | Get path to swarm saves, optionally creating necessary directories. getSwarmSavePath :: Bool -> IO FilePath -- | Get path to swarm history, optionally creating necessary directories. getSwarmHistoryPath :: Bool -> IO FilePath -- | Read all the .txt files in the data/ directory. readAppData :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => m (Map Text Text) -- | Load/save logic for achievements. module Swarm.Game.Achievement.Persistence -- | Get path to swarm achievements, optionally creating necessary -- directories. getSwarmAchievementsPath :: Bool -> IO FilePath -- | Load saved info about achievements from XDG data directory. Returns a -- tuple of warnings and attained achievements. loadAchievementsInfo :: (Has (Accum (Seq SystemFailure)) sig m, Has (Lift IO) sig m) => m [Attainment] -- | Save info about achievements to XDG data directory. saveAchievementsInfo :: [Attainment] -> IO () -- | Some convenient functions for putting together the whole Swarm -- language processing pipeline: parsing, type checking, capability -- checking, and elaboration. If you want to simply turn some raw text -- representing a Swarm program into something useful, this is probably -- the module you want. module Swarm.Language.Pipeline -- | A record containing the results of the language processing pipeline. -- Put a Term in, and get one of these out. A ProcessedTerm -- contains: -- -- data ProcessedTerm ProcessedTerm :: TModule -> Requirements -> ReqCtx -> ProcessedTerm -- | Given a Text value representing a Swarm program, -- --
    --
  1. Parse it (see Swarm.Language.Parse)
  2. --
  3. Typecheck it (see Swarm.Language.Typecheck)
  4. --
  5. Elaborate it (see Swarm.Language.Elaborate)
  6. --
  7. Check what capabilities it requires (see -- Swarm.Language.Capability)
  8. --
-- -- Return either the end result (or Nothing if the input was -- only whitespace) or a pretty-printed error message. processTerm :: Text -> Either Text (Maybe ProcessedTerm) -- | Like processTerm, but use a term that has already been parsed. processParsedTerm :: Syntax -> Either ContextualTypeErr ProcessedTerm -- | Like processTerm, but use explicit starting contexts. processTerm' :: TCtx -> ReqCtx -> Text -> Either Text (Maybe ProcessedTerm) -- | Like processTerm', but use a term that has already been parsed. processParsedTerm' :: TCtx -> ReqCtx -> Syntax -> Either ContextualTypeErr ProcessedTerm processTermEither :: Text -> Either Text ProcessedTerm instance GHC.Generics.Generic Swarm.Language.Pipeline.ProcessedTerm instance GHC.Classes.Eq Swarm.Language.Pipeline.ProcessedTerm instance GHC.Show.Show Swarm.Language.Pipeline.ProcessedTerm instance Data.Data.Data Swarm.Language.Pipeline.ProcessedTerm instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Pipeline.ProcessedTerm instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Pipeline.ProcessedTerm -- | Simple Markdown AST and related utilities. -- -- Parametrising Document with the type of inline code and code -- blocks allows us to inspect and validate Swarm code in descriptions. -- -- See drawMarkdown for rendering the descriptions as brick -- widgets. module Swarm.Language.Text.Markdown -- | The top-level markdown document. newtype Document c Document :: [Paragraph c] -> Document c [paragraphs] :: Document c -> [Paragraph c] -- | Markdown paragraphs that contain inline leaf nodes. -- -- The idea is that paragraphs do not have line breaks, and so the inline -- elements follow each other. In particular inline code can be followed -- by text without space between them (e.g. loggers). newtype Paragraph c Paragraph :: [Node c] -> Paragraph c [nodes] :: Paragraph c -> [Node c] -- | Inline leaf nodes. -- -- The raw node is from the raw_annotation extension, and can be used for -- typesentitiesinvalid code. data Node c LeafText :: Set TxtAttr -> Text -> Node c LeafRaw :: String -> Text -> Node c LeafCode :: c -> Node c LeafCodeBlock :: String -> c -> Node c -- | Simple text attributes that make it easier to find key info in -- descriptions. data TxtAttr Strong :: TxtAttr Emphasis :: TxtAttr -- | Read Markdown document and parse&validate the code. -- -- If you want only the document with code as Text, use the -- fromTextPure function. fromTextM :: MonadFail m => Text -> m (Document Syntax) -- | Parse Markdown document, but throw on invalid code. fromText :: Text -> Document Syntax -- | Convert Document to Text. -- -- Note that this will strip some markdown, emphasis and bold marks. If -- you want to get markdown again, use docToMark. docToText :: PrettyPrec a => Document a -> Text -- | Convert Document to markdown text. docToMark :: PrettyPrec a => Document a -> Text -- | Token stream that can be easily converted to text or brick widgets. -- -- TODO: #574 Code blocks should probably be handled separately. data StreamNode' t TextNode :: Set TxtAttr -> t -> StreamNode' t CodeNode :: t -> StreamNode' t RawNode :: String -> t -> StreamNode' t type StreamNode = StreamNode' Text -- | Convert elements to one dimensional stream of nodes, that is easy to -- format and layout. -- -- If you want to split the stream at line length, use the -- chunksOf function afterward. class ToStream a toStream :: ToStream a => a -> [StreamNode] -- | This is the naive and easy way to get text from markdown document. toText :: ToStream a => a -> Text findCode :: Document Syntax -> [Syntax] -- | Get chunks of nodes not exceeding length and broken at word boundary. chunksOf :: Int -> [StreamNode] -> [[StreamNode]] instance GHC.Classes.Ord Swarm.Language.Text.Markdown.TxtAttr instance GHC.Show.Show Swarm.Language.Text.Markdown.TxtAttr instance GHC.Classes.Eq Swarm.Language.Text.Markdown.TxtAttr instance Data.Traversable.Traversable Swarm.Language.Text.Markdown.Node instance Data.Foldable.Foldable Swarm.Language.Text.Markdown.Node instance GHC.Base.Functor Swarm.Language.Text.Markdown.Node instance GHC.Show.Show c => GHC.Show.Show (Swarm.Language.Text.Markdown.Node c) instance GHC.Classes.Eq c => GHC.Classes.Eq (Swarm.Language.Text.Markdown.Node c) instance GHC.Base.Monoid (Swarm.Language.Text.Markdown.Paragraph c) instance GHC.Base.Semigroup (Swarm.Language.Text.Markdown.Paragraph c) instance Data.Traversable.Traversable Swarm.Language.Text.Markdown.Paragraph instance Data.Foldable.Foldable Swarm.Language.Text.Markdown.Paragraph instance GHC.Base.Functor Swarm.Language.Text.Markdown.Paragraph instance GHC.Show.Show c => GHC.Show.Show (Swarm.Language.Text.Markdown.Paragraph c) instance GHC.Classes.Eq c => GHC.Classes.Eq (Swarm.Language.Text.Markdown.Paragraph c) instance GHC.Base.Monoid (Swarm.Language.Text.Markdown.Document c) instance GHC.Base.Semigroup (Swarm.Language.Text.Markdown.Document c) instance Data.Traversable.Traversable Swarm.Language.Text.Markdown.Document instance Data.Foldable.Foldable Swarm.Language.Text.Markdown.Document instance GHC.Base.Functor Swarm.Language.Text.Markdown.Document instance GHC.Show.Show c => GHC.Show.Show (Swarm.Language.Text.Markdown.Document c) instance GHC.Classes.Eq c => GHC.Classes.Eq (Swarm.Language.Text.Markdown.Document c) instance GHC.Base.Functor Swarm.Language.Text.Markdown.StreamNode' instance GHC.Show.Show t => GHC.Show.Show (Swarm.Language.Text.Markdown.StreamNode' t) instance GHC.Classes.Eq t => GHC.Classes.Eq (Swarm.Language.Text.Markdown.StreamNode' t) instance Swarm.Language.Pretty.PrettyPrec a => Swarm.Language.Text.Markdown.ToStream (Swarm.Language.Text.Markdown.Node a) instance Swarm.Language.Pretty.PrettyPrec a => Swarm.Language.Text.Markdown.ToStream (Swarm.Language.Text.Markdown.Paragraph a) instance Commonmark.Types.Rangeable (Swarm.Language.Text.Markdown.Document c) instance Commonmark.Types.HasAttributes (Swarm.Language.Text.Markdown.Document c) instance GHC.Exts.IsList (Swarm.Language.Text.Markdown.Document a) instance Data.String.IsString (Swarm.Language.Text.Markdown.Document Swarm.Language.Syntax.Syntax) instance Data.String.IsString (Swarm.Language.Text.Markdown.Paragraph Swarm.Language.Syntax.Syntax) instance Commonmark.Types.IsBlock (Swarm.Language.Text.Markdown.Paragraph Data.Text.Internal.Text) (Swarm.Language.Text.Markdown.Document Data.Text.Internal.Text) instance Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Text.Markdown.Document Swarm.Language.Syntax.Syntax) instance Data.Aeson.Types.FromJSON.FromJSON (Swarm.Language.Text.Markdown.Document Swarm.Language.Syntax.Syntax) instance Commonmark.Types.Rangeable (Swarm.Language.Text.Markdown.Paragraph c) instance Commonmark.Types.HasAttributes (Swarm.Language.Text.Markdown.Paragraph c) instance Commonmark.Types.IsInline (Swarm.Language.Text.Markdown.Paragraph Data.Text.Internal.Text) instance Data.Aeson.Types.ToJSON.ToJSON (Swarm.Language.Text.Markdown.Paragraph Swarm.Language.Syntax.Syntax) -- | A quasiquoter for Swarm terms. module Swarm.Language.Pipeline.QQ -- | A quasiquoter for Swarm language terms, so we can conveniently write -- them down using concrete syntax and have them parsed into abstract -- syntax at compile time. The quasiquoter actually runs the entire -- pipeline on them (parsing, typechecking, elaborating), so a -- quasiquoted Swarm program with a parse error or a type error will fail -- at Haskell compile time. This is useful for creating system robot -- programs (for example, see seedProgram). tmQ :: QuasiQuoter -- | Types and utilities to compute code size in terms of textual length -- and AST. module Swarm.Game.Scenario.Scoring.CodeSize data CodeSizeDeterminators CodeSizeDeterminators :: Maybe ProcessedTerm -> Bool -> CodeSizeDeterminators [initialCode] :: CodeSizeDeterminators -> Maybe ProcessedTerm [hasUsedREPL] :: CodeSizeDeterminators -> Bool data ScenarioCodeMetrics ScenarioCodeMetrics :: Int -> Int -> ScenarioCodeMetrics [sourceTextLength] :: ScenarioCodeMetrics -> Int [astSize] :: ScenarioCodeMetrics -> Int codeSizeFromDeterminator :: CodeSizeDeterminators -> Maybe ScenarioCodeMetrics instance GHC.Show.Show Swarm.Game.Scenario.Scoring.CodeSize.CodeSizeDeterminators instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Scoring.CodeSize.ScenarioCodeMetrics instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Scoring.CodeSize.ScenarioCodeMetrics instance GHC.Generics.Generic Swarm.Game.Scenario.Scoring.CodeSize.ScenarioCodeMetrics instance GHC.Read.Read Swarm.Game.Scenario.Scoring.CodeSize.ScenarioCodeMetrics instance GHC.Show.Show Swarm.Game.Scenario.Scoring.CodeSize.ScenarioCodeMetrics instance GHC.Classes.Ord Swarm.Game.Scenario.Scoring.CodeSize.ScenarioCodeMetrics instance GHC.Classes.Eq Swarm.Game.Scenario.Scoring.CodeSize.ScenarioCodeMetrics module Swarm.Game.Scenario.Objective data PrerequisiteConfig PrerequisiteConfig :: Bool -> Prerequisite ObjectiveLabel -> PrerequisiteConfig -- | Typically, only the currently "active" objectives are displayed to the -- user in the Goals dialog. An objective is "active" if all of its -- prerequisites are met. -- -- However, some objectives may be "high-level", in that they may explain -- the broader intention behind potentially multiple prerequisites. -- -- Set this to option True to display this goal in the "upcoming" section -- even if the objective has currently unmet prerequisites. [previewable] :: PrerequisiteConfig -> Bool -- | Boolean expression of dependencies upon other objectives. Variables in -- this expression are the "id"s of other objectives, and become "true" -- if the corresponding objective is completed. The "condition" of the -- objective at hand shall not be evaluated until its prerequisite -- expression evaluates as True. -- -- Note that the achievement of these objective dependencies is -- persistent; once achieved, they still count even if their "condition" -- might not still hold. The condition is never re-evaluated once True. [logic] :: PrerequisiteConfig -> Prerequisite ObjectiveLabel -- | An objective is a condition to be achieved by a player in a scenario. data Objective Objective :: Document Syntax -> Maybe Text -> ProcessedTerm -> Maybe ObjectiveLabel -> Bool -> Maybe PrerequisiteConfig -> Bool -> Maybe AchievementInfo -> Objective [_objectiveGoal] :: Objective -> Document Syntax [_objectiveTeaser] :: Objective -> Maybe Text [_objectiveCondition] :: Objective -> ProcessedTerm [_objectiveId] :: Objective -> Maybe ObjectiveLabel [_objectiveOptional] :: Objective -> Bool [_objectivePrerequisite] :: Objective -> Maybe PrerequisiteConfig [_objectiveHidden] :: Objective -> Bool [_objectiveAchievement] :: Objective -> Maybe AchievementInfo -- | An explanation of the goal of the objective, shown to the player -- during play. It is represented as a list of paragraphs. objectiveGoal :: Lens' Objective (Document Syntax) -- | A very short (3-5 words) description of the goal for displaying on the -- left side of the Objectives modal. objectiveTeaser :: Lens' Objective (Maybe Text) -- | A winning condition for the objective, expressed as a program of type -- cmd bool. By default, this program will be run to completion -- every tick (the usual limits on the number of CESK steps per tick do -- not apply). objectiveCondition :: Lens' Objective ProcessedTerm -- | Optional name by which this objective may be referenced as a -- prerequisite for other objectives. objectiveId :: Lens' Objective (Maybe Text) -- | Indicates whether the objective is not required in order to "win" the -- scenario. Useful for (potentially hidden) achievements. If the field -- is not supplied, it defaults to False (i.e. the objective is mandatory -- to "win"). objectiveOptional :: Lens' Objective Bool -- | Dependencies upon other objectives objectivePrerequisite :: Lens' Objective (Maybe PrerequisiteConfig) -- | Whether the goal is displayed in the UI before completion. The goal -- will always be revealed after it is completed. -- -- This attribute often goes along with an Achievement. objectiveHidden :: Lens' Objective Bool -- | An optional Achievement that is to be registered globally when this -- objective is completed. objectiveAchievement :: Lens' Objective (Maybe AchievementInfo) data CompletionBuckets CompletionBuckets :: [Objective] -> [Objective] -> [Objective] -> CompletionBuckets [incomplete] :: CompletionBuckets -> [Objective] [completed] :: CompletionBuckets -> [Objective] [unwinnable] :: CompletionBuckets -> [Objective] -- | TODO: #1044 Could also add an ObjectiveFailed constructor... newtype Announcement ObjectiveCompleted :: Objective -> Announcement data ObjectiveCompletion ObjectiveCompletion :: CompletionBuckets -> Set ObjectiveLabel -> ObjectiveCompletion -- | This is the authoritative "completion status" for all objectives. Note -- that there is a separate Set to store the completion status of -- prerequisite objectives, which must be carefully kept in sync with -- this. Those prerequisite objectives are required to have labels, but -- other objectives are not. Therefore only prerequisites exist in the -- completion map keyed by label. [completionBuckets] :: ObjectiveCompletion -> CompletionBuckets [completedIDs] :: ObjectiveCompletion -> Set ObjectiveLabel -- | Concatenates all incomplete and completed objectives. listAllObjectives :: CompletionBuckets -> [Objective] addCompleted :: Objective -> ObjectiveCompletion -> ObjectiveCompletion addUnwinnable :: Objective -> ObjectiveCompletion -> ObjectiveCompletion setIncomplete :: ([Objective] -> [Objective]) -> ObjectiveCompletion -> ObjectiveCompletion addIncomplete :: Objective -> ObjectiveCompletion -> ObjectiveCompletion -- | Returns the ObjectiveCompletion with the "incomplete" goals -- extracted to a separate tuple member. This is intended as input to a -- "fold". extractIncomplete :: ObjectiveCompletion -> (ObjectiveCompletion, [Objective]) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.CompletionBuckets instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Objective.CompletionBuckets instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.CompletionBuckets instance GHC.Show.Show Swarm.Game.Scenario.Objective.CompletionBuckets instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.Announcement instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.Announcement instance GHC.Show.Show Swarm.Game.Scenario.Objective.Announcement instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.ObjectiveCompletion instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Objective.ObjectiveCompletion instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.ObjectiveCompletion instance GHC.Show.Show Swarm.Game.Scenario.Objective.ObjectiveCompletion instance Servant.Docs.Internal.ToSample Swarm.Game.Scenario.Objective.Objective instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Objective.Objective instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.PrerequisiteConfig instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.PrerequisiteConfig instance GHC.Show.Show Swarm.Game.Scenario.Objective.PrerequisiteConfig instance GHC.Classes.Eq Swarm.Game.Scenario.Objective.PrerequisiteConfig instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.Objective instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.Objective instance GHC.Show.Show Swarm.Game.Scenario.Objective.Objective instance GHC.Classes.Eq Swarm.Game.Scenario.Objective.Objective instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Objective.PrerequisiteConfig -- | Utilities to check whether conditions are met for a game win/loss. module Swarm.Game.Scenario.Objective.WinCheck -- | We have "won" if all of the "unwinnable" or remaining "incomplete" -- objectives are "optional". didWin :: ObjectiveCompletion -> Bool -- | We have "lost" if any of the "unwinnable" objectives not "optional". didLose :: ObjectiveCompletion -> Bool isPrereqsSatisfied :: ObjectiveCompletion -> Objective -> Bool isUnwinnablePrereq :: Set ObjectiveLabel -> Prerequisite ObjectiveLabel -> Bool isUnwinnable :: ObjectiveCompletion -> Objective -> Bool -- | The first element of the returned tuple consists of "active" -- objectives, the second element "inactive". partitionActiveObjectives :: ObjectiveCompletion -> ([Objective], [Objective]) getActiveObjectives :: ObjectiveCompletion -> [Objective] -- | For debugging only (via Web API) data PrereqSatisfaction PrereqSatisfaction :: Objective -> Set (Signed ObjectiveLabel) -> Bool -> PrereqSatisfaction [objective] :: PrereqSatisfaction -> Objective [deps] :: PrereqSatisfaction -> Set (Signed ObjectiveLabel) [prereqsSatisfied] :: PrereqSatisfaction -> Bool -- | Used only by the web interface for debugging getSatisfaction :: ObjectiveCompletion -> [PrereqSatisfaction] getDistinctConstants :: Ord a => Prerequisite a -> Set (Signed a) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.WinCheck.PrereqSatisfaction instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.WinCheck.PrereqSatisfaction instance GHC.Generics.Generic (Data.BoolExpr.Signed Swarm.Game.Scenario.Objective.Logic.ObjectiveLabel) instance Data.Aeson.Types.ToJSON.ToJSON (Data.BoolExpr.Signed Swarm.Game.Scenario.Objective.Logic.ObjectiveLabel) instance Servant.Docs.Internal.ToSample Swarm.Game.Scenario.Objective.WinCheck.PrereqSatisfaction -- | A UI-centric model for Objective presentation. module Swarm.TUI.Model.Goal -- | These are intended to be used as keys in a map of lists of goals. data GoalStatus -- | Goals in this category have other goals as prerequisites. However, -- they are only displayed if the "previewable" attribute is -- true. Upcoming :: GoalStatus -- | Goals in this category may be pursued in parallel. However, they are -- only displayed if the "hidden" attribute is false. Active :: GoalStatus -- | A goal's programmatic condition, as well as all its prerequisites, -- were completed. This is a "latch" mechanism; at some point the -- conditions required to meet the goal may no longer hold. Nonetheless, -- the goal remains "completed". Completed :: GoalStatus -- | A goal that can no longer be achieved. If this goal is not an -- "optional" goal, then the player also Loses the scenario. -- -- Note that currently the only way to Fail a goal is by way of a -- negative prerequisite that was completed. Failed :: GoalStatus type CategorizedGoals = Map GoalStatus (NonEmpty Objective) data GoalEntry Header :: GoalStatus -> GoalEntry Goal :: GoalStatus -> Objective -> GoalEntry Spacer :: GoalEntry shouldSkipSelection :: GoalEntry -> Bool data GoalTracking GoalTracking :: [Announcement] -> CategorizedGoals -> GoalTracking -- | TODO: #1044 the actual contents of these are not used yet, other than -- as a flag to pop up the Goal dialog. [announcements] :: GoalTracking -> [Announcement] [goals] :: GoalTracking -> CategorizedGoals data GoalDisplay GoalDisplay :: GoalTracking -> List Name GoalEntry -> FocusRing Name -> GoalDisplay [_goalsContent] :: GoalDisplay -> GoalTracking -- | required for maintaining the selection/navigation state among list -- items [_listWidget] :: GoalDisplay -> List Name GoalEntry [_focus] :: GoalDisplay -> FocusRing Name listWidget :: Lens' GoalDisplay (List Name GoalEntry) goalsContent :: Lens' GoalDisplay GoalTracking focus :: Lens' GoalDisplay (FocusRing Name) emptyGoalDisplay :: GoalDisplay hasAnythingToShow :: GoalTracking -> Bool hasMultipleGoals :: GoalTracking -> Bool constructGoalMap :: Bool -> ObjectiveCompletion -> CategorizedGoals instance Data.Aeson.Types.ToJSON.ToJSONKey Swarm.TUI.Model.Goal.GoalStatus instance Data.Aeson.Types.ToJSON.ToJSON Swarm.TUI.Model.Goal.GoalStatus instance GHC.Generics.Generic Swarm.TUI.Model.Goal.GoalStatus instance GHC.Enum.Enum Swarm.TUI.Model.Goal.GoalStatus instance GHC.Enum.Bounded Swarm.TUI.Model.Goal.GoalStatus instance GHC.Classes.Ord Swarm.TUI.Model.Goal.GoalStatus instance GHC.Classes.Eq Swarm.TUI.Model.Goal.GoalStatus instance GHC.Show.Show Swarm.TUI.Model.Goal.GoalStatus instance Data.Aeson.Types.ToJSON.ToJSON Swarm.TUI.Model.Goal.GoalTracking instance GHC.Generics.Generic Swarm.TUI.Model.Goal.GoalTracking instance Servant.Docs.Internal.ToSample Swarm.TUI.Model.Goal.GoalTracking -- | Utilities for performing graph analysis on Objective prerequisites module Swarm.Game.Scenario.Objective.Graph -- | This is only needed for constructing a Graph, which requires all nodes -- to have a key. data ObjectiveId Label :: Signed ObjectiveLabel -> ObjectiveId -- | for unlabeled objectives Ordinal :: Int -> ObjectiveId data GraphInfo GraphInfo :: Graph -> Bool -> [SCC Objective] -> [ObjectiveId] -> GraphInfo [actualGraph] :: GraphInfo -> Graph [isAcyclic] :: GraphInfo -> Bool [sccInfo] :: GraphInfo -> [SCC Objective] [nodeIDs] :: GraphInfo -> [ObjectiveId] getConstFromSigned :: Signed a -> a -- | Collect all of the constants that have a negation. This is necessary -- for enumerating all of the distinct nodes when constructing a Graph, -- as we treat a constant and its negation as distinct nodes. getNegatedIds :: [Objective] -> Map ObjectiveLabel Objective getObjectivesById :: [Objective] -> Map ObjectiveLabel Objective -- | Uses the textual labels for those objectives that have them, and -- assigns arbitrary integer IDs for the remaining. -- -- Only necessary for constructing a Graph. assignIds :: [Objective] -> Map ObjectiveId Objective type Edges = [(Objective, ObjectiveId, [ObjectiveId])] -- | NOTE: Based strictly on the goal labels, the graph could potentially -- contain a cycle, if there exist mutually-exclusive goals. That is, if -- goal A depends on the NOT of "goal B". Goal B could then also depend -- on "NOT Goal A" (re-enforcing the mutual-exclusivity), or it could -- mandate a completion order, e.g.: Goal A and Goal B are simultaneously -- available to pursue. However, if the player completes Goal B first, -- then it closes off the option to complete Goal A. However, if Goal A -- is completed first, then the user is also allowed to complete Goal B. -- -- To avoid a "cycle" in this circumstance, A needs to exist as a -- distinct node from "NOT A" in the graph. makeGraph :: Edges -> Graph makeGraphEdges :: [Objective] -> Edges isAcyclicGraph :: [SCC Objective] -> Bool makeGraphInfo :: ObjectiveCompletion -> GraphInfo instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.Graph.ObjectiveId instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.Graph.ObjectiveId instance GHC.Show.Show Swarm.Game.Scenario.Objective.Graph.ObjectiveId instance GHC.Classes.Ord Swarm.Game.Scenario.Objective.Graph.ObjectiveId instance GHC.Classes.Eq Swarm.Game.Scenario.Objective.Graph.ObjectiveId instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Objective.Graph.GraphInfo instance GHC.Generics.Generic Swarm.Game.Scenario.Objective.Graph.GraphInfo instance GHC.Show.Show Swarm.Game.Scenario.Objective.Graph.GraphInfo instance Servant.Docs.Internal.ToSample Swarm.Game.Scenario.Objective.Graph.GraphInfo instance Data.Aeson.Types.ToJSON.ToJSON (Data.Graph.SCC Swarm.Game.Scenario.Objective.Objective) instance Data.Aeson.Types.ToJSON.ToJSON Data.Graph.Graph -- | Validity checking for Objective prerequisites module Swarm.Game.Scenario.Objective.Validation -- | 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] module Swarm.Language.LSP.VarUsage data BindingType Lambda :: BindingType Let :: BindingType Bind :: BindingType data VarUsage VarUsage :: LocVar -> BindingType -> VarUsage type BindingSites = Map Var (NonEmpty SrcLoc) data Usage Usage :: Set LocVar -> [VarUsage] -> Usage -- | Variable references [usages] :: Usage -> Set LocVar -- | Variable declarations without any references [problems] :: Usage -> [VarUsage] toErrPos :: Text -> VarUsage -> Maybe (Range, Text) -- | Descends the syntax tree rooted at a variable declaration, -- accumulating variable references. Generates a "problem" if an -- associated variable reference is not encountered in the subtree for -- this declaration. checkOccurrences :: BindingSites -> LocVar -> BindingType -> [Syntax] -> Usage -- | Build up the bindings map as a function argument as we descend into -- the syntax tree. Aggregates unused bindings as we return from each -- layer. getUsage :: BindingSites -> Syntax -> Usage instance GHC.Show.Show Swarm.Language.LSP.VarUsage.BindingType instance GHC.Classes.Eq Swarm.Language.LSP.VarUsage.BindingType instance GHC.Base.Semigroup Swarm.Language.LSP.VarUsage.Usage instance GHC.Base.Monoid Swarm.Language.LSP.VarUsage.Usage module Swarm.Language.LSP.Hover showHoverInfo :: NormalizedUri -> TextDocumentVersion -> Position -> VirtualFile -> Maybe (Text, Maybe Range) renderDoc :: Int -> Text -> Text treeToMarkdown :: Int -> Tree Text -> Text -- | Find the most specific term for a given position within the code. narrowToPosition :: ExplainableType ty => Syntax' ty -> Int -> Syntax' ty explain :: ExplainableType ty => Syntax' ty -> Tree Text instance Swarm.Language.LSP.Hover.ExplainableType () instance Swarm.Language.LSP.Hover.ExplainableType Swarm.Language.Types.Polytype -- | Language Server Protocol (LSP) server for the Swarm language. See the -- docs/EDITORS.md to learn how to use it. module Swarm.Language.LSP lspMain :: IO () diagnosticSourcePrefix :: Text debug :: MonadIO m => Text -> m () validateSwarmCode :: NormalizedUri -> TextDocumentVersion -> Text -> LspM () () showTypeErrorPos :: Text -> ContextualTypeErr -> ((Int, Int), (Int, Int), Text) handlers :: Handlers (LspM ()) -- | Parsing and pretty-printing for keys (as in, keys on a keyboard) and -- key combos. module Swarm.Language.Key -- | A keyboard input, represented as a key + modifiers. Invariant: the -- modifier list is always sorted. data KeyCombo -- | Smart constructor for KeyCombo. mkKeyCombo :: [Modifier] -> Key -> KeyCombo -- | Parse a key combo with nothing after it. parseKeyComboFull :: Parser KeyCombo -- | Parse a key combo like "M-C-F5", Down, or "C-x". parseKeyCombo :: Parser KeyCombo -- | Pretty-print a key combo, e.g. "C-M-F5". Right inverse to -- parseKeyCombo. Left inverse up to reordering of modifiers. prettyKeyCombo :: KeyCombo -> Text specialKeyNames :: Set Text instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Key.KeyCombo instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Key.KeyCombo instance GHC.Generics.Generic Swarm.Language.Key.KeyCombo instance GHC.Show.Show Swarm.Language.Key.KeyCombo instance GHC.Classes.Ord Swarm.Language.Key.KeyCombo instance GHC.Classes.Eq Swarm.Language.Key.KeyCombo instance Data.Aeson.Types.FromJSON.FromJSON Graphics.Vty.Input.Events.Key instance Data.Aeson.Types.FromJSON.FromJSON Graphics.Vty.Input.Events.Modifier instance Data.Aeson.Types.ToJSON.ToJSON Graphics.Vty.Input.Events.Key instance Data.Aeson.Types.ToJSON.ToJSON Graphics.Vty.Input.Events.Modifier instance Swarm.Language.Key.Names' f => Swarm.Language.Key.Names' (GHC.Generics.M1 GHC.Generics.D t f) instance (Swarm.Language.Key.Names' f, Swarm.Language.Key.Names' g) => Swarm.Language.Key.Names' (f GHC.Generics.:+: g) instance GHC.Generics.Constructor c => Swarm.Language.Key.Names' (GHC.Generics.C1 c f) -- | Values and environments used for interpreting the Swarm language. module Swarm.Language.Value -- | A value is a term that cannot (or does not) take any more -- evaluation steps on its own. data Value -- | The unit value. [VUnit] :: Value -- | An integer. [VInt] :: Integer -> Value -- | Literal text. [VText] :: Text -> Value -- | A direction. [VDir] :: Direction -> Value -- | A boolean. [VBool] :: Bool -> Value -- | A reference to a robot. [VRobot] :: Int -> Value -- | An injection into a sum type. False = left, True = right. [VInj] :: Bool -> Value -> Value -- | A pair. [VPair] :: Value -> Value -> Value -- | A closure, representing a lambda term along with an environment -- containing bindings for any free variables in the body of the lambda. [VClo] :: Var -> Term -> Env -> Value -- | An application of a constant to some value arguments, potentially -- waiting for more arguments. If a constant application is fully -- saturated (as defined by its arity), whether it is a value or -- not depends on whether or not it represents a command (as defined by -- isCmd). If a command (e.g. Build), it is a value, and -- awaits an FExec frame which will cause it to execute. Otherwise -- (e.g. If), it is not a value, and will immediately reduce. [VCApp] :: Const -> [Value] -> Value -- | A definition, which does not take effect until executed. The -- Bool indicates whether the definition is recursive. [VDef] :: Bool -> Var -> Term -> Env -> Value -- | The result of a command, consisting of the result of the command as -- well as an environment of bindings from TDef commands. [VResult] :: Value -> Env -> Value -- | An unevaluated bind expression, waiting to be executed, of the form -- i.e. c1 ; c2 or x <- c1; c2. We also store -- an Env in which to interpret the commands. [VBind] :: Maybe Var -> Term -> Term -> Env -> Value -- | A (non-recursive) delayed term, along with its environment. If a term -- would otherwise be evaluated but we don't want it to be (e.g. -- as in the case of arguments to an 'if', or a recursive binding), we -- can stick a TDelay on it, which turns it into a value. Delayed -- terms won't be evaluated until Force is applied to them. [VDelay] :: Term -> Env -> Value -- | A reference to a memory cell in the store. [VRef] :: Int -> Value -- | A record value. [VRcd] :: Map Var Value -> Value -- | A keyboard input. [VKey] :: KeyCombo -> Value -- | A requirements command awaiting execution. [VRequirements] :: Text -> Term -> Env -> Value -- | Ensure that a value is not wrapped in VResult. stripVResult :: Value -> Value -- | Pretty-print a value. prettyValue :: Value -> Text -- | Inject a value back into a term. valueToTerm :: Value -> Term -- | An environment is a mapping from variable names to values. type Env = Ctx Value instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Language.Value.Value instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Language.Value.Value instance GHC.Generics.Generic Swarm.Language.Value.Value instance GHC.Show.Show Swarm.Language.Value.Value instance GHC.Classes.Eq Swarm.Language.Value.Value -- | Various utilities related to parsing YAML files. module Swarm.Util.Yaml -- | A generic wrapper for computations which also depend on knowing a -- value of type e. newtype With e f a E :: (e -> f a) -> With e f a [runE] :: With e f a -> e -> f a -- | A ParserE is a YAML Parser that can also depend on -- knowing an value of type e. The E used to stand for -- EntityMap, but now that it is generalized, it stands for -- Environment. type ParserE e = With e Parser -- | Lift a computation that does not care about the environment value. liftE :: Functor f => f a -> With e f a -- | Locally modify an environment. localE :: (e' -> e) -> With e f a -> With e' f a -- | Locally merge an environment with the current one for given action. withE :: Semigroup e => e -> With e f a -> With e f a -- | Get the current environment. getE :: Monad f => With e f e -- | FromJSONE governs values that can be parsed from a YAML (or -- JSON) file, but which also have access to an extra, read-only -- environment value. -- -- For things that don't care about the environment, the default -- implementation of parseJSONE simply calls parseJSON from -- a FromJSON instance. class FromJSONE e a parseJSONE :: FromJSONE e a => Value -> ParserE e a parseJSONE :: (FromJSONE e a, FromJSON a) => Value -> ParserE e a parseJSONE' :: FromJSONE e a => e -> Value -> Parser a -- | Read a value from a YAML file, providing the needed extra environment. decodeFileEitherE :: FromJSONE e a => e -> FilePath -> IO (Either ParseException a) -- | A variant of .: for ParserE: project out a field of an -- Value, passing along the extra environment. (..:) :: FromJSONE e a => Object -> Text -> ParserE e a -- | A variant of .:? for ParserE: project out an optional -- field of an Value, passing along the extra environment. (..:?) :: FromJSONE e a => Object -> Text -> ParserE e (Maybe a) -- | A variant of .!= for any functor. (..!=) :: Functor f => f (Maybe a) -> a -> f a -- | withTextE name f value applies f to the -- Text when value is a String and fails -- otherwise. withTextE :: String -> (Text -> ParserE e a) -> Value -> ParserE e a -- | withObjectE name f value applies f to the -- Value when value is an Value and fails -- otherwise. withObjectE :: String -> (Object -> ParserE e a) -> Value -> ParserE e a -- | withArrayE name f value applies f to the -- Value when value is an Value and fails -- otherwise. withArrayE :: String -> (Array -> ParserE e a) -> Value -> ParserE e a instance GHC.Base.Alternative f => GHC.Base.Alternative (Swarm.Util.Yaml.With e f) instance Control.Monad.Fail.MonadFail f => Control.Monad.Fail.MonadFail (Swarm.Util.Yaml.With e f) instance GHC.Base.Monad f => GHC.Base.Monad (Swarm.Util.Yaml.With e f) instance GHC.Base.Applicative f => GHC.Base.Applicative (Swarm.Util.Yaml.With e f) instance GHC.Base.Functor f => GHC.Base.Functor (Swarm.Util.Yaml.With e f) instance Swarm.Util.Yaml.FromJSONE e GHC.Types.Int instance Swarm.Util.Yaml.FromJSONE e a => Swarm.Util.Yaml.FromJSONE e [a] instance (Swarm.Util.Yaml.FromJSONE e a, Swarm.Util.Yaml.FromJSONE e b) => Swarm.Util.Yaml.FromJSONE e (a, b) -- | Utilities for describing how to display in-game entities in the TUI. module Swarm.Game.Display -- | Display priority. Entities with higher priority will be drawn on top -- of entities with lower priority. type Priority = Int -- | An internal attribute name. data Attribute ADefault :: Attribute ARobot :: Attribute AEntity :: Attribute AWorld :: Text -> Attribute ATerrain :: Text -> Attribute -- | A record explaining how to display an entity in the TUI. data Display -- | The default character to use for display. defaultChar :: Lens' Display Char -- | For robots or other entities that have an orientation, this map -- optionally associates different display characters with different -- orientations. If an orientation is not in the map, the -- defaultChar will be used. orientationMap :: Lens' Display (Map AbsoluteDir Char) -- | The display caches the current orientation of the entity, so we know -- which character to use from the orientation map. curOrientation :: Lens' Display (Maybe Direction) -- | The attribute to use for display. displayAttr :: Lens' Display Attribute -- | This entity's display priority. Higher priorities are drawn on top of -- lower. displayPriority :: Lens' Display Priority -- | Whether the entity is currently invisible. invisible :: Lens' Display Bool -- | Look up the character that should be used for a display. displayChar :: Display -> Char -- | Modify a display to use a ? character for entities that are -- hidden/unknown. hidden :: Display -> Display -- | The default way to display some terrain using the given character and -- attribute, with priority 0. defaultTerrainDisplay :: Char -> Attribute -> Display -- | Construct a default display for an entity that uses only a single -- display character, the default entity attribute, and priority 1. defaultEntityDisplay :: Char -> Display -- | Construct a default robot display for a given orientation, with -- display characters "X^>v<", the default robot -- attribute, and priority 10. -- -- Note that the defaultChar is used for direction DDown -- and is overridden for the special base robot. defaultRobotDisplay :: Display instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Display.Display instance Swarm.Util.Yaml.FromJSONE Swarm.Game.Display.Display Swarm.Game.Display.Display instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Display.Display instance GHC.Base.Monoid Swarm.Game.Display.Display instance Data.Hashable.Class.Hashable Swarm.Game.Display.Attribute instance GHC.Generics.Generic Swarm.Game.Display.Attribute instance GHC.Show.Show Swarm.Game.Display.Attribute instance GHC.Classes.Ord Swarm.Game.Display.Attribute instance GHC.Classes.Eq Swarm.Game.Display.Attribute instance Data.Hashable.Class.Hashable Swarm.Game.Display.Display instance GHC.Generics.Generic Swarm.Game.Display.Display instance GHC.Show.Show Swarm.Game.Display.Display instance GHC.Classes.Ord Swarm.Game.Display.Display instance GHC.Classes.Eq Swarm.Game.Display.Display instance GHC.Base.Semigroup Swarm.Game.Display.Display instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Display.Attribute instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Display.Attribute -- | Rendering attributes (i.e. foreground and background colors, -- styles, etc.) used by the Swarm TUI. -- -- We export constants only for those we use in the Haskell code and not -- those used in the world map, to avoid abusing attributes. For example -- using the robot attribute to highlight some text. -- -- The few attributes that we use for drawing the logo are an exception. module Swarm.TUI.Attr -- | A mapping from the defined attribute names to TUI attributes. swarmAttrMap :: AttrMap -- | Colors of entities in the world. -- -- Also used to color messages, so water is special and excluded. worldAttributes :: [(AttrName, Attr)] worldPrefix :: AttrName toAttrName :: Attribute -> AttrName dirtAttr :: AttrName grassAttr :: AttrName stoneAttr :: AttrName waterAttr :: AttrName iceAttr :: AttrName entityAttr :: AttrName -- | The default robot attribute. robotAttr :: AttrName rockAttr :: AttrName plantAttr :: AttrName -- | Some defined attribute names used in the Swarm TUI. highlightAttr :: AttrName -- | Some defined attribute names used in the Swarm TUI. notifAttr :: AttrName -- | Some defined attribute names used in the Swarm TUI. infoAttr :: AttrName -- | Some defined attribute names used in the Swarm TUI. boldAttr :: AttrName -- | Some defined attribute names used in the Swarm TUI. italicAttr :: AttrName -- | Some defined attribute names used in the Swarm TUI. dimAttr :: AttrName -- | Some basic colors used in TUI. magentaAttr :: AttrName -- | Some basic colors used in TUI. cyanAttr :: AttrName -- | Some basic colors used in TUI. lightCyanAttr :: AttrName -- | Some basic colors used in TUI. yellowAttr :: AttrName -- | Some basic colors used in TUI. blueAttr :: AttrName -- | Some basic colors used in TUI. greenAttr :: AttrName -- | Some basic colors used in TUI. redAttr :: AttrName -- | Some defined attribute names used in the Swarm TUI. defAttr :: AttrName customEditFocusedAttr :: AttrName module Swarm.TUI.View.CustomStyling toStyle :: StyleFlag -> Style toAttrColor :: HexColor -> Color toAttrPair :: CustomAttr -> (AttrName, Attr) -- | Terrain types and properties. module Swarm.Game.Terrain -- | The different possible types of terrain. Unlike entities and robots, -- these are hard-coded into the game. data TerrainType StoneT :: TerrainType DirtT :: TerrainType GrassT :: TerrainType IceT :: TerrainType BlankT :: TerrainType readTerrain :: Text -> Maybe TerrainType -- | A map containing a Display record for each different -- TerrainType. terrainMap :: Map TerrainType Display getTerrainDefaultPaletteChar :: TerrainType -> Char getTerrainWord :: TerrainType -> Text instance GHC.Enum.Enum Swarm.Game.Terrain.TerrainType instance GHC.Enum.Bounded Swarm.Game.Terrain.TerrainType instance GHC.Read.Read Swarm.Game.Terrain.TerrainType instance GHC.Show.Show Swarm.Game.Terrain.TerrainType instance GHC.Classes.Ord Swarm.Game.Terrain.TerrainType instance GHC.Classes.Eq Swarm.Game.Terrain.TerrainType instance GHC.Base.Semigroup Swarm.Game.Terrain.TerrainType instance GHC.Base.Monoid Swarm.Game.Terrain.TerrainType instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Terrain.TerrainType -- | An Entity represents an object that exists in the world. Each -- entity has a way to be displayed, some metadata such as a name and -- description, some properties, and possibly an inventory of other -- entities. -- -- This module also defines the Inventory type, since the two -- types are mutually recursive (an inventory contains entities, which -- can have inventories). module Swarm.Game.Entity -- | Various properties that an entity can have, which affect how robots -- can interact with it. data EntityProperty -- | Robots can't move onto a cell containing this entity. Unwalkable :: EntityProperty -- | Robots can pick this up (via Grab or Harvest). Portable :: EntityProperty -- | Obstructs the view of robots that attempt to "scout" Opaque :: EntityProperty -- | Regrows from a seed after it is harvested. Growable :: EntityProperty -- | Regenerates infinitely when grabbed or harvested. Infinite :: EntityProperty -- | Robots drown if they walk on this without a boat. Liquid :: EntityProperty -- | Robots automatically know what this is without having to scan it. Known :: EntityProperty -- | How long an entity takes to regrow. This represents the minimum and -- maximum amount of time taken by one growth stage (there are two -- stages). The actual time for each stage will be chosen uniformly at -- random between these two values. newtype GrowthTime GrowthTime :: (Integer, Integer) -> GrowthTime defaultGrowthTime :: GrowthTime -- | A record to hold information about an entity. -- -- The constructor for Entity is intentionally not exported. To -- construct one manually, use the mkEntity function. -- -- There are two main constraints on the way entities are stored: -- --
    --
  1. We want to be able to easily modify an entity in one particular -- cell of the world (for example, painting one tree red).
  2. --
  3. In an inventory, we want to store identical entities only once, -- along with a count.
  4. --
-- -- We could get (2) nicely by storing only names of entities, and having -- a global lookup table from names to entity records. However, storing -- names instead of actual entity records in the world makes (1) more -- complex: every time we modify an entity we would have to generate a -- fresh name for the modified entity and add it to the global entity -- table. This approach is also annoying because it means we can't just -- uses lenses to drill down into the properties of an entity in the -- world or in an inventory, but have to do an intermediate lookup in the -- global (mutable!) entity table. -- -- On the other hand, if we just store entity records everywhere, -- checking them for equality becomes expensive. Having an inventory be a -- map with entities themselves as keys sounds awful. -- -- The solution we adopt here is that every Entity record -- carries along a hash value of all the other fields. We just assume -- that these hashes are unique (a collision is of course possible but -- extremely unlikely). Entities can be efficiently compared just by -- looking at their hashes; they can be stored in a map using hash values -- as keys; and we provide lenses which automatically recompute the hash -- value when modifying a field of an entity record. Note also that world -- storage is still efficient, too: thanks to referential transparency, -- in practice most of the entities stored in the world that are the same -- will literally just be stored as pointers to the same shared record. data Entity -- | Create an entity with no orientation, an empty inventory, providing no -- capabilities (automatically filling in the hash value). mkEntity :: Display -> Text -> Document Syntax -> [EntityProperty] -> [Capability] -> Entity -- | The Display explaining how to draw this entity in the world -- display. entityDisplay :: Lens' Entity Display -- | The name of the entity. entityName :: Lens' Entity Text -- | The irregular plural version of the entity's name, if there is one. entityPlural :: Lens' Entity (Maybe Text) -- | Get a version of the entity's name appropriate to the number---the -- singular name for 1, and a plural name for any other number. The -- plural name is obtained either by looking it up if irregular, or by -- applying standard heuristics otherwise. entityNameFor :: Int -> Getter Entity Text -- | A longer, free-form description of the entity. Each Text value -- represents a paragraph. entityDescription :: Lens' Entity (Document Syntax) -- | The direction this entity is facing (if it has one). entityOrientation :: Lens' Entity (Maybe Heading) -- | How long this entity takes to grow, if it regrows. entityGrowth :: Lens' Entity (Maybe GrowthTime) -- | The name of a different entity yielded when this entity is grabbed, if -- any. entityYields :: Lens' Entity (Maybe Text) -- | The properties enjoyed by this entity. entityProperties :: Lens' Entity (Set EntityProperty) -- | Test whether an entity has a certain property. hasProperty :: Entity -> EntityProperty -> Bool -- | The capabilities this entity provides when equipped. entityCapabilities :: Lens' Entity (Set Capability) -- | The inventory of other entities carried by this entity. entityInventory :: Lens' Entity Inventory -- | Get the hash of an entity. Note that this is a getter, not a lens; the -- Swarm.Game.Entity module carefully maintains some internal -- invariants ensuring that hashes work properly, and by golly, no one -- else is going to mess that up. entityHash :: Getter Entity Int -- | An EntityMap is a data structure containing all the loaded -- entities, allowing them to be looked up either by name or by what -- capabilities they provide (if any). data EntityMap EntityMap :: Map Text Entity -> Map Capability [Entity] -> EntityMap [entitiesByName] :: EntityMap -> Map Text Entity [entitiesByCap] :: EntityMap -> Map Capability [Entity] -- | Build an EntityMap from a list of entities. The idea is that -- this will be called once at startup, when loading the entities from a -- file; see loadEntities. buildEntityMap :: Has (Throw LoadingFailure) sig m => [Entity] -> m EntityMap -- | Load entities from a data file called entities.yaml, -- producing either an EntityMap or a parse error. loadEntities :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => m EntityMap -- | Find an entity with the given name. lookupEntityName :: Text -> EntityMap -> Maybe Entity -- | Find all entities which are devices that provide the given capability. deviceForCap :: Capability -> EntityMap -> [Entity] -- | An inventory is really just a bag/multiset of entities. That is, it -- contains some entities, along with the number of times each occurs. -- Entities can be looked up directly, or by name. data Inventory -- | A convenient synonym to remind us when an Int is supposed to -- represent how many of something we have. type Count = Int -- | The empty inventory. empty :: Inventory -- | Create an inventory containing one entity. singleton :: Entity -> Inventory -- | Create an inventory from a list of entities. fromList :: [Entity] -> Inventory -- | Create an inventory from a list of entities and their counts. fromElems :: [(Count, Entity)] -> Inventory -- | Look up an entity in an inventory, returning the number of copies -- contained. lookup :: Entity -> Inventory -> Count -- | Look up an entity by name in an inventory, returning a list of -- matching entities. Note, if this returns some entities, it does *not* -- mean we necessarily have any in our inventory! It just means we *know -- about* them. If you want to know whether you have any, use -- lookup and see whether the resulting Count is positive, -- or just use countByName in the first place. lookupByName :: Text -> Inventory -> [Entity] -- | Look up an entity by name and see how many there are in the inventory. -- If there are multiple entities with the same name, it just picks the -- first one returned from lookupByName. countByName :: Text -> Inventory -> Count -- | Check whether an inventory contains at least one of a given entity. contains :: Inventory -> Entity -> Bool -- | Check whether an inventory has an entry for entity (used by robots). contains0plus :: Entity -> Inventory -> Bool -- | Get the entities in an inventory and their associated counts. elems :: Inventory -> [(Count, Entity)] -- | Check if the first inventory is a subset of the second. Note that -- entities with a count of 0 are ignored. isSubsetOf :: Inventory -> Inventory -> Bool -- | Check whether an inventory is empty, meaning that it contains 0 total -- entities (although it may still know about some entities, that -- is, have them as keys with a count of 0). isEmpty :: Inventory -> Bool -- | Compute the set of capabilities provided by the devices in an -- inventory. inventoryCapabilities :: Inventory -> Set Capability -- | List elements that possess a given Capability and exist with nonzero -- count in the inventory. extantElemsWithCapability :: Capability -> Inventory -> [Entity] -- | Groups entities by the capabilities they offer. entitiesByCapability :: Inventory -> Map Capability (NonEmpty Entity) -- | Insert an entity into an inventory. If the inventory already contains -- this entity, then only its count will be incremented. insert :: Entity -> Inventory -> Inventory -- | Insert a certain number of copies of an entity into an inventory. If -- the inventory already contains this entity, then only its count will -- be incremented. insertCount :: Count -> Entity -> Inventory -> Inventory -- | Delete a single copy of a certain entity from an inventory. delete :: Entity -> Inventory -> Inventory -- | Delete a specified number of copies of an entity from an inventory. deleteCount :: Count -> Entity -> Inventory -> Inventory -- | Delete all copies of a certain entity from an inventory. deleteAll :: Entity -> Inventory -> Inventory -- | Union two inventories. union :: Inventory -> Inventory -> Inventory -- | Subtract the second inventory from the first. difference :: Inventory -> Inventory -> Inventory instance Data.Hashable.Class.Hashable Swarm.Game.Entity.EntityProperty instance GHC.Generics.Generic Swarm.Game.Entity.EntityProperty instance GHC.Enum.Bounded Swarm.Game.Entity.EntityProperty instance GHC.Enum.Enum Swarm.Game.Entity.EntityProperty instance GHC.Read.Read Swarm.Game.Entity.EntityProperty instance GHC.Show.Show Swarm.Game.Entity.EntityProperty instance GHC.Classes.Ord Swarm.Game.Entity.EntityProperty instance GHC.Classes.Eq Swarm.Game.Entity.EntityProperty instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Entity.GrowthTime instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Entity.GrowthTime instance Data.Hashable.Class.Hashable Swarm.Game.Entity.GrowthTime instance GHC.Generics.Generic Swarm.Game.Entity.GrowthTime instance GHC.Read.Read Swarm.Game.Entity.GrowthTime instance GHC.Show.Show Swarm.Game.Entity.GrowthTime instance GHC.Classes.Ord Swarm.Game.Entity.GrowthTime instance GHC.Classes.Eq Swarm.Game.Entity.GrowthTime instance GHC.Generics.Generic Swarm.Game.Entity.Entity instance GHC.Show.Show Swarm.Game.Entity.Entity instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Entity.Inventory instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Entity.Inventory instance GHC.Generics.Generic Swarm.Game.Entity.Inventory instance GHC.Show.Show Swarm.Game.Entity.Inventory instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Entity.EntityMap instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Entity.EntityMap instance GHC.Generics.Generic Swarm.Game.Entity.EntityMap instance GHC.Show.Show Swarm.Game.Entity.EntityMap instance GHC.Classes.Eq Swarm.Game.Entity.EntityMap instance GHC.Base.Semigroup Swarm.Game.Entity.EntityMap instance GHC.Base.Monoid Swarm.Game.Entity.EntityMap instance Swarm.Util.Yaml.FromJSONE Swarm.Game.Entity.EntityMap Swarm.Game.Entity.Entity instance Data.Hashable.Class.Hashable Swarm.Game.Entity.Entity instance GHC.Classes.Eq Swarm.Game.Entity.Entity instance GHC.Classes.Ord Swarm.Game.Entity.Entity instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Entity.Entity instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Entity.Entity instance Data.Hashable.Class.Hashable Swarm.Game.Entity.Inventory instance GHC.Classes.Eq Swarm.Game.Entity.Inventory instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Entity.EntityProperty instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Entity.EntityProperty module Swarm.TUI.Inventory.Sorting data InventorySortOptions InventorySortOptions :: InventorySortDirection -> InventorySortOrder -> InventorySortOptions data InventorySortDirection Ascending :: InventorySortDirection Descending :: InventorySortDirection data InventorySortOrder ByNaturalAlphabetic :: InventorySortOrder ByQuantity :: InventorySortOrder ByType :: InventorySortOrder cycleSortOrder :: InventorySortOptions -> InventorySortOptions cycleSortDirection :: InventorySortOptions -> InventorySortOptions defaultSortOptions :: InventorySortOptions sortInventory :: Ord a => InventorySortOptions -> [(a, Entity)] -> [(a, Entity)] renderSortMethod :: InventorySortOptions -> Text instance GHC.Classes.Eq Swarm.TUI.Inventory.Sorting.InventorySortDirection instance GHC.Enum.Bounded Swarm.TUI.Inventory.Sorting.InventorySortDirection instance GHC.Enum.Enum Swarm.TUI.Inventory.Sorting.InventorySortDirection instance GHC.Classes.Eq Swarm.TUI.Inventory.Sorting.InventorySortOrder instance GHC.Enum.Bounded Swarm.TUI.Inventory.Sorting.InventorySortOrder instance GHC.Enum.Enum Swarm.TUI.Inventory.Sorting.InventorySortOrder -- | A world refers to the grid on which the game takes place, and -- the things in it (besides robots). A world has a base, immutable -- terrain layer, where each cell contains a terrain type, and a -- mutable entity layer, with at most one entity per cell. -- -- A world is technically finite but practically infinite (worlds are -- indexed by 32-bit signed integers, so they correspond to a -- <math> torus). module Swarm.Game.World -- | World coordinates use (row,column) format, with the row increasing as -- we move down the screen. We use this format for indexing worlds -- internally, since it plays nicely with things like drawing the screen, -- and reading maps from configuration files. The locToCoords and -- coordsToLoc functions convert back and forth between this type -- and Location, which is used when presenting coordinates -- externally to the player. newtype Coords Coords :: (Int32, Int32) -> Coords [unCoords] :: Coords -> (Int32, Int32) -- | Convert an external (x,y) location to an internal Coords value. locToCoords :: Location -> Coords -- | Convert an internal Coords value to an external (x,y) location. coordsToLoc :: Coords -> Location -- | Represents the top-left and bottom-right coordinates of a bounding -- rectangle of cells in the world map type BoundsRectangle = (Coords, Coords) -- | A WorldFun t e represents a 2D world with terrain of type -- t (exactly one per cell) and entities of type e (at -- most one per cell). newtype WorldFun t e WF :: (Coords -> (t, Erasable (Last e))) -> WorldFun t e [getWF] :: WorldFun t e -> Coords -> (t, Erasable (Last e)) runWF :: WorldFun t e -> Coords -> (t, Maybe e) -- | Create a world function from a finite array of specified cells. worldFunFromArray :: Monoid t => Array (Int32, Int32) (t, Erasable e) -> WorldFun t e -- | A World consists of a WorldFun that specifies the -- initial world, a cache of loaded square tiles to make lookups faster, -- and a map storing locations whose entities have changed from their -- initial values. -- -- Right now the World simply holds on to all the tiles it has -- ever loaded. Ideally it would use some kind of LRU caching scheme to -- keep memory usage bounded, but it would be a bit tricky, and in any -- case it's probably not going to matter much for a while. Once tile -- loads can trigger robots to spawn, it would also make for some -- difficult decisions in terms of how to handle respawning. data World t e type MultiWorld t e = Map SubworldName (World t e) -- | Load the tile containing a specific cell. loadCell :: IArray UArray t => Coords -> World t e -> World t e -- | Load all the tiles which overlap the given rectangular region -- (specified as an upper-left and lower-right corner, inclusive). loadRegion :: forall t e. IArray UArray t => (Coords, Coords) -> World t e -> World t e -- | Create a new World from a WorldFun. newWorld :: WorldFun t e -> World t e lookupCosmicTerrain :: IArray UArray Int => Cosmic Coords -> MultiWorld Int e -> TerrainType -- | Look up the terrain value at certain coordinates: try looking it up in -- the tile cache first, and fall back to running the WorldFun -- otherwise. -- -- This function does not ensure that the tile containing the -- given coordinates is loaded. For that, see lookupTerrainM. lookupTerrain :: IArray UArray t => Coords -> World t e -> t lookupCosmicEntity :: Cosmic Coords -> MultiWorld t e -> Maybe e -- | Look up the entity at certain coordinates: first, see if it is in the -- map of locations with changed entities; then try looking it up in the -- tile cache first; and finally fall back to running the -- WorldFun. -- -- This function does not ensure that the tile containing the -- given coordinates is loaded. For that, see lookupEntityM. lookupEntity :: Coords -> World t e -> Maybe e -- | Update the entity (or absence thereof) at a certain location, -- returning an updated World and a Boolean indicating whether the -- update changed the entity here. See also updateM. update :: Coords -> (Maybe Entity -> Maybe Entity) -> World t Entity -> (World t Entity, Bool) -- | A stateful variant of lookupTerrain, which first loads the tile -- containing the given coordinates if it is not already loaded, then -- looks up the terrain value. lookupTerrainM :: forall t e sig m. (Has (State (World t e)) sig m, IArray UArray t) => Coords -> m t -- | A stateful variant of lookupEntity, which first loads the tile -- containing the given coordinates if it is not already loaded, then -- looks up the terrain value. lookupEntityM :: forall t e sig m. (Has (State (World t e)) sig m, IArray UArray t) => Coords -> m (Maybe e) -- | A stateful variant of update, which also ensures the tile -- containing the given coordinates is loaded. updateM :: forall t sig m. (Has (State (World t Entity)) sig m, IArray UArray t) => Coords -> (Maybe Entity -> Maybe Entity) -> m Bool -- | Update world in an inspectable way. -- -- This type is used for changes by e.g. the drill command at later tick. -- Using ADT allows us to serialize and inspect the updates. data WorldUpdate e ReplaceEntity :: Cosmic Location -> e -> Maybe e -> WorldUpdate e [updatedLoc] :: WorldUpdate e -> Cosmic Location [originalEntity] :: WorldUpdate e -> e [newEntity] :: WorldUpdate e -> Maybe e instance GHC.Base.Monoid t => GHC.Base.Monoid (Swarm.Game.World.WorldFun t e) instance GHC.Base.Semigroup t => GHC.Base.Semigroup (Swarm.Game.World.WorldFun t e) instance GHC.Base.Functor (Swarm.Game.World.WorldFun t) instance GHC.Generics.Generic Swarm.Game.World.TileCoords instance GHC.Ix.Ix Swarm.Game.World.TileCoords instance GHC.Show.Show Swarm.Game.World.TileCoords instance GHC.Classes.Ord Swarm.Game.World.TileCoords instance GHC.Classes.Eq Swarm.Game.World.TileCoords instance GHC.Generics.Generic Swarm.Game.World.TileOffset instance GHC.Ix.Ix Swarm.Game.World.TileOffset instance GHC.Show.Show Swarm.Game.World.TileOffset instance GHC.Classes.Ord Swarm.Game.World.TileOffset instance GHC.Classes.Eq Swarm.Game.World.TileOffset instance Data.Aeson.Types.ToJSON.ToJSON e => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.World.WorldUpdate e) instance Data.Aeson.Types.FromJSON.FromJSON e => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.World.WorldUpdate e) instance GHC.Generics.Generic (Swarm.Game.World.WorldUpdate e) instance GHC.Show.Show e => GHC.Show.Show (Swarm.Game.World.WorldUpdate e) instance GHC.Classes.Ord e => GHC.Classes.Ord (Swarm.Game.World.WorldUpdate e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Swarm.Game.World.WorldUpdate e) instance Control.Lens.Wrapped.Rewrapped Swarm.Game.World.TileOffset t instance Control.Lens.Wrapped.Wrapped Swarm.Game.World.TileOffset instance Control.Lens.Wrapped.Rewrapped Swarm.Game.World.TileCoords t instance Control.Lens.Wrapped.Wrapped Swarm.Game.World.TileCoords instance Data.Bifunctor.Bifunctor Swarm.Game.World.WorldFun -- | Stand-in type for an Entity for purposes that do not require -- carrying around the entire state of an Entity. -- -- Useful for simplified serialization, debugging, and equality checking, -- particularly for the World Editor. module Swarm.Game.Scenario.Topography.EntityFacade type EntityName = Text -- | This datatype is a lightweight stand-in for the full-fledged -- Entity type without the baggage of all of its other fields. It -- contains the bare minimum display information for rendering. data EntityFacade EntityFacade :: EntityName -> Display -> EntityFacade mkFacade :: Entity -> EntityFacade instance GHC.Classes.Eq Swarm.Game.Scenario.Topography.EntityFacade.EntityFacade instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Topography.EntityFacade.EntityFacade -- | A recipe represents some kind of process for transforming some input -- entities into some output entities. module Swarm.Game.Recipe -- | An ingredient list is a list of entities with multiplicity. It is -- polymorphic in the entity type so that we can use either entity names -- when serializing, or actual entity objects while the game is running. type IngredientList e = [(Count, e)] -- | A recipe is just a list of input entities and a list of output -- entities (both with multiplicity). The idea is that it represents some -- kind of process where the inputs are transformed into the outputs. data Recipe e Recipe :: IngredientList e -> IngredientList e -> IngredientList e -> Integer -> Integer -> Recipe e [_recipeInputs] :: Recipe e -> IngredientList e [_recipeOutputs] :: Recipe e -> IngredientList e [_recipeRequirements] :: Recipe e -> IngredientList e [_recipeTime] :: Recipe e -> Integer [_recipeWeight] :: Recipe e -> Integer -- | The inputs to a recipe. recipeInputs :: Lens' (Recipe e) (IngredientList e) -- | The outputs from a recipe. recipeOutputs :: Lens' (Recipe e) (IngredientList e) -- | Other entities which the recipe requires you to have, but which are -- not consumed by the recipe (e.g. a furnace). recipeRequirements :: Lens' (Recipe e) (IngredientList e) -- | The time required to finish a recipe. recipeTime :: Lens' (Recipe e) Integer -- | How this recipe is weighted against other recipes. Any time there are -- multiple valid recipes that fit certain criteria, one of the recipes -- will be randomly chosen with probability proportional to its weight. recipeWeight :: Lens' (Recipe e) Integer -- | Given an already loaded EntityMap, try to load a list of -- recipes from the data file recipes.yaml. loadRecipes :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => EntityMap -> m [Recipe Entity] -- | Build a map of recipes indexed by output ingredients. outRecipeMap :: [Recipe Entity] -> IntMap [Recipe Entity] -- | Build a map of recipes indexed by input ingredients. inRecipeMap :: [Recipe Entity] -> IntMap [Recipe Entity] -- | Build a map of recipes indexed by requirements. reqRecipeMap :: [Recipe Entity] -> IntMap [Recipe Entity] data MissingIngredient MissingIngredient :: MissingType -> Count -> Entity -> MissingIngredient data MissingType MissingInput :: MissingType MissingCatalyst :: MissingType -- | Figure out if a recipe is available, but it can be lacking items. knowsIngredientsFor :: (Inventory, Inventory) -> Recipe Entity -> Bool -- | Get a list of all the recipes for the given entity. Look up an entity -- in either an inRecipeMap or outRecipeMap depending on -- whether you want to know recipes that consume or produce the given -- entity, respectively. recipesFor :: IntMap [Recipe Entity] -> Entity -> [Recipe Entity] -- | Try to make a recipe, deleting the recipe's inputs from the inventory. -- Return either a description of which items are lacking, if the -- inventory does not contain sufficient inputs, or an inventory without -- inputs and function adding outputs if it was successful. make :: (Inventory, Inventory) -> Recipe Entity -> Either [MissingIngredient] (Inventory, IngredientList Entity, Recipe Entity) -- | Try to make a recipe, but do not insert it yet. make' :: (Inventory, Inventory) -> Recipe Entity -> Either [MissingIngredient] (Inventory, IngredientList Entity) instance GHC.Classes.Eq Swarm.Game.Recipe.MissingType instance GHC.Show.Show Swarm.Game.Recipe.MissingType instance GHC.Classes.Eq Swarm.Game.Recipe.MissingIngredient instance GHC.Show.Show Swarm.Game.Recipe.MissingIngredient instance Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Recipe.Recipe Data.Text.Internal.Text) instance Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.Recipe.Recipe Data.Text.Internal.Text) instance Swarm.Util.Yaml.FromJSONE Swarm.Game.Entity.EntityMap (Swarm.Game.Recipe.Recipe Swarm.Game.Entity.Entity) instance GHC.Generics.Generic (Swarm.Game.Recipe.Recipe e) instance Data.Traversable.Traversable Swarm.Game.Recipe.Recipe instance Data.Foldable.Foldable Swarm.Game.Recipe.Recipe instance GHC.Base.Functor Swarm.Game.Recipe.Recipe instance GHC.Show.Show e => GHC.Show.Show (Swarm.Game.Recipe.Recipe e) instance GHC.Classes.Ord e => GHC.Classes.Ord (Swarm.Game.Recipe.Recipe e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Swarm.Game.Recipe.Recipe e) instance Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Recipe.Recipe Swarm.Game.Entity.Entity) instance Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.Recipe.Recipe Swarm.Game.Entity.Entity) -- | Runtime exceptions for the Swarm language interpreter. module Swarm.Game.Exception -- | The type of exceptions that can be thrown by robot programs. data Exn -- | Something went very wrong. This is a bug in Swarm and cannot be caught -- by a try block (but at least it will not crash the entire -- UI). Fatal :: Text -> Exn -- | An infinite loop was detected via a blackhole. This cannot be caught -- by a try block. InfiniteLoop :: Exn -- | A robot tried to do something for which it does not have some of the -- required capabilities. This cannot be caught by a try block. Incapable :: IncapableFix -> Requirements -> Term -> Exn -- | A command failed in some "normal" way (e.g. a Move -- command could not move, or a Grab command found nothing to -- grab, etc.). CmdFailed :: Const -> Text -> Maybe GameplayAchievement -> Exn -- | The user program explicitly called Undefined or -- Fail. User :: Text -> Exn -- | Suggested way to fix incapable error. data IncapableFix -- | Equip the missing device on yourself/target FixByEquip :: IncapableFix -- | Add the missing device to your inventory FixByObtain :: IncapableFix -- | Pretty-print an exception for displaying to the player. formatExn :: EntityMap -> Exn -> Text -- | Pretty print the incapable exception with an actionable suggestion on -- how to fix it. -- --
--   >>> import Data.Either (fromRight)
--   
--   >>> import Control.Carrier.Throw.Either (runThrow)
--   
--   >>> import Control.Algebra (run)
--   
--   >>> import Swarm.Game.Failure (LoadingFailure)
--   
--   >>> :set -XTypeApplications
--   
--   >>> w = mkEntity (defaultEntityDisplay 'l') "magic wand" mempty mempty [CAppear]
--   
--   >>> r = mkEntity (defaultEntityDisplay 'o') "the one ring" mempty mempty [CAppear]
--   
--   >>> m = fromRight mempty . run . runThrow @LoadingFailure $ buildEntityMap [w,r]
--   
--   >>> incapableError cs t = putStr . unpack $ formatIncapable m FixByEquip cs t
--   
-- --
--   >>> incapableError (R.singletonCap CGod) (TConst As)
--   Thou shalt not utter such blasphemy:
--     'as'
--     If God in troth thou wantest to play, try thou a Creative game.
--   
-- --
--   >>> incapableError (R.singletonCap CAppear) (TConst Appear)
--   You do not have the devices required for:
--     'appear'
--     Please equip:
--     - the one ring or magic wand
--   
-- --
--   >>> incapableError (R.singletonCap CRandom) (TConst Random)
--   Missing the random capability for:
--     'random'
--     but no device yet provides it. See
--     https://github.com/swarm-game/swarm/issues/26
--   
-- --
--   >>> incapableError (R.singletonInv 3 "tree") (TConst Noop)
--   You are missing required inventory for:
--     'noop'
--     Please obtain:
--     - tree (3)
--   
formatIncapable :: EntityMap -> IncapableFix -> Requirements -> Term -> Text formatIncapableFix :: IncapableFix -> Text instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Exception.IncapableFix instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Exception.IncapableFix instance GHC.Generics.Generic Swarm.Game.Exception.IncapableFix instance GHC.Show.Show Swarm.Game.Exception.IncapableFix instance GHC.Classes.Eq Swarm.Game.Exception.IncapableFix instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Exception.Exn instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Exception.Exn instance GHC.Generics.Generic Swarm.Game.Exception.Exn instance GHC.Show.Show Swarm.Game.Exception.Exn instance GHC.Classes.Eq Swarm.Game.Exception.Exn -- | The Swarm interpreter uses a technique known as a CESK machine -- (if you want to read up on them, you may want to start by reading -- about CEK machines first). Execution happens simply by -- iterating a step function, sending one state of the CESK machine to -- the next. In addition to being relatively efficient, this means we can -- easily run a bunch of robots synchronously, in parallel, without -- resorting to any threads (by stepping their machines in a round-robin -- fashion); pause and single-step the game; save and resume, and so on. -- -- Essentially, a CESK machine state has four components: -- -- -- -- You can think of a CESK machine as a defunctionalization of a -- recursive big-step interpreter, where we explicitly keep track of the -- call stack and the environments that would be in effect at various -- places in the recursion. One could probably even derive this -- mechanically, by writing a recursive big-step interpreter, then -- converting it to CPS, then defunctionalizing the continuations. -- -- The slightly confusing thing about CESK machines is how we have to -- pass around environments everywhere. Basically, anywhere there can be -- unevaluated terms containing free variables (in values, in -- continuation stack frames, ...), we have to store the proper -- environment alongside so that when we eventually get around to -- evaluating it, we will be able to pull out the environment to use. module Swarm.Game.CESK -- | A frame is a single component of a continuation stack, explaining what -- to do next after we finish evaluating the currently focused term. data Frame -- | We were evaluating the first component of a pair; next, we should -- evaluate the second component which was saved in this frame (and push -- a FFst frame on the stack to save the first component). FSnd :: Term -> Env -> Frame -- | We were evaluating the second component of a pair; when done, we -- should combine it with the value of the first component saved in this -- frame to construct a fully evaluated pair. FFst :: Value -> Frame -- | FArg t e says that we were evaluating the left-hand side of -- an application, so the next thing we should do is evaluate the term -- t (the right-hand side, i.e. argument of the -- application) in environment e. We will also push an -- FApp frame on the stack. FArg :: Term -> Env -> Frame -- | FApp v says that we were evaluating the right-hand side of an -- application; once we are done, we should pass the resulting value as -- an argument to v. FApp :: Value -> Frame -- | FLet x t2 e says that we were evaluating a term t1 -- in an expression of the form let x = t1 in t2, that is, we -- were evaluating the definition of x; the next thing we should -- do is evaluate t2 in the environment e extended with -- a binding for x. FLet :: Var -> Term -> Env -> Frame -- | We are executing inside a Try block. If an exception is raised, -- we will execute the stored term (the "catch" block). FTry :: Value -> Frame -- | We were executing a command; next we should take any environment it -- returned and union it with this one to produce the result of a bind -- expression. FUnionEnv :: Env -> Frame -- | We were executing a command that might have definitions; next we -- should take the resulting Env and add it to the robot's -- robotEnv, along with adding this accompanying Ctx and -- ReqCtx to the robot's robotCtx. FLoadEnv :: TCtx -> ReqCtx -> Frame -- | We were executing a definition; next we should take the resulting -- value and return a context binding the variable to the value. FDef :: Var -> Frame -- | An FExec frame means the focused value is a command, which we -- should now execute. FExec :: Frame -- | We are in the process of executing the first component of a bind; once -- done, we should also execute the second component in the given -- environment (extended by binding the variable, if there is one, to the -- output of the first command). FBind :: Maybe Var -> Term -> Env -> Frame -- | Discard any environment generated as the result of executing a -- command. FDiscardEnv :: Frame -- | Apply specific updates to the world and current robot. -- -- The Const is used to track the original command for error -- messages. FImmediate :: Const -> [WorldUpdate Entity] -> [RobotUpdate] -> Frame -- | Update the memory cell at a certain location with the computed value. FUpdate :: Addr -> Frame -- | Signal that we are done with an atomic computation. FFinishAtomic :: Frame -- | We are in the middle of running a computation for all the nearby -- robots. We have the function to run, and the list of robot IDs to run -- it on. FMeetAll :: Value -> [Int] -> Frame -- | We are in the middle of evaluating a record: some fields have already -- been evaluated; we are focusing on evaluating one field; and some -- fields have yet to be evaluated. FRcd :: Env -> [(Var, Value)] -> Var -> [(Var, Maybe Term)] -> Frame -- | We are in the middle of evaluating a record field projection.(:*:) FProj :: Var -> Frame -- | A continuation is just a stack of frames. type Cont = [Frame] -- | Update world in an inspectable way. -- -- This type is used for changes by e.g. the drill command at later tick. -- Using ADT allows us to serialize and inspect the updates. data WorldUpdate e ReplaceEntity :: Cosmic Location -> e -> Maybe e -> WorldUpdate e [updatedLoc] :: WorldUpdate e -> Cosmic Location [originalEntity] :: WorldUpdate e -> e [newEntity] :: WorldUpdate e -> Maybe e -- | Update the robot in an inspectable way. -- -- This type is used for changes by e.g. the drill command at later tick. -- Using ADT allows us to serialize and inspect the updates. -- -- Note that this can not be in Robot as it would create a cyclic -- dependency. data RobotUpdate AddEntity :: Count -> Entity -> RobotUpdate LearnEntity :: Entity -> RobotUpdate -- | Store represents a store, indexing integer locations to -- Cells. data Store type Addr = Int emptyStore :: Store -- | A memory cell can be in one of three states. data Cell -- | A cell starts out life as an unevaluated term together with its -- environment. E :: Term -> Env -> Cell -- | When the cell is Forced, it is set to a Blackhole while -- being evaluated. If it is ever referenced again while still a -- Blackhole, that means it depends on itself in a way that would -- trigger an infinite loop, and we can signal an error. (Of course, we -- <http://www.lel.ed.ac.uk/~gpullum/loopsnoop.html cannot -- detect all infinite loops this way>.) -- -- A Blackhole saves the original Term and Env that -- are being evaluated; if Ctrl-C is used to cancel a computation while -- we are in the middle of evaluating a cell, the Blackhole can be -- reset to E. Blackhole :: Term -> Env -> Cell -- | Once evaluation is complete, we cache the final Value in the -- Cell, so that subsequent lookups can just use it without -- recomputing anything. V :: Value -> Cell -- | Allocate a new memory cell containing an unevaluated expression with -- the current environment. Return the index of the allocated cell. allocate :: Env -> Term -> Store -> (Addr, Store) -- | Look up the cell at a given index. lookupCell :: Addr -> Store -> Maybe Cell -- | Set the cell at a given index. setCell :: Addr -> Cell -> Store -> Store -- | The overall state of a CESK machine, which can actually be one of -- three kinds of states. The CESK machine is named after the first kind -- of state, and it would probably be possible to inline a bunch of -- things and get rid of the second state, but I find it much more -- natural and elegant this way. Most tutorial presentations of CEK/CESK -- machines only have one kind of state, but then again, most tutorial -- presentations only deal with the bare lambda calculus, so one can tell -- whether a term is a value just by seeing whether it is syntactically a -- lambda. I learned this approach from Harper's Practical Foundations of -- Programming Languages. data CESK -- | When we are on our way "in/down" into a term, we have a currently -- focused term to evaluate in the environment, a store, and a -- continuation. In this mode we generally pattern-match on the -- Term to decide what to do next. In :: Term -> Env -> Store -> Cont -> CESK -- | Once we finish evaluating a term, we end up with a Value and we -- switch into "out" mode, bringing the value back up out of the depths -- to the context that was expecting it. In this mode we generally -- pattern-match on the Cont to decide what to do next. -- -- Note that there is no Env, because we don't have anything with -- variables to evaluate at the moment, and we maintain the invariant -- that any unevaluated terms buried inside a Value or Cont -- must carry along their environment with them. Out :: Value -> Store -> Cont -> CESK -- | An exception has been raised. Keep unwinding the continuation stack -- (until finding an enclosing Try in the case of a command -- failure or a user-generated exception, or until the stack is empty in -- the case of a fatal exception). Up :: Exn -> Store -> Cont -> CESK -- | The machine is waiting for the game to reach a certain time to resume -- its execution. Waiting :: TickNumber -> CESK -> CESK -- | Initialize a machine state with a starting term along with its type; -- the term will be executed or just evaluated depending on whether it -- has a command type or not. initMachine :: ProcessedTerm -> Env -> Store -> CESK -- | Like initMachine, but also take an explicit starting -- continuation. initMachine' :: ProcessedTerm -> Env -> Store -> Cont -> CESK -- | Cancel the currently running computation. cancel :: CESK -> CESK -- | Reset any Blackholes in the Store. We need to use this -- any time a running computation is interrupted, either by an exception -- or by a Ctrl+C. resetBlackholes :: Store -> Store -- | Is the CESK machine in a final (finished) state? If so, extract the -- final value and store. finalValue :: CESK -> Maybe (Value, Store) newtype TickNumber TickNumber :: Integer -> TickNumber [getTickNumber] :: TickNumber -> Integer addTicks :: Integer -> TickNumber -> TickNumber instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.CESK.TickNumber instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.CESK.TickNumber instance GHC.Generics.Generic Swarm.Game.CESK.TickNumber instance GHC.Read.Read Swarm.Game.CESK.TickNumber instance GHC.Show.Show Swarm.Game.CESK.TickNumber instance GHC.Classes.Ord Swarm.Game.CESK.TickNumber instance GHC.Classes.Eq Swarm.Game.CESK.TickNumber instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.CESK.Cell instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.CESK.Cell instance GHC.Generics.Generic Swarm.Game.CESK.Cell instance GHC.Classes.Eq Swarm.Game.CESK.Cell instance GHC.Show.Show Swarm.Game.CESK.Cell instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.CESK.Store instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.CESK.Store instance GHC.Generics.Generic Swarm.Game.CESK.Store instance GHC.Classes.Eq Swarm.Game.CESK.Store instance GHC.Show.Show Swarm.Game.CESK.Store instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.CESK.RobotUpdate instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.CESK.RobotUpdate instance GHC.Generics.Generic Swarm.Game.CESK.RobotUpdate instance GHC.Show.Show Swarm.Game.CESK.RobotUpdate instance GHC.Classes.Ord Swarm.Game.CESK.RobotUpdate instance GHC.Classes.Eq Swarm.Game.CESK.RobotUpdate instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.CESK.Frame instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.CESK.Frame instance GHC.Generics.Generic Swarm.Game.CESK.Frame instance GHC.Show.Show Swarm.Game.CESK.Frame instance GHC.Classes.Eq Swarm.Game.CESK.Frame instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.CESK.CESK instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.CESK.CESK instance GHC.Generics.Generic Swarm.Game.CESK.CESK instance GHC.Show.Show Swarm.Game.CESK.CESK instance GHC.Classes.Eq Swarm.Game.CESK.CESK instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.CESK.CESK instance Prettyprinter.Internal.Pretty Swarm.Game.CESK.TickNumber -- | Data types and instances for specific scoring methods module Swarm.Game.Scenario.Scoring.ConcreteMetrics scenarioOptions :: Options data DurationMetrics DurationMetrics :: NominalDiffTime -> TickNumber -> DurationMetrics -- | Time elapsed until winning the scenario. [_scenarioElapsed] :: DurationMetrics -> NominalDiffTime -- | Ticks elapsed until winning the scenario. [_scenarioElapsedTicks] :: DurationMetrics -> TickNumber scenarioElapsedTicks :: Lens' DurationMetrics TickNumber scenarioElapsed :: Lens' DurationMetrics NominalDiffTime emptyDurationMetric :: DurationMetrics data AttemptMetrics AttemptMetrics :: DurationMetrics -> Maybe ScenarioCodeMetrics -> AttemptMetrics [_scenarioDurationMetrics] :: AttemptMetrics -> DurationMetrics -- | Size of the user's program. [_scenarioCodeMetrics] :: AttemptMetrics -> Maybe ScenarioCodeMetrics emptyAttemptMetric :: AttemptMetrics scenarioDurationMetrics :: Lens' AttemptMetrics DurationMetrics scenarioCodeMetrics :: Lens' AttemptMetrics (Maybe ScenarioCodeMetrics) instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Scoring.ConcreteMetrics.AttemptMetrics instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Scoring.ConcreteMetrics.AttemptMetrics instance GHC.Generics.Generic Swarm.Game.Scenario.Scoring.ConcreteMetrics.AttemptMetrics instance GHC.Read.Read Swarm.Game.Scenario.Scoring.ConcreteMetrics.AttemptMetrics instance GHC.Show.Show Swarm.Game.Scenario.Scoring.ConcreteMetrics.AttemptMetrics instance GHC.Classes.Ord Swarm.Game.Scenario.Scoring.ConcreteMetrics.AttemptMetrics instance GHC.Classes.Eq Swarm.Game.Scenario.Scoring.ConcreteMetrics.AttemptMetrics instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Scoring.ConcreteMetrics.DurationMetrics instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Scoring.ConcreteMetrics.DurationMetrics instance GHC.Generics.Generic Swarm.Game.Scenario.Scoring.ConcreteMetrics.DurationMetrics instance GHC.Read.Read Swarm.Game.Scenario.Scoring.ConcreteMetrics.DurationMetrics instance GHC.Show.Show Swarm.Game.Scenario.Scoring.ConcreteMetrics.DurationMetrics instance GHC.Classes.Ord Swarm.Game.Scenario.Scoring.ConcreteMetrics.DurationMetrics instance GHC.Classes.Eq Swarm.Game.Scenario.Scoring.ConcreteMetrics.DurationMetrics -- | Types and records for updating and retrieving the best scores for a -- scenario. module Swarm.Game.Scenario.Scoring.Best data BestByCriteria BestByTime :: BestByCriteria BestByTicks :: BestByCriteria BestByCharCount :: BestByCriteria BestByAstSize :: BestByCriteria describeCriteria :: BestByCriteria -> Text data ProgressStats ProgressStats :: ZonedTime -> AttemptMetrics -> ProgressStats -- | Time when the scenario was started including time zone. [_scenarioStarted] :: ProgressStats -> ZonedTime [_scenarioAttemptMetrics] :: ProgressStats -> AttemptMetrics scenarioStarted :: Lens' ProgressStats ZonedTime scenarioAttemptMetrics :: Lens' ProgressStats AttemptMetrics type ProgressMetric = Metric ProgressStats data BestRecords BestRecords :: ProgressMetric -> ProgressMetric -> ProgressMetric -> ProgressMetric -> BestRecords [_scenarioBestByTime] :: BestRecords -> ProgressMetric [_scenarioBestByTicks] :: BestRecords -> ProgressMetric [_scenarioBestByCharCount] :: BestRecords -> ProgressMetric [_scenarioBestByAstSize] :: BestRecords -> ProgressMetric emptyBest :: ZonedTime -> BestRecords updateBest :: ProgressMetric -> BestRecords -> BestRecords -- | The best status of the scenario, measured in real world time. scenarioBestByTime :: Lens' BestRecords ProgressMetric -- | The best status of the scenario, measured in game ticks. scenarioBestByTicks :: Lens' BestRecords ProgressMetric -- | The best code size of the scenario, measured in character count. scenarioBestByCharCount :: Lens' BestRecords ProgressMetric -- | The best code size of the scenario, measured in AST size. scenarioBestByAstSize :: Lens' BestRecords ProgressMetric -- | Uses the start time of the play-attempt to de-dupe records that are -- from the same game. The start time should be sufficient to uniquely -- identify a game. getBestGroups :: BestRecords -> [(Metric ProgressStats, NonEmpty BestByCriteria)] instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Scoring.Best.BestRecords instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Scoring.Best.BestRecords instance GHC.Generics.Generic Swarm.Game.Scenario.Scoring.Best.BestRecords instance GHC.Read.Read Swarm.Game.Scenario.Scoring.Best.BestRecords instance GHC.Classes.Ord Swarm.Game.Scenario.Scoring.Best.BestRecords instance GHC.Classes.Eq Swarm.Game.Scenario.Scoring.Best.BestRecords instance GHC.Show.Show Swarm.Game.Scenario.Scoring.Best.BestRecords instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Scoring.Best.ProgressStats instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Scoring.Best.ProgressStats instance GHC.Show.Show Swarm.Game.Scenario.Scoring.Best.BestByCriteria instance GHC.Enum.Enum Swarm.Game.Scenario.Scoring.Best.BestByCriteria instance GHC.Enum.Bounded Swarm.Game.Scenario.Scoring.Best.BestByCriteria instance GHC.Classes.Ord Swarm.Game.Scenario.Scoring.Best.BestByCriteria instance GHC.Classes.Eq Swarm.Game.Scenario.Scoring.Best.BestByCriteria instance GHC.Generics.Generic Swarm.Game.Scenario.Scoring.Best.ProgressStats instance GHC.Read.Read Swarm.Game.Scenario.Scoring.Best.ProgressStats instance GHC.Show.Show Swarm.Game.Scenario.Scoring.Best.ProgressStats instance GHC.Classes.Ord Swarm.Game.Scenario.Scoring.Best.ProgressStats instance GHC.Classes.Eq Swarm.Game.Scenario.Scoring.Best.ProgressStats instance GHC.Classes.Eq Data.Time.LocalTime.Internal.ZonedTime.ZonedTime instance GHC.Classes.Ord Data.Time.LocalTime.Internal.ZonedTime.ZonedTime -- | A data type to represent in-game logs by robots. -- -- Because of the use of system robots, we sometimes want to use special -- kinds of logs that will be shown to the player. -- -- TODO: #1039 Currently we abuse this system for system logs, which is -- fun, but we should eventually make a dedicated SystemLogEntry -- type for RuntimeState message queue. module Swarm.Game.Log -- | Source of the robot log. data LogSource -- | Log produced by Say Said :: LogSource -- | Log produced by Log Logged :: LogSource -- | Log produced by an exception or system. ErrorTrace :: ErrorLevel -> LogSource -- | Severity of the error - critical errors are bugs and should be -- reported as Issues. data ErrorLevel Debug :: ErrorLevel Warning :: ErrorLevel Error :: ErrorLevel Critical :: ErrorLevel -- | An entry in a robot's log. data LogEntry LogEntry :: TickNumber -> LogSource -> Text -> Int -> LogLocation (Cosmic Location) -> Text -> LogEntry -- | The time at which the entry was created. Note that this is the first -- field we sort on. [_leTime] :: LogEntry -> TickNumber -- | Whether this log records a said message. [_leSource] :: LogEntry -> LogSource -- | The name of the robot that generated the entry. [_leRobotName] :: LogEntry -> Text -- | The ID of the robot that generated the entry. [_leRobotID] :: LogEntry -> Int -- | Location of the robot at log entry creation. [_leLocation] :: LogEntry -> LogLocation (Cosmic Location) -- | The text of the log entry. [_leText] :: LogEntry -> Text data LogLocation a Omnipresent :: LogLocation a Located :: a -> LogLocation a leText :: Lens' LogEntry Text leSource :: Lens' LogEntry LogSource leRobotName :: Lens' LogEntry Text leTime :: Lens' LogEntry TickNumber leLocation :: Lens' LogEntry (LogLocation (Cosmic Location)) leRobotID :: Lens' LogEntry Int instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Log.ErrorLevel instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Log.ErrorLevel instance GHC.Generics.Generic Swarm.Game.Log.ErrorLevel instance GHC.Classes.Ord Swarm.Game.Log.ErrorLevel instance GHC.Classes.Eq Swarm.Game.Log.ErrorLevel instance GHC.Show.Show Swarm.Game.Log.ErrorLevel instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Log.LogSource instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Log.LogSource instance GHC.Generics.Generic Swarm.Game.Log.LogSource instance GHC.Classes.Ord Swarm.Game.Log.LogSource instance GHC.Classes.Eq Swarm.Game.Log.LogSource instance GHC.Show.Show Swarm.Game.Log.LogSource instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Log.LogLocation a) instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.Log.LogLocation a) instance GHC.Generics.Generic (Swarm.Game.Log.LogLocation a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Swarm.Game.Log.LogLocation a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Swarm.Game.Log.LogLocation a) instance GHC.Show.Show a => GHC.Show.Show (Swarm.Game.Log.LogLocation a) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Log.LogEntry instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Log.LogEntry instance GHC.Generics.Generic Swarm.Game.Log.LogEntry instance GHC.Classes.Ord Swarm.Game.Log.LogEntry instance GHC.Classes.Eq Swarm.Game.Log.LogEntry instance GHC.Show.Show Swarm.Game.Log.LogEntry -- | A data type to represent robots. module Swarm.Game.Robot -- | The phase of a robot description record. data RobotPhase -- | The robot record has just been read in from a scenario description; it -- represents a template that may later be instantiated as one or -- more concrete robots. TemplateRobot :: RobotPhase -- | The robot record represents a concrete robot in the world. ConcreteRobot :: RobotPhase -- | A unique identifier for a robot. type RID = Int -- | A value of type RobotR is a record representing the state of a -- single robot. The f parameter is for tracking whether or not -- the robot has been assigned a unique ID. data RobotR (phase :: RobotPhase) -- | A concrete robot, with a unique ID number and a specific location. type Robot = RobotR 'ConcreteRobot -- | A template robot, i.e. a template robot record without a unique ID -- number, and possibly without a location. type TRobot = RobotR 'TemplateRobot -- | Update the robot in an inspectable way. -- -- This type is used for changes by e.g. the drill command at later tick. -- Using ADT allows us to serialize and inspect the updates. -- -- Note that this can not be in Robot as it would create a cyclic -- dependency. data RobotUpdate AddEntity :: Count -> Entity -> RobotUpdate LearnEntity :: Entity -> RobotUpdate -- | A record that stores the information for all definitions stored in a -- Robot data RobotContext defTypes :: Lens' RobotContext TCtx defReqs :: Lens' RobotContext ReqCtx defVals :: Lens' RobotContext Env defStore :: Lens' RobotContext Store emptyRobotContext :: RobotContext -- | Robots are not entities, but they have almost all the characteristics -- of one (or perhaps we could think of robots as very special sorts of -- entities), so for convenience each robot carries an Entity -- record to store all the information it has in common with any -- Entity. -- -- Note there are various lenses provided for convenience that directly -- reference fields inside this record; for example, one can use -- robotName instead of writing robotEntity . -- entityName. robotEntity :: Lens' (RobotR phase) Entity -- | The name of a robot. robotName :: Lens' Robot Text -- | The name of a robot template. trobotName :: Lens' TRobot Text -- | The creation date of the robot. robotCreatedAt :: Lens' Robot TimeSpec -- | The Display of a robot. This is a special lens that -- automatically sets the curOrientation to the orientation of the -- robot every time you do a get operation. Technically this -- does not satisfy the lens laws---in particular, the get/put law does -- not hold. But we should think of the curOrientation as being -- simply a cache of the displayed entity's direction. robotDisplay :: Lens' Robot Display -- | The robot's current location, represented as (x,y). This is only a -- getter, since when changing a robot's location we must remember to -- update the robotsByLocation map as well. You can use the -- updateRobotLocation function for this purpose. robotLocation :: Getter Robot (Cosmic Location) -- | Set a robot's location. This is unsafe and should never be called -- directly except by the updateRobotLocation function. The -- reason is that we need to make sure the robotsByLocation map -- stays in sync. unsafeSetRobotLocation :: Cosmic Location -> Robot -> Robot -- | A template robot's location. Unlike robotLocation, this is a -- lens, since when dealing with robot templates there is as yet no -- robotsByLocation map to keep up-to-date. trobotLocation :: Lens' TRobot (Maybe (Cosmic Location)) -- | Which way the robot is currently facing. robotOrientation :: Lens' Robot (Maybe Heading) -- | The robot's inventory. robotInventory :: Lens' Robot Inventory -- | A separate inventory for equipped devices, which provide the robot -- with certain capabilities. -- -- Note that every time the inventory of equipped devices is modified, -- this lens recomputes a cached set of the capabilities the equipped -- devices provide, to speed up subsequent lookups to see whether the -- robot has a certain capability (see robotCapabilities) equippedDevices :: Lens' Robot Inventory -- | The robot's own private message log, most recent message last. -- Messages can be added both by explicit use of the Log -- command, and by uncaught exceptions. Stored as a Data.Sequence -- so that we can efficiently add to the end and also process from -- beginning to end. Note that updating via this lens will also set the -- robotLogUpdated. robotLog :: Lens' Robot (Seq LogEntry) -- | Has the robotLog been updated since the last time it was -- viewed? robotLogUpdated :: Lens' Robot Bool -- | A hash of a robot's entity record and equipped devices, to facilitate -- quickly deciding whether we need to redraw the robot info panel. inventoryHash :: Getter Robot Int -- | Get the set of capabilities this robot possesses. This is only a -- getter, not a lens, because it is automatically generated from the -- equippedDevices. The only way to change a robot's capabilities -- is to modify its equippedDevices. robotCapabilities :: Getter Robot (Set Capability) -- | The robot's context. robotContext :: Lens' Robot RobotContext -- | The robot's context. trobotContext :: Lens' TRobot RobotContext -- | The (unique) ID number of the robot. This is only a Getter since the -- robot ID is immutable. robotID :: Getter Robot RID -- | The ID number of the robot's parent, that is, the robot that built (or -- most recently reprogrammed) this robot, if there is one. robotParentID :: Lens' Robot (Maybe RID) -- | Is this robot extra heavy (thus requiring tank treads to move)? robotHeavy :: Lens' Robot Bool -- | The robot's current CEK machine state. machine :: Lens' Robot CESK -- | Is this robot a "system robot"? System robots are generated by the -- system (as opposed to created by the user) and are not subject to the -- usual capability restrictions. systemRobot :: Lens' Robot Bool -- | Does this robot wish to self destruct? selfDestruct :: Lens' Robot Bool -- | The need for tickSteps is a bit technical, and I hope I can -- eventually find a different, better way to accomplish it. Ideally, we -- would want each robot to execute a single command at every game -- tick, so that e.g. two robots executing move;move;move -- and repeat 3 move (given a suitable definition of -- repeat) will move in lockstep. However, the second robot -- actually has to do more computation than the first (it has to look up -- the definition of repeat, reduce its application to the -- number 3, etc.), so its CESK machine will take more steps. It won't do -- to simply let each robot run until executing a command---because robot -- programs can involve arbitrary recursion, it is very easy to write a -- program that evaluates forever without ever executing a command, which -- in this scenario would completely freeze the UI. (It also wouldn't -- help to ensure all programs are terminating---it would still be -- possible to effectively do the same thing by making a program that -- takes a very, very long time to terminate.) So instead, we allocate -- each robot a certain maximum number of computation steps per tick -- (defined in evalStepsPerTick), and it suspends computation when -- it either executes a command or reaches the maximum number of steps, -- whichever comes first. -- -- It seems like this really isn't something the robot should be keeping -- track of itself, but that seemed the most technically convenient way -- to do it at the time. The robot needs some way to signal when it has -- executed a command, which it currently does by setting tickSteps to -- zero. However, that has the disadvantage that when tickSteps becomes -- zero, we can't tell whether that happened because the robot ran out of -- steps, or because it executed a command and set it to zero manually. -- -- Perhaps instead, each robot should keep a counter saying how many -- commands it has executed. The loop stepping the robot can tell when -- the counter increments. tickSteps :: Lens' Robot Int -- | Is the robot currently running an atomic block? runningAtomic :: Lens' Robot Bool -- | A general function for creating robots. mkRobot :: RobotID phase -> Maybe Int -> Text -> Document Syntax -> RobotLocation phase -> Heading -> Display -> CESK -> [Entity] -> [(Count, Entity)] -> Bool -> Bool -> TimeSpec -> RobotR phase -- | Instantiate a robot template to make it into a concrete robot, by -- providing a robot ID. Concrete robots also require a location; if the -- robot template didn't have a location already, just set the location -- to (0,0) by default. If you want a different location, set it via -- trobotLocation before calling instantiateRobot. instantiateRobot :: RID -> TRobot -> Robot -- | Does a robot know of an entity's existence? robotKnows :: Robot -> Entity -> Bool -- | Is the robot actively in the middle of a computation? isActive :: Robot -> Bool -- | Active robots include robots that are waiting; -- wantsToStep is true if the robot actually wants to take another -- step right now (this is a subset of active robots). wantsToStep :: TickNumber -> Robot -> Bool -- | The time until which the robot is waiting, if any. waitingUntil :: Robot -> Maybe TickNumber -- | Get the result of the robot's computation if it is finished. getResult :: Robot -> Maybe (Value, Store) hearingDistance :: Num i => i instance Servant.Docs.Internal.ToSample Swarm.Game.Robot.Robot instance Swarm.Util.Yaml.FromJSONE Swarm.Game.Entity.EntityMap Swarm.Game.Robot.TRobot instance GHC.Generics.Generic (Swarm.Game.Robot.RobotR phase) instance (GHC.Show.Show (Swarm.Game.Robot.RobotLocation phase), GHC.Show.Show (Swarm.Game.Robot.RobotID phase)) => GHC.Show.Show (Swarm.Game.Robot.RobotR phase) instance (GHC.Classes.Eq (Swarm.Game.Robot.RobotLocation phase), GHC.Classes.Eq (Swarm.Game.Robot.RobotID phase)) => GHC.Classes.Eq (Swarm.Game.Robot.RobotR phase) instance (Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Robot.RobotLocation phase), Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Robot.RobotID phase)) => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.Robot.RobotR phase) instance Control.Lens.At.Ixed Swarm.Game.Robot.RobotContext instance Control.Lens.At.At Swarm.Game.Robot.RobotContext instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Robot.RobotContext instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Robot.RobotContext instance GHC.Generics.Generic Swarm.Game.Robot.RobotContext instance GHC.Show.Show Swarm.Game.Robot.RobotContext instance GHC.Classes.Eq Swarm.Game.Robot.RobotContext -- | Abstract syntax for the Swarm world description DSL. module Swarm.Game.World.Syntax type World b = Coords -> b type RawCellVal = [(Maybe CellTag, Text)] data CellTag CellTerrain :: CellTag CellEntity :: CellTag CellRobot :: CellTag data CellVal CellVal :: TerrainType -> Erasable (Last Entity) -> [Robot] -> CellVal data Rot Rot0 :: Rot Rot90 :: Rot Rot180 :: Rot Rot270 :: Rot type Var = Text data Axis X :: Axis Y :: Axis data Op Not :: Op Neg :: Op And :: Op Or :: Op Add :: Op Sub :: Op Mul :: Op Div :: Op Mod :: Op Eq :: Op Neq :: Op Lt :: Op Leq :: Op Gt :: Op Geq :: Op If :: Op Perlin :: Op Reflect :: Axis -> Op Rot :: Rot -> Op Mask :: Op Overlay :: Op Abs :: Op data WExp [WInt] :: Integer -> WExp [WFloat] :: Double -> WExp [WBool] :: Bool -> WExp [WCell] :: RawCellVal -> WExp [WVar] :: Text -> WExp [WOp] :: Op -> [WExp] -> WExp [WSeed] :: WExp [WCoord] :: Axis -> WExp [WHash] :: WExp [WLet] :: [(Var, WExp)] -> WExp -> WExp [WOverlay] :: NonEmpty WExp -> WExp [WImport] :: Text -> WExp instance GHC.Enum.Bounded Swarm.Game.World.Syntax.CellTag instance GHC.Enum.Enum Swarm.Game.World.Syntax.CellTag instance GHC.Show.Show Swarm.Game.World.Syntax.CellTag instance GHC.Classes.Ord Swarm.Game.World.Syntax.CellTag instance GHC.Classes.Eq Swarm.Game.World.Syntax.CellTag instance GHC.Show.Show Swarm.Game.World.Syntax.CellVal instance GHC.Classes.Eq Swarm.Game.World.Syntax.CellVal instance GHC.Enum.Enum Swarm.Game.World.Syntax.Rot instance GHC.Enum.Bounded Swarm.Game.World.Syntax.Rot instance GHC.Show.Show Swarm.Game.World.Syntax.Rot instance GHC.Classes.Ord Swarm.Game.World.Syntax.Rot instance GHC.Classes.Eq Swarm.Game.World.Syntax.Rot instance GHC.Enum.Enum Swarm.Game.World.Syntax.Axis instance GHC.Enum.Bounded Swarm.Game.World.Syntax.Axis instance GHC.Show.Show Swarm.Game.World.Syntax.Axis instance GHC.Classes.Ord Swarm.Game.World.Syntax.Axis instance GHC.Classes.Eq Swarm.Game.World.Syntax.Axis instance GHC.Show.Show Swarm.Game.World.Syntax.Op instance GHC.Classes.Ord Swarm.Game.World.Syntax.Op instance GHC.Classes.Eq Swarm.Game.World.Syntax.Op instance GHC.Show.Show Swarm.Game.World.Syntax.WExp instance GHC.Classes.Eq Swarm.Game.World.Syntax.WExp instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.World.Syntax.Axis instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.World.Syntax.Rot instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.World.Syntax.CellVal instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.World.Syntax.CellTag -- | Typechecking and elaboration for the Swarm world DSL. For more -- information, see: -- -- -- https://byorgey.wordpress.com/2023/07/13/compiling-to-intrinsically-typed-combinators/ module Swarm.Game.World.Typecheck class Empty e empty :: Empty e => e class Over m () :: Over m => m -> m -> m class Applicable t ($$) :: Applicable t => t (a -> b) -> t a -> t b infixl 1 $$ type family IsFun a type NotFun a = IsFun a ~ 'False -- | Type-indexed constants. These include both language built-ins -- (if, arithmetic, comparison, <>, etc.) as well -- as combinators (S, I, C, K, -- B, Φ) we will use both for elaboration and later as -- a compilation target. data Const :: Type -> Type [CLit] :: (Show a, NotFun a) => a -> Const a [CCell] :: CellVal -> Const CellVal [CFI] :: Const (Integer -> Double) [CIf] :: Const (Bool -> a -> a -> a) [CNot] :: Const (Bool -> Bool) [CNeg] :: (Num a, NotFun a) => Const (a -> a) [CAbs] :: (Num a, NotFun a) => Const (a -> a) [CAnd] :: Const (Bool -> Bool -> Bool) [COr] :: Const (Bool -> Bool -> Bool) [CAdd] :: (Num a, NotFun a) => Const (a -> a -> a) [CSub] :: (Num a, NotFun a) => Const (a -> a -> a) [CMul] :: (Num a, NotFun a) => Const (a -> a -> a) [CDiv] :: (Fractional a, NotFun a) => Const (a -> a -> a) [CIDiv] :: (Integral a, NotFun a) => Const (a -> a -> a) [CMod] :: (Integral a, NotFun a) => Const (a -> a -> a) [CEq] :: (Eq a, NotFun a) => Const (a -> a -> Bool) [CNeq] :: (Eq a, NotFun a) => Const (a -> a -> Bool) [CLt] :: (Ord a, NotFun a) => Const (a -> a -> Bool) [CLeq] :: (Ord a, NotFun a) => Const (a -> a -> Bool) [CGt] :: (Ord a, NotFun a) => Const (a -> a -> Bool) [CGeq] :: (Ord a, NotFun a) => Const (a -> a -> Bool) [CMask] :: (Empty a, NotFun a) => Const (World Bool -> World a -> World a) [CSeed] :: Const Integer [CCoord] :: Axis -> Const (World Integer) [CHash] :: Const (World Integer) [CPerlin] :: Const (Integer -> Integer -> Double -> Double -> World Double) [CReflect] :: Axis -> Const (World a -> World a) [CRot] :: Rot -> Const (World a -> World a) [COver] :: (Over a, NotFun a) => Const (a -> a -> a) [K] :: Const (a -> b -> a) [S] :: Const ((a -> b -> c) -> (a -> b) -> a -> c) [I] :: Const (a -> a) [B] :: Const ((b -> c) -> (a -> b) -> a -> c) [C] :: Const ((a -> b -> c) -> b -> a -> c) [Φ] :: Const ((a -> b -> c) -> (d -> a) -> (d -> b) -> d -> c) class HasConst t embed :: HasConst t => Const a -> t a (.$$) :: (HasConst t, Applicable t) => Const (a -> b) -> t a -> t b infixl 1 .$$ ($$.) :: (HasConst t, Applicable t) => t (a -> b) -> Const a -> t b infixl 1 $$. (.$$.) :: (HasConst t, Applicable t) => Const (a -> b) -> Const a -> t b infixl 1 .$$. -- | Type-level list append. type family Append (xs :: [k]) (ys :: [k]) :: [k] -- | Type- and context-indexed de Bruijn indices. (v :: Idx g a) means v -- represents a variable with type a in a type context g. data Idx :: [Type] -> Type -> Type [VZ] :: Idx (ty : g) ty [VS] :: Idx g ty -> Idx (x : g) ty idxToNat :: Idx g a -> Int -- | A variable valid in one context is also valid in another extended -- context with additional variables. weakenVar :: forall h g a. Idx g a -> Idx (Append g h) a -- | Type-indexed terms. Note this is a stripped-down core language, with -- only variables, lambdas, application, and constants. data TTerm :: [Type] -> Type -> Type [TVar] :: Idx g a -> TTerm g a [TLam] :: TTerm (ty1 : g) ty2 -> TTerm g (ty1 -> ty2) [TApp] :: TTerm g (a -> b) -> TTerm g a -> TTerm g b [TConst] :: Const a -> TTerm g a -- | A term valid in one context is also valid in another extended context -- with additional variables (which the term does not use). weaken :: forall h g a. TTerm g a -> TTerm (Append g h) a -- | Errors that can occur during typechecking/elaboration. data CheckErr [ApplyErr] :: Some (TTerm g) -> Some (TTerm g) -> CheckErr [NoInstance] :: Text -> TTy a -> CheckErr [Unbound] :: Text -> CheckErr [BadType] :: Some (TTerm g) -> TTy b -> CheckErr [BadDivType] :: TTy a -> CheckErr [UnknownImport] :: Text -> CheckErr [NotAThing] :: Text -> CellTag -> CheckErr [NotAnything] :: Text -> CheckErr -- | Base types. data Base :: Type -> Type [BInt] :: Base Integer [BFloat] :: Base Double [BBool] :: Base Bool [BCell] :: Base CellVal -- | Type representations indexed by the corresponding host language type. data TTy :: Type -> Type [TTyBase] :: Base t -> TTy t [:->:] :: TTy a -> TTy b -> TTy (a -> b) [TTyWorld] :: TTy t -> TTy (World t) infixr 0 :->: pattern TTyBool :: TTy Bool pattern TTyInt :: TTy Integer pattern TTyFloat :: TTy Double pattern TTyCell :: TTy CellVal -- | Check that a particular type has an Op instance, and run a -- computation in a context provided with an Op constraint. The -- other checkX functions are similar. checkEq :: Has (Throw CheckErr) sig m => TTy ty -> ((Eq ty, NotFun ty) => m a) -> m a checkOrd :: Has (Throw CheckErr) sig m => TTy ty -> ((Ord ty, NotFun ty) => m a) -> m a checkNum :: Has (Throw CheckErr) sig m => TTy ty -> ((Num ty, NotFun ty) => m a) -> m a checkIntegral :: Has (Throw CheckErr) sig m => TTy ty -> ((Integral ty, NotFun ty) => m a) -> m a checkEmpty :: Has (Throw CheckErr) sig m => TTy ty -> ((Empty ty, NotFun ty) => m a) -> m a checkOver :: Has (Throw CheckErr) sig m => TTy ty -> ((Over ty, NotFun ty) => m a) -> m a -- | Wrap up a type-indexed thing to hide the type index, but package it -- with a TTy which we can pattern-match on to recover the type -- later. data Some :: (Type -> Type) -> Type [Some] :: TTy α -> t α -> Some t mapSome :: (forall α. s α -> t α) -> Some s -> Some t type SomeTy = Some (Const ()) pattern SomeTy :: TTy α -> SomeTy type WorldMap = Map Text (Some (TTerm '[])) -- | Type contexts, indexed by a type-level list of types of all the -- variables in the context. data Ctx :: [Type] -> Type [CNil] :: Ctx '[] [CCons] :: Text -> TTy ty -> Ctx g -> Ctx (ty : g) -- | Look up a variable name in the context, returning a type-indexed de -- Bruijn index. lookup :: Has (Throw CheckErr) sig m => Text -> Ctx g -> m (Some (Idx g)) -- | Check that a term has a given type, and if so, return a corresponding -- elaborated and type-indexed term. Note that this also deals with -- subtyping: for example, if we check that the term 3 has type -- World Int, we will get back a suitably lifted value -- (i.e. const 3). check :: (Has (Throw CheckErr) sig m, Has (Reader EntityMap) sig m, Has (Reader WorldMap) sig m) => Ctx g -> TTy t -> WExp -> m (TTerm g t) -- | Get the underlying base type of a term which either has a base type or -- a World type. getBaseType :: Some (TTerm g) -> SomeTy -- | Apply one term to another term, automatically handling promotion and -- lifting, via the fact that World is Applicative. That is, (1) if a -- term of type T is used where a term of type World T is expected, it -- will automatically be promoted (by an application of const); (2) if a -- function of type (T1 -> T2 -> ... -> Tn) is applied to any -- arguments of type (World Ti), the function will be lifted to (World T1 -- -> World T2 -> ... -> World Tn). apply :: Has (Throw CheckErr) sig m => Some (TTerm g) -> Some (TTerm g) -> m (Some (TTerm g)) applyTo :: Has (Throw CheckErr) sig m => Some (TTerm g) -> Some (TTerm g) -> m (Some (TTerm g)) -- | Infer the type of an operator: turn a raw operator into a type-indexed -- constant. However, some operators are polymorphic, so we also provide -- a list of type arguments. For example, the type of the negation -- operator can be either (Int -> Int) or (Float -> Float) so we -- provide it as an argument. -- -- Currently, all operators take at most one type argument, so (Maybe -- SomeTy) might seem more appropriate than [SomeTy], but that is just a -- coincidence; in general one can easily imagine operators that are -- polymorphic in more than one type variable, and we may wish to add -- such in the future. inferOp :: Has (Throw CheckErr) sig m => [SomeTy] -> Op -> m (Some (TTerm g)) -- | Given a raw operator and the terms the operator is applied to, select -- which types should be supplied as the type arguments to the operator. -- For example, for an operator like + we can just select the -- type of its first argument; for an operator like if, we must -- select the type of its second argument, since if : Bool -> a -- -> a -> a. In all cases we must also select the underlying -- base type in case the argument has a World type. For example -- if + is applied to an argument of type World Int we -- still want to give + the type Int -> Int -> -- Int. It can be lifted to have type World Int -> World Int -- -> World Int but that will be taken care of by application, -- which will insert the right combinators to do the lifting. typeArgsFor :: Op -> [Some (TTerm g)] -> [SomeTy] -- | Typecheck the application of an operator to some terms, returning a -- typed, elaborated version of the application. applyOp :: (Has (Throw CheckErr) sig m, Has (Reader EntityMap) sig m, Has (Reader WorldMap) sig m) => Ctx g -> Op -> [WExp] -> m (Some (TTerm g)) -- | Infer the type of a term, and elaborate along the way. infer :: forall sig m g. (Has (Throw CheckErr) sig m, Has (Reader EntityMap) sig m, Has (Reader WorldMap) sig m) => Ctx g -> WExp -> m (Some (TTerm g)) -- | Try to resolve a RawCellVal---containing only Text names -- for terrain, entities, and robots---into a real CellVal with -- references to actual terrain, entities, and robots. resolveCell :: (Has (Throw CheckErr) sig m, Has (Reader EntityMap) sig m) => RawCellVal -> m CellVal -- | Try to resolve one cell item name into an actual item (terrain, -- entity, robot, etc.). resolveCellItem :: forall sig m. (Has (Throw CheckErr) sig m, Has (Reader EntityMap) sig m) => (Maybe CellTag, Text) -> m CellVal -- | Infer the type of a let expression, and elaborate into a series of -- lambda applications. inferLet :: (Has (Throw CheckErr) sig m, Has (Reader EntityMap) sig m, Has (Reader WorldMap) sig m) => Ctx g -> [(Var, WExp)] -> WExp -> m (Some (TTerm g)) -- | Infer the type of an overlay expression, and elaborate into a -- chain of <> (over) operations. inferOverlay :: (Has (Throw CheckErr) sig m, Has (Reader EntityMap) sig m, Has (Reader WorldMap) sig m) => Ctx g -> NonEmpty WExp -> m (Some (TTerm g)) instance GHC.Show.Show (Swarm.Game.World.Typecheck.Const ty) instance GHC.Show.Show (Swarm.Game.World.Typecheck.Idx g ty) instance GHC.Show.Show (Swarm.Game.World.Typecheck.TTerm g ty) instance GHC.Show.Show Swarm.Game.World.Typecheck.CheckErr instance GHC.Show.Show (Swarm.Game.World.Typecheck.Base ty) instance GHC.Show.Show (Swarm.Game.World.Typecheck.TTy ty) instance (forall α. GHC.Show.Show (t α)) => GHC.Show.Show (Swarm.Game.World.Typecheck.Some t) instance Swarm.Language.Pretty.PrettyPrec Swarm.Game.World.Typecheck.CheckErr instance Data.Type.Equality.TestEquality Swarm.Game.World.Typecheck.TTy instance Swarm.Language.Pretty.PrettyPrec (Swarm.Game.World.Typecheck.TTy ty) instance Data.Type.Equality.TestEquality Swarm.Game.World.Typecheck.Base instance Swarm.Language.Pretty.PrettyPrec (Swarm.Game.World.Typecheck.Base α) instance Swarm.Game.World.Typecheck.Applicable (Swarm.Game.World.Typecheck.TTerm g) instance Swarm.Game.World.Typecheck.HasConst (Swarm.Game.World.Typecheck.TTerm g) instance Swarm.Language.Pretty.PrettyPrec (Swarm.Game.World.Typecheck.TTerm g α) instance Swarm.Language.Pretty.PrettyPrec (Swarm.Game.World.Typecheck.Const α) instance Swarm.Game.World.Typecheck.Over GHC.Types.Bool instance Swarm.Game.World.Typecheck.Over GHC.Num.Integer.Integer instance Swarm.Game.World.Typecheck.Over GHC.Types.Double instance Swarm.Game.World.Typecheck.Over Swarm.Game.World.Syntax.CellVal instance Swarm.Game.World.Typecheck.Empty Swarm.Game.World.Syntax.CellVal -- | Explicitly type-preserving bracket abstraction, a la Oleg Kiselyov. -- Turn elaborated, type-indexed terms into variableless, type-indexed -- terms with only constants and application. -- -- For more information, see: -- -- -- https://byorgey.wordpress.com/2023/07/13/compiling-to-intrinsically-typed-combinators/ module Swarm.Game.World.Abstract -- | Closed, fully abstracted terms. All computation is represented by -- combinators. This is the ultimate target for the bracket abstraction -- operation. data BTerm :: Type -> Type [BApp] :: BTerm (a -> b) -> BTerm a -> BTerm b [BConst] :: Const a -> BTerm a -- | These explicitly open terms are an intermediate stage in the bracket -- abstraction algorithm, i.e. they represent terms which have -- been only partially abstracted. data OTerm :: [Type] -> Type -> Type [E] :: BTerm a -> OTerm g a [V] :: OTerm (a : g) a [N] :: OTerm g (a -> b) -> OTerm (a : g) b [W] :: OTerm g b -> OTerm (a : g) b -- | Bracket abstraction: convert the TTerm to an OTerm, then -- project out the embedded BTerm. GHC can see this is total since -- E is the only constructor that can produce an OTerm with -- an empty environment. bracket :: TTerm '[] a -> BTerm a -- | Type-preserving conversion from TTerm to OTerm -- (conv + the Applicable instance). Taken directly from -- Kiselyov. conv :: TTerm g a -> OTerm g a instance GHC.Show.Show (Swarm.Game.World.Abstract.BTerm t) instance Swarm.Game.World.Typecheck.HasConst (Swarm.Game.World.Abstract.OTerm g) instance Swarm.Game.World.Typecheck.Applicable (Swarm.Game.World.Abstract.OTerm g) instance Swarm.Game.World.Typecheck.Applicable Swarm.Game.World.Abstract.BTerm instance Swarm.Game.World.Typecheck.HasConst Swarm.Game.World.Abstract.BTerm -- | Parser for the Swarm world description DSL. module Swarm.Game.World.Parse type Parser = Parsec Void Text type ParserError = ParseErrorBundle Text Void sepByNE :: MonadPlus m => m a -> m sep -> m (NonEmpty a) reservedWords :: [Text] -- | Skip spaces and comments. sc :: Parser () -- | In general, we follow the convention that every token parser assumes -- no leading whitespace and consumes all trailing whitespace. -- Concretely, we achieve this by wrapping every token parser using -- lexeme. lexeme :: Parser a -> Parser a -- | A lexeme consisting of a literal string. symbol :: Text -> Parser Text operatorChar :: Parser Char operator :: Text -> Parser Text -- | A positive integer literal token. integerOrFloat :: Parser (Either Integer Double) -- | Parse a case-insensitive reserved word, making sure it is not a prefix -- of a longer variable name, and allowing the parser to backtrack if it -- fails. reserved :: Text -> Parser () -- | Parse an identifier, i.e. any non-reserved string containing -- alphanumeric characters and underscores and not starting with a -- number. identifier :: Parser Var brackets :: Parser a -> Parser a parens :: Parser a -> Parser a braces :: Parser a -> Parser a comma :: Parser () parseWExpAtom :: Parser WExp parseWExp :: Parser WExp parseCell :: Parser WExp parseCellItem :: Parser (Maybe CellTag, Text) parseCellTag :: Parser CellTag parseName :: Parser Text parseIf :: Parser WExp parsePerlin :: Parser WExp parseAbs :: Parser WExp parseLet :: Parser WExp parseOverlay :: Parser WExp parseMask :: Parser WExp parseImport :: Parser WExp runParser :: Parser a -> Text -> Either ParserError a instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.World.Syntax.WExp -- | Loading world descriptions from `worlds/*.world`. module Swarm.Game.World.Load -- | Load and typecheck all world descriptions from `worlds/*.world`. Emit -- a warning for each one which fails to parse or typecheck. loadWorlds :: (Has (Accum (Seq SystemFailure)) sig m, Has (Lift IO) sig m) => EntityMap -> m WorldMap -- | Load a file containing a world DSL term, throwing an exception if it -- fails to parse or typecheck. loadWorld :: Has (Throw SystemFailure) sig m => FilePath -> EntityMap -> (FilePath, String) -> m (Text, Some (TTerm '[])) -- | Strip a leading directory from a FilePath. stripDir :: FilePath -> FilePath -> FilePath -- | Utilities for working with procedurally generated worlds. module Swarm.Game.World.Gen type Seed = Int -- | Extract a list of all entities mentioned in a given world DSL term. extractEntities :: TTerm g a -> Set Entity -- | Offset a world by a multiple of the skip in such a way that -- it satisfies the given predicate. findOffset :: Integer -> ((Coords -> (t, Erasable (Last e))) -> Bool) -> WorldFun t e -> WorldFun t e -- | Offset the world so the base starts in a 32x32 patch containing at -- least one of each of a list of required entities. findPatchWith :: [Text] -> WorldFun t Entity -> WorldFun t Entity -- | Offset the world so the base starts on empty spot next to tree and -- grass. findTreeOffset :: WorldFun t Entity -> WorldFun t Entity -- | Offset the world so the base starts in a good patch (near necessary -- items), next to a tree. findGoodOrigin :: WorldFun t Entity -> WorldFun t Entity -- | Interpreter for the Swarm world description DSL. module Swarm.Game.World.Interpret -- | Interpret an abstracted term into the host language. interpBTerm :: Seed -> BTerm a -> a -- | Interpret a constant into the host language. interpConst :: Seed -> Const a -> a -- | Interprect a reflection. interpReflect :: Axis -> Coords -> Coords -- | Interpret a rotation. interpRot :: Rot -> Coords -> Coords -- | Evaluation for the Swarm world description DSL. module Swarm.Game.World.Eval -- | Run a typechecked world description DSL term to produce a -- WorldFun. runWorld :: TTerm '[] (World CellVal) -> Seed -> WorldFun TerrainType Entity -- | Compiling abstracted combinator expressions (BTerm) to native -- Haskell terms. This can supposedly be more efficient than directly -- interpreting BTerms, but some benchmarking is probably needed -- to decide whether we want this or not. -- -- For more info, see: -- -- -- https://byorgey.wordpress.com/2023/07/13/compiling-to-intrinsically-typed-combinators/ module Swarm.Game.World.Compile data CTerm a [CFun] :: (CTerm a -> CTerm b) -> CTerm (a -> b) [CConst] :: NotFun a => a -> CTerm a compile :: Seed -> BTerm a -> CTerm a compileConst :: Seed -> Const a -> CTerm a unary :: (NotFun a, NotFun b) => (a -> b) -> CTerm (a -> b) binary :: (NotFun a, NotFun b, NotFun c) => (a -> b -> c) -> CTerm (a -> b -> c) compileMask :: (NotFun a, Empty a) => CTerm (World Bool -> World a -> World a) compileHash :: CTerm (Coords -> Integer) compilePerlin :: CTerm (Integer -> Integer -> Double -> Double -> World Double) compileReflect :: Axis -> CTerm (World a -> World a) compileRot :: Rot -> CTerm (World a -> World a) type family NoFunParams a :: Constraint -- | Interpret a compiled term into the host language. runCTerm :: NoFunParams a => CTerm a -> a instance Swarm.Game.World.Typecheck.Applicable Swarm.Game.World.Compile.CTerm -- | Conversions from native Haskell values to values in the swarm -- language. -- -- SPDX-License-Identifier: BSD-3-Clause module Swarm.Game.Value type VRect = Value pattern VRect :: Integer -> Integer -> Integer -> Integer -> VRect -- | Conversion from native Haskell types to their swarm-lang equivalents, -- useful for implementing swarm commands in Haskell. class Valuable a asValue :: Valuable a => a -> Value instance Swarm.Game.Value.Valuable GHC.Int.Int32 instance Swarm.Game.Value.Valuable GHC.Types.Int instance Swarm.Game.Value.Valuable a => Swarm.Game.Value.Valuable (Linear.V2.V2 a) instance (Swarm.Game.Value.Valuable a, Swarm.Game.Value.Valuable b) => Swarm.Game.Value.Valuable (a, b) instance Swarm.Game.Value.Valuable Swarm.Game.Location.Location instance Swarm.Game.Value.Valuable Swarm.Game.Entity.Entity instance Swarm.Game.Value.Valuable Swarm.Game.Robot.Robot instance Swarm.Game.Value.Valuable a => Swarm.Game.Value.Valuable (GHC.Maybe.Maybe a) instance (Swarm.Game.Value.Valuable a, Swarm.Game.Value.Valuable b) => Swarm.Game.Value.Valuable (Data.Either.Either a b) module Swarm.Game.Scenario.RobotLookup newtype RobotName RobotName :: Text -> RobotName -- | A robot template paired with its definition's index within the -- Scenario file type IndexedTRobot = (Int, TRobot) -- | A map from names to robots, used to look up robots in scenario -- descriptions. type RobotMap = Map RobotName IndexedTRobot -- | Create a RobotMap from a list of robot templates. buildRobotMap :: [TRobot] -> RobotMap -- | Look up a thing by name, throwing a parse error if it is not found. getThing :: Show k => Text -> (k -> m -> Maybe a) -> k -> ParserE m a -- | Look up an entity by name in an EntityMap, throwing a parse -- error if it is not found. getEntity :: Text -> ParserE EntityMap Entity -- | Look up a robot by name in a RobotMap, throwing a parse error -- if it is not found. getRobot :: RobotName -> ParserE RobotMap IndexedTRobot instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.RobotLookup.RobotName instance GHC.Generics.Generic Swarm.Game.Scenario.RobotLookup.RobotName instance GHC.Classes.Ord Swarm.Game.Scenario.RobotLookup.RobotName instance GHC.Classes.Eq Swarm.Game.Scenario.RobotLookup.RobotName instance GHC.Show.Show Swarm.Game.Scenario.RobotLookup.RobotName module Swarm.Game.Scenario.Topography.Cell -- | A single cell in a world map, which contains a terrain value, and -- optionally an entity and robot. It is parameterized on the Entity type -- to facilitate less stateful versions of the Entity type in rendering -- scenario data. data PCell e Cell :: TerrainType -> Erasable e -> [IndexedTRobot] -> PCell e [cellTerrain] :: PCell e -> TerrainType [cellEntity] :: PCell e -> Erasable e [cellRobots] :: PCell e -> [IndexedTRobot] -- | A single cell in a world map, which contains a terrain value, and -- optionally an entity and robot. type Cell = PCell Entity -- | Supplements a cell with waypoint information data AugmentedCell e AugmentedCell :: Maybe WaypointConfig -> PCell e -> AugmentedCell e [waypointCfg] :: AugmentedCell e -> Maybe WaypointConfig [standardCell] :: AugmentedCell e -> PCell e -- | Stateless cells used for the World Editor. These cells contain the -- bare minimum display information for rendering. type CellPaintDisplay = PCell EntityFacade instance GHC.Show.Show e => GHC.Show.Show (Swarm.Game.Scenario.Topography.Cell.PCell e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.Cell.PCell e) instance GHC.Show.Show e => GHC.Show.Show (Swarm.Game.Scenario.Topography.Cell.AugmentedCell e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.Cell.AugmentedCell e) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Topography.Cell.CellPaintDisplay instance Swarm.Util.Yaml.FromJSONE (Swarm.Game.Entity.EntityMap, Swarm.Game.Scenario.RobotLookup.RobotMap) (Swarm.Game.Scenario.Topography.Cell.AugmentedCell Swarm.Game.Entity.Entity) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Topography.Cell.Cell instance Swarm.Util.Yaml.FromJSONE (Swarm.Game.Entity.EntityMap, Swarm.Game.Scenario.RobotLookup.RobotMap) Swarm.Game.Scenario.Topography.Cell.Cell module Swarm.Game.Scenario.Topography.WorldPalette -- | A world palette maps characters to PCell values. newtype WorldPalette e WorldPalette :: KeyMap (AugmentedCell e) -> WorldPalette e [unPalette] :: WorldPalette e -> KeyMap (AugmentedCell e) type TerrainWith a = (TerrainType, Erasable a) cellToTerrainPair :: CellPaintDisplay -> TerrainWith EntityFacade toCellPaintDisplay :: Cell -> CellPaintDisplay toKey :: TerrainWith EntityFacade -> TerrainWith EntityName -- | We want to identify all of the unique (terrain, entity facade) pairs. -- However, EntityFacade includes a Display record, which -- contains more fields than desirable for use as a unique key. -- Therefore, we extract just the entity name for use in a (terrain, -- entity name) key, and couple it with the original (terrain, entity -- facade) pair in a Map. getUniqueTerrainFacadePairs :: [[CellPaintDisplay]] -> Map (TerrainWith EntityName) (TerrainWith EntityFacade) constructPalette :: [(Char, TerrainWith EntityFacade)] -> KeyMap CellPaintDisplay constructWorldMap :: [(Char, TerrainWith EntityFacade)] -> [[CellPaintDisplay]] -> Text -- | All alphanumeric characters. These are used as supplemental map -- placeholders in case a pre-existing display character is not available -- to re-use. genericCharacterPool :: Set Char -- | Note that display characters are not unique across different entities! -- However, the palette KeyMap as a conveyance serves to dedupe them. prepForJson :: WorldPalette EntityFacade -> [[CellPaintDisplay]] -> (Text, KeyMap CellPaintDisplay) instance GHC.Show.Show e => GHC.Show.Show (Swarm.Game.Scenario.Topography.WorldPalette.WorldPalette e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.WorldPalette.WorldPalette e) instance Swarm.Util.Yaml.FromJSONE (Swarm.Game.Entity.EntityMap, Swarm.Game.Scenario.RobotLookup.RobotMap) (Swarm.Game.Scenario.Topography.WorldPalette.WorldPalette Swarm.Game.Entity.Entity) module Swarm.TUI.Editor.Model data BoundsSelectionStep UpperLeftPending :: BoundsSelectionStep -- | Stores the *world coords* of the upper-left click LowerRightPending :: Cosmic Coords -> BoundsSelectionStep SelectionComplete :: BoundsSelectionStep data EntityPaint Facade :: EntityFacade -> EntityPaint Ref :: Entity -> EntityPaint getDisplay :: EntityPaint -> Display toFacade :: EntityPaint -> EntityFacade getEntityName :: EntityFacade -> EntityName data MapEditingBounds MapEditingBounds :: Maybe (Cosmic BoundsRectangle) -> TimeSpec -> BoundsSelectionStep -> MapEditingBounds -- | Upper-left and lower-right coordinates of the map to be saved. [_boundsRect] :: MapEditingBounds -> Maybe (Cosmic BoundsRectangle) [_boundsPersistDisplayUntil] :: MapEditingBounds -> TimeSpec [_boundsSelectionStep] :: MapEditingBounds -> BoundsSelectionStep boundsSelectionStep :: Lens' MapEditingBounds BoundsSelectionStep boundsRect :: Lens' MapEditingBounds (Maybe (Cosmic BoundsRectangle)) boundsPersistDisplayUntil :: Lens' MapEditingBounds TimeSpec data WorldEditor n WorldEditor :: Bool -> List n TerrainType -> List n EntityFacade -> Map Coords (TerrainWith EntityFacade) -> MapEditingBounds -> FocusRing n -> FilePath -> Maybe String -> WorldEditor n [_isWorldEditorEnabled] :: WorldEditor n -> Bool [_terrainList] :: WorldEditor n -> List n TerrainType -- | This field has deferred initialization; it gets populated when a game -- is initialized. [_entityPaintList] :: WorldEditor n -> List n EntityFacade [_paintedTerrain] :: WorldEditor n -> Map Coords (TerrainWith EntityFacade) [_editingBounds] :: WorldEditor n -> MapEditingBounds [_editorFocusRing] :: WorldEditor n -> FocusRing n [_outputFilePath] :: WorldEditor n -> FilePath [_lastWorldEditorMessage] :: WorldEditor n -> Maybe String terrainList :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) (List n_a7o6s TerrainType) paintedTerrain :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) (Map Coords (TerrainWith EntityFacade)) outputFilePath :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) FilePath lastWorldEditorMessage :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) (Maybe String) isWorldEditorEnabled :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) Bool entityPaintList :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) (List n_a7o6s EntityFacade) editorFocusRing :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) (FocusRing n_a7o6s) editingBounds :: forall n_a7o6s. Lens' (WorldEditor n_a7o6s) MapEditingBounds initialWorldEditor :: TimeSpec -> WorldEditor Name instance GHC.Classes.Eq Swarm.TUI.Editor.Model.EntityPaint module Swarm.Game.Scenario.Topography.Structure data NamedStructure c NamedStructure :: StructureName -> PStructure c -> NamedStructure c [name] :: NamedStructure c -> StructureName [structure] :: NamedStructure c -> PStructure c type InheritedStructureDefs = [NamedStructure (Maybe (PCell Entity))] data PStructure c Structure :: [[c]] -> [NamedStructure c] -> [Placement] -> [Waypoint] -> PStructure c [area] :: PStructure c -> [[c]] -- | structure definitions from parents shall be accessible by children [structures] :: PStructure c -> [NamedStructure c] -- | earlier placements will be overlaid on top of later placements in the -- YAML file [placements] :: PStructure c -> [Placement] [waypoints] :: PStructure c -> [Waypoint] data MergedStructure c MergedStructure :: [[c]] -> [Originated Waypoint] -> MergedStructure c -- | Destructively overlays one direct child structure upon the input -- structure. However, the child structure is assembled recursively. overlaySingleStructure :: Map StructureName (PStructure (Maybe a)) -> (Placement, PStructure (Maybe a)) -> MergedStructure (Maybe a) -> MergedStructure (Maybe a) -- | Overlays all of the "child placements", such that the children -- encountered earlier in the YAML file supersede the later ones (due to -- use of "foldr" instead of "foldl"). mergeStructures :: Map StructureName (PStructure (Maybe a)) -> Maybe Placement -> PStructure (Maybe a) -> MergedStructure (Maybe a) -- | Paint a world map using a WorldPalette, turning it from -- a raw string into a nested list of PCell values by looking up -- each character in the palette, failing if any character in the raw map -- is not contained in the palette. paintMap :: MonadFail m => Maybe Char -> WorldPalette e -> Text -> m ([[Maybe (PCell e)]], [Waypoint]) readMap :: Applicative f => (Char -> f b) -> Text -> f [[b]] instance GHC.Show.Show c => GHC.Show.Show (Swarm.Game.Scenario.Topography.Structure.NamedStructure c) instance GHC.Classes.Eq c => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.Structure.NamedStructure c) instance GHC.Show.Show c => GHC.Show.Show (Swarm.Game.Scenario.Topography.Structure.PStructure c) instance GHC.Classes.Eq c => GHC.Classes.Eq (Swarm.Game.Scenario.Topography.Structure.PStructure c) instance Swarm.Util.Yaml.FromJSONE (Swarm.Game.Entity.EntityMap, Swarm.Game.Scenario.RobotLookup.RobotMap) (Swarm.Game.Scenario.Topography.Structure.NamedStructure (GHC.Maybe.Maybe (Swarm.Game.Scenario.Topography.Cell.PCell Swarm.Game.Entity.Entity))) instance Swarm.Util.Yaml.FromJSONE (Swarm.Game.Entity.EntityMap, Swarm.Game.Scenario.RobotLookup.RobotMap) (Swarm.Game.Scenario.Topography.Structure.PStructure (GHC.Maybe.Maybe (Swarm.Game.Scenario.Topography.Cell.PCell Swarm.Game.Entity.Entity))) module Swarm.Game.Scenario.Topography.WorldDescription -- | A description of a world parsed from a YAML file. This type is -- parameterized to accommodate Cells that utilize a less stateful Entity -- type. data PWorldDescription e WorldDescription :: Bool -> Bool -> WorldPalette e -> Location -> [[PCell e]] -> Navigation Identity WaypointName -> SubworldName -> Maybe (TTerm '[] (World CellVal)) -> PWorldDescription e [offsetOrigin] :: PWorldDescription e -> Bool [scrollable] :: PWorldDescription e -> Bool [palette] :: PWorldDescription e -> WorldPalette e [ul] :: PWorldDescription e -> Location [area] :: PWorldDescription e -> [[PCell e]] [navigation] :: PWorldDescription e -> Navigation Identity WaypointName [worldName] :: PWorldDescription e -> SubworldName [worldProg] :: PWorldDescription e -> Maybe (TTerm '[] (World CellVal)) type WorldDescription = PWorldDescription Entity -- | A pared-down (stateless) version of WorldDescription just for -- the purpose of rendering a Scenario file type WorldDescriptionPaint = PWorldDescription EntityFacade instance GHC.Show.Show e => GHC.Show.Show (Swarm.Game.Scenario.Topography.WorldDescription.PWorldDescription e) instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Topography.WorldDescription.WorldDescriptionPaint instance Swarm.Util.Yaml.FromJSONE (Swarm.Game.World.Typecheck.WorldMap, Swarm.Game.Scenario.Topography.Structure.InheritedStructureDefs, Swarm.Game.Entity.EntityMap, Swarm.Game.Scenario.RobotLookup.RobotMap) Swarm.Game.Scenario.Topography.WorldDescription.WorldDescription module Swarm.TUI.Editor.Json data SkeletonScenario SkeletonScenario :: Int -> Text -> Text -> Bool -> [Entity] -> WorldDescriptionPaint -> [String] -> SkeletonScenario [version] :: SkeletonScenario -> Int [name] :: SkeletonScenario -> Text [description] :: SkeletonScenario -> Text [creative] :: SkeletonScenario -> Bool [entities] :: SkeletonScenario -> [Entity] [world] :: SkeletonScenario -> WorldDescriptionPaint [robots] :: SkeletonScenario -> [String] instance GHC.Generics.Generic Swarm.TUI.Editor.Json.SkeletonScenario instance Data.Aeson.Types.ToJSON.ToJSON Swarm.TUI.Editor.Json.SkeletonScenario -- | Scenarios are standalone worlds with specific starting and winning -- conditions, which can be used both for building interactive tutorials -- and for standalone puzzles and scenarios. module Swarm.Game.Scenario -- | A single cell in a world map, which contains a terrain value, and -- optionally an entity and robot. It is parameterized on the Entity type -- to facilitate less stateful versions of the Entity type in rendering -- scenario data. data PCell e Cell :: TerrainType -> Erasable e -> [IndexedTRobot] -> PCell e [cellTerrain] :: PCell e -> TerrainType [cellEntity] :: PCell e -> Erasable e [cellRobots] :: PCell e -> [IndexedTRobot] -- | A single cell in a world map, which contains a terrain value, and -- optionally an entity and robot. type Cell = PCell Entity -- | A description of a world parsed from a YAML file. This type is -- parameterized to accommodate Cells that utilize a less stateful Entity -- type. data PWorldDescription e WorldDescription :: Bool -> Bool -> WorldPalette e -> Location -> [[PCell e]] -> Navigation Identity WaypointName -> SubworldName -> Maybe (TTerm '[] (World CellVal)) -> PWorldDescription e [offsetOrigin] :: PWorldDescription e -> Bool [scrollable] :: PWorldDescription e -> Bool [palette] :: PWorldDescription e -> WorldPalette e [ul] :: PWorldDescription e -> Location [area] :: PWorldDescription e -> [[PCell e]] [navigation] :: PWorldDescription e -> Navigation Identity WaypointName [worldName] :: PWorldDescription e -> SubworldName [worldProg] :: PWorldDescription e -> Maybe (TTerm '[] (World CellVal)) type WorldDescription = PWorldDescription Entity -- | A robot template paired with its definition's index within the -- Scenario file type IndexedTRobot = (Int, TRobot) -- | A Scenario contains all the information to describe a scenario. data Scenario Scenario :: Int -> Text -> Maybe Text -> Text -> Bool -> Maybe Int -> [CustomAttr] -> EntityMap -> [Recipe Entity] -> [Text] -> NonEmpty WorldDescription -> Navigation (Map SubworldName) Location -> [TRobot] -> [Objective] -> Maybe ProcessedTerm -> Maybe Int -> Scenario [_scenarioVersion] :: Scenario -> Int [_scenarioName] :: Scenario -> Text [_scenarioAuthor] :: Scenario -> Maybe Text [_scenarioDescription] :: Scenario -> Text [_scenarioCreative] :: Scenario -> Bool [_scenarioSeed] :: Scenario -> Maybe Int [_scenarioAttrs] :: Scenario -> [CustomAttr] [_scenarioEntities] :: Scenario -> EntityMap [_scenarioRecipes] :: Scenario -> [Recipe Entity] [_scenarioKnown] :: Scenario -> [Text] [_scenarioWorlds] :: Scenario -> NonEmpty WorldDescription [_scenarioNavigation] :: Scenario -> Navigation (Map SubworldName) Location [_scenarioRobots] :: Scenario -> [TRobot] [_scenarioObjectives] :: Scenario -> [Objective] [_scenarioSolution] :: Scenario -> Maybe ProcessedTerm [_scenarioStepsPerTick] :: Scenario -> Maybe Int -- | The version number of the scenario schema. Currently, this should -- always be 1, but it is ignored. In the future, this may be used to -- convert older formats to newer ones, or simply to print a nice error -- message when we can't read an older format. scenarioVersion :: Lens' Scenario Int -- | The name of the scenario. scenarioName :: Lens' Scenario Text -- | The author of the scenario. scenarioAuthor :: Lens' Scenario (Maybe Text) -- | A high-level description of the scenario, shown e.g. in the -- menu. scenarioDescription :: Lens' Scenario Text -- | Whether the scenario should start in creative mode. scenarioCreative :: Lens' Scenario Bool -- | The seed used for the random number generator. If Nothing, -- use a random seed / prompt the user for the seed. scenarioSeed :: Lens' Scenario (Maybe Int) -- | Custom attributes defined in the scenario. scenarioAttrs :: Lens' Scenario [CustomAttr] -- | Any custom entities used for this scenario. scenarioEntities :: Lens' Scenario EntityMap -- | Any custom recipes used in this scenario. scenarioRecipes :: Lens' Scenario [Recipe Entity] -- | List of entities that should be considered "known", so robots do not -- have to scan them. scenarioKnown :: Lens' Scenario [Text] -- | The subworlds of the scenario. The "root" subworld shall always be at -- the head of the list, by construction. scenarioWorlds :: Lens' Scenario (NonEmpty WorldDescription) -- | Waypoints and inter-world portals scenarioNavigation :: Lens' Scenario (Navigation (Map SubworldName) Location) -- | The starting robots for the scenario. Note this should include the -- base. scenarioRobots :: Lens' Scenario [TRobot] -- | A sequence of objectives for the scenario (if any). scenarioObjectives :: Lens' Scenario [Objective] -- | An optional solution of the scenario, expressed as a program of type -- cmd a. This is useful for automated testing of the win -- condition. scenarioSolution :: Lens' Scenario (Maybe ProcessedTerm) -- | Optionally, specify the maximum number of steps each robot may take -- during a single tick. scenarioStepsPerTick :: Lens' Scenario (Maybe Int) -- | Load a scenario with a given name from disk, given an entity map to -- use. This function is used if a specific scenario is requested on the -- command line. loadScenario :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => FilePath -> EntityMap -> WorldMap -> m (Scenario, FilePath) -- | Load a scenario from a file. loadScenarioFile :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => EntityMap -> WorldMap -> FilePath -> m Scenario getScenarioPath :: Has (Lift IO) sig m => FilePath -> m (Maybe FilePath) instance Swarm.Util.Yaml.FromJSONE (Swarm.Game.Entity.EntityMap, Swarm.Game.World.Typecheck.WorldMap) Swarm.Game.Scenario.Scenario instance GHC.Show.Show Swarm.Game.Scenario.Scenario module Swarm.TUI.Editor.Palette makeSuggestedPalette :: Maybe Scenario -> [[CellPaintDisplay]] -> KeyMap (AugmentedCell EntityFacade) -- | Generate a "skeleton" scenario with placeholders for certain required -- fields constructScenario :: Maybe Scenario -> [[CellPaintDisplay]] -> SkeletonScenario -- | High-level status of scenario play. Representation of progress, logic -- for updating. module Swarm.Game.Scenario.Status -- | These launch parameters are used in a number of ways: * Serializing -- the seed/script path for saves * Holding parse status from form -- fields, including Error info * Carrying fully-validated launch -- parameters. -- -- Type parameters are utilized to support all of these use cases. data ParameterizableLaunchParams code f LaunchParams :: f (Maybe Seed) -> f (Maybe code) -> ParameterizableLaunchParams code f [seedVal] :: ParameterizableLaunchParams code f -> f (Maybe Seed) [initialCode] :: ParameterizableLaunchParams code f -> f (Maybe code) type SerializableLaunchParams = ParameterizableLaunchParams FilePath Identity -- | A ScenarioStatus stores the status of a scenario along with -- appropriate metadata: NotStarted, or Played. The -- Played status has two sub-states: Attempted or -- Completed. data ScenarioStatus NotStarted :: ScenarioStatus Played :: SerializableLaunchParams -> ProgressMetric -> BestRecords -> ScenarioStatus getLaunchParams :: ScenarioStatus -> SerializableLaunchParams -- | A ScenarioInfo record stores metadata about a scenario: its -- canonical path and status. By way of the ScenarioStatus record, -- it stores the most recent status and best-ever status. data ScenarioInfo ScenarioInfo :: FilePath -> ScenarioStatus -> ScenarioInfo [_scenarioPath] :: ScenarioInfo -> FilePath [_scenarioStatus] :: ScenarioInfo -> ScenarioStatus type ScenarioInfoPair = (Scenario, ScenarioInfo) -- | The path of the scenario, relative to data/scenarios. scenarioPath :: Lens' ScenarioInfo FilePath -- | The status of the scenario. scenarioStatus :: Lens' ScenarioInfo ScenarioStatus -- | Update the current ScenarioInfo record when quitting a game. -- -- Note that when comparing "best" times, shorter is not always better! -- As long as the scenario is not completed (e.g. some do not have win -- condition) we consider having fun _longer_ to be better. updateScenarioInfoOnFinish :: CodeSizeDeterminators -> ZonedTime -> TickNumber -> Bool -> ScenarioInfo -> ScenarioInfo instance GHC.Generics.Generic Swarm.Game.Scenario.Status.ScenarioStatus instance GHC.Read.Read Swarm.Game.Scenario.Status.ScenarioStatus instance GHC.Show.Show Swarm.Game.Scenario.Status.ScenarioStatus instance GHC.Classes.Ord Swarm.Game.Scenario.Status.ScenarioStatus instance GHC.Classes.Eq Swarm.Game.Scenario.Status.ScenarioStatus instance GHC.Generics.Generic Swarm.Game.Scenario.Status.ScenarioInfo instance GHC.Read.Read Swarm.Game.Scenario.Status.ScenarioInfo instance GHC.Show.Show Swarm.Game.Scenario.Status.ScenarioInfo instance GHC.Classes.Ord Swarm.Game.Scenario.Status.ScenarioInfo instance GHC.Classes.Eq Swarm.Game.Scenario.Status.ScenarioInfo instance GHC.Classes.Eq Swarm.Game.Scenario.Status.SerializableLaunchParams instance GHC.Classes.Ord Swarm.Game.Scenario.Status.SerializableLaunchParams instance GHC.Show.Show Swarm.Game.Scenario.Status.SerializableLaunchParams instance GHC.Read.Read Swarm.Game.Scenario.Status.SerializableLaunchParams instance GHC.Generics.Generic Swarm.Game.Scenario.Status.SerializableLaunchParams instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Status.SerializableLaunchParams instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Status.SerializableLaunchParams instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Status.ScenarioInfo instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Status.ScenarioInfo instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.Scenario.Status.ScenarioStatus instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.Scenario.Status.ScenarioStatus -- | Saving and loading info about scenarios (status, path, etc.) as well -- as loading recursive scenario collections. module Swarm.Game.ScenarioInfo -- | A ScenarioStatus stores the status of a scenario along with -- appropriate metadata: NotStarted, or Played. The -- Played status has two sub-states: Attempted or -- Completed. data ScenarioStatus NotStarted :: ScenarioStatus Played :: SerializableLaunchParams -> ProgressMetric -> BestRecords -> ScenarioStatus _NotStarted :: Prism' ScenarioStatus () -- | A ScenarioInfo record stores metadata about a scenario: its -- canonical path and status. By way of the ScenarioStatus record, -- it stores the most recent status and best-ever status. data ScenarioInfo ScenarioInfo :: FilePath -> ScenarioStatus -> ScenarioInfo [_scenarioPath] :: ScenarioInfo -> FilePath [_scenarioStatus] :: ScenarioInfo -> ScenarioStatus -- | The path of the scenario, relative to data/scenarios. scenarioPath :: Lens' ScenarioInfo FilePath -- | The status of the scenario. scenarioStatus :: Lens' ScenarioInfo ScenarioStatus data CodeSizeDeterminators CodeSizeDeterminators :: Maybe ProcessedTerm -> Bool -> CodeSizeDeterminators -- | Update the current ScenarioInfo record when quitting a game. -- -- Note that when comparing "best" times, shorter is not always better! -- As long as the scenario is not completed (e.g. some do not have win -- condition) we consider having fun _longer_ to be better. updateScenarioInfoOnFinish :: CodeSizeDeterminators -> ZonedTime -> TickNumber -> Bool -> ScenarioInfo -> ScenarioInfo type ScenarioInfoPair = (Scenario, ScenarioInfo) -- | A scenario collection is a tree of scenarios, keyed by name, together -- with an optional order. Invariant: every item in the scOrder exists as -- a key in the scMap. data ScenarioCollection SC :: Maybe [FilePath] -> Map FilePath ScenarioItem -> ScenarioCollection [scOrder] :: ScenarioCollection -> Maybe [FilePath] [scMap] :: ScenarioCollection -> Map FilePath ScenarioItem -- | Convert a scenario collection to a list of scenario items. scenarioCollectionToList :: ScenarioCollection -> [ScenarioItem] flatten :: ScenarioItem -> [ScenarioInfoPair] -- | Access and modify ScenarioItems in collection based on their path. scenarioItemByPath :: FilePath -> Traversal' ScenarioCollection ScenarioItem -- | Canonicalize a scenario path, making it usable as a unique key. normalizeScenarioPath :: MonadIO m => ScenarioCollection -> FilePath -> m FilePath -- | A scenario item is either a specific scenario, or a collection of -- scenarios (*e.g.* the scenarios contained in a subdirectory). data ScenarioItem SISingle :: ScenarioInfoPair -> ScenarioItem SICollection :: Text -> ScenarioCollection -> ScenarioItem -- | Retrieve the name of a scenario item. scenarioItemName :: ScenarioItem -> Text _SISingle :: Prism' ScenarioItem ScenarioInfoPair -- | Load all the scenarios from the scenarios data directory. loadScenarios :: (Has (Accum (Seq SystemFailure)) sig m, Has (Lift IO) sig m) => EntityMap -> WorldMap -> m ScenarioCollection -- | Load saved info about played scenario from XDG data directory. loadScenarioInfo :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => FilePath -> m ScenarioInfo -- | Save info about played scenario to XDG data directory. saveScenarioInfo :: FilePath -> ScenarioInfo -> IO () instance GHC.Show.Show Swarm.Game.ScenarioInfo.ScenarioItem instance GHC.Show.Show Swarm.Game.ScenarioInfo.ScenarioCollection -- | Definition of the record holding all the game-related state, and -- various related utility functions. module Swarm.Game.State -- | The ViewCenterRule specifies how to determine the center of the -- world viewport. data ViewCenterRule -- | The view should be centered on an absolute position. VCLocation :: Cosmic Location -> ViewCenterRule -- | The view should be centered on a certain robot. VCRobot :: RID -> ViewCenterRule -- | A data type to represent the current status of the REPL. data REPLStatus -- | The REPL is not doing anything actively at the moment. We persist the -- last value and its type though. INVARIANT: the Value stored here is -- not a VResult. REPLDone :: Maybe (Typed Value) -> REPLStatus -- | A command entered at the REPL is currently being run. The -- Polytype represents the type of the expression that was -- entered. The Maybe Value starts out as Nothing and -- gets filled in with a result once the command completes. REPLWorking :: Typed (Maybe Value) -> REPLStatus data WinStatus -- | There are one or more objectives remaining that the player has not yet -- accomplished. Ongoing :: WinStatus -- | The player has won. The boolean indicates whether they have already -- been congratulated. Won :: Bool -> WinStatus -- | The player has completed certain "goals" that preclude (via negative -- prerequisites) the completion of all of the required goals. The -- boolean indicates whether they have already been informed. Unwinnable :: Bool -> WinStatus data WinCondition -- | There is no winning condition. NoWinCondition :: WinCondition -- | NOTE: It is possible to continue to achieve "optional" objectives even -- after the game has been won (or deemed unwinnable). WinConditions :: WinStatus -> ObjectiveCompletion -> WinCondition data ObjectiveCompletion ObjectiveCompletion :: CompletionBuckets -> Set ObjectiveLabel -> ObjectiveCompletion -- | This is the authoritative "completion status" for all objectives. Note -- that there is a separate Set to store the completion status of -- prerequisite objectives, which must be carefully kept in sync with -- this. Those prerequisite objectives are required to have labels, but -- other objectives are not. Therefore only prerequisites exist in the -- completion map keyed by label. [completionBuckets] :: ObjectiveCompletion -> CompletionBuckets [completedIDs] :: ObjectiveCompletion -> Set ObjectiveLabel _NoWinCondition :: Prism' WinCondition () _WinConditions :: Prism' WinCondition (WinStatus, ObjectiveCompletion) -- | TODO: #1044 Could also add an ObjectiveFailed constructor... newtype Announcement ObjectiveCompleted :: Objective -> Announcement -- | A data type to keep track of the pause mode. data RunStatus -- | The game is running. Running :: RunStatus -- | The user paused the game, and it should stay pause after visiting the -- help. ManualPause :: RunStatus -- | The game got paused while visiting the help, and it should unpause -- after returning back to the game. AutoPause :: RunStatus type Seed = Int -- | Game step mode - we use the single step mode when debugging robot -- CESK machine. data Step WorldTick :: Step RobotStep :: SingleStep -> Step -- | Type for remebering which robots will be run next in a robot step -- mode. -- -- Once some robots have run, we need to store RID to know which ones -- should go next. At SBefore no robots were run yet, so it is -- safe to transition to and from WorldTick. -- --
--                       tick
--       ┌────────────────────────────────────┐
--       │                                    │
--       │               step                 │
--       │              ┌────┐                │
--       ▼              ▼    │                │
--   ┌───────┐ step  ┌───────┴───┐ step  ┌────┴─────┐
--   │SBefore├──────►│SSingle RID├──────►│SAfter RID│
--   └──┬────┘       └───────────┘       └────┬─────┘
--      │ ▲ player        ▲                   │
--      ▼ │ switch        └───────────────────┘
--   ┌────┴────┐             view RID > oldRID
--   │WorldTick│
--   └─────────┘
--   
data SingleStep -- | Run the robots from the beginning until the focused robot -- (noninclusive). SBefore :: SingleStep -- | Run a single step of the focused robot. SSingle :: RID -> SingleStep -- | Run robots after the (previously) focused robot and finish the tick. SAfter :: RID -> SingleStep -- | The main record holding the state for the game itself (as distinct -- from the UI). See the lenses below for access to its fields. data GameState -- | Is the user in creative mode (i.e. able to do anything without -- restriction)? creativeMode :: Lens' GameState Bool -- | How to step the game - WorldTick or RobotStep for -- debugging the CESK machine. gameStep :: Lens' GameState Step -- | How to determine whether the player has won. winCondition :: Lens' GameState WinCondition -- | How to win (if possible). This is useful for automated testing and to -- show help to cheaters (or testers). winSolution :: Lens' GameState (Maybe ProcessedTerm) -- | Map of in-game achievements that were attained gameAchievements :: Lens' GameState (Map GameplayAchievement Attainment) -- | A queue of global announcements. Note that this is distinct from the -- "messageQueue", which is for messages emitted by robots. -- -- Note that we put the newest entry to the right. announcementQueue :: Lens' GameState (Seq Announcement) -- | The current RunStatus. runStatus :: Lens' GameState RunStatus -- | Whether the game is currently paused. paused :: Getter GameState Bool -- | All the robots that currently exist in the game, indexed by ID. robotMap :: Lens' GameState (IntMap Robot) -- | The names of all robots that currently exist in the game, indexed by -- location (which we need both for e.g. the Salvage -- command as well as for actually drawing the world). Unfortunately -- there is no good way to automatically keep this up to date, since we -- don't just want to completely rebuild it every time the -- robotMap changes. Instead, we just make sure to update it every -- time the location of a robot changes, or a robot is created or -- destroyed. Fortunately, there are relatively few ways for these things -- to happen. robotsByLocation :: Lens' GameState (Map SubworldName (Map Location IntSet)) -- | Get a list of all the robots at a particular location. robotsAtLocation :: Cosmic Location -> GameState -> [Robot] -- | Get a list of all the robots that are "watching" by location. robotsWatching :: Lens' GameState (Map (Cosmic Location) (Set RID)) -- | Get all the robots within a given Manhattan distance from a location. robotsInArea :: Cosmic Location -> Int32 -> GameState -> [Robot] -- | The base robot, if it exists. baseRobot :: Traversal' GameState Robot -- | The names of the robots that are currently not sleeping. activeRobots :: Getter GameState IntSet -- | The names of the robots that are currently sleeping, indexed by wake -- up time. Note that this may not include all sleeping robots, -- particularly those that are only taking a short nap (e.g. wait 1). waitingRobots :: Getter GameState (Map TickNumber [RID]) -- | The list of available recipes. availableRecipes :: Lens' GameState (Notifications (Recipe Entity)) -- | The list of available commands. availableCommands :: Lens' GameState (Notifications Const) -- | Get the notification list of messages from the point of view of -- focused robot. messageNotifications :: Getter GameState (Notifications LogEntry) -- | The list of entities that have been discovered. allDiscoveredEntities :: Lens' GameState Inventory -- | A counter used to generate globally unique IDs. gensym :: Lens' GameState Int -- | The initial seed that was used for the random number generator, and -- world generation. seed :: Lens' GameState Seed -- | Pseudorandom generator initialized at start. randGen :: Lens' GameState StdGen -- | Read-only list of words, for use in building random robot names. adjList :: Getter GameState (Array Int Text) -- | Read-only list of words, for use in building random robot names. nameList :: Getter GameState (Array Int Text) -- | Code that is run upon scenario start, before any REPL interaction. initiallyRunCode :: Lens' GameState (Maybe ProcessedTerm) -- | The catalog of all entities that the game knows about. entityMap :: Lens' GameState EntityMap -- | All recipes the game knows about, indexed by outputs. recipesOut :: Lens' GameState (IntMap [Recipe Entity]) -- | All recipes the game knows about, indexed by inputs. recipesIn :: Lens' GameState (IntMap [Recipe Entity]) -- | All recipes the game knows about, indexed by requirement/catalyst. recipesReq :: Lens' GameState (IntMap [Recipe Entity]) -- | The filepath of the currently running scenario. -- -- This is useful as an index to scenarios collection, see -- scenarioItemByPath. currentScenarioPath :: Lens' GameState (Maybe FilePath) -- | The names of entities that should be considered "known", that is, -- robots know what they are without having to scan them. knownEntities :: Lens' GameState [Text] -- | Includes a Map of named locations and an "Edge list" (graph) -- that maps portal entrances to exits worldNavigation :: Lens' GameState (Navigation (Map SubworldName) Location) -- | The current state of the world (terrain and entities only; robots are -- stored in the robotMap). Int is used instead of -- TerrainType because we need to be able to store terrain values -- in unboxed tile arrays. multiWorld :: Lens' GameState (MultiWorld Int Entity) -- | Whether the world map is supposed to be scrollable or not. worldScrollable :: Lens' GameState Bool -- | The current rule for determining the center of the world view. It -- updates also, viewCenter and focusedRobotName to keep everything -- synchronize. viewCenterRule :: Lens' GameState ViewCenterRule -- | The current center of the world view. Note that this cannot be -- modified directly, since it is calculated automatically from the -- viewCenterRule. To modify the view center, either set the -- viewCenterRule, or use modifyViewCenter. viewCenter :: Getter GameState (Cosmic Location) -- | Whether the world view needs to be redrawn. needsRedraw :: Lens' GameState Bool -- | The current status of the REPL. replStatus :: Lens' GameState REPLStatus -- | The index of the next it{index} value replNextValueIndex :: Lens' GameState Integer -- | Whether the repl is currently working. replWorking :: Getter GameState Bool -- | Either the type of the command being executed, or of the last command replActiveType :: Getter REPLStatus (Maybe Polytype) -- | The currently installed input handler and hint text. inputHandler :: Lens' GameState (Maybe (Text, Value)) -- | A queue of global messages. -- -- Note that we put the newest entry to the right. messageQueue :: Lens' GameState (Seq LogEntry) -- | Last time message queue has been viewed (used for notification). lastSeenMessageTime :: Lens' GameState TickNumber -- | The current robot in focus. -- -- It is only a Getter because this value should be updated only -- when the viewCenterRule is specified to be a robot. -- -- Technically it's the last robot ID specified by viewCenterRule, -- but that robot may not be alive anymore - to be safe use -- focusedRobot. focusedRobotID :: Getter GameState RID -- | The number of ticks elapsed since the game started. ticks :: Lens' GameState TickNumber -- | The maximum number of CESK machine steps a robot may take during a -- single tick. robotStepsPerTick :: Lens' GameState Int -- | A data type to keep track of discovered recipes and commands data Notifications a Notifications :: Int -> [a] -> Notifications a [_notificationsCount] :: Notifications a -> Int [_notificationsContent] :: Notifications a -> [a] notificationsCount :: forall a_a7Nb2. Lens' (Notifications a_a7Nb2) Int notificationsContent :: forall a_a7Nb2 a_a7NDC. Lens (Notifications a_a7Nb2) (Notifications a_a7NDC) [a_a7Nb2] [a_a7NDC] type LaunchParams a = ParameterizableLaunchParams CodeToRun a -- | In this stage in the UI pipeline, both fields have already been -- validated, and Nothing means that the field is simply absent. type ValidatedLaunchParams = LaunchParams Identity -- | Record to pass information needed to create an initial -- GameState record when starting a scenario. data GameStateConfig GameStateConfig :: Array Int Text -> Array Int Text -> EntityMap -> [Recipe Entity] -> WorldMap -> GameStateConfig [initAdjList] :: GameStateConfig -> Array Int Text [initNameList] :: GameStateConfig -> Array Int Text [initEntities] :: GameStateConfig -> EntityMap [initRecipes] :: GameStateConfig -> [Recipe Entity] [initWorldMap] :: GameStateConfig -> WorldMap -- | Create an initial, fresh game state record when starting a new -- scenario. initGameState :: GameStateConfig -> GameState -- | Create an initial game state corresponding to the given scenario. scenarioToGameState :: Scenario -> ValidatedLaunchParams -> GameStateConfig -> IO GameState data CodeToRun CodeToRun :: SolutionSource -> ProcessedTerm -> CodeToRun newtype Sha1 Sha1 :: String -> Sha1 data SolutionSource ScenarioSuggested :: SolutionSource -- | Includes the SHA1 of the program text for the purpose of corroborating -- solutions on a leaderboard. PlayerAuthored :: FilePath -> Sha1 -> SolutionSource parseCodeFile :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => FilePath -> m CodeToRun -- | Given a current mapping from robot names to robots, apply a -- ViewCenterRule to derive the location it refers to. The result -- is Maybe because the rule may refer to a robot which does not -- exist. applyViewCenterRule :: ViewCenterRule -> IntMap Robot -> Maybe (Cosmic Location) -- | Recalculate the veiw center (and cache the result in the -- viewCenter field) based on the current viewCenterRule. -- If the viewCenterRule specifies a robot which does not exist, -- simply leave the current viewCenter as it is. Set -- needsRedraw if the view center changes. recalcViewCenter :: GameState -> GameState -- | Modify the viewCenter by applying an arbitrary function to the -- current value. Note that this also modifies the viewCenterRule -- to match. After calling this function the viewCenterRule will -- specify a particular location, not a robot. modifyViewCenter :: (Cosmic Location -> Cosmic Location) -> GameState -> GameState -- | Given a width and height, compute the region, centered on the -- viewCenter, that should currently be in view. viewingRegion :: GameState -> (Int32, Int32) -> Cosmic BoundsRectangle -- | Unfocus by modifying the view center rule to look at the -- current location instead of a specific robot, and also set the focused -- robot ID to an invalid value. In classic mode this causes the map view -- to become nothing but static. unfocus :: GameState -> GameState -- | Find out which robot has been last specified by the -- viewCenterRule, if any. focusedRobot :: GameState -> Maybe Robot -- | Type for describing how far away a robot is from the base, which -- determines what kind of communication can take place. data RobotRange -- | Close; communication is perfect. Close :: RobotRange -- | Mid-range; communication is possible but lossy. MidRange :: Double -> RobotRange -- | Far; communication is not possible. Far :: RobotRange -- | Check how far away the focused robot is from the base. -- Nothing is returned if there is no focused robot; otherwise, -- return a RobotRange value as follows. -- -- focusedRange :: GameState -> Maybe RobotRange -- | Clear the robotLogUpdated flag of the focused robot. clearFocusedRobotLogUpdated :: Has (State GameState) sig m => m () -- | Add a robot to the game state, adding it to the main robot map, the -- active robot set, and to to the index of robots by location. addRobot :: Has (State GameState) sig m => Robot -> m () -- | Helper function for updating the "robotsByLocation" bookkeeping addRobotToLocation :: Has (State GameState) sig m => RID -> Cosmic Location -> m () -- | Add a concrete instance of a robot template to the game state: first, -- generate a unique ID number for it. Then, add it to the main robot -- map, the active robot set, and to to the index of robots by location. -- Return the updated robot. addTRobot :: Has (State GameState) sig m => TRobot -> m Robot -- | Add a message to the message queue. emitMessage :: Has (State GameState) sig m => LogEntry -> m () -- | Iterates through all of the currently "wait"-ing robots, and moves -- forward the wake time of the ones that are watching this location. -- -- NOTE: Clearing TickNumber map entries from -- "internalWaitingRobots" upon wakeup is handled by -- "wakeUpRobotsDoneSleeping" in State.hs wakeWatchingRobots :: Has (State GameState) sig m => Cosmic Location -> m () -- | Takes a robot out of the activeRobots set and puts it in the -- waitingRobots queue. sleepUntil :: Has (State GameState) sig m => RID -> TickNumber -> m () -- | Takes a robot out of the activeRobots set. sleepForever :: Has (State GameState) sig m => RID -> m () -- | Removes robots whose wake up time matches the current game ticks count -- from the waitingRobots queue and put them back in the activeRobots set -- if they still exist in the keys of robotMap. wakeUpRobotsDoneSleeping :: Has (State GameState) sig m => m () deleteRobot :: Has (State GameState) sig m => RID -> m () -- | Makes sure empty sets don't hang around in the robotsByLocation -- map. We don't want a key with an empty set at every location any robot -- has ever visited! removeRobotFromLocationMap :: Has (State GameState) sig m => Cosmic Location -> RID -> m () -- | Adds a robot to the activeRobots set. activateRobot :: Has (State GameState) sig m => RID -> m () -- | Switch (auto or manually) paused game to running and running to -- manually paused. -- -- Note that this function is not safe to use in the app directly, -- because the UI also tracks time between ticks - use -- safeTogglePause instead. toggleRunStatus :: RunStatus -> RunStatus messageIsRecent :: GameState -> LogEntry -> Bool -- | Reconciles the possibilities of log messages being omnipresent and -- robots being in different worlds messageIsFromNearby :: Cosmic Location -> LogEntry -> Bool getRunCodePath :: CodeToRun -> Maybe FilePath instance GHC.Classes.Ord Swarm.Game.State.RobotRange instance GHC.Classes.Eq Swarm.Game.State.RobotRange instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.State.RunStatus instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.State.RunStatus instance GHC.Generics.Generic Swarm.Game.State.RunStatus instance GHC.Show.Show Swarm.Game.State.RunStatus instance GHC.Classes.Eq Swarm.Game.State.RunStatus instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Swarm.Game.State.Notifications a) instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Swarm.Game.State.Notifications a) instance GHC.Generics.Generic (Swarm.Game.State.Notifications a) instance GHC.Show.Show a => GHC.Show.Show (Swarm.Game.State.Notifications a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Swarm.Game.State.Notifications a) instance GHC.Base.Semigroup (Swarm.Game.State.Notifications a) instance GHC.Base.Monoid (Swarm.Game.State.Notifications a) instance Servant.Docs.Internal.ToSample Swarm.Game.State.WinCondition instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.State.REPLStatus instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.State.REPLStatus instance GHC.Generics.Generic Swarm.Game.State.REPLStatus instance GHC.Show.Show Swarm.Game.State.REPLStatus instance GHC.Classes.Eq Swarm.Game.State.REPLStatus instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.State.WinStatus instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.State.WinStatus instance GHC.Generics.Generic Swarm.Game.State.WinStatus instance GHC.Show.Show Swarm.Game.State.WinStatus instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.State.WinCondition instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.State.WinCondition instance GHC.Generics.Generic Swarm.Game.State.WinCondition instance GHC.Show.Show Swarm.Game.State.WinCondition instance Data.Aeson.Types.ToJSON.ToJSON Swarm.Game.State.ViewCenterRule instance Data.Aeson.Types.FromJSON.FromJSON Swarm.Game.State.ViewCenterRule instance GHC.Generics.Generic Swarm.Game.State.ViewCenterRule instance GHC.Show.Show Swarm.Game.State.ViewCenterRule instance GHC.Classes.Ord Swarm.Game.State.ViewCenterRule instance GHC.Classes.Eq Swarm.Game.State.ViewCenterRule module Swarm.TUI.Model.Menu data ScenarioOutcome WinModal :: ScenarioOutcome LoseModal :: ScenarioOutcome data ModalType HelpModal :: ModalType RecipesModal :: ModalType CommandsModal :: ModalType MessagesModal :: ModalType EntityPaletteModal :: ModalType TerrainPaletteModal :: ModalType RobotsModal :: ModalType ScenarioEndModal :: ScenarioOutcome -> ModalType QuitModal :: ModalType KeepPlayingModal :: ModalType DescriptionModal :: Entity -> ModalType GoalModal :: ModalType data ButtonAction Cancel :: ButtonAction KeepPlaying :: ButtonAction StartOver :: Seed -> ScenarioInfoPair -> ButtonAction QuitAction :: ButtonAction Next :: ScenarioInfoPair -> ButtonAction data Modal Modal :: ModalType -> Dialog ButtonAction Name -> Modal [_modalType] :: Modal -> ModalType [_modalDialog] :: Modal -> Dialog ButtonAction Name modalType :: Lens' Modal ModalType modalDialog :: Lens' Modal (Dialog ButtonAction Name) data MainMenuEntry NewGame :: MainMenuEntry Tutorial :: MainMenuEntry Achievements :: MainMenuEntry Messages :: MainMenuEntry About :: MainMenuEntry Quit :: MainMenuEntry data Menu -- | We started playing directly from command line, no menu to show NoMenu :: Menu MainMenu :: List Name MainMenuEntry -> Menu -- | Stack of scenario item lists. INVARIANT: the currently selected menu -- item is ALWAYS the same as the scenario currently being played. See -- https://github.com/swarm-game/swarm/issues/1064 and -- https://github.com/swarm-game/swarm/pull/1065. NewGameMenu :: NonEmpty (List Name ScenarioItem) -> Menu AchievementsMenu :: List Name CategorizedAchievement -> Menu MessagesMenu :: Menu AboutMenu :: Menu mainMenu :: MainMenuEntry -> List Name MainMenuEntry _AboutMenu :: Prism' Menu () _MessagesMenu :: Prism' Menu () _AchievementsMenu :: Prism' Menu (List Name CategorizedAchievement) _NewGameMenu :: Prism' Menu (NonEmpty (List Name ScenarioItem)) _MainMenu :: Prism' Menu (List Name MainMenuEntry) _NoMenu :: Prism' Menu () -- | Create a brick List of scenario items from a -- ScenarioCollection. mkScenarioList :: Bool -> ScenarioCollection -> List Name ScenarioItem -- | Given a ScenarioCollection and a FilePath which is the -- canonical path to some folder or scenario, construct a -- NewGameMenu stack focused on the given item, if possible. mkNewGameMenu :: Bool -> ScenarioCollection -> FilePath -> Maybe Menu -- | An entry in the inventory list displayed in the info panel. We can -- either have an entity with a count in the robot's inventory, an entity -- equipped on the robot, or a labelled separator. The purpose of the -- separators is to show a clear distinction between the robot's -- inventory and its equipped devices. data InventoryListEntry Separator :: Text -> InventoryListEntry InventoryEntry :: Count -> Entity -> InventoryListEntry EquippedEntry :: Entity -> InventoryListEntry _EquippedEntry :: Prism' InventoryListEntry Entity _InventoryEntry :: Prism' InventoryListEntry (Count, Entity) _Separator :: Prism' InventoryListEntry Text instance GHC.Classes.Eq Swarm.TUI.Model.Menu.InventoryListEntry instance GHC.Enum.Enum Swarm.TUI.Model.Menu.MainMenuEntry instance GHC.Enum.Bounded Swarm.TUI.Model.Menu.MainMenuEntry instance GHC.Read.Read Swarm.TUI.Model.Menu.MainMenuEntry instance GHC.Show.Show Swarm.TUI.Model.Menu.MainMenuEntry instance GHC.Classes.Ord Swarm.TUI.Model.Menu.MainMenuEntry instance GHC.Classes.Eq Swarm.TUI.Model.Menu.MainMenuEntry instance GHC.Show.Show Swarm.TUI.Model.Menu.ScenarioOutcome instance GHC.Show.Show Swarm.TUI.Model.Menu.ModalType -- | Types for representing state of the launch dialog, along with -- conversion functions for validated launch parameters. module Swarm.TUI.Launch.Model -- | Use this to store error messages on individual fields type EditingLaunchParams = LaunchParams (Either Text) toSerializableParams :: ValidatedLaunchParams -> SerializableLaunchParams fromSerializableParams :: SerializableLaunchParams -> IO EditingLaunchParams data FileBrowserControl FileBrowserControl :: FileBrowser Name -> Maybe FilePath -> Bool -> FileBrowserControl [_fbWidget] :: FileBrowserControl -> FileBrowser Name [_maybeSelectedFile] :: FileBrowserControl -> Maybe FilePath [_fbIsDisplayed] :: FileBrowserControl -> Bool maybeSelectedFile :: Lens' FileBrowserControl (Maybe FilePath) fbWidget :: Lens' FileBrowserControl (FileBrowser Name) fbIsDisplayed :: Lens' FileBrowserControl Bool -- | UI elements to configure scenario launch options data LaunchControls LaunchControls :: FileBrowserControl -> Editor Text Name -> FocusRing Name -> Maybe ScenarioInfoPair -> LaunchControls [_fileBrowser] :: LaunchControls -> FileBrowserControl [_seedValueEditor] :: LaunchControls -> Editor Text Name [_scenarioConfigFocusRing] :: LaunchControls -> FocusRing Name [_isDisplayedFor] :: LaunchControls -> Maybe ScenarioInfoPair seedValueEditor :: Lens' LaunchControls (Editor Text Name) scenarioConfigFocusRing :: Lens' LaunchControls (FocusRing Name) isDisplayedFor :: Lens' LaunchControls (Maybe ScenarioInfoPair) fileBrowser :: Lens' LaunchControls FileBrowserControl -- | UI elements to configure scenario launch options data LaunchOptions LaunchOptions :: LaunchControls -> EditingLaunchParams -> LaunchOptions [_controls] :: LaunchOptions -> LaunchControls [_editingParams] :: LaunchOptions -> EditingLaunchParams editingParams :: Lens' LaunchOptions EditingLaunchParams controls :: Lens' LaunchOptions LaunchControls -- | Prepares and validates scenario launch parameters module Swarm.TUI.Launch.Prep swarmLangFileExtension :: String toValidatedParams :: EditingLaunchParams -> Either Text ValidatedLaunchParams parseSeedInput :: Editor Text Name -> Either Text (Maybe Seed) parseWidgetParams :: LaunchControls -> IO EditingLaunchParams makeFocusRingWith :: [ScenarioConfigPanelFocusable] -> FocusRing Name initEditorWidget :: Text -> Editor Text Name -- | Called before any particular scenario is selected, so we supply some -- Nothings as defaults to the ValidatedLaunchParams. initConfigPanel :: IO LaunchOptions initFileBrowserWidget :: MonadIO m => Maybe FilePath -> m (FileBrowser Name) -- | If the selected scenario has been launched with an initial script -- before, set the file browser to initially open that script's -- directory. Then set the launch dialog to be displayed. -- -- Note that the FileBrowser widget normally allows multiple selections -- ("marked" files). However, there do not exist any public "setters" set -- the marked files, so we have some workarounds: * When the user marks -- the first file, we immediately close the FileBrowser widget. * We -- re-instantiate the FileBrowser from scratch every time it is opened, -- so that it is not possible to mark more than one file. * The "marked -- file" is persisted outside of the FileBrowser state, and the "initial -- directory" is set upon instantiation from that external state. prepareLaunchDialog :: ScenarioInfoPair -> EventM Name LaunchOptions () module Swarm.TUI.Model.UI -- | The main record holding the UI state. For access to the fields, see -- the lenses below. data UIState UIState :: Menu -> Bool -> Bool -> FocusRing Name -> LaunchOptions -> Maybe (Cosmic Coords) -> WorldEditor Name -> REPLState -> Maybe (Int, List Name InventoryListEntry) -> InventorySortOptions -> Maybe Text -> Bool -> Bool -> Bool -> Maybe Text -> Maybe Modal -> GoalDisplay -> Bool -> Map CategorizedAchievement Attainment -> Bool -> Bool -> Bool -> Bool -> TimeSpec -> Bool -> Double -> Double -> Int -> Int -> Int -> Int -> TimeSpec -> TimeSpec -> TimeSpec -> AttrMap -> Maybe ScenarioInfoPair -> UIState [_uiMenu] :: UIState -> Menu [_uiPlaying] :: UIState -> Bool [_uiCheatMode] :: UIState -> Bool [_uiFocusRing] :: UIState -> FocusRing Name [_uiLaunchConfig] :: UIState -> LaunchOptions [_uiWorldCursor] :: UIState -> Maybe (Cosmic Coords) [_uiWorldEditor] :: UIState -> WorldEditor Name [_uiREPL] :: UIState -> REPLState [_uiInventory] :: UIState -> Maybe (Int, List Name InventoryListEntry) [_uiInventorySort] :: UIState -> InventorySortOptions [_uiInventorySearch] :: UIState -> Maybe Text [_uiMoreInfoTop] :: UIState -> Bool [_uiMoreInfoBot] :: UIState -> Bool [_uiScrollToEnd] :: UIState -> Bool [_uiError] :: UIState -> Maybe Text [_uiModal] :: UIState -> Maybe Modal [_uiGoal] :: UIState -> GoalDisplay [_uiHideGoals] :: UIState -> Bool [_uiAchievements] :: UIState -> Map CategorizedAchievement Attainment [_uiShowFPS] :: UIState -> Bool [_uiShowREPL] :: UIState -> Bool [_uiShowZero] :: UIState -> Bool [_uiShowDebug] :: UIState -> Bool [_uiHideRobotsUntil] :: UIState -> TimeSpec [_uiInventoryShouldUpdate] :: UIState -> Bool [_uiTPF] :: UIState -> Double [_uiFPS] :: UIState -> Double [_lgTicksPerSecond] :: UIState -> Int [_tickCount] :: UIState -> Int [_frameCount] :: UIState -> Int [_frameTickCount] :: UIState -> Int [_lastFrameTime] :: UIState -> TimeSpec [_accumulatedTime] :: UIState -> TimeSpec [_lastInfoTime] :: UIState -> TimeSpec [_uiAttrMap] :: UIState -> AttrMap [_scenarioRef] :: UIState -> Maybe ScenarioInfoPair data GoalDisplay GoalDisplay :: GoalTracking -> List Name GoalEntry -> FocusRing Name -> GoalDisplay [_goalsContent] :: GoalDisplay -> GoalTracking -- | required for maintaining the selection/navigation state among list -- items [_listWidget] :: GoalDisplay -> List Name GoalEntry [_focus] :: GoalDisplay -> FocusRing Name -- | The current menu state. uiMenu :: Lens' UIState Menu -- | Are we currently playing the game? True = we are playing, and should -- thus display a world, REPL, etc.; False = we should display the -- current menu. uiPlaying :: Lens' UIState Bool -- | Cheat mode, i.e. are we allowed to turn creative mode on and off? uiCheatMode :: Lens' UIState Bool -- | The focus ring is the set of UI panels we can cycle among using the -- Tab key. uiFocusRing :: Lens' UIState (FocusRing Name) -- | Configuration modal when launching a scenario uiLaunchConfig :: Lens' UIState LaunchOptions -- | The last clicked position on the world view. uiWorldCursor :: Lens' UIState (Maybe (Cosmic Coords)) -- | State of all World Editor widgets uiWorldEditor :: Lens' UIState (WorldEditor Name) -- | The state of REPL panel. uiREPL :: Lens' UIState REPLState -- | The hash value of the focused robot entity (so we can tell if its -- inventory changed) along with a list of the items in the focused -- robot's inventory. uiInventory :: Lens' UIState (Maybe (Int, List Name InventoryListEntry)) -- | The order and direction of sorting inventory list. uiInventorySort :: Lens' UIState InventorySortOptions -- | The current search string used to narrow the inventory view. uiInventorySearch :: Lens' UIState (Maybe Text) -- | Does the info panel contain more content past the top of the panel? uiMoreInfoTop :: Lens' UIState Bool -- | Does the info panel contain more content past the bottom of the panel? uiMoreInfoBot :: Lens' UIState Bool -- | A flag telling the UI to scroll the info panel to the very end (used -- when a new log message is appended). uiScrollToEnd :: Lens' UIState Bool -- | When this is Just, it represents a popup box containing an -- error message that is shown on top of the rest of the UI. uiError :: Lens' UIState (Maybe Text) -- | When this is Just, it represents a modal to be displayed on -- top of the UI, e.g. for the Help screen. uiModal :: Lens' UIState (Maybe Modal) -- | Status of the scenario goal: whether there is one, and whether it has -- been displayed to the user initially. uiGoal :: Lens' UIState GoalDisplay -- | When running with --autoplay, suppress the goal dialogs. -- -- For developement, the --cheat flag shows goals again. uiHideGoals :: Lens' UIState Bool -- | Map of achievements that were attained uiAchievements :: Lens' UIState (Map CategorizedAchievement Attainment) -- | The base-2 logarithm of the current game speed in ticks/second. Note -- that we cap this value to the range of +/- log2 INTMAX. lgTicksPerSecond :: Lens' UIState Int -- | The time of the last Frame event. lastFrameTime :: Lens' UIState TimeSpec -- | The amount of accumulated real time. Every time we get a -- Frame event, we accumulate the amount of real time that -- happened since the last frame, then attempt to take an appropriate -- number of ticks to "catch up", based on the target tick rate. -- -- See https://gafferongames.com/post/fix_your_timestep/ . accumulatedTime :: Lens' UIState TimeSpec -- | A counter used to track how many ticks have happened since the last -- time we updated the ticks/frame statistics. tickCount :: Lens' UIState Int -- | A counter used to track how many frames have been rendered since the -- last time we updated the ticks/frame statistics. frameCount :: Lens' UIState Int -- | A counter used to track how many ticks have happened in the current -- frame, so we can stop when we get to the tick cap. frameTickCount :: Lens' UIState Int -- | The time of the last info widget update lastInfoTime :: Lens' UIState TimeSpec -- | A toggle to show the FPS by pressing f uiShowFPS :: Lens' UIState Bool -- | A toggle to expand or collapse the REPL by pressing `Ctrl-k` uiShowREPL :: Lens' UIState Bool -- | A toggle to show or hide inventory items with count 0 by pressing `0` uiShowZero :: Lens' UIState Bool -- | A toggle to show debug. -- -- TODO: #1112 use record for selection of debug features? uiShowDebug :: Lens' UIState Bool -- | Whether to show or hide robots on the world map. uiShowRobots :: Getter UIState Bool -- | Hide robots on the world map. uiHideRobotsUntil :: Lens' UIState TimeSpec -- | Whether the Inventory ui panel should update uiInventoryShouldUpdate :: Lens' UIState Bool -- | Computed ticks per milli seconds uiTPF :: Lens' UIState Double -- | Computed frames per milli seconds uiFPS :: Lens' UIState Double -- | Attribute map uiAttrMap :: Lens' UIState AttrMap -- | The currently active Scenario description, useful for starting over. scenarioRef :: Lens' UIState (Maybe ScenarioInfoPair) -- | The initial state of the focus ring. NOTE: Normally, the Tab key might -- cycle through the members of the focus ring. However, the REPL already -- uses Tab. So, to is not used at all right now for navigating the -- toplevel focus ring. initFocusRing :: FocusRing Name -- | The initial tick speed. defaultInitLgTicksPerSecond :: Int -- | Initialize the UI state. This needs to be in the IO monad since it -- involves reading a REPL history file, getting the current time, and -- loading text files from the data directory. The Bool -- parameter indicates whether we should start off by showing the main -- menu. initUIState :: (Has (Accum (Seq SystemFailure)) sig m, Has (Lift IO) sig m) => Int -> Bool -> Bool -> m UIState -- | Facilities for stepping the robot CESK machines, i.e. the -- actual interpreter for the Swarm language. -- -- -- -- The only reason we need IO is so that robots can run programs -- loaded from files, via the Run command. This could be avoided -- by using Import command instead and parsing the required -- files at the time of declaration. See -- https://github.com/swarm-game/swarm/issues/495. module Swarm.Game.Step -- | The main function to do one game tick. -- -- Note that the game may be in RobotStep mode and not finish the -- tick. Use the return value to check whether a full tick happened. gameTick :: (Has (State GameState) sig m, Has (Lift IO) sig m) => m Bool -- | Finish a game tick in progress and set the game to WorldTick -- mode afterwards. -- -- Use this function if you need to unpause the game. finishGameTick :: (Has (State GameState) sig m, Has (Lift IO) sig m) => m () insertBackRobot :: Has (State GameState) sig m => RID -> Robot -> m () runRobotIDs :: (Has (State GameState) sig m, Has (Lift IO) sig m) => IntSet -> m () singleStep :: (Has (State GameState) sig m, Has (Lift IO) sig m) => SingleStep -> RID -> IntSet -> m Bool -- | An accumulator for folding over the incomplete objectives to evaluate -- for their completion data CompletionsWithExceptions CompletionsWithExceptions :: [Text] -> ObjectiveCompletion -> [Objective] -> CompletionsWithExceptions [exceptions] :: CompletionsWithExceptions -> [Text] [completions] :: CompletionsWithExceptions -> ObjectiveCompletion -- | Upon completion, an objective is enqueued. It is dequeued when -- displayed on the UI. [completionAnnouncementQueue] :: CompletionsWithExceptions -> [Objective] -- | Execute the win condition check *hypothetically*: i.e. in a fresh CESK -- machine, using a copy of the current game state. -- -- The win check is performed only on "active" goals; that is, the goals -- that are currently unmet and have had all of their prerequisites -- satisfied. Note that it may be possible, while traversing through the -- goal list, for one goal to be met earlier in the list that happens to -- be a prerequisite later in the traversal. This is why: 1) We must not -- pre-filter the goals to be traversed based on satisfied prerequisites -- (i.e. we cannot use the "getActiveObjectives" function). 2) The -- traversal order must be "reverse topological" order, so that -- prerequisites are evaluated before dependent goals. 3) The iteration -- needs to be a "fold", so that state is updated after each element. hypotheticalWinCheck :: (Has (State GameState) sig m, Has (Lift IO) sig m) => EntityMap -> GameState -> WinStatus -> ObjectiveCompletion -> m () evalPT :: (Has (Lift IO) sig m, Has (Throw Exn) sig m, Has (State GameState) sig m) => ProcessedTerm -> m Value getNow :: Has (Lift IO) sig m => m TimeSpec -- | Create a special robot to check some hypothetical, for example the win -- condition. -- -- Use ID (-1) so it won't conflict with any robots currently in the -- robot map. hypotheticalRobot :: CESK -> TimeSpec -> Robot evaluateCESK :: (Has (Lift IO) sig m, Has (Throw Exn) sig m, Has (State GameState) sig m) => CESK -> m Value runCESK :: (Has (Lift IO) sig m, Has (Throw Exn) sig m, Has (State GameState) sig m, Has (State Robot) sig m) => CESK -> m Value -- | Set a flag telling the UI that the world needs to be redrawn. flagRedraw :: Has (State GameState) sig m => m () -- | Perform an action requiring a World state component in a larger -- context with a GameState. zoomWorld :: Has (State GameState) sig m => SubworldName -> StateC (World Int Entity) Identity b -> m (Maybe b) -- | Get the entity (if any) at a given location. entityAt :: Has (State GameState) sig m => Cosmic Location -> m (Maybe Entity) -- | Modify the entity (if any) at a given location. updateEntityAt :: Has (State GameState) sig m => Cosmic Location -> (Maybe Entity -> Maybe Entity) -> m () -- | Get the robot with a given ID. robotWithID :: Has (State GameState) sig m => RID -> m (Maybe Robot) -- | Get the robot with a given name. robotWithName :: Has (State GameState) sig m => Text -> m (Maybe Robot) -- | Generate a uniformly random number using the random generator in the -- game state. uniform :: (Has (State GameState) sig m, UniformRange a) => (a, a) -> m a -- | Given a weighting function and a list of values, choose one of the -- values randomly (using the random generator in the game state), with -- the probability of each being proportional to its weight. Return -- Nothing if the list is empty. weightedChoice :: Has (State GameState) sig m => (a -> Integer) -> [a] -> m (Maybe a) -- | Generate a random robot name in the form adjective_name. randomName :: Has (State GameState) sig m => m Text -- | Create a log entry given current robot and game time in ticks noting -- whether it has been said. -- -- This is the more generic version used both for (recorded) said -- messages and normal logs. createLogEntry :: (Has (State GameState) sig m, Has (State Robot) sig m) => LogSource -> Text -> m LogEntry -- | Print some text via the robot's log. traceLog :: (Has (State GameState) sig m, Has (State Robot) sig m) => LogSource -> Text -> m LogEntry -- | Print a showable value via the robot's log. -- -- Useful for debugging. traceLogShow :: (Has (State GameState) sig m, Has (State Robot) sig m, Show a) => a -> m () -- | Capabilities needed for a specific robot to evaluate or execute a -- constant. Right now, the only difference is whether the robot is heavy -- or not when executing the Move command, but there might be -- other exceptions added in the future. constCapsFor :: Const -> Robot -> Maybe Capability -- | Ensure that a robot is capable of executing a certain constant (either -- because it has a device which gives it that capability, or it is a -- system robot, or we are in creative mode). ensureCanExecute :: (Has (State Robot) sig m, Has (State GameState) sig m, Has (Throw Exn) sig m) => Const -> m () -- | Test whether the current robot has a given capability (either because -- it has a device which gives it that capability, or it is a system -- robot, or we are in creative mode). hasCapability :: (Has (State Robot) sig m, Has (State GameState) sig m) => Capability -> m Bool -- | Ensure that either a robot has a given capability, OR we are in -- creative mode. hasCapabilityFor :: (Has (State Robot) sig m, Has (State GameState) sig m, Has (Throw Exn) sig m) => Capability -> Term -> m () -- | Create an exception about a command failing. cmdExn :: Const -> [Text] -> Exn -- | Create an exception about a command failing, with an achievement cmdExnWithAchievement :: Const -> [Text] -> GameplayAchievement -> Exn -- | Raise an exception about a command failing with a formatted error -- message. raise :: Has (Throw Exn) sig m => Const -> [Text] -> m a -- | Run a subcomputation that might throw an exception in a context where -- we are returning a CESK machine; any exception will be turned into an -- Up state. withExceptions :: Monad m => Store -> Cont -> ThrowC Exn m CESK -> m CESK -- | Run a robot for one tick, which may consist of up to -- robotStepsPerTick CESK machine steps and at most one tangible -- command execution, whichever comes first. tickRobot :: (Has (State GameState) sig m, Has (Lift IO) sig m) => Robot -> m Robot -- | Recursive helper function for tickRobot, which checks if the -- robot is actively running and still has steps left, and if so runs it -- for one step, then calls itself recursively to continue stepping the -- robot. tickRobotRec :: (Has (State GameState) sig m, Has (Lift IO) sig m) => Robot -> m Robot -- | Single-step a robot by decrementing its tickSteps counter and -- running its CESK machine for one step. stepRobot :: (Has (State GameState) sig m, Has (Lift IO) sig m) => Robot -> m Robot -- | replace some entity in the world with another entity updateWorld :: (Has (State GameState) sig m, Has (Throw Exn) sig m) => Const -> WorldUpdate Entity -> m () applyRobotUpdates :: (Has (State GameState) sig m, Has (State Robot) sig m) => [RobotUpdate] -> m () data SKpair SKpair :: Store -> Cont -> SKpair -- | Performs some side-effectful computation for an FImmediate -- Frame. Aborts processing the continuation stack if an error is -- encountered. -- -- Compare to "withExceptions". processImmediateFrame :: (Has (State GameState) sig m, Has (State Robot) sig m, Has (Lift IO) sig m) => Value -> SKpair -> ErrorC Exn m () -> m CESK updateWorldAndRobots :: HasRobotStepState sig m => Const -> [WorldUpdate Entity] -> [RobotUpdate] -> m () -- | The main CESK machine workhorse. Given a robot, look at its CESK -- machine state and figure out a single next step. stepCESK :: (Has (State GameState) sig m, Has (State Robot) sig m, Has (Lift IO) sig m) => CESK -> m CESK -- | Eexecute a constant, catching any exception thrown and returning it -- via a CESK machine state. evalConst :: (Has (State GameState) sig m, Has (State Robot) sig m, Has (Lift IO) sig m) => Const -> [Value] -> Store -> Cont -> m CESK -- | A system program for a "seed robot", to regrow a growable entity after -- it is harvested. seedProgram :: Integer -> Integer -> Text -> ProcessedTerm -- | Construct a "seed robot" from entity, time range and position, and add -- it to the world. It has low priority and will be covered by placed -- entities. addSeedBot :: Has (State GameState) sig m => Entity -> (Integer, Integer) -> Cosmic Location -> TimeSpec -> m () -- | All functions that are used for robot step can access GameState -- and the current Robot. -- -- They can also throw exception of our custom type, which is handled -- elsewhere. Because of that the constraint is only Throw, but -- not Catch/ErrorLevel. type HasRobotStepState sig m = (Has (State GameState) sig m, Has (State Robot) sig m, Has (Throw Exn) sig m) -- | Interpret the execution (or evaluation) of a constant application to -- some values. execConst :: (HasRobotStepState sig m, Has (Lift IO) sig m) => Const -> [Value] -> Store -> Cont -> m CESK addWatchedLocation :: HasRobotStepState sig m => Cosmic Location -> m () -- | Clear watches that are out of range purgeFarAwayWatches :: HasRobotStepState sig m => m () -- | Exempts the robot from various command constraints when it is either a -- system robot or playing in creative mode isPrivilegedBot :: (Has (State GameState) sig m, Has (State Robot) sig m) => m Bool -- | Requires that the target location is within one cell. Requirement is -- waived if the bot is privileged. isNearbyOrExempt :: Bool -> Cosmic Location -> Cosmic Location -> Bool grantAchievement :: (Has (State GameState) sig m, Has (Lift IO) sig m) => GameplayAchievement -> m () data MoveFailureMode PathBlocked :: MoveFailureMode PathLiquid :: MoveFailureMode data MoveFailureDetails MoveFailureDetails :: Entity -> MoveFailureMode -> MoveFailureDetails -- | How to handle failure, for example when moving to blocked location data RobotFailure ThrowExn :: RobotFailure Destroy :: RobotFailure IgnoreFail :: RobotFailure -- | How to handle failure when moving/teleporting to a location. data MoveFailure MoveFailure :: RobotFailure -> RobotFailure -> MoveFailure [failIfBlocked] :: MoveFailure -> RobotFailure [failIfDrown] :: MoveFailure -> RobotFailure data GrabbingCmd Grab' :: GrabbingCmd Harvest' :: GrabbingCmd Swap' :: GrabbingCmd Push' :: GrabbingCmd verbGrabbingCmd :: GrabbingCmd -> Text verbedGrabbingCmd :: GrabbingCmd -> Text -- | Format a set of suggested devices for use in an error message, in the -- format device1 or device2 or ... or deviceN. formatDevices :: Set Entity -> Text -- | Give some entities from a parent robot (the robot represented by the -- ambient State Robot effect) to a child robot (represented by -- the given RID) as part of a Build or Reprogram -- command. The first Inventory is devices to be equipped, and the -- second is entities to be transferred. -- -- In classic mode, the entities will be transferred (that is, -- removed from the parent robot's inventory); in creative mode, the -- entities will be copied/created, that is, no entities will be removed -- from the parent robot. provisionChild :: HasRobotStepState sig m => RID -> Inventory -> Inventory -> m () -- | Update the location of a robot, and simultaneously update the -- robotsByLocation map, so we can always look up robots by -- location. This should be the only way to update the location of -- a robot. Also implements teleportation by portals. updateRobotLocation :: HasRobotStepState sig m => Cosmic Location -> Cosmic Location -> m () -- | Execute a stateful action on a target robot --- whether the current -- one or another. onTarget :: HasRobotStepState sig m => RID -> (forall sig' m'. HasRobotStepState sig' m' => m' ()) -> m () -- | Evaluate the application of a comparison operator. Returns -- Nothing if the application does not make sense. evalCmp :: Has (Throw Exn) sig m => Const -> Value -> Value -> m Bool -- | Compare two values, returning an Ordering if they can be -- compared, or Nothing if they cannot. compareValues :: Has (Throw Exn) sig m => Value -> Value -> m Ordering -- | Values with different types were compared; this should not be possible -- since the type system should catch it. incompatCmp :: Has (Throw Exn) sig m => Value -> Value -> m a -- | Values were compared of a type which cannot be compared (e.g. -- functions, etc.). incomparable :: Has (Throw Exn) sig m => Value -> Value -> m a -- | Evaluate the application of an arithmetic operator, returning an -- exception in the case of a failing operation, or in case we -- incorrectly use it on a bad Const in the library. evalArith :: Has (Throw Exn) sig m => Const -> Integer -> Integer -> m Integer -- | Perform an integer division, but return Nothing for division -- by zero. safeDiv :: Has (Throw Exn) sig m => Integer -> Integer -> m Integer -- | Perform exponentiation, but return Nothing if the power is -- negative. safeExp :: Has (Throw Exn) sig m => Integer -> Integer -> m Integer -- | Update the global list of discovered entities, and check for new -- recipes. updateDiscoveredEntities :: HasRobotStepState sig m => Entity -> m () -- | Update the availableRecipes list. This implementation is not -- efficient: * Every time we discover a new entity, we iterate through -- the entire list of recipes to see which ones we can make. Trying to do -- something more clever seems like it would definitely be a case of -- premature optimization. One doesn't discover new entities all that -- often. * For each usable recipe, we do a linear search through the -- list of known recipes to see if we already know it. This is a little -- more troubling, since it's quadratic in the number of recipes. But it -- probably doesn't really make that much difference until we get up to -- thousands of recipes. updateAvailableRecipes :: Has (State GameState) sig m => (Inventory, Inventory) -> Entity -> m () updateAvailableCommands :: Has (State GameState) sig m => Entity -> m () instance GHC.Show.Show Swarm.Game.Step.GrabbingCmd instance GHC.Classes.Eq Swarm.Game.Step.GrabbingCmd -- | Query current and upstream Swarm version. module Swarm.Version -- | Check that the tag follows the PVP versioning policy. -- -- Note that this filters out VS Code plugin releases. isSwarmReleaseTag :: String -> Bool version :: String -- | Read Swarm tag as Version. -- -- Swarm tags follow the PVP versioning scheme, so comparing them makes -- sense. -- --
--   >>> map (first versionBranch) $ readP_to_S parseVersion "0.1.0.0"
--   [([0],".1.0.0"),([0,1],".0.0"),([0,1,0],".0"),([0,1,0,0],"")]
--   
--   >>> Version [0,0,0,1] [] < tagToVersion "0.1.0.0"
--   True
--   
tagToVersion :: String -> Version -- | Get the current upstream release version if any. upstreamReleaseVersion :: IO (Either NewReleaseFailure String) -- | Get a newer upstream release version. -- -- This function can fail if the current branch is not main, if there is -- no Internet connection or no newer release. getNewerReleaseVersion :: Maybe GitInfo -> IO (Either NewReleaseFailure String) data NewReleaseFailure [FailedReleaseQuery] :: String -> NewReleaseFailure [NoMainUpstreamRelease] :: [String] -> NewReleaseFailure [OnDevelopmentBranch] :: String -> NewReleaseFailure [OldUpstreamRelease] :: Version -> Version -> NewReleaseFailure instance GHC.Show.Show Swarm.Version.NewReleaseFailure -- | Application state for the brick-based Swarm TUI. module Swarm.TUI.Model -- | AppEvent represents a type for custom event types our app can -- receive. The primary custom event Frame is sent by a separate -- thread as fast as it can, telling the TUI to render a new frame. data AppEvent Frame :: AppEvent Web :: WebCommand -> AppEvent UpstreamVersion :: Either NewReleaseFailure String -> AppEvent newtype WebCommand RunWebCode :: Text -> WebCommand data FocusablePanel -- | The panel containing the REPL. REPLPanel :: FocusablePanel -- | The panel containing the world view. WorldPanel :: FocusablePanel -- | The panel containing the world editor controls. WorldEditorPanel :: FocusablePanel -- | The panel showing robot info and inventory on the top left. RobotPanel :: FocusablePanel -- | The info panel on the bottom left. InfoPanel :: FocusablePanel -- | Name represents names to uniquely identify various components -- of the UI, such as forms, panels, caches, extents, lists, and buttons. data Name FocusablePanel :: FocusablePanel -> Name -- | An individual control within the world editor panel. WorldEditorPanelControl :: WorldEditorFocusable -> Name -- | The REPL input form. REPLInput :: Name -- | The render cache for the world view. WorldCache :: Name -- | The cached extent for the world view. WorldExtent :: Name -- | The cursor/viewCenter display in the bottom left of the World view WorldPositionIndicator :: Name -- | The list of possible entities to paint a map with. EntityPaintList :: Name -- | The entity paint item position in the EntityPaintList. EntityPaintListItem :: Int -> Name -- | The list of possible terrain materials. TerrainList :: Name -- | The terrain item position in the TerrainList. TerrainListItem :: Int -> Name -- | The list of inventory items for the currently focused robot. InventoryList :: Name -- | The inventory item position in the InventoryList. InventoryListItem :: Int -> Name -- | The list of main menu choices. MenuList :: Name -- | The list of achievements. AchievementList :: Name -- | An individual control within the scenario launch config panel ScenarioConfigControl :: ScenarioConfigPanel -> Name -- | The list of goals/objectives. GoalWidgets :: GoalWidget -> Name -- | The list of scenario choices. ScenarioList :: Name -- | The scrollable viewport for the info panel. InfoViewport :: Name -- | The scrollable viewport for any modal dialog. ModalViewport :: Name -- | A clickable button in a modal dialog. Button :: Button -> Name data ModalType HelpModal :: ModalType RecipesModal :: ModalType CommandsModal :: ModalType MessagesModal :: ModalType EntityPaletteModal :: ModalType TerrainPaletteModal :: ModalType RobotsModal :: ModalType ScenarioEndModal :: ScenarioOutcome -> ModalType QuitModal :: ModalType KeepPlayingModal :: ModalType DescriptionModal :: Entity -> ModalType GoalModal :: ModalType data ScenarioOutcome WinModal :: ScenarioOutcome LoseModal :: ScenarioOutcome -- | Clickable buttons in modal dialogs. data Button CancelButton :: Button KeepPlayingButton :: Button StartOverButton :: Button QuitButton :: Button NextButton :: Button data ButtonAction Cancel :: ButtonAction KeepPlaying :: ButtonAction StartOver :: Seed -> ScenarioInfoPair -> ButtonAction QuitAction :: ButtonAction Next :: ScenarioInfoPair -> ButtonAction data Modal Modal :: ModalType -> Dialog ButtonAction Name -> Modal [_modalType] :: Modal -> ModalType [_modalDialog] :: Modal -> Dialog ButtonAction Name modalType :: Lens' Modal ModalType modalDialog :: Lens' Modal (Dialog ButtonAction Name) data MainMenuEntry NewGame :: MainMenuEntry Tutorial :: MainMenuEntry Achievements :: MainMenuEntry Messages :: MainMenuEntry About :: MainMenuEntry Quit :: MainMenuEntry mainMenu :: MainMenuEntry -> List Name MainMenuEntry data Menu -- | We started playing directly from command line, no menu to show NoMenu :: Menu MainMenu :: List Name MainMenuEntry -> Menu -- | Stack of scenario item lists. INVARIANT: the currently selected menu -- item is ALWAYS the same as the scenario currently being played. See -- https://github.com/swarm-game/swarm/issues/1064 and -- https://github.com/swarm-game/swarm/pull/1065. NewGameMenu :: NonEmpty (List Name ScenarioItem) -> Menu AchievementsMenu :: List Name CategorizedAchievement -> Menu MessagesMenu :: Menu AboutMenu :: Menu _NewGameMenu :: Prism' Menu (NonEmpty (List Name ScenarioItem)) -- | Create a brick List of scenario items from a -- ScenarioCollection. mkScenarioList :: Bool -> ScenarioCollection -> List Name ScenarioItem -- | Given a ScenarioCollection and a FilePath which is the -- canonical path to some folder or scenario, construct a -- NewGameMenu stack focused on the given item, if possible. mkNewGameMenu :: Bool -> ScenarioCollection -> FilePath -> Maybe Menu -- | An item in the REPL history. data REPLHistItem -- | Something entered by the user. REPLEntry :: Text -> REPLHistItem -- | A response printed by the system. REPLOutput :: Text -> REPLHistItem -- | Get the text of REPL input/output. replItemText :: REPLHistItem -> Text -- | Useful helper function to filter out REPL output. isREPLEntry :: REPLHistItem -> Bool -- | Useful helper function to only get user input text. getREPLEntry :: REPLHistItem -> Maybe Text -- | History of the REPL with indices (0 is first entry) to the current -- line and to the first entry since loading saved history. We also -- (ab)use the length of the REPL as the index of current input line, -- since that number is one past the index of last entry. data REPLHistory -- | The current index in the REPL history (if the user is going back -- through the history using up/down keys). replIndex :: Lens' REPLHistory Int -- | Current number lines of the REPL history - (ab)used as index of input -- buffer. replLength :: REPLHistory -> Int -- | Sequence of REPL inputs and outputs, oldest entry is leftmost. replSeq :: Lens' REPLHistory (Seq REPLHistItem) -- | Create new REPL history (i.e. from loaded history file lines). newREPLHistory :: [REPLHistItem] -> REPLHistory -- | Add new REPL input - the index must have been pointing one past the -- last element already, so we increment it to keep it that way. addREPLItem :: REPLHistItem -> REPLHistory -> REPLHistory -- | Point the start of REPL history after current last line. See -- replStart. restartREPLHistory :: REPLHistory -> REPLHistory -- | Get the latest N items in history, starting with the oldest one. -- -- This is used to show previous REPL lines in UI, so we need the items -- sorted in the order they were entered and will be drawn top to bottom. getLatestREPLHistoryItems :: Int -> REPLHistory -> [REPLHistItem] moveReplHistIndex :: TimeDir -> Text -> REPLHistory -> REPLHistory getCurrentItemText :: REPLHistory -> Maybe Text replIndexIsAtInput :: REPLHistory -> Bool data TimeDir Newer :: TimeDir Older :: TimeDir -- | This data type tells us how to interpret the text typed by the player -- at the prompt (which is stored in Editor). data REPLPrompt -- | Interpret the prompt text as a regular command. The list is for -- potential completions, which we can cycle through by hitting Tab -- repeatedly CmdPrompt :: [Text] -> REPLPrompt -- | Interpret the prompt text as "search this text in history" SearchPrompt :: REPLHistory -> REPLPrompt -- | Given some text, removes the REPLEntry within REPLHistory which is -- equal to that. This is used when the user enters in search mode and -- want to traverse the history. If a command has been used many times, -- the history will be populated with it causing the effect that search -- command always finds the same command. removeEntry :: Text -> REPLHistory -> REPLHistory -- | An entry in the inventory list displayed in the info panel. We can -- either have an entity with a count in the robot's inventory, an entity -- equipped on the robot, or a labelled separator. The purpose of the -- separators is to show a clear distinction between the robot's -- inventory and its equipped devices. data InventoryListEntry Separator :: Text -> InventoryListEntry InventoryEntry :: Count -> Entity -> InventoryListEntry EquippedEntry :: Entity -> InventoryListEntry _Separator :: Prism' InventoryListEntry Text _InventoryEntry :: Prism' InventoryListEntry (Count, Entity) _EquippedEntry :: Prism' InventoryListEntry Entity data REPLState -- | What is being done with user input to the REPL panel? data ReplControlMode -- | The user is typing at the REPL. Typing :: ReplControlMode -- | The user is driving the base using piloting mode. Piloting :: ReplControlMode -- | A custom user key handler is processing user input. Handling :: ReplControlMode -- | The way we interpret text typed by the player in the REPL prompt. replPromptType :: Lens' REPLState REPLPrompt -- | The prompt where the user can type input at the REPL. replPromptEditor :: Lens' REPLState (Editor Text Name) -- | Convinience lens to get text from editor and replace it with new one -- that has the provided text. replPromptText :: Lens' REPLState Text -- | Whether the prompt text is a valid Term. replValid :: Lens' REPLState Bool -- | The last thing the user has typed which isn't part of the history. -- This is used to restore the repl form after the user visited the -- history. replLast :: Lens' REPLState Text -- | The type of the current REPL input which should be displayed to the -- user (if any). replType :: Lens' REPLState (Maybe Polytype) -- | The current REPL control mode, i.e. how user input to the REPL panel -- is being handled. replControlMode :: Lens' REPLState ReplControlMode -- | History of things the user has typed at the REPL, interleaved with -- outputs the system has generated. replHistory :: Lens' REPLState REPLHistory newREPLEditor :: Text -> Editor Text Name -- | Given the focused robot, populate the UI inventory list in the info -- panel with information about its inventory. populateInventoryList :: MonadState UIState m => Maybe Robot -> m () infoScroll :: ViewportScroll Name modalScroll :: ViewportScroll Name data RuntimeState -- | The port on which the HTTP debug service is running. webPort :: Lens' RuntimeState (Maybe Port) -- | The upstream release version. upstreamRelease :: Lens' RuntimeState (Either NewReleaseFailure String) -- | A log of runtime events. -- -- This logging is separate from the logging done during game-play. If -- some error happens before a game is even selected, this is the place -- to log it. eventLog :: Lens' RuntimeState (Notifications LogEntry) -- | A collection of typechecked world DSL terms that are available to be -- used in scenario definitions. worlds :: Lens' RuntimeState WorldMap -- | The collection of scenarios that comes with the game. scenarios :: Lens' RuntimeState ScenarioCollection -- | The standard entity map loaded from disk. Individual scenarios may -- define additional entities which will get added to this map when -- loading the scenario. stdEntityMap :: Lens' RuntimeState EntityMap -- | The standard list of recipes loaded from disk. Individual scenarios -- may define additional recipes which will get added to this list when -- loading the scenario. stdRecipes :: Lens' RuntimeState [Recipe Entity] -- | Free-form data loaded from the data directory, for things -- like the logo, about page, tutorial story, etc. appData :: Lens' RuntimeState (Map Text Text) -- | List of words for use in building random robot names. stdAdjList :: Lens' RuntimeState (Array Int Text) -- | List of words for use in building random robot names. stdNameList :: Lens' RuntimeState (Array Int Text) -- | Simply log to the runtime event log. logEvent :: LogSource -> (Text, RID) -> Text -> Notifications LogEntry -> Notifications LogEntry -- | Create a GameStateConfig record from the RuntimeState. mkGameStateConfig :: RuntimeState -> GameStateConfig -- | The AppState just stores together the other states. -- -- This is so you can use a smaller state when e.g. writing some game -- logic or updating the UI. Also consider that GameState can change when -- loading a new scenario - if the state should persist games, use -- RuntimeState. data AppState AppState :: GameState -> UIState -> RuntimeState -> AppState -- | The GameState record. gameState :: Lens' AppState GameState -- | The UIState record. uiState :: Lens' AppState UIState -- | The RuntimeState record runtimeState :: Lens' AppState RuntimeState -- | Command-line options for configuring the app. data AppOpts AppOpts :: Maybe Seed -> Maybe FilePath -> Maybe FilePath -> Bool -> Int -> Bool -> Maybe ColorMode -> Maybe Port -> Maybe GitInfo -> AppOpts -- | Explicit seed chosen by the user. [userSeed] :: AppOpts -> Maybe Seed -- | Scenario the user wants to play. [userScenario] :: AppOpts -> Maybe FilePath -- | Code to be run on base. [scriptToRun] :: AppOpts -> Maybe FilePath -- | Automatically run the solution defined in the scenario file [autoPlay] :: AppOpts -> Bool -- | Initial game speed (logarithm) [speed] :: AppOpts -> Int -- | Should cheat mode be enabled? [cheatMode] :: AppOpts -> Bool -- | What colour mode should be used? [colorMode] :: AppOpts -> Maybe ColorMode -- | Explicit port on which to run the web API [userWebPort] :: AppOpts -> Maybe Port -- | Information about the Git repository (not present in release). [repoGitInfo] :: AppOpts -> Maybe GitInfo -- | A default/empty AppOpts record. defaultAppOpts :: AppOpts type Seed = Int data ColorMode NoColor :: ColorMode ColorMode8 :: ColorMode ColorMode16 :: ColorMode ColorMode240 :: !Word8 -> ColorMode FullColor :: ColorMode -- | Context for the REPL commands to execute in. Contains the base robot -- context plus the it variable that refer to the previously -- computed values. (Note that `it{n}` variables are set in the base -- robot context; we only set it here because it's so transient) topContext :: AppState -> RobotContext -- | Get the currently focused InventoryListEntry from the robot -- info panel (if any). focusedItem :: AppState -> Maybe InventoryListEntry -- | Get the currently focused entity from the robot info panel (if any). -- This is just like focusedItem but forgets the distinction -- between plain inventory items and equipped devices. focusedEntity :: AppState -> Maybe Entity -- | Extract the scenario which would come next in the menu from the -- currently selected scenario (if any). Can return Nothing if -- either we are not in the NewGameMenu, or the current scenario -- is the last among its siblings. nextScenario :: Menu -> Maybe ScenarioInfoPair initRuntimeState :: (Has (Throw SystemFailure) sig m, Has (Accum (Seq SystemFailure)) sig m, Has (Lift IO) sig m) => m RuntimeState instance GHC.Show.Show Swarm.TUI.Model.WebCommand instance GHC.Show.Show Swarm.TUI.Model.AppEvent module Swarm.TUI.View.Achievement padAllEvenly :: Int -> Widget Name -> Widget Name getCompletionIcon :: Bool -> Widget Name drawAchievementsMenuUI :: AppState -> List Name CategorizedAchievement -> Widget Name drawAchievementListItem :: Map CategorizedAchievement Attainment -> CategorizedAchievement -> Widget Name singleAchievementDetails :: Map CategorizedAchievement Attainment -> CategorizedAchievement -> Widget Name module Swarm.TUI.Editor.Util getEntitiesForList :: EntityMap -> Vector EntityFacade getEditingBounds :: WorldDescription -> (Bool, Cosmic BoundsRectangle) getContentAt :: WorldEditor Name -> MultiWorld Int Entity -> Cosmic Coords -> (TerrainType, Maybe EntityPaint) getTerrainAt :: WorldEditor Name -> MultiWorld Int Entity -> Cosmic Coords -> TerrainType isOutsideTopLeftCorner :: Coords -> Coords -> Bool isOutsideBottomRightCorner :: Coords -> Coords -> Bool isOutsideRegion :: BoundsRectangle -> Coords -> Bool getEditedMapRectangle :: WorldEditor Name -> Maybe (Cosmic BoundsRectangle) -> MultiWorld Int Entity -> [[CellPaintDisplay]] module Swarm.TUI.Model.StateUpdate -- | Initialize the AppState from scratch. initAppState :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => AppOpts -> m AppState -- | Initialize the more persistent parts of the app state, i.e. the -- RuntimeState and UIState. This is split out into a -- separate function so that in the integration test suite we can call -- this once and reuse the resulting states for all tests. initPersistentState :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => AppOpts -> m (RuntimeState, UIState) -- | Construct an AppState from an already-loaded -- RuntimeState and UIState, given the AppOpts the -- app was started with. constructAppState :: (Has (Throw SystemFailure) sig m, Has (Lift IO) sig m) => RuntimeState -> UIState -> AppOpts -> m AppState -- | Create an initial app state for a specific scenario. Note that this -- function is used only for unit tests, integration tests, and -- benchmarks. -- -- In normal play, an AppState already exists and we simply need -- to update it using scenarioToAppState. initAppStateForScenario :: String -> Maybe Seed -> Maybe FilePath -> ExceptT Text IO AppState -- | For convenience, the AppState corresponding to the classic game -- with seed 0. This is used only for benchmarks and unit tests. classicGame0 :: ExceptT Text IO AppState -- | Load a Scenario and start playing the game. startGame :: (MonadIO m, MonadState AppState m) => ScenarioInfoPair -> Maybe CodeToRun -> m () -- | Load a Scenario and start playing the game, with the -- possibility for the user to override the seed. startGameWithSeed :: (MonadIO m, MonadState AppState m) => ScenarioInfoPair -> ValidatedLaunchParams -> m () -- | Re-initialize the game from the stored reference to the current -- scenario. -- -- Note that "restarting" is intended only for "scenarios"; with some -- scenarios, it may be possible to get stuck so that it is either -- impossible or very annoying to win, so being offered an option to -- restart is more user-friendly. -- -- Since scenarios are stored as a Maybe in the UI state, we handle the -- Nothing case upstream so that the Scenario passed to this function -- definitely exists. restartGame :: (MonadIO m, MonadState AppState m) => Seed -> ScenarioInfoPair -> m () attainAchievement :: (MonadIO m, MonadState AppState m) => CategorizedAchievement -> m () attainAchievement' :: (MonadIO m, MonadState AppState m) => ZonedTime -> Maybe FilePath -> CategorizedAchievement -> m () -- | Modify the AppState appropriately when starting a new scenario. scenarioToAppState :: (MonadIO m, MonadState AppState m) => ScenarioInfoPair -> ValidatedLaunchParams -> m () module Swarm.TUI.Editor.Masking shouldHideWorldCell :: UIState -> Coords -> Bool -- | Rendering of cells in the map view -- -- SPDX-License-Identifier: BSD-3-Clause module Swarm.TUI.View.CellDisplay -- | Render a display as a UI widget. renderDisplay :: Display -> Widget n -- | Render the Display for a specific location. drawLoc :: UIState -> GameState -> Cosmic Coords -> Widget Name displayTerrainCell :: WorldEditor Name -> GameState -> Cosmic Coords -> Display displayRobotCell :: GameState -> Cosmic Coords -> [Display] displayEntityCell :: WorldEditor Name -> GameState -> Cosmic Coords -> [Display] data HideEntity HideAllEntities :: HideEntity HideNoEntity :: HideEntity HideEntityUnknownTo :: Robot -> HideEntity hidingMode :: GameState -> HideEntity -- | Get the Display for a specific location, by combining the -- Displays for the terrain, entity, and robots at the location, -- and taking into account "static" based on the distance to the robot -- being viewed. displayLoc :: Bool -> WorldEditor Name -> GameState -> Cosmic Coords -> Display -- | Get the Display for a specific location, by combining the -- Displays for the terrain, entity, and robots at the location. displayLocRaw :: Bool -> WorldEditor Name -> GameState -> Cosmic Coords -> Display -- | Random "static" based on the distance to the robot being -- viewed. staticDisplay :: GameState -> Coords -> Display -- | Draw static given a number from 0-15 representing the state of the -- four quarter-pixels in a cell displayStatic :: Word32 -> Display -- | Given a value from 0--15, considered as 4 bits, pick the character -- with the corresponding quarter pixels turned on. staticChar :: Word32 -> Char -- | Random "static" based on the distance to the robot being -- viewed. A cell can either be static-free (represented by -- Nothing) or can have one of sixteen values (representing the -- state of the four quarter-pixels in one cell). getStatic :: GameState -> Coords -> Maybe Word32 module Swarm.TUI.View.Util -- | Generate a fresh modal window of the requested type. generateModal :: AppState -> ModalType -> Modal -- | Render the type of the current REPL input to be shown to the user. drawType :: Polytype -> Widget Name -- | Draw markdown document with simple codebolditalic attributes. -- -- TODO: #574 Code blocks should probably be handled separately. drawMarkdown :: Document Syntax -> Widget Name drawLabeledTerrainSwatch :: TerrainType -> Widget Name descriptionTitle :: Entity -> String -- | Width cap for modal and error message windows maxModalWindowWidth :: Int -- | Get the name of the current New Game menu. curMenuName :: AppState -> Maybe Text quitMsg :: Menu -> Text locationToString :: Location -> String -- | Display a list of text-wrapped paragraphs with one blank line after -- each. displayParagraphs :: [Text] -> Widget Name -- | Display a list of paragraphs with one blank line after each. -- -- For the common case of `[Text]` use displayParagraphs. layoutParagraphs :: [Widget Name] -> Widget Name data EllipsisSide Beginning :: EllipsisSide End :: EllipsisSide withEllipsis :: EllipsisSide -> Text -> Widget Name -- | Make a widget scrolling if it is bigger than the available vertical -- space. Thanks to jtdaugherty for this code. maybeScroll :: (Ord n, Show n) => n -> Widget n -> Widget n -- | Display logic for Objectives. module Swarm.TUI.View.Objective makeListWidget :: GoalTracking -> List Name GoalEntry renderGoalsDisplay :: GoalDisplay -> Widget Name getCompletionIcon :: Objective -> GoalStatus -> Widget Name drawGoalListItem :: Bool -> GoalEntry -> Widget Name singleGoalDetails :: GoalEntry -> Widget Name -- | Rendering of the scenario launch configuration dialog. module Swarm.TUI.Launch.View drawFileBrowser :: FileBrowser Name -> Widget Name optionDescription :: ScenarioConfigPanelFocusable -> Maybe Text drawLaunchConfigPanel :: LaunchOptions -> [Widget Name] module Swarm.TUI.Editor.View drawWorldEditor :: FocusRing Name -> UIState -> Widget Name drawLabeledEntitySwatch :: EntityFacade -> Widget Name drawTerrainSelector :: AppState -> Widget Name listDrawTerrainElement :: Int -> Bool -> TerrainType -> Widget Name drawEntityPaintSelector :: AppState -> Widget Name listDrawEntityPaintElement :: Int -> Bool -> EntityFacade -> Widget Name module Swarm.TUI.Controller.Util -- | Pattern synonyms to simplify brick event handler pattern Key :: Key -> BrickEvent n e pattern CharKey :: Char -> BrickEvent n e pattern ControlChar :: Char -> BrickEvent n e pattern MetaChar :: Char -> BrickEvent n e pattern ShiftKey :: Key -> BrickEvent n e pattern EscapeKey :: BrickEvent n e pattern BackspaceKey :: BrickEvent n e pattern FKey :: Int -> BrickEvent n e openModal :: ModalType -> EventM Name AppState () -- | The running modals do not autopause the game. isRunningModal :: ModalType -> Bool setFocus :: FocusablePanel -> EventM Name AppState () immediatelyRedrawWorld :: EventM Name AppState () -- | Make sure all tiles covering the visible part of the world are loaded. loadVisibleRegion :: EventM Name AppState () mouseLocToWorldCoords :: Location -> EventM Name GameState (Maybe (Cosmic Coords)) -- | Event handling for the scenario launch configuration dialog. module Swarm.TUI.Launch.Controller updateFocusRing :: EditingLaunchParams -> EventM Name LaunchOptions () cacheValidatedInputs :: EventM Name LaunchOptions () -- | Split this out from the combined parameter-validation function because -- validating the seed is cheap, and shouldn't have to pay the cost of -- re-parsing script code as the user types in the seed selection field. cacheValidatedSeedInput :: EventM Name LaunchOptions () -- | If the FileBrowser is in "search mode", then we allow more of the key -- events to pass through. Otherwise, we intercept things like "q" (for -- quit) and Space (so that we can restrict file selection to at most -- one). handleFBEvent :: BrickEvent Name AppEvent -> EventM Name AppState () handleLaunchOptionsEvent :: ScenarioInfoPair -> BrickEvent Name AppEvent -> EventM Name AppState () module Swarm.TUI.Editor.Controller activateWorldEditorFunction :: WorldEditorFocusable -> EventM Name AppState () handleCtrlLeftClick :: Location -> EventM Name AppState () handleRightClick :: Location -> EventM Name AppState () -- | "Eye Dropper" tool: handleMiddleClick :: Location -> EventM Name AppState () -- | Handle user input events in the robot panel. handleWorldEditorPanelEvent :: BrickEvent Name AppEvent -> EventM Name AppState () -- | Return value: whether the cursor position should be updated updateAreaBounds :: Maybe (Cosmic Coords) -> EventM Name AppState Bool saveMapFile :: EventM Name AppState () -- | Event handlers for the TUI. module Swarm.TUI.Controller -- | The top-level event handler for the TUI. handleEvent :: BrickEvent Name AppEvent -> EventM Name AppState () -- | Quit a game. -- -- quitGame :: EventM Name AppState () -- | Run the game for a single frame (i.e. screen redraw), -- then update the UI. Depending on how long it is taking to draw each -- frame, and how many ticks per second we are trying to achieve, this -- may involve stepping the game any number of ticks (including zero). runFrameUI :: EventM Name AppState () -- | Run the game for a single frame, without updating the UI. runFrame :: EventM Name AppState () ticksPerFrameCap :: Int -- | Do zero or more ticks, with each tick notionally taking the given -- timestep, until we have used up all available accumulated time, OR -- until we have hit the cap on ticks per frame, whichever comes first. runFrameTicks :: TimeSpec -> EventM Name AppState () -- | Run the game for a single tick, and update the UI. runGameTickUI :: EventM Name AppState () -- | Run the game for a single tick (without updating the UI). Every -- robot is given a certain amount of maximum computation to perform a -- single world action (like moving, turning, grabbing, etc.). runGameTick :: EventM Name AppState () -- | Update the UI. This function is used after running the game for some -- number of ticks. updateUI :: EventM Name AppState Bool runBaseWebCode :: MonadState AppState m => Text -> m () -- | Handle a user input event for the REPL. handleREPLEvent :: BrickEvent Name AppEvent -> EventM Name AppState () -- | Validate the REPL input when it changes: see if it parses and -- typechecks, and set the color accordingly. validateREPLForm :: AppState -> AppState -- | Update our current position in the REPL history. adjReplHistIndex :: TimeDir -> AppState -> AppState data TimeDir Newer :: TimeDir Older :: TimeDir -- | Handle a user input event in the world view panel. handleWorldEvent :: BrickEvent Name AppEvent -> EventM Name AppState () -- | Convert a directional key into a direction. keyToDir :: Key -> Heading -- | Manually scroll the world view. scrollView :: (Location -> Location) -> EventM Name AppState () -- | Adjust the ticks per second speed. adjustTPS :: (Int -> Int -> Int) -> AppState -> AppState -- | Handle user events in the info panel (just scrolling). handleInfoPanelEvent :: ViewportScroll Name -> BrickEvent Name AppEvent -> EventM Name AppState () getTutorials :: ScenarioCollection -> ScenarioCollection instance GHC.Classes.Eq Swarm.TUI.Controller.CompletionType -- | Code for drawing the TUI. module Swarm.TUI.View -- | The main entry point for drawing the entire UI. Figures out which menu -- screen we should show (if any), or just the game itself. drawUI :: AppState -> [Widget Name] -- | Draw info about the current number of ticks per second. drawTPS :: AppState -> Widget Name -- | Draw the error dialog window, if it should be displayed right now. drawDialog :: AppState -> Widget Name -- | Hide the cursor when a modal is set chooseCursor :: AppState -> [CursorLocation n] -> Maybe (CursorLocation n) -- | Draw a menu explaining what key commands are available for the current -- panel. This menu is displayed as one or two lines in between the world -- panel and the REPL. -- -- This excludes the F-key modals that are shown elsewhere. drawKeyMenu :: AppState -> Widget Name -- | Draw the F-key modal menu. This is displayed in the top left world -- corner. drawModalMenu :: AppState -> Widget Name -- | Draw a single key command in the menu. drawKeyCmd :: (KeyHighlight, Text, Text) -> Widget Name -- | Draw the current world view. drawWorld :: UIState -> GameState -> Widget Name -- | Draw info about the currently focused robot, such as its name, -- position, orientation, and inventory, as long as it is not too far -- away. drawRobotPanel :: AppState -> Widget Name -- | Draw an inventory entry. drawItem :: Maybe Int -> Int -> Bool -> InventoryListEntry -> Widget Name -- | Draw the name of an entity, labelled with its visual representation as -- a cell in the world. drawLabelledEntityName :: Entity -> Widget Name -- | Draw the info panel in the bottom-left corner, which shows info about -- the currently focused inventory item. drawInfoPanel :: AppState -> Widget Name -- | Display info about the currently focused inventory entity, such as its -- description and relevant recipes. explainFocusedItem :: AppState -> Widget Name -- | Draw the REPL. drawREPL :: AppState -> Widget Name -- | Assess pedagogical soundness of the tutorials. -- -- Approach: 1. Obtain a list of all of the tutorial scenarios, in order -- 2. Search their "solution" code for commands 3. "fold" over -- the tutorial list, noting which tutorial was first to introduce each -- command module Swarm.Doc.Pedagogy renderTutorialProgression :: IO Text -- | Extract the tutorials from the complete scenario collection and derive -- their command coverage info. generateIntroductionsSequence :: ScenarioCollection -> [CoverageInfo] -- | Tutorials augmented by the set of commands that they introduce. -- Generated by folding over all of the tutorials in sequence. data CoverageInfo CoverageInfo :: TutorialInfo -> Map Const [SrcLoc] -> CoverageInfo [tutInfo] :: CoverageInfo -> TutorialInfo [novelSolutionCommands] :: CoverageInfo -> Map Const [SrcLoc] -- | Tutorial scenarios with the set of commands introduced in their -- solution and descriptions having been extracted data TutorialInfo TutorialInfo :: ScenarioInfoPair -> Int -> Map Const [SrcLoc] -> Set Const -> TutorialInfo [scenarioPair] :: TutorialInfo -> ScenarioInfoPair [tutIndex] :: TutorialInfo -> Int [solutionCommands] :: TutorialInfo -> Map Const [SrcLoc] [descriptionCommands] :: TutorialInfo -> Set Const module Swarm.Doc.Gen generateDocs :: GenerateDocs -> IO () data GenerateDocs -- | Entity dependencies by recipes. [RecipeGraph] :: GenerateDocs -- | Keyword lists for editors. [EditorKeywords] :: Maybe EditorType -> GenerateDocs -- | List of special key names recognized by key command [SpecialKeyNames] :: GenerateDocs [CheatSheet] :: PageAddress -> Maybe SheetType -> GenerateDocs -- | List command introductions by tutorial [TutorialCoverage] :: GenerateDocs data EditorType Emacs :: EditorType VSCode :: EditorType data SheetType Entities :: SheetType Commands :: SheetType Capabilities :: SheetType Recipes :: SheetType -- | Get formatted list of basic functions/commands. keywordsCommands :: EditorType -> Text -- | Get formatted list of directions. keywordsDirections :: EditorType -> Text operatorNames :: Text builtinFunctionList :: EditorType -> Text editorList :: EditorType -> [Text] -> Text data PageAddress PageAddress :: Text -> Text -> Text -> Text -> PageAddress [entityAddress] :: PageAddress -> Text [commandsAddress] :: PageAddress -> Text [capabilityAddress] :: PageAddress -> Text [recipesAddress] :: PageAddress -> Text commandsPage :: Text capabilityPage :: PageAddress -> EntityMap -> Text noPageAddresses :: PageAddress instance GHC.Enum.Bounded Swarm.Doc.Gen.EditorType instance GHC.Enum.Enum Swarm.Doc.Gen.EditorType instance GHC.Show.Show Swarm.Doc.Gen.EditorType instance GHC.Classes.Eq Swarm.Doc.Gen.EditorType instance GHC.Enum.Bounded Swarm.Doc.Gen.SheetType instance GHC.Enum.Enum Swarm.Doc.Gen.SheetType instance GHC.Show.Show Swarm.Doc.Gen.SheetType instance GHC.Classes.Eq Swarm.Doc.Gen.SheetType instance GHC.Show.Show Swarm.Doc.Gen.PageAddress instance GHC.Classes.Eq Swarm.Doc.Gen.PageAddress instance GHC.Show.Show Swarm.Doc.Gen.GenerateDocs instance GHC.Classes.Eq Swarm.Doc.Gen.GenerateDocs -- | A web service for Swarm. -- -- The service can be started using the `--port 5357` command line -- argument, or through the REPL by calling demoWeb. -- -- Once running, here are the available endpoints: -- -- -- -- Missing endpoints: -- -- module Swarm.Web newtype RobotID RobotID :: Int -> RobotID type SwarmAPI = "robots" :> Get '[JSON] [Robot] :<|> "robot" :> Capture "id" RobotID :> Get '[JSON] (Maybe Robot) :<|> "goals" :> "prereqs" :> Get '[JSON] [PrereqSatisfaction] :<|> "goals" :> "active" :> Get '[JSON] [Objective] :<|> "goals" :> "graph" :> Get '[JSON] (Maybe GraphInfo) :<|> "goals" :> "uigoal" :> Get '[JSON] GoalTracking :<|> "goals" :> Get '[JSON] WinCondition :<|> "code" :> "render" :> ReqBody '[PlainText] Text :> Post '[PlainText] Text :<|> "code" :> "run" :> ReqBody '[PlainText] Text :> Post '[PlainText] Text :<|> "repl" :> "history" :> "full" :> Get '[JSON] [REPLHistItem] swarmApi :: Proxy SwarmAPI type ToplevelAPI = SwarmAPI :<|> Raw api :: Proxy ToplevelAPI docsBS :: ByteString mkApp :: ReadableIORef AppState -> BChan AppEvent -> Server SwarmAPI -- | Simple result type to report errors from forked startup thread. data WebStartResult WebStarted :: WebStartResult WebStartError :: String -> WebStartResult webMain :: Maybe (MVar WebStartResult) -> Port -> ReadableIORef AppState -> BChan AppEvent -> IO () defaultPort :: Port -- | Attempt to start a web thread on the requested port, or a default one -- if none is requested (or don't start a web thread if the requested -- port is 0). If an explicit port was requested, fail if startup doesn't -- work. Otherwise, ignore the failure. In any case, return a Maybe -- Port value representing whether a web server is actually running, -- and if so, what port it is on. startWebThread :: Maybe Port -> ReadableIORef AppState -> BChan AppEvent -> IO (Either String Port) instance Web.Internal.HttpApiData.FromHttpApiData Swarm.Web.RobotID instance Servant.Docs.Internal.ToCapture (Servant.API.Capture.Capture "id" Swarm.Web.RobotID) instance Servant.Docs.Internal.ToSample Data.Text.Internal.Text -- | Main entry point for the Swarm application. module Swarm.App type EventHandler = BrickEvent Name AppEvent -> EventM Name AppState () -- | The definition of the app used by the brick library. app :: EventHandler -> App AppState AppEvent Name -- | The main IO computation which initializes the state, sets up -- some communication channels, and runs the UI. appMain :: AppOpts -> IO () -- | A demo program to run the web service directly, without the terminal -- application. This is useful to live update the code using `ghcid -W -- --test "Swarm.App.demoWeb"` demoWeb :: IO () -- | If available for the terminal emulator, enable bracketed paste mode. enablePasteMode :: EventM n s ()