private IEnumerable<IFormulaToken> InterpretOperators(IEnumerable<IFormulaToken> tokens, IEnumerable<IFormulaToken> lookAhead)
{
var pending = new Stack<FormulaTree>();
lookAhead = InterpretMinusTokenForward(lookAhead);
var lookAhead2 = lookAhead.GetEnumerator();
foreach (var context in tokens.WithContext())
{
if (IsCancellationRequested) yield break;
var previousToken = context[0];
var token = context[1];
if (token == null) yield break;
// yield parameter separators
if (token is FormulaTokenParameterSeparator)
{
yield return token;
continue;
}
var token2 = (FormulaTree) token;
var operatorToken = token2 as IFormulaOperator;
// advance lookAhead parallel to tokens
var nextIndex = GetOrigin(token).End;
var nextToken = lookAhead2.FirstOrDefault(token3 => GetOrigin(token3).Start == nextIndex);
// stash operators
if (operatorToken != null)
{
if ((previousToken == null || previousToken is FormulaTokenParameterSeparator) && operatorToken is FormulaNodeInfixOperator)
{
SetParsingError(
source: Range.Empty(GetOrigin(token2).Start),
message: AppResourcesHelper.Get("FormulaInterpreter_Operator_LeftEmptyInfixOperator"));
yield break;
}
if (nextToken == null || nextToken is FormulaTokenParameterSeparator || nextToken is FormulaNodeInfixOperator)
{
SetParsingError(
source: Range.Empty(GetOrigin(token2).End),
message: operatorToken is FormulaNodePrefixOperator
? AppResourcesHelper.Get("FormulaInterpreter_Operator_EmptyPrefixOperator")
: AppResourcesHelper.Get("FormulaInterpreter_Operator_RightEmptyInfixOperator"));
yield break;
}
pending.Push(token2);
continue;
}
// merge with pending tokens (regarding operator order)
var nextInfixOperatorToken = nextToken as FormulaNodeInfixOperator;
if (nextInfixOperatorToken == null || (pending.Count != 0 && ((IFormulaOperator) pending.Peek()).Order >= nextInfixOperatorToken.Order))
{
while (pending.Count != 0)
{
var pendingOperator = pending.Pop();
// attach token to prefix operator
var pendingPrefixOperator = pendingOperator as FormulaNodePrefixOperator;
if (pendingPrefixOperator != null)
{
var numberToken = token2 as FormulaNodeNumber;
// merge negative sign and number
if (numberToken != null && pendingPrefixOperator is FormulaNodeNegativeSign)
{
numberToken.Value *= -1;
SetOrigin(token2, new[] {pendingOperator, token2});
}
else
{
pendingPrefixOperator.Child = token2;
SetOrigin(pendingPrefixOperator, new[] {pendingOperator, token2});
token2 = pendingOperator;
}
}
// attach token to infix operator
var pendingInfixOperator = pendingOperator as FormulaNodeInfixOperator;
if (pendingInfixOperator != null)
{
pendingInfixOperator.LeftChild = pending.Pop();
pendingInfixOperator.RightChild = token2;
SetOrigin(pendingInfixOperator,
new[] {pendingInfixOperator.LeftChild, pendingOperator, token2});
token2 = pendingOperator;
}
}
}
// stash to infix operator attached tokens
if (nextInfixOperatorToken != null)
{
pending.Push(token2);
continue;
}
// yield finished or unattached tokens
yield return token2;
}
}