packages feed

brainfuck-tut 0.5.1.3 → 0.6.0.0

raw patch · 3 files changed

+68/−44 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Language.Brainfuck.Parse: instance Show JumpMatchError
+ Language.Brainfuck.Parse: matchJumps :: [Term] -> Either JumpPairs JumpMatchError
+ Language.Brainfuck.Parse: type JumpPairs = [(Int, Int)]

Files

brainfuck-tut.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                brainfuck-tut-version:             0.5.1.3+version:             0.6.0.0 synopsis:            A simple BF interpreter. license:             BSD3 license-file:        LICENSE
src/Language/Brainfuck/Eval.hs view
@@ -13,8 +13,7 @@  import Data.Array ((//), (!)) import Data.Char (ord, chr)-import Data.List (elemIndices)-import Data.Maybe (listToMaybe)+import Data.Tuple (swap) import Data.Word (Word8)  import Language.Brainfuck.Types@@ -45,61 +44,64 @@  >>> let tape = listArray (0,99) (replicate 100 0) >>> eval tape "+.+."-TODO+\1\2 >>> eval tape ",."-TODO-+aa -} eval :: Tape -> String -> IO Tape eval storage program =   let instructions = parse program+      jumpPairs = matchJumps instructions -  in go storage instructions instructions 0 (PC 0)+  in case jumpPairs of+     (Right e) -> print e >> return storage+     (Left j)  -> let jrev = map swap j in+       step storage instructions instructions 0 (PC 0) j jrev    -- first set of instructions we advance over   -- second set of instructions are maintained for jump logic-  where go :: Tape -> [Term] -> [Term] ->-              DataPointer -> ProgramCounter -> IO Tape-        go tape [] _ _ _ = return tape-        go tape (IncDP:ops) os pos pc = go tape ops os (pos+1) (next pc)-        go tape (DecDP:ops) os pos pc = go tape ops os (pos-1) (next pc)-        go tape (IncByte:ops) os pos pc =-          go (modPos tape pos (+1)) ops os pos (next pc)-        go tape (DecByte:ops) os pos pc =-          go (modPos tape pos (subtract 1)) ops os pos (next pc)-        go tape (OutByte:ops) os pos pc =-          (showAt tape pos) >> go tape ops os pos (next pc)-        go tape (InByte:ops) os pos pc = do-          c <- getChar-          let b = fromIntegral $ ord c :: Word8-          go (tape // [(pos, b)]) ops os pos (next pc)-        go tape (JumpForward:ops) os pos pc = if shouldJump Forward tape pos-          then jump tape Forward os pos pc-          else go tape ops os pos (next pc)-        go tape (JumpBackward:ops) os pos pc = if shouldJump Backward tape pos-          then jump tape Backward os pos pc-          else go tape ops os pos (next pc)+  -- first JumpPairs allows lookups for ForwardJumps+  -- second JumpPairs allows lookups for BackwardJumps+  -- TODO: consider using a Reader monad to carry environment+  where step :: Tape -> [Term] -> [Term] ->+                DataPointer -> ProgramCounter -> JumpPairs -> JumpPairs ->+                IO Tape+        step tape [] _ _ _ _ _ = return tape+        step tape (o:ops) os pos pc jp jpr = case o of+          IncDP -> step tape ops os (pos+1) (next pc) jp jpr+          DecDP -> step tape ops os (pos-1) (next pc) jp jpr+          IncByte -> step (modAt tape pos (+1)) ops os pos (next pc) jp jpr+          DecByte -> step (modAt tape pos (subtract 1)) ops os pos (next pc) jp jpr+          OutByte -> showAt tape pos >> step tape ops os pos (next pc) jp jpr+          InByte -> do+            c <- getChar+            let b = fromIntegral $ ord c :: Word8+            step (tape // [(pos, b)]) ops os pos (next pc) jp jpr+          JumpForward -> doJump Forward tape ops os pos pc jp jpr+          JumpBackward -> doJump Backward tape ops os pos pc jp jpr -        jump tape dir os pos (PC pc) = do-          let jumpTo = findFunc dir pc (flipDir dir) os+        doJump :: Direction -> Tape -> [Term] -> [Term] ->+                  DataPointer -> ProgramCounter -> JumpPairs -> JumpPairs ->+                  IO Tape+        doJump dir tape ops os pos pc jp jpr =+          if shouldJump dir tape pos+          then jump tape dir os pos pc jp jpr+          else step tape ops os pos (next pc) jp jpr++        jump :: Tape -> Direction -> [Term] ->+                DataPointer -> ProgramCounter -> JumpPairs -> JumpPairs ->+                IO Tape+        jump tape dir os pos (PC pc) jp jpr = do+          let jumpTo = lookup pc (if dir == Forward then jp else jpr)           case jumpTo of-            Nothing -> print "jump not found" >> return tape-            (Just p) -> go tape (drop p os) os pos (PC p)+            Nothing -> return tape+            (Just p) -> step tape (drop p os) os pos (PC p) jp jpr          -- jump utilities-        dirToJump Forward  = JumpForward-        dirToJump Backward = JumpBackward         shouldJump Forward tape pos = (tape ! pos) == 0         shouldJump Backward tape pos = (tape ! pos) /= 0-        findIx p x = listToMaybe . filter p . elemIndices x-        findIxAfter pos = findIx (>pos)-        findIxBefore pos = findIx (<pos)-        findFunc Forward = findIxAfter-        findFunc Backward = findIxBefore-        flipDir Forward = dirToJump Backward-        flipDir Backward = dirToJump Forward          -- other evaluator utilities-        modPos arr pos f = arr // [(pos, f (arr ! pos))]-        showAt arr pos = putChar $ (chr . fromIntegral) $ (arr ! pos)+        modAt arr pos f = arr // [(pos, f (arr ! pos))]+        showAt arr pos = putChar $ (chr . fromIntegral) (arr ! pos)         next (PC n) = PC $ n + 1
src/Language/Brainfuck/Parse.hs view
@@ -8,7 +8,9 @@ Portability : POSIX -} module Language.Brainfuck.Parse (-  parse+  parse,+  matchJumps,+  JumpPairs ) where  import Language.Brainfuck.Types (Term(..))@@ -26,3 +28,23 @@   '[' -> JumpForward : parse xs   ']' -> JumpBackward : parse xs   _   -> parse xs++-- |Possible failure modes for pre-computing jump locations+data JumpMatchError+  = ForwardJumpNotMatched Int+  | BackwardJumpNotMatched Int deriving Show++type JumpPairs = [(Int,Int)]++-- TODO: swap [(Int,Int)] with Map Int Int for efficiency+-- |Given a list of terms, precomputes jump locations for matching '[' ']'+-- |Respects nesting of '[' and ']' terms.+matchJumps :: [Term] -> Either JumpPairs JumpMatchError+matchJumps ts' = go ts' [] 0 []+  where go (JumpForward:t:ts) acc pos ret = go (t:ts) (pos:acc) (pos+1) ret+        go (JumpBackward:ts) (p:acc) pos ret = go ts acc (pos+1) ((p,pos):ret)+        go (JumpBackward:_) [] pos _ = Right $ BackwardJumpNotMatched pos+        go [JumpForward] _ pos _ = Right $ ForwardJumpNotMatched pos+        go [] (p:_) _ _ = Right $ ForwardJumpNotMatched p+        go [] [] _ ret = Left ret+        go (_:ts) acc pos ret = go ts acc (pos+1) ret