/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Parser/ParseInterpolatedString.vb
337 строк
15 KB
Youssef Victor
IDE0036 - VB
27 авг 2020, 18:40
27 авг 2020, 18:40
c55795e
Код
Авторство
О чём код?
' 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 System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.Syntax.InternalSyntax Imports InternalSyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.SyntaxFactory ' '============ Methods for parsing portions of executable statements == ' Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Partial Friend Class Parser Private Function ParseInterpolatedStringExpression() As InterpolatedStringExpressionSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.DollarSignDoubleQuoteToken, "ParseInterpolatedStringExpression called on the wrong token.") ResetCurrentToken(ScannerState.InterpolatedStringPunctuation) Debug.Assert(CurrentToken.Kind = SyntaxKind.DollarSignDoubleQuoteToken, "Rescanning $"" failed.") Dim dollarSignDoubleQuoteToken = DirectCast(CurrentToken, PunctuationSyntax) GetNextToken(ScannerState.InterpolatedStringContent) Dim contentBuilder = _pool.Allocate(Of InterpolatedStringContentSyntax) Dim doubleQuoteToken As PunctuationSyntax Dim skipped As SyntaxListBuilder(Of SyntaxToken) = Nothing Do Dim content As InterpolatedStringContentSyntax Select Case CurrentToken.Kind Case SyntaxKind.InterpolatedStringTextToken Dim textToken = DirectCast(CurrentToken, InterpolatedStringTextTokenSyntax) ' At this point we're either right before an {, an } (error), or a "". GetNextToken(ScannerState.InterpolatedStringPunctuation) Debug.Assert(CurrentToken.Kind <> SyntaxKind.InterpolatedStringTextToken, "Two interpolated string text literal tokens encountered back-to-back. " & "Scanner should have scanned these as a single token.") content = SyntaxFactory.InterpolatedStringText(textToken) Case SyntaxKind.OpenBraceToken content = ParseInterpolatedStringInterpolation() Case SyntaxKind.CloseBraceToken If skipped.IsNull Then skipped = _pool.Allocate(Of SyntaxToken) End If skipped.Add(CurrentToken) GetNextToken(ScannerState.InterpolatedStringContent) Continue Do Case SyntaxKind.DoubleQuoteToken doubleQuoteToken = DirectCast(CurrentToken, PunctuationSyntax) GetNextToken() Exit Do Case SyntaxKind.EndOfInterpolatedStringToken doubleQuoteToken = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.DoubleQuoteToken) GetNextToken(ScannerState.VB) Exit Do Case Else doubleQuoteToken = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.DoubleQuoteToken) Exit Do End Select If Not skipped.IsNull Then content = AddLeadingSyntax(content, _pool.ToListAndFree(skipped), ERRID.ERR_Syntax) skipped = Nothing End If contentBuilder.Add(content) Loop If Not skipped.IsNull Then doubleQuoteToken = AddLeadingSyntax(doubleQuoteToken, _pool.ToListAndFree(skipped), ERRID.ERR_Syntax) skipped = Nothing End If Dim node = SyntaxFactory.InterpolatedStringExpression(dollarSignDoubleQuoteToken, _pool.ToListAndFree(contentBuilder), doubleQuoteToken) Return CheckFeatureAvailability(Feature.InterpolatedStrings, node) End Function Private Function ParseInterpolatedStringInterpolation() As InterpolationSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.OpenBraceToken, "ParseInterpolatedStringEmbeddedExpression called on the wrong token.") Dim colonToken As PunctuationSyntax = Nothing Dim excessText As String = Nothing Dim openBraceToken = DirectCast(CurrentToken, PunctuationSyntax) GetNextToken(ScannerState.VB) Dim expression As ExpressionSyntax If CurrentToken.Kind = SyntaxKind.ColonToken Then openBraceToken = DirectCast(RemoveTrailingColonTriviaAndConvertToColonToken(openBraceToken, colonToken, excessText), PunctuationSyntax) expression = ReportSyntaxError(InternalSyntaxFactory.MissingExpression(), ERRID.ERR_ExpectedExpression) Else expression = ParseExpressionCore() ' Scanned this as a terminator. Fix it. If CurrentToken.Kind = SyntaxKind.ColonToken Then expression = DirectCast(RemoveTrailingColonTriviaAndConvertToColonToken(expression, colonToken, excessText), ExpressionSyntax) End If End If Dim alignmentClauseOpt As InterpolationAlignmentClauseSyntax If CurrentToken.Kind = SyntaxKind.CommaToken Then Debug.Assert(colonToken Is Nothing) Dim commaToken = DirectCast(CurrentToken, PunctuationSyntax) GetNextToken(ScannerState.VB) If CurrentToken.Kind = SyntaxKind.ColonToken Then commaToken = DirectCast(RemoveTrailingColonTriviaAndConvertToColonToken(commaToken, colonToken, excessText), PunctuationSyntax) End If Dim signTokenOpt As PunctuationSyntax If CurrentToken.Kind = SyntaxKind.MinusToken OrElse CurrentToken.Kind = SyntaxKind.PlusToken Then signTokenOpt = DirectCast(CurrentToken, PunctuationSyntax) GetNextToken(ScannerState.VB) If CurrentToken.Kind = SyntaxKind.ColonToken Then signTokenOpt = DirectCast(RemoveTrailingColonTriviaAndConvertToColonToken(signTokenOpt, colonToken, excessText), PunctuationSyntax) End If Else signTokenOpt = Nothing End If Dim widthToken As IntegerLiteralTokenSyntax If CurrentToken.Kind = SyntaxKind.IntegerLiteralToken Then widthToken = DirectCast(CurrentToken, IntegerLiteralTokenSyntax) GetNextToken(ScannerState.VB) If CurrentToken.Kind = SyntaxKind.ColonToken Then widthToken = DirectCast(RemoveTrailingColonTriviaAndConvertToColonToken(widthToken, colonToken, excessText), IntegerLiteralTokenSyntax) End If Else widthToken = ReportSyntaxError(InternalSyntaxFactory.MissingIntegerLiteralToken(), ERRID.ERR_ExpectedIntLiteral) End If Dim valueExpression As ExpressionSyntax = SyntaxFactory.NumericLiteralExpression(widthToken) If signTokenOpt IsNot Nothing Then valueExpression = SyntaxFactory.UnaryExpression( If(signTokenOpt.Kind = SyntaxKind.PlusToken, SyntaxKind.UnaryPlusExpression, SyntaxKind.UnaryMinusExpression), signTokenOpt, valueExpression) End If alignmentClauseOpt = SyntaxFactory.InterpolationAlignmentClause(commaToken, valueExpression) Else alignmentClauseOpt = Nothing End If Dim formatStringClauseOpt As InterpolationFormatClauseSyntax If CurrentToken.Kind = SyntaxKind.ColonToken AndAlso colonToken IsNot Nothing Then ' If colonToken IsNot Nothing we were able to recovery. GetNextToken(ScannerState.InterpolatedStringFormatString) Dim formatStringToken As InterpolatedStringTextTokenSyntax If CurrentToken.Kind = SyntaxKind.InterpolatedStringTextToken Then formatStringToken = DirectCast(CurrentToken, InterpolatedStringTextTokenSyntax) GetNextToken(ScannerState.InterpolatedStringPunctuation) If excessText IsNot Nothing Then formatStringToken = InternalSyntaxFactory.InterpolatedStringTextToken(excessText & formatStringToken.Text, excessText & formatStringToken.Value, formatStringToken.GetLeadingTrivia(), formatStringToken.GetTrailingTrivia()) End If Else If excessText IsNot Nothing Then formatStringToken = InternalSyntaxFactory.InterpolatedStringTextToken(excessText, excessText, Nothing, Nothing) Else formatStringToken = Nothing End If End If If formatStringToken Is Nothing Then formatStringToken = DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.InterpolatedStringTextToken), InterpolatedStringTextTokenSyntax) formatStringToken = ReportSyntaxError(formatStringToken, ERRID.ERR_Syntax) ElseIf formatStringToken.GetTrailingTrivia() IsNot Nothing Then formatStringToken = ReportSyntaxError(formatStringToken, ERRID.ERR_InterpolationFormatWhitespace) End If formatStringClauseOpt = SyntaxFactory.InterpolationFormatClause(colonToken, formatStringToken) Else formatStringClauseOpt = Nothing If CurrentToken.Kind = SyntaxKind.ColonToken Then ' But if colonToken is null we weren't able to gracefully recover. GetNextToken(ScannerState.InterpolatedStringFormatString) End If End If Dim closeBraceToken As PunctuationSyntax If CurrentToken.Kind = SyntaxKind.CloseBraceToken Then ' Must rescan this with interpolated string rules for trailing trivia. ' Specifically, any trailing trivia attached to the closing brace is actually interpolated string content. ResetCurrentToken(ScannerState.InterpolatedStringPunctuation) closeBraceToken = DirectCast(CurrentToken, PunctuationSyntax) GetNextToken(ScannerState.InterpolatedStringContent) ElseIf CurrentToken.Kind = SyntaxKind.EndOfInterpolatedStringToken Then GetNextToken(ScannerState.VB) closeBraceToken = DirectCast(HandleUnexpectedToken(SyntaxKind.CloseBraceToken), PunctuationSyntax) Else ' Content rules will either resync at a } or at the closing ". If Not IsValidStatementTerminator(CurrentToken) Then ResetCurrentToken(ScannerState.InterpolatedStringFormatString) End If Debug.Assert(CurrentToken.Kind <> SyntaxKind.CloseBraceToken) closeBraceToken = DirectCast(HandleUnexpectedToken(SyntaxKind.CloseBraceToken), PunctuationSyntax) If CurrentToken.Kind = SyntaxKind.InterpolatedStringTextToken Then ResetCurrentToken(ScannerState.InterpolatedStringContent) GetNextToken(ScannerState.InterpolatedStringContent) End If End If Return SyntaxFactory.Interpolation(openBraceToken, expression, alignmentClauseOpt, formatStringClauseOpt, closeBraceToken) End Function Private Shared Function RemoveTrailingColonTriviaAndConvertToColonToken( token As SyntaxToken, <Out> ByRef colonToken As PunctuationSyntax, <Out> ByRef excessText As String ) As SyntaxToken If Not token.HasTrailingTrivia Then colonToken = Nothing excessText = Nothing Return token End If Dim triviaList As New CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode)(token.GetTrailingTrivia()) Dim indexOfFirstColon As Integer = -1 Dim newTrailingTrivia As GreenNode If triviaList.Count = 1 Then indexOfFirstColon = 0 newTrailingTrivia = Nothing excessText = Nothing ElseIf triviaList(0).Kind = SyntaxKind.ColonTrivia indexOfFirstColon = 0 newTrailingTrivia = Nothing excessText = triviaList.GetEndOfTrivia(1).Node.ToFullString() Else For i = 0 To triviaList.Count - 1 If triviaList(i).Kind = SyntaxKind.ColonTrivia Then indexOfFirstColon = i Exit For End If Next newTrailingTrivia = triviaList.GetStartOfTrivia(indexOfFirstColon).Node If indexOfFirstColon = triviaList.Count - 1 Then excessText = Nothing Else excessText = triviaList.GetEndOfTrivia(indexOfFirstColon + 1).Node.ToFullString() Debug.Assert(triviaList.GetEndOfTrivia(indexOfFirstColon + 1).AnyAndOnly(SyntaxKind.ColonTrivia, SyntaxKind.WhitespaceTrivia)) End If End If Dim firstColonTrivia = DirectCast(triviaList(indexOfFirstColon), SyntaxTrivia) colonToken = New PunctuationSyntax(SyntaxKind.ColonToken, firstColonTrivia.Text, Nothing, Nothing) Return DirectCast(token.WithTrailingTrivia(newTrailingTrivia), SyntaxToken) End Function Private Function RemoveTrailingColonTriviaAndConvertToColonToken( node As VisualBasicSyntaxNode, <Out> ByRef colonToken As PunctuationSyntax, <Out> ByRef excessText As String ) As VisualBasicSyntaxNode Dim lastNonMissing = DirectCast(node.GetLastToken(), SyntaxToken) Dim newLastNonMissing = RemoveTrailingColonTriviaAndConvertToColonToken(lastNonMissing, colonToken, excessText) Dim newNode = LastTokenReplacer.Replace(node, Function(t) If(t Is lastNonMissing, newLastNonMissing, t)) ' If no token was replaced we have failed to recover; let high contexts deal with it. If newNode Is node Then colonToken = Nothing excessText = Nothing End If Return newNode End Function End Class End Namespace