-- see https://markkarpov.com/tutorial/megaparsec.html {-# LANGUAGE ImportQualifiedPost #-} module Parser.Expr (parseExpr, ParseResult) where import Control.Monad.Combinators.Expr import Data.Functor.Identity qualified import Data.Void (Void) import Text.Megaparsec as MP import Text.Megaparsec.Char as C import Text.Megaparsec.Char.Lexer as L import Types.Expr type Parser = Parsec Void String lexemeParser :: Parser a -> Parser a lexemeParser = L.lexeme C.space symbolParser :: String -> Parser String symbolParser = L.symbol C.space intParser :: Parser Int intParser = lexemeParser L.decimal term :: Parser Expr term = Lit <$> intParser table :: [[Operator Parser Expr]] table = [ [ binaryOp "*" Mul -- binaryOp "/" Div ], [ binaryOp "+" Add, binaryOp "-" Sub ] ] binaryOp :: String -> (a -> a -> a) -> Operator (ParsecT Void String Data.Functor.Identity.Identity) a binaryOp name f = InfixL (f <$ symbolParser name) expr :: Parser Expr expr = makeExprParser term table type ParseResult = Either (ParseErrorBundle String Void) Expr parseExpr :: String -> ParseResult parseExpr = MP.parse (C.space *> expr <* eof) "" -- parseE = parseExpr