#include #include namespace proto = boost::proto; namespace mpl = boost::mpl; namespace detail { struct action_not_found_ {}; template struct has_action { typedef char yes; typedef struct { char c[2]; } no; template static yes check(typename A::template when::transform_type*); template static no check(...); static const bool value = (sizeof(check(0)) == sizeof(yes)); typedef mpl::bool_ type; }; template struct select_action_; template < typename Actions , typename Grammar , template class Action , typename Rule , typename Expr> struct select_action_, Expr> { typedef typename mpl::eval_if< mpl::and_< has_action , proto::matches > , mpl::identity > , mpl::identity >::type type; }; template struct fold_actions : mpl::fold< Actions , action_not_found_ , mpl::if_< boost::is_same< mpl::_2 , action_not_found_ > , mpl::_1 , mpl::_2 > > {}; #define M0(Z, N, DATA) \ typename select_action_< \ Actions \ , typename BOOST_PP_CAT(G, N)::proto_grammar \ , typename Actions::template when< \ BOOST_PP_CAT(G, N), Actions \ >, Expr \ >::type \ /**/ #define M1(Z, N, DATA) \ template < \ typename Actions \ BOOST_PP_ENUM_TRAILING_PARAMS(N, typename G) \ , template class Action \ , typename Rule \ , typename Expr> \ struct select_action_< \ Actions \ , proto::DATA \ , Action \ , Expr> \ { \ struct hide \ : proto::DATA \ {}; \ typedef \ BOOST_PP_CAT(mpl::vector, BOOST_PP_INC(N))< \ typename select_action_< \ Actions \ , hide \ , Action \ , Expr \ >::type \ BOOST_PP_ENUM_TRAILING(N, M0, _) \ > \ actions; \ typedef typename fold_actions::type type; \ }; \ /**/ BOOST_PP_REPEAT(BOOST_PROTO_MAX_LOGICAL_ARITY, M1, or_) BOOST_PP_REPEAT(BOOST_PROTO_MAX_LOGICAL_ARITY, M1, and_) #undef M0 #undef M1 template < typename Actions , typename Cases , template class Action , typename Rule , typename Expr> struct select_action_< Actions , proto::switch_ , Action , Expr> { struct hide : proto::switch_ {}; typedef typename Cases::template case_< typename proto::tag_of::type > case_; typedef mpl::vector3< typename select_action_< Actions , hide , Action , Expr >::type , typename select_action_< Actions , typename case_::proto_grammar , typename Actions::template when , Expr >::type , typename select_action_< Actions , typename case_::proto_grammar , typename Actions::template when< typename case_::proto_grammar , Actions > , Expr >::type > actions; typedef typename fold_actions::type type; }; } template struct select_action : detail::select_action_< Actions , typename Grammar::proto_grammar , typename Actions::template when, Expr > {}; template struct _traverse : proto::transform<_traverse > { template struct impl : proto::transform_impl { typedef typename select_action::type action; template struct result_helper { typedef typename Action::template impl< Expr, State, Data >::result_type type; }; typedef typename mpl::eval_if< boost::is_same< action , detail::action_not_found_ > , mpl::identity , result_helper >::type result_type; result_type operator()( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d ) const { return invoke(e,s,d, action()); } private: template result_type invoke( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d , Action ) const { return typename Action::template impl()(e, s, d); } result_type invoke( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d , detail::action_not_found_ ) const { return e; } }; }; namespace boost { namespace proto { template struct is_callable<_traverse > : mpl::true_ {}; }} template typename _traverse< Grammar , Actions>::template impl< Expr const & , int , int >::result_type traverse(Expr const& expr) { return typename _traverse< Grammar , Actions>::template impl< Expr const & , int , int >()(expr, 0, 0); } template struct action { template struct when; }; struct int_terminal : proto::terminal {}; struct char_terminal : proto::terminal {}; struct my_grammar : proto::or_< int_terminal , char_terminal , proto::plus > {}; struct my_actions; struct print : proto::callable { typedef std::string result_type; result_type operator()(int) const { return "int"; } result_type operator()(char) const { return "char"; } template result_type operator()(T1 const& t1, T2 const& t2) const { std::string res(""); res += traverse(t1); res += " + "; res += traverse(t2); return res; } }; struct my_actions : action { template struct when : proto::call {}; template struct when : proto::call {}; template struct when, Actions> : proto::call< print( proto::_left , proto::_right ) > {}; }; int main() { proto::literal i(8), j(9); proto::literal a('a'), b('b'); std::cout << traverse(a) << "\n"; // printing char std::cout << traverse(a) << "\n"; // printing nothing, cause no char terminal in the int_terminal grammar std::cout << traverse(i) << "\n"; // printing nothing, cause no int terminal in char_terminal grammar std::cout << traverse(j) << "\n"; // printing int std::cout << traverse(j) << "\n"; // printing int std::cout << traverse(a) << "\n"; // printing char std::cout << traverse(i + i) << "\n"; // printing int + int }