File: Parser\ParseStatement.vb
Web Access
Project: src\src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.

'-----------------------------------------------------------------------------
' Contains the definition of the Parser
'-----------------------------------------------------------------------------
Imports Microsoft.CodeAnalysis.Syntax.InternalSyntax
Imports InternalSyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.SyntaxFactory

Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax

    Partial Friend Class Parser

        '
        '============ Methods for parsing specific executable statements
        '

        ' [in] Token starting the statement
        ' File: Parser.cpp
        ' Lines: 5870 - 5870
        ' Statement* .Parser::ParseContinueStatement( [ _In_ Token* StmtStart ] [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseContinueStatement() As ContinueStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.ContinueKeyword, "ParseContinueStatement called on wrong token")

            Dim continueKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim kind As SyntaxKind
            Dim blockKeyword As KeywordSyntax = Nothing

            Select Case (CurrentToken.Kind)

                Case SyntaxKind.DoKeyword
                    kind = SyntaxKind.ContinueDoStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.ForKeyword
                    kind = SyntaxKind.ContinueForStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.WhileKeyword
                    kind = SyntaxKind.ContinueWhileStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case Else

                    ' The pretty lister is expected to turn Continue statements
                    ' that don't specify a Do, While or For to have the correct
                    ' form. That requires identifying this condition during
                    ' parsing and correcting the parse trees.

                    Dim loopContext = Context.FindNearest(AddressOf SyntaxFacts.SupportsContinueStatement)

                    If loopContext IsNot Nothing Then

                        Select Case loopContext.BlockKind
                            Case SyntaxKind.SimpleDoLoopBlock,
                                 SyntaxKind.DoWhileLoopBlock

                                kind = SyntaxKind.ContinueDoStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.DoKeyword)

                            Case SyntaxKind.ForBlock, SyntaxKind.ForEachBlock
                                kind = SyntaxKind.ContinueForStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.ForKeyword)

                            Case SyntaxKind.WhileBlock
                                kind = SyntaxKind.ContinueWhileStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.WhileKeyword)

                        End Select

                    End If

                    If blockKeyword Is Nothing Then
                        ' No context found which can have a continue statement was found
                        ' TODO - Which keyword in this case?
                        kind = SyntaxKind.ContinueDoStatement
                        blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.DoKeyword)
                    End If

                    blockKeyword = ReportSyntaxError(blockKeyword, ERRID.ERR_ExpectedContinueKind)
            End Select

            Dim statement = SyntaxFactory.ContinueStatement(kind, continueKeyword, blockKeyword)

            Return statement
        End Function

        Private Function ParseExitStatement() As StatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.ExitKeyword, "ParseExitStatement called on wrong token")

            Dim exitKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim statement As StatementSyntax = Nothing
            Dim kind As SyntaxKind
            Dim blockKeyword As KeywordSyntax = Nothing

            Select Case (CurrentToken.Kind)

                Case SyntaxKind.DoKeyword
                    kind = SyntaxKind.ExitDoStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.ForKeyword
                    kind = SyntaxKind.ExitForStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.WhileKeyword
                    kind = SyntaxKind.ExitWhileStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.SelectKeyword
                    kind = SyntaxKind.ExitSelectStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                ' The pretty lister is expected to turn Exit statements
                ' that don
                ' statements that do. That requires identifying this
                ' condition during parsing and correcting the parse trees.

                Case SyntaxKind.SubKeyword
                    ' Error message moved to context
                    kind = SyntaxKind.ExitSubStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.FunctionKeyword
                    ' Error message moved to context
                    kind = SyntaxKind.ExitFunctionStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.PropertyKeyword
                    ' Error message moved to context
                    kind = SyntaxKind.ExitPropertyStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case SyntaxKind.TryKeyword
                    kind = SyntaxKind.ExitTryStatement
                    blockKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                Case Else
                    'The block keyword is missing.  Look at the contexts to determine what should be here
                    Dim loopContext = Context.FindNearest(AddressOf SyntaxFacts.SupportsExitStatement)

                    If loopContext IsNot Nothing Then

                        Select Case loopContext.BlockKind

                            Case SyntaxKind.SimpleDoLoopBlock,
                                 SyntaxKind.DoWhileLoopBlock

                                kind = SyntaxKind.ExitDoStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.DoKeyword)

                            Case SyntaxKind.ForBlock, SyntaxKind.ForEachBlock
                                kind = SyntaxKind.ExitForStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.ForKeyword)

                            Case SyntaxKind.WhileBlock
                                kind = SyntaxKind.ExitWhileStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.WhileKeyword)

                            Case SyntaxKind.SelectBlock
                                kind = SyntaxKind.ExitSelectStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.SelectKeyword)

                            Case SyntaxKind.SubBlock, SyntaxKind.ConstructorBlock
                                kind = SyntaxKind.ExitSubStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.SubKeyword)

                            Case SyntaxKind.FunctionBlock
                                kind = SyntaxKind.ExitFunctionStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.FunctionKeyword)

                            Case SyntaxKind.PropertyBlock
                                kind = SyntaxKind.ExitPropertyStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.PropertyKeyword)

                            Case SyntaxKind.TryBlock
                                kind = SyntaxKind.ExitTryStatement
                                blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.TryKeyword)

                        End Select
                    End If

                    ' "Exit Operator" is not a valid exit kind, but we keep track of when
                    ' a user might be expected to use it to give a smarter error.
                    ' ""Exit Operator' is not valid. Use 'Return' to exit an Operator.'
                    ' Or
                    ' ""Exit AddHandler', 'Exit RemoveHandler' and 'Exit RaiseEvent' are not valid. Use 'Return' to exit from event members.'
                    Dim stmtError As ERRID = Nothing

                    Select Case CurrentToken.Kind
                        Case SyntaxKind.OperatorKeyword
                            stmtError = ERRID.ERR_ExitOperatorNotValid

                        Case SyntaxKind.AddHandlerKeyword,
                            SyntaxKind.RemoveHandlerKeyword,
                            SyntaxKind.RaiseEventKeyword
                            stmtError = ERRID.ERR_ExitEventMemberNotInvalid

                    End Select

                    If stmtError <> ERRID.ERR_None Then
                        statement = SyntaxFactory.ReturnStatement(InternalSyntaxFactory.MissingKeyword(SyntaxKind.ReturnKeyword), Nothing)
                        statement = statement.AddLeadingSyntax(
                            CodeAnalysis.Syntax.InternalSyntax.SyntaxList.List(exitKeyword, CurrentToken), stmtError)
                        GetNextToken()
                        Return statement
                    End If

                    If blockKeyword Is Nothing Then
                        ' No context found which can have an exit statement was found
                        'TODO - What kind of statement should be generated?  Bad Exit would make most sense.
                        ' For now generate an Exit Sub but this leads to spurious errors.
                        kind = SyntaxKind.ExitSubStatement
                        blockKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.SubKeyword)
                    End If

                    blockKeyword = ReportSyntaxError(blockKeyword, ERRID.ERR_ExpectedExitKind)
            End Select

            statement = SyntaxFactory.ExitStatement(kind, exitKeyword, blockKeyword)

            Return statement

        End Function

        Private Function ParseCaseStatement() As CaseStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.CaseKeyword, "ParseCaseStatement called on wrong token.")

            Dim caseKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim caseClauses = _pool.AllocateSeparated(Of CaseClauseSyntax)()
            Dim elseKeyword As KeywordSyntax = Nothing

            If CurrentToken.Kind = SyntaxKind.ElseKeyword Then
                elseKeyword = DirectCast(CurrentToken, KeywordSyntax)
                GetNextToken() '// get off ELSE

                Dim caseClause = SyntaxFactory.ElseCaseClause(elseKeyword)
                caseClauses.Add(caseClause)

            Else

                Do
                    Dim StartCase As SyntaxKind = CurrentToken.Kind ' dev10_500588 Snap the start of the expression token AFTER we've moved off the EOL (if one is present)
                    Dim caseClause As CaseClauseSyntax

                    If StartCase = SyntaxKind.IsKeyword OrElse SyntaxFacts.IsRelationalOperator(StartCase) Then

                        ' dev10_526560 Allow implicit newline after IS
                        Dim optionalIsKeyword As KeywordSyntax = Nothing
                        TryGetTokenAndEatNewLine(SyntaxKind.IsKeyword, optionalIsKeyword)

                        If SyntaxFacts.IsRelationalOperator(CurrentToken.Kind) Then

                            Dim relationalOperator = DirectCast(CurrentToken, PunctuationSyntax)
                            GetNextToken() ' get off relational operator
                            TryEatNewLine() ' dev10_503248

                            Dim CaseExpr As ExpressionSyntax = ParseExpressionCore()

                            If CaseExpr.ContainsDiagnostics Then
                                CaseExpr = ResyncAt(CaseExpr)
                            End If

                            caseClause = SyntaxFactory.RelationalCaseClause(RelationalOperatorKindToCaseKind(relationalOperator.Kind), optionalIsKeyword, relationalOperator, CaseExpr)

                        Else
                            ' Since we saw IS, create a relational case.
                            ' This helps intellisense do a drop down of
                            ' the operators that can follow "Is".
                            Dim relationalOperator = ReportSyntaxError(InternalSyntaxFactory.MissingPunctuation(SyntaxKind.EqualsToken), ERRID.ERR_ExpectedRelational)

                            caseClause = ResyncAt(InternalSyntaxFactory.RelationalCaseClause(SyntaxKind.CaseEqualsClause, optionalIsKeyword, relationalOperator, InternalSyntaxFactory.MissingExpression))
                        End If

                    Else

                        Dim value As ExpressionSyntax = ParseExpressionCore()

                        If value.ContainsDiagnostics Then
                            value = ResyncAt(value, SyntaxKind.ToKeyword)
                        End If

                        Dim toKeyword As KeywordSyntax = Nothing
                        If TryGetToken(SyntaxKind.ToKeyword, toKeyword) Then

                            Dim upperBound As ExpressionSyntax = ParseExpressionCore()

                            If upperBound.ContainsDiagnostics Then
                                upperBound = ResyncAt(upperBound)
                            End If

                            caseClause = SyntaxFactory.RangeCaseClause(value, toKeyword, upperBound)
                        Else

                            caseClause = SyntaxFactory.SimpleCaseClause(value)
                        End If
                    End If

                    caseClauses.Add(caseClause)

                    Dim comma As PunctuationSyntax = Nothing
                    If Not TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
                        Exit Do
                    End If

                    caseClauses.AddSeparator(comma)
                Loop

            End If

            Dim separatedCaseClauses = caseClauses.ToList()
            _pool.Free(caseClauses)

            Dim statement As CaseStatementSyntax

            If elseKeyword Is Nothing Then
                statement = SyntaxFactory.CaseStatement(caseKeyword, separatedCaseClauses)
            Else
                statement = SyntaxFactory.CaseElseStatement(caseKeyword, separatedCaseClauses)
            End If

            Return statement

        End Function

        Private Shared Function RelationalOperatorKindToCaseKind(kind As SyntaxKind) As SyntaxKind

            Select Case kind
                Case SyntaxKind.LessThanToken
                    Return SyntaxKind.CaseLessThanClause

                Case SyntaxKind.LessThanEqualsToken
                    Return SyntaxKind.CaseLessThanOrEqualClause

                Case SyntaxKind.EqualsToken
                    Return SyntaxKind.CaseEqualsClause

                Case SyntaxKind.LessThanGreaterThanToken
                    Return SyntaxKind.CaseNotEqualsClause

                Case SyntaxKind.GreaterThanToken
                    Return SyntaxKind.CaseGreaterThanClause

                Case SyntaxKind.GreaterThanEqualsToken
                    Return SyntaxKind.CaseGreaterThanOrEqualClause

                Case Else
                    Debug.Assert(False, "Wrong relational operator kind")
                    Return Nothing
            End Select

        End Function

        Private Function ParseSelectStatement() As SelectStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.SelectKeyword, "ParseSelectStatement called on wrong token.")

            Dim selectKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken() ' get off SELECT

            ' Allow the expected CASE token to be present or not.

            Dim optionalCaseKeyword As KeywordSyntax = Nothing
            TryGetToken(SyntaxKind.CaseKeyword, optionalCaseKeyword)

            Dim value As ExpressionSyntax = ParseExpressionCore()

            If value.ContainsDiagnostics Then
                value = ResyncAt(value)
            End If

            Dim statement = SyntaxFactory.SelectStatement(selectKeyword, optionalCaseKeyword, value)

            Return statement
        End Function

        ' ParseIfConstruct handles the parsing of block and line if statements and
        ' block and line elseif statements, setting *IsLineIf as appropriate.
        ' For a line if/elseif, parsing consumes through the first statement (if any)
        ' in the then clause. The returned tree is the block created for the if or else if.

        ' Parse the expression (and following text) in an If or ElseIf statement.

        ' File: Parser.cpp
        ' Lines: 11249 - 11249
        ' ExpressionBlockStatement* .Parser::ParseIfConstruct( [ ParseTree::IfStatement* IfContainingElseIf ] [ _Out_ bool* IsLineIf ] [ _Inout_ bool& ErrorInConstruct ] )

        'davidsch - Renamed ParseIfStatement from ParseIfConstruct
        Private Function ParseIfStatement() As IfStatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.IfKeyword, "ParseIfConstruct called on wrong token.")

            Dim ifKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim condition = ParseExpressionCore(OperatorPrecedence.PrecedenceNone)

            If condition.ContainsDiagnostics Then
                condition = ResyncAt(condition, SyntaxKind.ThenKeyword)
            End If

            Dim thenKeyword As KeywordSyntax = Nothing
            TryGetToken(SyntaxKind.ThenKeyword, thenKeyword)

            Dim statement = SyntaxFactory.IfStatement(ifKeyword, condition, thenKeyword)

            Return statement

        End Function

        Private Function ParseElseStatement() As ElseStatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.ElseKeyword, "ParseIfConstruct called on wrong token.")

            Dim elseKeyword = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim statement = SyntaxFactory.ElseStatement(elseKeyword)

            Return statement
        End Function

        Private Function ParseElseIfStatement() As StatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.ElseIfKeyword OrElse (CurrentToken.Kind = SyntaxKind.ElseKeyword AndAlso PeekToken(1).Kind = SyntaxKind.IfKeyword),
                         "ParseIfConstruct called on wrong token.")

            Dim elseIfKeyword As KeywordSyntax = Nothing

            If CurrentToken.Kind = SyntaxKind.ElseIfKeyword Then
                elseIfKeyword = DirectCast(CurrentToken, KeywordSyntax)

                GetNextToken()

            ElseIf CurrentToken.Kind = SyntaxKind.ElseKeyword Then
                ' When written as 'Else If' we need to merged the two keywords together.

                Dim elseKeyword = DirectCast(CurrentToken, KeywordSyntax)
                GetNextToken()

                If Context.IsSingleLine Then
                    ' But inside of a single-line If this isn't allowed. We parse as an Else statement
                    ' so that the SingleLineIfBlockContext can parse the rest as a separate If statement.

                    Return SyntaxFactory.ElseStatement(elseKeyword)
                End If

                Dim ifKeyword = DirectCast(CurrentToken, KeywordSyntax)
                GetNextToken()

                elseIfKeyword = New KeywordSyntax(SyntaxKind.ElseIfKeyword, MergeTokenText(elseKeyword, ifKeyword), elseKeyword.GetLeadingTrivia(), ifKeyword.GetTrailingTrivia())
            End If

            Dim condition = ParseExpressionCore(OperatorPrecedence.PrecedenceNone)

            If condition.ContainsDiagnostics Then
                condition = ResyncAt(condition, SyntaxKind.ThenKeyword)
            End If

            Dim thenKeyword As KeywordSyntax = Nothing
            TryGetToken(SyntaxKind.ThenKeyword, thenKeyword)

            Dim statement = SyntaxFactory.ElseIfStatement(elseIfKeyword, condition, thenKeyword)

            Return statement
        End Function

        Private Function ParseAnachronisticStatement() As StatementSyntax
            ' Assume CurrentToken is on ENDIF, WEND
            Debug.Assert(CurrentToken.Kind = SyntaxKind.EndIfKeyword OrElse
                             CurrentToken.Kind = SyntaxKind.GosubKeyword OrElse
                             CurrentToken.Kind = SyntaxKind.WendKeyword, "ParseAnachronisticEndIfStatement called on wrong token")

            Dim keyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            ' Put the 'ENDIF'/'WEND'/'GOSUB' token in the unexpected.
            Dim unexpected As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of SyntaxToken) = ResyncAt()

            Dim missingEndKeyword As KeywordSyntax = InternalSyntaxFactory.MissingKeyword(SyntaxKind.EndKeyword)
            Dim statement As StatementSyntax = Nothing
            Dim errorId As ERRID

            Select Case keyword.Kind
                Case SyntaxKind.EndIfKeyword
                    ' EndIf is anachronistic - Correct syntax is END IF
                    ' TODO - Is an END IF with missing tokens the right way to model this?
                    statement = SyntaxFactory.EndIfStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.IfKeyword))
                    errorId = ERRID.ERR_ObsoleteEndIf

                Case SyntaxKind.WendKeyword
                    ' While...Wend are anachronistic
                    ' TODO - Is an END IF with missing tokens the right way to model this?
                    statement = SyntaxFactory.EndWhileStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.WhileKeyword))
                    errorId = ERRID.ERR_ObsoleteWhileWend

                Case SyntaxKind.GosubKeyword
                    statement = InternalSyntaxFactory.EmptyStatement
                    errorId = ERRID.ERR_ObsoleteGosub

            End Select

            'The Dev10 parser does not mark this statement as bad.
            Return statement.AddTrailingSyntax(unexpected, errorId)
        End Function

        Private Function ParseDoStatement() As DoStatementSyntax

            ' Assume CurrentToken is on Do
            Debug.Assert(CurrentToken.Kind = SyntaxKind.DoKeyword, "ParseDoStatement called on wrong token")

            Dim doKeyword = DirectCast(CurrentToken, KeywordSyntax)

            ' Consume the Do.
            GetNextToken()

            Dim optionalWhileOrUntilClause As WhileOrUntilClauseSyntax = Nothing

            TryParseOptionalWhileOrUntilClause(doKeyword, optionalWhileOrUntilClause)

            Dim kind As SyntaxKind
            If optionalWhileOrUntilClause Is Nothing Then
                kind = SyntaxKind.SimpleDoStatement
            ElseIf optionalWhileOrUntilClause.Kind = SyntaxKind.WhileClause Then
                kind = SyntaxKind.DoWhileStatement
            Else
                kind = SyntaxKind.DoUntilStatement
            End If

            Dim statement As DoStatementSyntax = SyntaxFactory.DoStatement(kind, doKeyword, optionalWhileOrUntilClause)

            Return statement
        End Function

        Private Function ParseLoopStatement() As LoopStatementSyntax
            ' Assume CurrentToken is on Loop
            Debug.Assert(CurrentToken.Kind = SyntaxKind.LoopKeyword, "ParseDoStatement called on wrong token")

            Dim loopKeyword = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            ' Moved ERRID.ERR_LoopDoubleCondition to TryParseOptionalWhileOrUntilClause
            Dim optionalWhileOrUntilClause As WhileOrUntilClauseSyntax = Nothing

            TryParseOptionalWhileOrUntilClause(loopKeyword, optionalWhileOrUntilClause)

            Dim kind As SyntaxKind
            If optionalWhileOrUntilClause Is Nothing Then
                kind = SyntaxKind.SimpleLoopStatement
            ElseIf optionalWhileOrUntilClause.Kind = SyntaxKind.WhileClause Then
                kind = SyntaxKind.LoopWhileStatement
            Else
                kind = SyntaxKind.LoopUntilStatement
            End If

            Dim statement As LoopStatementSyntax = SyntaxFactory.LoopStatement(kind, loopKeyword, optionalWhileOrUntilClause)

            Return statement
        End Function

        Private Function ParseForStatement() As StatementSyntax
            ' Assume CurrentToken is on For
            Debug.Assert(CurrentToken.Kind = SyntaxKind.ForKeyword, "ParseForStatement called on wrong token")

            Dim forKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            ' Consume the FOR.
            GetNextToken()

            Dim eachKeyword As KeywordSyntax = Nothing
            If TryGetToken(SyntaxKind.EachKeyword, eachKeyword) Then

                Return ParseForEachStatement(forKeyword, eachKeyword)

            Else
                Return ParseForStatement(forKeyword)

            End If
        End Function

        Private Function ParseForEachStatement(forKeyword As KeywordSyntax, eachKeyword As KeywordSyntax) As ForEachStatementSyntax

            Dim controlVariable = ParseForLoopControlVariable()

            Dim expression As ExpressionSyntax = Nothing

            If controlVariable.ContainsDiagnostics Then
                controlVariable = ResyncAt(controlVariable, SyntaxKind.InKeyword)
            End If

            TryEatNewLineIfFollowedBy(SyntaxKind.InKeyword)

            Dim inKeyword As KeywordSyntax = Nothing
            If TryGetTokenAndEatNewLine(SyntaxKind.InKeyword, inKeyword) Then

                expression = ParseExpressionCore()

                If expression.ContainsDiagnostics Then
                    expression = ResyncAt(expression)
                End If
            Else
                'TODO - In Dev 10 only syntax error was reported.  Now
                ' expected 'In" is reported.  Should only 1 message be reported?
                ' Also see parsing For with expected =.
                inKeyword = DirectCast(HandleUnexpectedToken(SyntaxKind.InKeyword), KeywordSyntax)
                expression = InternalSyntaxFactory.MissingExpression.AddTrailingSyntax(ResyncAt({SyntaxKind.ToKeyword}), ERRID.ERR_Syntax)
            End If

            Dim statement = SyntaxFactory.ForEachStatement(forKeyword, eachKeyword, controlVariable, inKeyword, expression)

            Return statement
        End Function

        Private Function ParseForStatement(forKeyword As KeywordSyntax) As ForStatementSyntax

            Dim controlVariable = ParseForLoopControlVariable()

            Dim fromValue As ExpressionSyntax = Nothing
            Dim toValue As ExpressionSyntax = Nothing

            If controlVariable.ContainsDiagnostics Then
                controlVariable = ResyncAt(controlVariable, SyntaxKind.EqualsToken, SyntaxKind.ToKeyword)
            End If

            ' TODO - Handle case where controlVariable is OK but current token is not equals.  Need to resync in that case too
            ' e.g.
            ' For i,j = 1 to 10
            ' See bug 8590.

            Dim equalsToken As PunctuationSyntax = Nothing

            If TryGetTokenAndEatNewLine(SyntaxKind.EqualsToken, equalsToken) Then

                ' Dev10_545918 - Allow implicit line continuation after '=' 

                fromValue = ParseExpressionCore()

                If fromValue.ContainsDiagnostics Then
                    fromValue = ResyncAt(fromValue, SyntaxKind.ToKeyword)
                End If

            Else
                'Dev 10 only reported syntax error.  Code now reports expected '=' and syntax error.
                ' TODO - consider removing redundant syntax error message.
                equalsToken = DirectCast(HandleUnexpectedToken(SyntaxKind.EqualsToken), PunctuationSyntax)

                fromValue = InternalSyntaxFactory.MissingExpression.AddTrailingSyntax(ResyncAt({SyntaxKind.ToKeyword}), ERRID.ERR_Syntax)

            End If

            Dim toKeyword As KeywordSyntax = Nothing
            If TryGetToken(SyntaxKind.ToKeyword, toKeyword) Then

                'TODO - davidsch - Why is newline allowed after '=' but not after 'to'?
                toValue = ParseExpressionCore()

                If toValue.ContainsDiagnostics Then
                    toValue = ResyncAt(toValue, SyntaxKind.StepKeyword)
                End If

            Else
                'No error for expected 'To' keyword.  HandleUnexpectedToken returns ERRID_Syntax
                toKeyword = DirectCast(HandleUnexpectedToken(SyntaxKind.ToKeyword), KeywordSyntax)
                'TODO - ERRID_ExpectedExpression here?
                toValue = InternalSyntaxFactory.MissingExpression.AddTrailingSyntax(ResyncAt({SyntaxKind.ToKeyword}))

            End If

            Dim optionalStepClause As ForStepClauseSyntax = Nothing
            Dim stepKeyword As KeywordSyntax = Nothing
            Dim stepValue As ExpressionSyntax = Nothing

            If TryGetToken(SyntaxKind.StepKeyword, stepKeyword) Then

                stepValue = ParseExpressionCore()

                If stepValue.ContainsDiagnostics Then
                    stepValue = ResyncAt(stepValue)
                End If

                optionalStepClause = SyntaxFactory.ForStepClause(stepKeyword, stepValue)

            End If

            Dim statement = SyntaxFactory.ForStatement(forKeyword, controlVariable, equalsToken, fromValue, toKeyword, toValue, optionalStepClause)

            Return statement
        End Function

        Private Function ParseNextStatement() As NextStatementSyntax
            ' Assume CurrentToken is on Next
            Debug.Assert(CurrentToken.Kind = SyntaxKind.NextKeyword, "ParseNextStatement called on wrong token")

            Dim nextKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken()

            If CanFollowStatement(CurrentToken) Then

                Return SyntaxFactory.NextStatement(nextKeyword, Nothing)

            Else
                ' Collect the next variables.
                ' Context is updated when statement is processed by ForBlockContext.
                Dim variables = _pool.AllocateSeparated(Of ExpressionSyntax)()
                Dim enclosing As BlockContext = Context
                Do
                    Dim variable As ExpressionSyntax = ParseVariable()

                    If variable.ContainsDiagnostics Then
                        variable = ResyncAt(variable)
                    End If

                    ' Report ERR_ExtraNextVariable for the first additional Next variable
                    ' only. This matches the behavior of the native compiler and avoids
                    ' walking out too many contexts.
                    If enclosing IsNot Nothing AndAlso
                        enclosing.BlockKind <> SyntaxKind.ForBlock AndAlso
                        enclosing.BlockKind <> SyntaxKind.ForEachBlock Then
                        variable = ReportSyntaxError(variable, ERRID.ERR_ExtraNextVariable)
                        ' Skip further checks for extra variables.
                        enclosing = Nothing
                    End If

                    variables.Add(variable)

                    Dim comma As PunctuationSyntax = Nothing
                    If Not TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
                        Exit Do
                    End If

                    variables.AddSeparator(comma)

                    If enclosing IsNot Nothing Then
                        enclosing = enclosing.PrevBlock
                        Debug.Assert(enclosing IsNot Nothing)
                    End If
                Loop

                Dim statement = SyntaxFactory.NextStatement(nextKeyword, variables.ToList)

                _pool.Free(variables)

                Return statement
            End If
        End Function

        ' /*********************************************************************
        ' *
        ' * Function:
        ' *     Parser::ParseForLoopControlVariable
        ' *
        ' * Purpose:
        ' *     Parses: <Expression> | <ident>[ArrayList] As <type>
        ' *
        ' **********************************************************************/

        ' File: Parser.cpp
        ' Lines: 5717 - 5717
        ' Expression* .Parser::ParseForLoopControlVariable( [ ParseTree::BlockStatement* ForBlock ] [ _In_ Token* ForStart ] [ _Out_ ParseTree::VariableDeclarationStatement** Decl ] [ _Inout_ bool& ErrorInConstruct ] )
        Private Function ParseForLoopControlVariable() As VisualBasicSyntaxNode

            'TODO - davidsch - I have kept this code as-is but it seems that it would be better to parse the common prefix of 
            ' ParseVariable and ParseForLoopVariableDeclaration instead of peeking for 'AS', 'IN', '='

            Select Case (CurrentToken.Kind)

                Case SyntaxKind.IdentifierToken

                    Select Case PeekToken(1).Kind

                        Case SyntaxKind.QuestionToken, SyntaxKind.AsKeyword
                            Return ParseForLoopVariableDeclaration()

                        Case SyntaxKind.OpenParenToken
                            Dim lookAhead As SyntaxToken = Nothing
                            Dim i = PeekAheadFor(s_isTokenOrKeywordFunc, {SyntaxKind.AsKeyword, SyntaxKind.InKeyword, SyntaxKind.EqualsToken}, lookAhead)
                            If lookAhead IsNot Nothing AndAlso
                                lookAhead.Kind = SyntaxKind.AsKeyword AndAlso
                                PeekToken(i - 1).Kind = SyntaxKind.CloseParenToken Then
                                Return ParseForLoopVariableDeclaration()
                            End If

                            ' Fall through to Non-Declaration, i.e. ParseVariable below
                    End Select

                    Return ParseVariable()

                Case Else
                    Return ParseVariable()
            End Select
        End Function

        ' /*********************************************************************
        ' *
        ' * Function:
        ' *     Parser::ParseForLoopVariableDeclaration
        ' *
        ' * Purpose:
        ' *     Parses: <ident>[ArrayList] As <type>
        ' *
        ' **********************************************************************/
        ' File: Parser.cpp
        ' Lines: 5761 - 5761
        ' Expression* .Parser::ParseForLoopVariableDeclaration( [ ParseTree::BlockStatement* ForBlock ] [ _In_ Token* ForStart ] [ _Out_ ParseTree::VariableDeclarationStatement** Decl ] [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseForLoopVariableDeclaration() As VariableDeclaratorSyntax

            ' Parse the control variable declaration
            Dim Declarator = ParseModifiedIdentifier(True, False)

            If Declarator.ContainsDiagnostics Then
                ' If we see As before a In or Each, then assume that
                ' we are still on the Control Variable Declaration.
                ' Otherwise, don't resync and allow the caller to
                ' decide how to recover.

                If PeekAheadFor(SyntaxKind.AsKeyword, SyntaxKind.InKeyword, SyntaxKind.EqualsToken) = SyntaxKind.AsKeyword Then
                    Declarator = ResyncAt(Declarator, SyntaxKind.AsKeyword)
                End If
            End If

            Dim [As] As KeywordSyntax = Nothing
            Dim Type As TypeSyntax = Nothing
            Dim optionalAsClause As AsClauseSyntax = Nothing

            If CurrentToken.Kind = SyntaxKind.AsKeyword Then
                [As] = DirectCast(CurrentToken, KeywordSyntax)

                ' Parse the type
                GetNextToken()
                Type = ParseGeneralType()
                optionalAsClause = SyntaxFactory.SimpleAsClause([As], Nothing, Type)
            End If ' Else if "As" is not present, the error falls out as a "Syntax error" IN the caller

            Dim names = _pool.AllocateSeparated(Of ModifiedIdentifierSyntax)()
            names.Add(Declarator)

            Dim result = SyntaxFactory.VariableDeclarator(names.ToList, optionalAsClause, Nothing)

            _pool.Free(names)

            Return result
        End Function

        ' Parse a reference to a label, which can be an identifier or a line number.

        ' File: Parser.cpp
        ' Lines: 11363 - 11363
        ' .Parser::ParseLabelReference( [ _Out_ ParseTree::LabelReferenceStatement* LabelReference ] [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseLabelReference() As SyntaxToken

            Dim label As SyntaxToken = CurrentToken

            If label.Kind = SyntaxKind.IdentifierToken Then

                Dim ident As IdentifierTokenSyntax = DirectCast(label, IdentifierTokenSyntax)
                If ident.TypeCharacter <> TypeCharacter.None Then
                    label = ReportSyntaxError(label, ERRID.ERR_NoTypecharInLabel)
                    GetNextToken()
                    Return label
                End If
                Return ParseIdentifier()

            ElseIf label.Kind = SyntaxKind.IntegerLiteralToken Then

                Dim intLiteral As IntegerLiteralTokenSyntax = DirectCast(label, IntegerLiteralTokenSyntax)

                If Not intLiteral.ContainsDiagnostics Then
                    If intLiteral.TypeSuffix = TypeCharacter.None Then

                        ' Labels must be unsigned. Reinterpret label as a ulong / uint in case it was a negative number written in hex &hffffffff or octal.
                        Dim intLiteralValue As ULong = CULng(intLiteral.ObjectValue)
                        If TypeOf intLiteral Is IntegerLiteralTokenSyntax(Of Integer) Then
                            intLiteralValue = CUInt(intLiteralValue)
                        End If
                        intLiteral = New IntegerLiteralTokenSyntax(Of ULong)(SyntaxKind.IntegerLiteralToken, intLiteral.ToString, intLiteral.GetLeadingTrivia, intLiteral.GetTrailingTrivia, intLiteral.Base, TypeCharacter.None, intLiteralValue)
                    Else
                        intLiteral = ReportSyntaxError(intLiteral, ERRID.ERR_Syntax)
                    End If
                End If

                GetNextToken()

                Return intLiteral

            Else
                label = InternalSyntaxFactory.MissingIdentifier()
                label = ReportSyntaxError(label, ERRID.ERR_ExpectedIdentifier)
                Return label
            End If

        End Function

        ' File: Parser.cpp
        ' Lines: 11410 - 11410
        ' .Parser::ParseGotoStatement( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseGotoStatement() As StatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.GoToKeyword, "Alleged GOTO isn't.")

            Dim gotoKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken()

            Dim labelName = ParseLabelReference()

            'TODO - Not calling ResyncAt may cause different errors from Dev10.

            'Dev10 calls ResyncAt  here if the label has an error.  However, this is
            ' unnecessary now because GetStatementTerminator will do the resync.

            Dim gotoStmt = SyntaxFactory.GoToStatement(gotoKeyword, GetLabelSyntaxForIdentifierOrLineNumber(labelName))

            Return gotoStmt
        End Function

        Private Function GetLabelSyntaxForIdentifierOrLineNumber(ByVal labelName As SyntaxToken) As LabelSyntax
            Debug.Assert(labelName.Kind = SyntaxKind.IntegerLiteralToken OrElse labelName.Kind = SyntaxKind.IdentifierToken)
            Return If(labelName.Kind = SyntaxKind.IntegerLiteralToken, SyntaxFactory.NumericLabel(labelName), SyntaxFactory.IdentifierLabel(labelName))
        End Function

        ' File: Parser.cpp
        ' Lines: 11440 - 11440
        ' .Parser::ParseOnErrorStatement( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseOnErrorStatement() As StatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.OnKeyword, "ON statement must start with ON.")

            Dim onKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken()
            Dim errorKeyword As KeywordSyntax

            If CurrentToken.Kind = SyntaxKind.ErrorKeyword Then
                errorKeyword = DirectCast(CurrentToken, KeywordSyntax)
                GetNextToken()

            Else
                errorKeyword = ReportSyntaxError(InternalSyntaxFactory.MissingKeyword(SyntaxKind.ErrorKeyword), ERRID.ERR_ObsoleteOnGotoGosub)
                errorKeyword = ResyncAt(errorKeyword, SyntaxKind.GoToKeyword, SyntaxKind.ResumeKeyword)
            End If

            If CurrentToken.Kind = SyntaxKind.ResumeKeyword Then

                Return ParseOnErrorResumeNext(onKeyword, errorKeyword)

            ElseIf CurrentToken.Kind = SyntaxKind.GoToKeyword Then

                Return ParseOnErrorGoto(onKeyword, errorKeyword)

            Else
                Dim missingGotoKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.GoToKeyword)

                If Not errorKeyword.ContainsDiagnostics Then
                    missingGotoKeyword = ReportSyntaxError(missingGotoKeyword, ERRID.ERR_ExpectedResumeOrGoto)
                End If

                Dim statement = SyntaxFactory.OnErrorGoToStatement(SyntaxKind.OnErrorGoToLabelStatement,
                                                       onKeyword,
                                                       errorKeyword,
                                                       missingGotoKeyword,
                                                       Nothing,
                                                       SyntaxFactory.IdentifierLabel(InternalSyntaxFactory.MissingIdentifier()))

                Return statement
            End If

        End Function

        Private Function ParseOnErrorResumeNext(onKeyword As KeywordSyntax, errorKeyword As KeywordSyntax) As OnErrorResumeNextStatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.ResumeKeyword, "ParseOnErrorResumeNext called on wrong token.")

            Dim resumeKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            Dim nextKeyword As KeywordSyntax = Nothing

            GetNextToken()

            VerifyExpectedToken(SyntaxKind.NextKeyword, nextKeyword)

            Dim statement = SyntaxFactory.OnErrorResumeNextStatement(onKeyword, errorKeyword, resumeKeyword, nextKeyword)

            Return statement
        End Function

        Private Function ParseOnErrorGoto(onKeyword As KeywordSyntax, errorKeyword As KeywordSyntax) As OnErrorGoToStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.GoToKeyword, "ParseOnErrorGoto called on wrong token.")

            Dim gotoKeyword = DirectCast(CurrentToken, KeywordSyntax)

            Dim optionalMinusToken As PunctuationSyntax = Nothing
            Dim label As LabelSyntax
            Dim kind As SyntaxKind

            Dim nextToken As SyntaxToken = PeekToken(1)

            If nextToken.Kind = SyntaxKind.IntegerLiteralToken AndAlso
                nextToken.ValueText = "0" Then

                kind = SyntaxKind.OnErrorGoToZeroStatement
                label = SyntaxFactory.NumericLabel(nextToken)

                GetNextToken()
                GetNextToken()

            ElseIf nextToken.Kind = SyntaxKind.MinusToken AndAlso
                PeekToken(2).Kind = SyntaxKind.IntegerLiteralToken AndAlso
                PeekToken(2).ValueText = "1" Then

                kind = SyntaxKind.OnErrorGoToMinusOneStatement
                optionalMinusToken = DirectCast(nextToken, PunctuationSyntax)
                label = SyntaxFactory.NumericLabel(PeekToken(2))

                GetNextToken()
                GetNextToken()
                GetNextToken()

            Else
                GetNextToken()
                kind = SyntaxKind.OnErrorGoToLabelStatement
                label = GetLabelSyntaxForIdentifierOrLineNumber(ParseLabelReference())
            End If

            Dim statement = SyntaxFactory.OnErrorGoToStatement(kind, onKeyword, errorKeyword, gotoKeyword, optionalMinusToken, label)

            Return statement
        End Function

        ' File: Parser.cpp
        ' Lines: 11551 - 11551
        ' .Parser::ParseResumeStatement( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseResumeStatement() As ResumeStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.ResumeKeyword, "ParseResumeStatement called on wrong token.")

            Dim resumeKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            Dim optionalLabel As SyntaxToken = Nothing
            Dim statement As ResumeStatementSyntax

            GetNextToken()

            If Not IsValidStatementTerminator(CurrentToken) Then

                If CurrentToken.Kind = SyntaxKind.NextKeyword Then

                    Dim nextKeyword = DirectCast(CurrentToken, KeywordSyntax)
                    GetNextToken()

                    statement = SyntaxFactory.ResumeNextStatement(resumeKeyword, SyntaxFactory.NextLabel(nextKeyword))

                Else
                    optionalLabel = ParseLabelReference()

                    statement = SyntaxFactory.ResumeLabelStatement(resumeKeyword, GetLabelSyntaxForIdentifierOrLineNumber(optionalLabel))
                End If

            Else
                statement = SyntaxFactory.ResumeStatement(resumeKeyword, Nothing)
            End If

            Return statement

        End Function

        Private Function ParseAssignmentOrInvocationStatement() As StatementSyntax
            Dim target As ExpressionSyntax = ParseTerm()

            If target.ContainsDiagnostics Then
                target = ResyncAt(target, SyntaxKind.EqualsToken)
            End If

            ' Could be a function call or it could be an assignment

            If SyntaxFacts.IsAssignmentStatementOperatorToken(CurrentToken.Kind) Then
                ' Consume the assignment operator
                Dim operatorToken As PunctuationSyntax = DirectCast(CurrentToken, PunctuationSyntax)
                GetNextToken()

                TryEatNewLine()

                Dim source = ParseExpressionCore()

                If source.ContainsDiagnostics Then
                    ' Sync to avoid other errors
                    source = ResyncAt(source)
                End If

                Return MakeAssignmentStatement(target, operatorToken, source)
            End If

            Return SyntaxFactory.ExpressionStatement(MakeInvocationExpression(target))
        End Function

        Private Function MakeInvocationExpression(target As ExpressionSyntax) As ExpressionSyntax
            ' Dig into conditional access
            If target.Kind = SyntaxKind.ConditionalAccessExpression Then
                Dim conditionalTarget = DirectCast(target, ConditionalAccessExpressionSyntax)
                Dim invocation = MakeInvocationExpression(conditionalTarget.WhenNotNull)

                If conditionalTarget.WhenNotNull IsNot invocation Then
                    target = SyntaxFactory.ConditionalAccessExpression(conditionalTarget.Expression, conditionalTarget.QuestionMarkToken, invocation)
                End If

            ElseIf target.Kind <> SyntaxKind.InvocationExpression Then ' VS320205
                If Not CanEndExecutableStatement(CurrentToken) AndAlso
                    CurrentToken.Kind <> SyntaxKind.BadToken AndAlso
                    target.Kind <> SyntaxKind.PredefinedCastExpression Then
                    'TODO - Are there other built-in types that should not through this path?, i.e
                    'NodeKind.GetTypeKeyword,
                    'NodeKind.GetXmlNamespaceKeyword
                    ' See call to ParseAssignmentOrCallStatement
                    ' Actually why are built in casts treated differently??

                    ' absence of parentheses and act as if they were present.

                    ' A non-parenthesized argument list cannot contain
                    ' a newline.

                    Dim unexpected As GreenNode = Nothing
                    Dim arguments = ParseArguments(unexpected)
                    Dim closeParen = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.CloseParenToken)
                    If unexpected IsNot Nothing Then
                        closeParen = closeParen.AddLeadingSyntax(unexpected)
                    End If
                    Dim argumentList = SyntaxFactory.ArgumentList(InternalSyntaxFactory.MissingPunctuation(SyntaxKind.OpenParenToken),
                                                                arguments,
                                                                closeParen)

                    target = SyntaxFactory.InvocationExpression(target, ReportSyntaxError(argumentList, ERRID.ERR_ObsoleteArgumentsNeedParens))
                Else
                    target = SyntaxFactory.InvocationExpression(target, Nothing)
                End If
            End If

            Return target
        End Function

        Private Function MakeAssignmentStatement(left As ExpressionSyntax, operatorToken As PunctuationSyntax, right As ExpressionSyntax) As AssignmentStatementSyntax
            Select Case operatorToken.Kind

                Case SyntaxKind.EqualsToken
                    Return SyntaxFactory.SimpleAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.PlusEqualsToken
                    Return SyntaxFactory.AddAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.MinusEqualsToken
                    Return SyntaxFactory.SubtractAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.AsteriskEqualsToken
                    Return SyntaxFactory.MultiplyAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.SlashEqualsToken
                    Return SyntaxFactory.DivideAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.BackslashEqualsToken
                    Return SyntaxFactory.IntegerDivideAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.CaretEqualsToken
                    Return SyntaxFactory.ExponentiateAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.LessThanLessThanEqualsToken
                    Return SyntaxFactory.LeftShiftAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.GreaterThanGreaterThanEqualsToken
                    Return SyntaxFactory.RightShiftAssignmentStatement(left, operatorToken, right)

                Case SyntaxKind.AmpersandEqualsToken
                    Return SyntaxFactory.ConcatenateAssignmentStatement(left, operatorToken, right)

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(operatorToken.Kind)

            End Select
        End Function

        ' File: Parser.cpp
        ' Lines: 11600 - 11600
        ' .Parser::ParseCallStatement( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseCallStatement() As CallStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.CallKeyword, "ParseCallStatement called on wrong token.")

            Dim callKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim invocation As ExpressionSyntax = MakeCallStatementExpression(ParseVariable())

            If invocation.ContainsDiagnostics Then
                invocation = ResyncAt(invocation)
            End If

            Dim statement = SyntaxFactory.CallStatement(callKeyword, invocation)

            Return statement

        End Function

        Private Function MakeCallStatementExpression(expr As ExpressionSyntax) As ExpressionSyntax
            If expr.Kind = SyntaxKind.ConditionalAccessExpression Then
                Dim conditionalTarget = DirectCast(expr, ConditionalAccessExpressionSyntax)
                Dim invocation = MakeCallStatementExpression(conditionalTarget.WhenNotNull)

                If conditionalTarget.WhenNotNull IsNot invocation Then
                    expr = SyntaxFactory.ConditionalAccessExpression(conditionalTarget.Expression, conditionalTarget.QuestionMarkToken, invocation)
                End If

            ElseIf expr.Kind <> SyntaxKind.InvocationExpression Then
                ' Make sure that the expression is an invocation in case user left off parentheses
                expr = SyntaxFactory.InvocationExpression(expr, Nothing)
            End If

            Return expr
        End Function

        ' File: Parser.cpp
        ' Lines: 11656 - 11656
        ' .Parser::ParseRaiseEventStatement( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseRaiseEventStatement() As RaiseEventStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.RaiseEventKeyword, "RaiseEvent statement must start with RaiseEvent.")

            Dim raiseEventKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken()

            Dim ident = ParseIdentifierNameAllowingKeyword()

            If ident.ContainsDiagnostics Then
                ident = ident.AddTrailingSyntax(ResyncAt())
            End If

            Dim optionalArgumentList As ArgumentListSyntax = Nothing
            If CurrentToken.Kind = SyntaxKind.OpenParenToken Then
                optionalArgumentList = ParseParenthesizedArguments()
            End If

            Dim statement = SyntaxFactory.RaiseEventStatement(raiseEventKeyword, ident, optionalArgumentList)

            Return statement
        End Function

        ' File: Parser.cpp
        ' Lines: 11690 - 11690
        ' .Parser::ParseRedimStatement( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseRedimStatement() As StatementSyntax '[ReDim]

            Debug.Assert(CurrentToken.Kind = SyntaxKind.ReDimKeyword, "ParseRedimStatement must start with Redim.")
            Dim reDimKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim possibleKeyword As KeywordSyntax = Nothing
            Dim optionalPreserveKeyword As KeywordSyntax = Nothing

            If CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso
                TryIdentifierAsContextualKeyword(CurrentToken, possibleKeyword) AndAlso possibleKeyword.Kind = SyntaxKind.PreserveKeyword Then
                optionalPreserveKeyword = possibleKeyword
                GetNextToken()
            End If

            ' NOTE: Generation of ERR_RedimNoSizes error was moved to binding to match Dev10 behavior
            Dim clauses = _pool.AllocateSeparated(Of RedimClauseSyntax)()

            Do
                Dim possibleInvocation As ExpressionSyntax = ParseTerm(BailIfFirstTokenRejected:=False, RedimOrNewParent:=True)

                If possibleInvocation.ContainsDiagnostics Then
                    possibleInvocation = ResyncAt(possibleInvocation)
                End If

                Dim clause As RedimClauseSyntax

                If possibleInvocation.Kind = SyntaxKind.InvocationExpression Then
                    Dim invocation = DirectCast(possibleInvocation, InvocationExpressionSyntax)

                    clause = SyntaxFactory.RedimClause(invocation.Expression, invocation.ArgumentList)
                    Dim diagnostics() As DiagnosticInfo = invocation.GetDiagnostics()

                    If diagnostics IsNot Nothing AndAlso diagnostics.Length > 0 Then
                        clause = clause.WithDiagnostics(diagnostics)
                    End If
                Else
                    clause = SyntaxFactory.RedimClause(possibleInvocation, SyntaxFactory.ArgumentList(InternalSyntaxFactory.MissingPunctuation(SyntaxKind.OpenParenToken),
                                                                           Nothing,
                                                                           InternalSyntaxFactory.MissingPunctuation(SyntaxKind.CloseParenToken)))
                End If

                clauses.Add(clause)

                Dim comma As PunctuationSyntax = Nothing
                If Not TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
                    Exit Do
                End If

                clauses.AddSeparator(comma)

            Loop

            Dim statement = If(optionalPreserveKeyword Is Nothing,
                               SyntaxFactory.ReDimStatement(reDimKeyword, optionalPreserveKeyword, clauses.ToList),
                               SyntaxFactory.ReDimPreserveStatement(reDimKeyword, optionalPreserveKeyword, clauses.ToList)
                            )

            _pool.Free(clauses)

            If CurrentToken.Kind = SyntaxKind.AsKeyword Then
                statement = statement.AddTrailingSyntax(CurrentToken, ERRID.ERR_ObsoleteRedimAs)
                GetNextToken()
            End If

            Return statement
        End Function

        ' File: Parser.cpp
        ' Lines: 11755 - 11755
        ' .Parser::ParseHandlerStatement( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseHandlerStatement() As AddRemoveHandlerStatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.AddHandlerKeyword OrElse CurrentToken.Kind = SyntaxKind.RemoveHandlerKeyword, "Handler statement parsing confused.")

            Dim keyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            Dim kind = If(keyword.Kind = SyntaxKind.AddHandlerKeyword, SyntaxKind.AddHandlerStatement, SyntaxKind.RemoveHandlerStatement)
            GetNextToken()

            Dim eventExpression = ParseExpressionCore()

            If eventExpression.ContainsDiagnostics Then
                eventExpression = ResyncAt(eventExpression, SyntaxKind.CommaToken)
            End If

            Dim commaToken As PunctuationSyntax = Nothing
            TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, commaToken, createIfMissing:=True)

            Dim DelegateExpression = ParseExpressionCore()

            If DelegateExpression.ContainsDiagnostics Then
                DelegateExpression = ResyncAt(DelegateExpression)
            End If

            Dim statement = SyntaxFactory.AddRemoveHandlerStatement(kind, keyword, eventExpression, commaToken, DelegateExpression)

            Return statement
        End Function

        ' File: Parser.cpp
        ' Lines: 11830 - 11830
        ' .Parser::ParseExpressionBlockStatement( [ ParseTree::Statement::Opcodes Opcode ] [ _Inout_ bool& ErrorInConstruct ] )

        ' davidsch
        ' used by While/With/Synclock
        ' The return type can't be more specific because these statements don't share a more
        ' specific class.

        'TODO - Rename ParseKeywordExpression and share with other statements that follow this pattern
        ' i.e. Throw, others?
        Private Function ParseExpressionBlockStatement() As StatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.WhileKeyword OrElse
                             CurrentToken.Kind = SyntaxKind.WithKeyword OrElse
                             CurrentToken.Kind = SyntaxKind.SyncLockKeyword, "ParseExpressionBlockStatement called on wrong token.")

            Dim keyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken()

            Dim operand = ParseExpressionCore(OperatorPrecedence.PrecedenceNone)

            If operand.ContainsDiagnostics Then
                operand = ResyncAt(operand)
            End If

            Dim statement As StatementSyntax = Nothing

            Select Case keyword.Kind
                Case SyntaxKind.WhileKeyword
                    statement = SyntaxFactory.WhileStatement(keyword, operand)
                Case SyntaxKind.WithKeyword
                    statement = SyntaxFactory.WithStatement(keyword, operand)
                Case SyntaxKind.SyncLockKeyword
                    statement = SyntaxFactory.SyncLockStatement(keyword, operand)
            End Select

            Return statement
        End Function

        ' File: Parser.cpp
        ' Lines: 11854 - 11854
        ' .Parser::ParseAssignmentStatement( [ _Inout_ bool& ErrorInConstruct ] )

        'TODO - rename ParseObsoleteAssignment
        Private Function ParseAssignmentStatement() As StatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.LetKeyword OrElse CurrentToken.Kind = SyntaxKind.SetKeyword, "Assignment statement parsing is lost.")
            ' Let and set are now illegal

            If CurrentToken.Kind = SyntaxKind.SetKeyword AndAlso
                (IsValidStatementTerminator(PeekToken(1)) OrElse PeekToken(1).Kind = SyntaxKind.OpenParenToken) AndAlso
                Context.IsWithin(SyntaxKind.SetAccessorBlock, SyntaxKind.GetAccessorBlock) Then
                ' If this is a set parse it as a property accessor and then mark it with an error
                ' so that the Set will terminate a Get context.
                Return ParsePropertyOrEventAccessor(SyntaxKind.SetAccessorStatement, Nothing, Nothing)
            Else

                Dim keyword As SyntaxToken = CurrentToken
                GetNextToken()

                ' Only consume the let.  Leave the rest to be processed as an assignment in case the user wrote let x = ...
                Return InternalSyntaxFactory.EmptyStatement.AddTrailingSyntax(keyword, ERRID.ERR_ObsoleteLetSetNotNeeded)
            End If

        End Function

        ' File: Parser.cpp
        ' Lines: 11909 - 11909
        ' .Parser::ParseTry( )
        Private Function ParseTry() As TryStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.TryKeyword, "ParseTry called on wrong token")

            Dim tryKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim statement = SyntaxFactory.TryStatement(tryKeyword)

            Return statement
        End Function

        ' File: Parser.cpp
        ' Lines: 11933 - 11933
        ' .Parser::ParseCatch( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseCatch() As CatchStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.CatchKeyword, "ParseCatch called on wrong token.")

            Dim catchKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken()

            Dim optionalName As IdentifierNameSyntax = Nothing
            Dim optionalAsClause As SimpleAsClauseSyntax = Nothing

            If CurrentToken.Kind = SyntaxKind.IdentifierToken Then
                Dim id = ParseIdentifier()
                If id.Kind <> SyntaxKind.None Then
                    optionalName = SyntaxFactory.IdentifierName(id)
                End If

                Dim asKeyword As KeywordSyntax = Nothing
                Dim typeName As TypeSyntax = Nothing

                If TryGetToken(SyntaxKind.AsKeyword, asKeyword) Then

                    typeName = ParseTypeName()

                    If typeName.ContainsDiagnostics Then
                        typeName = ResyncAt(typeName, SyntaxKind.WhenKeyword)
                    End If

                    optionalAsClause = SyntaxFactory.SimpleAsClause(asKeyword, Nothing, typeName)
                End If
            End If

            Dim optionalWhenClause As CatchFilterClauseSyntax = Nothing
            Dim whenKeyword As KeywordSyntax = Nothing
            Dim filter As ExpressionSyntax = Nothing
            If TryGetToken(SyntaxKind.WhenKeyword, whenKeyword) Then
                filter = ParseExpressionCore()

                optionalWhenClause = SyntaxFactory.CatchFilterClause(whenKeyword, filter)
            End If

            Dim statement = SyntaxFactory.CatchStatement(catchKeyword, optionalName, optionalAsClause, optionalWhenClause)

            Return statement
        End Function

        ' File: Parser.cpp
        ' Lines: 12022 - 12022
        ' .Parser::ParseFinally( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseFinally() As FinallyStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.FinallyKeyword, "ParseFinally called on wrong token.")

            Dim finallyKeyword = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim statement = SyntaxFactory.FinallyStatement(finallyKeyword)

            Return statement
        End Function

        Private Function ParseThrowStatement() As ThrowStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.ThrowKeyword, "ParseThrowStatement called on wrong token.")

            Dim throwKeyword = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim value = ParseExpressionCore(bailIfFirstTokenRejected:=True)
            If value IsNot Nothing Then
                If value.ContainsDiagnostics Then
                    value = ResyncAt(value)
                End If
            End If

            Dim statement = SyntaxFactory.ThrowStatement(throwKeyword, value)

            Return statement
        End Function

        Private Function ParseError() As ErrorStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.ErrorKeyword)

            Dim errorKeyword = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim value = ParseExpressionCore()

            If value.ContainsDiagnostics Then
                value = ResyncAt(value)
            End If

            Dim statement = SyntaxFactory.ErrorStatement(errorKeyword, value)

            Return statement
        End Function

        ' Parse an Erase statement.

        ' File: Parser.cpp
        ' Lines: 12077 - 12077
        ' .Parser::ParseErase( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseErase() As EraseStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.EraseKeyword, "Erase statement parsing lost.")

            Dim eraseKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)

            GetNextToken()

            Dim variables = ParseVariableList()

            Dim statement = SyntaxFactory.EraseStatement(eraseKeyword, variables)

            Return statement

        End Function

        Private Function ShouldParseAsLabel() As Boolean
            Return IsFirstStatementOnLine(CurrentToken) AndAlso PeekToken(1).Kind = SyntaxKind.ColonToken
        End Function

        Private Function ParseLabel() As LabelStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken OrElse CurrentToken.Kind = SyntaxKind.IntegerLiteralToken)

            Dim labelName = ParseLabelReference()

            If labelName.Kind = SyntaxKind.IntegerLiteralToken AndAlso CurrentToken.Kind <> SyntaxKind.ColonToken Then
                Return ReportSyntaxError(SyntaxFactory.LabelStatement(labelName, InternalSyntaxFactory.MissingPunctuation(SyntaxKind.ColonToken)), ERRID.ERR_ObsoleteLineNumbersAreLabels)
            End If

            Dim trivia = New CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode)(labelName.GetTrailingTrivia())
            Debug.Assert(trivia.Count > 0)
            Dim index = -1
            For i = 0 To trivia.Count - 1
                If trivia(i).Kind = SyntaxKind.ColonTrivia Then
                    index = i
                    Exit For
                End If
            Next

            Debug.Assert(index >= 0)
            labelName = DirectCast(labelName.WithTrailingTrivia(trivia.GetStartOfTrivia(index).Node), SyntaxToken)

            Dim colonTrivia = DirectCast(trivia(index), SyntaxTrivia)
            trivia = trivia.GetEndOfTrivia(index + 1)
            Dim colonToken = New PunctuationSyntax(SyntaxKind.ColonToken, colonTrivia.Text, Nothing, trivia.Node)
            Dim statement = SyntaxFactory.LabelStatement(labelName, colonToken)
            Return statement

        End Function

        ' Parse a Mid statement.

        ' File: Parser.cpp
        ' Lines: 12105 - 12105
        ' .Parser::ParseMid( [ _Inout_ bool& ErrorInConstruct ] )

        Private Function ParseMid() As AssignmentStatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso DirectCast(CurrentToken, IdentifierTokenSyntax).PossibleKeywordKind = SyntaxKind.MidKeyword)

            ' Mid[$]  OpenParenthesis  Expression  Comma  Expression  [  Comma  Expression  ]  CloseParenthesis  Equals  Expression  StatementTerminator

            'TODO - Does the Mid need to be modeled as a contextual keyword?  Right now it is kept as an identifier.
            Dim mid = DirectCast(CurrentToken, IdentifierTokenSyntax)
            GetNextToken()

            Debug.Assert(CurrentToken.Kind = SyntaxKind.OpenParenToken)
            Dim openParen As PunctuationSyntax = Nothing
            TryGetTokenAndEatNewLine(SyntaxKind.OpenParenToken, openParen)

            Dim argumentsBuilder As SeparatedSyntaxListBuilder(Of ArgumentSyntax) = _pool.AllocateSeparated(Of ArgumentSyntax)()
            Dim comma As PunctuationSyntax = Nothing

            ' Parse the first required argument followed by a comma
            argumentsBuilder.Add(ParseArgument(RedimOrNewParent:=False))

            If Not TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
                VerifyExpectedToken(SyntaxKind.CommaToken, comma)
            End If

            argumentsBuilder.AddSeparator(comma)

            ' Parse the second required argument
            argumentsBuilder.Add(ParseArgument(RedimOrNewParent:=False))

            If TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
                argumentsBuilder.AddSeparator(comma)

                ' Parse the third argument
                argumentsBuilder.Add(ParseArgument(RedimOrNewParent:=False))
            End If

            Dim arguments As CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(Of ArgumentSyntax) = argumentsBuilder.ToList
            _pool.Free(argumentsBuilder)

            Dim closeParen As PunctuationSyntax = Nothing
            TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=True)

            Dim equals As PunctuationSyntax = Nothing
            VerifyExpectedToken(SyntaxKind.EqualsToken, equals)

            Dim source As ExpressionSyntax = ParseExpressionCore()

            If source.ContainsDiagnostics() Then
                source = ResyncAt(source)
            End If

            Dim statement = SyntaxFactory.MidAssignmentStatement(SyntaxFactory.MidExpression(mid, SyntaxFactory.ArgumentList(openParen, arguments, closeParen)),
                                                                 equals, source)

            Return statement
        End Function

        ' Out
        ' File: Parser.cpp
        ' Lines: 16887 - 16887
        ' Expression* .Parser::ParseOptionalWhileOrUntilClause( [ _Out_ bool* IsWhile ] [ _Inout_ bool& ErrorInConstruct ] )

        Private Function TryParseOptionalWhileOrUntilClause(precedingKeyword As KeywordSyntax, ByRef optionalWhileOrUntilClause As WhileOrUntilClauseSyntax) As Boolean
            If Not CanFollowStatement(CurrentToken) Then

                Dim keyword As KeywordSyntax = Nothing
                If CurrentToken.Kind = SyntaxKind.WhileKeyword Then
                    keyword = DirectCast(CurrentToken, KeywordSyntax)
                Else
                    TryTokenAsContextualKeyword(CurrentToken, SyntaxKind.UntilKeyword, keyword)
                End If

                If keyword IsNot Nothing Then

                    ' Error reporting for ERRID.ERR_LoopDoubleCondition moved to the DoLoopContext

                    GetNextToken()

                    Dim condition = ParseExpressionCore()
                    If condition.ContainsDiagnostics Then
                        condition = ResyncAt(condition)
                    End If

                    Dim kind As SyntaxKind
                    If keyword.Kind = SyntaxKind.WhileKeyword Then
                        kind = SyntaxKind.WhileClause
                    Else
                        kind = SyntaxKind.UntilClause
                    End If

                    optionalWhileOrUntilClause = SyntaxFactory.WhileOrUntilClause(kind, keyword, condition)
                    Return True

                Else
                    Dim kind As SyntaxKind
                    If precedingKeyword.Kind = SyntaxKind.DoKeyword Then
                        kind = SyntaxKind.UntilClause
                        keyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.UntilKeyword)
                    Else
                        kind = SyntaxKind.WhileClause
                        keyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.WhileKeyword)
                    End If

                    Dim clause As WhileOrUntilClauseSyntax = SyntaxFactory.WhileOrUntilClause(kind, keyword, InternalSyntaxFactory.MissingExpression)

                    ' Dev10 places the error only on the current token. 
                    ' This marks the entire clause which seems better.
                    optionalWhileOrUntilClause = ReportSyntaxError(ResyncAt(clause), ERRID.ERR_Syntax)
                    Return True
                End If
            End If

            Return False
        End Function

        Private Function ParseReturnStatement() As ReturnStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.ReturnKeyword, "ParseReturnStatement called on wrong token.")

            Dim returnKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim startToken = CurrentToken

            ' Dev10#694102 - Consider "Dim f = Sub() Return + 5". Which of the following should it mean?
            '   Dim f = (Sub() Return) + 5   ' use an overloaded addition operator
            '   Dim f = (Sub() Return (+5))  ' return the number +5
            ' The spec says that we will greedily parse the body of a statement lambda.
            ' And indeed doing so agrees with the user's intuition ("Return +5" should give an error
            ' that subs cannot return values: it should not give an error that there is no overloaded
            ' operator + between functions and integers!)

            ' We will try to parse the expression, but the final "true" argument means
            ' "Bail if the first token isn't a valid way to start an expression; in this case just return NULL"
            Dim operand = ParseExpressionCore(OperatorPrecedence.PrecedenceNone, True)

            ' Note: Orcas behavior had been to bail immediately if IsValidStatementTerminator(CurrentToken).
            ' Well, all such tokens are invalid as ways to start an expression, so the above call to ParseExpressionCore
            ' will bail correctly for them. I've put in this assert to show that it's safe to skip the check for IsValidStatementTerminator.

            Debug.Assert(operand Is Nothing OrElse Not IsValidStatementTerminator(startToken), "Unexpected: we should have bailed on the token after this return statement")

            If operand Is Nothing Then
                ' if we bailed because the first token was not a way to start an expression, we might
                ' be in a situation like "goo(Sub() Return, 15)" where next token was a valid thing
                ' to come after this return statement, in which case we proceed without trying
                ' to gobble up the return expression. Or we might be like "Return Select", where the next
                ' token cannot possibly come after the statement, so we'll report on it now:
                If Not CanFollowStatement(CurrentToken) Then
                    ' This time don't let it bail:
                    operand = ParseExpressionCore(OperatorPrecedence.PrecedenceNone, False)
                End If

            ElseIf operand.ContainsDiagnostics Then
                operand = ResyncAt(operand)
            End If

            Dim statement = SyntaxFactory.ReturnStatement(returnKeyword, operand)

            Return statement

        End Function

        'TODO - See if all of the simple statements that take only one keyword can be merged into one parsing function
        ' StopOrEnd
        ' TryStatement
        ' FinallyStatement
        Private Function ParseStopOrEndStatement() As StopOrEndStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.StopKeyword OrElse CurrentToken.Kind = SyntaxKind.EndKeyword, "ParseStopOrEndStatement called on wrong token.")

            Dim stopOrEndKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim stmtKind As SyntaxKind = If(stopOrEndKeyword.Kind = SyntaxKind.StopKeyword, SyntaxKind.StopStatement, SyntaxKind.EndStatement)

            Dim statement = SyntaxFactory.StopOrEndStatement(stmtKind, stopOrEndKeyword)

            Return statement
        End Function

        Private Function ParseUsingStatement() As UsingStatementSyntax
            Debug.Assert(CurrentToken.Kind = SyntaxKind.UsingKeyword, "ParseUsingStatement called on wrong token")

            Dim usingKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
            GetNextToken()

            Dim optionalExpression As ExpressionSyntax = Nothing
            Dim variables As CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(Of VariableDeclaratorSyntax) = Nothing

            Dim nextToken As SyntaxToken = PeekToken(1)

            ' change from Dev10: allowing as new with multiple variable names, e.g. "Using a, b As New C1()"
            If nextToken.Kind = SyntaxKind.AsKeyword OrElse
               nextToken.Kind = SyntaxKind.EqualsToken OrElse
               nextToken.Kind = SyntaxKind.CommaToken OrElse
               nextToken.Kind = SyntaxKind.QuestionToken Then

                variables = ParseVariableDeclaration(allowAsNewWith:=True)
            Else
                optionalExpression = ParseExpressionCore()
            End If

            'TODO - not resyncing here may cause errors to differ from Dev10.

            'No need to resync on error.  This will be handled by GetStatementTerminator

            Dim statement = SyntaxFactory.UsingStatement(usingKeyword, optionalExpression, variables)

            Return statement
        End Function

        Private Function ParseAwaitStatement() As ExpressionStatementSyntax

            Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso
                         DirectCast(CurrentToken, IdentifierTokenSyntax).ContextualKind = SyntaxKind.AwaitKeyword,
                         "ParseAwaitStatement called on wrong token.")

            Dim expression = ParseAwaitExpression()

            Debug.Assert(expression.Kind = SyntaxKind.AwaitExpression)

            If expression.ContainsDiagnostics Then
                expression = ResyncAt(expression)
            End If

            Dim statement = SyntaxFactory.ExpressionStatement(expression)

            Return statement

        End Function

        Private Function ParseYieldStatement() As YieldStatementSyntax
            Debug.Assert(DirectCast(CurrentToken, IdentifierTokenSyntax).ContextualKind = SyntaxKind.YieldKeyword)

            Dim yieldKeyword As KeywordSyntax = Nothing

            TryIdentifierAsContextualKeyword(CurrentToken, yieldKeyword)

            Debug.Assert(yieldKeyword IsNot Nothing AndAlso yieldKeyword.Kind = SyntaxKind.YieldKeyword)

            yieldKeyword = CheckFeatureAvailability(Feature.Iterators, yieldKeyword)
            GetNextToken()

            Dim expression As ExpressionSyntax = ParseExpressionCore()
            Dim result = SyntaxFactory.YieldStatement(yieldKeyword, expression)

            Return result

        End Function

        Private Function ParsePrintStatement() As PrintStatementSyntax
            Dim questionToken = DirectCast(CurrentToken, PunctuationSyntax)
            GetNextToken()

            Dim expression As ExpressionSyntax = ParseExpressionCore()
            Dim result = SyntaxFactory.PrintStatement(questionToken, expression)

            ' skip possible statement terminator
            Dim lookahead = PeekToken(1)

            If lookahead.Kind <> SyntaxKind.EndOfFileToken OrElse _scanner.Options.Kind = SourceCodeKind.Regular Then
                result = result.AddError(ERRID.ERR_UnexpectedExpressionStatement)
            End If

            Return result
        End Function

    End Class
End Namespace