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 "--")
|
2024-11-20 12:23:41 -08:00
|
|
|
(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}
|