|
{-# 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
|
|
|
|
|
|
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))
|
|
|
|
eof :: Parser ()
|
|
eof = Parser $ \state ->
|
|
case ptTs state of
|
|
[] -> Right ((), state)
|
|
(x:_) -> Left (Unexpected x)
|
|
|
|
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
|
|
|
|
parens :: Parser a -> Parser a
|
|
parens k = do
|
|
expect Tok_oparen
|
|
x <- k
|
|
expect Tok_cparen
|
|
pure x
|
|
|
|
square :: Parser a -> Parser a
|
|
square k = do
|
|
expect Tok_osquare
|
|
x <- k
|
|
expect Tok_csquare
|
|
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 Exp -> Parser Exp
|
|
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 (Span start end x)
|
|
|
|
body :: Parser Exp
|
|
body = attachPos letExpr <|> attachPos lamExpr <|> attachPos exprPi where
|
|
lamExpr = do
|
|
expect Tok_lambda
|
|
vs <- some arg
|
|
expect Tok_arrow
|
|
e <- body
|
|
pure (foldr Lam e vs)
|
|
|
|
letExpr = do
|
|
expect Tok_let
|
|
v <- T.unpack <$> var
|
|
expect Tok_colon
|
|
t <- body
|
|
expect Tok_equal
|
|
b <- body
|
|
expect Tok_in
|
|
Let v t b <$> body
|
|
|
|
arg = T.unpack <$> var
|
|
|
|
exprPi :: Parser Exp
|
|
exprPi = attachPos $
|
|
do
|
|
bs <- optionally binder
|
|
case bs of
|
|
Just k -> foldl (.) id k <$> attachPos exprPi
|
|
Nothing -> attachPos exprArr
|
|
where
|
|
binder = (some (parens bind) <* expect Tok_arrow)
|
|
<|> (fmap pure (parens sigma) <* expect Tok_times)
|
|
|
|
bind = do
|
|
names <- some (T.unpack <$> var)
|
|
expect Tok_colon
|
|
t <- exprPi
|
|
pure (foldr (\n k -> Pi n t . k) id names)
|
|
|
|
sigma = do
|
|
names <- some (T.unpack <$> var)
|
|
expect Tok_colon
|
|
t <- exprPi
|
|
pure (foldr (\n k -> Sigma n t . k) id names)
|
|
|
|
exprArr :: Parser Exp
|
|
exprArr = attachPos $ do
|
|
t <- attachPos exprConj
|
|
c <- optionally (fmap (const True) (expect Tok_arrow) <|> fmap (const False) (expect Tok_times))
|
|
case c of
|
|
Just True -> Pi "_" t <$> exprPi
|
|
Just False -> Sigma "_" t <$> exprPi
|
|
Nothing -> pure t
|
|
|
|
exprApp :: Parser Exp
|
|
exprApp = attachPos $
|
|
do
|
|
head <- atom
|
|
spine <- many spineEntry
|
|
pure (foldl app head spine)
|
|
where
|
|
spineEntry = atom
|
|
app f s = App f s
|
|
|
|
exprDisj :: Parser Exp
|
|
exprDisj = attachPos $
|
|
do
|
|
first <- exprApp
|
|
rest <- many disjunct
|
|
pure (foldl IOr first rest)
|
|
where
|
|
disjunct = expect Tok_or *> exprApp
|
|
|
|
exprConj :: Parser Exp
|
|
exprConj = attachPos $
|
|
do
|
|
first <- exprDisj
|
|
rest <- many conjunct
|
|
pure (foldl IAnd first rest)
|
|
where
|
|
conjunct = expect Tok_and *> exprDisj
|
|
|
|
atom0 :: Parser Exp
|
|
atom0 = attachPos $
|
|
fmap (Var . T.unpack) var
|
|
<|> fmap (const Type) (expect Tok_type)
|
|
<|> fmap (const I) (expect Tok_I)
|
|
<|> fmap (const I0) (expect Tok_I0)
|
|
<|> fmap (const I1) (expect Tok_I1)
|
|
<|> fmap (const Path) (expect Tok_path)
|
|
<|> fmap (const SubT) (expect Tok_sub)
|
|
<|> fmap (const PartialT) (expect Tok_phi)
|
|
<|> fmap (const Comp) (expect Tok_comp)
|
|
<|> fmap INot (expect Tok_not *> atom)
|
|
<|> parens pair
|
|
<|> square (Partial <$> (system <|> pure []))
|
|
|
|
atom :: Parser Exp
|
|
atom = attachPos $
|
|
do
|
|
e <- atom0
|
|
c <- many (selectToken (projection . tokClass))
|
|
pure $ case c of
|
|
[] -> e
|
|
sls -> foldl (flip ($)) e sls
|
|
where
|
|
projection Tok_p1 = pure Proj1
|
|
projection Tok_p2 = pure Proj2
|
|
projection _ = Nothing
|
|
|
|
|
|
system :: Parser [(Formula, Exp)]
|
|
system =
|
|
do
|
|
t <- comp
|
|
x <- optionally (expect Tok_comma)
|
|
case x of
|
|
Just () -> (t:) <$> system
|
|
Nothing -> pure [t]
|
|
where
|
|
comp = do
|
|
t <- formula
|
|
expect Tok_arrow
|
|
(t,) <$> body
|
|
|
|
pair :: Parser Exp
|
|
pair = do
|
|
t <- body
|
|
x <- optionally (expect Tok_comma)
|
|
case x of
|
|
Just () -> Pair t <$> pair
|
|
Nothing -> pure t
|
|
|
|
statement :: Parser Statement
|
|
statement = (assume <|> declare <|> (Eval <$> body)) <* eof where
|
|
assume = do
|
|
expect Tok_assume
|
|
Assume <$> vars
|
|
|
|
declare = do
|
|
expect Tok_let
|
|
x <- T.unpack <$> var
|
|
expect Tok_colon
|
|
ty <- body
|
|
expect Tok_equal
|
|
Declare x ty <$> body
|
|
|
|
bind = do
|
|
var <- some (T.unpack <$> var)
|
|
expect Tok_colon
|
|
body <- body
|
|
pure $ map ((, body)) var
|
|
|
|
vars = do
|
|
var <- bind
|
|
t <- optionally (expect Tok_comma)
|
|
case t of
|
|
Nothing -> pure var
|
|
Just x -> (var ++) <$> vars
|
|
|
|
formula :: Parser Formula
|
|
formula = conjunction where
|
|
conjunction, disjunction, atom :: Parser Formula
|
|
conjunction = do
|
|
d <- disjunction
|
|
t <- optionally (expect Tok_and)
|
|
case t of
|
|
Nothing -> pure d
|
|
Just x -> And d <$> conjunction
|
|
|
|
disjunction = do
|
|
d <- atom
|
|
t <- optionally (expect Tok_or)
|
|
case t of
|
|
Nothing -> pure d
|
|
Just x -> Or d <$> disjunction
|
|
|
|
atom = (Is1 . T.unpack) <$> var
|
|
<|> (Is0 . T.unpack) <$> (expect Tok_not *> var)
|
|
<|> Top <$ expect Tok_I1
|
|
<|> Bot <$ expect Tok_I0
|