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); }