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