From 2042fa2012c0f4e948f56bc635fd3350156c57d6 Mon Sep 17 00:00:00 2001 From: fintarin Date: Sat, 17 Feb 2024 16:35:59 +0300 Subject: [PATCH] Remove unused values of IOperator::Priority. Refactor Expression --- include/fintamath/expressions/Expression.hpp | 27 ++- include/fintamath/functions/IOperator.hpp | 10 +- src/fintamath/expressions/Expression.cpp | 183 +++++++++---------- 3 files changed, 114 insertions(+), 106 deletions(-) diff --git a/include/fintamath/expressions/Expression.hpp b/include/fintamath/expressions/Expression.hpp index 5d5dbda12..fe1935c90 100644 --- a/include/fintamath/expressions/Expression.hpp +++ b/include/fintamath/expressions/Expression.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include "fintamath/expressions/IExpression.hpp" #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/IFunction.hpp" +#include "fintamath/functions/IOperator.hpp" #include "fintamath/literals/Variable.hpp" namespace fintamath { @@ -36,7 +38,24 @@ struct Term final { } }; -using TermVector = std::vector>; +struct FunctionTerm final { + Term term; + + std::optional priority; + +public: + FunctionTerm() = default; + + FunctionTerm(Term inTerm, const std::optional inPriority) + : term(std::move(inTerm)), + priority(inPriority) { + } +}; + +using TermVector = std::vector; + +using FunctionTermStack = std::stack; + using OperandStack = std::stack>; } @@ -104,11 +123,11 @@ class Expression final : public IExpressionCRTP { static std::unique_ptr operandsToObject(detail::OperandStack &operands); - static ArgumentPtrVector unwrapComma(const ArgumentPtr &child); + static void moveFunctionsToOperands(detail::OperandStack &operands, detail::FunctionTermStack &functions, const IOperator *nextOper); static void insertMultiplications(detail::TermVector &terms); - static void fixOperatorTypes(const detail::TermVector &terms); + static void fixOperatorTypes(detail::TermVector &terms); static void collapseFactorials(detail::TermVector &terms); @@ -128,6 +147,8 @@ class Expression final : public IExpressionCRTP { static bool doesArgMatch(const MathObjectType &expectedType, const ArgumentPtr &arg); + static ArgumentPtrVector unwrapComma(const ArgumentPtr &child); + static ArgumentPtr compress(const ArgumentPtr &child); friend std::unique_ptr detail::makeExpr(const IFunction &func, ArgumentPtrVector args); diff --git a/include/fintamath/functions/IOperator.hpp b/include/fintamath/functions/IOperator.hpp index 93b99a253..b1e9f50af 100644 --- a/include/fintamath/functions/IOperator.hpp +++ b/include/fintamath/functions/IOperator.hpp @@ -17,7 +17,6 @@ class IOperator : public IFunction { public: enum class Priority : uint8_t { - Highest, Exponentiation, // e.g. a ^ b PostfixUnary, // e.g. a! PrefixUnary, // e.g. -a @@ -30,7 +29,6 @@ class IOperator : public IFunction { Implication, // e.g. a -> b Equivalence, // e.g. a <-> b Comma, // e.g. a , b - Lowest, }; public: @@ -45,9 +43,13 @@ class IOperator : public IFunction { return getParser().parse(validator, parsedStr); } - static std::unique_ptr parse(const std::string &parsedStr, Priority priority = Priority::Lowest) { + static std::unique_ptr parse(const std::string &parsedStr) { + return getParser().parse(parsedStr); + } + + static std::unique_ptr parse(const std::string &parsedStr, Priority priority) { const auto validator = [priority](const std::unique_ptr &oper) { - return priority == Priority::Lowest || oper->getPriority() == priority; + return oper->getPriority() == priority; }; return getParser().parse(validator, parsedStr); } diff --git a/src/fintamath/expressions/Expression.cpp b/src/fintamath/expressions/Expression.cpp index e2af018ea..ecaec1943 100644 --- a/src/fintamath/expressions/Expression.cpp +++ b/src/fintamath/expressions/Expression.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -40,20 +41,6 @@ namespace fintamath { using namespace detail; -struct TermWithPriority final { - std::unique_ptr term; - - IOperator::Priority priority = IOperator::Priority::Lowest; - -public: - TermWithPriority() = default; - - TermWithPriority(std::unique_ptr inTerm, const IOperator::Priority inPriority) - : term(std::move(inTerm)), - priority(inPriority) { - } -}; - Expression::Expression() : child(Integer(0).clone()) { } @@ -196,10 +183,10 @@ TermVector Expression::tokensToTerms(const TokenVector &tokens) { for (const auto i : stdv::iota(0U, terms.size())) { if (auto term = getTermParser().parse(tokens[i])) { - terms[i] = std::move(term); + terms[i] = std::move(*term); } else { - terms[i] = std::make_unique(tokens[i], std::unique_ptr{}); + terms[i] = Term(tokens[i], std::unique_ptr{}); } } @@ -213,66 +200,49 @@ TermVector Expression::tokensToTerms(const TokenVector &tokens) { // Use the shunting yard algorithm // https://en.m.wikipedia.org/wiki/Shunting_yard_algorithm OperandStack Expression::termsToOperands(TermVector &terms) { - OperandStack outStack; - std::stack operStack; + OperandStack operands; + FunctionTermStack functions; for (auto &term : terms) { - if (!term->value) { - if (term->name == "(") { - operStack.emplace(std::move(term), IOperator::Priority::Lowest); + if (!term.value) { + if (term.name == "(") { + functions.emplace(std::move(term), std::optional{}); } - else if (term->name == ")") { - while (!operStack.empty() && - operStack.top().term->name != "(") { - - outStack.emplace(std::move(operStack.top().term->value)); - operStack.pop(); - } + else if (term.name == ")") { + moveFunctionsToOperands(operands, functions, {}); - if (operStack.empty()) { + if (functions.empty()) { throw InvalidInputException(""); } - operStack.pop(); + functions.pop(); } else { throw InvalidInputException(""); } } - else { - if (is(term->value)) { - if (const auto *oper = cast(term->value.get())) { - while (!operStack.empty() && - operStack.top().term->name != "(" && - operStack.top().priority <= oper->getPriority() && - !isPrefixOperator(oper)) { - - outStack.emplace(std::move(operStack.top().term->value)); - operStack.pop(); - } - - operStack.emplace(std::move(term), oper->getPriority()); - } - else { - operStack.emplace(std::move(term), IOperator::Priority::Highest); - } - } - else { - outStack.emplace(std::move(term->value)); + else if (is(term.value)) { + std::optional priority; + + if (const auto *oper = cast(term.value.get())) { + moveFunctionsToOperands(operands, functions, oper); + priority = oper->getPriority(); } + + functions.emplace(std::move(term), priority); + } + else { + operands.emplace(std::move(term.value)); } } - while (!operStack.empty()) { - if (operStack.top().term->name == "(") { - throw InvalidInputException(""); - } + moveFunctionsToOperands(operands, functions, {}); - outStack.emplace(std::move(operStack.top().term->value)); - operStack.pop(); + if (!functions.empty()) { + throw InvalidInputException(""); } - return outStack; + return operands; } std::unique_ptr Expression::operandsToObject(OperandStack &operands) { @@ -308,53 +278,53 @@ std::unique_ptr Expression::operandsToObject(OperandStack &operands return arg; } -ArgumentPtrVector Expression::unwrapComma(const ArgumentPtr &child) { - if (const auto childExpr = cast(child); - childExpr && - is(childExpr->getFunction())) { +void Expression::moveFunctionsToOperands(OperandStack &operands, std::stack &functions, const IOperator *nextOper) { + if (isPrefixOperator(nextOper)) { + return; + } - const ArgumentPtr &lhs = childExpr->getChildren().front(); - const ArgumentPtr &rhs = childExpr->getChildren().back(); + while (!functions.empty() && + functions.top().term.name != "(" && + (!nextOper || + !functions.top().priority || + *functions.top().priority <= nextOper->getPriority())) { - ArgumentPtrVector children = unwrapComma(lhs); - children.push_back(rhs); - return children; + operands.emplace(std::move(functions.top().term.value)); + functions.pop(); } - - return {child}; } void Expression::insertMultiplications(TermVector &terms) { static const ArgumentPtr mul = Mul{}.clone(); for (size_t i = 1; i < terms.size(); i++) { - if (canNextTermBeBinaryOperator(*terms[i - 1]) && - canPrevTermBeBinaryOperator(*terms[i])) { + if (canNextTermBeBinaryOperator(terms[i - 1]) && + canPrevTermBeBinaryOperator(terms[i])) { - auto term = std::make_unique(mul->toString(), mul->clone()); + Term term(mul->toString(), mul->clone()); terms.insert(terms.begin() + static_cast(i), std::move(term)); i++; } } } -void Expression::fixOperatorTypes(const TermVector &terms) { +void Expression::fixOperatorTypes(TermVector &terms) { bool isFixed = true; - if (const auto &term = terms.front(); - is(term->value) && - !isPrefixOperator(term->value.get())) { + if (auto &term = terms.front(); + is(term.value) && + !isPrefixOperator(term.value.get())) { - term->value = IOperator::parse(term->name, IOperator::Priority::PrefixUnary); - isFixed = static_cast(term->value); + term.value = IOperator::parse(term.name, IOperator::Priority::PrefixUnary); + isFixed = static_cast(term.value); } - if (const auto &term = terms.back(); - is(term->value) && - !isPostfixOperator(term->value.get())) { + if (auto &term = terms.back(); + is(term.value) && + !isPostfixOperator(term.value.get())) { - term->value = IOperator::parse(term->name, IOperator::Priority::PostfixUnary); - isFixed = isFixed && static_cast(term->value); + term.value = IOperator::parse(term.name, IOperator::Priority::PostfixUnary); + isFixed = isFixed && static_cast(term.value); } if (!isFixed) { @@ -366,28 +336,28 @@ void Expression::fixOperatorTypes(const TermVector &terms) { } for (const auto i : stdv::iota(1U, terms.size() - 1)) { - const auto &term = terms[i]; + auto &term = terms[i]; const auto &termPrev = terms[i - 1]; - if (is(term->value) && - !isPrefixOperator(term->value.get()) && - !canNextTermBeBinaryOperator(*termPrev)) { + if (is(term.value) && + !isPrefixOperator(term.value.get()) && + !canNextTermBeBinaryOperator(termPrev)) { - term->value = IOperator::parse(term->name, IOperator::Priority::PrefixUnary); - isFixed = isFixed && term->value; + term.value = IOperator::parse(term.name, IOperator::Priority::PrefixUnary); + isFixed = isFixed && term.value; } } for (const auto i : stdv::iota(1U, terms.size() - 1) | stdv::reverse) { - const auto &term = terms[i]; + auto &term = terms[i]; const auto &termNext = terms[i + 1]; - if (is(term->value) && - !isPostfixOperator(term->value.get()) && - !canPrevTermBeBinaryOperator(*termNext)) { + if (is(term.value) && + !isPostfixOperator(term.value.get()) && + !canPrevTermBeBinaryOperator(termNext)) { - term->value = IOperator::parse(term->name, IOperator::Priority::PostfixUnary); - isFixed = isFixed && term->value; + term.value = IOperator::parse(term.name, IOperator::Priority::PostfixUnary); + isFixed = isFixed && term.value; } } @@ -398,12 +368,12 @@ void Expression::fixOperatorTypes(const TermVector &terms) { void Expression::collapseFactorials(TermVector &terms) { for (size_t i = 1; i + 1 < terms.size(); i++) { - const auto &term = terms[i]; + auto &term = terms[i]; const auto &termNext = terms[i + 1]; - if (is(term->value) && is(termNext->value)) { - const auto &oldFactorial = cast(*term->value); - term->value = Factorial(oldFactorial.getOrder() + 1).clone(); + if (is(term.value) && is(termNext.value)) { + const auto &oldFactorial = cast(*term.value); + term.value = Factorial(oldFactorial.getOrder() + 1).clone(); terms.erase(terms.begin() + static_cast(i) + 1); i--; @@ -445,6 +415,22 @@ bool Expression::isNonOperatorFunction(const IMathObject *val) { return is(val) && !is(val); } +ArgumentPtrVector Expression::unwrapComma(const ArgumentPtr &child) { + if (const auto childExpr = cast(child); + childExpr && + is(childExpr->getFunction())) { + + const ArgumentPtr &lhs = childExpr->getChildren().front(); + const ArgumentPtr &rhs = childExpr->getChildren().back(); + + ArgumentPtrVector children = unwrapComma(lhs); + children.push_back(rhs); + return children; + } + + return {child}; +} + ArgumentPtr Expression::compress(const ArgumentPtr &child) { if (const auto expr = cast(child)) { return expr->child; @@ -582,5 +568,4 @@ std::unique_ptr makeExpr(const IFunction &func, const ArgumentRefVe } } - }