module Language.CSharp.Parser.Statement where import Text.Parsec hiding (Empty) import Language.CSharp.Lexer import Language.CSharp.Syntax import Language.CSharp.Parser.Utility import Language.CSharp.Parser.Expression import Language.CSharp.Parser.Type pStatements :: P [Statement] pStatements = many pStatement "a statement" pStatement :: P Statement pStatement = choice [ pIfThenElseStatement, pWhileStatement , pDoStatement , pForEachStatement , pLockStatement , pBlockStatement , pLabeledStatement , pEmptyStatement , pBreakStatement , pContinueStatement , pReturnStatement , pThrowStatement , pYieldStatement , pDeclarationStatement, pCheckedStatement , pUncheckedStatement , pExpressionStatement , pUsingStatement , pSwitchStatement , pGotoStatement , pTry , pForStatement ] pLabeledStatement :: P Statement pLabeledStatement = try (Labeled <$> pIdentifier <* pColon <*> pStatement) pDeclarationStatement :: P Statement pDeclarationStatement = try (Declaration <$> pLocalVarDeclaration <* pSemi) pLocalVarDeclaration :: P LocalVarDeclaration pLocalVarDeclaration = LocalVarDeclaration <$> pLocalVarType <*> sepBy1 pVariableDeclarator pComma pLocalVarType :: P LocalVarType pLocalVarType = VarType <$> pType <|> Var <$ pIdentifierKeyword "var" pVariableDeclarator :: P VariableDeclarator pVariableDeclarator = do name <- pIdentifier initializer <- optionMaybe (pEqualSign *> pVariableInitializer) return $ VariableDeclarator name initializer pVariableInitializer :: P VariableInitializer pVariableInitializer = VariableInitializerExpression <$> pExpression <|> VariableInitializerArray <$> pArrayInitializer pArrayInitializer :: P ArrayInitializer pArrayInitializer = ArrayInitializer <$> betweenCurly (sepBy pVariableInitializer pComma) pBlockStatement :: P Statement pBlockStatement = Block <$> betweenCurly pStatements pEmptyStatement :: P Statement pEmptyStatement = Empty <$ pSemi pExpressionStatement :: P Statement pExpressionStatement = ExpressionStatement <$> pExpression <* pSemi pIfThenElseStatement :: P Statement pIfThenElseStatement = do pToken TKWif guard <- betweenParens pExpression trueBody <- pStatement falseBody <- optionMaybe (pToken TKWelse *> pStatement) return $ IfThenElse guard trueBody falseBody pWhileStatement :: P Statement pWhileStatement = do pToken TKWwhile guard <- betweenParens pExpression body <- pStatement return $ While guard body pDoStatement :: P Statement pDoStatement = do pToken TKWdo body <- pStatement pToken TKWwhile guard <- betweenParens pExpression <* pSemi return $ Do body guard pForStatement :: P Statement pForStatement = do pToken TKWfor pOParens initializer <- optionMaybe pForInitializer pSemi guard <- optionMaybe pExpression pSemi iterator <- optionMaybe (sepBy1 pExpression pComma) pCParens body <- pStatement return $ For initializer guard iterator body pForInitializer :: P ForInitializer pForInitializer = ForInitializerDeclaration <$> pLocalVarDeclaration <|> ForInitializerExpressions <$> sepBy1 pExpression pComma pForEachStatement :: P Statement pForEachStatement = do pToken TKWforeach pOParens ty <- pLocalVarType name <- pIdentifier pToken TKWin expr <- pExpression pCParens body <- pStatement return $ ForEach ty name expr body pSwitchStatement :: P Statement pSwitchStatement = do pToken TKWswitch expression <- betweenParens pExpression cases <- betweenCurly (many (pSwitchCaseBlock <|> pSwitchDefaultBlock)) return $ Switch expression cases pSwitchCaseBlock :: P SwitchBlock pSwitchCaseBlock = LabeledBlock <$ pToken TKWcase <*> pExpression <* pColon <*> many pStatement pSwitchDefaultBlock :: P SwitchBlock pSwitchDefaultBlock = DefaultBlock <$ pToken TKWdefault <* pColon <*> many pStatement pTry :: P Statement pTry = do pToken TKWtry statements <- betweenCurly pStatements (catches, finally) <- choice [ try ((,) <$> many1 pCatch <* pToken TKWfinally <*> betweenCurly pStatements) , try ((,[]) <$> many1 pCatch) , try (([],) <$ pToken TKWfinally <*> betweenCurly pStatements) ] return $ Try statements catches finally pCatch :: P Catch pCatch = do pToken TKWcatch specifier <- optionMaybe pExceptionSpecifier when <- optionMaybe (pIdentifierKeyword "when" *> betweenParens pExpression) statements <- betweenCurly pStatements return $ Catch specifier when statements where pExceptionSpecifier = betweenParens (ExceptionSpecifier <$> pType <*> optionMaybe pIdentifier) pGotoStatement :: P Statement pGotoStatement = Goto <$> pGotoTarget <* pSemi pGotoTarget :: P GotoTarget pGotoTarget = choice [ try (GotoLabel <$ pToken TKWgoto <*> pIdentifier) , try (GotoCase <$ pToken TKWgoto <* pToken TKWcase <*> pExpression) , try (GotoDefault <$ pToken TKWgoto <* pToken TKWdefault) ] pBreakStatement :: P Statement pBreakStatement = Break <$ pToken TKWbreak <* pSemi pContinueStatement :: P Statement pContinueStatement = Continue <$ pToken TKWcontinue <* pSemi pReturnStatement :: P Statement pReturnStatement = Return <$ pToken TKWreturn <*> pMaybeExpression <* pSemi pThrowStatement :: P Statement pThrowStatement = Throw <$ pToken TKWthrow <*> pMaybeExpression <* pSemi pLockStatement :: P Statement pLockStatement = do pToken TKWlock expr <- betweenParens pExpression body <- pStatement return $ Lock expr body pUsingStatement :: P Statement pUsingStatement = do pToken TKWusing resource <- betweenParens pResourceAquisition body <- pStatement return $ UsingStatement resource body pResourceAquisition :: P ResourceAcquisition pResourceAquisition = ResourceAcquisitionVariable <$> sepBy1 pVariableDeclarator pComma <|> ResourceAcquisitionExpression <$> pExpression pCheckedStatement :: P Statement pCheckedStatement = try $ CheckedStatement <$ pToken TKWchecked <*> betweenCurly pStatements pUncheckedStatement :: P Statement pUncheckedStatement = try $ UncheckedStatement <$ pToken TKWunchecked <*> betweenCurly pStatements pYieldStatement :: P Statement pYieldStatement = pIdentifierKeyword "yield" *> (pYieldReturn <|> pYieldBreak) where pYieldReturn = Yield . Just <$ pToken TKWreturn <*> pExpression <* pSemi pYieldBreak = Yield Nothing <$ pToken TKWbreak <* pSemi