packages feed

cfopu-0.1.0: Data/Memory.hs

module Data.Memory ( Memory
                   , Cell
                   , initialMemory
                   , word8sToCells
                   , stringToCells
                   , charToCell
                   , word8ToCell
                   , defaultCell
                   , cellToWord8
                   , cellToChar
                   , cellsToWord8s
                   , cellsToString
                   , moveInstructionPointerLeft
                   , moveInstructionPointerRight
                   , moveDataPointerLeft
                   , moveDataPointerRight
                   , moveInstructionPointerToDataPointer
                   , moveDataPointerToInstructionPointer
                   , getInstruction
                   , getData
                   , setData
                   , modifyData
                   ) where

import Prelude hiding (null)
import Data.ByteString.Internal (c2w, w2c)
import Data.Dequeue
import Data.Maybe (fromJust)
import Data.Word (Word8)

type Cell              = Word8
type InternalContainer = BankersDequeue Cell  -- Back is right end; Front is left end

data Memory = ID { id_p :: InternalContainer
                 , id_i :: InternalContainer
                 , id_d :: InternalContainer
                 }
            | DI { di_p :: InternalContainer
                 , di_d :: InternalContainer
                 , di_i :: InternalContainer
                 }
            | E  { e_p  :: InternalContainer
                 , e_e  :: InternalContainer
                 }

initialMemory :: [Cell] -> Memory
initialMemory = E empty . foldr (flip pushFront) empty

defaultCell :: Cell
defaultCell = 0x00

word8ToCell :: Word8 -> Cell
word8ToCell = id

charToCell :: Char -> Cell
charToCell = c2w

word8sToCells :: [Word8] -> [Cell]
word8sToCells = map word8ToCell

stringToCells :: String -> [Cell]
stringToCells = map charToCell

cellToWord8 :: Cell -> Word8
cellToWord8 = id

cellToChar :: Cell -> Char
cellToChar = w2c

cellsToWord8s :: [Cell] -> [Word8]
cellsToWord8s = map cellToWord8

cellsToString :: [Cell] -> String
cellsToString = map cellToChar

