/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Parser/ParseConditional.vb
478 строк
21 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. ' // ' //============ Methods related to conditional compilation. ============== ' // ' // Parse a line containing a conditional compilation directive. Imports System.Globalization Imports Microsoft.CodeAnalysis.Syntax.InternalSyntax Imports InternalSyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.SyntaxFactory Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Partial Friend Class Parser ' File: Parser.cpp ' Lines: 18978 - 18978 ' .Parser::ParseConditionalCompilationStatement( [ bool SkippingMethodBody ] ) Friend Function ParseConditionalCompilationStatement() As DirectiveTriviaSyntax ' # may be actually scanned as a date literal. This is an error. If CurrentToken.Kind = SyntaxKind.DateLiteralToken OrElse CurrentToken.Kind = SyntaxKind.BadToken Then Dim missingHash = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.HashToken) missingHash = missingHash.AddLeadingSyntax(New CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of SyntaxToken)(CurrentToken)) GetNextToken() Return (ParseBadDirective(missingHash)) End If Debug.Assert(CurrentToken.Kind = SyntaxKind.HashToken, "Conditional compilation lines start with '#'.") ' // First parse the conditional line, then interpret it. Dim statement As DirectiveTriviaSyntax = Nothing Dim hashToken = DirectCast(CurrentToken, PunctuationSyntax) GetNextToken() Select Case CurrentToken.Kind Case SyntaxKind.ElseKeyword statement = ParseElseDirective(hashToken) Case SyntaxKind.IfKeyword statement = ParseIfDirective(hashToken, Nothing) Case SyntaxKind.ElseIfKeyword statement = ParseElseIfDirective(hashToken) Case SyntaxKind.EndKeyword statement = ParseEndDirective(hashToken) Case SyntaxKind.EndIfKeyword statement = ParseAnachronisticEndIfDirective(hashToken) Case SyntaxKind.ConstKeyword statement = ParseConstDirective(hashToken) Case SyntaxKind.IdentifierToken Select Case DirectCast(CurrentToken, IdentifierTokenSyntax).PossibleKeywordKind Case SyntaxKind.ExternalSourceKeyword statement = ParseExternalSourceDirective(hashToken) Case SyntaxKind.ExternalChecksumKeyword statement = ParseExternalChecksumDirective(hashToken) Case SyntaxKind.RegionKeyword statement = ParseRegionDirective(hashToken) Case SyntaxKind.EnableKeyword, SyntaxKind.DisableKeyword statement = ParseWarningDirective(hashToken) Case SyntaxKind.ReferenceKeyword statement = ParseReferenceDirective(hashToken) Case Else statement = ParseBadDirective(hashToken) End Select Case Else statement = ParseBadDirective(hashToken) End Select Return statement End Function ' File: Parser.cpp ' Lines: 19739 - 19739 ' Expression* .Parser::ParseConditionalCompilationExpression( [ _Inout_ bool& ErrorInConstruct ] ) Friend Function ParseConditionalCompilationExpression() As ExpressionSyntax Dim PrevEvaluatingConditionCompilationExpressions As Boolean = _evaluatingConditionCompilationExpression _evaluatingConditionCompilationExpression = True Dim Expr = ParseExpressionCore() _evaluatingConditionCompilationExpression = PrevEvaluatingConditionCompilationExpressions Return Expr End Function Private Function ParseElseDirective(hashToken As PunctuationSyntax) As DirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.ElseKeyword) Dim elseKeyword = DirectCast(CurrentToken, KeywordSyntax) GetNextToken() If CurrentToken.Kind <> SyntaxKind.IfKeyword Then Dim statement = SyntaxFactory.ElseDirectiveTrivia(hashToken, elseKeyword) Return statement Else ' // Accept Else If as a synonym for ElseIf. Return ParseIfDirective(hashToken, elseKeyword) End If End Function Private Function ParseElseIfDirective(hashToken As PunctuationSyntax) As DirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.ElseIfKeyword) Return ParseIfDirective(hashToken, Nothing) End Function Private Function ParseIfDirective(hashToken As PunctuationSyntax, elseKeyword As KeywordSyntax) As IfDirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.IfKeyword OrElse CurrentToken.Kind = SyntaxKind.ElseIfKeyword) Dim ifKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax) GetNextToken() Dim expression = ParseConditionalCompilationExpression() If expression.ContainsDiagnostics Then expression = ResyncAt(expression) End If Dim thenKeyword As KeywordSyntax = Nothing If CurrentToken.Kind = SyntaxKind.ThenKeyword Then thenKeyword = DirectCast(CurrentToken, KeywordSyntax) GetNextToken() End If Dim statement As IfDirectiveTriviaSyntax If ifKeyword.Kind = SyntaxKind.IfKeyword AndAlso elseKeyword Is Nothing Then statement = SyntaxFactory.IfDirectiveTrivia(hashToken, elseKeyword, ifKeyword, expression, thenKeyword) Else statement = SyntaxFactory.ElseIfDirectiveTrivia(hashToken, elseKeyword, ifKeyword, expression, thenKeyword) End If Return statement End Function Private Function ParseEndDirective(hashToken As PunctuationSyntax) As DirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.EndKeyword) Dim endKeyword = DirectCast(CurrentToken, KeywordSyntax) GetNextToken() Dim statement As DirectiveTriviaSyntax = Nothing If CurrentToken.Kind = SyntaxKind.IfKeyword Then Dim ifKeyword = DirectCast(CurrentToken, KeywordSyntax) GetNextToken() statement = SyntaxFactory.EndIfDirectiveTrivia(hashToken, endKeyword, ifKeyword) ElseIf CurrentToken.Kind = SyntaxKind.IdentifierToken Then Dim identifier = DirectCast(CurrentToken, IdentifierTokenSyntax) If identifier.PossibleKeywordKind = SyntaxKind.RegionKeyword Then Dim regionKeyword = _scanner.MakeKeyword(DirectCast(CurrentToken, IdentifierTokenSyntax)) GetNextToken() statement = SyntaxFactory.EndRegionDirectiveTrivia(hashToken, endKeyword, regionKeyword) ElseIf identifier.PossibleKeywordKind = SyntaxKind.ExternalSourceKeyword Then Dim externalSourceKeyword = _scanner.MakeKeyword(DirectCast(CurrentToken, IdentifierTokenSyntax)) GetNextToken() statement = SyntaxFactory.EndExternalSourceDirectiveTrivia(hashToken, endKeyword, externalSourceKeyword) End If End If If statement Is Nothing Then hashToken = hashToken.AddTrailingSyntax(endKeyword, ERRID.ERR_Syntax) statement = SyntaxFactory.BadDirectiveTrivia(hashToken) End If Return statement End Function Private Function ParseAnachronisticEndIfDirective(hashToken As PunctuationSyntax) As DirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.EndIfKeyword) Dim endIfKeyword = DirectCast(CurrentToken, KeywordSyntax) GetNextToken() Dim endKeyword = InternalSyntaxFactory.MissingKeyword(SyntaxKind.EndKeyword) endKeyword = endKeyword.AddLeadingSyntax(endIfKeyword, ERRID.ERR_ObsoleteEndIf) Dim statement = SyntaxFactory.EndIfDirectiveTrivia(hashToken, endKeyword, InternalSyntaxFactory.MissingKeyword(SyntaxKind.IfKeyword)) Return statement End Function Private Function ParseConstDirective(hashToken As PunctuationSyntax) As ConstDirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.ConstKeyword) Dim constKeyword = DirectCast(CurrentToken, KeywordSyntax) GetNextToken() Dim Name = ParseIdentifier() Dim unexpected As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of SyntaxToken) = Nothing If Name.ContainsDiagnostics Then unexpected = ResyncAt({SyntaxKind.EqualsToken}) End If Dim equalsToken As PunctuationSyntax = Nothing VerifyExpectedToken(SyntaxKind.EqualsToken, equalsToken) If unexpected.Node IsNot Nothing Then equalsToken = equalsToken.AddLeadingSyntax(unexpected, ERRID.ERR_Syntax) End If Dim expression = ParseConditionalCompilationExpression() If expression.ContainsDiagnostics Then expression = ResyncAt(expression) End If Dim statement = SyntaxFactory.ConstDirectiveTrivia(hashToken, constKeyword, Name, equalsToken, expression) Return statement End Function Private Function ParseRegionDirective(hashToken As PunctuationSyntax) As RegionDirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso DirectCast(CurrentToken, IdentifierTokenSyntax).PossibleKeywordKind = SyntaxKind.RegionKeyword, NameOf(ParseRegionDirective) & " called with wrong token.") Dim identifier = DirectCast(CurrentToken, IdentifierTokenSyntax) GetNextToken() Dim regionKeyword = _scanner.MakeKeyword(identifier) Dim title As StringLiteralTokenSyntax = Nothing VerifyExpectedToken(SyntaxKind.StringLiteralToken, title) Dim statement = SyntaxFactory.RegionDirectiveTrivia(hashToken, regionKeyword, title) Return statement End Function Private Function ParseExternalSourceDirective(hashToken As PunctuationSyntax) As ExternalSourceDirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso DirectCast(CurrentToken, IdentifierTokenSyntax).PossibleKeywordKind = SyntaxKind.ExternalSourceKeyword, NameOf(ParseExternalSourceDirective) & " called with wrong token") Dim identifier = DirectCast(CurrentToken, IdentifierTokenSyntax) Dim externalSourceKeyword = _scanner.MakeKeyword(identifier) GetNextToken() Dim openParen As PunctuationSyntax = Nothing Dim closeParen As PunctuationSyntax = Nothing VerifyExpectedToken(SyntaxKind.OpenParenToken, openParen) Dim externalSource As StringLiteralTokenSyntax = Nothing VerifyExpectedToken(SyntaxKind.StringLiteralToken, externalSource) Dim comma As PunctuationSyntax = Nothing VerifyExpectedToken(SyntaxKind.CommaToken, comma) Dim externalSourceFileStartLine As IntegerLiteralTokenSyntax = Nothing VerifyExpectedToken(SyntaxKind.IntegerLiteralToken, externalSourceFileStartLine) VerifyExpectedToken(SyntaxKind.CloseParenToken, closeParen) 'TODO - Need to keep track of external source nesting and report and error 'If m_CurrentExternalSourceDirective IsNot Nothing Then ' ReportSyntaxError(ERRID.ERR_NestedExternalSource, Start, m_CurrentToken, ErrorInConstruct) ' hasErrors = True 'ElseIf m_ExternalSourceDirectiveTarget IsNot Nothing Then 'End If Dim statement = SyntaxFactory.ExternalSourceDirectiveTrivia(hashToken, externalSourceKeyword, openParen, externalSource, comma, externalSourceFileStartLine, closeParen) Return statement End Function Private Function ParseExternalChecksumDirective(hashToken As PunctuationSyntax) As ExternalChecksumDirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso DirectCast(CurrentToken, IdentifierTokenSyntax).PossibleKeywordKind = SyntaxKind.ExternalChecksumKeyword, NameOf(ParseExternalChecksumDirective) & " called with wrong token") Dim identifier = DirectCast(CurrentToken, IdentifierTokenSyntax) Dim externalChecksumKeyword = _scanner.MakeKeyword(identifier) GetNextToken() Dim openParen As PunctuationSyntax = Nothing Dim closeParen As PunctuationSyntax = Nothing VerifyExpectedToken(SyntaxKind.OpenParenToken, openParen) Dim externalSource As StringLiteralTokenSyntax = Nothing VerifyExpectedToken(SyntaxKind.StringLiteralToken, externalSource) Dim firstComma As PunctuationSyntax = Nothing VerifyExpectedToken(SyntaxKind.CommaToken, firstComma) Dim guid As StringLiteralTokenSyntax = Nothing VerifyExpectedToken(SyntaxKind.StringLiteralToken, guid) If Not guid.IsMissing Then Dim tmp As System.Guid If Not System.Guid.TryParse(guid.ValueText, tmp) Then guid = guid.WithDiagnostics(ErrorFactory.ErrorInfo(ERRID.WRN_BadGUIDFormatExtChecksum)) End If End If Dim secondComma As PunctuationSyntax = Nothing VerifyExpectedToken(SyntaxKind.CommaToken, secondComma) Dim checksum As StringLiteralTokenSyntax = Nothing VerifyExpectedToken(SyntaxKind.StringLiteralToken, checksum) If Not checksum.IsMissing Then Dim checksumText = checksum.ValueText If checksumText.Length Mod 2 <> 0 Then checksum = checksum.WithDiagnostics(ErrorFactory.ErrorInfo(ERRID.WRN_BadChecksumValExtChecksum)) Else For Each ch In checksumText If Not SyntaxFacts.IsHexDigit(ch) Then checksum = checksum.WithDiagnostics(ErrorFactory.ErrorInfo(ERRID.WRN_BadChecksumValExtChecksum)) Exit For End If Next End If End If VerifyExpectedToken(SyntaxKind.CloseParenToken, closeParen) Dim statement = SyntaxFactory.ExternalChecksumDirectiveTrivia(hashToken, externalChecksumKeyword, openParen, externalSource, firstComma, guid, secondComma, checksum, closeParen) Return statement End Function Private Function ParseWarningDirective(hashToken As PunctuationSyntax) As DirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken, NameOf(ParseWarningDirective) & " called with token that is not an " & NameOf(SyntaxKind.IdentifierToken)) Dim identifier = DirectCast(CurrentToken, IdentifierTokenSyntax) Debug.Assert((identifier.PossibleKeywordKind = SyntaxKind.EnableKeyword) OrElse (identifier.PossibleKeywordKind = SyntaxKind.DisableKeyword), NameOf(ParseWarningDirective) & " called with token that is neither " & NameOf(SyntaxKind.EnableKeyword) & " nor " & NameOf(SyntaxKind.DisableKeyword)) Dim enableOrDisableKeyword = _scanner.MakeKeyword(identifier) GetNextToken() Dim warningKeyword As KeywordSyntax = Nothing TryGetContextualKeyword(SyntaxKind.WarningKeyword, warningKeyword, createIfMissing:=True) If warningKeyword.ContainsDiagnostics Then warningKeyword = ResyncAt(warningKeyword) End If Dim errorCodes = Me._pool.AllocateSeparated(Of IdentifierNameSyntax)() If Not SyntaxFacts.IsTerminator(CurrentToken.Kind) Then Do Dim errorCode = SyntaxFactory.IdentifierName(ParseIdentifier()) If errorCode.ContainsDiagnostics Then errorCode = ResyncAt(errorCode, SyntaxKind.CommaToken) ElseIf errorCode.Identifier.TypeCharacter <> TypeCharacter.None Then ' Disallow type characters at the end of diagnostic ids. errorCode = ReportSyntaxError(errorCode, ERRID.ERR_TypecharNotallowed) End If errorCodes.Add(errorCode) Dim comma As PunctuationSyntax = Nothing If Not TryGetToken(SyntaxKind.CommaToken, comma) Then If SyntaxFacts.IsTerminator(CurrentToken.Kind) Then Exit Do Else comma = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.CommaToken) comma = ReportSyntaxError(comma, ERRID.ERR_ExpectedComma) End If End If If comma.ContainsDiagnostics Then comma = ResyncAt(comma) End If errorCodes.AddSeparator(comma) Loop End If Dim statement As DirectiveTriviaSyntax = Nothing If enableOrDisableKeyword.Kind = SyntaxKind.EnableKeyword Then statement = SyntaxFactory.EnableWarningDirectiveTrivia( hashToken, enableOrDisableKeyword, warningKeyword, errorCodes.ToList) ElseIf enableOrDisableKeyword.Kind = SyntaxKind.DisableKeyword Then statement = SyntaxFactory.DisableWarningDirectiveTrivia( hashToken, enableOrDisableKeyword, warningKeyword, errorCodes.ToList) End If If statement IsNot Nothing Then statement = CheckFeatureAvailability(Feature.WarningDirectives, statement) End If Me._pool.Free(errorCodes) Return statement End Function Private Function ParseReferenceDirective(hashToken As PunctuationSyntax) As DirectiveTriviaSyntax Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso DirectCast(CurrentToken, IdentifierTokenSyntax).PossibleKeywordKind = SyntaxKind.ReferenceKeyword, NameOf(ParseReferenceDirective) & " called with wrong token.") Dim identifier = DirectCast(CurrentToken, IdentifierTokenSyntax) GetNextToken() Dim referenceKeyword = _scanner.MakeKeyword(identifier) If Not IsScript Then referenceKeyword = AddError(referenceKeyword, ERRID.ERR_ReferenceDirectiveOnlyAllowedInScripts) End If Dim file As StringLiteralTokenSyntax = Nothing VerifyExpectedToken(SyntaxKind.StringLiteralToken, file) Return SyntaxFactory.ReferenceDirectiveTrivia(hashToken, referenceKeyword, file) End Function Private Shared Function ParseBadDirective(hashToken As PunctuationSyntax) As BadDirectiveTriviaSyntax Dim badDirective = InternalSyntaxFactory.BadDirectiveTrivia(hashToken) If Not badDirective.ContainsDiagnostics Then badDirective = ReportSyntaxError(badDirective, ERRID.ERR_ExpectedConditionalDirective) End If Return badDirective End Function End Class End Namespace