perga/app/Parser.hs

91 lines
2 KiB
Haskell
Raw Normal View History

2024-10-05 13:31:09 -07:00
module Parser where
import Control.Monad (void)
import Data.Bifunctor (first)
import Data.Void (Void)
import Expr (Expr (..))
import Text.Megaparsec
( MonadParsec (eof, label),
Parsec,
between,
choice,
errorBundlePretty,
parse,
(<|>),
)
import Control.Applicative.Combinators.NonEmpty (some)
import Text.Megaparsec.Char
( char,
space1,
string,
)
import qualified Text.Megaparsec.Char.Lexer as L
import Data.Either (fromRight)
type Parser = Parsec Void String
skipSpace :: Parser ()
skipSpace =
L.space
space1
(L.skipLineComment "--")
(L.skipBlockCommentNested "(*" "*)")
lexeme :: Parser a -> Parser a
lexeme = L.lexeme skipSpace
pVar :: Parser Integer
pVar = label "variable" $ lexeme L.decimal
-- pVar :: Parser String
-- pVar = label "variable" $ lexeme $ do
-- firstChar <- letterChar <|> char '_'
-- rest <- many $ alphaNumChar <|> char '_'
-- return $ firstChar : rest
pLambda :: Parser ()
pLambda = lexeme $ label "λ" $ void $ string "lambda" <|> string "λ"
pPi :: Parser ()
pPi = lexeme $ label "Π" $ void $ string "Pi" <|> string "Π"
pLAbs :: Parser Expr
pLAbs = lexeme $ label "λ-abstraction" $ do
Abs <$> between pLambda pDot pExpr <*> pExpr
pPAbs :: Parser Expr
pPAbs = lexeme $ label "Π-abstraction" $ do
Pi <$> between pPi pDot pExpr <*> pExpr
pApp :: Parser Expr
pApp = foldl1 App <$> some pTerm
pDot :: Parser ()
pDot = lexeme $ label "." $ void $ char '.'
pStar :: Parser Expr
pStar = lexeme $ label "" $ Star <$ (string "*" <|> string "")
pSquare :: Parser Expr
pSquare = lexeme $ label "" $ Square <$ (string "" <|> string "[]")
pTerm :: Parser Expr
pTerm =
lexeme $
label "term" $
choice
[ between (char '(') (char ')') pExpr,
Var <$> pVar,
pStar,
pSquare
]
pExpr :: Parser Expr
pExpr = lexeme $ pLAbs <|> pApp <|> pPAbs
pAll :: String -> Either String Expr
pAll = first errorBundlePretty . parse (between skipSpace eof pExpr) ""
p :: String -> Expr
p = fromRight Star . pAll