|
' 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 for parsing portions of executable statements ==
'
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.Syntax.InternalSyntax
Imports InternalSyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.SyntaxFactory
Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Partial Friend Class Parser
Friend Function ParseExpression(
Optional pendingPrecedence As OperatorPrecedence = OperatorPrecedence.PrecedenceNone,
Optional bailIfFirstTokenRejected As Boolean = False
) As ExpressionSyntax
Return ParseWithStackGuard(Of ExpressionSyntax)(
Function() ParseExpressionCore(pendingPrecedence, bailIfFirstTokenRejected),
Function() InternalSyntaxFactory.MissingExpression())
End Function
' /*********************************************************************
' *
' * Function:
' * Parser::ParseExpression
' *
' * Purpose:
' *
' * Parses an expression.
' *
' **********************************************************************/
' [in] precedence of previous oper
' File: Parser.cpp
' Lines: 12312 - 12312
' Expression* .Parser::ParseExpression( [ OperatorPrecedence PendingPrecedence ] [ _Inout_ bool& ErrorInConstruct ] [ bool AllowArrayInitExpression ] )
' //EatLeadingNewLine: Indicates that the parser should
' //dig through a leading EOL token when it tries
' //to parse the expression.
'
' bool EatLeadingNewLine, - we no longer support it in ParseExpressionCore, please eat the new line yourself before calling
' bool BailIfFirstTokenRejected // bail (return NULL) if the first token isn't a valid expression-starter, rather than reporting an error or setting ErrorInConstruct
Private Function ParseExpressionCore(
Optional pendingPrecedence As OperatorPrecedence = OperatorPrecedence.PrecedenceNone,
Optional bailIfFirstTokenRejected As Boolean = False
) As ExpressionSyntax
Try
_recursionDepth += 1
StackGuard.EnsureSufficientExecutionStack(_recursionDepth)
'// Note: this function will only ever return NULL if the flag "BailIfFirstTokenIsRejected" is set,
'// and if the first token isn't a valid way to start an expression. In all other error scenarios
'// it returns a "bad expression".
Dim expression As ExpressionSyntax = Nothing
Dim startToken As SyntaxToken = CurrentToken
If _evaluatingConditionCompilationExpression AndAlso
Not StartsValidConditionalCompilationExpr(startToken) Then
If bailIfFirstTokenRejected Then
Return Nothing
End If
expression = InternalSyntaxFactory.MissingExpression().AddTrailingSyntax(startToken, ERRID.ERR_BadCCExpression)
GetNextToken()
Return expression
End If
' Check for leading unary operators
Select Case (startToken.Kind)
Case SyntaxKind.MinusToken
' "-" unary minus
GetNextToken()
Dim Operand As ExpressionSyntax = ParseExpressionCore(OperatorPrecedence.PrecedenceNegate)
expression = SyntaxFactory.UnaryMinusExpression(startToken, Operand)
Case SyntaxKind.NotKeyword
' NOT expr
GetNextToken()
Dim Operand = ParseExpressionCore(OperatorPrecedence.PrecedenceNot)
expression = SyntaxFactory.NotExpression(startToken, Operand)
Case SyntaxKind.PlusToken
' "+" unary plus
GetNextToken()
' unary "+" has the same precedence as unary "-"
Dim Operand = ParseExpressionCore(OperatorPrecedence.PrecedenceNegate)
expression = SyntaxFactory.UnaryPlusExpression(startToken, Operand)
Case SyntaxKind.AddressOfKeyword
GetNextToken()
Dim Operand = ParseExpressionCore(OperatorPrecedence.PrecedenceNegate)
expression = SyntaxFactory.AddressOfExpression(startToken, Operand)
Case Else
expression = ParseTerm(bailIfFirstTokenRejected)
If expression Is Nothing Then
Return Nothing
End If
End Select
' SHIQIC: I removed Expr->Opcode == ParseTree.Expression.Lambda, since we don't need to cast it to Lambda before test whether it is a statement lambda.
' Expr.AsLambda().IsStatementLambda is changed to (Expr.Kind = NodeKind.MultiLineFunctionLambda OrElse Expr.Kind = NodeKind.MultiLineSubLambda)
If SyntaxKind.CollectionInitializer <> expression.Kind Then 'AndAlso
#If UNDONE Then
Not ( (Expr.Kind = NodeKind.MultiLineFunctionLambda OrElse Expr.Kind = NodeKind.MultiLineSubLambda) AndAlso
Not DirectCast(Expr, Lambda).GetStatementLambdaBody().HasProperTermination ) Then ' Array initializer expressions NYI and we do not want to enter here if the expression is a multiline lambda without an end construct.
#End If
' Parse operators that follow the term according to precedence.
Do
Dim precedence As OperatorPrecedence
If Not CurrentToken.IsBinaryOperator Then
Exit Do
End If
If _evaluatingConditionCompilationExpression AndAlso
Not IsValidOperatorForConditionalCompilationExpr(CurrentToken) Then
' Should current token be consumed here?
expression = ReportSyntaxError(expression, ERRID.ERR_BadCCExpression)
Exit Do
End If
precedence = KeywordTable.TokenOpPrec(CurrentToken.Kind)
Debug.Assert(precedence <> OperatorPrecedence.PrecedenceNone, "should have a non-zero precedence for operators.")
' Only continue parsing if precedence is high enough
If precedence <= pendingPrecedence Then
Exit Do
End If
Dim [operator] As SyntaxToken = ParseBinaryOperator()
'Dim Binary As ParseTree.BinaryExpression = New ParseTree.BinaryExpression
'Binary.Opcode = Opcode
'Binary.Left = Expr
Dim rightOperand As ExpressionSyntax = ParseExpressionCore(precedence)
expression = SyntaxFactory.BinaryExpression(GetBinaryOperatorHelper([operator]), expression, [operator], rightOperand)
Loop
End If
Return expression
Finally
_recursionDepth -= 1
End Try
End Function
Private Function ParseTerm(
Optional BailIfFirstTokenRejected As Boolean = False,
Optional RedimOrNewParent As Boolean = False
) As ExpressionSyntax
'// Note: this function will only ever return NULL if the flag "BailIfFirstTokenIsRejected" is set,
'// and if the first token isn't a valid way to start an expression. In all other error scenarios
'// it returns a "bad expression".
Debug.Assert(Not _evaluatingConditionCompilationExpression OrElse
StartsValidConditionalCompilationExpr(CurrentToken), "Conditional compilation expression parsing confused!!!")
Dim term As ExpressionSyntax = Nothing
Dim start As SyntaxToken = CurrentToken
' Resync points are delimiters.
Select Case start.Kind
Case SyntaxKind.IdentifierToken
Dim keyword As KeywordSyntax = Nothing
' See if this is a beginning of a query
If TryIdentifierAsContextualKeyword(start, keyword) Then
If keyword.Kind = SyntaxKind.FromKeyword OrElse keyword.Kind = SyntaxKind.AggregateKeyword Then
term = ParsePotentialQuery(keyword)
If term IsNot Nothing Then
Exit Select
End If
ElseIf keyword.Kind = SyntaxKind.AsyncKeyword OrElse keyword.Kind = SyntaxKind.IteratorKeyword Then
Dim nextToken = PeekToken(1)
If nextToken.Kind = SyntaxKind.IdentifierToken Then
Dim possibleKeyword As KeywordSyntax = Nothing
If TryTokenAsContextualKeyword(nextToken, possibleKeyword) AndAlso
possibleKeyword.Kind <> keyword.Kind AndAlso
(possibleKeyword.Kind = SyntaxKind.AsyncKeyword OrElse possibleKeyword.Kind = SyntaxKind.IteratorKeyword) Then
nextToken = PeekToken(2)
End If
End If
If nextToken.Kind = SyntaxKind.SubKeyword OrElse nextToken.Kind = SyntaxKind.FunctionKeyword Then
term = ParseLambda(parseModifiers:=True)
Exit Select
End If
ElseIf Context.IsWithinAsyncMethodOrLambda AndAlso keyword.Kind = SyntaxKind.AwaitKeyword Then
term = ParseAwaitExpression(keyword)
Exit Select
End If
End If
term = ParseSimpleNameExpressionAllowingKeywordAndTypeArguments()
Case SyntaxKind.ExclamationToken
term = ParseQualifiedExpr(Nothing)
Case SyntaxKind.DotToken
term = ParseQualifiedExpr(Nothing)
Case SyntaxKind.GlobalKeyword
' NB. GetNextToken has the side-effect of advancing CurrentToken.
term = SyntaxFactory.GlobalName(DirectCast(start, KeywordSyntax))
GetNextToken()
If CurrentToken.Kind <> SyntaxKind.DotToken Then
' Dev10#519742: MyClass/MyBase/Global on their own are bad parse-tree nodes.
' If we don't mark them bad now, then InterpretExpression will try to bind them later on
' (which would be incorrect).
term = ReportSyntaxError(term, ERRID.ERR_ExpectedDotAfterGlobalNameSpace)
End If
Case SyntaxKind.MyBaseKeyword
term = SyntaxFactory.MyBaseExpression(DirectCast(start, KeywordSyntax))
GetNextToken()
If CurrentToken.Kind <> SyntaxKind.DotToken Then
' Dev10#519742: MyClass/MyBase/Global on their own are bad parse-tree nodes.
' If we don't mark them bad now, then InterpretExpression will try to bind them later on
' (which would be incorrect).
term = ReportSyntaxError(term, ERRID.ERR_ExpectedDotAfterMyBase)
End If
Case SyntaxKind.MyClassKeyword
term = SyntaxFactory.MyClassExpression(DirectCast(start, KeywordSyntax))
GetNextToken()
If CurrentToken.Kind <> SyntaxKind.DotToken Then
' Dev10#519742: MyClass/MyBase/Global on their own are bad parse-tree nodes.
' If we don't mark them bad now, then InterpretExpression will try to bind them later on
' (which would be incorrect).
term = ReportSyntaxError(term, ERRID.ERR_ExpectedDotAfterMyClass)
End If
Case SyntaxKind.MeKeyword
term = SyntaxFactory.MeExpression(DirectCast(start, KeywordSyntax))
GetNextToken()
Case SyntaxKind.OpenParenToken
term = ParseParenthesizedExpressionOrTupleLiteral()
'XML
Case SyntaxKind.LessThanToken,
SyntaxKind.LessThanQuestionToken,
SyntaxKind.BeginCDataToken,
SyntaxKind.LessThanExclamationMinusMinusToken,
SyntaxKind.LessThanSlashToken,
SyntaxKind.LessThanGreaterThanToken
' Xml Literals
' 1. single element "<" element ">"
' 2. xml document "<?xml ...?>
' 3. xml pi
' 4. xml cdata <![CDATA[
' 5. xml comment <!--
' 6. end element without begin </
' 7. error case <>, element missing name
' /* Dev10_427764 : Allow an implicit line continuation for XML after '(', e.g. goo(
Dim tokenHasFullWidthChars As Boolean = TokenContainsFullWidthChars(start)
If tokenHasFullWidthChars Then
If BailIfFirstTokenRejected Then
Return Nothing
End If
term = InternalSyntaxFactory.MissingExpression()
term = term.AddTrailingSyntax(CurrentToken, ERRID.ERR_FullWidthAsXmlDelimiter)
GetNextToken()
Return term
End If
term = ParseXmlExpression()
Case SyntaxKind.IntegerLiteralToken
term = ParseIntLiteral()
Case SyntaxKind.CharacterLiteralToken
term = ParseCharLiteral()
Case SyntaxKind.DecimalLiteralToken
term = ParseDecLiteral()
Case SyntaxKind.FloatingLiteralToken
term = ParseFltLiteral()
Case SyntaxKind.DateLiteralToken
term = ParseDateLiteral()
Case SyntaxKind.StringLiteralToken
term = ParseStringLiteral()
Case SyntaxKind.TrueKeyword
term = SyntaxFactory.TrueLiteralExpression(CurrentToken)
GetNextToken()
Case SyntaxKind.FalseKeyword
term = SyntaxFactory.FalseLiteralExpression(CurrentToken)
GetNextToken()
Case SyntaxKind.NothingKeyword
term = SyntaxFactory.NothingLiteralExpression(CurrentToken)
GetNextToken()
Case SyntaxKind.TypeOfKeyword
term = ParseTypeOf()
Case SyntaxKind.GetTypeKeyword
term = ParseGetType()
Case SyntaxKind.NameOfKeyword
term = ParseNameOf()
Case SyntaxKind.GetXmlNamespaceKeyword
term = ParseGetXmlNamespace()
Case SyntaxKind.NewKeyword
term = ParseNewExpression()
Case SyntaxKind.CBoolKeyword,
SyntaxKind.CDateKeyword,
SyntaxKind.CDblKeyword,
SyntaxKind.CSByteKeyword,
SyntaxKind.CByteKeyword,
SyntaxKind.CCharKeyword,
SyntaxKind.CShortKeyword,
SyntaxKind.CUShortKeyword,
SyntaxKind.CIntKeyword,
SyntaxKind.CUIntKeyword,
SyntaxKind.CLngKeyword,
SyntaxKind.CULngKeyword,
SyntaxKind.CSngKeyword,
SyntaxKind.CStrKeyword,
SyntaxKind.CDecKeyword,
SyntaxKind.CObjKeyword
term = ParseCastExpression()
Case SyntaxKind.CTypeKeyword, SyntaxKind.DirectCastKeyword, SyntaxKind.TryCastKeyword
term = ParseCast()
Case SyntaxKind.IfKeyword
term = ParseIfExpression()
Case SyntaxKind.ShortKeyword,
SyntaxKind.UShortKeyword,
SyntaxKind.IntegerKeyword,
SyntaxKind.UIntegerKeyword,
SyntaxKind.LongKeyword,
SyntaxKind.ULongKeyword,
SyntaxKind.DecimalKeyword,
SyntaxKind.SingleKeyword,
SyntaxKind.DoubleKeyword,
SyntaxKind.SByteKeyword,
SyntaxKind.ByteKeyword,
SyntaxKind.BooleanKeyword,
SyntaxKind.CharKeyword,
SyntaxKind.DateKeyword,
SyntaxKind.StringKeyword,
SyntaxKind.VariantKeyword,
SyntaxKind.ObjectKeyword
term = ParseTypeName()
Case SyntaxKind.OpenBraceToken
' A CollectionInitializer is an AnonymousArrayCreationExpression. AnonymousArrayCreationExpression type
' is no longer part of the object model.
term = ParseCollectionInitializer()
Case SyntaxKind.SubKeyword,
SyntaxKind.FunctionKeyword
term = ParseLambda(parseModifiers:=False)
Case SyntaxKind.DollarSignDoubleQuoteToken
term = ParseInterpolatedStringExpression()
Case Else
If start.Kind = SyntaxKind.QuestionToken AndAlso CanStartConsequenceExpression(Me.PeekToken(1).Kind, qualified:=False) Then
' This looks like ?. or ?!
Dim qToken = DirectCast(start, PunctuationSyntax)
qToken = CheckFeatureAvailability(Feature.NullPropagatingOperator, qToken)
GetNextToken()
term = SyntaxFactory.ConditionalAccessExpression(term, qToken, ParsePostFixExpression(RedimOrNewParent, term:=Nothing))
Else
If BailIfFirstTokenRejected Then
Return Nothing
End If
term = InternalSyntaxFactory.MissingExpression()
term = ReportSyntaxError(term, ERRID.ERR_ExpectedExpression)
End If
End Select
Debug.Assert(term IsNot Nothing)
' Complex expressions such as "." or "!" qualified, etc are not allowed cond comp expressions.
'
If Not _evaluatingConditionCompilationExpression Then
' Valid suffixes are ".", "!", and "(". Everything else is considered
' to end the term.
term = ParsePostFixExpression(RedimOrNewParent, term)
End If
If CurrentToken IsNot Nothing AndAlso CurrentToken.Kind = SyntaxKind.QuestionToken Then
term = term.AddTrailingSyntax(CurrentToken, ERRID.ERR_NullableCharNotSupported)
GetNextToken()
End If
Return term
End Function
Private Function ParsePostFixExpression(RedimOrNewParent As Boolean, term As ExpressionSyntax) As ExpressionSyntax
Do
Dim [Next] As SyntaxToken = CurrentToken
' Dev10#670442 - you can't apply invocation parentheses directly to a single-line sub lambda,
' nor DotQualified/BangDictionaryLookup
Dim isAfterSingleLineSub As Boolean = term IsNot Nothing AndAlso term.Kind = SyntaxKind.SingleLineSubLambdaExpression
If [Next].Kind = SyntaxKind.DotToken Then
If isAfterSingleLineSub Then
term = ReportSyntaxError(term, ERRID.ERR_SubRequiresParenthesesDot)
End If
term = ParseQualifiedExpr(term)
ElseIf [Next].Kind = SyntaxKind.ExclamationToken Then
If isAfterSingleLineSub Then
term = ReportSyntaxError(term, ERRID.ERR_SubRequiresParenthesesBang)
End If
term = ParseQualifiedExpr(term)
ElseIf [Next].Kind = SyntaxKind.OpenParenToken Then
If isAfterSingleLineSub Then
term = ReportSyntaxError(term, ERRID.ERR_SubRequiresParenthesesLParen)
End If
term = ParseParenthesizedQualifier(term, RedimOrNewParent)
ElseIf [Next].Kind = SyntaxKind.QuestionToken AndAlso CanStartConsequenceExpression(Me.PeekToken(1).Kind, qualified:=True) Then
' This looks like ?. ?! or ?(
Dim qToken = DirectCast([Next], PunctuationSyntax)
qToken = CheckFeatureAvailability(Feature.NullPropagatingOperator, qToken)
GetNextToken()
If isAfterSingleLineSub Then
Select Case CurrentToken.Kind
Case SyntaxKind.DotToken
term = ReportSyntaxError(term, ERRID.ERR_SubRequiresParenthesesDot)
Case SyntaxKind.ExclamationToken
term = ReportSyntaxError(term, ERRID.ERR_SubRequiresParenthesesBang)
Case SyntaxKind.OpenParenToken
term = ReportSyntaxError(term, ERRID.ERR_SubRequiresParenthesesLParen)
Case Else
Throw ExceptionUtilities.Unreachable
End Select
End If
term = SyntaxFactory.ConditionalAccessExpression(term, qToken, ParsePostFixExpression(RedimOrNewParent, term:=Nothing))
Else
' We're done with the term.
Exit Do
End If
Loop
Return term
End Function
Private Function CanStartConsequenceExpression(kind As SyntaxKind, qualified As Boolean) As Boolean
Return kind = SyntaxKind.DotToken OrElse kind = SyntaxKind.ExclamationToken OrElse (qualified AndAlso kind = SyntaxKind.OpenParenToken)
End Function
Private Shared Function TokenContainsFullWidthChars(tk As SyntaxToken) As Boolean
Dim spelling = tk.Text
For Each ch In spelling
If SyntaxFacts.IsFullWidth(ch) Then
Return True
End If
Next
Return False
End Function
Private Shared Function GetArgumentAsExpression(arg As ArgumentSyntax) As ExpressionSyntax
Select Case arg.Kind
Case SyntaxKind.SimpleArgument
Dim simpleArgument = DirectCast(arg, SimpleArgumentSyntax)
Dim expression = simpleArgument.Expression
If simpleArgument.NameColonEquals IsNot Nothing Then
expression = expression.AddLeadingSyntax(
CodeAnalysis.Syntax.InternalSyntax.SyntaxList.List(simpleArgument.NameColonEquals.Name, simpleArgument.NameColonEquals.ColonEqualsToken), ERRID.ERR_IllegalOperandInIIFName)
End If
Return expression
Case Else
' argument for IF expression cannot be omitted
Dim expr = InternalSyntaxFactory.MissingExpression
expr = expr.AddLeadingSyntax(arg, ERRID.ERR_ExpectedExpression)
Return expr
End Select
End Function
Private Function ParseIfExpression() As ExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.IfKeyword)
Dim IfStart = DirectCast(CurrentToken, KeywordSyntax)
GetNextToken() ' get off If
If CurrentToken.Kind = SyntaxKind.OpenParenToken Then
Dim Arguments = ParseParenthesizedArguments()
Dim Args = Arguments.Arguments
Select Case Args.Count
Case 0
Return SyntaxFactory.BinaryConditionalExpression(
IfStart,
Arguments.OpenParenToken,
InternalSyntaxFactory.MissingExpression.WithDiagnostics(ErrorFactory.ErrorInfo(ERRID.ERR_IllegalOperandInIIFCount)),
DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.CommaToken), PunctuationSyntax),
InternalSyntaxFactory.MissingExpression,
Arguments.CloseParenToken)
Case 1
Return SyntaxFactory.BinaryConditionalExpression(
IfStart,
Arguments.OpenParenToken,
GetArgumentAsExpression(Args(0)),
DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.CommaToken), PunctuationSyntax),
InternalSyntaxFactory.MissingExpression.WithDiagnostics(ErrorFactory.ErrorInfo(ERRID.ERR_IllegalOperandInIIFCount)),
Arguments.CloseParenToken)
Case 2
Return SyntaxFactory.BinaryConditionalExpression(
IfStart,
Arguments.OpenParenToken,
GetArgumentAsExpression(Args(0)),
DirectCast(Args.GetWithSeparators(1), PunctuationSyntax),
GetArgumentAsExpression(Args(1)),
Arguments.CloseParenToken)
Case 3
Return SyntaxFactory.TernaryConditionalExpression(
IfStart,
Arguments.OpenParenToken,
GetArgumentAsExpression(Args(0)),
DirectCast(Args.GetWithSeparators(1), PunctuationSyntax),
GetArgumentAsExpression(Args(1)),
DirectCast(Args.GetWithSeparators(3), PunctuationSyntax),
GetArgumentAsExpression(Args(2)),
Arguments.CloseParenToken)
Case Else
' Wrong arg count
Debug.Assert(Args.Count > 3)
Dim withSeparators As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode) = Args.GetWithSeparators()
Const firstNotUsedIndex As Integer = 5
Debug.Assert(withSeparators.Count > firstNotUsedIndex)
Dim leading(withSeparators.Count - firstNotUsedIndex - 1) As VisualBasicSyntaxNode
For i As Integer = firstNotUsedIndex To withSeparators.Count - 1
leading(i - firstNotUsedIndex) = withSeparators(i)
Next
Return SyntaxFactory.TernaryConditionalExpression(
IfStart,
Arguments.OpenParenToken,
GetArgumentAsExpression(Args(0)),
DirectCast(withSeparators(1), PunctuationSyntax),
GetArgumentAsExpression(Args(1)),
DirectCast(withSeparators(3), PunctuationSyntax),
GetArgumentAsExpression(Args(2)),
Arguments.CloseParenToken.AddLeadingSyntax(
CodeAnalysis.Syntax.InternalSyntax.SyntaxList.List(ArrayElement(Of GreenNode).MakeElementArray(leading)), ERRID.ERR_IllegalOperandInIIFCount))
End Select
Else
' ( was not there
Return SyntaxFactory.BinaryConditionalExpression(
IfStart,
DirectCast(HandleUnexpectedToken(SyntaxKind.OpenParenToken), PunctuationSyntax),
InternalSyntaxFactory.MissingExpression,
DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.CommaToken), PunctuationSyntax),
InternalSyntaxFactory.MissingExpression,
DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.CloseParenToken), PunctuationSyntax))
End If
End Function
''' <summary>
''' Parse GetType,
''' GetTypeExpression -> GetType OpenParenthesis GetTypeTypeName CloseParenthesis
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Function ParseGetType() As GetTypeExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.GetTypeKeyword, "should be at GetType.")
Dim [getType] As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
GetNextToken()
Dim openParen As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.OpenParenToken, openParen, createIfMissing:=True)
'// Dev10 #526220 Note, we are passing 'true' here to allow empty type arguments,
'// this may be incorrect for a Nullable type when '?' is used at the end of the type name.
'// In this case, we may generate some spurious errors and fail to report an expected error.
'// In order to deal with this issue, Parser::ParseTypeName() will walk the type tree and
'// report expected errors, removing false errors at the same time.
Dim getTypeTypeName = ParseGeneralType(True) ' /* Allow type arguments to be empty i.e. allow C1(Of , ,)*/
Dim closeParen As PunctuationSyntax = Nothing
TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=True)
Return SyntaxFactory.GetTypeExpression([getType], openParen, getTypeTypeName, closeParen)
End Function
''' <summary>
''' Parse NameOf,
''' NameOfExpression -> NameOf OpenParenthesis Name CloseParenthesis
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Function ParseNameOf() As NameOfExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.NameOfKeyword, "should be at NameOf.")
Dim [nameOf] As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
[nameOf] = CheckFeatureAvailability(Feature.NameOfExpressions, [nameOf])
GetNextToken()
Dim openParen As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.OpenParenToken, openParen, createIfMissing:=True)
Dim nameOfName = ValidateNameOfArgument(ParseExpressionCore(), isTopLevel:=True)
Dim closeParen As PunctuationSyntax = Nothing
TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=True)
Return SyntaxFactory.NameOfExpression([nameOf], openParen, nameOfName, closeParen)
End Function
Private Function ValidateNameOfArgument(argument As ExpressionSyntax, isTopLevel As Boolean) As ExpressionSyntax
Select Case argument.Kind
Case SyntaxKind.IdentifierName,
SyntaxKind.GenericName
Return argument
Case SyntaxKind.MeExpression,
SyntaxKind.MyClassExpression,
SyntaxKind.MyBaseExpression,
SyntaxKind.PredefinedType,
SyntaxKind.NullableType,
SyntaxKind.GlobalName
If isTopLevel Then
Return ReportSyntaxError(argument, ERRID.ERR_ExpressionDoesntHaveName)
End If
Return argument
Case SyntaxKind.SimpleMemberAccessExpression
Dim access = DirectCast(argument, MemberAccessExpressionSyntax)
If access.Expression IsNot Nothing Then
Dim expression = ValidateNameOfArgument(access.Expression, isTopLevel:=False)
If expression IsNot access.Expression Then
access = SyntaxFactory.SimpleMemberAccessExpression(expression, access.OperatorToken, access.Name)
End If
End If
Return access
Case Else
Return ReportSyntaxError(argument, If(isTopLevel, ERRID.ERR_ExpressionDoesntHaveName, ERRID.ERR_InvalidNameOfSubExpression))
End Select
End Function
' File: Parser.cpp
' Lines: 15850 - 15850
' Expression* .Parser::ParseGetXmlNamespace( [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseGetXmlNamespace() As ExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.GetXmlNamespaceKeyword, "should be at GetXmlNamespace.")
Dim getXmlNamespaceKeyword = DirectCast(CurrentToken, KeywordSyntax)
GetNextToken(ScannerState.VB)
If CurrentToken.Kind = SyntaxKind.OpenParenToken Then
' Use Element state so the Rem style comments are disabled to support GetXmlNamespace(Rem)
ResetCurrentToken(ScannerState.Element)
Dim openParen As PunctuationSyntax = Nothing
VerifyExpectedToken(SyntaxKind.OpenParenToken, openParen, ScannerState.Element)
Dim name As XmlPrefixNameSyntax = Nothing
If CurrentToken.Kind = SyntaxKind.XmlNameToken Then
name = SyntaxFactory.XmlPrefixName(DirectCast(CurrentToken, XmlNameTokenSyntax))
GetNextToken(ScannerState.Element)
End If
Dim closeParen As PunctuationSyntax = Nothing
VerifyExpectedToken(SyntaxKind.CloseParenToken, closeParen)
Dim result = SyntaxFactory.GetXmlNamespaceExpression(getXmlNamespaceKeyword, openParen, name, closeParen)
result = AdjustTriviaForMissingTokens(result)
result = TransitionFromXmlToVB(result)
Return result
Else
Dim openParen = DirectCast(HandleUnexpectedToken(SyntaxKind.OpenParenToken), PunctuationSyntax)
Dim closeParen = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.CloseParenToken)
Return SyntaxFactory.GetXmlNamespaceExpression(getXmlNamespaceKeyword, openParen, Nothing, closeParen)
End If
End Function
' File: Parser.cpp
' Lines: 15892 - 15892
' Expression* .Parser::ParseCastExpression( [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseCastExpression() As ExpressionSyntax
Debug.Assert(SyntaxFacts.IsPredefinedCastExpressionKeyword(CurrentToken.Kind), "ParseCastExpression called with the wrong token.")
Dim Start = DirectCast(CurrentToken, KeywordSyntax)
GetNextToken()
Dim openParen As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.OpenParenToken, openParen, createIfMissing:=True)
Dim Operand = ParseExpressionCore()
Dim closeParen As PunctuationSyntax = Nothing
TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=True)
Return SyntaxFactory.PredefinedCastExpression(Start, openParen, Operand, closeParen)
End Function
' File: Parser.cpp
' Lines: 15971 - 15971
' Expression* .Parser::ParseNewExpression( [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseNewExpression() As ExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.NewKeyword, "must be at a New expression.")
Dim NewKeyword = DirectCast(CurrentToken, KeywordSyntax)
GetNextToken() ' get off 'new'
If CurrentToken.Kind = SyntaxKind.WithKeyword Then
' Anonymous type initializer
' Parsing from "With" in "New With {Initializer list}"
Dim objInitializer = ParseObjectInitializerList(True) ' AnonymousTypeInitializer
Return SyntaxFactory.AnonymousObjectCreationExpression(NewKeyword, Nothing, objInitializer)
End If
Dim Type = ParseTypeName()
If Type.ContainsDiagnostics Then
Type = ResyncAt(Type, SyntaxKind.OpenParenToken)
End If
Dim Arguments As ArgumentListSyntax = Nothing
If CurrentToken.Kind = SyntaxKind.OpenParenToken Then
' This is an ambiguity in the grammar between
'
' New <Type> ( <Arguments> )
' New <Type> <ArrayDeclaratorList> <AggregateInitializer>
'
' Try it as the first form, and if this fails, try the second.
' (All valid instances of the second form have a beginning that is a valid
' instance of the first form, so no spurious errors should result.)
' Try parsing the arguments to determine whether they are constructor
' arguments or array declarators.
Arguments = ParseParenthesizedArguments(True)
' TODO: having "0 To 10" style arguments would also point to array init
' for Dev10 compat we will let it slip through.
Dim IsArrayCreationExpression = False
Dim arrayModifiers As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of ArrayRankSpecifierSyntax) = Nothing
If Me.CurrentToken.Kind = Global.Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.OpenParenToken Then
' Parse array modifiers
arrayModifiers = ParseArrayRankSpecifiers(ERRID.ERR_NoConstituentArraySizes)
IsArrayCreationExpression = True
ElseIf CurrentToken.Kind = SyntaxKind.OpenBraceToken Then
' Check whether arguments should be reinterpreted as modifiers
If TryReinterpretAsArraySpecifier(Arguments, arrayModifiers) Then
Arguments = Nothing
End If
IsArrayCreationExpression = True
End If
If IsArrayCreationExpression Then
' Treat this as the form of New expression that allocates an array.
' TODO: this should be optional
Dim initializer = ParseCollectionInitializer()
Return SyntaxFactory.ArrayCreationExpression(
NewKeyword,
Nothing,
Type,
Arguments,
arrayModifiers,
initializer)
End If
End If
' Here we are after parsing " New Blah(a1,a2)"
Dim FromToken As KeywordSyntax = Nothing
If TryTokenAsContextualKeyword(CurrentToken, SyntaxKind.FromKeyword, FromToken) Then
' From is considered as an initializer only if followed by "{" or EOL
' For example, the following cases are initializers
' dim x1 = new C() from {
' dim x2 = new () from
' {
'
' But this is not.
' From i In {} Select p = New Object From j In {} Select j
'
' The second "From" starts a from query and is not an initializer.
If PeekToken(1).Kind = SyntaxKind.OpenBraceToken OrElse PeekToken(1).Kind = SyntaxKind.StatementTerminatorToken Then
GetNextToken()
Dim objInit = ParseObjectCollectionInitializer(FromToken)
If (CurrentToken.Kind = SyntaxKind.WithKeyword) Then
' TODO: this should actually go on the next token ( "With" )
' perhaps we should capture With as an unexpected syntax?
objInit = ReportSyntaxError(objInit, ERRID.ERR_CantCombineInitializers)
End If
Return SyntaxFactory.ObjectCreationExpression(NewKeyword, Nothing, Type, Arguments, objInit)
End If
End If
If CurrentToken.Kind = SyntaxKind.WithKeyword Then
' Parsing from "With" in "New Type(ParameterList) with {Initializer list}"
Dim objInit = ParseObjectInitializerList()
If (CurrentToken.Kind = SyntaxKind.WithKeyword) Then
' TODO: this should actually go on the next token ( "With" )
' perhaps we should capture With as an unexpected syntax?
objInit = ReportSyntaxError(objInit, ERRID.ERR_CantCombineInitializers)
End If
If TryTokenAsContextualKeyword(CurrentToken, SyntaxKind.FromKeyword, FromToken) AndAlso
PeekToken(1).Kind = SyntaxKind.OpenBraceToken Then
objInit = ReportSyntaxError(objInit, ERRID.ERR_CantCombineInitializers)
End If
Return SyntaxFactory.ObjectCreationExpression(NewKeyword, Nothing, Type, Arguments, objInit)
End If
Return SyntaxFactory.ObjectCreationExpression(NewKeyword, Nothing, Type, Arguments, Nothing)
End Function
''' <summary>
''' Parse TypeOf ... Is ... or TypeOf ... IsNot ...
''' TypeOfExpression -> "TypeOf" Expression "Is|IsNot" LineTerminator? TypeName
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Function ParseTypeOf() As TypeOfExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.TypeOfKeyword, "must be at TypeOf.")
Dim [typeOf] As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
' Consume 'TypeOf'.
GetNextToken()
Dim exp As ExpressionSyntax = ParseExpressionCore(OperatorPrecedence.PrecedenceRelational) 'Dev10 uses ParseVariable
If exp.ContainsDiagnostics Then
exp = ResyncAt(exp, SyntaxKind.IsKeyword, SyntaxKind.IsNotKeyword)
End If
Dim operatorToken As KeywordSyntax = Nothing
Dim current As SyntaxToken = CurrentToken
If current.Kind = SyntaxKind.IsKeyword OrElse
current.Kind = SyntaxKind.IsNotKeyword Then
operatorToken = DirectCast(current, KeywordSyntax)
If operatorToken.Kind = SyntaxKind.IsNotKeyword Then
operatorToken = CheckFeatureAvailability(Feature.TypeOfIsNot, operatorToken)
End If
GetNextToken()
TryEatNewLine(ScannerState.VB)
Else
operatorToken = DirectCast(HandleUnexpectedToken(SyntaxKind.IsKeyword), KeywordSyntax)
End If
Dim typeName = ParseGeneralType()
Dim kind As SyntaxKind = If(operatorToken.Kind = SyntaxKind.IsNotKeyword,
SyntaxKind.TypeOfIsNotExpression,
SyntaxKind.TypeOfIsExpression)
Return SyntaxFactory.TypeOfExpression(kind, [typeOf], exp, operatorToken, typeName)
End Function
' /*********************************************************************
' *
' * Function:
' * Parser::ParseVariable
' *
' * Purpose:
' *
' **********************************************************************/
' File: Parser.cpp
' Lines: 16191 - 16191
' Expression* .Parser::ParseVariable( [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseVariable() As ExpressionSyntax
Return ParseExpressionCore(OperatorPrecedence.PrecedenceRelational)
End Function
' /*********************************************************************
' *
' * Function:
' * Parser::ParseQualifiedExpr
' *
' * Purpose:
' * Parses a dot or bang reference, starting at the dot or bang.
' *
' **********************************************************************/
' [in] token starting term
' [in] stuff before "." or "!"
' File: Parser.cpp
' Lines: 16211 - 16211
' Expression* .Parser::ParseQualifiedExpr( [ _In_ Token* Start ] [ _In_opt_ ParseTree::Expression* Term ] [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseQualifiedExpr(
Term As ExpressionSyntax
) As ExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.DotToken OrElse
CurrentToken.Kind = SyntaxKind.ExclamationToken,
"Must be on either a '.' or '!' when entering parseQualifiedExpr()")
Dim DotOrBangToken As PunctuationSyntax = DirectCast(CurrentToken, PunctuationSyntax)
Dim prevPrevToken = PrevToken
GetNextToken()
If DotOrBangToken.Kind = SyntaxKind.ExclamationToken Then
Dim Name = ParseIdentifierNameAllowingKeyword()
Return SyntaxFactory.DictionaryAccessExpression(Term, DotOrBangToken, Name)
Else
If (CurrentToken.IsEndOfLine() AndAlso Not CurrentToken.IsEndOfParse()) Then
Debug.Assert(CurrentToken.Kind = SyntaxKind.StatementTerminatorToken AndAlso
PrevToken.Kind = SyntaxKind.DotToken,
"We shouldn't get here without .<eol> tokens")
'/* We know we are sitting on an EOL preceded by a tkDot. What we need to catch is the
' case where a tkDot following an EOL isn't preceded by a valid token. Bug Dev10_429652 For example:
' with i <eol>
' . <-- this is bad. This . follows an EOL and isn't preceded by a tkID. Can't have it dangling like this
' field = 42
'*/
If (prevPrevToken Is Nothing OrElse
prevPrevToken.Kind = SyntaxKind.StatementTerminatorToken) Then
' if ( CurrentToken->m_Prev->m_Prev == NULL || // make sure we can look back far enough. We know we can look back once, but twice we need to test
' CurrentToken->m_Prev->m_Prev->m_TokenType == tkEOL ) // Make sure there is something besides air before the '.' DEV10_486908
Dim missingIdent = ReportSyntaxError(InternalSyntaxFactory.MissingIdentifier, ERRID.ERR_ExpectedIdentifier)
' We are sitting on the tkEOL so let's just return this and keep parsing. No ReSync() needed here, in other words.
Return SyntaxFactory.SimpleMemberAccessExpression(Term, DotOrBangToken, SyntaxFactory.IdentifierName(missingIdent))
ElseIf Not NextLineStartsWithStatementTerminator() Then
'//ILC: undone
'// Right now we don't continue after a "." when the following tokens indicate XML member access
'// We should probably enable this.
TryEatNewLineIfNotFollowedBy(SyntaxKind.DotToken)
End If
End If
' Decide whether we're parsing:
' 1. Element axis i.e. ".<ident>"
' 2. Attribute axis i.e. ".@ident" or ".@<ident>
' 3. Descendant axis i.e. "...<ident>"
' 4. Regular CLR member axis i.e. ".ident"
Select Case (CurrentToken.Kind)
Case SyntaxKind.AtToken
Dim atToken = DirectCast(CurrentToken, PunctuationSyntax)
Dim name As XmlNodeSyntax
' Do not accept space or anything else between @ and name or <
If atToken.HasTrailingTrivia Then
GetNextToken(ScannerState.VB)
atToken = ReportSyntaxError(atToken, ERRID.ERR_ExpectedXmlName)
atToken = atToken.AddTrailingSyntax(ResyncAt())
name = SyntaxFactory.XmlName(Nothing, DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.XmlNameToken), XmlNameTokenSyntax))
Else
' Parse the Xml attribute name (allow name with and without angle brackets)
If PeekNextToken(ScannerState.VB).Kind = SyntaxKind.LessThanToken Then
' Consume the @ and remember that this is an element axis
GetNextToken(ScannerState.Element)
name = ParseBracketedXmlQualifiedName()
Else
' Consume the @ and remember that this is attribute axis
GetNextToken(ScannerState.VB)
name = ParseXmlQualifiedNameVB()
If name.HasLeadingTrivia Then
atToken = ReportSyntaxError(atToken, ERRID.ERR_ExpectedXmlName)
atToken.AddTrailingSyntax(name)
atToken.AddTrailingSyntax(ResyncAt())
name = SyntaxFactory.XmlName(Nothing, DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.XmlNameToken), XmlNameTokenSyntax))
End If
End If
End If
Return SyntaxFactory.XmlMemberAccessExpression(SyntaxKind.XmlAttributeAccessExpression, Term, DotOrBangToken, atToken, Nothing, name)
Case SyntaxKind.LessThanToken
' Remember that this is element axis
' Parse the Xml element name
Dim name = ParseBracketedXmlQualifiedName()
Return SyntaxFactory.XmlMemberAccessExpression(SyntaxKind.XmlElementAccessExpression, Term, DotOrBangToken, Nothing, Nothing, name)
Case SyntaxKind.DotToken
If PeekToken(1).Kind = SyntaxKind.DotToken Then
' Consume the 2nd and 3rd dots and remember that this is descendant axis
Dim secondDotToken = DirectCast(CurrentToken, PunctuationSyntax)
GetNextToken()
Dim thirdDotToken As PunctuationSyntax = Nothing
TryGetToken(SyntaxKind.DotToken, thirdDotToken)
' Parse the Xml element name
TryEatNewLineIfFollowedBy(SyntaxKind.LessThanToken)
Dim name As XmlBracketedNameSyntax
If CurrentToken.Kind = SyntaxKind.LessThanToken Then
name = ParseBracketedXmlQualifiedName()
Else
name = ReportExpectedXmlBracketedName()
End If
Return SyntaxFactory.XmlMemberAccessExpression(SyntaxKind.XmlDescendantAccessExpression, Term, DotOrBangToken, secondDotToken, thirdDotToken, name)
End If
Case Else
Dim name = ParseSimpleNameExpressionAllowingKeywordAndTypeArguments()
Return SyntaxFactory.SimpleMemberAccessExpression(Term, DotOrBangToken, name)
End Select
End If
'This is reachable with the following invalid syntax.
' p.
' x
'
' or
' p..y
Dim result As ExpressionSyntax
If CurrentToken.Kind = SyntaxKind.AtToken Then
Dim missingName = DirectCast(InternalSyntaxFactory.MissingToken(SyntaxKind.XmlNameToken), XmlNameTokenSyntax)
result = SyntaxFactory.XmlMemberAccessExpression(SyntaxKind.XmlAttributeAccessExpression,
Term,
DotOrBangToken, Nothing, Nothing,
ReportSyntaxError(InternalSyntaxFactory.XmlName(Nothing, missingName), ERRID.ERR_ExpectedXmlName))
Else
result = SyntaxFactory.SimpleMemberAccessExpression(Term, DotOrBangToken, ReportSyntaxError(InternalSyntaxFactory.IdentifierName(InternalSyntaxFactory.MissingIdentifier), ERRID.ERR_ExpectedIdentifier))
End If
Return result
End Function
Private Sub RescanTrailingColonAsToken(ByRef prevToken As SyntaxToken, ByRef currentToken As SyntaxToken)
_scanner.RescanTrailingColonAsToken(prevToken, currentToken)
_currentToken = currentToken
End Sub
''' <summary>
''' Transition from scanning XML to scanning VB. As a result,
''' any single line trivia is consumed and appended to the token
''' which is assumed to be the token at the transition point.
''' </summary>
Private Function TransitionFromXmlToVB(Of T As VisualBasicSyntaxNode)(node As T) As T
node = LastTokenReplacer.Replace(node, Function(token)
Dim trivia = New CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode)(token.GetTrailingTrivia())
Dim toRemove As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode) = Nothing
Dim toAdd As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode) = Nothing
_scanner.TransitionFromXmlToVB(trivia, toRemove, toAdd)
trivia = trivia.GetStartOfTrivia(trivia.Count - toRemove.Count)
token = DirectCast(token.WithTrailingTrivia(trivia.Node), SyntaxToken)
token = SyntaxToken.AddTrailingTrivia(token, toAdd)
Return token
End Function)
_currentToken = Nothing
Return node
End Function
Private Function TransitionFromVBToXml(Of T As VisualBasicSyntaxNode)(state As ScannerState, node As T) As T
node = LastTokenReplacer.Replace(node, Function(token)
Dim trivia = New CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode)(token.GetTrailingTrivia())
Dim toRemove As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode) = Nothing
Dim toAdd As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of VisualBasicSyntaxNode) = Nothing
_scanner.TransitionFromVBToXml(state, trivia, toRemove, toAdd)
trivia = trivia.GetStartOfTrivia(trivia.Count - toRemove.Count)
token = DirectCast(token.WithTrailingTrivia(trivia.Node), SyntaxToken)
token = SyntaxToken.AddTrailingTrivia(token, toAdd)
Return token
End Function)
_currentToken = Nothing
Return node
End Function
' File: Parser.cpp
' Lines: 16286 - 16286
' Expression* .Parser::ParseBracketedXmlQualifiedName( [ bool IsElement ] [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseBracketedXmlQualifiedName() As XmlBracketedNameSyntax
Dim lessToken As PunctuationSyntax = Nothing
' Parse '<', Xml QName, '>'
' Ensure the < is parsed in Xml state so that trivia on the < is correct. For example, we don't want comments attached
' to the < which can happen in a vb scanning state.
ResetCurrentToken(ScannerState.Content)
If TryGetToken(SyntaxKind.LessThanToken, lessToken) Then
' Next state is element so that a bracketed qualified name gets the > to close name.
' If state is VB a bracketed name followed by = does not get the > because >= is returned instead.
ResetCurrentToken(ScannerState.Element)
Dim name = ParseXmlQualifiedName(False, False, ScannerState.Element, ScannerState.Element)
Dim greaterToken As PunctuationSyntax = Nothing
VerifyExpectedToken(SyntaxKind.GreaterThanToken, greaterToken)
Dim result = SyntaxFactory.XmlBracketedName(lessToken, DirectCast(name, XmlNameSyntax), greaterToken)
result = AdjustTriviaForMissingTokens(result)
result = TransitionFromXmlToVB(result)
' Report an error if leading and trailing whitespace is found
Dim whitespaceChecker As New XmlWhitespaceChecker()
Return DirectCast(whitespaceChecker.Visit(result), XmlBracketedNameSyntax)
Else
ResetCurrentToken(ScannerState.VB)
Return ReportExpectedXmlBracketedName()
End If
End Function
Private Function ReportExpectedXmlBracketedName() As XmlBracketedNameSyntax
Dim lessToken = DirectCast(HandleUnexpectedToken(SyntaxKind.LessThanToken), PunctuationSyntax)
Dim name = ReportExpectedXmlName()
Dim greaterToken = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.GreaterThanToken)
Return SyntaxFactory.XmlBracketedName(lessToken, name, greaterToken)
End Function
Private Function ReportExpectedXmlName() As XmlNameSyntax
Return ReportSyntaxError(SyntaxFactory.XmlName(Nothing, SyntaxFactory.XmlNameToken("", SyntaxKind.XmlNameToken, Nothing, Nothing)), ERRID.ERR_ExpectedXmlName)
End Function
Private Function ParseParenthesizedExpressionOrTupleLiteral() As ExpressionSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.OpenParenToken)
' "(" expr ")" 'parenthesized
' "(" Name:= .... 'parse a tuple
' "(" expr, .... 'parse a tuple
Dim openParen As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.OpenParenToken, openParen)
If (CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso
PeekToken(1).Kind = SyntaxKind.ColonEqualsToken) Then
Dim argumentName = ParseIdentifierNameAllowingKeyword()
Dim colonEquals As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.ColonEqualsToken, colonEquals)
Dim nameColonEquals = SyntaxFactory.NameColonEquals(argumentName, colonEquals)
Dim firstArgument = SyntaxFactory.SimpleArgument(nameColonEquals, ParseExpressionCore())
Return ParseTheRestOfTupleLiteral(openParen, firstArgument)
End If
Dim operand = ParseExpressionCore()
If (CurrentToken.Kind = SyntaxKind.CommaToken) Then
Dim firstArgument = SyntaxFactory.SimpleArgument(nameColonEquals:=Nothing, expression:=operand)
Return ParseTheRestOfTupleLiteral(openParen, firstArgument)
End If
Dim closeParen As PunctuationSyntax = Nothing
TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=True)
Return SyntaxFactory.ParenthesizedExpression(openParen, operand, closeParen)
End Function
Private Function ParseTheRestOfTupleLiteral(openParen As PunctuationSyntax, firstArgument As SimpleArgumentSyntax) As TupleExpressionSyntax
Dim argumentBuilder = _pool.AllocateSeparated(Of SimpleArgumentSyntax)()
argumentBuilder.Add(firstArgument)
While CurrentToken.Kind = SyntaxKind.CommaToken
Dim commaToken As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, commaToken)
argumentBuilder.AddSeparator(commaToken)
Dim nameColonEquals As NameColonEqualsSyntax = Nothing
If (CurrentToken.Kind = SyntaxKind.IdentifierToken AndAlso
PeekToken(1).Kind = SyntaxKind.ColonEqualsToken) Then
Dim argumentName = ParseIdentifierNameAllowingKeyword()
Dim colonEquals As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.ColonEqualsToken, colonEquals)
nameColonEquals = SyntaxFactory.NameColonEquals(argumentName, colonEquals)
End If
Dim argument = SyntaxFactory.SimpleArgument(nameColonEquals, ParseExpressionCore())
argumentBuilder.Add(argument)
End While
Dim closeParen As PunctuationSyntax = Nothing
TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=True)
If argumentBuilder.Count < 2 Then
argumentBuilder.AddSeparator(InternalSyntaxFactory.MissingToken(SyntaxKind.CommaToken))
Dim missing = SyntaxFactory.IdentifierName(InternalSyntaxFactory.MissingIdentifier())
missing = ReportSyntaxError(missing, ERRID.ERR_TupleTooFewElements)
argumentBuilder.Add(SyntaxFactory.SimpleArgument(nameColonEquals:=Nothing, expression:=missing))
End If
Dim arguments = argumentBuilder.ToList
_pool.Free(argumentBuilder)
Dim tupleExpression = SyntaxFactory.TupleExpression(openParen, arguments, closeParen)
tupleExpression = CheckFeatureAvailability(Feature.Tuples, tupleExpression)
Return tupleExpression
End Function
' Parse an argument list enclosed in parentheses.
' File: Parser.cpp
' Lines: 16304 - 16304
' ParenthesizedArgumentList .Parser::ParseParenthesizedArguments( [ _Inout_ bool& ErrorInConstruct ] )
Friend Function ParseParenthesizedArguments(Optional RedimOrNewParent As Boolean = False, Optional attributeListParent As Boolean = False) As ArgumentListSyntax
Debug.Assert(CurrentToken.Kind = SyntaxKind.OpenParenToken, "should be at tkLParen.")
Dim arguments As CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(Of ArgumentSyntax) = Nothing
Dim openParen As PunctuationSyntax = Nothing
Dim closeParen As PunctuationSyntax = Nothing
Debug.Assert(CurrentToken.Kind = SyntaxKind.OpenParenToken)
TryGetTokenAndEatNewLine(SyntaxKind.OpenParenToken, openParen)
Dim unexpected As GreenNode = Nothing
arguments = ParseArguments(unexpected, RedimOrNewParent, attributeListParent)
If Not TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=False) Then
' On error, peek for ")" with "(". If ")" seen before
' "(", then sync on that. Otherwise, assume missing ")"
' and let caller decide.
Dim clue As SyntaxKind = PeekAheadFor(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken)
If clue = SyntaxKind.CloseParenToken Then
' We should not hit this case since ParseArguments should have
' resynced to the close paren and TryEatNewLineAndGetToken
' above should have succeeded. If we do hit this, add a test case.
Debug.Assert(False, "Unexpected close paren")
Dim trash = ResyncAt({SyntaxKind.CloseParenToken})
closeParen = DirectCast(CurrentToken, PunctuationSyntax)
closeParen = closeParen.AddLeadingSyntax(trash)
GetNextToken()
Else
closeParen = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.CloseParenToken)
closeParen = ReportSyntaxError(closeParen, ERRID.ERR_ExpectedRparen)
End If
End If
If unexpected IsNot Nothing Then
closeParen = closeParen.AddLeadingSyntax(unexpected)
End If
Return SyntaxFactory.ArgumentList(openParen, arguments, closeParen)
End Function
' /*********************************************************************
' *
' * Function:
' * Parser::ParseParenthesizedQualifier
' *
' * Purpose:
' * Parses a parenthesized qualifier:
' * <qualifier>(...)
' *
' **********************************************************************/
' [in] token starting term
' [in] preceding term
' File: Parser.cpp
' Lines: 16366 - 16366
' Expression* .Parser::ParseParenthesizedQualifier( [ _In_ Token* Start ] [ _In_ ParseTree::Expression* Term ] [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseParenthesizedQualifier(Term As ExpressionSyntax, Optional RedimOrNewParent As Boolean = False) As ExpressionSyntax
' Because parentheses are used for array indexing, parameter passing, and array
' declaring (via the Redim statement), there is some ambiguity about how to handle
' a parenthesized list that begins with an expression. The most general case is to
' parse it as an argument list, with special treatment if a TO occurs in a Redim
' context.
Dim Arguments = ParseParenthesizedArguments(RedimOrNewParent)
Return SyntaxFactory.InvocationExpression(Term, Arguments)
End Function
' Parse a list of comma-separated arguments.
' Where to insert the next list element
' File: Parser.cpp
' Lines: 16425 - 16425
' .Parser::ParseArguments( [ _In_ ParseTree::ArgumentList** Target ] [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseArguments(ByRef unexpected As GreenNode, Optional RedimOrNewParent As Boolean = False, Optional attributeListParent As Boolean = False) As CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(Of ArgumentSyntax)
Dim arguments = _pool.AllocateSeparated(Of ArgumentSyntax)()
Dim allowNonTrailingNamedArguments = _scanner.Options.LanguageVersion.AllowNonTrailingNamedArguments()
Dim seenNames As Boolean = False
Do
Dim isNamed As Boolean = False
If (CurrentToken.Kind = SyntaxKind.IdentifierToken OrElse CurrentToken.IsKeyword()) AndAlso
PeekToken(1).Kind = SyntaxKind.ColonEqualsToken Then
seenNames = True
isNamed = True
End If
Dim comma As PunctuationSyntax = Nothing
If isNamed Then
If attributeListParent Then
ParseNamedArguments(arguments)
Exit Do
End If
Dim argumentName As IdentifierNameSyntax = ParseIdentifierNameAllowingKeyword()
Dim colonEquals As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.ColonEqualsToken, colonEquals)
Dim namedArgument = SyntaxFactory.SimpleArgument(SyntaxFactory.NameColonEquals(argumentName, colonEquals), ParseExpressionCore())
arguments.Add(namedArgument)
ElseIf CurrentToken.Kind = SyntaxKind.CommaToken Then
TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma)
Dim argument = ReportNonTrailingNamedArgumentIfNeeded(InternalSyntaxFactory.OmittedArgument(), seenNames, allowNonTrailingNamedArguments)
arguments.Add(argument)
arguments.AddSeparator(comma)
Continue Do
ElseIf CurrentToken.Kind = SyntaxKind.CloseParenToken Then
If arguments.Count > 0 Then
Dim argument = ReportNonTrailingNamedArgumentIfNeeded(InternalSyntaxFactory.OmittedArgument(), seenNames, allowNonTrailingNamedArguments)
arguments.Add(argument)
End If
Exit Do
Else
Dim argument = ParseArgument(RedimOrNewParent)
argument = ReportNonTrailingNamedArgumentIfNeeded(argument, seenNames, allowNonTrailingNamedArguments)
arguments.Add(argument)
End If
If TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
arguments.AddSeparator(comma)
Continue Do
ElseIf CurrentToken.Kind = SyntaxKind.CloseParenToken OrElse MustEndStatement(CurrentToken) Then
Exit Do
Else
' There is a syntax error of some kind.
Dim skipped = ResyncAt({SyntaxKind.CommaToken, SyntaxKind.CloseParenToken}).Node
If skipped IsNot Nothing Then
skipped = ReportSyntaxError(skipped, ERRID.ERR_ArgumentSyntax)
End If
If CurrentToken.Kind = SyntaxKind.CommaToken Then
comma = DirectCast(CurrentToken, PunctuationSyntax)
comma = comma.AddLeadingSyntax(skipped)
arguments.AddSeparator(comma)
GetNextToken()
Else
unexpected = skipped
Exit Do
End If
End If
Loop
Dim result = arguments.ToList
_pool.Free(arguments)
Return result
End Function
''' <summary>After VB15.5 it is possible to use named arguments in non-trailing position, except in attribute lists (where it remains disallowed)</summary>
Private Shared Function ReportNonTrailingNamedArgumentIfNeeded(argument As ArgumentSyntax, seenNames As Boolean, allowNonTrailingNamedArguments As Boolean) As ArgumentSyntax
If Not seenNames OrElse allowNonTrailingNamedArguments Then
Return argument
End If
Return ReportSyntaxError(argument, ERRID.ERR_ExpectedNamedArgument,
New VisualBasicRequiredLanguageVersion(Feature.NonTrailingNamedArguments.GetLanguageVersion()))
End Function
' Parse a list of comma-separated keyword arguments.
' Where to insert the next list element
' File: Parser.cpp
' Lines: 16515 - 16515
' .Parser::ParseNamedArguments( [ ParseTree::ArgumentList** Target ] [ _Inout_ bool& ErrorInConstruct ] )
Private Sub ParseNamedArguments(arguments As SeparatedSyntaxListBuilder(Of ArgumentSyntax))
Do
Dim argumentName As IdentifierNameSyntax
Dim colonEquals As PunctuationSyntax = Nothing
Dim hasError As Boolean = False
If (CurrentToken.Kind = SyntaxKind.IdentifierToken OrElse CurrentToken.IsKeyword()) AndAlso
PeekToken(1).Kind = SyntaxKind.ColonEqualsToken Then
argumentName = ParseIdentifierNameAllowingKeyword()
TryGetTokenAndEatNewLine(SyntaxKind.ColonEqualsToken, colonEquals)
Else
argumentName = SyntaxFactory.IdentifierName(InternalSyntaxFactory.MissingIdentifier())
colonEquals = InternalSyntaxFactory.MissingPunctuation(SyntaxKind.ColonEqualsToken)
hasError = True
End If
If hasError Then
argumentName = ReportSyntaxError(argumentName, ERRID.ERR_ExpectedNamedArgumentInAttributeList)
End If
Dim namedArgument = SyntaxFactory.SimpleArgument(SyntaxFactory.NameColonEquals(argumentName, colonEquals), ParseExpressionCore())
If CurrentToken.Kind <> SyntaxKind.CommaToken Then
If CurrentToken.Kind = SyntaxKind.CloseParenToken OrElse MustEndStatement(CurrentToken) Then
arguments.Add(namedArgument)
Exit Do
End If
' There is a syntax error of some kind.
namedArgument = ReportSyntaxError(namedArgument, ERRID.ERR_ArgumentSyntax)
namedArgument = ResyncAt(namedArgument, SyntaxKind.CommaToken, SyntaxKind.CloseParenToken)
If CurrentToken.Kind <> SyntaxKind.CommaToken Then
arguments.Add(namedArgument)
Exit Do
End If
End If
Dim comma As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma)
Debug.Assert(comma.Kind = SyntaxKind.CommaToken)
arguments.Add(namedArgument)
arguments.AddSeparator(comma)
Loop
End Sub
' File: Parser.cpp
' Lines: 16564 - 16564
' Argument* .Parser::ParseArgument( [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseArgument(Optional RedimOrNewParent As Boolean = False) As ArgumentSyntax
Dim argument As ArgumentSyntax
Dim value As ExpressionSyntax = ParseExpressionCore(OperatorPrecedence.PrecedenceNone)
If value.ContainsDiagnostics Then
value = ResyncAt(value, SyntaxKind.CommaToken, SyntaxKind.CloseParenToken)
End If
If RedimOrNewParent AndAlso CurrentToken.Kind = SyntaxKind.ToKeyword Then
Dim toKeyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
Dim lowerBound As ExpressionSyntax = value
GetNextToken() ' consume tkTO
value = ParseExpressionCore(OperatorPrecedence.PrecedenceNone)
' Check that lower bound is equal to 0 moved to binder.
argument = SyntaxFactory.RangeArgument(lowerBound, toKeyword, value)
Else
argument = SyntaxFactory.SimpleArgument(Nothing, value)
End If
Return argument
End Function
''' <summary>
''' ParseCast parses CType, DirectCast, TryCast.
''' CCCastExpression -> DirectCast ( CCExpression , TypeName )
''' | TryCast ( CCExpression , TypeName )
''' | CType ( CCExpression , TypeName )
''' { | CastTarget ( CCExpression ) }
''' </summary>
''' <returns>Cast</returns>
''' <remarks>Dev10 ParseCType does not parse exact grammar in the spec, since dev10 accepts Expression whereas the grammar uses CCExpression.
''' This function only does not parse CastTarget ( ... ), it is parsed in ParseTerm
''' </remarks>
Private Function ParseCast() As CastExpressionSyntax
Dim keyword As KeywordSyntax = DirectCast(CurrentToken, KeywordSyntax)
Dim keywordKind As SyntaxKind = keyword.Kind
Debug.Assert(keywordKind = SyntaxKind.CTypeKeyword OrElse
keywordKind = SyntaxKind.DirectCastKeyword OrElse
keywordKind = SyntaxKind.TryCastKeyword,
"Expected CTYPE or DIRECTCAST or TRYCAST token.")
GetNextToken()
Dim openParen As PunctuationSyntax = Nothing
TryGetTokenAndEatNewLine(SyntaxKind.OpenParenToken, openParen, createIfMissing:=True)
Dim exp As ExpressionSyntax = ParseExpressionCore(OperatorPrecedence.PrecedenceNone)
If exp.ContainsDiagnostics Then
exp = ResyncAt(exp, SyntaxKind.CommaToken, SyntaxKind.CloseParenToken)
End If
Dim comma As PunctuationSyntax = Nothing
If Not TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
comma = ReportSyntaxError(InternalSyntaxFactory.MissingPunctuation(SyntaxKind.CommaToken),
ERRID.ERR_SyntaxInCastOp)
End If
Dim targetType As TypeSyntax = ParseGeneralType()
Dim closeParen As PunctuationSyntax = Nothing
TryEatNewLineAndGetToken(SyntaxKind.CloseParenToken, closeParen, createIfMissing:=True)
Dim cast As CastExpressionSyntax = Nothing
Select Case keywordKind
Case SyntaxKind.CTypeKeyword
cast = SyntaxFactory.CTypeExpression(keyword, openParen, exp, comma, targetType, closeParen)
Case SyntaxKind.DirectCastKeyword
cast = SyntaxFactory.DirectCastExpression(keyword, openParen, exp, comma, targetType, closeParen)
Case SyntaxKind.TryCastKeyword
cast = SyntaxFactory.TryCastExpression(keyword, openParen, exp, comma, targetType, closeParen)
Case Else
Throw ExceptionUtilities.UnexpectedValue(keywordKind)
End Select
Return cast
End Function
Private Function ParseFunctionOrSubLambdaHeader(<Out> ByRef isMultiLine As Boolean, Optional parseModifiers As Boolean = False) As LambdaHeaderSyntax
Dim modifiers As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of KeywordSyntax)
Dim save_isInMethodDeclarationHeader As Boolean = _isInMethodDeclarationHeader
_isInMethodDeclarationHeader = True
Dim save_isInAsyncMethodDeclarationHeader As Boolean = _isInAsyncMethodDeclarationHeader
Dim save_isInIteratorMethodDeclarationHeader As Boolean = _isInIteratorMethodDeclarationHeader
If parseModifiers Then
Debug.Assert(CurrentToken.Kind = SyntaxKind.IdentifierToken)
modifiers = ParseSpecifiers()
_isInAsyncMethodDeclarationHeader = modifiers.Any(SyntaxKind.AsyncKeyword)
_isInIteratorMethodDeclarationHeader = modifiers.Any(SyntaxKind.IteratorKeyword)
Else
modifiers = Nothing
_isInAsyncMethodDeclarationHeader = False
_isInIteratorMethodDeclarationHeader = False
End If
Debug.Assert(CurrentToken.Kind = SyntaxKind.FunctionKeyword OrElse
CurrentToken.Kind = SyntaxKind.SubKeyword,
"ParseFunctionLambda called on wrong token.")
' The current token is on the function or delegate's name
Dim methodKeyword = DirectCast(CurrentToken, KeywordSyntax)
GetNextToken()
Dim genericParams As TypeParameterListSyntax = Nothing
Dim openParen As PunctuationSyntax = Nothing
Dim params As CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(Of ParameterSyntax) = Nothing
Dim closeParen As PunctuationSyntax = Nothing
isMultiLine = False
If CurrentToken.Kind = SyntaxKind.OpenParenToken Then
TryRejectGenericParametersForMemberDecl(genericParams)
End If
If CurrentToken.Kind = SyntaxKind.OpenParenToken Then
params = ParseParameters(openParen, closeParen)
Else
openParen = DirectCast(HandleUnexpectedToken(SyntaxKind.OpenParenToken), PunctuationSyntax)
closeParen = DirectCast(HandleUnexpectedToken(SyntaxKind.CloseParenToken), PunctuationSyntax)
End If
Debug.Assert(openParen IsNot Nothing)
Debug.Assert(closeParen IsNot Nothing)
If genericParams IsNot Nothing Then
openParen = openParen.AddLeadingSyntax(genericParams, ERRID.ERR_GenericParamsOnInvalidMember)
End If
Dim asClause As SimpleAsClauseSyntax = Nothing
Dim returnTypeAttributes As CodeAnalysis.Syntax.InternalSyntax.SyntaxList(Of AttributeListSyntax) = Nothing
Dim asKeyword As KeywordSyntax = Nothing
' Check the return type.
' Parse the as clause if one exists even if this is a sub. This aids in error recovery situations. Otherwise,
' Sub () as integer
' becomes a single line sub lambda.
If CurrentToken.Kind = SyntaxKind.AsKeyword Then
asKeyword = DirectCast(CurrentToken, KeywordSyntax)
GetNextToken()
If CurrentToken.Kind = SyntaxKind.LessThanToken Then
returnTypeAttributes = ParseAttributeLists(False)
asKeyword = asKeyword.AddTrailingSyntax(returnTypeAttributes.Node, ERRID.ERR_AttributeOnLambdaReturnType)
End If
Dim returnType As TypeSyntax = ParseGeneralType()
If returnType.ContainsDiagnostics Then
returnType = ResyncAt(returnType)
End If
asClause = SyntaxFactory.SimpleAsClause(asKeyword, Nothing, returnType)
isMultiLine = True
End If
If methodKeyword.Kind <> SyntaxKind.FunctionKeyword AndAlso asClause IsNot Nothing Then
closeParen = closeParen.AddTrailingSyntax(asClause, ERRID.ERR_ExpectedEOS)
asClause = Nothing
End If
isMultiLine = isMultiLine OrElse CurrentToken.Kind = SyntaxKind.StatementTerminatorToken
_isInMethodDeclarationHeader = save_isInMethodDeclarationHeader
_isInAsyncMethodDeclarationHeader = save_isInAsyncMethodDeclarationHeader
_isInIteratorMethodDeclarationHeader = save_isInIteratorMethodDeclarationHeader
Return SyntaxFactory.LambdaHeader(If(methodKeyword.Kind = SyntaxKind.FunctionKeyword, SyntaxKind.FunctionLambdaHeader, SyntaxKind.SubLambdaHeader),
Nothing, modifiers, methodKeyword, SyntaxFactory.ParameterList(openParen, params, closeParen), asClause)
End Function
'TODO - Review all errors in Dev10 ParseStatementLambda
' Ensure messages are reported and messages are added to error resource.
' The following cases are allowed by the new parser but errors in dev10
'
'ERRID_SubDisallowsStatement for Sub() Dim x=e1 , y=e2
Private Function ParseLambda(parseModifiers As Boolean) As ExpressionSyntax
'AssertLanguageFeature(ERRID.FEATUREID_StatementLambdas, CurrentToken)
Dim isMultiLine As Boolean = False
Dim header = ParseFunctionOrSubLambdaHeader(isMultiLine, parseModifiers)
header = AdjustTriviaForMissingTokens(header)
Dim value As ExpressionSyntax
If header.Kind = SyntaxKind.FunctionLambdaHeader AndAlso Not isMultiLine Then
' This is a single line lambda function
Dim lambdaContext = New SingleLineLambdaContext(header, _context)
_context = lambdaContext
value = SyntaxFactory.SingleLineLambdaExpression(SyntaxKind.SingleLineFunctionLambdaExpression,
header,
ParseExpressionCore())
value = AdjustTriviaForMissingTokens(value)
If header.Modifiers.Any(SyntaxKind.IteratorKeyword) Then
value = Parser.ReportSyntaxError(value, ERRID.ERR_BadIteratorExpressionLambda)
End If
Debug.Assert(_context Is lambdaContext)
_context = lambdaContext.PrevBlock
Else
Dim statementContext = _context 'This is the statement context that contains the lambda expression
'This is either a single line sub or multi line lambda sub or function
Dim lambdaContext As MethodBlockContext
If isMultiLine Then
lambdaContext = New LambdaContext(header, statementContext)
Else
lambdaContext = New SingleLineLambdaContext(header, statementContext)
End If
_context = lambdaContext
If isMultiLine OrElse CurrentToken.Kind = SyntaxKind.ColonToken Then
_context = _context.ResyncAndProcessStatementTerminator(header, lambdaContext)
End If
Dim statement As StatementSyntax = Nothing
While _context.Level >= lambdaContext.Level
If CurrentToken.IsEndOfParse() Then
_context = _context.EndLambda()
Exit While
End If
statement = _context.Parse()
statement = AdjustTriviaForMissingTokens(statement)
Dim isDeclaration = IsDeclarationStatement(statement.Kind)
If isDeclaration Then
' A declaration always closes a lambda.
_context.Add(ReportSyntaxError(statement, ERRID.ERR_InvInsideEndsProc))
Else
_context = _context.LinkSyntax(statement)
If _context.Level < lambdaContext.Level Then
Exit While
End If
End If
_context = _context.ResyncAndProcessStatementTerminator(statement, lambdaContext)
statement = Nothing
If isDeclaration Then
If _context.Level >= lambdaContext.Level Then
_context = _context.EndLambda()
End If
Exit While
End If
End While
Debug.Assert(_context Is statementContext, "Lambda terminated with the wrong context.")
value = DirectCast(lambdaContext.CreateBlockSyntax(statement), ExpressionSyntax)
End If
If isMultiLine Then
value = CheckFeatureAvailability(Feature.StatementLambdas, value)
End If
Return value
End Function
Friend Shared Function IsDeclarationStatement(kind As SyntaxKind) As Boolean
Select Case kind
Case _
SyntaxKind.SubStatement,
SyntaxKind.SubNewStatement,
SyntaxKind.FunctionStatement,
SyntaxKind.OperatorStatement,
SyntaxKind.PropertyStatement,
SyntaxKind.EventStatement,
SyntaxKind.NamespaceStatement,
SyntaxKind.ClassStatement,
SyntaxKind.StructureStatement,
SyntaxKind.EnumStatement,
SyntaxKind.ModuleStatement,
SyntaxKind.InterfaceStatement,
SyntaxKind.SetAccessorStatement,
SyntaxKind.GetAccessorStatement,
SyntaxKind.DeclareSubStatement,
SyntaxKind.DeclareFunctionStatement,
SyntaxKind.DelegateFunctionStatement,
SyntaxKind.DelegateSubStatement
Return True
Case Else
Return False
End Select
End Function
' Parse a list of comma-separated Variables.
' File: Parser.cpp
' Lines: 16738 - 16738
' ExpressionList* .Parser::ParseVariableList( [ _Inout_ bool& ErrorInConstruct ] )
Private Function ParseVariableList() As CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(Of ExpressionSyntax)
Dim variables As SeparatedSyntaxListBuilder(Of ExpressionSyntax) = Me._pool.AllocateSeparated(Of ExpressionSyntax)()
Do
variables.Add(ParseVariable())
Dim comma As PunctuationSyntax = Nothing
If Not TryGetTokenAndEatNewLine(SyntaxKind.CommaToken, comma) Then
Exit Do
End If
variables.AddSeparator(comma)
Loop
Dim result = variables.ToList
Me._pool.Free(variables)
Return result
End Function
Private Function ParseAwaitExpression(Optional awaitKeyword As KeywordSyntax = Nothing) As AwaitExpressionSyntax
Debug.Assert(DirectCast(CurrentToken, IdentifierTokenSyntax).ContextualKind = SyntaxKind.AwaitKeyword)
If awaitKeyword Is Nothing Then
TryIdentifierAsContextualKeyword(CurrentToken, awaitKeyword)
Debug.Assert(awaitKeyword IsNot Nothing AndAlso awaitKeyword.Kind = SyntaxKind.AwaitKeyword)
End If
GetNextToken()
Dim expression = ParseTerm()
Return SyntaxFactory.AwaitExpression(awaitKeyword, expression)
End Function
End Class
End Namespace
|