module Language.Eiffel.Parser.Statement where
import qualified Data.Text as Text
import Language.Eiffel.Syntax
import Language.Eiffel.Parser.Clause
import Language.Eiffel.Parser.Expr
import Language.Eiffel.Parser.Lex
import Language.Eiffel.Parser.Typ
import Text.Parsec
stmt = attachTokenPos bareStmt
bareStmt = do
s <- choice [ across
, assign
, assignAttempt
, check
, retry
, create
, ifStmt
, inspect
, loop
, debug
, try callStmt
]
optional semicolon
return s
stmts :: Parser [Stmt]
stmts = many stmt
stmts' = many bareStmt
retry = do
keyword TokRetry
return Retry
across = do
keyword TokAcross
e <- expr
keyword TokAs
i <- identifier
keyword TokLoop
bl <- blockPos
keyword TokEnd
return (Across e i bl)
inspect =
let whenPart = do
keyword TokWhen
es <- expr `sepBy1` comma
s <- attachTokenPos (keyword TokThen >> Block `fmap` stmts)
return (es, s)
in do
keyword TokInspect
e <- expr
whens <- many1 whenPart
elseMb <- optionMaybe (attachTokenPos $ keyword TokElse >> Block `fmap` stmts)
keyword TokEnd
return $ Inspect e whens elseMb
check = do
keyword TokCheck
clauses <- many clause
let chk = keyword TokEnd >> return (Check clauses)
checkBlock = do
keyword TokThen
body <- blockPos
keyword TokEnd
return (CheckBlock clauses body)
checkBlock <|> chk
blockPos = attachTokenPos block
block :: Parser UnPosStmt
block = fmap Block stmts
ifStmt :: Parser UnPosStmt
ifStmt = do
b <- keyword TokIf >> expr
body <- attachTokenPos (keyword TokThen >> fmap Block stmts)
ifelses <- many ifelseP
elseMb <- optionMaybe elseP
elseMb' <- maybe (return Nothing) (fmap Just . attachTokenPos . return) elseMb
keyword TokEnd
return (If b body ifelses elseMb')
elseP :: Parser UnPosStmt
elseP = keyword TokElse >> fmap Block stmts
ifelseP :: Parser (ElseIfPart Expr)
ifelseP = do
b <- keyword TokElseIf >> expr
s1 <- attachTokenPos $ keyword TokThen >> fmap Block stmts
return (ElseIfPart b s1)
create :: Parser UnPosStmt
create = do
keyword TokCreate
t <- optionMaybe (braces typ)
v <- attachTokenPos var
s <- (do
period
callE <- call
case callE of
UnqualCall fName args -> return (Create t v fName args)
VarOrCall fName -> return (Create t v fName [])
e -> error $ "create: should not have parsed " ++ show e
) <|> return (Create t v defaultCreate [])
return s
loop :: Parser UnPosStmt
loop = do
keyword TokFrom
fr <- attachTokenPos block
invarMb <- option [] (keyword TokInvariant >> many clause)
un <- keyword TokUntil >> expr
lo <- attachTokenPos $ keyword TokLoop >> block
variant <- optionMaybe (keyword TokVariant >> clauseExpr `fmap` clause)
keyword TokEnd
return (Loop fr invarMb un lo variant)
assignId :: Parser Expr
assignId = do
e <- expr
colon
opInfo (RelOp Eq NoType)
return e
assignAttemptId :: Parser Expr
assignAttemptId = do
i <- attachTokenPos var
symbol '?'
opInfo (RelOp Eq NoType)
return i
callStmt :: Parser UnPosStmt
callStmt = do
c <- attachTokenPos call
return $ CallStmt c
assign :: Parser UnPosStmt
assign = do
i <- try assignId
e <- expr <?> "assignment expression"
return $ Assign i e
assignAttempt :: Parser UnPosStmt
assignAttempt = do
i <- try assignAttemptId
e <- expr <?> "assignment attempt expression"
return $ AssignAttempt i e
debug :: Parser UnPosStmt
debug = do
keyword TokDebug
str <- option Text.empty (parens anyStringTok)
b <- attachTokenPos block
keyword TokEnd
return (Debug str b)