Esempio n. 1
0
        /// <summary>
        /// Возможно ли расчитать числовое значение данного токена. Если да, то <see cref="Calculate"/> вернет данное значение
        /// </summary>
        public bool CanBeCalculated(RuntimeDataPackage package = null)
        {
            //Можно посчиатать если:
            //  1. Значение уже подсчитано
            // или
            //  2. Нету дочерных токенов
            //  Если дочерные токены есть, то можно если:
            //  3. Все значениея дочерных уже подсчиатыны
            // или
            //  4. Если ссылки на дочерные установлены
            //      4.1. И если ссылки - переменные, то если все переменные есть в mz
            // или
            //  5. Все дочерные значения примитивные, и их можно подсчитать
            //
            // Но подсчитать нельзя если:
            //   Некоторые дочерние токены имеют унарные функции или операторы

            if (_valueSet)
            {
                return(true);
            }

            if (Subtokens != null)
            {
                bool referenceConditional = true;
                bool hasRefsToVar         = Subtokens.Exists(p => p.Reference != null && p.Reference.Type == ReferenceType.Variable);
                if (hasRefsToVar)
                {
                    referenceConditional = package != null &&
                                           Subtokens
                                           .FindAll(p => p.Reference != null && p.Reference.Type == ReferenceType.Variable)
                                           .All(p => package.ContainsVarialbe(p.Reference.Index));
                }

                if (!referenceConditional)
                {
                    return(false);
                }

                return((Subtokens.All(p => p._valueSet) || Subtokens.All(p => p.IsSimple)) &&
                       (Subtokens.Exists(p => p.UnaryFunction == null) && Subtokens.Exists(p => p.UnaryOperator == null)));
            }
            else if (_referenceSet && Reference.Type == ReferenceType.Variable)
            {
                return(package != null && package.ContainsVarialbe(Reference.Index));
            }
            else
            {
                return(true);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Расчитывает числовое значение данного токена. Возможно только в случае если <see cref="CanBeCalculated"/> <see cref="true"/>
        /// </summary>
        /// <returns></returns>
        public Constant Calculate(RuntimeDataPackage package)
        {
            Steps = 0;

            if (_valueSet)
            {
                return(Value);
            }

            if (IsSimple)
            {
                CalculateValue(Parse(package), this);
                _valueSet = true;
                return(Value);
            }

            //1. Найти пару с найбольшим приоритетом
            //2. Удалить ее, заменив ее решением
            //Посторять 1-2 пункты пока не останится последний токен
            //3. Применить унарный оператор

            //Создаем копию саб токенов. Нам не нужно портить изначальный массив.
            var subTokens = Subtokens.Select(p => (Token)p.Clone()).ToList();

            while (subTokens.Count != 1)
            {
                //Индексы в массиве операнов при самом приоритетном операторе
                int maxLeftIndex  = -1;
                int maxRightIndex = -1;
                //Приоритет самого приоритетного оператора
                int maxPriority = 0;
                //Самый приоритетный оператор
                Operator op = null;

                //Ищем оператор
                for (int i = 0; i < subTokens.Count; i++)
                {
                    //Ищем по левому, бикоз вай нот
                    if (subTokens[i].LeftSideOperator != null)
                    {
                        if (subTokens[i].LeftSideOperator.Priority > maxPriority)
                        {
                            //Запоминаем наши индексы и прочее
                            maxLeftIndex  = i - 1;
                            maxRightIndex = i;
                            maxPriority   = subTokens[i].LeftSideOperator.Priority;
                            op            = subTokens[i].LeftSideOperator;
                        }
                    }
                }

                //Хз, можно убрать наверное

                /*if (!subTokens[maxLeftIndex].IsPrimitive)
                 *  throw new Exception("Token must be primitive");
                 *
                 * if (!subTokens[maxRightIndex].IsPrimitive)
                 *  throw new Exception("Token must be primitive");*/

                //Получаем числовые значение
                //Учитываем, что операнды могут иметь свои унарные операции и функции.
                //Их приоритет всегда выше бинарных, потому сразу выполняем их
                CalculateValue(subTokens[maxLeftIndex].Parse(package), subTokens[maxLeftIndex]);
                CalculateValue(subTokens[maxRightIndex].Parse(package), subTokens[maxRightIndex]);

                var value = op.BinaryFunc(subTokens[maxLeftIndex].Value, subTokens[maxRightIndex].Value);
                Steps += op.OperatorSteps;

                //Дебага ради создаем новое строковое значение
                var newRawValue = value.ToString();

                //Важно грамотно сохранить левые и правые токены
                var newToken = new Token(newRawValue)
                {
                    LeftSideOperator = subTokens[maxLeftIndex].LeftSideOperator,
                    LeftSideToken    = subTokens[maxLeftIndex].LeftSideToken,

                    RightSideOperator = subTokens[maxRightIndex].RightSideOperator,
                    RightSideToken    = subTokens[maxRightIndex].RightSideToken,

                    Value     = value,
                    _valueSet = true
                };

                //Подставляем в существующие токены наш новы
                if (maxLeftIndex - 1 >= 0)
                {
                    subTokens[maxLeftIndex - 1].RightSideToken = newToken;
                }

                if (maxRightIndex + 1 < subTokens.Count)
                {
                    subTokens[maxRightIndex + 1].LeftSideToken = newToken;
                }


                //Удаляем 2 старых
                subTokens.RemoveAt(maxRightIndex);
                subTokens.RemoveAt(maxLeftIndex);
                //Заменяя его на новый
                subTokens.Insert(maxLeftIndex, newToken);
            }

            CalculateValue(subTokens[0].Value, this);
            return(Value);
        }