• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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