/////////////////////////////////////////////////////////////////////////////// /// \file debug.hpp /// Utilities for debugging Proto expression trees // // Copyright 2008 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PROTO_DEBUG_HPP_EAN_12_31_2006 #define BOOST_PROTO_DEBUG_HPP_EAN_12_31_2006 #include <iostream> #include <boost/preprocessor/stringize.hpp> #include <boost/ref.hpp> #include <boost/mpl/assert.hpp> #include <boost/proto/proto_fwd.hpp> #include <boost/proto/traits.hpp> #include <boost/proto/matches.hpp> #include <boost/proto/fusion.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <boost/detail/sp_typeinfo.hpp> namespace boost { namespace proto { namespace tagns_ { namespace tag { #define BOOST_PROTO_DEFINE_TAG_INSERTION(Tag) \ /** \brief INTERNAL ONLY */ \ inline std::ostream &operator <<(std::ostream &sout, Tag const &) \ { \ return sout << BOOST_PP_STRINGIZE(Tag); \ } \ /**/ BOOST_PROTO_DEFINE_TAG_INSERTION(terminal) BOOST_PROTO_DEFINE_TAG_INSERTION(unary_plus) BOOST_PROTO_DEFINE_TAG_INSERTION(negate) BOOST_PROTO_DEFINE_TAG_INSERTION(dereference) BOOST_PROTO_DEFINE_TAG_INSERTION(complement) BOOST_PROTO_DEFINE_TAG_INSERTION(address_of) BOOST_PROTO_DEFINE_TAG_INSERTION(logical_not) BOOST_PROTO_DEFINE_TAG_INSERTION(pre_inc) BOOST_PROTO_DEFINE_TAG_INSERTION(pre_dec) BOOST_PROTO_DEFINE_TAG_INSERTION(post_inc) BOOST_PROTO_DEFINE_TAG_INSERTION(post_dec) BOOST_PROTO_DEFINE_TAG_INSERTION(shift_left) BOOST_PROTO_DEFINE_TAG_INSERTION(shift_right) BOOST_PROTO_DEFINE_TAG_INSERTION(multiplies) BOOST_PROTO_DEFINE_TAG_INSERTION(divides) BOOST_PROTO_DEFINE_TAG_INSERTION(modulus) BOOST_PROTO_DEFINE_TAG_INSERTION(plus) BOOST_PROTO_DEFINE_TAG_INSERTION(minus) BOOST_PROTO_DEFINE_TAG_INSERTION(less) BOOST_PROTO_DEFINE_TAG_INSERTION(greater) BOOST_PROTO_DEFINE_TAG_INSERTION(less_equal) BOOST_PROTO_DEFINE_TAG_INSERTION(greater_equal) BOOST_PROTO_DEFINE_TAG_INSERTION(equal_to) BOOST_PROTO_DEFINE_TAG_INSERTION(not_equal_to) BOOST_PROTO_DEFINE_TAG_INSERTION(logical_or) BOOST_PROTO_DEFINE_TAG_INSERTION(logical_and) BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_and) BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_or) BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_xor) BOOST_PROTO_DEFINE_TAG_INSERTION(comma) BOOST_PROTO_DEFINE_TAG_INSERTION(mem_ptr) BOOST_PROTO_DEFINE_TAG_INSERTION(assign) BOOST_PROTO_DEFINE_TAG_INSERTION(shift_left_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(shift_right_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(multiplies_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(divides_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(modulus_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(plus_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(minus_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_and_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_or_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(bitwise_xor_assign) BOOST_PROTO_DEFINE_TAG_INSERTION(subscript) BOOST_PROTO_DEFINE_TAG_INSERTION(member) BOOST_PROTO_DEFINE_TAG_INSERTION(if_else_) BOOST_PROTO_DEFINE_TAG_INSERTION(function) #undef BOOST_PROTO_DEFINE_TAG_INSERTION }} namespace hidden_detail_ { struct ostream_wrapper { ostream_wrapper(std::ostream &sout) : sout_(sout) {} std::ostream &sout_; private: ostream_wrapper &operator =(ostream_wrapper const &); }; struct named_any { template<typename T> named_any(T const &) : name_(BOOST_SP_TYPEID(T).name()) {} char const *name_; }; inline std::ostream &operator <<(ostream_wrapper sout_wrap, named_any t) { return sout_wrap.sout_ << t.name_; } } namespace detail { struct display_expr_impl { explicit display_expr_impl(std::ostream &sout, int depth = 0) : depth_(depth) , first_(true) , sout_(sout) {} template<typename Expr> void operator()(Expr const &expr) const { this->impl(expr, mpl::long_<arity_of<Expr>::value>()); } private: display_expr_impl(display_expr_impl const &); display_expr_impl &operator =(display_expr_impl const &); template<typename Expr> void impl(Expr const &expr, mpl::long_<0>) const { using namespace hidden_detail_; typedef typename tag_of<Expr>::type tag; this->sout_.width(this->depth_); this->sout_ << (this->first_? "" : ", "); this->sout_ << tag() << "(" << proto::value(expr) << ")\n"; this->first_ = false; } template<typename Expr, typename Arity> void impl(Expr const &expr, Arity) const { using namespace hidden_detail_; typedef typename tag_of<Expr>::type tag; this->sout_.width(this->depth_); this->sout_ << (this->first_? "" : ", "); this->sout_ << tag() << "(\n"; display_expr_impl display(this->sout_, this->depth_ + 4); fusion::for_each(expr, display); this->sout_.width(this->depth_); this->sout_ << "" << ")\n"; this->first_ = false; } int depth_; mutable bool first_; std::ostream &sout_; }; } namespace functional { /// \brief Pretty-print a Proto expression tree. /// /// A PolymorphicFunctionObject which accepts a Proto expression /// tree and pretty-prints it to an \c ostream for debugging /// purposes. struct display_expr { BOOST_PROTO_CALLABLE() typedef void result_type; /// \param sout The \c ostream to which the expression tree /// will be written. /// \param depth The starting indentation depth for this node. /// Children nodes will be displayed at a starting /// depth of <tt>depth+4</tt>. explicit display_expr(std::ostream &sout = std::cout, int depth = 0) : depth_(depth) , sout_(sout) {} /// \brief Pretty-print the current node in a Proto expression /// tree. template<typename Expr> void operator()(Expr const &expr) const { detail::display_expr_impl(this->sout_, this->depth_)(expr); } private: int depth_; reference_wrapper<std::ostream> sout_; }; } /// \brief Pretty-print a Proto expression tree. /// /// \note Equivalent to <tt>functional::display_expr(0, sout)(expr)</tt> /// \param expr The Proto expression tree to pretty-print /// \param sout The \c ostream to which the output should be /// written. If not specified, defaults to /// <tt>std::cout</tt>. template<typename Expr> void display_expr(Expr const &expr, std::ostream &sout) { functional::display_expr(sout, 0)(expr); } /// \overload /// template<typename Expr> void display_expr(Expr const &expr) { functional::display_expr()(expr); } /// \brief Assert at compile time that a particular expression /// matches the specified grammar. /// /// \note Equivalent to <tt>BOOST_MPL_ASSERT((proto::matches\<Expr, Grammar\>))</tt> /// \param expr The Proto expression to check againts <tt>Grammar</tt> template<typename Grammar, typename Expr> void assert_matches(Expr const & /*expr*/) { BOOST_MPL_ASSERT((proto::matches<Expr, Grammar>)); } /// \brief Assert at compile time that a particular expression /// does not match the specified grammar. /// /// \note Equivalent to <tt>BOOST_MPL_ASSERT_NOT((proto::matches\<Expr, Grammar\>))</tt> /// \param expr The Proto expression to check againts <tt>Grammar</tt> template<typename Grammar, typename Expr> void assert_matches_not(Expr const & /*expr*/) { BOOST_MPL_ASSERT_NOT((proto::matches<Expr, Grammar>)); } /// \brief Assert at compile time that a particular expression /// matches the specified grammar. /// /// \note Equivalent to <tt>proto::assert_matches\<Grammar\>(Expr)</tt> /// \param Expr The Proto expression to check againts <tt>Grammar</tt> /// \param Grammar The grammar used to validate Expr. #define BOOST_PROTO_ASSERT_MATCHES(Expr, Grammar) \ (true ? (void)0 : boost::proto::assert_matches<Grammar>(Expr)) /// \brief Assert at compile time that a particular expression /// does not match the specified grammar. /// /// \note Equivalent to <tt>proto::assert_matches_not\<Grammar\>(Expr)</tt> /// \param Expr The Proto expression to check againts <tt>Grammar</tt> /// \param Grammar The grammar used to validate Expr. #define BOOST_PROTO_ASSERT_MATCHES_NOT(Expr, Grammar) \ (true ? (void)0 : boost::proto::assert_matches_not<Grammar>(Expr)) }} #endif