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