private ExpressionSyntax ParseSubExpression(uint precedence, bool allowDeclarationExpressionAtTheBeginning = true, bool contextRequiresVariable = false)
        {
            ExpressionSyntax leftOperand   = null;
            uint             newPrecedence = 0;
            SyntaxKind       opKind        = SyntaxKind.None;

            // all of these are tokens that start statements and are invalid
            // to start a expression with. if we see one, then we must have
            // something like:
            //
            // return
            // if (...
            // parse out a missing name node for the expression, and keep on going
            var tk = this.CurrentToken.Kind;

            if (IsInvalidSubExpression(tk))
            {
                return(this.AddError(this.CreateMissingIdentifierName(), ErrorCode.ERR_InvalidExprTerm, SyntaxKindFacts.GetText(tk)));
            }

            // No left operand, so we need to parse one -- possibly preceded by a
            // unary operator.
            if (IsExpectedPrefixUnaryOperator(tk))
            {
                opKind        = SyntaxKindFacts.GetPrefixUnaryExpression(tk);
                newPrecedence = GetPrecedence(opKind);
                var opToken = this.EatToken();
                var operand = this.ParseSubExpression(newPrecedence);
                leftOperand = _syntaxFactory.PrefixUnaryExpression(opKind, opToken, operand);
            }
            else
            {
                // Not a unary operator - get a primary expression.
                leftOperand = this.ParseTerm(precedence, allowDeclarationExpressionAtTheBeginning, contextRequiresVariable);
            }

            while (true)
            {
                // We either have a binary operator here, or we're finished.
                tk = this.CurrentToken.Kind;
                if (!IsExpectedBinaryOperator(tk))
                {
                    break;
                }

                opKind        = SyntaxKindFacts.GetBinaryExpression(tk);
                newPrecedence = GetPrecedence(opKind);

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

                // check for >> or >>= or >>> or >>>=
                bool doubleOp        = false;
                bool doubleOpPlusOne = false;
                if (tk == SyntaxKind.GreaterThanToken &&
                    (this.PeekToken(1).Kind == SyntaxKind.GreaterThanToken) &&
                    (this.PeekToken(2).Kind == SyntaxKind.GreaterThanToken ||
                     this.PeekToken(2).Kind == SyntaxKind.GreaterThanEqualsToken))
                {
                    // check to see if they really are adjacent
                    if (this.CurrentToken.GetTrailingTriviaWidth() == 0 &&
                        this.PeekToken(1).GetLeadingTriviaWidth() == 0 &&
                        this.PeekToken(1).GetTrailingTriviaWidth() == 0 &&
                        this.PeekToken(2).GetLeadingTriviaWidth() == 0
                        )
                    {
                        opKind = SyntaxKindFacts.GetBinaryExpression(this.PeekToken(2).Kind == SyntaxKind.GreaterThanToken ?
                                                                     SyntaxKind.GreaterThanGreaterThanGreaterThanToken :
                                                                     SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken);


                        newPrecedence   = GetPrecedence(opKind);
                        doubleOp        = true;
                        doubleOpPlusOne = true;
                    }
                }
                else if (tk == SyntaxKind.GreaterThanToken &&
                         (this.PeekToken(1).Kind == SyntaxKind.GreaterThanToken ||
                          this.PeekToken(1).Kind == SyntaxKind.GreaterThanEqualsToken))
                {
                    // check to see if they really are adjacent
                    if (this.CurrentToken.GetTrailingTriviaWidth() == 0 && this.PeekToken(1).GetLeadingTriviaWidth() == 0)
                    {
                        opKind = SyntaxKindFacts.GetBinaryExpression(this.PeekToken(1).Kind == SyntaxKind.GreaterThanToken ?
                                                                     SyntaxKind.GreaterThanGreaterThanToken :
                                                                     SyntaxKind.GreaterThanGreaterThanEqualsToken);
                        newPrecedence = GetPrecedence(opKind);
                        doubleOp      = true;
                    }
                }

                // 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) && !IsRightAssociative(opKind))
                {
                    break;
                }

                // Precedence is okay, so we'll "take" this operator.
                var opToken = this.EatToken();
                if (doubleOp)
                {
                    // combine tokens into a single token
                    var opToken2 = this.EatToken();
                    if (doubleOpPlusOne)
                    {
                        var opToken3 = this.EatToken();
                        var kind     = opToken3.Kind == SyntaxKind.GreaterThanToken ?
                                       SyntaxKind.GreaterThanGreaterThanGreaterThanToken :
                                       SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken;

                        opToken = SyntaxFactory.Token(opToken.GetLeadingTrivia(), kind, opToken3.GetTrailingTrivia());
                    }
                    else
                    {
                        var kind = opToken2.Kind == SyntaxKind.GreaterThanToken ?
                                   SyntaxKind.GreaterThanGreaterThanToken :
                                   SyntaxKind.GreaterThanGreaterThanEqualsToken;
                        opToken = SyntaxFactory.Token(opToken.GetLeadingTrivia(), kind, opToken2.GetTrailingTrivia());
                    }
                }

                if (opKind == SyntaxKind.InstanceOfExpression)
                {
                    leftOperand = _syntaxFactory.BinaryExpression(opKind, leftOperand, opToken,
                                                                  this.ParseTypeCore(parentIsParameter: false, isInstanceOfOrAs: true, expectSizes: false, isArrayCreation: false));
                }
                else
                {
                    leftOperand = _syntaxFactory.BinaryExpression(opKind, leftOperand, opToken, this.ParseSubExpression(newPrecedence));
                }
            }

            // From the language spec:
            //
            // conditional-expression:
            //  null-coalescing-expression
            //  null-coalescing-expression   ?   expression   :   expression
            //
            // Only take the ternary if we're at a precedence less than the null coelescing
            // expression.

            var nullCoalescingPrecedence = 2U;            //GetPrecedence(SyntaxKind.CoalesceExpression);

            if (tk == SyntaxKind.QuestionToken && precedence < 2)
            {
                var questionToken = this.EatToken();

                var colonLeft = this.ParseSubExpression(nullCoalescingPrecedence - 1);
                var colon     = this.EatToken(SyntaxKind.ColonToken);

                var colonRight = this.ParseSubExpression(nullCoalescingPrecedence - 1);
                leftOperand = _syntaxFactory.ConditionalExpression(leftOperand, questionToken, colonLeft, colon, colonRight);
            }

            return(leftOperand);
        }