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