LCOV - code coverage report
Current view: top level - src/x3 - evaluator.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 41 66 62.1 %
Date: 2022-11-05 14:57:37 Functions: 12 24 50.0 %

          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

Generated by: LCOV version 1.14