Prototype, extremely bad code implementation of CCHM Cubical Type Theory
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

284 lines
6.5 KiB

{-# 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