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