|
{-# LANGUAGE TupleSections #-}
|
|
{-# LANGUAGE BlockArguments #-}
|
|
{-# LANGUAGE LambdaCase #-}
|
|
{-# LANGUAGE DerivingVia #-}
|
|
module Presyntax.Parser where
|
|
|
|
import Control.Applicative
|
|
import Control.Monad.State
|
|
|
|
import qualified Data.Text as T
|
|
import Data.Text (Text)
|
|
|
|
import Presyntax.Lexer
|
|
import Presyntax
|
|
|
|
import Syntax
|
|
|
|
|
|
data ParseError
|
|
= UnexpectedEof Int Int
|
|
| Unexpected Token
|
|
| Empty
|
|
| AltError ParseError ParseError
|
|
deriving (Show)
|
|
|
|
data ParseState
|
|
= ParseState { ptTs :: [Token]
|
|
, ptLine :: !Int
|
|
, ptCol :: !Int
|
|
}
|
|
|
|
newtype Parser a =
|
|
Parser { runParser :: ParseState -> Either ParseError (a, ParseState) }
|
|
deriving
|
|
( Functor
|
|
, Applicative
|
|
, Monad
|
|
, MonadState ParseState
|
|
)
|
|
via (StateT ParseState (Either ParseError))
|
|
|
|
parseString :: Parser a -> String -> Either (Either LexError ParseError) a
|
|
parseString (Parser k) s =
|
|
case lexString s of
|
|
Left e -> Left (Left e)
|
|
Right xs ->
|
|
case k (ParseState xs 0 0) of
|
|
Left e -> Left (pure e)
|
|
Right (x, _) -> Right x
|
|
|
|
selectToken :: (Token -> Maybe a) -> Parser a
|
|
selectToken k = Parser \case
|
|
ParseState [] l c -> Left (UnexpectedEof l c)
|
|
ParseState (x:xs) _ _ ->
|
|
case k x of
|
|
Just p -> pure (p, ParseState xs (tokLine x) (tokCol x))
|
|
Nothing -> Left (Unexpected x)
|
|
|
|
expect :: TokenClass -> Parser ()
|
|
expect t = selectToken (\x -> if tokClass x == t then Just () else Nothing)
|
|
|
|
var :: Parser Text
|
|
var = selectToken \case
|
|
Token _ _ _ _ (Tok_var v) -> pure v
|
|
_ -> Nothing
|
|
|
|
optionally :: Parser a -> Parser (Maybe a)
|
|
optionally p = fmap Just p <|> pure Nothing
|
|
|
|
braces :: Parser a -> Parser a
|
|
braces k = do
|
|
expect Tok_obrace
|
|
x <- k
|
|
expect Tok_cbrace
|
|
pure x
|
|
|
|
parens :: Parser a -> Parser a
|
|
parens k = do
|
|
expect Tok_oparen
|
|
x <- k
|
|
expect Tok_cparen
|
|
pure x
|
|
|
|
instance Alternative Parser where
|
|
empty = Parser \_ -> Left Empty
|
|
Parser kx <|> Parser ky = Parser \x ->
|
|
case kx x of
|
|
Right x -> Right x
|
|
Left e ->
|
|
case ky x of
|
|
Left _ -> Left e
|
|
Right y -> Right y
|
|
|
|
attachPos :: Parser RawExpr -> Parser RawExpr
|
|
attachPos k = do
|
|
start <- gets (\(ParseState ~(x:_) _ _) -> (tokLine x, tokCol x - (tokOff x - tokSOff x)))
|
|
x <- k
|
|
end <- gets (\(ParseState _ l c) -> (l, c))
|
|
pure (RSrcPos start end x)
|
|
|
|
body :: Parser RawExpr
|
|
body = attachPos letExpr <|> attachPos lamExpr <|> attachPos exprPi where
|
|
letExpr = do
|
|
expect Tok_let
|
|
n <- var
|
|
expect Tok_colon
|
|
t <- body
|
|
letSmol n t <|> letBig n t
|
|
|
|
letSmol n t = do
|
|
expect Tok_equal
|
|
d <- body
|
|
expect Tok_semi
|
|
Rlet n t d <$> body
|
|
|
|
letBig n t = do
|
|
expect Tok_semi
|
|
selectToken \case
|
|
Token _ _ _ _ (Tok_var n') | n' == n -> Just ()
|
|
_ -> Nothing
|
|
args <- many arg
|
|
expect Tok_equal
|
|
d <- body
|
|
expect Tok_semi
|
|
Rlet n t (foldr lam d args) <$> body
|
|
|
|
lamExpr = do
|
|
expect Tok_lambda
|
|
vs <- some arg
|
|
expect Tok_arrow
|
|
e <- body
|
|
pure (foldr lam e vs)
|
|
|
|
arg = fmap (Ex,) var <|> fmap (Im,) (braces var)
|
|
|
|
lam (p, v) b = Rlam p v b
|
|
|
|
exprPi :: Parser RawExpr
|
|
exprPi = attachPos $
|
|
do
|
|
bs <- optionally binder
|
|
case bs of
|
|
Just k -> foldl (.) id k <$> attachPos exprPi
|
|
Nothing -> attachPos exprArr
|
|
where
|
|
binder = (some (parens (bind Ex) <|> braces (bind Im)) <* expect Tok_arrow)
|
|
<|> (fmap pure (parens sigma) <* expect Tok_times)
|
|
|
|
bind p = do
|
|
names <- some var
|
|
expect Tok_colon
|
|
t <- exprPi
|
|
pure (foldr (\n k -> Rpi p n t . k) id names)
|
|
|
|
sigma = do
|
|
n <- var
|
|
expect Tok_colon
|
|
Rsigma n <$> exprPi
|
|
|
|
exprArr :: Parser RawExpr
|
|
exprArr = attachPos $ do
|
|
t <- attachPos exprApp
|
|
c <- optionally (fmap (const True) (expect Tok_arrow) <|> fmap (const False) (expect Tok_times))
|
|
case c of
|
|
Just True -> Rpi Ex (T.singleton '_') t <$> exprPi
|
|
Just False -> Rsigma (T.singleton '_') t <$> exprPi
|
|
Nothing -> pure t
|
|
|
|
exprEq0 :: Parser RawExpr
|
|
exprEq0 = attachPos $
|
|
do
|
|
head <- atom
|
|
spine <- many spineEntry
|
|
pure (foldl app head spine)
|
|
where
|
|
spineEntry = fmap (Ex,) atom <|> fmap (Im,) (braces exprPi)
|
|
app f (x, s) = Rapp x f s
|
|
|
|
exprApp :: Parser RawExpr
|
|
exprApp = attachPos $ do
|
|
t <- exprEq0
|
|
c <- optionally (expect Tok_equiv)
|
|
case c of
|
|
Just () -> Req t <$> exprEq0
|
|
Nothing -> pure t
|
|
|
|
atom0 :: Parser RawExpr
|
|
atom0 = attachPos $
|
|
fmap Rvar var
|
|
<|> fmap (const Rtype) (expect Tok_type)
|
|
<|> fmap (const Rhole) (expect Tok_under)
|
|
<|> fmap (const Rtop) (expect Tok_top)
|
|
<|> fmap (const Rrefl) (expect Tok_refl)
|
|
<|> fmap (const Rcoe) (expect Tok_coe)
|
|
<|> fmap (const Rcong) (expect Tok_cong)
|
|
<|> fmap (const Rsym) (expect Tok_sym)
|
|
<|> fmap (const Runit) (parens (pure ()))
|
|
<|> parens pair
|
|
|
|
pair :: Parser RawExpr
|
|
pair = attachPos $ do
|
|
t <- body
|
|
c <- optionally (expect Tok_comma)
|
|
case c of
|
|
Just () -> Rpair t <$> pair
|
|
Nothing -> pure t
|
|
|
|
atom :: Parser RawExpr
|
|
atom = attachPos $
|
|
do
|
|
e <- atom0
|
|
c <- many (selectToken (projection . tokClass))
|
|
pure $ case c of
|
|
[] -> e
|
|
sls -> foldl (flip ($)) e sls
|
|
where
|
|
projection Tok_proj1 = pure Rproj1
|
|
projection Tok_proj2 = pure Rproj2
|
|
projection _ = Nothing
|