Ejemplo n.º 1
0
        public void SyntaxFactsMethods()
        {
            Assert.AreEqual("protected internal", SyntaxFacts.GetText(Accessibility.ProtectedOrInternal));
            Assert.AreEqual("??", SyntaxFacts.GetText(SyntaxKind.QuestionQuestionToken));
            Assert.AreEqual("this", SyntaxFacts.GetText(SyntaxKind.ThisKeyword));

            Assert.AreEqual(SyntaxKind.CharacterLiteralExpression, SyntaxFacts.GetLiteralExpression(SyntaxKind.CharacterLiteralToken));
            Assert.AreEqual(SyntaxKind.CoalesceExpression, SyntaxFacts.GetBinaryExpression(SyntaxKind.QuestionQuestionToken));
            Assert.AreEqual(SyntaxKind.None, SyntaxFacts.GetBinaryExpression(SyntaxKind.UndefDirectiveTrivia));
            Assert.AreEqual(false, SyntaxFacts.IsPunctuation(SyntaxKind.StringLiteralToken));
        }
Ejemplo n.º 2
0
        private ExpressionSyntax ParseEquality()
        {
            var left = this.ParseLogicalNot();
            while (this.CurrentToken.Kind == SyntaxKind.EqualsEqualsToken || this.CurrentToken.Kind == SyntaxKind.ExclamationEqualsToken)
            {
                var op = this.EatToken();
                var right = this.ParseEquality();
                left = SyntaxFactory.BinaryExpression(SyntaxFacts.GetBinaryExpression(op.Kind), left, op, right);
            }

            return left;
        }
Ejemplo n.º 3
0
        private static bool BinaryTokenNeedsSeparator(SyntaxKind kind)
        {
            switch (kind)
            {
            case SyntaxKind.DotToken:
            case SyntaxKind.MinusGreaterThanToken:
                return(false);

            default:
                return(SyntaxFacts.GetBinaryExpression(kind) != SyntaxKind.None);
            }
        }
        public void TestBinaryOperators(SyntaxKind kind)
        {
            var text = "(a) " + kind.GetText() + " b";
            var expr = ParseExpression(text);

            Assert.NotNull(expr);
            var opKind = SyntaxFacts.GetBinaryExpression(kind);

            Assert.Equal(opKind, expr.Kind);
            Assert.Equal(text, expr.ToString());
            Assert.Equal(0, expr.GetDiagnostics().Count());
            var b = (BinaryExpressionSyntax)expr;

            Assert.NotNull(b.OperatorToken);
            Assert.Equal(kind, b.OperatorToken.Kind);
            Assert.NotNull(b.Left);
            Assert.NotNull(b.Right);
            Assert.Equal("(a)", b.Left.ToString());
            Assert.Equal("b", b.Right.ToString());
        }
Ejemplo n.º 5
0
        private ExpressionSyntax ParseSubExpression(Precedence precedence)
        {
            ExpressionSyntax leftOperand   = null;
            Precedence       newPrecedence = 0;
            SyntaxKind       opKind        = SyntaxKind.None;

            var tk = CurrentToken.Kind;

            leftOperand = ParseTerm(precedence);

            while (true)
            {
                tk = CurrentToken.Kind;

                if (IsExpectedBinaryOperator(tk))
                {
                    opKind = SyntaxFacts.GetBinaryExpression(tk);
                }
                else
                {
                    break;
                }

                newPrecedence = GetPrecedence(opKind);

                if (newPrecedence <= precedence)
                {
                    break;
                }

                var opToken = EatToken(tk);

                leftOperand = SyntaxFactory.BinaryExpression(opKind, leftOperand, opToken, ParseSubExpression(newPrecedence));
            }

            return(leftOperand);
        }
