-
Notifications
You must be signed in to change notification settings - Fork 6
/
Expression.hpp
186 lines (117 loc) · 5.05 KB
/
Expression.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#pragma once
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include "fintamath/core/IMathObject.hpp"
#include "fintamath/core/MathObjectClass.hpp"
#include "fintamath/core/Parser.hpp"
#include "fintamath/core/Tokenizer.hpp"
#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 {
namespace detail {
struct Term final {
Token name;
std::unique_ptr<IMathObject> value;
public:
Term() = default;
Term(std::string inName, std::unique_ptr<IMathObject> inValue)
: name(std::move(inName)),
value(std::move(inValue)) {
}
};
struct FunctionTerm final {
Term term;
std::optional<IOperator::Priority> priority;
public:
FunctionTerm() = default;
FunctionTerm(Term inTerm, const std::optional<IOperator::Priority> inPriority)
: term(std::move(inTerm)),
priority(inPriority) {
}
};
using TermVector = std::vector<Term>;
using FunctionTermStack = std::stack<FunctionTerm>;
using ObjectStack = std::stack<std::unique_ptr<IMathObject>>;
}
class Expression : public IExpressionCRTP<Expression> {
FINTAMATH_CLASS_BODY(Expression, IExpression)
using ExpressionConstructor = std::function<std::unique_ptr<IMathObject>(ArgumentPtrVector &&)>;
using ExpressionMaker = std::unordered_map<MathObjectClass, ExpressionConstructor>;
public:
Expression();
explicit Expression(const std::string &str);
explicit Expression(const ArgumentPtr &obj);
Expression(const IMathObject &obj);
Expression(int64_t val);
std::string toString() const override;
const std::shared_ptr<IFunction> &getFunction() const override;
const ArgumentPtrVector &getChildren() const override;
void setChildren(const ArgumentPtrVector &childVect) override;
void setVariables(const std::vector<std::pair<Variable, ArgumentPtr>> &varsToVals) override;
void setVariable(const Variable &var, const Expression &val);
template <typename Function>
static void registerExpressionConstructor(ExpressionConstructor constructor);
protected:
ArgumentPtr simplify() const override;
private:
void simplifyMutable() const;
void updateStringMutable() const;
static detail::TermVector tokensToTerms(detail::TokenVector &tokens);
static detail::ObjectStack termsToObjects(detail::TermVector &terms);
static std::unique_ptr<IMathObject> objectsToExpr(detail::ObjectStack &objects);
static std::unique_ptr<IFunction> findFunction(const std::string &str, size_t argNum);
static std::unique_ptr<IOperator> findOperator(const std::string &str, IOperator::Priority priority);
static detail::Term parseTerm(const std::string &str);
static void moveFunctionTermsToObjects(detail::ObjectStack &objects, detail::FunctionTermStack &functions, const IOperator *nextOper);
static void insertMultiplications(detail::TermVector &terms);
static void fixOperatorTypes(detail::TermVector &terms);
static void collapseFactorials(detail::TermVector &terms);
static bool canNextTermBeBinaryOperator(const detail::Term &term);
static bool canPrevTermBeBinaryOperator(const detail::Term &term);
static bool isBinaryOperator(const IMathObject *val);
static bool isPrefixOperator(const IMathObject *val);
static bool isPostfixOperator(const IMathObject *val);
static bool isNonOperatorFunction(const IMathObject *val);
static void validateFunctionArgs(const IFunction &func, const ArgumentPtrVector &args);
static std::pair<MathObjectClass, bool> doesArgMatch(const MathObjectClass &expectedClass, const ArgumentPtr &arg);
static ArgumentPtrVector unwrapComma(const ArgumentPtr &child);
static ArgumentPtr compress(const ArgumentPtr &child);
friend std::unique_ptr<IMathObject> detail::makeExpr(const IFunction &func, ArgumentPtrVector args);
friend std::unique_ptr<IMathObject> detail::makeExprWithValidation(const IFunction &func, ArgumentPtrVector args);
friend std::unique_ptr<IMathObject> parseRawExpr(const std::string &str);
friend Expression approximate(const Expression &rhs, unsigned precision);
static ExpressionMaker &getExpressionMaker();
private:
mutable ArgumentPtr child;
mutable ArgumentPtrVector childrenCached = {{}};
mutable std::string stringCached;
mutable bool isSimplified = false;
};
std::unique_ptr<IMathObject> parseRawExpr(const std::string &str);
template <typename Function>
void Expression::registerExpressionConstructor(ExpressionConstructor constructor) {
getExpressionMaker()[Function::getClassStatic()] = [maker = std::move(constructor)](ArgumentPtrVector &&args) {
static const size_t funcArgSize = Function{}.getArgumentClasses().size();
std::unique_ptr<IMathObject> res;
if constexpr (Function::isVariadicStatic()) {
res = maker(std::move(args));
}
else {
if (funcArgSize == args.size()) {
res = maker(std::move(args));
}
}
return res;
};
}
}