提交 c91de6da 编写于 作者: A AlekseyTs 提交者: GitHub

Merge pull request #14822 from AlekseyTs/Issue14761_1

Adjust the way parser handles line-If termination.
......@@ -301,17 +301,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Friend MustOverride Function ProcessStatementTerminator(lambdaContext As BlockContext) As BlockContext
Friend Overridable Function ProcessElseAsStatementTerminator() As BlockContext
' Nothing to do. The Else should be processed as a
' statement associated with this context.
Return Me
End Function
Friend Overridable Function ProcessOtherAsStatementTerminator() As BlockContext
' Nothing to do.
Return Me
End Function
Friend MustOverride ReadOnly Property IsSingleLine As Boolean
Friend Overridable ReadOnly Property IsLambda As Boolean
......
......@@ -14,6 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
MyBase.New(kind, statement, prevContext)
Debug.Assert(kind = SyntaxKind.SingleLineElseClause)
Debug.Assert(prevContext.BlockKind = SyntaxKind.SingleLineIfStatement)
End Sub
Friend Overrides Function ProcessSyntax(node As VisualBasicSyntaxNode) As BlockContext
......@@ -92,34 +93,90 @@ EndBlock:
End If
GoTo EndBlock
Case Else
Throw ExceptionUtilities.UnexpectedValue(token.Kind)
End Select
End Function
Friend Overrides Function ResyncAndProcessStatementTerminator(statement As StatementSyntax, lambdaContext As BlockContext) As BlockContext
Dim token = Parser.CurrentToken
Select Case token.Kind
Case SyntaxKind.StatementTerminatorToken, SyntaxKind.EndOfFileToken, SyntaxKind.ColonToken
Return ProcessStatementTerminator(lambdaContext)
Case SyntaxKind.ElseKeyword
' Terminated by Else from containing block.
Parser.ConsumedStatementTerminator(allowLeadingMultilineTrivia:=False)
Return ProcessElseAsStatementTerminator()
If TreatElseAsStatementTerminator Then
' Terminated by Else from containing block.
Parser.ConsumedStatementTerminator(allowLeadingMultilineTrivia:=False)
Return ProcessElseAsStatementTerminator()
End If
Return MyBase.ResyncAndProcessStatementTerminator(statement, lambdaContext)
Case Else
' Terminated if we've already seen at least one statement.
If _statements.Count > 0 Then
Return ProcessOtherAsStatementTerminator()
End If
' Terminated if the next token can follow a statement.
If Parser.CanFollowStatementButIsNotSelectFollowingExpression(token) Then
Return ProcessOtherAsStatementTerminator()
If TreatOtherAsStatementTerminator Then
Return ProcessOtherAsStatementTerminator()
End If
Return MyBase.ResyncAndProcessStatementTerminator(statement, lambdaContext)
End If
Parser.ConsumedStatementTerminator(allowLeadingMultilineTrivia:=False)
Return Me
End Select
End Function
Friend Overrides Function ProcessElseAsStatementTerminator() As BlockContext
Dim context = EndBlock(Nothing)
Return context.ProcessElseAsStatementTerminator()
End Function
Friend Overrides Function ProcessOtherAsStatementTerminator() As BlockContext
Dim context = EndBlock(Nothing)
Return context.ProcessOtherAsStatementTerminator()
Private ReadOnly Property TreatElseAsStatementTerminator As Boolean
Get
' We can treat 'Else' as a valid statement terminator only
' if there is a line-If without Else up the block context chain, or
' if we are inside a single-line statement lambda and the 'Else' terminates the lambda.
Debug.Assert(BlockKind = SyntaxKind.SingleLineElseClause)
Debug.Assert(PrevBlock.BlockKind = SyntaxKind.SingleLineIfStatement)
Dim possiblyLineIfWithoutElse = PrevBlock.PrevBlock
While possiblyLineIfWithoutElse.BlockKind <> SyntaxKind.SingleLineIfStatement
Select Case possiblyLineIfWithoutElse.BlockKind
Case SyntaxKind.SingleLineElseClause
' This is a line-If with Else, jump out of it
Debug.Assert(possiblyLineIfWithoutElse.PrevBlock.BlockKind = SyntaxKind.SingleLineIfStatement)
possiblyLineIfWithoutElse = possiblyLineIfWithoutElse.PrevBlock.PrevBlock
Case SyntaxKind.SingleLineSubLambdaExpression
Return True
Case Else
Return False
End Select
End While
Debug.Assert(possiblyLineIfWithoutElse.BlockKind = SyntaxKind.SingleLineIfStatement)
Return True
End Get
End Property
Private Function ProcessElseAsStatementTerminator() As BlockContext
Dim context = EndBlock(Nothing) ' This gets us out of entire line-if context
While context.BlockKind <> SyntaxKind.SingleLineIfStatement
Select Case context.BlockKind
Case SyntaxKind.SingleLineElseClause
' This is a line-If with Else, jump out of it
context = context.EndBlock(Nothing) ' This gets us out of entire line-if context
Case SyntaxKind.SingleLineSubLambdaExpression
' This will force termination of the single line lambda
Return context.PrevBlock
Case Else
Throw ExceptionUtilities.UnexpectedValue(context.BlockKind)
End Select
End While
Return context
End Function
End Class
......
......@@ -11,6 +11,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Inherits SingleLineIfOrElseBlockContext
Private _optionalElseClause As SingleLineElseClauseSyntax
Private _haveElseClause As Boolean
Friend Sub New(statement As StatementSyntax, prevContext As BlockContext)
MyBase.New(SyntaxKind.SingleLineIfStatement, statement, prevContext)
......@@ -36,6 +37,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Return Me.EndBlock(Nothing)
Case SyntaxKind.ElseStatement
If _haveElseClause Then
Throw ExceptionUtilities.Unreachable
End If
_haveElseClause = True
Return New SingleLineElseContext(SyntaxKind.SingleLineElseClause, DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.SingleLineElseClause
......@@ -90,6 +96,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Parser.ConsumeColonInSingleLineExpression()
Return Me
Case Else
Throw ExceptionUtilities.UnexpectedValue(token.Kind)
End Select
End Function
Friend Overrides Function ResyncAndProcessStatementTerminator(statement As StatementSyntax, lambdaContext As BlockContext) As BlockContext
Dim token = Parser.CurrentToken
Select Case token.Kind
Case SyntaxKind.StatementTerminatorToken, SyntaxKind.EndOfFileToken, SyntaxKind.ColonToken
Return ProcessStatementTerminator(lambdaContext)
Case SyntaxKind.ElseKeyword
Parser.ConsumedStatementTerminator(allowLeadingMultilineTrivia:=False)
Return Me
......@@ -97,19 +114,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Case Else
' Terminated if we've already seen at least one statement.
If _statements.Count > 0 Then
Return ProcessOtherAsStatementTerminator()
If TreatOtherAsStatementTerminator Then
Return ProcessOtherAsStatementTerminator()
End If
Return MyBase.ResyncAndProcessStatementTerminator(statement, lambdaContext)
End If
Parser.ConsumedStatementTerminator(allowLeadingMultilineTrivia:=False)
Return Me
End Select
End Function
Friend Overrides Function ProcessOtherAsStatementTerminator() As BlockContext
Dim context = EndBlock(Nothing)
Return context.ProcessOtherAsStatementTerminator()
End Function
End Class
End Namespace
......@@ -9,15 +9,54 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
MyBase.New(kind, statement, prevContext)
End Sub
Friend Overrides Function ResyncAndProcessStatementTerminator(statement As StatementSyntax, lambdaContext As BlockContext) As BlockContext
Return ProcessStatementTerminator(lambdaContext)
End Function
Friend Overrides ReadOnly Property IsSingleLine As Boolean
Get
Return True
End Get
End Property
Protected ReadOnly Property TreatOtherAsStatementTerminator As Boolean
Get
' Is this line-If, or immediately enclosing line-If(s),
' a body of a single-line statement lambda. Then the token
' terminates the lambda
Dim parentContext As BlockContext = PrevBlock
Do
Select Case parentContext.BlockKind
Case SyntaxKind.SingleLineElseClause,
SyntaxKind.SingleLineIfStatement
parentContext = parentContext.PrevBlock
Case SyntaxKind.SingleLineSubLambdaExpression
Return True
Case Else
Return False
End Select
Loop
End Get
End Property
Protected Function ProcessOtherAsStatementTerminator() As BlockContext
Dim context = EndBlock(Nothing)
Do
Select Case context.BlockKind
Case SyntaxKind.SingleLineElseClause,
SyntaxKind.SingleLineIfStatement
context = context.EndBlock(Nothing)
Case SyntaxKind.SingleLineSubLambdaExpression
' This will force termination of the single line lambda
Return context.PrevBlock
Case Else
Throw ExceptionUtilities.UnexpectedValue(context.BlockKind)
End Select
Loop
End Function
End Class
End Namespace
......@@ -85,16 +85,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Return PrevBlock
End Function
Friend Overrides Function ProcessElseAsStatementTerminator() As BlockContext
' Else from outer If terminates the lambda.
Return PrevBlock
End Function
Friend Overrides Function ProcessOtherAsStatementTerminator() As BlockContext
' Other non-terminator terminates the lambda.
Return PrevBlock
End Function
Friend Overrides ReadOnly Property IsSingleLine As Boolean
Get
Return True
......
......@@ -62,11 +62,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
' // enabled), and it isn't possible to look back past the first token of a
' // line, so test if this is the first token of the last read line.
' // (bug 32704) "else" is a special case in the construct "if foo then resume else statement"
' REM and XmlDocComment are now trivia so they have been removed from the test
Return SyntaxFacts.IsTerminator(t.Kind) OrElse
(Context.IsLineIf AndAlso t.Kind = SyntaxKind.ElseKeyword)
Return SyntaxFacts.IsTerminator(t.Kind)
End Function
' // Parser::CanFollowStatement -- Can this token follow a complete statement?
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册