| File: Parser\BlockContexts\SingleLineElseContext.vb | Web Access |
| Project: 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. Imports Microsoft.CodeAnalysis.VisualBasic.Syntax '----------------------------------------------------------------------------- ' Contains the definition of the BlockContext '----------------------------------------------------------------------------- Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Friend NotInheritable Class SingleLineElseContext Inherits SingleLineIfOrElseBlockContext Friend Sub New(kind As SyntaxKind, statement As StatementSyntax, prevContext As BlockContext) 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 Select Case node.Kind Case SyntaxKind.IfStatement ' Single line if statements can always open a new context. ' A single line if has a "then" on the line and is not followed by a ":", EOL or EOF. ' Multi line if's can only open a new context if they are followed by ":" Dim ifStmt = DirectCast(node, IfStatementSyntax) ' single line if If ifStmt.ThenKeyword IsNot Nothing AndAlso Not SyntaxFacts.IsTerminator(Parser.CurrentToken.Kind) Then Return MyBase.ProcessSyntax(node) End If ' multi-line if handled after select Case SyntaxKind.ElseIfStatement ' ElseIf ends the context. This is an error case. Let the outer context process them. ' Previously we explicitly added a missing terminator. Now, terminators are added automatically ' if a statement is added next to a statement. Return EndBlock(Nothing).ProcessSyntax(node) Case SyntaxKind.CatchStatement, SyntaxKind.FinallyStatement ' A Catch or Finally always closes a single line else Add(Parser.ReportSyntaxError(node, If(node.Kind = SyntaxKind.CatchStatement, ERRID.ERR_CatchNoMatchingTry, ERRID.ERR_FinallyNoMatchingTry))) Return Me.EndBlock(Nothing) End Select Return MyBase.ProcessSyntax(node) End Function Friend Overrides Function CreateBlockSyntax(endStmt As StatementSyntax) As VisualBasicSyntaxNode Debug.Assert(endStmt Is Nothing) Return CreateElseBlockSyntax() End Function Private Function CreateElseBlockSyntax() As SingleLineElseClauseSyntax Debug.Assert(BeginStatement IsNot Nothing) Dim elseStatement = DirectCast(BeginStatement, ElseStatementSyntax) Dim result = SyntaxFactory.SingleLineElseClause(elseStatement.ElseKeyword, OptionalBody()) FreeStatements() Return result End Function Friend Overrides Function EndBlock(statement As StatementSyntax) As BlockContext Debug.Assert(statement Is Nothing) Dim context = PrevBlock.ProcessSyntax(CreateElseBlockSyntax()) Debug.Assert(context Is PrevBlock) Return context.EndBlock(Nothing) End Function Friend Overrides Function ProcessStatementTerminator(lambdaContext As BlockContext) As BlockContext Dim token = Parser.CurrentToken Select Case token.Kind Case SyntaxKind.StatementTerminatorToken, SyntaxKind.EndOfFileToken EndBlock: ' A single-line Else is terminated at the end of the line. Dim context = EndBlock(Nothing) Return context.ProcessStatementTerminator(lambdaContext) Case SyntaxKind.ColonToken ' A colon only represents the end of the single-line Else ' if there are no statements before the colon. If _statements.Count > 0 Then Parser.ConsumeColonInSingleLineExpression() Return Me 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 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 If TreatOtherAsStatementTerminator Then Return ProcessOtherAsStatementTerminator() End If Return MyBase.ResyncAndProcessStatementTerminator(statement, lambdaContext) End If Parser.ConsumedStatementTerminator(allowLeadingMultilineTrivia:=False) Return Me End Select End Function 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 End Namespace