perga/lib/Parser.hs

143 lines
3.9 KiB
Haskell
Raw Normal View History

2024-11-17 01:57:53 -08:00
{-# LANGUAGE NamedFieldPuns #-}
2024-11-14 19:56:33 -08:00
module Parser (pAll) 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
import Control.Monad.State.Strict
2024-11-11 16:38:46 -08:00
import Data.Bifunctor (first)
2024-10-05 16:04:13 -07:00
import Data.Functor.Identity
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 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 01:57:53 -08:00
data InnerState = IS {_binds :: [Text], _defs :: Env}
newtype TypeError = TE TypeCheckError
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
showErrorComponent (TE e) = show e
2024-10-05 13:31:09 -07:00
2024-11-17 01:57:53 -08:00
bindsToIS :: ([Text] -> [Text]) -> InnerState -> InnerState
bindsToIS f x@(IS{_binds}) = x{_binds = f _binds}
2024-10-05 16:04:13 -07:00
2024-11-17 01:57:53 -08:00
defsToIS :: (Env -> Env) -> InnerState -> InnerState
defsToIS f x@(IS{_defs}) = x{_defs = f _defs}
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 01:57:53 -08:00
binders <- _binds <$> get
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-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
_ <- defChoice $ ":" :| []
ty <- pExpr
2024-11-17 01:57:53 -08:00
modify $ bindsToIS $ 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-14 22:02:04 -08:00
pParams :: Parser [(Text, Expr)]
2024-11-11 16:38:46 -08:00
pParams = concat <$> some pParamGroup
2024-10-05 13:31:09 -07:00
pLAbs :: Parser Expr
pLAbs = lexeme $ label "λ-abstraction" $ do
2024-11-11 16:38:46 -08:00
_ <- defChoice $ "λ" :| ["lambda", "fun"]
params <- pParams
_ <- defChoice $ "." :| ["=>", ""]
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-11 16:38:46 -08:00
_ <- defChoice $ "" :| ["Pi", "forall", ""]
params <- pParams
_ <- defChoice $ "." :| [","]
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
pApp = foldl1 App <$> some pTerm
pStar :: Parser Expr
2024-10-05 16:04:13 -07:00
pStar = Star <$ defChoice ("*" :| [])
2024-10-05 13:31:09 -07:00
pSquare :: Parser Expr
2024-10-05 16:04:13 -07:00
pSquare = Square <$ defChoice ("" :| ["[]"])
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
, pVar
, pStar
, pSquare
]
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 01:57:53 -08:00
pDef :: Parser ()
pDef = lexeme $ label "definition" $ do
ident <- pIdentifier
_ <- defChoice $ ":=" :| []
value <- pExpr
_ <- defChoice $ ";" :| []
foo <- get
let ty = checkType (_defs foo) [] value
case ty of
Left err -> customFailure $ TE err
Right _ -> modify $ defsToIS $ M.insert ident value
pProgram :: Parser ()
pProgram = void $ many pDef
pAll :: Text -> Either String ()
pAll input = first errorBundlePretty $ fst $ runIdentity $ runStateT (runParserT pProgram "" input) $ IS{_binds = [], _defs = M.empty}