never executed always true always false
    1 {-|
    2 Description : Brainfuck parsing
    3 Copyright   : (c) Sebastian Galkin, 2018
    4 License     : GPL-3
    5 
    6 Parsing 'Text' into 'Program' 'Unparsed'
    7 -}
    8 module HBF.Parser
    9   ( module HBF.Parser
   10   -- * Reexport from "Text.Parsec"
   11   , Text.Parsec.ParseError
   12   ) where
   13 
   14 import           Control.Applicative   ((<|>))
   15 import           Data.Text.Lazy        (Text)
   16 import           Text.Parsec           (ParseError, between, eof, many, many1,
   17                                         runP)
   18 import           Text.Parsec.Char      (char, noneOf, oneOf)
   19 import           Text.Parsec.Text.Lazy (Parser)
   20 
   21 import           HBF.Types
   22 
   23 -- $setup
   24 -- >>> :set -XOverloadedStrings
   25 -- >>> import Data.Either
   26 -- >>> let parse :: Parser a -> Text -> Either ParseError a; parse p text = runP p () "" text
   27 -- | Parser for a full 'Program'.
   28 --
   29 -- >>> isRight $ parse program "  +[->>+  +[<] ##garbage## ],.[-]  can ignore garbage"
   30 -- True
   31 program :: Parser (Program Unoptimized)
   32 program = Program <$> many1 operation
   33 
   34 -- | Parser for an 'Op', ignoring unknown characters.
   35 --
   36 -- >>> parse operation "  +///"
   37 -- Right (Inc 1 0)
   38 --
   39 -- >>> parse operation "fooo  [+>]  baaar  "
   40 -- Right (Loop [Inc 1 0,Move 1])
   41 operation :: Parser Op
   42 operation = many garbage *> (simpleOp <|> loopOp) <* many garbage
   43 
   44 -- | The characters allowed in a Brainfuck program except for the loop characters @[@ and @]@.
   45 bfSimpleTokens :: String
   46 bfSimpleTokens = "><+-.,"
   47 
   48 -- | The characters allowed in a Brainfuck program.
   49 bfTokens :: String
   50 bfTokens = "[]" ++ bfSimpleTokens
   51 
   52 -- | Parser for unknown characters
   53 --
   54 -- >>> parse garbage "this is @#! garbage"
   55 -- Right 't'
   56 --
   57 -- >>> isLeft $ parse garbage "+"
   58 -- True
   59 garbage :: Parser Char
   60 garbage = noneOf bfTokens
   61 
   62 -- | Parser for simple operations (not loops).
   63 --
   64 -- >>> parse simpleOp ">"
   65 -- Right (Move 1)
   66 --
   67 -- >>> parse simpleOp "."
   68 -- Right (Out 1 0)
   69 simpleOp :: Parser Op
   70 simpleOp = build <$> oneOf bfSimpleTokens
   71   where
   72     build '>' = Move 1
   73     build '<' = Move (-1)
   74     build '+' = Inc 1 0
   75     build '-' = Inc (-1) 0
   76     build '.' = Out 1 0
   77     build ',' = In 1 0
   78     build _   = error "Unknown character"
   79 
   80 -- | Parser for loops.
   81 --
   82 -- >>> parse loopOp "[+-]"
   83 -- Right (Loop [Inc 1 0,Inc (-1) 0])
   84 loopOp :: Parser Op
   85 loopOp = Loop . instructions <$> between (char '[') (char ']') program
   86 
   87 -- | Parse program stream. Returns an error or the parsed 'Program'
   88 parseProgram :: Text -> Either ParseError (Program Unoptimized)
   89 parseProgram = runP (program <* eof) () ""