예제 #1
0
        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);
            }
        }
예제 #2
0
        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);
            }
        }
예제 #4
0
 //
 // 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));
 }
예제 #5
0
        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);
            }
        }
예제 #6
0
 //
 // 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);
 }