moveInstructionPointerLeft :: Memory -> Memory
moveInstructionPointerLeft (ID p i d) =
    case popBack p of
        ((Just cell), p') -> ID p' (pushFront i cell)        d
        ((Nothing),   _)  -> ID p  (pushFront i defaultCell) d
moveInstructionPointerLeft (DI p d i) =
    case popBack d of
        ((Just cell), d') -> case () of _
                                           | null d'   -> E  p    $ pushFront i cell
                                           | otherwise -> DI p d' $ pushFront i cell
        ((Nothing),   _)  -> moveInstructionPointerLeft $ E p i
moveInstructionPointerLeft (E  p e) =
    case popBack p of
        ((Just cell), p') -> ID p' (pushFront empty cell)        e
        ((Nothing),   _)  -> ID p  (pushFront empty defaultCell) e

moveInstructionPointerRight :: Memory -> Memory
moveInstructionPointerRight (ID p i d) =
    case popFront i of
        ((Just cell), i') -> case () of _
                                           | null i'   -> E  (pushBack p cell) d
                                           | otherwise -> ID (pushBack p cell) i' d
        ((Nothing),   _)  -> moveInstructionPointerRight $ E p i
moveInstructionPointerRight (DI p d i) =
    case popFront i of
        ((Just cell), i') -> case () of _
                                           | null i'   -> DI p (pushBack d cell) $ pushBack i' defaultCell
                                           | otherwise -> DI p (pushBack d cell) $ i'
        ((Nothing),   _)  -> moveInstructionPointerRight $ E p d
moveInstructionPointerRight (E  p e) =
    case popFront e of
        ((Just cell), e') -> case () of _
                                           | null e'   -> DI p (pushBack empty cell) $ pushBack empty defaultCell
                                           | otherwise -> DI p (pushBack empty cell) e'
        ((Nothing),   _)  -> moveInstructionPointerRight $ E p $ pushBack empty defaultCell

moveDataPointerLeft :: Memory -> Memory
moveDataPointerLeft (ID p i d) =
    case popBack i of
        ((Just cell), i') -> case () of _
                                           | null i'   -> E  p    $ pushFront d cell
                                           | otherwise -> ID p i' $ pushFront d cell
        ((Nothing),   _)  -> moveDataPointerLeft $ E p d
moveDataPointerLeft (DI p d i) =
    case popBack p of
        ((Just cell), p') -> DI p' (pushFront d cell)        i
        ((Nothing),   _)  -> DI p  (pushFront d defaultCell) i
moveDataPointerLeft (E  p e) =
    case popBack p of
        ((Just cell), p') -> DI p' (pushFront empty cell)        e
        ((Nothing),   _)  -> DI p  (pushFront empty defaultCell) e

moveDataPointerRight :: Memory -> Memory
moveDataPointerRight (ID p i d) =
    case popFront d of
        ((Just cell), d') -> case () of _
                                           | null d'   -> ID p (pushBack i cell) $ pushBack d' defaultCell
                                           | otherwise -> ID p (pushBack i cell) $ d'
        ((Nothing),   _)  -> moveDataPointerRight $ E p i
moveDataPointerRight (DI p d i) =
    case popFront d of
        ((Just cell), d') -> case () of _
                                           | null d'   -> E  (pushBack p cell) i
                                           | otherwise -> DI (pushBack p cell) d' i
        ((Nothing),   _)  -> moveDataPointerRight $ E p d
moveDataPointerRight (E  p e) =
    case popFront e of
        ((Just cell), e') -> case () of _
                                           | null e'   -> ID p (pushBack empty cell) $ pushBack empty defaultCell
                                           | otherwise -> ID p (pushBack empty cell) e'
        ((Nothing),   _)  -> moveDataPointerRight $ E p $ pushBack empty defaultCell

moveInstructionPointerToDataPointer :: Memory -> Memory
moveInstructionPointerToDataPointer mem@(ID {}) = moveInstructionPointerToDataPointer . moveInstructionPointerRight $ mem
moveInstructionPointerToDataPointer mem@(DI {}) = moveInstructionPointerToDataPointer . moveInstructionPointerLeft  $ mem
moveInstructionPointerToDataPointer mem@(E  {}) = mem

moveDataPointerToInstructionPointer :: Memory -> Memory
moveDataPointerToInstructionPointer mem@(ID {}) = moveDataPointerToInstructionPointer . moveDataPointerLeft  $ mem
moveDataPointerToInstructionPointer mem@(DI {}) = moveDataPointerToInstructionPointer . moveDataPointerRight $ mem
moveDataPointerToInstructionPointer mem@(E  {}) = mem

getInstruction :: Memory -> Cell
getInstruction (ID p i d) =
    case popFront i of
        ((Just cell), _) -> cell
        ((Nothing),   _) -> getInstruction $ E p i
getInstruction (DI p d i) =
    case popFront i of
        ((Just cell), _) -> cell
        ((Nothing),   _) -> defaultCell
getInstruction (E  p e) =
    case popFront e of
        ((Just cell), _) -> cell
        ((Nothing),   _) -> defaultCell

getData :: Memory -> Cell
getData (ID p i d) =
    case popFront d of
        ((Just cell), _) -> cell
        ((Nothing),   _) -> defaultCell
getData (DI p d i) =
    case popFront d of
        ((Just cell), _) -> cell
        ((Nothing),   _) -> getData $ E p i
getData (E  p e) =
    case popFront e of
        ((Just cell), _) -> cell
        ((Nothing),   _) -> defaultCell

setData :: Cell -> Memory -> Memory
setData cell mem@(ID p i d) = mem{id_d = flip pushFront cell . snd $ popFront d}
setData cell mem@(DI p d i)
    | null d    = setData cell $ E p i
    | otherwise = mem{di_d  = flip pushFront cell . snd $ popFront d}
setData cell mem@(E  p e)   = mem{e_e  = flip pushFront cell . snd $ popFront e}

modifyData :: (Cell -> Cell) -> Memory -> Memory
modifyData f mem = flip setData mem . f . getData $ mem