1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file debug.hpp
3 /// Utilities for debugging Proto expression trees
4 //
5 //  Copyright 2008 Eric Niebler. Distributed under the Boost
6 //  Software License, Version 1.0. (See accompanying file
7 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_PROTO_DEBUG_HPP_EAN_12_31_2006
10 #define BOOST_PROTO_DEBUG_HPP_EAN_12_31_2006
11 
12 #include <iostream>
13 #include <boost/preprocessor/stringize.hpp>
14 #include <boost/core/ref.hpp>
15 #include <boost/core/typeinfo.hpp>
16 #include <boost/mpl/assert.hpp>
17 #include <boost/proto/proto_fwd.hpp>
18 #include <boost/proto/traits.hpp>
19 #include <boost/proto/matches.hpp>
20 #include <boost/proto/fusion.hpp>
21 #include <boost/fusion/algorithm/iteration/for_each.hpp>
22 
23 namespace boost { namespace proto
24 {
25     namespace tagns_ { namespace tag
26     {
27     #define BOOST_PROTO_DEFINE_TAG_INSERTION(Tag)                               \
28         /** \brief INTERNAL ONLY */                                             \
29         inline std::ostream &operator <<(std::ostream &sout, Tag const &)       \
30         {                                                                       \
31             return sout << BOOST_PP_STRINGIZE(Tag);                             \
32         }                                                                       \
33         /**/
34 
35         BOOST_PROTO_DEFINE_TAG_INSERTION(terminal)
36         BOOST_PROTO_DEFINE_TAG_INSERTION(unary_plus)
37         BOOST_PROTO_DEFINE_TAG_INSERTION(negate)
38         BOOST_PROTO_DEFINE_TAG_INSERTION(dereference)
39         BOOST_PROTO_DEFINE_TAG_INSERTION(complement)
40         BOOST_PROTO_DEFINE_TAG_INSERTION(address_of)
41         BOOST_PROTO_DEFINE_TAG_INSERTION(logical_not)
42         BOOST_PROTO_DEFINE_TAG_INSERTION(pre_inc)
43         BOOST_PROTO_DEFINE_TAG_INSERTION(pre_dec)
44         BOOST_PROTO_DEFINE_TAG_INSERTION(post_inc)
45         BOOST_PROTO_DEFINE_TAG_INSERTION(post_dec)
46         BOOST_PROTO_DEFINE_TAG_INSERTION(shift_left)
47         BOOST_PROTO_DEFINE_TAG_INSERTION(shift_right)
48         BOOST_PROTO_DEFINE_TAG_INSERTION(multiplies)
49         BOOST_PROTO_DEFINE_TAG_INSERTION(divides)
50         BOOST_PROTO_DEFINE_TAG_INSERTION(modulus)
51         BOOST_PROTO_DEFINE_TAG_INSERTION(plus)
52         BOOST_PROTO_DEFINE_TAG_INSERTION(minus)
53         BOOST_PROTO_DEFINE_TAG_INSERTION(less)
54         BOOST_PROTO_DEFINE_TAG_INSERTION(greater)
55         BOOST_PROTO_DEFINE_TAG_INSERTION(less_equal)
56         BOOST_PROTO_DEFINE_TAG_INSERTION(greater_equal)
57         BOOST_PROTO_DEFINE_TAG_INSERTION(equal_to)
58         BOOST_PROTO_DEFINE_TAG_INSERTION(not_equal_to)
59         BOOST_PROTO_DEFINE_TAG_INSERTION(logical_or)
60         BOOST_PROTO_DEFINE_TAG_INSERTION(logical_and)
61         BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_and)
62         BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_or)
63         BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_xor)
64         BOOST_PROTO_DEFINE_TAG_INSERTION(comma)
65         BOOST_PROTO_DEFINE_TAG_INSERTION(mem_ptr)
66         BOOST_PROTO_DEFINE_TAG_INSERTION(assign)
67         BOOST_PROTO_DEFINE_TAG_INSERTION(shift_left_assign)
68         BOOST_PROTO_DEFINE_TAG_INSERTION(shift_right_assign)
69         BOOST_PROTO_DEFINE_TAG_INSERTION(multiplies_assign)
70         BOOST_PROTO_DEFINE_TAG_INSERTION(divides_assign)
71         BOOST_PROTO_DEFINE_TAG_INSERTION(modulus_assign)
72         BOOST_PROTO_DEFINE_TAG_INSERTION(plus_assign)
73         BOOST_PROTO_DEFINE_TAG_INSERTION(minus_assign)
74         BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_and_assign)
75         BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_or_assign)
76         BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_xor_assign)
77         BOOST_PROTO_DEFINE_TAG_INSERTION(subscript)
78         BOOST_PROTO_DEFINE_TAG_INSERTION(member)
79         BOOST_PROTO_DEFINE_TAG_INSERTION(if_else_)
80         BOOST_PROTO_DEFINE_TAG_INSERTION(function)
81 
82     #undef BOOST_PROTO_DEFINE_TAG_INSERTION
83     }}
84 
85     namespace hidden_detail_
86     {
87         struct ostream_wrapper
88         {
ostream_wrapperboost::proto::hidden_detail_::ostream_wrapper89             ostream_wrapper(std::ostream &sout)
90               : sout_(sout)
91             {}
92 
93             std::ostream &sout_;
94 
95             BOOST_DELETED_FUNCTION(ostream_wrapper &operator =(ostream_wrapper const &))
96         };
97 
98         struct named_any
99         {
100             template<typename T>
named_anyboost::proto::hidden_detail_::named_any101             named_any(T const &)
102               : name_(BOOST_CORE_TYPEID(T).name())
103             {}
104 
105             char const *name_;
106         };
107 
operator <<(ostream_wrapper sout_wrap,named_any t)108         inline std::ostream &operator <<(ostream_wrapper sout_wrap, named_any t)
109         {
110             return sout_wrap.sout_ << t.name_;
111         }
112     }
113 
114     namespace detail
115     {
116         // copyable functor to pass by value to fusion::foreach
117         struct display_expr_impl;
118         struct display_expr_impl_functor
119         {
display_expr_impl_functorboost::proto::detail::display_expr_impl_functor120             display_expr_impl_functor(display_expr_impl const& impl): impl_(impl)
121             {}
122 
123             template<typename Expr>
operator ()boost::proto::detail::display_expr_impl_functor124             void operator()(Expr const &expr) const
125             {
126                 this->impl_(expr);
127             }
128 
129         private:
130             display_expr_impl const& impl_;
131         };
132 
133         struct display_expr_impl
134         {
display_expr_implboost::proto::detail::display_expr_impl135             explicit display_expr_impl(std::ostream &sout, int depth = 0)
136               : depth_(depth)
137               , first_(true)
138               , sout_(sout)
139             {}
140 
141             template<typename Expr>
operator ()boost::proto::detail::display_expr_impl142             void operator()(Expr const &expr) const
143             {
144                 this->impl(expr, mpl::long_<arity_of<Expr>::value>());
145             }
146 
147             BOOST_DELETED_FUNCTION(display_expr_impl(display_expr_impl const &))
148             BOOST_DELETED_FUNCTION(display_expr_impl &operator =(display_expr_impl const &))
149         private:
150 
151             template<typename Expr>
implboost::proto::detail::display_expr_impl152             void impl(Expr const &expr, mpl::long_<0>) const
153             {
154                 using namespace hidden_detail_;
155                 typedef typename tag_of<Expr>::type tag;
156                 this->sout_.width(this->depth_);
157                 this->sout_ << (this->first_? "" : ", ");
158                 this->sout_ << tag() << "(" << proto::value(expr) << ")\n";
159                 this->first_ = false;
160             }
161 
162             template<typename Expr, typename Arity>
implboost::proto::detail::display_expr_impl163             void impl(Expr const &expr, Arity) const
164             {
165                 using namespace hidden_detail_;
166                 typedef typename tag_of<Expr>::type tag;
167                 this->sout_.width(this->depth_);
168                 this->sout_ << (this->first_? "" : ", ");
169                 this->sout_ << tag() << "(\n";
170                 display_expr_impl display(this->sout_, this->depth_ + 4);
171                 fusion::for_each(expr, display_expr_impl_functor(display));
172                 this->sout_.width(this->depth_);
173                 this->sout_ << "" << ")\n";
174                 this->first_ = false;
175             }
176 
177             int depth_;
178             mutable bool first_;
179             std::ostream &sout_;
180         };
181     }
182 
183     namespace functional
184     {
185         /// \brief Pretty-print a Proto expression tree.
186         ///
187         /// A PolymorphicFunctionObject which accepts a Proto expression
188         /// tree and pretty-prints it to an \c ostream for debugging
189         /// purposes.
190         struct display_expr
191         {
192             BOOST_PROTO_CALLABLE()
193 
194             typedef void result_type;
195 
196             /// \param sout  The \c ostream to which the expression tree
197             ///              will be written.
198             /// \param depth The starting indentation depth for this node.
199             ///              Children nodes will be displayed at a starting
200             ///              depth of <tt>depth+4</tt>.
display_exprboost::proto::functional::display_expr201             explicit display_expr(std::ostream &sout = std::cout, int depth = 0)
202               : depth_(depth)
203               , sout_(sout)
204             {}
205 
206             /// \brief Pretty-print the current node in a Proto expression
207             /// tree.
208             template<typename Expr>
operator ()boost::proto::functional::display_expr209             void operator()(Expr const &expr) const
210             {
211                 detail::display_expr_impl(this->sout_, this->depth_)(expr);
212             }
213 
214         private:
215             int depth_;
216             reference_wrapper<std::ostream> sout_;
217         };
218     }
219 
220     /// \brief Pretty-print a Proto expression tree.
221     ///
222     /// \note Equivalent to <tt>functional::display_expr(0, sout)(expr)</tt>
223     /// \param expr The Proto expression tree to pretty-print
224     /// \param sout The \c ostream to which the output should be
225     ///             written. If not specified, defaults to
226     ///             <tt>std::cout</tt>.
227     template<typename Expr>
display_expr(Expr const & expr,std::ostream & sout)228     void display_expr(Expr const &expr, std::ostream &sout)
229     {
230         functional::display_expr(sout, 0)(expr);
231     }
232 
233     /// \overload
234     ///
235     template<typename Expr>
display_expr(Expr const & expr)236     void display_expr(Expr const &expr)
237     {
238         functional::display_expr()(expr);
239     }
240 
241     /// \brief Assert at compile time that a particular expression
242     ///        matches the specified grammar.
243     ///
244     /// \note Equivalent to <tt>BOOST_MPL_ASSERT((proto::matches\<Expr, Grammar\>))</tt>
245     /// \param expr The Proto expression to check againts <tt>Grammar</tt>
246     template<typename Grammar, typename Expr>
assert_matches(Expr const &)247     void assert_matches(Expr const & /*expr*/)
248     {
249         BOOST_MPL_ASSERT((proto::matches<Expr, Grammar>));
250     }
251 
252     /// \brief Assert at compile time that a particular expression
253     ///        does not match the specified grammar.
254     ///
255     /// \note Equivalent to <tt>BOOST_MPL_ASSERT_NOT((proto::matches\<Expr, Grammar\>))</tt>
256     /// \param expr The Proto expression to check againts <tt>Grammar</tt>
257     template<typename Grammar, typename Expr>
assert_matches_not(Expr const &)258     void assert_matches_not(Expr const & /*expr*/)
259     {
260         BOOST_MPL_ASSERT_NOT((proto::matches<Expr, Grammar>));
261     }
262 
263     /// \brief Assert at compile time that a particular expression
264     ///        matches the specified grammar.
265     ///
266     /// \note Equivalent to <tt>proto::assert_matches\<Grammar\>(Expr)</tt>
267     /// \param Expr The Proto expression to check againts <tt>Grammar</tt>
268     /// \param Grammar The grammar used to validate Expr.
269     #define BOOST_PROTO_ASSERT_MATCHES(Expr, Grammar)                                               \
270         (true ? (void)0 : boost::proto::assert_matches<Grammar>(Expr))
271 
272     /// \brief Assert at compile time that a particular expression
273     ///        does not match the specified grammar.
274     ///
275     /// \note Equivalent to <tt>proto::assert_matches_not\<Grammar\>(Expr)</tt>
276     /// \param Expr The Proto expression to check againts <tt>Grammar</tt>
277     /// \param Grammar The grammar used to validate Expr.
278     #define BOOST_PROTO_ASSERT_MATCHES_NOT(Expr, Grammar)                                           \
279         (true ? (void)0 : boost::proto::assert_matches_not<Grammar>(Expr))
280 
281 }}
282 
283 #endif
284