call_expr.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright (C) 2016-2018 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #include <boost/yap/expression.hpp>
  7. #include <boost/test/minimal.hpp>
  8. #include <sstream>
  9. template<typename T>
  10. using term = boost::yap::terminal<boost::yap::expression, T>;
  11. template<typename T>
  12. using ref = boost::yap::expression_ref<boost::yap::expression, T>;
  13. namespace yap = boost::yap;
  14. namespace bh = boost::hana;
  15. namespace user {
  16. struct number
  17. {
  18. explicit operator double() const { return value; }
  19. double value;
  20. };
  21. number naxpy(number a, number x, number y)
  22. {
  23. return number{a.value * x.value + y.value + 10.0};
  24. }
  25. struct tag_type
  26. {};
  27. inline number tag_function(double a, double b) { return number{a + b}; }
  28. struct eval_xform_tag
  29. {
  30. decltype(auto) operator()(
  31. yap::expr_tag<yap::expr_kind::call>, tag_type, number a, double b)
  32. {
  33. return tag_function(a.value, b);
  34. }
  35. int operator()(
  36. yap::expr_tag<yap::expr_kind::call>, tag_type, double a, double b)
  37. {
  38. return 42;
  39. }
  40. char const * operator()() { return "42"; }
  41. };
  42. struct empty_xform
  43. {};
  44. struct eval_xform_expr
  45. {
  46. decltype(auto) operator()(yap::expression<
  47. yap::expr_kind::call,
  48. bh::tuple<
  49. ref<term<user::tag_type>>,
  50. term<user::number>,
  51. term<int>>> const & expr)
  52. {
  53. using namespace boost::hana::literals;
  54. return tag_function(
  55. (double)yap::value(expr.elements[1_c]).value,
  56. (double)yap::value(expr.elements[2_c]));
  57. }
  58. decltype(auto) operator()(yap::expression<
  59. yap::expr_kind::call,
  60. bh::tuple<
  61. ref<term<user::tag_type>>,
  62. ref<term<user::number>>,
  63. term<int>>> const & expr)
  64. {
  65. using namespace boost::hana::literals;
  66. return tag_function(
  67. (double)yap::value(expr.elements[1_c]).value,
  68. (double)yap::value(expr.elements[2_c]));
  69. }
  70. };
  71. struct eval_xform_both
  72. {
  73. decltype(auto) operator()(
  74. yap::expr_tag<yap::expr_kind::call>,
  75. tag_type,
  76. user::number a,
  77. double b)
  78. {
  79. return tag_function(a.value, b);
  80. }
  81. decltype(auto) operator()(yap::expression<
  82. yap::expr_kind::call,
  83. bh::tuple<
  84. ref<term<user::tag_type>>,
  85. term<user::number>,
  86. term<int>>> const & expr)
  87. {
  88. using namespace boost::hana::literals;
  89. throw std::logic_error("Oops! Picked the wrong overload!");
  90. return tag_function(
  91. (double)yap::value(expr.elements[1_c]).value,
  92. (double)yap::value(expr.elements[2_c]));
  93. }
  94. decltype(auto) operator()(yap::expression<
  95. yap::expr_kind::call,
  96. bh::tuple<
  97. ref<term<user::tag_type>>,
  98. ref<term<user::number>>,
  99. term<int>>> const & expr)
  100. {
  101. using namespace boost::hana::literals;
  102. throw std::logic_error("Oops! Picked the wrong overload!");
  103. return tag_function(
  104. (double)yap::value(expr.elements[1_c]).value,
  105. (double)yap::value(expr.elements[2_c]));
  106. }
  107. };
  108. }
  109. int test_main(int, char * [])
  110. {
  111. {
  112. using namespace boost::yap::literals;
  113. {
  114. auto plus = yap::make_terminal(user::tag_type{});
  115. auto expr = plus(user::number{13}, 1);
  116. {
  117. transform(expr, user::empty_xform{});
  118. }
  119. {
  120. user::number result = transform(expr, user::eval_xform_tag{});
  121. BOOST_CHECK(result.value == 14);
  122. }
  123. {
  124. user::number result = transform(expr, user::eval_xform_expr{});
  125. BOOST_CHECK(result.value == 14);
  126. }
  127. {
  128. user::number result = transform(expr, user::eval_xform_both{});
  129. BOOST_CHECK(result.value == 14);
  130. }
  131. }
  132. {
  133. auto plus = yap::make_terminal(user::tag_type{});
  134. auto thirteen = yap::make_terminal(user::number{13});
  135. auto expr = plus(thirteen, 1);
  136. {
  137. user::number result = transform(expr, user::eval_xform_tag{});
  138. BOOST_CHECK(result.value == 14);
  139. }
  140. {
  141. user::number result = transform(expr, user::eval_xform_expr{});
  142. BOOST_CHECK(result.value == 14);
  143. }
  144. {
  145. user::number result = transform(expr, user::eval_xform_both{});
  146. BOOST_CHECK(result.value == 14);
  147. }
  148. }
  149. {
  150. term<user::number> a{{1.0}};
  151. term<user::number> x{{42.0}};
  152. term<user::number> y{{3.0}};
  153. auto n = yap::make_terminal(user::naxpy);
  154. auto expr = n(a, x, y);
  155. {
  156. user::number result = evaluate(expr);
  157. BOOST_CHECK(result.value == 55);
  158. }
  159. }
  160. }
  161. return 0;
  162. }