mprover-0.0.0.0: MProver/Parser.hs
module MProver.Parser where
import MProver.Syntax
import Text.Parsec hiding (parse)
import Text.Parsec.Pos
import Text.Parsec.Expr
import Text.Parsec.Language
import qualified Text.Parsec.Token as T
import Control.Monad
import Data.Char
import Data.Ratio
import Data.Either
import Unbound.LocallyNameless hiding (Infix,Fixity,fixity)
lexer = T.makeTokenParser (haskellDef {
T.reservedNames = ["Forall","Foralli","Assume","Assuming","eval","subst","trans","symm","proving","by"] ++ T.reservedNames haskellDef,
T.reservedOpNames = [":::","_|_"] ++ T.reservedOpNames haskellDef})
symbol = T.symbol lexer
reserved = T.reserved lexer
reservedOp = T.reservedOp lexer
identifier = try $ do
i <- T.identifier lexer
if isLower (head i)
then return i
else fail "expecting identifier"
ctor = try $ do
i <- T.identifier lexer
if isUpper (head i)
then return i
else fail "expecting constructor"
lparen = symbol "("
rparen = symbol ")"
lcurly = symbol "{"
rcurly = symbol "}"
parens = T.parens lexer
braces = T.braces lexer
brackets = T.brackets lexer
comma = T.comma lexer
operator = T.operator lexer
semi = T.semi lexer
natural = T.natural lexer
float = T.float lexer
stringLiteral = T.stringLiteral lexer
charLiteral = T.charLiteral lexer
-- Parser state is a bool indicating whether we are parsing in a context where
-- bottom is okay in expressions/patterns; and a list of fixity declarations
-- currently in scope.
type UserState = (Bool,[FixityDecl])
withBotok b m = do
(botok,fixitydecls) <- getState
putState (b,fixitydecls)
r <- m
(_,fixitydecls) <- getState
putState (botok,fixitydecls)
return r
program = do
fixitydecls <- lookAhead getFixityDecls
(botok,_) <- getState
putState (botok,fixitydecls)
p <- program'
eof
return p
getFixityDecls = do
optionMaybe (reserved "module" >> ctor >> reserved "where")
liftM rights (braces (topdecl `sepBy` semi))
program' = do
reserved "module"
modname <- ctor
reserved "where"
topdecls <- liftM lefts (braces (topdecl `sepBy` semi))
return $ Program modname (trec topdecls)
<|> do
topdecls <- liftM lefts (braces (topdecl `sepBy` semi))
return $ Program "Main" (trec topdecls)
<?> "program"
topdecl = liftM Left typedecl
<|> liftM Left datadecl
<|> liftM Left (try defn)
<|> liftM Left proofdecl
<|> liftM Right fixitydecl
<?> "top-level declaration"
typedecl = do
reserved "type"
typename <- ctor
vars <- many identifier
reservedOp "="
t <- ty
return $ TypeDecl typename (embed $ bind (map string2Name vars) t)
<?> "type declaration"
datadecl = do
reserved "data"
typename <- ctor
tyvars <- many identifier
reservedOp "="
constrs <- constrdecl `sepBy1` reservedOp "|"
return $ DataDecl typename (embed $ bind (map string2Name tyvars) constrs)
<?> "datatype declaration"
constrdecl = do
constrname <- ctor
tys <- many aty
return $ ConstrDecl constrname tys
<?> "constructor declaration"
defn = do
(x,t) <- try tysig
semi
e <- eqnnamed x
return (ExprDecl (Just (embed t)) (string2Name x) (embed e))
<|> do
(x,e) <- eqn
return $ (ExprDecl Nothing (string2Name x) (embed e))
<?> "expression definition"
tysig = do
x <- identifier
reservedOp "::"
t <- ty
return $ (x,t)
<|> do
op <- parens operator
reservedOp "::"
t <- ty
return $ (op,t)
<?> "type signature declaration"
eqn = do
x <- identifier
reservedOp "="
e <- expr
return (x,e)
<?> "function binding pattern"
eqnnamed n = do
symbol n
reservedOp "="
e <- expr
return e
<?> "function binding pattern for a function named " ++ n
data Fixity = InfixL | InfixR | InfixNone deriving (Eq,Show)
data FixityDecl = FixityDecl Fixity (Maybe Integer) [Identifier]
fixity = (reserved "infixl" >> return InfixL)
<|> (reserved "infixr" >> return InfixR)
<|> (reserved "infix" >> return InfixNone)
<?> "fixity"
fixitydecl = do
f <- fixity
p <- optionMaybe natural
ops <- many operator
return $ FixityDecl f p ops
<?> "fixity declaration"
ty = do
btys <- bty `sepBy1` (reservedOp "->")
return (foldr1 TyArrow btys)
<?> "type"
bty = do
atys <- many1 aty
return (foldl1 TyApp atys)
<?> "type application"
aty = liftM (TyVar . string2Name) identifier
<|> liftM TyCon ctor
<|> do
parens (do
tys <- ty `sepBy` comma
case tys of
[] -> return (TyCon "()")
[t] -> return t
_ -> return $ foldl TyApp (TyCon $ "(" ++ replicate (length tys - 1) ',' ++ ")") tys
)
<?> "atomic type"
pat = do
(botok,_) <- getState
(if botok
then (reservedOp "_|_" >> return PatBottom) <|> pat'
else pat') <?> "pattern"
pat' = do
v <- identifier
return (PatVar (string2Name v))
<|> do
c <- ctor
return (PatCtor c)
<|> do
l <- literal
return (PatLiteral l)
<|> do
reserved "_"
return PatWildcard
<|> try (do
parens (do
c <- ctor
ps <- many1 pat
return (PatApp c ps)
))
<|> do
parens (do
pats <- pat `sepBy` comma
case pats of
[] -> return (PatCtor "()")
[p] -> return p
_ -> return (PatApp ("(" ++ replicate (length pats - 1) ',' ++ ")") pats)
)
lamexpr = do
reservedOp "\\"
boundvar <- identifier
reservedOp "->"
body <- expr
return $ Lambda (bind (string2Name boundvar) body)
<?> "lambda expression"
letexpr = do
reserved "let"
lbs <- braces (lb `sepBy1` semi)
reserved "in"
body <- expr
return $ Let (bind (rec lbs) body)
<?> "let-expression"
lb = do
x <- identifier
reservedOp "="
e <- expr
return (string2Name x,embed e)
nontopdecl = defn
caseexpr = do
reserved "case"
scrut <- expr
reserved "of"
alts <- braces (alt `sepBy` semi)
return (Case scrut alts)
<?> "case expression"
literal = liftM LitInteger natural
<|> liftM LitFrac float
<|> liftM LitChar charLiteral
<?> "literal"
alt = do
p <- pat
reservedOp "->"
e <- expr
return (bind p e)
term = do
(botok,_) <- getState
(if botok
then (term' <|> (reservedOp "_|_" >> return Bottom))
else term') <?> "expression term"
term' = lamexpr
<|> try (liftM Literal literal)
<|> letexpr
<|> caseexpr
<|> liftM (Var . string2Name) identifier
<|> liftM Ctor ctor
<|> (try $ parens (return ()) >> return (Ctor "()"))
<|> (try $ parens expr)
<|> (parens $ expr `sepBy1` comma >>= \ es -> return $ foldl App (Ctor $ "(" ++ replicate (length es - 1) ',' ++ ")") es)
mkOperatorTable = do
(_,fixitydecls) <- getState
let fromFixity InfixL = AssocLeft
fromFixity InfixR = AssocRight
fromFixity InfixNone = AssocNone
fromPrec (Just x) = x
fromPrec Nothing = 9
mkCols (FixityDecl fx prec ids) =
map (\ i ->
Infix (do { symbol i
; return (\ e1 e2 -> (App (App (Var $ string2Name i) e1) e2)) })
(fromFixity fx))
ids
getPrec (FixityDecl _ prec _) = fromPrec prec
getOpers (FixityDecl _ _ os) = os
mkRow n = concat [mkCols fd | fd <- fixitydecls, getPrec fd == n]
allBound = concatMap getOpers fixitydecls
approw = [Infix (do { return (\ e1 e2 -> (App e1 e2)) }) AssocLeft]
row9 = [Infix (try $ do { oper <- operator ; if oper `elem` allBound then fail "<<shouldn't see this>>" else return (\ e1 e2 -> (App (App (Var $ string2Name oper) e1) e2)) }) AssocLeft] ++ mkRow 9
otherRows = map mkRow [8,7,6,5,4,3,2,1,0]
return (approw:row9:otherRows)
expr = do
table <- mkOperatorTable
buildExpressionParser table term <?> "expression"
proofdecl = do
(x,fo) <- try proofsig
semi
pr <- proofnamed x
return (ProofDecl (embed fo) (string2Name x) (embed pr))
proofsig = do
x <- identifier
reservedOp ":::"
fo <- formula
return $ (x,fo)
proofnamed x = do
symbol x
reservedOp "="
p <- proof
return p
<?> "proof named " ++ x
data ProofTerm = PTProof Proof | PTExpr Expr | PTCtor String
proofterm = do
reserved "Foralli"
lparen
x <- identifier
reservedOp "::"
t <- ty
rparen
comma
pr <- proof
return (PTProof $ ForallIExpr t (bind (string2Name x) pr))
<|> do
reserved "Assume"
lparen
x <- identifier
reservedOp ":::"
fo <- formula
rparen
comma
pr <- proof
return (PTProof $ ProofImpl fo (bind (string2Name x) pr))
<|> (liftM PTProof $ caseproof)
<|> (reserved "eval" >> return (PTProof Eval))
<|> do
reserved "trans"
(PTProof p1) <- proofterm
(PTProof p2) <- proofterm
return (PTProof $ Trans p1 p2)
<|> do
reserved "subst"
x <- identifier
reserved "by"
p <- proof
reserved "in"
e <- withBotok True expr
return (PTProof $ Subst (bind (string2Name x) (p,e)))
<|> do
reserved "symm"
p <- proof
return (PTProof $ Symm p)
<|> (liftM (PTProof . ProofVar . string2Name) $ identifier)
<|> (liftM PTCtor ctor)
<|> (liftM PTProof $ parens proof)
<|> (liftM PTExpr $ brackets (withBotok True expr))
<?> "proof term"
caseproof = do
reserved "case"
scrut <- withBotok True expr
reserved "proving"
fo <- formula
reserved "by"
x <- identifier
reserved "of"
proofalts <- braces (proofalt `sepBy` semi)
return (ProofCase scrut fo (bind (string2Name x) proofalts))
<?> "case expression"
proofalt = do
p <- withBotok True pat
reservedOp "->"
e <- proof
return (bind p e)
formula = do
reserved "Forall"
lparen
x <- identifier
reservedOp "::"
t <- ty
rparen
comma
fo <- formula
return (ForallExpr t (bind (string2Name x) fo))
<|> do
reserved "Assuming"
fo <- formula
comma
fo' <- formula
return (ForallProof fo fo')
<|> do
lcurly
e <- withBotok True expr
reservedOp "="
e' <- withBotok True expr
rcurly
return (FormulaEq e e')
<?> "formula"
proof = do
pts <- many1 proofterm
mr <- optionMaybe ( do
reservedOp ":::"
formula
)
let mkProofApp (PTProof p) (PTExpr e) = PTProof (ProofAppExpr p e)
mkProofApp (PTProof p) (PTProof p') = PTProof (ProofAppProof p p')
mkProofApp _ _ = error "Zabonga FIXME"
(PTProof pr) = case pts of
(PTCtor ctor:pts') -> PTProof $ ProofBisim ctor (map (\(PTProof p) -> p) pts')
_ -> foldl1 mkProofApp pts
case mr of
(Just fo) -> return (ProofAnno pr fo)
Nothing -> return pr
parse :: FilePath -> String -> Either ParseError Program
parse filename stream = runParser program (False,[]) filename stream
parseExpr :: FilePath -> String -> Either ParseError Expr
parseExpr filename stream = runParser (expr >>= \ e -> eof >> return e) (False,[]) filename stream