print.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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. #ifndef BOOST_YAP_PRINT_HPP_INCLUDED
  7. #define BOOST_YAP_PRINT_HPP_INCLUDED
  8. #include <boost/yap/algorithm_fwd.hpp>
  9. #include <boost/hana/for_each.hpp>
  10. #include <boost/type_index.hpp>
  11. #include <iostream>
  12. namespace boost { namespace yap {
  13. /** Returns the <code>char const *</code> string for the spelling of the
  14. C++ operator associated with \a kind. It returns the special values
  15. "ref" and "term" for the non-operator kinds
  16. <code>expr_kind::expr_ref</code> amd <code>expr_kind::terminal</code>,
  17. respectively.*/
  18. inline constexpr char const * op_string(expr_kind kind)
  19. {
  20. switch (kind) {
  21. case expr_kind::expr_ref: return "ref";
  22. case expr_kind::terminal: return "term";
  23. case expr_kind::unary_plus: return "+";
  24. case expr_kind::negate: return "-";
  25. case expr_kind::dereference: return "*";
  26. case expr_kind::complement: return "~";
  27. case expr_kind::address_of: return "&";
  28. case expr_kind::logical_not: return "!";
  29. case expr_kind::pre_inc: return "++";
  30. case expr_kind::pre_dec: return "--";
  31. case expr_kind::post_inc: return "++(int)";
  32. case expr_kind::post_dec: return "--(int)";
  33. case expr_kind::shift_left: return "<<";
  34. case expr_kind::shift_right: return ">>";
  35. case expr_kind::multiplies: return "*";
  36. case expr_kind::divides: return "/";
  37. case expr_kind::modulus: return "%";
  38. case expr_kind::plus: return "+";
  39. case expr_kind::minus: return "-";
  40. case expr_kind::less: return "<";
  41. case expr_kind::greater: return ">";
  42. case expr_kind::less_equal: return "<=";
  43. case expr_kind::greater_equal: return ">=";
  44. case expr_kind::equal_to: return "==";
  45. case expr_kind::not_equal_to: return "!=";
  46. case expr_kind::logical_or: return "||";
  47. case expr_kind::logical_and: return "&&";
  48. case expr_kind::bitwise_and: return "&";
  49. case expr_kind::bitwise_or: return "|";
  50. case expr_kind::bitwise_xor: return "^";
  51. case expr_kind::comma: return ",";
  52. case expr_kind::mem_ptr: return "->*";
  53. case expr_kind::assign: return "=";
  54. case expr_kind::shift_left_assign: return "<<=";
  55. case expr_kind::shift_right_assign: return ">>=";
  56. case expr_kind::multiplies_assign: return "*=";
  57. case expr_kind::divides_assign: return "/=";
  58. case expr_kind::modulus_assign: return "%=";
  59. case expr_kind::plus_assign: return "+=";
  60. case expr_kind::minus_assign: return "-=";
  61. case expr_kind::bitwise_and_assign: return "&=";
  62. case expr_kind::bitwise_or_assign: return "|=";
  63. case expr_kind::bitwise_xor_assign: return "^=";
  64. case expr_kind::subscript: return "[]";
  65. case expr_kind::if_else: return "?:";
  66. case expr_kind::call: return "()";
  67. default: return "** ERROR: UNKNOWN OPERATOR! **";
  68. }
  69. }
  70. namespace detail {
  71. inline std::ostream & print_kind(std::ostream & os, expr_kind kind)
  72. {
  73. return os << op_string(kind);
  74. }
  75. template<typename T, typename = void_t<>>
  76. struct printer
  77. {
  78. std::ostream & operator()(std::ostream & os, T const &)
  79. {
  80. return os << "<<unprintable-value>>";
  81. }
  82. };
  83. template<typename T>
  84. struct printer<
  85. T,
  86. void_t<decltype(
  87. std::declval<std::ostream &>() << std::declval<T const &>())>>
  88. {
  89. std::ostream & operator()(std::ostream & os, T const & x)
  90. {
  91. return os << x;
  92. }
  93. };
  94. template<typename T>
  95. inline std::ostream & print_value(std::ostream & os, T const & x)
  96. {
  97. return printer<T>{}(os, x);
  98. }
  99. template<long long I>
  100. inline std::ostream & print_value(std::ostream & os, hana::llong<I>)
  101. {
  102. return os << I << "_p";
  103. }
  104. template<typename T>
  105. std::ostream & print_type(std::ostream & os, hana::tuple<T> const &)
  106. {
  107. os << typeindex::type_id<T>().pretty_name();
  108. if (std::is_const<std::remove_reference_t<T>>::value)
  109. os << " const";
  110. if (std::is_volatile<std::remove_reference_t<T>>::value)
  111. os << " volatile";
  112. if (std::is_lvalue_reference<T>::value)
  113. os << " &";
  114. if (std::is_rvalue_reference<T>::value)
  115. os << " &&";
  116. return os;
  117. }
  118. template<typename T>
  119. bool is_const_expr_ref(T const &)
  120. {
  121. return false;
  122. }
  123. template<typename T, template<expr_kind, class> class expr_template>
  124. bool is_const_expr_ref(
  125. expr_template<expr_kind::expr_ref, hana::tuple<T const *>> const &)
  126. {
  127. return true;
  128. }
  129. #ifdef BOOST_NO_CONSTEXPR_IF
  130. template<expr_kind Kind>
  131. struct print_impl
  132. {
  133. template<typename Expr>
  134. std::ostream & operator()(
  135. std::ostream & os,
  136. Expr const & expr,
  137. int indent,
  138. char const * indent_str,
  139. bool is_ref = false,
  140. bool is_const_ref = false)
  141. {
  142. for (int i = 0; i < indent; ++i) {
  143. os << indent_str;
  144. }
  145. os << "expr<";
  146. ::boost::yap::detail::print_kind(os, Expr::kind);
  147. os << ">";
  148. if (is_const_ref)
  149. os << " const &";
  150. else if (is_ref)
  151. os << " &";
  152. os << "\n";
  153. hana::for_each(
  154. expr.elements,
  155. [&os, indent, indent_str](auto const & element) {
  156. using element_type = decltype(element);
  157. constexpr expr_kind kind =
  158. detail::remove_cv_ref_t<element_type>::kind;
  159. print_impl<kind>{}(os, element, indent + 1, indent_str);
  160. });
  161. return os;
  162. }
  163. };
  164. template<>
  165. struct print_impl<expr_kind::expr_ref>
  166. {
  167. template<typename Expr>
  168. std::ostream & operator()(
  169. std::ostream & os,
  170. Expr const & expr,
  171. int indent,
  172. char const * indent_str,
  173. bool is_ref = false,
  174. bool is_const_ref = false)
  175. {
  176. using ref_type = decltype(::boost::yap::deref(expr));
  177. constexpr expr_kind ref_kind =
  178. detail::remove_cv_ref_t<ref_type>::kind;
  179. print_impl<ref_kind>{}(
  180. os,
  181. ::boost::yap::deref(expr),
  182. indent,
  183. indent_str,
  184. true,
  185. ::boost::yap::detail::is_const_expr_ref(expr));
  186. return os;
  187. }
  188. };
  189. template<>
  190. struct print_impl<expr_kind::terminal>
  191. {
  192. template<typename Expr>
  193. std::ostream & operator()(
  194. std::ostream & os,
  195. Expr const & expr,
  196. int indent,
  197. char const * indent_str,
  198. bool is_ref = false,
  199. bool is_const_ref = false)
  200. {
  201. for (int i = 0; i < indent; ++i) {
  202. os << indent_str;
  203. }
  204. os << "term<";
  205. ::boost::yap::detail::print_type(os, expr.elements);
  206. os << ">[=";
  207. ::boost::yap::detail::print_value(
  208. os, ::boost::yap::value(expr));
  209. os << "]";
  210. if (is_const_ref)
  211. os << " const &";
  212. else if (is_ref)
  213. os << " &";
  214. os << "\n";
  215. return os;
  216. }
  217. };
  218. #else
  219. template<typename Expr>
  220. std::ostream & print_impl(
  221. std::ostream & os,
  222. Expr const & expr,
  223. int indent,
  224. char const * indent_str,
  225. bool is_ref = false,
  226. bool is_const_ref = false)
  227. {
  228. if constexpr (Expr::kind == expr_kind::expr_ref) {
  229. print_impl(
  230. os,
  231. ::boost::yap::deref(expr),
  232. indent,
  233. indent_str,
  234. true,
  235. ::boost::yap::detail::is_const_expr_ref(expr));
  236. } else {
  237. for (int i = 0; i < indent; ++i) {
  238. os << indent_str;
  239. }
  240. if constexpr (Expr::kind == expr_kind::terminal) {
  241. os << "term<";
  242. ::boost::yap::detail::print_type(os, expr.elements);
  243. os << ">[=";
  244. ::boost::yap::detail::print_value(
  245. os, ::boost::yap::value(expr));
  246. os << "]";
  247. if (is_const_ref)
  248. os << " const &";
  249. else if (is_ref)
  250. os << " &";
  251. os << "\n";
  252. } else {
  253. os << "expr<";
  254. ::boost::yap::detail::print_kind(os, Expr::kind);
  255. os << ">";
  256. if (is_const_ref)
  257. os << " const &";
  258. else if (is_ref)
  259. os << " &";
  260. os << "\n";
  261. hana::for_each(
  262. expr.elements,
  263. [&os, indent, indent_str](auto const & element) {
  264. ::boost::yap::detail::print_impl(
  265. os, element, indent + 1, indent_str);
  266. });
  267. }
  268. }
  269. return os;
  270. }
  271. #endif // BOOST_NO_CONSTEXPR_IF
  272. }
  273. /** Prints expression \a expr to stream \a os. Returns \a os. */
  274. template<typename Expr>
  275. std::ostream & print(std::ostream & os, Expr const & expr)
  276. {
  277. #ifdef BOOST_NO_CONSTEXPR_IF
  278. return detail::print_impl<detail::remove_cv_ref_t<Expr>::kind>{}(
  279. os, expr, 0, " ");
  280. #else
  281. return detail::print_impl(os, expr, 0, " ");
  282. #endif
  283. }
  284. }}
  285. #endif