perga/lib/Parser.hs

242 lines
7 KiB
Haskell
Raw Normal View History

2024-11-17 01:57:53 -08:00
{-# LANGUAGE NamedFieldPuns #-}
module Parser (parseDef, parseDefEmpty, parseExpr, parseProgram, handleFile) where
2024-10-05 13:31:09 -07:00
2024-11-17 01:57:53 -08:00
import Check
import Control.Monad.Except
2024-11-22 19:44:31 -08:00
import Data.List (elemIndex, foldl, foldl1)
import qualified Data.Map.Strict as M
2024-11-14 22:02:04 -08:00
import qualified Data.Text as T
2024-11-17 18:33:14 -08:00
import Errors (Error (..))
2024-11-17 01:57:53 -08:00
import Eval
2024-11-14 19:56:33 -08:00
import Expr (Expr (..), incIndices)
import Preprocessor
2024-11-22 19:44:31 -08:00
import Relude.Extra.Lens
import Text.Megaparsec (ParsecT, ShowErrorComponent (..), between, choice, chunk, customFailure, errorBundlePretty, label, runParserT, try)
2024-10-05 13:31:09 -07:00
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
2024-10-05 16:04:13 -07:00
2024-11-22 19:44:31 -08:00
data InnerState = IS {_binders :: [Text], _env :: Env}
2024-11-17 01:57:53 -08:00
2024-11-22 19:44:31 -08:00
bindsL :: Lens' InnerState [Text]
bindsL = lens _binders setter
where
setter (IS{_env}) new = IS{_env, _binders = new}
envL :: Lens' InnerState Env
envL = lens _env setter
where
setter (IS{_binders}) new = IS{_env = new, _binders}
2024-11-17 18:33:14 -08:00
newtype TypeError = TE Error
2024-11-22 19:44:31 -08:00
deriving (Eq, Ord)
2024-11-17 01:57:53 -08:00
type Parser = ParsecT TypeError Text (State InnerState)
2024-10-05 16:04:13 -07:00
2024-11-17 01:57:53 -08:00
instance ShowErrorComponent TypeError where
2024-11-22 19:44:31 -08:00
showErrorComponent (TE e) = toString e
2024-10-05 13:31:09 -07:00
skipSpace :: Parser ()
skipSpace =
2024-11-11 16:38:46 -08:00
L.space
space1
(L.skipLineComment "--")
(L.skipBlockCommentNested "[*" "*]")
2024-10-05 13:31:09 -07:00
lexeme :: Parser a -> Parser a
lexeme = L.lexeme skipSpace
2024-11-22 19:44:31 -08:00
eat :: Text -> Parser ()
eat = void . lexeme . chunk
2024-11-23 09:16:32 -08:00
keywords :: [Text]
keywords = ["forall", "let", "in", "end", "fun"]
2024-11-14 22:02:04 -08:00
pIdentifier :: Parser Text
2024-11-23 09:16:32 -08:00
pIdentifier = try $ label "identifier" $ lexeme $ do
2024-11-11 16:38:46 -08:00
firstChar <- letterChar <|> char '_'
rest <- many $ alphaNumChar <|> char '_'
2024-11-23 09:16:32 -08:00
let ident = T.pack (firstChar : rest)
when (ident `elem` keywords) $
fail $
"Reserved word: " ++ T.unpack ident
pure ident
2024-10-05 13:31:09 -07:00
2024-10-05 16:04:13 -07:00
pVar :: Parser Expr
pVar = label "variable" $ lexeme $ do
2024-11-22 19:44:31 -08:00
name <- pIdentifier
binders <- view bindsL <$> get
pure (Var name . fromIntegral <$> elemIndex name binders ?: Free name)
2024-10-05 13:31:09 -07:00
2024-11-22 19:44:31 -08:00
defChoice :: NonEmpty Text -> Parser ()
defChoice options = lexeme $ label (T.unpack $ head options) $ void $ choice $ fmap chunk options
2024-11-11 16:38:46 -08:00
2024-11-14 22:02:04 -08:00
pParamGroup :: Parser [(Text, Expr)]
2024-11-11 16:38:46 -08:00
pParamGroup = lexeme $ label "parameter group" $ between (char '(') (char ')') $ do
idents <- some pIdentifier
2024-11-22 19:44:31 -08:00
eat ":"
2024-11-11 16:38:46 -08:00
ty <- pExpr
2024-11-22 19:44:31 -08:00
modify $ over bindsL $ flip (foldl $ flip (:)) idents
2024-11-11 20:08:21 -08:00
pure $ zip idents (iterate incIndices ty)
2024-11-11 16:38:46 -08:00
2024-11-17 18:33:14 -08:00
pSomeParams :: Parser [(Text, Expr)]
pSomeParams = lexeme $ concat <$> some pParamGroup
pManyParams :: Parser [(Text, Expr)]
pManyParams = lexeme $ concat <$> many pParamGroup
2024-10-05 13:31:09 -07:00
2024-11-22 19:44:31 -08:00
withBinders :: Parser a -> Parser a
withBinders parser = do
oldBinders <- view bindsL <$> get
result <- parser
modify $ set bindsL oldBinders
pure result
2024-10-05 13:31:09 -07:00
pLAbs :: Parser Expr
2024-11-22 19:44:31 -08:00
pLAbs = lexeme $ label "λ-abstraction" $ withBinders $ do
2024-11-20 12:44:21 -08:00
_ <- defChoice $ "λ" :| ["fun"]
2024-11-17 18:33:14 -08:00
params <- pSomeParams
2024-11-20 12:44:21 -08:00
_ <- defChoice $ "=>" :| [""]
2024-11-11 16:38:46 -08:00
body <- pExpr
pure $ foldr (uncurry Abs) body params
2024-10-05 13:31:09 -07:00
pPAbs :: Parser Expr
2024-11-22 19:44:31 -08:00
pPAbs = lexeme $ label "Π-abstraction" $ withBinders $ do
2024-11-20 12:44:21 -08:00
_ <- defChoice $ "" :| ["forall", ""]
2024-11-17 18:33:14 -08:00
params <- pSomeParams
eat ","
2024-11-11 16:38:46 -08:00
body <- pExpr
pure $ foldr (uncurry Pi) body params
2024-11-23 09:16:32 -08:00
pBinding :: Parser (Text, Expr)
pBinding = lexeme $ label "binding" $ do
env <- get
2024-11-23 09:16:32 -08:00
eat "("
ident <- pIdentifier
params <- pManyParams
2024-11-23 09:16:32 -08:00
eat ":="
value <- pExpr
eat ")"
put env
2024-11-23 09:16:32 -08:00
modify $ over bindsL (ident :)
pure (ident, foldr (uncurry Abs) value params)
2024-11-23 09:16:32 -08:00
pLet :: Parser Expr
pLet = lexeme $ label "let expression" $ withBinders $ do
eat "let"
bindings <- some pBinding
eat "in"
body <- try pExpr
eat "end"
pure $ foldr (uncurry Let) body bindings
2024-11-11 16:38:46 -08:00
pArrow :: Parser Expr
pArrow = lexeme $ label "->" $ do
a <- pAppTerm
_ <- defChoice $ "->" :| [""]
2024-11-14 19:56:33 -08:00
Pi "" a . incIndices <$> pExpr
2024-10-05 13:31:09 -07:00
pApp :: Parser Expr
2024-11-17 18:33:14 -08:00
pApp = lexeme $ foldl1 App <$> some pTerm
2024-10-05 13:31:09 -07:00
pStar :: Parser Expr
pStar = lexeme $ Level 0 <$ eat "*"
2024-10-05 13:31:09 -07:00
pNumSort :: Parser Expr
pNumSort = lexeme $ label "sort" $ eat "*" >> Level <$> L.decimal
pSort :: Parser Expr
pSort = try pNumSort <|> pStar
2024-11-17 18:33:14 -08:00
2024-11-22 19:44:31 -08:00
checkAscription :: Text -> Expr -> Maybe Expr -> Parser ()
2024-11-17 18:33:14 -08:00
checkAscription ident value massert = do
env <- get
2024-11-22 19:44:31 -08:00
ty <- either (customFailure . TE) pure (checkType (env ^. envL) value)
case massert of
Nothing -> updateStateDefinition ident ty value
Just assert -> do
equiv <- either (customFailure . TE) pure (checkBeta (env ^. envL) ty assert)
unless equiv $ customFailure $ TE $ NotEquivalent ty assert value
updateStateDefinition ident assert value
updateStateDefinition :: Text -> Expr -> Expr -> Parser ()
updateStateDefinition ident ty value = do
env <- get
2024-11-22 19:44:31 -08:00
when (M.member ident (env ^. envL)) (customFailure $ TE $ DuplicateDefinition ident)
modify $ over envL $ M.insert ident $ makeDef ty value
pAxiom :: Text -> Maybe Expr -> Parser ()
pAxiom ident Nothing = customFailure $ TE $ PNMissingType ident
pAxiom ident (Just ascription) = do
eat "axiom"
eat ";"
updateStateDefinition ident ascription (Axiom ident)
pBody :: [(Text, Expr)] -> Text -> Maybe Expr -> Parser ()
pBody params ident ascription = do
value <- flip (foldr (uncurry Abs)) params <$> pExpr
checkAscription ident value ascription
eat ";"
pDef :: Parser ()
2024-11-17 18:33:14 -08:00
pDef = lexeme $ label "definition" $ do
skipSpace
ident <- pIdentifier
params <- pManyParams
ascription <- fmap (flip (foldr (uncurry Pi)) params) <$> pAscription
2024-11-22 19:44:31 -08:00
eat ":="
choice [pAxiom ident ascription, pBody params ident ascription]
2024-10-05 13:31:09 -07:00
pTerm :: Parser Expr
pTerm =
2024-11-11 16:38:46 -08:00
lexeme $
label "term" $
choice
[ between (char '(') (char ')') pExpr
, pSort
2024-11-17 18:33:14 -08:00
, pVar
2024-11-11 16:38:46 -08:00
]
pAppTerm :: Parser Expr
2024-11-23 09:16:32 -08:00
pAppTerm =
lexeme $
choice
[ pLAbs
, pPAbs
, pLet
, pApp
]
2024-10-05 13:31:09 -07:00
pExpr :: Parser Expr
2024-11-11 16:38:46 -08:00
pExpr = lexeme $ try pArrow <|> pAppTerm
2024-10-05 13:31:09 -07:00
2024-11-17 18:33:14 -08:00
pAscription :: Parser (Maybe Expr)
pAscription = lexeme $ optional $ try $ defChoice (pure ":") >> label "type" pExpr
pProgram :: Parser Env
2024-11-22 19:44:31 -08:00
pProgram = lexeme $ skipSpace >> many pDef >> _env <$> get
emptyBinders :: Env -> InnerState
emptyBinders env = IS{_binders = [], _env = env}
2024-11-17 18:33:14 -08:00
2024-11-20 07:37:49 -08:00
parseDef :: Text -> State Env (Either String ())
2024-11-17 18:33:14 -08:00
parseDef input = do
env <- get
2024-11-22 19:44:31 -08:00
let (output, IS{_env}) = runState (runParserT pDef "" input) (emptyBinders env)
2024-11-20 07:37:49 -08:00
put _env
2024-11-17 18:33:14 -08:00
pure $ first errorBundlePretty output
2024-11-20 07:37:49 -08:00
parseExpr :: Env -> Text -> Either String Expr
2024-11-22 19:44:31 -08:00
parseExpr env input = first errorBundlePretty $ evalState (runParserT pExpr "" input) $ emptyBinders env
2024-11-18 14:33:21 -08:00
2024-11-20 07:37:49 -08:00
parseDefEmpty :: Env -> Text -> (Either String (), Env)
2024-11-17 18:33:14 -08:00
parseDefEmpty env input = runState (parseDef input) env
parseProgram :: Env -> Text -> Either String Env
2024-11-22 19:44:31 -08:00
parseProgram initial input = first errorBundlePretty $ evalState (runParserT pProgram "" input) $ emptyBinders initial
handleFile :: Env -> String -> ExceptT String IO Env
handleFile initial filename = do
2024-11-22 19:44:31 -08:00
text <- toString `withExceptT` preprocess filename
liftEither $ parseProgram initial text