symantic-parser-0.2.1.20210803: parsers/Parsers/Brainfuck/SymanticParser/Grammar.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}
module Parsers.Brainfuck.SymanticParser.Grammar where
import Data.Char (Char)
import Data.Function ((.))
import qualified Prelude
import qualified Symantic.Parser as SP
import Parsers.Utils
import Parsers.Brainfuck.Types
-- | Use with @$$(runParser @Text grammar)@,
-- but in another Haskell module to avoid
-- GHC stage restriction on such top-level splice.
grammar :: forall tok repr.
CoerceEnum Char tok =>
CoerceEnum tok Char =>
SP.Grammarable tok repr =>
repr [Instruction]
grammar = whitespace SP.*> bf
where
whitespace = SP.skipMany (SP.noneOf (coerceEnum @_ @tok Prelude.<$> "<>+-,.[]"))
lexeme :: repr a -> repr a
lexeme p = p SP.<* whitespace
bf :: repr [Instruction]
bf = SP.many (lexeme (SP.match (SP.look (SP.item @tok))
(SP.prod . coerceEnum Prelude.<$> "<>+-,.[")
op SP.empty))
op :: SP.Production tok -> repr Instruction
op prod = case coerceEnum (SP.runValue prod) of
'<' -> SP.item @tok SP.$> SP.prod Backward
'>' -> SP.item @tok SP.$> SP.prod Forward
'+' -> SP.item @tok SP.$> SP.prod Increment
'-' -> SP.item @tok SP.$> SP.prod Decrement
',' -> SP.item @tok SP.$> SP.prod Input
'.' -> SP.item @tok SP.$> SP.prod Output
'[' -> SP.between (lexeme (SP.item @tok))
(SP.token (coerceEnum @_ @tok ']'))
($(SP.prodCon 'Loop) SP.<$> bf)
_ -> Prelude.undefined