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 
   28 
   29 -- | Parser for a full 'Program'.
   30 --
   31 -- >>> isRight $ parse program "  +[->>+  +[<] ##garbage## ],.[-]  can ignore garbage"
   32 -- True
   33 program :: Parser (Program Unoptimized)
   34 program = Program <$> many1 operation
   35 
   36 -- | Parser for an 'Op', ignoring unknown characters.
   37 --
   38 -- >>> parse operation "  +///"
   39 -- Right (Inc 1 0)
   40 --
   41 -- >>> parse operation "fooo  [+>]  baaar  "
   42 -- Right (Loop [Inc 1 0,Move 1])
   43 operation :: Parser Op
   44 operation = many garbage *> (simpleOp <|> loopOp) <* many garbage
   45 
   46 -- | The characters allowed in a Brainfuck program except for the loop characters @[@ and @]@.
   47 bfSimpleTokens :: String
   48 bfSimpleTokens = "><+-.,"
   49 
   50 -- | The characters allowed in a Brainfuck program.
   51 bfTokens :: String
   52 bfTokens = "[]" ++ bfSimpleTokens
   53 
   54 -- | Parser for unknown characters
   55 --
   56 -- >>> parse garbage "this is @#! garbage"
   57 -- Right 't'
   58 --
   59 -- >>> isLeft $ parse garbage "+"
   60 -- True
   61 garbage :: Parser Char
   62 garbage = noneOf bfTokens
   63 
   64 -- | Parser for simple operations (not loops).
   65 --
   66 -- >>> parse simpleOp ">"
   67 -- Right (Move 1)
   68 --
   69 -- >>> parse simpleOp "."
   70 -- Right (Out 1 0)
   71 simpleOp :: Parser Op
   72 simpleOp = build <$> oneOf bfSimpleTokens
   73   where
   74     build '>' = Move 1
   75     build '<' = Move (-1)
   76     build '+' = Inc 1 0
   77     build '-' = Inc (-1) 0
   78     build '.' = Out 1 0
   79     build ',' = In 1 0
   80     build _   = error "Unknown character"
   81 
   82 -- | Parser for loops.
   83 --
   84 -- >>> parse loopOp "[+-]"
   85 -- Right (Loop [Inc 1 0,Inc (-1) 0])
   86 loopOp :: Parser Op
   87 loopOp = Loop . instructions <$> between (char '[') (char ']') program
   88 
   89 -- | Parse program stream. Returns an error or the parsed 'Program'
   90 parseProgram :: Text -> Either ParseError (Program Unoptimized)
   91 parseProgram = runP (program <* eof) () ""