|
' 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 BlockContext
'-----------------------------------------------------------------------------
Imports Microsoft.CodeAnalysis.Syntax.InternalSyntax
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports InternalSyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.SyntaxFactory
Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Friend MustInherit Class BlockContext
Implements ISyntaxFactoryContext
Private _beginStatement As StatementSyntax
Protected _parser As Parser
Protected _statements As SyntaxListBuilder(Of StatementSyntax)
Private ReadOnly _kind As SyntaxKind
Private ReadOnly _endKind As SyntaxKind
Private ReadOnly _prev As BlockContext
Private ReadOnly _isWithinMultiLineLambda As Boolean
Private ReadOnly _isWithinSingleLineLambda As Boolean
Private ReadOnly _isWithinAsyncMethodOrLambda As Boolean
Private ReadOnly _isWithinIteratorMethodOrLambdaOrProperty As Boolean
Private ReadOnly _level As Integer
Private ReadOnly _syntaxFactory As ContextAwareSyntaxFactory
Protected Sub New(kind As SyntaxKind, statement As StatementSyntax, prev As BlockContext)
_beginStatement = statement
_kind = kind
_prev = prev
_syntaxFactory = New ContextAwareSyntaxFactory(Me)
If prev IsNot Nothing Then
_isWithinSingleLineLambda = prev._isWithinSingleLineLambda
_isWithinMultiLineLambda = prev._isWithinMultiLineLambda
End If
If Not _isWithinSingleLineLambda Then
_isWithinSingleLineLambda = SyntaxFacts.IsSingleLineLambdaExpression(_kind)
End If
If Not _isWithinMultiLineLambda Then
_isWithinMultiLineLambda = SyntaxFacts.IsMultiLineLambdaExpression(_kind)
End If
Select Case _kind
Case SyntaxKind.PropertyBlock
_isWithinIteratorMethodOrLambdaOrProperty = DirectCast(statement, PropertyStatementSyntax).Modifiers.Any(SyntaxKind.IteratorKeyword)
Case SyntaxKind.GetAccessorBlock,
SyntaxKind.SetAccessorBlock
Debug.Assert(_prev IsNot Nothing)
_isWithinIteratorMethodOrLambdaOrProperty = _prev.IsWithinIteratorMethodOrLambdaOrProperty
Case SyntaxKind.SubBlock,
SyntaxKind.FunctionBlock
_isWithinAsyncMethodOrLambda = DirectCast(statement, MethodStatementSyntax).Modifiers.Any(SyntaxKind.AsyncKeyword)
_isWithinIteratorMethodOrLambdaOrProperty = DirectCast(statement, MethodStatementSyntax).Modifiers.Any(SyntaxKind.IteratorKeyword)
Case SyntaxKind.SingleLineSubLambdaExpression,
SyntaxKind.MultiLineSubLambdaExpression,
SyntaxKind.SingleLineFunctionLambdaExpression,
SyntaxKind.MultiLineFunctionLambdaExpression
_isWithinAsyncMethodOrLambda = DirectCast(statement, LambdaHeaderSyntax).Modifiers.Any(SyntaxKind.AsyncKeyword)
_isWithinIteratorMethodOrLambdaOrProperty = DirectCast(statement, LambdaHeaderSyntax).Modifiers.Any(SyntaxKind.IteratorKeyword)
Case Else
If _prev IsNot Nothing Then
_isWithinAsyncMethodOrLambda = _prev.IsWithinAsyncMethodOrLambda
_isWithinIteratorMethodOrLambdaOrProperty = _prev.IsWithinIteratorMethodOrLambdaOrProperty
End If
End Select
_endKind = GetEndKind(kind)
_level = If(prev IsNot Nothing, prev.Level + 1, 0)
If prev IsNot Nothing Then
_parser = prev.Parser
_statements = _parser._pool.Allocate(Of StatementSyntax)()
End If
End Sub
Friend ReadOnly Property BeginStatement As StatementSyntax
Get
Return _beginStatement
End Get
End Property
Friend Sub GetBeginEndStatements(Of T1 As StatementSyntax, T2 As StatementSyntax)(ByRef beginStmt As T1, ByRef endStmt As T2)
Debug.Assert(BeginStatement IsNot Nothing)
beginStmt = DirectCast(BeginStatement, T1)
If endStmt Is Nothing Then
Dim errorId As ERRID
endStmt = DirectCast(CreateMissingEnd(errorId), T2)
If errorId <> Nothing Then
beginStmt = Parser.ReportSyntaxError(beginStmt, errorId)
End If
End If
End Sub
Friend Overridable Function KindEndsBlock(kind As SyntaxKind) As Boolean
Return _endKind = kind
End Function
Friend ReadOnly Property IsLineIf As Boolean
Get
Return _kind = SyntaxKind.SingleLineIfStatement OrElse _kind = SyntaxKind.SingleLineElseClause
End Get
End Property
Friend ReadOnly Property IsWithinLambda As Boolean
Get
Return _isWithinMultiLineLambda Or _isWithinSingleLineLambda
End Get
End Property
Friend ReadOnly Property IsWithinSingleLineLambda As Boolean
Get
Return _isWithinSingleLineLambda
End Get
End Property
Friend Overridable ReadOnly Property IsWithinAsyncMethodOrLambda As Boolean Implements ISyntaxFactoryContext.IsWithinAsyncMethodOrLambda
Get
Return _isWithinAsyncMethodOrLambda
End Get
End Property
Friend Overridable ReadOnly Property IsWithinIteratorContext As Boolean Implements ISyntaxFactoryContext.IsWithinIteratorContext
Get
Return _isWithinIteratorMethodOrLambdaOrProperty
End Get
End Property
Friend ReadOnly Property IsWithinIteratorMethodOrLambdaOrProperty As Boolean
Get
Return _isWithinIteratorMethodOrLambdaOrProperty
End Get
End Property
'TODO - Remove dependency on Parser
' For errors call error function directly
' for parsing, just pass a delegate to the context
Friend Property Parser As Parser
Get
Return _parser
End Get
Set(value As Parser)
Debug.Assert(BlockKind = SyntaxKind.CompilationUnit)
_parser = value
End Set
End Property
Friend ReadOnly Property SyntaxFactory As ContextAwareSyntaxFactory
Get
Return _syntaxFactory
End Get
End Property
Friend ReadOnly Property BlockKind As SyntaxKind
Get
Return _kind
End Get
End Property
Friend ReadOnly Property PrevBlock As BlockContext
Get
Return _prev
End Get
End Property
Friend ReadOnly Property Level As Integer
Get
Return _level
End Get
End Property
Friend Sub Add(node As VisualBasicSyntaxNode)
Debug.Assert(node IsNot Nothing)
_statements.Add(DirectCast(node, StatementSyntax))
End Sub
Friend ReadOnly Property Statements As SyntaxListBuilder(Of StatementSyntax)
Get
Return _statements
End Get
End Property
Friend Sub FreeStatements()
_parser._pool.Free(_statements)
End Sub
Friend Function Body() As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of StatementSyntax)
Dim result = _statements.ToList()
_statements.Clear()
Return result
End Function
''' <summary>
''' Returns the statement if there is exactly one in the body,
''' otherwise returns Nothing.
''' </summary>
Friend Function SingleStatementOrDefault() As StatementSyntax
Return If(_statements.Count = 1, _statements(0), Nothing)
End Function
''' <summary>
''' Return an empty body if the body is a single, zero-width EmptyStatement,
''' otherwise returns the entire body.
''' </summary>
Friend Function OptionalBody() As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of StatementSyntax)
Dim statement = SingleStatementOrDefault()
If statement IsNot Nothing AndAlso
statement.Kind = SyntaxKind.EmptyStatement AndAlso
statement.FullWidth = 0 Then
Return Nothing
End If
Return Body()
End Function
Friend Function Body(Of T As StatementSyntax)() As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of T)
Dim result = _statements.ToList(Of T)()
_statements.Clear()
Return result
End Function
' Same as Body(), but use a SyntaxListWithManyChildren if the
' body is large enough, so we get red node with weak children.
Friend Function BodyWithWeakChildren() As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of StatementSyntax)
If IsLargeEnoughNonEmptyStatementList(_statements) Then
Dim result = New CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of StatementSyntax)(
CodeAnalysis.Syntax.InternalSyntax.SyntaxList.List(CType(_statements, SyntaxListBuilder).ToArray))
_statements.Clear()
Return result
Else
Return Body()
End If
End Function
' Is this statement list non-empty, and large enough to make using weak children beneficial?
Private Shared Function IsLargeEnoughNonEmptyStatementList(statements As SyntaxListBuilder(Of StatementSyntax)) As Boolean
If statements.Count = 0 Then
Return False
ElseIf statements.Count <= 2 Then
' If we have a single statement (Count include separators), it might be small, like "return null", or large,
' like a loop or if or switch with many statements inside. Use the width as a proxy for
' how big it is. If it's small, its better to forgo a many children list anyway, since the
' weak reference would consume as much memory as is saved.
Return statements(0).Width > 60
Else
' For 2 or more statements, go ahead and create a many-children lists.
Return True
End If
End Function
Friend Function BaseDeclarations(Of T As InheritsOrImplementsStatementSyntax)() As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of T)
Dim result = _statements.ToList(Of T)()
_statements.Clear()
Return result
End Function
Friend MustOverride Function Parse() As StatementSyntax
Friend MustOverride Function ProcessSyntax(syntax As VisualBasicSyntaxNode) As BlockContext
Friend MustOverride Function CreateBlockSyntax(statement As StatementSyntax) As VisualBasicSyntaxNode
Friend MustOverride Function EndBlock(statement As StatementSyntax) As BlockContext
Friend MustOverride Function RecoverFromMismatchedEnd(statement As StatementSyntax) As BlockContext
Friend Overridable Function ResyncAndProcessStatementTerminator(statement As StatementSyntax, lambdaContext As BlockContext) As BlockContext
Dim unexpected = Parser.ResyncAt()
HandleAnyUnexpectedTokens(statement, unexpected)
Return ProcessStatementTerminator(lambdaContext)
End Function
Friend MustOverride Function ProcessStatementTerminator(lambdaContext As BlockContext) As BlockContext
Friend MustOverride ReadOnly Property IsSingleLine As Boolean
Friend Overridable ReadOnly Property IsLambda As Boolean
Get
Return False
End Get
End Property
Private Sub HandleAnyUnexpectedTokens(currentStmt As StatementSyntax, unexpected As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of SyntaxToken))
If unexpected.Node Is Nothing Then
Return
End If
Dim index As Integer
Dim stmt As StatementSyntax
If _statements.Count = 0 Then
index = -1
stmt = _beginStatement
Else
index = _statements.Count - 1
stmt = _statements(index)
End If
Debug.Assert(stmt IsNot Nothing)
If Not currentStmt.ContainsDiagnostics AndAlso Not unexpected.ContainsDiagnostics Then
stmt = stmt.AddTrailingSyntax(unexpected, ERRID.ERR_ExpectedEOS)
Else
' Don't report ERRID_ExpectedEOS when the statement is known to be bad
stmt = stmt.AddTrailingSyntax(unexpected)
End If
If index = -1 Then
_beginStatement = stmt
Else
_statements(index) = stmt
End If
End Sub
<Flags()>
Friend Enum LinkResult
NotUsed = 0 ' The syntax cannot be used. Force a reparse.
Used = 1 ' Reuse the syntax.
SkipTerminator = 2 ' Syntax is not followed by a statement terminator.
MissingTerminator = 4 ' Statement terminator is missing.
TerminatorFlags = 6 ' Combination of the above 2 flags.
Crumble = 8 ' Crumble the syntax and try to reuse the parts.
End Enum
Friend MustOverride Function TryLinkSyntax(node As VisualBasicSyntaxNode, ByRef newContext As BlockContext) As LinkResult
Friend Function LinkSyntax(node As VisualBasicSyntaxNode) As BlockContext
Debug.Assert(node IsNot Nothing)
Dim kind As SyntaxKind = node.Kind
Dim context = Me
While context IsNot Nothing
If context.KindEndsBlock(kind) Then
' Note, end statements in single line lambdas and single line if's can never close an outer context.
Dim scope = FindNearestLambdaOrSingleLineIf(context)
If scope IsNot Nothing Then
If scope.IsLambda Then
' Don't allow end statements from outer blocks to terminate single line statement lambdas.
' Single line if's have a special error for this case but single line lambdas don't.
Exit While
Else
' Don't allow end statements from outer blocks to terminate single line ifs.
node = Parser.ReportSyntaxError(node, ERRID.ERR_BogusWithinLineIf)
Return ProcessSyntax(node)
Debug.Assert(scope.IsLineIf)
End If
Else
If context IsNot Me Then
'This statement ends a block higher up.
'End all blocks from Me up to this one with a missing ends.
RecoverFromMissingEnd(context)
End If
'Add the block to the context above
Return context.EndBlock(DirectCast(node, StatementSyntax))
End If
ElseIf SyntaxFacts.IsEndBlockLoopOrNextStatement(kind) Then
' See if this kind closes an enclosing statement context
context = context.PrevBlock
Else
Return ProcessSyntax(node)
End If
End While
'No match was found for the end block statement
'Add it to the current context and leave the context unchanged
Return RecoverFromMismatchedEnd(DirectCast(node, StatementSyntax))
End Function
Friend Function UseSyntax(node As VisualBasicSyntaxNode, ByRef newContext As BlockContext, Optional AddMissingTerminator As Boolean = False) As LinkResult
' get off the current node as we are definitely using it and LinkStatement may need to look at next token
Parser.GetNextSyntaxNode()
' TODO: this will add an error to the statement. Perhaps duplicating it
' context-sensitive errors should be filtered out before re-using nodes.
' or better we should put contextual errors on the actual block not on the offending node (if possible).
newContext = LinkSyntax(node)
If AddMissingTerminator Then
Return LinkResult.Used Or LinkResult.MissingTerminator
End If
Return LinkResult.Used
End Function
Friend Function TryUseStatement(node As VisualBasicSyntaxNode, ByRef newContext As BlockContext) As LinkResult
Dim statement = TryCast(node, StatementSyntax)
If statement IsNot Nothing Then
' get off the current node as we are definitely using it and LinkStatement may need to look at next token
Return UseSyntax(statement, newContext)
Else
Return LinkResult.NotUsed
End If
End Function
' Returns Nothing if the statement isn't processed
Friend Function TryProcessExecutableStatement(node As VisualBasicSyntaxNode) As BlockContext
' top-level statements
Select Case node.Kind
Case SyntaxKind.SingleLineIfStatement
Add(node)
Case SyntaxKind.IfStatement
' A single line if has a "then" on the line and is not followed by a ":", EOL or EOF.
' It is OK for else to follow a single line if. i.e
' "if true then if true then else else
Dim ifStmt = DirectCast(node, IfStatementSyntax)
If ifStmt.ThenKeyword IsNot Nothing AndAlso Not SyntaxFacts.IsTerminator(Parser.CurrentToken.Kind) Then
Return New SingleLineIfBlockContext(ifStmt, Me)
Else
Return New IfBlockContext(ifStmt, Me)
End If
Case SyntaxKind.ElseStatement
' davidsch
' This error used to be reported in ParseStatementInMethodBody. Move to context.
' It used to be this error with a note that Semantics doesn't like an ELSEIF without an IF.
' Fully parse for now.
' ReportUnrecognizedStatementError(ERRID_ElseIfNoMatchingIf, ErrorInConstruct)
Add(Parser.ReportSyntaxError(node, ERRID.ERR_ElseNoMatchingIf))
Case SyntaxKind.ElseIfStatement
' davidsch
' This error used to be reported in ParseStatementInMethodBody. Move to context.
' It used to be this error with a note that Semantics doesn't like an ELSEIF without an IF.
' Fully parse for now.
' ReportUnrecognizedStatementError(ERRID_ElseIfNoMatchingIf, ErrorInConstruct)
Add(Parser.ReportSyntaxError(node, ERRID.ERR_ElseIfNoMatchingIf))
Case SyntaxKind.SimpleDoStatement,
SyntaxKind.DoWhileStatement,
SyntaxKind.DoUntilStatement
Return New DoLoopBlockContext(DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.ForStatement, SyntaxKind.ForEachStatement
Return New ForBlockContext(DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.SelectStatement
Return New SelectBlockContext(DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.CaseStatement
'TODO - davidsch
' In dev10 the error is reported on the CASE not the statement. If needed this error can be
' moved to ParseCaseStatement.
Add(Parser.ReportSyntaxError(node, ERRID.ERR_CaseNoSelect))
Case SyntaxKind.CaseElseStatement
'TODO - davidsch
' In dev10 the error is reported on the CASE not the statement. If needed this error can be
' moved to ParseCaseStatement.
Add(Parser.ReportSyntaxError(node, ERRID.ERR_CaseElseNoSelect))
Case SyntaxKind.WhileStatement
Return New StatementBlockContext(SyntaxKind.WhileBlock, DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.WithStatement
Return New StatementBlockContext(SyntaxKind.WithBlock, DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.SyncLockStatement
Return New StatementBlockContext(SyntaxKind.SyncLockBlock, DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.UsingStatement
Return New StatementBlockContext(SyntaxKind.UsingBlock, DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.TryStatement
Return New TryBlockContext(DirectCast(node, StatementSyntax), Me)
Case SyntaxKind.CatchStatement, SyntaxKind.FinallyStatement
Dim context = FindNearestInSameMethodScope(SyntaxKind.TryBlock, SyntaxKind.CatchBlock, SyntaxKind.FinallyBlock)
If context IsNot Nothing Then
RecoverFromMissingEnd(context)
Return context.ProcessSyntax(DirectCast(node, StatementSyntax))
End If
' In dev10 the error is reported on the CATCH not the statement.
' If needed this error can be moved to ParseCatchStatement.
Add(Parser.ReportSyntaxError(node, If(node.Kind = SyntaxKind.CatchStatement, ERRID.ERR_CatchNoMatchingTry, ERRID.ERR_FinallyNoMatchingTry)))
Case SyntaxKind.SelectBlock,
SyntaxKind.WhileBlock,
SyntaxKind.WithBlock,
SyntaxKind.SyncLockBlock,
SyntaxKind.UsingBlock,
SyntaxKind.TryBlock,
SyntaxKind.SimpleDoLoopBlock,
SyntaxKind.DoWhileLoopBlock,
SyntaxKind.DoUntilLoopBlock,
SyntaxKind.DoLoopWhileBlock,
SyntaxKind.DoLoopUntilBlock,
SyntaxKind.ForBlock,
SyntaxKind.ForEachBlock,
SyntaxKind.SingleLineIfStatement,
SyntaxKind.MultiLineIfBlock
' Handle any block that can be created by this context
Add(node)
Case Else
If Not TypeOf node Is ExecutableStatementSyntax Then
Return Nothing
End If
Add(node)
End Select
Return Me
End Function
Friend Function TryLinkStatement(node As VisualBasicSyntaxNode, ByRef newContext As BlockContext) As LinkResult
newContext = Nothing
Select Case node.Kind
Case SyntaxKind.SelectBlock
Return UseSyntax(node, newContext, DirectCast(node, SelectBlockSyntax).EndSelectStatement.IsMissing)
Case SyntaxKind.WhileBlock
Return UseSyntax(node, newContext, DirectCast(node, WhileBlockSyntax).EndWhileStatement.IsMissing)
Case SyntaxKind.WithBlock
Return UseSyntax(node, newContext, DirectCast(node, WithBlockSyntax).EndWithStatement.IsMissing)
Case SyntaxKind.SyncLockBlock
Return UseSyntax(node, newContext, DirectCast(node, SyncLockBlockSyntax).EndSyncLockStatement.IsMissing)
Case SyntaxKind.UsingBlock
Return UseSyntax(node, newContext, DirectCast(node, UsingBlockSyntax).EndUsingStatement.IsMissing)
Case SyntaxKind.TryBlock
Return UseSyntax(node, newContext, DirectCast(node, TryBlockSyntax).EndTryStatement.IsMissing)
Case SyntaxKind.SimpleDoLoopBlock,
SyntaxKind.DoWhileLoopBlock,
SyntaxKind.DoUntilLoopBlock,
SyntaxKind.DoLoopWhileBlock,
SyntaxKind.DoLoopUntilBlock
Return UseSyntax(node, newContext, DirectCast(node, DoLoopBlockSyntax).LoopStatement.IsMissing)
Case SyntaxKind.ForBlock,
SyntaxKind.ForEachBlock
' The EndOpt syntax can influence the next context in case it contains
' several control variables. If they are still valid needs to be checked in the ForBlockContext.
' This is the reason why we can't simply reuse the syntax here.
newContext = Me
Return LinkResult.Crumble
Case SyntaxKind.SingleLineIfStatement
Return UseSyntax(node, newContext)
Case SyntaxKind.MultiLineIfBlock
Return UseSyntax(node, newContext, DirectCast(node, MultiLineIfBlockSyntax).EndIfStatement.IsMissing)
Case SyntaxKind.NextStatement
' Don't reuse a next statement. The parser matches the variable list with the for context blocks.
' In order to reuse the next statement that error checking needs to be moved from the parser to the
' contexts. For now, crumble and reparse. The next statement is small and fast to parse.
newContext = Me
Return LinkResult.NotUsed
Case Else
Return TryUseStatement(node, newContext)
End Select
End Function
Private Function CreateMissingEnd(ByRef errorId As ERRID) As StatementSyntax
Return CreateMissingEnd(BlockKind, errorId)
End Function
Private Function CreateMissingEnd(kind As SyntaxKind, ByRef errorId As ERRID) As StatementSyntax
Dim endStmt As StatementSyntax
Dim missingEndKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.EndKeyword)
Select Case kind
Case SyntaxKind.NamespaceBlock
endStmt = SyntaxFactory.EndNamespaceStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.NamespaceKeyword))
errorId = ERRID.ERR_ExpectedEndNamespace
Case SyntaxKind.ModuleBlock
endStmt = SyntaxFactory.EndModuleStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.ModuleKeyword))
errorId = ERRID.ERR_ExpectedEndModule
Case SyntaxKind.ClassBlock
endStmt = SyntaxFactory.EndClassStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.ClassKeyword))
errorId = ERRID.ERR_ExpectedEndClass
Case SyntaxKind.StructureBlock
endStmt = SyntaxFactory.EndStructureStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.StructureKeyword))
errorId = ERRID.ERR_ExpectedEndStructure
Case SyntaxKind.InterfaceBlock
endStmt = SyntaxFactory.EndInterfaceStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.InterfaceKeyword))
errorId = ERRID.ERR_MissingEndInterface
Case SyntaxKind.EnumBlock
endStmt = SyntaxFactory.EndEnumStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.EnumKeyword))
errorId = ERRID.ERR_MissingEndEnum
Case SyntaxKind.SubBlock,
SyntaxKind.ConstructorBlock
endStmt = SyntaxFactory.EndSubStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.SubKeyword))
'TODO - davidsch make these expected error message names consistent. Some are EndXXExpected and others are ExpectedEndXX
errorId = ERRID.ERR_EndSubExpected
Case SyntaxKind.MultiLineSubLambdaExpression
endStmt = SyntaxFactory.EndSubStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.SubKeyword))
errorId = ERRID.ERR_MultilineLambdaMissingSub
Case SyntaxKind.FunctionBlock
endStmt = SyntaxFactory.EndFunctionStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.FunctionKeyword))
errorId = ERRID.ERR_EndFunctionExpected
Case SyntaxKind.MultiLineFunctionLambdaExpression
endStmt = SyntaxFactory.EndFunctionStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.FunctionKeyword))
errorId = ERRID.ERR_MultilineLambdaMissingFunction
Case SyntaxKind.OperatorBlock
endStmt = SyntaxFactory.EndOperatorStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.OperatorKeyword))
errorId = ERRID.ERR_EndOperatorExpected
Case SyntaxKind.PropertyBlock
endStmt = SyntaxFactory.EndPropertyStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.PropertyKeyword))
'TODO rename this enum for consistency ERRID_MissingEndProperty
errorId = ERRID.ERR_EndProp
Case SyntaxKind.GetAccessorBlock
endStmt = SyntaxFactory.EndGetStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.GetKeyword))
errorId = ERRID.ERR_MissingEndGet
Case SyntaxKind.SetAccessorBlock
endStmt = SyntaxFactory.EndSetStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.SetKeyword))
errorId = ERRID.ERR_MissingEndSet
Case SyntaxKind.EventBlock
endStmt = SyntaxFactory.EndEventStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.EventKeyword))
'TODO rename this enum for consistency ERRID_MissingEndProperty
errorId = ERRID.ERR_MissingEndEvent
Case SyntaxKind.AddHandlerAccessorBlock
endStmt = SyntaxFactory.EndAddHandlerStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.AddHandlerKeyword))
errorId = ERRID.ERR_MissingEndAddHandler
Case SyntaxKind.RemoveHandlerAccessorBlock
endStmt = SyntaxFactory.EndRemoveHandlerStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.RemoveHandlerKeyword))
errorId = ERRID.ERR_MissingEndRemoveHandler
Case SyntaxKind.RaiseEventAccessorBlock
endStmt = SyntaxFactory.EndRaiseEventStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.RaiseEventKeyword))
errorId = ERRID.ERR_MissingEndRaiseEvent
Case SyntaxKind.MultiLineIfBlock, SyntaxKind.ElseIfBlock, SyntaxKind.ElseBlock
endStmt = SyntaxFactory.EndIfStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.IfKeyword))
errorId = ERRID.ERR_ExpectedEndIf
Case SyntaxKind.SimpleDoLoopBlock, SyntaxKind.DoWhileLoopBlock
endStmt = SyntaxFactory.SimpleLoopStatement(InternalSyntaxFactory.MissingKeyword(SyntaxKind.LoopKeyword), Nothing)
errorId = ERRID.ERR_ExpectedLoop
Case SyntaxKind.WhileBlock
endStmt = SyntaxFactory.EndWhileStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.WhileKeyword))
errorId = ERRID.ERR_ExpectedEndWhile
Case SyntaxKind.WithBlock
endStmt = SyntaxFactory.EndWithStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.WithKeyword))
errorId = ERRID.ERR_ExpectedEndWith
Case SyntaxKind.ForBlock, SyntaxKind.ForEachBlock
endStmt = SyntaxFactory.NextStatement(InternalSyntaxFactory.MissingKeyword(SyntaxKind.NextKeyword), Nothing)
errorId = ERRID.ERR_ExpectedNext
Case SyntaxKind.SyncLockBlock
endStmt = SyntaxFactory.EndSyncLockStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.SyncLockKeyword))
errorId = ERRID.ERR_ExpectedEndSyncLock
Case SyntaxKind.SelectBlock
endStmt = SyntaxFactory.EndSelectStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.SelectKeyword))
errorId = ERRID.ERR_ExpectedEndSelect
Case SyntaxKind.TryBlock
endStmt = SyntaxFactory.EndTryStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.TryKeyword))
errorId = ERRID.ERR_ExpectedEndTry
Case SyntaxKind.UsingBlock
endStmt = SyntaxFactory.EndUsingStatement(missingEndKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.UsingKeyword))
errorId = ERRID.ERR_ExpectedEndUsing
Case Else
Throw ExceptionUtilities.UnexpectedValue(kind)
End Select
Return endStmt
End Function
Private Shared Function GetEndKind(kind As SyntaxKind) As SyntaxKind
Select Case kind
Case SyntaxKind.CompilationUnit,
SyntaxKind.SingleLineFunctionLambdaExpression,
SyntaxKind.SingleLineSubLambdaExpression
Return SyntaxKind.None
Case SyntaxKind.NamespaceBlock
Return SyntaxKind.EndNamespaceStatement
Case SyntaxKind.ModuleBlock
Return SyntaxKind.EndModuleStatement
Case SyntaxKind.ClassBlock
Return SyntaxKind.EndClassStatement
Case SyntaxKind.StructureBlock
Return SyntaxKind.EndStructureStatement
Case SyntaxKind.InterfaceBlock
Return SyntaxKind.EndInterfaceStatement
Case SyntaxKind.EnumBlock
Return SyntaxKind.EndEnumStatement
Case SyntaxKind.SubBlock,
SyntaxKind.ConstructorBlock,
SyntaxKind.MultiLineSubLambdaExpression
Return SyntaxKind.EndSubStatement
Case SyntaxKind.FunctionBlock,
SyntaxKind.MultiLineFunctionLambdaExpression
Return SyntaxKind.EndFunctionStatement
Case SyntaxKind.OperatorBlock
Return SyntaxKind.EndOperatorStatement
Case SyntaxKind.PropertyBlock
Return SyntaxKind.EndPropertyStatement
Case SyntaxKind.GetAccessorBlock
Return SyntaxKind.EndGetStatement
Case SyntaxKind.SetAccessorBlock
Return SyntaxKind.EndSetStatement
Case SyntaxKind.EventBlock
Return SyntaxKind.EndEventStatement
Case SyntaxKind.AddHandlerAccessorBlock
Return SyntaxKind.EndAddHandlerStatement
Case SyntaxKind.RemoveHandlerAccessorBlock
Return SyntaxKind.EndRemoveHandlerStatement
Case SyntaxKind.RaiseEventAccessorBlock
Return SyntaxKind.EndRaiseEventStatement
Case SyntaxKind.MultiLineIfBlock, SyntaxKind.ElseIfBlock, SyntaxKind.ElseBlock
Return SyntaxKind.EndIfStatement
Case SyntaxKind.SingleLineIfStatement, SyntaxKind.SingleLineElseClause
Return SyntaxKind.None
Case SyntaxKind.SimpleDoLoopBlock,
SyntaxKind.DoWhileLoopBlock
Return SyntaxKind.SimpleLoopStatement
Case SyntaxKind.WhileBlock
Return SyntaxKind.EndWhileStatement
Case SyntaxKind.ForBlock, SyntaxKind.ForEachBlock
Return SyntaxKind.NextStatement
Case SyntaxKind.WithBlock
Return SyntaxKind.EndWithStatement
Case SyntaxKind.SyncLockBlock
Return SyntaxKind.EndSyncLockStatement
Case SyntaxKind.SelectBlock, SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock
Return SyntaxKind.EndSelectStatement
Case SyntaxKind.TryBlock, SyntaxKind.CatchBlock, SyntaxKind.FinallyBlock
Return SyntaxKind.EndTryStatement
Case SyntaxKind.UsingBlock
Return SyntaxKind.EndUsingStatement
Case Else
Throw ExceptionUtilities.UnexpectedValue(kind)
End Select
End Function
End Class
End Namespace
|