PageRenderTime 44ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/versions/bitetail/Brainfuck.hs

http://github.com/rickardlindberg/brainfuck
Haskell | 106 lines | 84 code | 22 blank | 0 comment | 3 complexity | 0d65f3ab7abb883f07a492a552dd6afe MD5 | raw file
  1. module Brainfuck where
  2. import Data.Char (chr, ord)
  3. import Prelude hiding (Left, Right)
  4. import qualified Data.Map as M
  5. class Data d where
  6. emptyData :: d
  7. dataGet :: d -> Int
  8. dataModifyValue :: d -> (Int -> Int) -> d
  9. dataModifyPos :: (Int -> Int) -> d -> d
  10. dataMoveRight :: Data d => d -> d
  11. dataMoveRight = dataModifyPos (+1)
  12. dataMoveLeft :: Data d => d -> d
  13. dataMoveLeft = dataModifyPos (\x -> x - 1)
  14. data DataMap = DataMap
  15. { currentPos :: Int
  16. , values :: M.Map Int Int
  17. }
  18. emptyDataMap :: DataMap
  19. emptyDataMap = DataMap 0 M.empty
  20. instance Data DataMap where
  21. emptyData = emptyDataMap
  22. dataGet dat = M.findWithDefault 0 (currentPos dat) (values dat)
  23. dataModifyValue dat fn = dat { values = newValues }
  24. where
  25. value = M.findWithDefault 0 (currentPos dat) (values dat)
  26. newValues = M.insert (currentPos dat) (fn value) (values dat)
  27. dataModifyPos fn dat = dat { currentPos = fn (currentPos dat) }
  28. data CachingData = CachingData
  29. { currentValue :: Maybe Int
  30. , dataMap :: DataMap
  31. }
  32. emptyCachingDataMap :: CachingData
  33. emptyCachingDataMap = CachingData (Just 0) emptyDataMap
  34. instance Data CachingData where
  35. emptyData = emptyCachingDataMap
  36. dataGet (CachingData Nothing dataMap) = dataGet dataMap
  37. dataGet (CachingData (Just x) _) = x
  38. dataModifyValue (CachingData Nothing dataMap) fn = CachingData (Just $ fn $ dataGet dataMap) dataMap
  39. dataModifyValue (CachingData (Just x) dataMap) fn = CachingData (Just $ fn x) dataMap
  40. dataModifyPos fn (CachingData Nothing dataMap) = CachingData Nothing $ dataModifyPos fn dataMap
  41. dataModifyPos fn (CachingData (Just x) dataMap) = CachingData Nothing $ dataModifyPos fn $ dataModifyValue dataMap $ const x
  42. data Instruction
  43. = Inc
  44. | Dec
  45. | Left
  46. | Right
  47. | Print
  48. | Read
  49. | Loop [Instruction]
  50. deriving (Show, Eq)
  51. parse :: String -> [Instruction]
  52. parse input = let ("", instructios) = parseBlock input [] in instructios
  53. parseBlock :: String -> [Instruction] -> (String, [Instruction])
  54. parseBlock [] opTail = ([], opTail)
  55. parseBlock ('[':charsAfterOpening) opTail = (charTail, knot)
  56. where
  57. (charsAfterClosing, loopBody) = parseBlock charsAfterOpening knot
  58. (charTail, restOps) = parseBlock charsAfterClosing opTail
  59. knot = (Loop loopBody):restOps
  60. parseBlock (']':charsAfterClosing) opTail = (charsAfterClosing, opTail)
  61. parseBlock (x:xs) opTail
  62. | x `elem` "+-<>.," = let (a, b) = parseBlock xs opTail in (a, parseSingle x:b)
  63. | otherwise = parseBlock xs opTail
  64. parseSingle :: Char -> Instruction
  65. parseSingle '+' = Inc
  66. parseSingle '-' = Dec
  67. parseSingle '<' = Left
  68. parseSingle '>' = Right
  69. parseSingle '.' = Print
  70. parseSingle ',' = Read
  71. run :: Data d => [Instruction] -> String -> d -> String
  72. run [] input dat = "done!\n"
  73. run (Inc:next) input dat = run next input (dataModifyValue dat (+1))
  74. run (Dec:next) input dat = run next input (dataModifyValue dat (\x -> x - 1))
  75. run (Left:next) input dat = run next input (dataMoveLeft dat)
  76. run (Right:next) input dat = run next input (dataMoveRight dat)
  77. run (Print:next) input dat = chr (dataGet dat) : run next input dat
  78. run (Read:next) [] dat = error "no input"
  79. run (Read:next) (i:is) dat = run next is (dataModifyValue dat (const (ord i)))
  80. run ((Loop xs):next) input dat = if dataGet dat == 0
  81. then run next input dat
  82. else run xs input dat
  83. execute :: String -> IO ()
  84. execute program = interact (\input -> run (parse program) input emptyCachingDataMap)