// 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 #include #include #include namespace boost { namespace yap { /** Returns the char const * 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 expr_kind::expr_ref amd expr_kind::terminal, 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> struct printer { std::ostream & operator()(std::ostream & os, T const &) { return os << "<>"; } }; template struct printer< T, void_t() << std::declval())>> { std::ostream & operator()(std::ostream & os, T const & x) { return os << x; } }; template inline std::ostream & print_value(std::ostream & os, T const & x) { return printer{}(os, x); } template inline std::ostream & print_value(std::ostream & os, hana::llong) { return os << I << "_p"; } template std::ostream & print_type(std::ostream & os, hana::tuple const &) { os << typeindex::type_id().pretty_name(); if (std::is_const>::value) os << " const"; if (std::is_volatile>::value) os << " volatile"; if (std::is_lvalue_reference::value) os << " &"; if (std::is_rvalue_reference::value) os << " &&"; return os; } template bool is_const_expr_ref(T const &) { return false; } template class expr_template> bool is_const_expr_ref( expr_template> const &) { return true; } #ifdef BOOST_NO_CONSTEXPR_IF template struct print_impl { template 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::kind; print_impl{}(os, element, indent + 1, indent_str); }); return os; } }; template<> struct print_impl { template 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::kind; print_impl{}( os, ::boost::yap::deref(expr), indent, indent_str, true, ::boost::yap::detail::is_const_expr_ref(expr)); return os; } }; template<> struct print_impl { template 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 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 std::ostream & print(std::ostream & os, Expr const & expr) { #ifdef BOOST_NO_CONSTEXPR_IF return detail::print_impl::kind>{}( os, expr, 0, " "); #else return detail::print_impl(os, expr, 0, " "); #endif } }} #endif