123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- // Copyright (C) 2016-2018 T. Zachary Laine
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_YAP_PRINT_HPP_INCLUDED
- #define BOOST_YAP_PRINT_HPP_INCLUDED
- #include <boost/yap/algorithm_fwd.hpp>
- #include <boost/hana/for_each.hpp>
- #include <boost/type_index.hpp>
- #include <iostream>
- namespace boost { namespace yap {
- /** Returns the <code>char const *</code> string for the spelling of the
- C++ operator associated with \a kind. It returns the special values
- "ref" and "term" for the non-operator kinds
- <code>expr_kind::expr_ref</code> amd <code>expr_kind::terminal</code>,
- respectively.*/
- inline constexpr char const * op_string(expr_kind kind)
- {
- switch (kind) {
- case expr_kind::expr_ref: return "ref";
- case expr_kind::terminal: return "term";
- case expr_kind::unary_plus: return "+";
- case expr_kind::negate: return "-";
- case expr_kind::dereference: return "*";
- case expr_kind::complement: return "~";
- case expr_kind::address_of: return "&";
- case expr_kind::logical_not: return "!";
- case expr_kind::pre_inc: return "++";
- case expr_kind::pre_dec: return "--";
- case expr_kind::post_inc: return "++(int)";
- case expr_kind::post_dec: return "--(int)";
- case expr_kind::shift_left: return "<<";
- case expr_kind::shift_right: return ">>";
- case expr_kind::multiplies: return "*";
- case expr_kind::divides: return "/";
- case expr_kind::modulus: return "%";
- case expr_kind::plus: return "+";
- case expr_kind::minus: return "-";
- case expr_kind::less: return "<";
- case expr_kind::greater: return ">";
- case expr_kind::less_equal: return "<=";
- case expr_kind::greater_equal: return ">=";
- case expr_kind::equal_to: return "==";
- case expr_kind::not_equal_to: return "!=";
- case expr_kind::logical_or: return "||";
- case expr_kind::logical_and: return "&&";
- case expr_kind::bitwise_and: return "&";
- case expr_kind::bitwise_or: return "|";
- case expr_kind::bitwise_xor: return "^";
- case expr_kind::comma: return ",";
- case expr_kind::mem_ptr: return "->*";
- case expr_kind::assign: return "=";
- case expr_kind::shift_left_assign: return "<<=";
- case expr_kind::shift_right_assign: return ">>=";
- case expr_kind::multiplies_assign: return "*=";
- case expr_kind::divides_assign: return "/=";
- case expr_kind::modulus_assign: return "%=";
- case expr_kind::plus_assign: return "+=";
- case expr_kind::minus_assign: return "-=";
- case expr_kind::bitwise_and_assign: return "&=";
- case expr_kind::bitwise_or_assign: return "|=";
- case expr_kind::bitwise_xor_assign: return "^=";
- case expr_kind::subscript: return "[]";
- case expr_kind::if_else: return "?:";
- case expr_kind::call: return "()";
- default: return "** ERROR: UNKNOWN OPERATOR! **";
- }
- }
- namespace detail {
- inline std::ostream & print_kind(std::ostream & os, expr_kind kind)
- {
- return os << op_string(kind);
- }
- template<typename T, typename = void_t<>>
- struct printer
- {
- std::ostream & operator()(std::ostream & os, T const &)
- {
- return os << "<<unprintable-value>>";
- }
- };
- template<typename T>
- struct printer<
- T,
- void_t<decltype(
- std::declval<std::ostream &>() << std::declval<T const &>())>>
- {
- std::ostream & operator()(std::ostream & os, T const & x)
- {
- return os << x;
- }
- };
- template<typename T>
- inline std::ostream & print_value(std::ostream & os, T const & x)
- {
- return printer<T>{}(os, x);
- }
- template<long long I>
- inline std::ostream & print_value(std::ostream & os, hana::llong<I>)
- {
- return os << I << "_p";
- }
- template<typename T>
- std::ostream & print_type(std::ostream & os, hana::tuple<T> const &)
- {
- os << typeindex::type_id<T>().pretty_name();
- if (std::is_const<std::remove_reference_t<T>>::value)
- os << " const";
- if (std::is_volatile<std::remove_reference_t<T>>::value)
- os << " volatile";
- if (std::is_lvalue_reference<T>::value)
- os << " &";
- if (std::is_rvalue_reference<T>::value)
- os << " &&";
- return os;
- }
- template<typename T>
- bool is_const_expr_ref(T const &)
- {
- return false;
- }
- template<typename T, template<expr_kind, class> class expr_template>
- bool is_const_expr_ref(
- expr_template<expr_kind::expr_ref, hana::tuple<T const *>> const &)
- {
- return true;
- }
- #ifdef BOOST_NO_CONSTEXPR_IF
- template<expr_kind Kind>
- struct print_impl
- {
- template<typename Expr>
- std::ostream & operator()(
- std::ostream & os,
- Expr const & expr,
- int indent,
- char const * indent_str,
- bool is_ref = false,
- bool is_const_ref = false)
- {
- for (int i = 0; i < indent; ++i) {
- os << indent_str;
- }
- os << "expr<";
- ::boost::yap::detail::print_kind(os, Expr::kind);
- os << ">";
- if (is_const_ref)
- os << " const &";
- else if (is_ref)
- os << " &";
- os << "\n";
- hana::for_each(
- expr.elements,
- [&os, indent, indent_str](auto const & element) {
- using element_type = decltype(element);
- constexpr expr_kind kind =
- detail::remove_cv_ref_t<element_type>::kind;
- print_impl<kind>{}(os, element, indent + 1, indent_str);
- });
- return os;
- }
- };
- template<>
- struct print_impl<expr_kind::expr_ref>
- {
- template<typename Expr>
- std::ostream & operator()(
- std::ostream & os,
- Expr const & expr,
- int indent,
- char const * indent_str,
- bool is_ref = false,
- bool is_const_ref = false)
- {
- using ref_type = decltype(::boost::yap::deref(expr));
- constexpr expr_kind ref_kind =
- detail::remove_cv_ref_t<ref_type>::kind;
- print_impl<ref_kind>{}(
- os,
- ::boost::yap::deref(expr),
- indent,
- indent_str,
- true,
- ::boost::yap::detail::is_const_expr_ref(expr));
- return os;
- }
- };
- template<>
- struct print_impl<expr_kind::terminal>
- {
- template<typename Expr>
- std::ostream & operator()(
- std::ostream & os,
- Expr const & expr,
- int indent,
- char const * indent_str,
- bool is_ref = false,
- bool is_const_ref = false)
- {
- for (int i = 0; i < indent; ++i) {
- os << indent_str;
- }
- os << "term<";
- ::boost::yap::detail::print_type(os, expr.elements);
- os << ">[=";
- ::boost::yap::detail::print_value(
- os, ::boost::yap::value(expr));
- os << "]";
- if (is_const_ref)
- os << " const &";
- else if (is_ref)
- os << " &";
- os << "\n";
- return os;
- }
- };
- #else
- template<typename Expr>
- std::ostream & print_impl(
- std::ostream & os,
- Expr const & expr,
- int indent,
- char const * indent_str,
- bool is_ref = false,
- bool is_const_ref = false)
- {
- if constexpr (Expr::kind == expr_kind::expr_ref) {
- print_impl(
- os,
- ::boost::yap::deref(expr),
- indent,
- indent_str,
- true,
- ::boost::yap::detail::is_const_expr_ref(expr));
- } else {
- for (int i = 0; i < indent; ++i) {
- os << indent_str;
- }
- if constexpr (Expr::kind == expr_kind::terminal) {
- os << "term<";
- ::boost::yap::detail::print_type(os, expr.elements);
- os << ">[=";
- ::boost::yap::detail::print_value(
- os, ::boost::yap::value(expr));
- os << "]";
- if (is_const_ref)
- os << " const &";
- else if (is_ref)
- os << " &";
- os << "\n";
- } else {
- os << "expr<";
- ::boost::yap::detail::print_kind(os, Expr::kind);
- os << ">";
- if (is_const_ref)
- os << " const &";
- else if (is_ref)
- os << " &";
- os << "\n";
- hana::for_each(
- expr.elements,
- [&os, indent, indent_str](auto const & element) {
- ::boost::yap::detail::print_impl(
- os, element, indent + 1, indent_str);
- });
- }
- }
- return os;
- }
- #endif // BOOST_NO_CONSTEXPR_IF
- }
- /** Prints expression \a expr to stream \a os. Returns \a os. */
- template<typename Expr>
- std::ostream & print(std::ostream & os, Expr const & expr)
- {
- #ifdef BOOST_NO_CONSTEXPR_IF
- return detail::print_impl<detail::remove_cv_ref_t<Expr>::kind>{}(
- os, expr, 0, " ");
- #else
- return detail::print_impl(os, expr, 0, " ");
- #endif
- }
- }}
- #endif
|