Line data Source code
1 : #define MATHEVAL_IMPLEMENTATION
2 :
3 : #include "evaluator.hpp"
4 : #include "ast.hpp"
5 :
6 : namespace matheval {
7 :
8 : namespace ast {
9 :
10 : // Optimizer
11 :
12 : template <typename T>
13 : struct holds_alternative_impl {
14 : using result_type = bool;
15 :
16 : template <typename U>
17 2 : bool operator()(U const &) const {
18 2 : return std::is_same<U, T>::value;
19 : }
20 : };
21 :
22 : template <typename T, typename... Ts>
23 2 : bool holds_alternative(x3::variant<Ts...> const &v) {
24 2 : return boost::apply_visitor(holds_alternative_impl<T>(), v);
25 : }
26 :
27 0 : ConstantFolder::result_type ConstantFolder::operator()(nil) const {
28 0 : return result_type{0};
29 : }
30 :
31 2 : ConstantFolder::result_type ConstantFolder::operator()(double n) const {
32 2 : return result_type{n};
33 : }
34 :
35 0 : ConstantFolder::result_type ConstantFolder::
36 : operator()(std::string const &c) const {
37 0 : return result_type{c};
38 : }
39 :
40 1 : ConstantFolder::result_type ConstantFolder::
41 : operator()(operation const &x, operand const &lhs) const {
42 2 : auto rhs = boost::apply_visitor(*this, x.rhs);
43 :
44 1 : if (holds_alternative<double>(lhs) && holds_alternative<double>(rhs)) {
45 : return result_type{
46 2 : x.op(boost::get<double>(lhs), boost::get<double>(rhs))};
47 : }
48 0 : return result_type{binary_op{x.op, lhs, rhs}};
49 : }
50 :
51 0 : ConstantFolder::result_type ConstantFolder::
52 : operator()(unary_op const &x) const {
53 0 : auto rhs = boost::apply_visitor(*this, x.rhs);
54 :
55 : /// If the operand is known, we can directly evaluate the function.
56 0 : if (holds_alternative<double>(rhs)) {
57 0 : return result_type{x.op(boost::get<double>(rhs))};
58 : }
59 0 : return result_type{unary_op{x.op, rhs}};
60 : }
61 :
62 0 : ConstantFolder::result_type ConstantFolder::
63 : operator()(binary_op const &x) const {
64 0 : auto lhs = boost::apply_visitor(*this, x.lhs);
65 0 : auto rhs = boost::apply_visitor(*this, x.rhs);
66 :
67 : /// If both operands are known, we can directly evaluate the function,
68 : /// else we just update the children with the new expressions.
69 0 : if (holds_alternative<double>(lhs) && holds_alternative<double>(rhs)) {
70 : return result_type{
71 0 : x.op(boost::get<double>(lhs), boost::get<double>(rhs))};
72 : }
73 0 : return result_type{binary_op{x.op, lhs, rhs}};
74 : }
75 :
76 0 : ConstantFolder::result_type ConstantFolder::
77 : operator()(ternary_op const &x) const {
78 0 : auto cond = boost::apply_visitor(*this, x.cond);
79 0 : auto t = boost::apply_visitor(*this, x.t);
80 0 : auto f = boost::apply_visitor(*this, x.f);
81 :
82 : /// If both operands are known, we can directly evaluate the function,
83 : /// else we just update the children with the new expressions.
84 0 : if (holds_alternative<double>(cond) && holds_alternative<double>(t) && holds_alternative<double>(f)) {
85 : return result_type{
86 0 : x.op(boost::get<double>(cond), boost::get<double>(t), boost::get<double>(f))};
87 : }
88 0 : return result_type{ternary_op{x.op, cond, t, f}};
89 : }
90 :
91 8 : ConstantFolder::result_type ConstantFolder::
92 : operator()(expression const &x) const {
93 16 : auto state = boost::apply_visitor(*this, x.lhs);
94 9 : for (operation const &oper : x.rhs) {
95 1 : state = (*this)(oper, state);
96 : }
97 16 : return result_type{state};
98 : }
99 :
100 : // Evaluator
101 :
102 0 : double eval::operator()(nil) const {
103 0 : BOOST_ASSERT(0);
104 : return 0;
105 : }
106 :
107 217 : double eval::operator()(double n) const { return n; }
108 :
109 17 : double eval::operator()(std::string const &c) const {
110 17 : auto it = st.find(c);
111 17 : if (it == st.end()) {
112 2 : throw std::invalid_argument("Unknown variable " + c); // NOLINT
113 : }
114 15 : return it->second;
115 : }
116 :
117 127 : double eval::operator()(operation const &x, double lhs) const {
118 127 : double rhs = boost::apply_visitor(*this, x.rhs);
119 127 : return x.op(lhs, rhs);
120 : }
121 :
122 38 : double eval::operator()(unary_op const &x) const {
123 38 : double rhs = boost::apply_visitor(*this, x.rhs);
124 38 : return x.op(rhs);
125 : }
126 :
127 5 : double eval::operator()(binary_op const &x) const {
128 5 : double lhs = boost::apply_visitor(*this, x.lhs);
129 5 : double rhs = boost::apply_visitor(*this, x.rhs);
130 5 : return x.op(lhs, rhs);
131 : }
132 :
133 2 : double eval::operator()(ternary_op const &x) const {
134 2 : double cond = boost::apply_visitor(*this, x.cond);
135 2 : double t = boost::apply_visitor(*this, x.t);
136 2 : double f = boost::apply_visitor(*this, x.f);
137 2 : return x.op(cond, t, f);
138 : }
139 :
140 1316 : double eval::operator()(expression const &x) const {
141 1316 : double state = boost::apply_visitor(*this, x.lhs);
142 1431 : for (operation const &oper : x.rhs) {
143 127 : state = (*this)(oper, state);
144 : }
145 1304 : return state;
146 : }
147 :
148 : } // namespace ast
149 :
150 : } // namespace matheval
|