private bool IsPossibleDeclarationExpression(ParseTypeMode mode, bool permitTupleDesignation) { if (this.IsInAsync && this.CurrentToken.ContextualKind == SyntaxKind.AwaitKeyword) { // can't be a declaration expression. return(false); } var resetPoint = this.GetResetPoint(); try { bool typeIsVar = IsVarType(); SyntaxToken lastTokenOfType; if (ScanType(mode, out lastTokenOfType) == ScanTypeFlags.NotType) { return(false); } // check for a designation if (!ScanDesignation(permitTupleDesignation && (typeIsVar || IsPredefinedType(lastTokenOfType.Kind)))) { return(false); } return(mode != ParseTypeMode.FirstElementOfPossibleTupleLiteral || this.CurrentToken.Kind == SyntaxKind.CommaToken); } finally { this.Reset(ref resetPoint); this.Release(ref resetPoint); } }
private bool IsPossibleDeclarationExpression(ParseTypeMode mode, bool permitTupleDesignation) { if (this.IsInAsync && this.CurrentToken.ContextualKind == SyntaxKind.AwaitKeyword) { // can't be a declaration expression. return(false); } var resetPoint = this.GetResetPoint(); try { bool typeIsVar = IsVarType(); SyntaxToken lastTokenOfType; if (ScanType(mode, out lastTokenOfType) == ScanTypeFlags.NotType) { return(false); } // check for a designation if (!ScanDesignation(permitTupleDesignation && (typeIsVar || IsPredefinedType(lastTokenOfType.Kind)))) { return(false); } switch (mode) { case ParseTypeMode.FirstElementOfPossibleTupleLiteral: return(this.CurrentToken.Kind == SyntaxKind.CommaToken); case ParseTypeMode.AfterTupleComma: return(this.CurrentToken.Kind == SyntaxKind.CommaToken || this.CurrentToken.Kind == SyntaxKind.CloseParenToken); default: // The other case where we disambiguate between a declaration and expression is before the `in` of a foreach loop. // There we err on the side of accepting a declaration. return(true); } } finally { this.Reset(ref resetPoint); this.Release(ref resetPoint); } }
private bool IsPossibleDeclarationExpression(ParseTypeMode mode, bool permitTupleDesignation) { if (this.IsInAsync && this.CurrentToken.ContextualKind == SyntaxKind.AwaitKeyword) { // can't be a declaration expression. return(false); } var resetPoint = this.GetResetPoint(); try { bool typeIsVar = IsVarType(); SyntaxToken lastTokenOfType; switch (ScanType(out lastTokenOfType)) { case ScanTypeFlags.PointerOrMultiplication: if (mode == ParseTypeMode.FirstElementOfPossibleTupleLiteral || mode == ParseTypeMode.AfterTupleComma) { // Tuples cannot contain pointer types because pointers may not be generic type arguments. return(false); } break; case ScanTypeFlags.NotType: return(false); } // check for a designation if (!ScanDesignation(permitTupleDesignation && (typeIsVar || IsPredefinedType(lastTokenOfType.Kind)))) { return(false); } return(mode != ParseTypeMode.FirstElementOfPossibleTupleLiteral || this.CurrentToken.Kind == SyntaxKind.CommaToken); } finally { this.Reset(ref resetPoint); this.Release(ref resetPoint); } }
// // Parse an expression where a declaration expression would be permitted. This is suitable for use after // the `out` keyword in an argument list, or in the elements of a tuple literal (because they may // be on the left-hand-side of a positional subpattern). The first element of a tuple is handled slightly // differently, as we check for the comma before concluding that the identifier should cause a // disambiguation. For example, for the input `(A < B , C > D)`, we treat this as a tuple with // two elements, because if we considered the `A<B,C>` to be a type, it wouldn't be a tuple at // all. Since we don't have such a thing as a one-element tuple (even for positional subpattern), the // absence of the comma after the `D` means we don't treat the `D` as contributing to the // disambiguation of the expression/type. More formally, ... // // If a sequence of tokens can be parsed(in context) as a* simple-name* (§7.6.3), *member-access* (§7.6.5), // or* pointer-member-access* (§18.5.2) ending with a* type-argument-list* (§4.4.1), the token immediately // following the closing `>` token is examined, to see if it is // - One of `( ) ] } : ; , . ? == != | ^ && || & [`; or // - One of the relational operators `< > <= >= is as`; or // - A contextual query keyword appearing inside a query expression; or // - In certain contexts, we treat *identifier* as a disambiguating token.Those contexts are where the // sequence of tokens being disambiguated is immediately preceded by one of the keywords `is`, `case` // or `out`, or arises while parsing the first element of a tuple literal(in which case the tokens are // preceded by `(` or `:` and the identifier is followed by a `,`) or a subsequent element of a tuple literal. // // If the following token is among this list, or an identifier in such a context, then the *type-argument-list* is // retained as part of the *simple-name*, *member-access* or *pointer-member-access* and any other possible parse // of the sequence of tokens is discarded.Otherwise, the *type-argument-list* is not considered to be part of the // *simple-name*, *member-access* or *pointer-member-access*, even if there is no other possible parse of the // sequence of tokens.Note that these rules are not applied when parsing a *type-argument-list* in a *namespace-or-type-name* (§3.8). // // See also ScanTypeArgumentList where these disambiguation rules are encoded. // private ExpressionSyntax ParseExpressionOrDeclaration(ParseTypeMode mode, MessageID feature, bool permitTupleDesignation) { return(IsPossibleDeclarationExpression(mode, permitTupleDesignation) ? this.ParseDeclarationExpression(mode, feature) : this.ParseSubExpression(Precedence.Expression)); }
private bool IsPossibleDeclarationExpression(ParseTypeMode mode, bool permitTupleDesignation) { if (this.IsInAsync && this.CurrentToken.ContextualKind == SyntaxKind.AwaitKeyword) { // can't be a declaration expression. return false; } var resetPoint = this.GetResetPoint(); try { bool typeIsVar = IsVarType(); SyntaxToken lastTokenOfType; switch (ScanType(out lastTokenOfType)) { case ScanTypeFlags.PointerOrMultiplication: if (mode == ParseTypeMode.FirstElementOfPossibleTupleLiteral || mode == ParseTypeMode.AfterTupleComma) { // Tuples cannot contain pointer types because pointers may not be generic type arguments. return false; } break; case ScanTypeFlags.NotType: return false; } // check for a designation if (!ScanDesignation(permitTupleDesignation && (typeIsVar || IsPredefinedType(lastTokenOfType.Kind)))) { return false; } return mode != ParseTypeMode.FirstElementOfPossibleTupleLiteral || this.CurrentToken.Kind == SyntaxKind.CommaToken; } finally { this.Reset(ref resetPoint); this.Release(ref resetPoint); } }
// // Parse an expression where a declaration expression would be permitted. This is suitable for use after // the `out` keyword in an argument list, or in the elements of a tuple literal (because they may // be on the left-hand-side of a deconstruction). The first element of a tuple is handled slightly // differently, as we check for the comma before concluding that the identifier should cause a // disambiguation. For example, for the input `(A < B , C > D)`, we treat this as a tuple with // two elements, because if we considered the `A<B,C>` to be a type, it wouldn't be a tuple at // all. Since we don't have such a thing as a one-element tuple (even for deconstruction), the // absence of the comma after the `D` means we don't treat the `D` as contributing to the // disambiguation of the expression/type. More formally, ... // // If a sequence of tokens can be parsed(in context) as a* simple-name* (§7.6.3), *member-access* (§7.6.5), // or* pointer-member-access* (§18.5.2) ending with a* type-argument-list* (§4.4.1), the token immediately // following the closing `>` token is examined, to see if it is // - One of `( ) ] } : ; , . ? == != | ^ && || & [`; or // - One of the relational operators `< > <= >= is as`; or // - A contextual query keyword appearing inside a query expression; or // - In certain contexts, we treat *identifier* as a disambiguating token.Those contexts are where the // sequence of tokens being disambiguated is immediately preceded by one of the keywords `is`, `case` // or `out`, or arises while parsing the first element of a tuple literal(in which case the tokens are // preceded by `(` or `:` and the identifier is followed by a `,`) or a subsequent element of a tuple literal. // // If the following token is among this list, or an identifier in such a context, then the *type-argument-list* is // retained as part of the *simple-name*, *member-access* or *pointer-member-access* and any other possible parse // of the sequence of tokens is discarded.Otherwise, the *type-argument-list* is not considered to be part of the // *simple-name*, *member-access* or *pointer-member-access*, even if there is no other possible parse of the // sequence of tokens.Note that these rules are not applied when parsing a *type-argument-list* in a *namespace-or-type-name* (§3.8). // // See also ScanTypeArgumentList where these disambiguation rules are encoded. // private ExpressionSyntax ParseExpressionOrDeclaration(ParseTypeMode mode, MessageID feature, bool permitTupleDesignation) { return IsPossibleDeclarationExpression(mode, permitTupleDesignation) ? this.ParseDeclarationExpression(mode, feature) : this.ParseSubExpression(Precedence.Expression); }