perga/lib/Parser.hs

208 lines
6.4 KiB
Haskell
Raw Normal View History

2024-11-17 01:57:53 -08:00
{-# LANGUAGE NamedFieldPuns #-}
2024-11-20 07:37:49 -08:00
module Parser (parseProgram, parseDef, parseDefEmpty, parseExpr) where
2024-10-05 13:31:09 -07:00
2024-11-17 01:57:53 -08:00
import Check
2024-10-05 16:04:13 -07:00
import Control.Monad
2024-11-17 18:33:14 -08:00
import Control.Monad.State.Strict (
MonadState (get, put),
State,
evalState,
modify,
runState,
)
2024-11-11 16:38:46 -08:00
import Data.Bifunctor (first)
2024-10-05 16:04:13 -07:00
import Data.List (elemIndex)
2024-11-11 16:38:46 -08:00
import Data.List.NonEmpty (NonEmpty ((:|)))
2024-10-05 16:04:13 -07:00
import qualified Data.List.NonEmpty as NE
2024-11-17 01:57:53 -08:00
import qualified Data.Map as M
2024-11-14 22:02:04 -08:00
import Data.Text (Text)
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)
2024-10-05 16:04:13 -07:00
import Text.Megaparsec hiding (State)
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-17 18:33:14 -08:00
data TypeDef = TD {_ident :: Text, _type :: Expr}
2024-11-20 07:37:49 -08:00
data DefinitionLine = DL {_td :: TypeDef, _body :: Expr} | PN TypeDef
2024-11-17 01:57:53 -08:00
2024-11-20 07:37:49 -08:00
data InnerState = IS {_binds :: [TypeDef], _env :: Env}
2024-11-17 18:33:14 -08:00
newtype TypeError = TE Error
2024-11-17 01:57:53 -08:00
deriving (Eq, Ord, Show)
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-17 18:33:14 -08:00
showErrorComponent (TE e) = show e
2024-10-05 13:31:09 -07:00
2024-11-17 18:33:14 -08:00
bindsToIS :: ([TypeDef] -> [TypeDef]) -> InnerState -> InnerState
2024-11-17 01:57:53 -08:00
bindsToIS f x@(IS{_binds}) = x{_binds = f _binds}
2024-10-05 16:04:13 -07:00
2024-11-20 07:37:49 -08:00
modifyEnv :: (Env -> Env) -> InnerState -> InnerState
modifyEnv f x@(IS{_env}) = x{_env = f _env}
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-14 22:02:04 -08:00
pIdentifier :: Parser Text
2024-10-05 16:04:13 -07:00
pIdentifier = label "identifier" $ lexeme $ do
2024-11-11 16:38:46 -08:00
firstChar <- letterChar <|> char '_'
rest <- many $ alphaNumChar <|> char '_'
2024-11-17 01:57:53 -08:00
return $ T.pack (firstChar : rest)
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-11 16:38:46 -08:00
var <- pIdentifier
2024-11-17 18:33:14 -08:00
binders <- map _ident . _binds <$> get
2024-11-17 01:57:53 -08:00
pure $ case elemIndex var binders of
Just i -> Var (fromIntegral i) var
Nothing -> Free var
2024-10-05 13:31:09 -07:00
2024-11-20 07:37:49 -08:00
pPN :: Parser ()
2024-11-20 12:44:21 -08:00
pPN = label "primitive notion" $ lexeme $ defChoice $ pure "axiom"
2024-11-20 07:37:49 -08:00
2024-11-14 22:02:04 -08:00
defChoice :: NE.NonEmpty Text -> Parser ()
defChoice options = lexeme $ label (T.unpack $ NE.head options) $ void $ choice $ NE.map 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-17 18:33:14 -08:00
_ <- defChoice $ pure ":"
2024-11-11 16:38:46 -08:00
ty <- pExpr
2024-11-17 18:33:14 -08:00
modify $ bindsToIS $ flip (foldl $ flip (:)) (map (\idt -> TD{_ident = idt, _type = ty}) 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
pLAbs :: Parser Expr
pLAbs = lexeme $ label "λ-abstraction" $ 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
2024-11-17 01:57:53 -08:00
modify $ bindsToIS $ drop $ length params
2024-11-11 16:38:46 -08:00
pure $ foldr (uncurry Abs) body params
2024-10-05 13:31:09 -07:00
pPAbs :: Parser Expr
pPAbs = lexeme $ label "Π-abstraction" $ do
2024-11-20 12:44:21 -08:00
_ <- defChoice $ "" :| ["forall", ""]
2024-11-17 18:33:14 -08:00
params <- pSomeParams
2024-11-20 12:44:21 -08:00
_ <- defChoice $ pure ","
2024-11-11 16:38:46 -08:00
body <- pExpr
2024-11-17 01:57:53 -08:00
modify $ bindsToIS $ drop $ length params
2024-11-11 16:38:46 -08:00
pure $ foldr (uncurry Pi) body params
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
2024-11-17 18:33:14 -08:00
pStar = lexeme $ Star <$ defChoice (pure "*")
2024-10-05 13:31:09 -07:00
pSquare :: Parser Expr
2024-11-17 18:33:14 -08:00
pSquare = lexeme $ Square <$ defChoice ("" :| ["[]"])
checkAscription :: Text -> Expr -> Maybe Expr -> Parser DefinitionLine
checkAscription ident value massert = do
2024-11-20 07:37:49 -08:00
IS{_env} <- get
case (checkType _env value, massert) of
2024-11-17 18:33:14 -08:00
(Left err, _) -> customFailure $ TE err
(Right ty, Nothing) -> pure DL{_td = TD{_ident = ident, _type = ty}, _body = value}
2024-11-20 07:37:49 -08:00
(Right ty, Just assert) -> case checkBeta _env ty assert of
2024-11-17 18:33:14 -08:00
Left err -> customFailure $ TE err
Right equiv -> do
unless equiv $ customFailure $ TE $ NotEquivalent ty assert value
pure DL{_td = TD{_ident = ident, _type = assert}, _body = value}
updateStateDefinition :: DefinitionLine -> Parser ()
updateStateDefinition DL{_td, _body} = do
2024-11-20 07:37:49 -08:00
modify $
modifyEnv
(M.insert (_ident _td) EL{_ty = _type _td, _val = _body})
updateStateDefinition (PN TD{_type, _ident}) = do
modify $
modifyEnv
(M.insert _ident EL{_ty = _type, _val = Axiom _ident})
2024-11-17 18:33:14 -08:00
pDef :: Parser DefinitionLine
pDef = lexeme $ label "definition" $ do
skipSpace
ident <- pIdentifier
params <- pManyParams
ascription <- fmap (flip (foldr (uncurry Pi)) params) <$> pAscription
_ <- defChoice $ pure ":="
2024-11-20 07:37:49 -08:00
choice
[ do
_ <- pPN
_ <- defChoice $ pure ";"
case ascription of
Just ty -> pure $ PN TD{_ident = ident, _type = ty}
Nothing -> customFailure $ TE $ PNMissingType ident
, do
value <- flip (foldr (uncurry Abs)) params <$> pExpr
res <- checkAscription ident value ascription
_ <- defChoice $ pure ";"
pure res
]
2024-11-17 18:33:14 -08:00
pDefUpdate :: Parser ()
pDefUpdate = pDef >>= updateStateDefinition
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
, pStar
, pSquare
2024-11-17 18:33:14 -08:00
, pVar
2024-11-11 16:38:46 -08:00
]
pAppTerm :: Parser Expr
pAppTerm = lexeme $ pLAbs <|> pPAbs <|> 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-20 07:37:49 -08:00
pProgram = lexeme $ skipSpace >> many pDefUpdate >> _env <$> get
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-20 07:37:49 -08:00
let (output, IS{_env}) = runState (runParserT pDefUpdate "" input) (IS{_binds = [], _env = env})
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
parseExpr env input = first errorBundlePretty $ evalState (runParserT pExpr "" input) IS{_binds = [], _env = 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 :: Text -> Either String Env
2024-11-20 07:37:49 -08:00
parseProgram input = first errorBundlePretty $ evalState (runParserT pProgram "" input) IS{_binds = [], _env = M.empty}