Ejemplo n.º 6
0
        // Priority is the TypeSyntax. It might return TypeSyntax which might be a constant pattern such as enum 'Days.Sunday'
        // We handle such cases in the binder of is operator.
        // It is used for parsing patterns in the is operators.
        private CSharpSyntaxNode ParseTypeOrPattern()
        {
            var tk = this.CurrentToken.Kind;
            CSharpSyntaxNode node = null;

            switch (tk)
            {
            case SyntaxKind.CloseParenToken:
            case SyntaxKind.CloseBracketToken:
            case SyntaxKind.CloseBraceToken:
            case SyntaxKind.SemicolonToken:
            case SyntaxKind.CommaToken:
                // HACK: for error recovery, we prefer a (missing) type.
                return(this.ParseTypeCore(parentIsParameter: false, isOrAs: true, expectSizes: false, isArrayCreation: false));

            default:
                // attempt to disambiguate.
                break;
            }

            // If it is a nameof, skip the 'if' and parse as a constant pattern.
            if (SyntaxFacts.IsPredefinedType(tk) ||
                (tk == SyntaxKind.IdentifierToken && this.CurrentToken.ContextualKind != SyntaxKind.NameOfKeyword))
            {
                var resetPoint = this.GetResetPoint();
                try
                {
                    TypeSyntax type = this.ParseTypeCore(parentIsParameter: false, isOrAs: true, expectSizes: false, isArrayCreation: false);

                    tk = this.CurrentToken.ContextualKind;
                    if (!type.IsMissing)
                    {
                        if (this.IsTrueIdentifier())
                        {
                            var identifier = ParseIdentifierToken();
                            node = _syntaxFactory.DeclarationPattern(type, identifier);
                        }
                    }

                    if (node == null)
                    {
                        Debug.Assert(Precedence.Shift == Precedence.Relational + 1);
                        if ((IsExpectedBinaryOperator(tk) && GetPrecedence(SyntaxFacts.GetBinaryExpression(tk)) > Precedence.Relational) ||
                            tk == SyntaxKind.DotToken) // member selection is not formally a binary operator but has higher precedence than relational
                        {
                            this.Reset(ref resetPoint);
                            // We parse a shift-expression ONLY (nothing looser) - i.e. not a relational expression
                            // So x is y < z should be parsed as (x is y) < z
                            // But x is y << z should be parsed as x is (y << z)
                            node = _syntaxFactory.ConstantPattern(this.ParseSubExpression(Precedence.Shift));
                        }
                        // it is a typical "is Type" operator
                        else
                        {
                            // Note that we don't bother checking for primary expressions such as X[e], X(e), X++, and X--
                            // as those are never semantically valid constant expressions for a pattern
                            node = type;
                        }
                    }
                }
                finally
                {
                    this.Release(ref resetPoint);
                }
            }
            else
            {
                // In places where a pattern is supported, we do not support tuple types
                // due to both syntactic and semantic ambiguities between tuple types and positional patterns.

                // But it still might be a pattern such as (operand is 3) or (operand is nameof(x))
                node = _syntaxFactory.ConstantPattern(this.ParseExpressionCore());
            }
            return(node);
        }
        private ExpressionSyntax ParseSubExpression(uint precedence)
        {
            if (Current.Kind == SyntaxKind.CompileKeyword)
            {
                var compile            = Match(SyntaxKind.CompileKeyword);
                var shaderTarget       = Match(SyntaxKind.IdentifierToken);
                var shaderFunctionName = ParseIdentifier();
                var shaderFunction     = new FunctionInvocationExpressionSyntax(shaderFunctionName, ParseParenthesizedArgumentList(false));
                return(new CompileExpressionSyntax(compile, shaderTarget, shaderFunction));
            }

            ExpressionSyntax leftOperand;
            SyntaxKind       opKind;

            // No left operand, so we need to parse one -- possibly preceded by a
            // unary operator.
            var tk = Current.Kind;

            if (SyntaxFacts.IsPrefixUnaryExpression(tk))
            {
                opKind      = SyntaxFacts.GetPrefixUnaryExpression(tk);
                leftOperand = ParsePrefixUnaryExpression(opKind);
            }
            else
            {
                // Not a unary operator - get a primary expression.
                leftOperand = ParseTerm();
            }

            while (true)
            {
                // We either have a binary or assignment or compound operator here, or we're finished.
                tk = Current.Kind;

                ExpressionOperatorType operatorType;
                if (SyntaxFacts.IsBinaryExpression(tk) &&
                    (!_greaterThanTokenIsNotOperator || tk != SyntaxKind.GreaterThanToken) &&
                    (tk != SyntaxKind.GreaterThanToken || !_allowGreaterThanTokenAroundRhsExpression || Lookahead.Kind != SyntaxKind.SemiToken))
                {
                    operatorType = ExpressionOperatorType.BinaryExpression;
                    opKind       = SyntaxFacts.GetBinaryExpression(tk);
                }
                else if (SyntaxFacts.IsAssignmentExpression(tk))
                {
                    operatorType = ExpressionOperatorType.AssignmentExpression;
                    opKind       = SyntaxFacts.GetAssignmentExpression(tk);
                }
                else if (tk == SyntaxKind.CommaToken && CommaIsSeparatorStack.Peek() == false)
                {
                    operatorType = ExpressionOperatorType.CompoundExpression;
                    opKind       = SyntaxKind.CompoundExpression;
                }
                else
                {
                    break;
                }

                var newPrecedence = SyntaxFacts.GetOperatorPrecedence(opKind);

                Debug.Assert(newPrecedence > 0); // All binary operators must have precedence > 0!

                // Check the precedence to see if we should "take" this operator
                if (newPrecedence < precedence)
                {
                    break;
                }

                // Same precedence, but not right-associative -- deal with this "later"
                if (newPrecedence == precedence && !SyntaxFacts.IsRightAssociative(opKind))
                {
                    break;
                }

                // Precedence is okay, so we'll "take" this operator.
                var opToken = NextToken();

                SyntaxToken lessThanToken = null;
                if (operatorType == ExpressionOperatorType.AssignmentExpression && _allowGreaterThanTokenAroundRhsExpression)
                {
                    lessThanToken = NextTokenIf(SyntaxKind.LessThanToken);
                }

                var rightOperand = ParseSubExpression(newPrecedence);

                SyntaxToken greaterThanToken = null;
                if (lessThanToken != null)
                {
                    greaterThanToken = NextTokenIf(SyntaxKind.GreaterThanToken);
                }

                switch (operatorType)
                {
                case ExpressionOperatorType.BinaryExpression:
                    leftOperand = new BinaryExpressionSyntax(opKind, leftOperand, opToken, rightOperand);
                    break;

                case ExpressionOperatorType.AssignmentExpression:
                    leftOperand = new AssignmentExpressionSyntax(opKind, leftOperand, opToken, lessThanToken, rightOperand, greaterThanToken);
                    break;

                case ExpressionOperatorType.CompoundExpression:
                    leftOperand = new CompoundExpressionSyntax(opKind, leftOperand, opToken, rightOperand);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            var conditionalPrecedence = SyntaxFacts.GetOperatorPrecedence(SyntaxKind.ConditionalExpression);

            if (tk == SyntaxKind.QuestionToken && precedence <= conditionalPrecedence)
            {
                var questionToken = NextToken();

                var colonLeft = ParseSubExpression(conditionalPrecedence);
                var colon     = Match(SyntaxKind.ColonToken);

                var colonRight = ParseSubExpression(conditionalPrecedence);
                leftOperand = new ConditionalExpressionSyntax(leftOperand, questionToken, colonLeft, colon, colonRight);
            }

            return(leftOperand);
        }
Ejemplo n.º 8
0
        private CSharpSyntaxNode ParseTypeOrPatternForIsOperatorCore()
        {
            var        tk         = this.CurrentToken.Kind;
            Precedence precedence = GetPrecedence(SyntaxKind.IsPatternExpression);

            // We will parse a shift-expression ONLY (nothing looser) - i.e. not a relational expression
            // So x is y < z should be parsed as (x is y) < z
            // But x is y << z should be parsed as x is (y << z)
            Debug.Assert(Precedence.Shift == precedence + 1);

            // For totally broken syntax, parse a type for error recovery purposes
            switch (tk)
            {
            case SyntaxKind.IdentifierToken when this.CurrentToken.ContextualKind == SyntaxKind.UnderscoreToken:
            // We permit a type named `_` on the right-hand-side of an is operator, but not inside of a pattern.
            case SyntaxKind.CloseParenToken:
            case SyntaxKind.CloseBracketToken:
            case SyntaxKind.CloseBraceToken:
            case SyntaxKind.SemicolonToken:
            case SyntaxKind.CommaToken:
                // HACK: for error recovery, we prefer a (missing) type.
                return(this.ParseType(ParseTypeMode.AfterIs));

            default:
                // attempt to disambiguate.
                break;
            }

            // If it starts with 'nameof(', skip the 'if' and parse as a constant pattern.
            if (LooksLikeTypeOfPattern(tk))
            {
                var resetPoint = this.GetResetPoint();
                try
                {
                    TypeSyntax type = this.ParseType(ParseTypeMode.AfterIs);

                    if (!type.IsMissing)
                    {
                        PatternSyntax p = ParsePatternContinued(type, precedence, whenIsKeyword: false);
                        if (p != null)
                        {
                            return(p);
                        }
                    }

                    tk = this.CurrentToken.ContextualKind;
                    if ((!IsExpectedBinaryOperator(tk) || GetPrecedence(SyntaxFacts.GetBinaryExpression(tk)) <= precedence) &&
                        // member selection is not formally a binary operator but has higher precedence than relational
                        tk != SyntaxKind.DotToken)
                    {
                        // it is a typical "is Type" operator.
                        // Note that we don't bother checking for primary expressions such as X[e], X(e), X++, and X--
                        // as those are never semantically valid constant expressions for a pattern
                        return(type);
                    }

                    this.Reset(ref resetPoint);
                }
                finally
                {
                    this.Release(ref resetPoint);
                }
            }

            // check to see if it looks like a recursive pattern.
            if (tk == SyntaxKind.OpenParenToken || tk == SyntaxKind.OpenBraceToken)
            {
                var resetPoint = this.GetResetPoint();
                try
                {
                    PatternSyntax p = ParsePatternContinued(type: null, precedence, whenIsKeyword: false);
                    if (p != null)
                    {
                        return(p);
                    }

                    // this can occur when we encounter a misplaced lambda expression.
                    this.Reset(ref resetPoint);
                }
                finally
                {
                    this.Release(ref resetPoint);
                }
            }

            // In places where a pattern is supported, we do not support tuple types
            // due to both syntactic and semantic ambiguities between tuple types and positional patterns.
            // But it still might be a pattern such as (operand is 3) or (operand is nameof(x))
            return(_syntaxFactory.ConstantPattern(this.ParseSubExpressionCore(precedence)));
        }
Ejemplo n.º 9
0
        private ExpressionSyntax ParseDirectiveSubExpression(uint precedence)
        {
            ExpressionSyntax leftOperand;
            SyntaxKind       opKind;

            // No left operand, so we need to parse one -- possibly preceded by a
            // unary operator.
            var tk = Current.Kind;

            if (SyntaxFacts.IsPrefixUnaryExpression(tk, true))
            {
                opKind      = SyntaxFacts.GetPrefixUnaryExpression(tk);
                leftOperand = ParseDirectivePrefixUnaryExpression(opKind);
            }
            else
            {
                // Not a unary operator - get a primary expression.
                leftOperand = ParseDirectiveTerm();
            }

            while (true)
            {
                // We either have a binary operator here, or we're finished.
                tk = Current.Kind;

                if (SyntaxFacts.IsBinaryExpression(tk))
                {
                    opKind = SyntaxFacts.GetBinaryExpression(tk);
                }
                else
                {
                    break;
                }

                var newPrecedence = SyntaxFacts.GetOperatorPrecedence(opKind);

                Debug.Assert(newPrecedence > 0); // All binary operators must have precedence > 0!

                // Check the precedence to see if we should "take" this operator
                if (newPrecedence < precedence)
                {
                    break;
                }

                // Same precedence, but not right-associative -- deal with this "later"
                if (newPrecedence == precedence && !SyntaxFacts.IsRightAssociative(opKind))
                {
                    break;
                }

                // Precedence is okay, so we'll "take" this operator.
                var opToken = NextToken();

                var rightOperand = ParseDirectiveSubExpression(newPrecedence);
                leftOperand = new BinaryExpressionSyntax(opKind, leftOperand, opToken, rightOperand);
            }

            var conditionalPrecedence = SyntaxFacts.GetOperatorPrecedence(SyntaxKind.ConditionalExpression);

            if (tk == SyntaxKind.QuestionToken && precedence <= conditionalPrecedence)
            {
                var questionToken = NextToken();

                var colonLeft = ParseDirectiveSubExpression(conditionalPrecedence);
                var colon     = Match(SyntaxKind.ColonToken);

                var colonRight = ParseDirectiveSubExpression(conditionalPrecedence);
                leftOperand = new ConditionalExpressionSyntax(leftOperand, questionToken, colonLeft, colon, colonRight);
            }

            return(leftOperand);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Parses the type, or pattern, right-hand operand of an is expression.
        /// Priority is the TypeSyntax. It may return a TypeSyntax which turns out in binding to
        /// be a constant pattern such as enum 'Days.Sunday'. We handle such cases in the binder of the is operator.
        /// </summary>
        private CSharpSyntaxNode ParseTypeOrPatternForIsOperator()
        {
            var        tk         = this.CurrentToken.Kind;
            Precedence precedence = GetPrecedence(SyntaxKind.IsPatternExpression);

            switch (tk)
            {
            case SyntaxKind.CloseParenToken:
            case SyntaxKind.CloseBracketToken:
            case SyntaxKind.CloseBraceToken:
            case SyntaxKind.SemicolonToken:
            case SyntaxKind.CommaToken:
                // HACK: for error recovery, we prefer a (missing) type.
                return(this.ParseType(ParseTypeMode.AfterIs));

            default:
                // attempt to disambiguate.
                break;
            }

            // If it starts with 'nameof(', skip the 'if' and parse as a constant pattern.
            if (SyntaxFacts.IsPredefinedType(tk) ||
                (tk == SyntaxKind.IdentifierToken &&
                 (this.CurrentToken.ContextualKind != SyntaxKind.NameOfKeyword || this.PeekToken(1).Kind != SyntaxKind.OpenParenToken)))
            {
                var resetPoint = this.GetResetPoint();
                try
                {
                    TypeSyntax type = this.ParseType(ParseTypeMode.AfterIs);

                    if (!type.IsMissing && this.IsTrueIdentifier())
                    {
                        var designation = ParseSimpleDesignation();
                        return(_syntaxFactory.DeclarationPattern(type, designation));
                    }

                    tk = this.CurrentToken.ContextualKind;
                    if ((!IsExpectedBinaryOperator(tk) || GetPrecedence(SyntaxFacts.GetBinaryExpression(tk)) <= precedence) &&
                        // member selection is not formally a binary operator but has higher precedence than relational
                        tk != SyntaxKind.DotToken)
                    {
                        // it is a typical "is Type" operator.
                        // Note that we don't bother checking for primary expressions such as X[e], X(e), X++, and X--
                        // as those are never semantically valid constant expressions for a pattern
                        return(type);
                    }

                    this.Reset(ref resetPoint);
                }
                finally
                {
                    this.Release(ref resetPoint);
                }
            }

            // We parse a shift-expression ONLY (nothing looser) - i.e. not a relational expression
            // So x is y < z should be parsed as (x is y) < z
            // But x is y << z should be parsed as x is (y << z)
            Debug.Assert(Precedence.Shift == precedence + 1);

            // In places where a pattern is supported, we do not support tuple types
            // due to both syntactic and semantic ambiguities between tuple types and positional patterns.
            // But it still might be a pattern such as (operand is 3) or (operand is nameof(x))
            return(_syntaxFactory.ConstantPattern(this.ParseSubExpressionCore(precedence)));
        }