Skip to content

Commit

Permalink
Refactor expression parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
fintarin committed Oct 7, 2023
1 parent b8987da commit 6cb56e0
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 94 deletions.
24 changes: 11 additions & 13 deletions include/fintamath/expressions/Expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ namespace fintamath {
struct Term {
Token name;

ArgumentPtr value;
std::unique_ptr<IMathObject> value;

public:
Term() = default;

Term(std::string inName, ArgumentPtr inValue)
Term(std::string inName, std::unique_ptr<IMathObject> inValue)
: name(std::move(inName)),
value(std::move(inValue)) {
}
};

using TermVector = std::vector<std::shared_ptr<Term>>;
using OperandStack = std::stack<ArgumentPtr>;
using TermVector = std::vector<std::unique_ptr<Term>>;
using OperandStack = std::stack<std::unique_ptr<IMathObject>>;

class Expression : public IExpressionCRTP<Expression> {
public:
Expand Down Expand Up @@ -85,9 +85,9 @@ class Expression : public IExpressionCRTP<Expression> {

static TermVector tokensToTerms(const TokenVector &tokens);

static OperandStack termsToOperands(const TermVector &terms);
static OperandStack termsToOperands(TermVector &terms);

static ArgumentPtr operandsToExpr(OperandStack &operands);
static std::unique_ptr<IMathObject> operandsToObject(OperandStack &operands);

static ArgumentPtrVector unwrapComma(const ArgumentPtr &child);

Expand All @@ -101,13 +101,13 @@ class Expression : public IExpressionCRTP<Expression> {

static bool canPrevTermBeBinaryOperator(const Term &term);

static bool isBinaryOperator(const ArgumentPtr &val);
static bool isBinaryOperator(const IMathObject *val);

static bool isPrefixOperator(const ArgumentPtr &val);
static bool isPrefixOperator(const IMathObject *val);

static bool isPostfixOperator(const ArgumentPtr &val);
static bool isPostfixOperator(const IMathObject *val);

static bool isNonOperatorFunction(const ArgumentPtr &val);
static bool isNonOperatorFunction(const IMathObject *val);

static void validateFunctionArgs(const IFunction &func, const ArgumentPtrVector &args);

Expand All @@ -121,7 +121,7 @@ class Expression : public IExpressionCRTP<Expression> {

friend std::unique_ptr<IMathObject> makeExpr(const IFunction &func, const ArgumentPtrVector &args);

friend ArgumentPtr parseExpr(const std::string &str);
friend std::unique_ptr<IMathObject> parseFintamath(const std::string &str);

static Parser::Vector<std::unique_ptr<Term>, const Token &> &getTermMakers();

Expand All @@ -137,8 +137,6 @@ class Expression : public IExpressionCRTP<Expression> {
mutable bool isSimplified = false;
};

ArgumentPtr parseExpr(const std::string &str);

Expression operator+(const Variable &lhs, const Variable &rhs);

Expression operator+(const Expression &lhs, const Variable &rhs);
Expand Down
9 changes: 9 additions & 0 deletions include/fintamath/expressions/ExpressionParser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include "fintamath/core/IMathObject.hpp"

namespace fintamath {

std::unique_ptr<IMathObject> parseFintamath(const std::string &str);

}
2 changes: 0 additions & 2 deletions include/fintamath/expressions/IExpression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ class IExpression : public IArithmetic {

static void preciseSimplifyChild(ArgumentPtr &child);

static void constSimplifyChild(ArgumentPtr &child);

static ArgumentPtr callFunction(const IFunction &func, const ArgumentPtrVector &argPtrs);

private:
Expand Down
16 changes: 8 additions & 8 deletions src/fintamath/config/ExpressionConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,28 +98,28 @@ struct ExpressionConfig {

static void registerTermsMakers() {
Expression::registerTermsMaker([](const Token &token) {
if (ArgumentPtr arg = IFunction::parse(token, IFunction::Type::Binary)) {
return std::make_unique<Term>(token, arg);
if (auto arg = IFunction::parse(token, IFunction::Type::Binary)) {
return std::make_unique<Term>(token, std::move(arg));
}

if (ArgumentPtr arg = IFunction::parse(token)) {
return std::make_unique<Term>(token, arg);
if (auto arg = IFunction::parse(token)) {
return std::make_unique<Term>(token, std::move(arg));
}

return std::unique_ptr<Term>();
});

Expression::registerTermsMaker([](const Token &token) {
if (ArgumentPtr arg = ILiteral::parse(token)) {
return std::make_unique<Term>(token, arg);
if (auto arg = ILiteral::parse(token)) {
return std::make_unique<Term>(token, std::move(arg));
}

return std::unique_ptr<Term>();
});

Expression::registerTermsMaker([](const Token &token) {
if (ArgumentPtr arg = INumber::parse(token)) {
return std::make_unique<Term>(token, arg->toMinimalObject());
if (auto arg = INumber::parse(token)) {
return std::make_unique<Term>(token, std::move(arg));
}

return std::unique_ptr<Term>();
Expand Down
93 changes: 46 additions & 47 deletions src/fintamath/expressions/Expression.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "fintamath/expressions/Expression.hpp"

#include "fintamath/expressions/ExpressionParser.hpp"
#include "fintamath/expressions/ExpressionUtils.hpp"
#include "fintamath/expressions/FunctionExpression.hpp"
#include "fintamath/functions/arithmetic/Add.hpp"
Expand All @@ -17,14 +18,14 @@
namespace fintamath {

struct TermWithPriority {
std::shared_ptr<Term> term;
std::unique_ptr<Term> term;

IOperator::Priority priority = IOperator::Priority::Lowest;

public:
TermWithPriority() = default;

TermWithPriority(std::shared_ptr<Term> inTerm, IOperator::Priority inPriority)
TermWithPriority(std::unique_ptr<Term> inTerm, IOperator::Priority inPriority)
: term(std::move(inTerm)),
priority(inPriority) {
}
Expand All @@ -33,7 +34,7 @@ struct TermWithPriority {
Expression::Expression() : child(Integer(0).clone()) {
}

Expression::Expression(const std::string &str) : child(parseExpr(str)) {
Expression::Expression(const std::string &str) : child(parseFintamath(str)) {
}

Expression::Expression(const ArgumentPtr &obj) : child(compress(obj)) {
Expand Down Expand Up @@ -140,12 +141,12 @@ void Expression::updateStringMutable() const {
stringCached = child->toString();
}

ArgumentPtr parseExpr(const std::string &str) {
std::unique_ptr<IMathObject> parseFintamath(const std::string &str) {
try {
auto tokens = Tokenizer::tokenize(str);
auto terms = Expression::tokensToTerms(tokens);
auto stack = Expression::termsToOperands(terms);
auto expr = Expression::operandsToExpr(stack);
auto expr = Expression::operandsToObject(stack);
return expr;
}
catch (const InvalidInputException &) {
Expand All @@ -165,7 +166,7 @@ TermVector Expression::tokensToTerms(const TokenVector &tokens) {
terms[i] = std::move(term);
}
else {
terms[i] = std::make_unique<Term>(tokens[i], ArgumentPtr());
terms[i] = std::make_unique<Term>(tokens[i], std::unique_ptr<IMathObject>());
}
}

Expand All @@ -178,20 +179,20 @@ TermVector Expression::tokensToTerms(const TokenVector &tokens) {

// Use the shunting yard algorithm
// https://en.m.wikipedia.org/wiki/Shunting_yard_algorithm
OperandStack Expression::termsToOperands(const TermVector &terms) {
std::stack<ArgumentPtr> outStack;
OperandStack Expression::termsToOperands(TermVector &terms) {
OperandStack outStack;
std::stack<TermWithPriority> operStack;

for (const auto &term : terms) {
for (auto &&term : terms) {
if (!term->value) {
if (term->name == "(") {
operStack.emplace(term, IOperator::Priority::Lowest);
operStack.emplace(std::move(term), IOperator::Priority::Lowest);
}
else if (term->name == ")") {
while (!operStack.empty() &&
operStack.top().term->name != "(") {

outStack.emplace(operStack.top().term->value);
outStack.emplace(std::move(operStack.top().term->value));
operStack.pop();
}

Expand All @@ -207,24 +208,24 @@ OperandStack Expression::termsToOperands(const TermVector &terms) {
}
else {
if (is<IFunction>(term->value)) {
if (auto oper = cast<IOperator>(term->value)) {
if (auto *oper = cast<IOperator>(term->value.get())) {
while (!operStack.empty() &&
operStack.top().term->name != "(" &&
operStack.top().priority <= oper->getOperatorPriority() &&
!isPrefixOperator(oper)) {

outStack.emplace(operStack.top().term->value);
outStack.emplace(std::move(operStack.top().term->value));
operStack.pop();
}

operStack.emplace(term, oper->getOperatorPriority());
operStack.emplace(std::move(term), oper->getOperatorPriority());
}
else {
operStack.emplace(term, IOperator::Priority::Highest);
operStack.emplace(std::move(term), IOperator::Priority::Highest);
}
}
else {
outStack.emplace(term->value);
outStack.emplace(std::move(term->value));
}
}
}
Expand All @@ -234,26 +235,27 @@ OperandStack Expression::termsToOperands(const TermVector &terms) {
throw InvalidInputException("");
}

outStack.emplace(operStack.top().term->value);
outStack.emplace(std::move(operStack.top().term->value));
operStack.pop();
}

return outStack;
}

ArgumentPtr Expression::operandsToExpr(OperandStack &operands) {
std::unique_ptr<IMathObject> Expression::operandsToObject(OperandStack &operands) {
if (operands.empty()) {
throw InvalidInputException("");
}

ArgumentPtr arg = operands.top();
std::unique_ptr<IMathObject> arg = std::move(operands.top());
operands.pop();

if (auto func = cast<IFunction>(arg)) {
ArgumentPtr rhsChild = operandsToExpr(operands);
if (is<IFunction>(arg)) {
auto func = cast<IFunction>(std::move(arg));
ArgumentPtr rhsChild = operandsToObject(operands);

if (isBinaryOperator(func)) {
ArgumentPtr lhsChild = operandsToExpr(operands);
if (isBinaryOperator(func.get())) {
ArgumentPtr lhsChild = operandsToObject(operands);
return makeExpr(*func, {lhsChild, rhsChild});
}

Expand Down Expand Up @@ -298,8 +300,8 @@ void Expression::insertMultiplications(TermVector &terms) {
if (canNextTermBeBinaryOperator(*terms[i - 1]) &&
canPrevTermBeBinaryOperator(*terms[i])) {

auto term = std::make_shared<Term>(mul->toString(), mul);
terms.insert(terms.begin() + ptrdiff_t(i), term);
auto term = std::make_unique<Term>(mul->toString(), mul->clone());
terms.insert(terms.begin() + ptrdiff_t(i), std::move(term));
i++;
}
}
Expand All @@ -310,15 +312,15 @@ void Expression::fixOperatorTypes(TermVector &terms) {

if (const auto &term = terms.front();
is<IOperator>(term->value) &&
!isPrefixOperator(term->value)) {
!isPrefixOperator(term->value.get())) {

term->value = IOperator::parse(term->name, IOperator::Priority::PrefixUnary);
isFixed = isFixed && term->value;
}

if (const auto &term = terms.back();
is<IOperator>(term->value) &&
!isPostfixOperator(term->value)) {
!isPostfixOperator(term->value.get())) {

term->value = IOperator::parse(term->name, IOperator::Priority::PostfixUnary);
isFixed = isFixed && term->value;
Expand All @@ -337,7 +339,7 @@ void Expression::fixOperatorTypes(TermVector &terms) {
const auto &termPrev = terms[i - 1];

if (is<IOperator>(term->value) &&
!isPrefixOperator(term->value) &&
!isPrefixOperator(term->value.get()) &&
!canNextTermBeBinaryOperator(*termPrev)) {

term->value = IOperator::parse(term->name, IOperator::Priority::PrefixUnary);
Expand All @@ -351,7 +353,7 @@ void Expression::fixOperatorTypes(TermVector &terms) {
const auto &termNext = terms[i + 1];

if (is<IOperator>(term->value) &&
!isPostfixOperator(term->value) &&
!isPostfixOperator(term->value.get()) &&
!canPrevTermBeBinaryOperator(*termNext)) {

term->value = IOperator::parse(term->name, IOperator::Priority::PostfixUnary);
Expand All @@ -369,12 +371,9 @@ void Expression::collapseFactorials(TermVector &terms) {
const auto &term = terms[i];
const auto &termNext = terms[i + 1];

if (auto factorial = cast<Factorial>(term->value);
factorial &&
is<Factorial>(termNext->value)) {

Factorial newFactorial;
newFactorial.setOrder(factorial->getOrder() + 1);
if (is<Factorial>(term->value) && is<Factorial>(termNext->value)) {
auto &oldFactorial = cast<Factorial>(*term->value);
Factorial newFactorial(oldFactorial.getOrder() + 1);
term->value = newFactorial.clone();

terms.erase(terms.begin() + ptrdiff_t(i) + 1);
Expand All @@ -384,36 +383,36 @@ void Expression::collapseFactorials(TermVector &terms) {
}

bool Expression::canNextTermBeBinaryOperator(const Term &term) {
return !(isPrefixOperator(term.value) ||
isBinaryOperator(term.value) ||
isNonOperatorFunction(term.value) ||
return !(isPrefixOperator(term.value.get()) ||
isBinaryOperator(term.value.get()) ||
isNonOperatorFunction(term.value.get()) ||
term.name == "(" ||
term.name == ",");
}

bool Expression::canPrevTermBeBinaryOperator(const Term &term) {
return !(isPostfixOperator(term.value) ||
isBinaryOperator(term.value) ||
return !(isPostfixOperator(term.value.get()) ||
isBinaryOperator(term.value.get()) ||
term.name == ")" ||
term.name == ",");
}

bool Expression::isBinaryOperator(const ArgumentPtr &val) {
auto oper = cast<IOperator>(val);
bool Expression::isBinaryOperator(const IMathObject *val) {
const auto *oper = cast<IOperator>(val);
return oper && oper->getFunctionType() == IFunction::Type::Binary;
}

bool Expression::isPrefixOperator(const ArgumentPtr &val) {
auto oper = cast<IOperator>(val);
bool Expression::isPrefixOperator(const IMathObject *val) {
const auto *oper = cast<IOperator>(val);
return oper && oper->getOperatorPriority() == IOperator::Priority::PrefixUnary;
}

bool Expression::isPostfixOperator(const ArgumentPtr &val) {
auto oper = cast<IOperator>(val);
bool Expression::isPostfixOperator(const IMathObject *val) {
const auto *oper = cast<IOperator>(val);
return oper && oper->getOperatorPriority() == IOperator::Priority::PostfixUnary;
}

bool Expression::isNonOperatorFunction(const ArgumentPtr &val) {
bool Expression::isNonOperatorFunction(const IMathObject *val) {
return is<IFunction>(val) && !is<IOperator>(val);
}

Expand Down
Loading

0 comments on commit 6cb56e0

Please sign in to comment.