packages feed

Fungi-1.0: Ip.hs

module Ip (
    Ip
  , mkIp

  , getId
  , getPos
  , getDelta
  , getSs
  , isAlive
  , getStorageOffset
  , getSemantics

  , testMode
  , addMode
  , removeMode
  , toggleMode

  , killIp
  , reverseIp
  , setPos
  , setDelta
  , setSs
  , setStorageOffset

  ) where

import Control.Monad.State.Strict

import Data.Deque
import Data.I
import Data.Map (Map)
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Stack
import Data.Vector

import Text.PrettyShow

import Mode
import Semantics

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

type Instruction env i = StateT (env i) IO

data Ip env i = Ip {
    getId :: i
  , getPos :: Vector i
  , getDelta :: Vector i
  , getSs :: Stack (Deque i)
  , isAlive :: Bool
  , getStorageOffset :: !(Vector i)
  , getSemantics :: Semantics env i
  , modes :: Set Mode
  }

instance (PrettyShow i) => PrettyShow (Ip env i) where
  pshow ip = concat [ []
    , "(IP"
    , " "
    , "id=" ++ pshow (getId ip)
    , " "
    , "pos=" ++ pshow (getPos ip)
    , " "
    , "delta=" ++ pshow (getDelta ip)
    , " "
    , "modes=" ++ pshow (Set.toList $ modes ip)
    , ")"
    ]

mkIp :: (I i) => Int -> i -> Map i (Instruction env i ()) -> Ip env i
mkIp dim ident baseSemantics = Ip {
    getId = ident
  , getPos = takeV dim 0
  , getDelta = takeV dim (1 `cons` 0)
  , getSs = mkStack1 mkDeque
  , isAlive = True
  , getStorageOffset = takeV dim 0
  , getSemantics = mkSemantics baseSemantics
  , modes = Set.empty
  }

testMode :: Mode -> Ip env i -> Bool
testMode mode = Set.member mode . modes

addMode :: Mode -> Ip env i -> Ip env i
addMode mode ip = ip { modes = Set.insert mode $ modes ip }

removeMode :: Mode -> Ip env i -> Ip env i
removeMode mode ip = ip { modes = Set.delete mode $ modes ip }

toggleMode :: Mode -> Ip env i -> Ip env i
toggleMode mode ip = if testMode mode ip
  then removeMode mode ip
  else addMode mode ip

killIp :: Ip env i -> Ip env i
killIp ip = ip { isAlive = False }

reverseIp :: (Num i) => Ip env i -> Ip env i
reverseIp ip = ip { getDelta = negate . getDelta $ ip }

setPos :: (Num i) => Vector i -> Ip env i -> Ip env i
setPos pos ip = ip { getPos = pos }

setDelta :: (Num i) => Vector i -> Ip env i -> Ip env i
setDelta delta ip = ip { getDelta = delta }

setSs :: Stack (Deque i) -> Ip env i -> Ip env i
setSs s ip = ip { getSs = s }

setStorageOffset :: Vector i -> Ip env i -> Ip env i
setStorageOffset v ip = ip { getStorageOffset = v }