-- | This parser extends the @FormalLanguage.Parser@ parser of single- and -- multi-dim grammars to accept grammar product definitions as well. -- -- TODO display function names like this: module FormalLanguage.GrammarProduct.Parser where import Control.Arrow import Control.Applicative import Control.Lens import Control.Monad (MonadPlus(..), guard, when) import Control.Monad.Trans.Class import Control.Monad.Trans.State.Strict import Control.Monad.Trans.Reader import Data.Default import Data.Either import Data.Map (Map) import Data.Set (Set) import Debug.Trace import Data.List import qualified Data.ByteString.Char8 as B --import qualified Data.HashSet as H import qualified Data.Map as M import qualified Data.Set as S import Text.Parser.Expression import Text.Parser.Token.Highlight import Text.Parser.Token.Style import Text.Printf import Text.Trifecta import Text.Trifecta.Delta import Text.Trifecta.Result import Data.Semigroup ((<>)) import qualified "newtype" Control.Newtype as T --import Numeric.Natural.Internal import Prelude hiding (subtract) import Control.Monad import Data.Char (isUpper) import Data.Data.Lens import System.IO.Unsafe (unsafePerformIO) import FormalLanguage.CFG.Grammar import FormalLanguage.CFG.Parser import FormalLanguage.CFG.PrettyPrint.ANSI import FormalLanguage.GrammarProduct.Op -- | The top-level parser for a grammar product. It can be used as one of the -- additional parser arguments, the formal grammars parser accepts. parseGrammarProduct :: Parse m () parseGrammarProduct = do reserve fgIdents "Product:" n <- newGrammarName current <~ parseProductString current.grammarName .= n -- need to set here, otherwise the underlying combinator produces a combined name (funny but useless ;-) reserve fgIdents "//" v <- use verbose g <- use current seq (unsafePerformIO $ if v then (printDoc $ genGrammarDoc g) else return ()) $ env %= M.insert n g -- | Performs the actual parsing of a product string. Uses an expression parser -- internally. parseProductString :: Parse m Grammar parseProductString = getGrammar <$> expr where expr :: Parse m ExprGrammar expr = buildExpressionParser table term table = [ [ binary "><" exprDirect AssocLeft , binary "*" exprPower AssocLeft ] , [ binary "+" exprPlus AssocLeft , binary "-" exprMinus AssocLeft ] ] term = parens expr <|> (ExprGrammar <$> knownGrammarName "grammar not available in environment") <|> (ExprNumber <$> natural "integral power of grammar") binary n f a = Infix (f <$ reserve fgIdents n) a exprDirect l r = ExprGrammar (getGrammar l >< getGrammar r) exprPlus l r = ExprGrammar (getGrammar l `gAdd` getGrammar r) exprMinus l r = ExprGrammar (getGrammar l `gSubtract` getGrammar r) exprPower l r = ExprGrammar (getGrammar l `gPower` getNumber r) data ExprGrammar = ExprGrammar { getGrammar :: Grammar } | ExprNumber { getNumber :: Integer }