{-# 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 Language.Haskell.TH.Syntax as TH import qualified Prelude import Symantic.Univariant.Trans 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.production Loop [||Loop||] SP.<$> bf) _ -> Prelude.undefined reproGrammar :: forall tok repr. CoerceEnum Char tok => CoerceEnum tok Char => SP.Grammarable tok repr => repr [tok] reproGrammar = SP.many (SP.item @tok)