private static ResultCode MakeImplicitMultiplications(
            ExpressionOptions options, List <Token> tokens)
        {
            for (int i = 0; i < tokens.Count; i++)
            {
                var token = tokens[i];
                if (token is CollectionToken collectionToken)
                {
                    var code = MakeImplicitMultiplications(options, collectionToken.Children);
                    if (code != ResultCode.Ok)
                    {
                        return(code);
                    }
                }
                else if (token.Type != TokenType.Name)
                {
                    // Skip as this type is not allowed to have an implicit factor prefix.
                    continue;
                }

                if (i - 1 < 0)
                {
                    continue; // We are at the list's beginning.
                }
                var leftToken = tokens[i - 1];
                if (leftToken.Type == TokenType.Operator ||
                    leftToken.Type == TokenType.Name ||
                    leftToken.Type == TokenType.ListSeparator)
                {
                    continue;
                }

                if (leftToken.Type != TokenType.DecimalDigit &&
                    leftToken.Type != TokenType.DecimalNumber &&
                    leftToken.Type != TokenType.List)
                {
                    return(ResultCode.InvalidTokenBeforeList);
                }

                var multiplyOpDef = options.GetOperatorDefinition(OperatorType.Multiply);
                if (multiplyOpDef == null)
                {
                    return(ResultCode.MissingMultiplicationDefinition);
                }

                var opToken = new ValueToken(TokenType.Operator, multiplyOpDef.Names[0]);
                tokens.Insert(i, opToken);
            }
            return(ResultCode.Ok);
        }
Пример #2
0
        public static EError?ValidateOperatorTokens(
            ExpressionOptions options, ValueToken op, Token?left, Token?right)
        {
            var opDef = options.GetOperatorDefinition(op.Value);

            if (opDef != null)
            {
                if (left == null && (
                        opDef.Associativity == OperatorSidedness.Both ||
                        opDef.Associativity.HasFlag(OperatorSidedness.Left)))
                {
                    return(EErrorCode.OperatorMissingLeftValue);
                }

                if (right == null && (
                        opDef.Associativity == OperatorSidedness.Both ||
                        opDef.Associativity.HasFlag(OperatorSidedness.Right)))
                {
                    return(EErrorCode.OperatorMissingRightValue);
                }
            }
            return(null);
        }
        private static ResultCode MakeOperatorGroups(ExpressionOptions options, List <Token> tokens)
        {
            var listStack = new Stack <List <Token> >();

            listStack.Push(tokens);

            var opIndices = new List <(int index, ValueToken token, OperatorDefinition definition)>();
            var opShifts  = new List <(int index, int shift)>();

            while (listStack.Count > 0)
            {
                var currentTokens = listStack.Pop();
                for (int j = 0; j < currentTokens.Count; j++)
                {
                    var token = currentTokens[j];
                    if (token is CollectionToken collectionToken)
                    {
                        listStack.Push(collectionToken.Children);
                    }
                }

                // Gather operators so we can sort them by priority rules.
                opIndices.Clear();
                for (int j = 0; j < currentTokens.Count; j++)
                {
                    var token = currentTokens[j];
                    if (token.Type != TokenType.Operator)
                    {
                        continue;
                    }

                    var opToken = (ValueToken)token;
                    var opDef   = options.GetOperatorDefinition(opToken.Value);
                    if (opDef == null)
                    {
                        return(ResultCode.UnknownSymbol);
                    }

                    opIndices.Add((index: j, opToken, opDef));
                }

                opIndices.Sort((x, y) =>
                {
                    int xPriority = x.definition?.Precedence ?? 0;
                    int yPriority = y.definition?.Precedence ?? 0;

                    // Sort types in descending order.
                    int priorityCompare = yPriority.CompareTo(xPriority);
                    if (priorityCompare != 0)
                    {
                        return(priorityCompare);
                    }

                    // Sort indices of same type in ascending order.
                    return(x.index.CompareTo(y.index));
                });

                // Merge token triplets with a center operator or
                // pairs with a leading operator.
                opShifts.Clear();
                for (int i = 0; i < opIndices.Count; i++)
                {
                    var(opIndex, opToken, opDef) = opIndices[i];

                    // Offset "opIndex" by shifts caused by previous operator merges.
                    for (int j = 0; j < opShifts.Count; j++)
                    {
                        var(shiftIndex, shift) = opShifts[j];
                        if (shiftIndex < opIndex)
                        {
                            opIndex += shift;
                        }
                    }

                    Token?leftToken  = null;
                    Token?rightToken = null;

                    int left = opIndex - 1;
                    if (opDef?.Associativity != OperatorSidedness.Right)
                    {
                        if (left < 0)
                        {
                            if (opDef != null && opDef.Associativity.HasFlag(OperatorSidedness.Left))
                            {
                                return(ResultCode.OperatorMissingLeftValue);
                            }
                        }
                        else
                        {
                            leftToken = currentTokens[left];
                        }
                    }
                    if (leftToken?.Type == TokenType.Operator)
                    {
                        continue;
                    }

                    int right = opIndex + 1;
                    if (opDef != null && opDef.Associativity != OperatorSidedness.Left)
                    {
                        if (right >= currentTokens.Count)
                        {
                            if (opDef.Associativity.HasFlag(OperatorSidedness.Right))
                            {
                                return(ResultCode.OperatorMissingRightValue);
                            }
                        }
                        else
                        {
                            rightToken = currentTokens[right];
                            if (rightToken.Type == TokenType.Operator)
                            {
                                continue;
                            }

                            // Mitigates operators with following operators.
                            if (rightToken.Type == TokenType.Operator)
                            {
                                int secondRight = opIndex + 2;
                                if (secondRight < currentTokens.Count)
                                {
                                    var subToken = new ListToken(new List <Token>(2)
                                    {
                                        rightToken,
                                        currentTokens[secondRight]
                                    });

                                    rightToken           = subToken;
                                    currentTokens[right] = rightToken;
                                    currentTokens.RemoveAt(secondRight);

                                    opShifts.Add((right, -1));
                                    opIndices.RemoveAll(x => x.index == right);
                                }
                                else
                                {
                                    return(ResultCode.OperatorMissingRightValue);
                                }
                            }
                        }
                    }

                    int sideTokenCount = 0;
                    if (leftToken != null)
                    {
                        sideTokenCount++;
                    }
                    if (rightToken != null)
                    {
                        sideTokenCount++;
                    }

                    // Try to skip making a 1-item list.
                    int resultCount = 1 + sideTokenCount;
                    if (resultCount == currentTokens.Count)
                    {
                        continue;
                    }

                    var resultList = new List <Token>(resultCount);
                    if (leftToken != null)
                    {
                        resultList.Add(leftToken);
                    }
                    resultList.Add(opToken);
                    if (rightToken != null)
                    {
                        resultList.Add(rightToken);
                    }

                    int firstIndex  = opIndex - (leftToken != null ? 1 : 0);
                    var resultToken = new ListToken(resultList);
                    currentTokens[firstIndex] = resultToken;
                    currentTokens.RemoveRange(firstIndex + 1, resultList.Count - 1);

                    int nextShift = 1 - resultList.Count;
                    opShifts.Add((opIndex, nextShift));
                }
            }
            return(ResultCode.Ok);
        }