{-| Module : Language.Brainfuck.Parse Description : Parser for the BF language Copyright : (c) Allele Dev, 2014 License : BSD-3 Maintainer : allele.dev@gmail.com Stability : experimental Portability : POSIX -} module Language.Brainfuck.Parse ( parse, matchJumps, JumpPairs ) where import Language.Brainfuck.Types (Term(..)) -- |A total function over the BF syntax. parse :: String -> [Term] parse [] = [] parse (x:xs) = case x of '>' -> IncDP : parse xs '<' -> DecDP : parse xs '?' -> OutDP : parse xs '+' -> IncByte : parse xs '-' -> DecByte : parse xs '.' -> OutByte : parse xs ',' -> InByte : parse xs '[' -> 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