debug.hpp 10 KB

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