#include #include #include #include #define BOOST_PHOENIX_LIMIT 10 #define BOOST_PHOENIX_ARG_LIMIT BOOST_PHOENIX_LIMIT namespace boost { namespace phoenix { //////////////////////////////////////////////////////////////////////////////////////////// struct evaluator; //////////////////////////////////////////////////////////////////////////////////////////// template struct actor; //////////////////////////////////////////////////////////////////////////////////////////// struct make_actor : proto::call(proto::_)> {}; //////////////////////////////////////////////////////////////////////////////////////////// struct generator_cases { template struct case_ : proto::when {}; }; namespace detail { //////////////////////////////////////////////////////////////////////////////////////////// struct generator : proto::switch_ {}; //////////////////////////////////////////////////////////////////////////////////////////// struct domain : proto::domain {}; //////////////////////////////////////////////////////////////////////////////////////// template struct argument { typedef typename Int::tag tag; typedef typename Int::value_type value_type; typedef argument type; typedef argument next; typedef argument prior; static value_type const value = Int::value; friend std::ostream &operator<<(std::ostream &sout, argument) { return sout << "boost::phoenix::arg_names::arg" << (Int::value+1); } }; template typename Int::value_type const argument::value; //////////////////////////////////////////////////////////////////////////////////////// struct at : proto::callable { template struct result; template struct result : fusion::result_of::at {}; template typename fusion::result_of::at::type operator ()(Cont &cont, Arg &) const { return fusion::at(cont); } }; //////////////////////////////////////////////////////////////////////////////////////// template struct result; template struct result : result_of {}; #define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A, A_const_ref_a, ref_a) \ template \ struct result \ : result_of &)> \ {}; \ /**/ #define BOOST_PROTO_LOCAL_A BOOST_PROTO_A #define BOOST_PROTO_LOCAL_LIMITS (1, BOOST_PHOENIX_ARG_LIMIT) #include BOOST_PROTO_LOCAL_ITERATE() } //////////////////////////////////////////////////////////////////////////////////////////// struct evaluator_cases { template struct case_ : proto::when > {}; }; template<> struct evaluator_cases::case_ : proto::or_< proto::when< proto::terminal > , detail::at(proto::_data, proto::_value) > , proto::otherwise > > {}; //////////////////////////////////////////////////////////////////////////////////////////// struct evaluator : proto::switch_ {}; #define BOOST_PHOENIX_INVOKE(N, typename_A, A_const_ref, A_const_ref_a, a) \ template \ typename detail::result::type \ operator()(A_const_ref_a(N)) const \ { \ BOOST_PP_CAT(fusion::vector, N) args(a(N)); \ return evaluator()(*this, 0, args); \ } \ /**/ //////////////////////////////////////////////////////////////////////////////////////////// template struct actor { BOOST_PROTO_BASIC_EXTENDS(Expr, actor, detail::domain) template struct result : detail::result {}; // TODO: handle nullary lambdas #define BOOST_PROTO_LOCAL_MACRO BOOST_PHOENIX_INVOKE #define BOOST_PROTO_LOCAL_a BOOST_PROTO_a #define BOOST_PROTO_LOCAL_LIMITS (1, BOOST_PHOENIX_ARG_LIMIT) #include BOOST_PROTO_LOCAL_ITERATE() }; //////////////////////////////////////////////////////////////////////////////////////////// template struct argument { typedef typename proto::terminal > >::type base_type; BOOST_PROTO_BASIC_EXTENDS(base_type, argument, detail::domain) // For backwards compatibility operator actor > const &() const { return argument::argI; } static actor > const argI; }; template actor > const argument::argI = {{{{}}}}; //////////////////////////////////////////////////////////////////////////////////////////// namespace arg_names { // Phoenix style names actor > const arg1 = {{{{}}}}; actor > const arg2 = {{{{}}}}; actor > const arg3 = {{{{}}}}; // BLL style names actor > const _1 = {{{{}}}}; actor > const _2 = {{{{}}}}; actor > const _3 = {{{{}}}}; // Bring in the rest or the Phoenix style arguments (arg4 .. argN+1) // and BLL style arguments (_4 .. _N+1), using PP #define BOOST_PHOENIX_DECLARE_ARG(Z, N, DATA) \ actor > const BOOST_PP_CAT(arg, BOOST_PP_INC(N)) = {{{{}}}}; \ actor > const BOOST_PP_CAT(_, BOOST_PP_INC(N)) = {{{{}}}}; \ /**/ BOOST_PP_REPEAT_FROM_TO(3, BOOST_PHOENIX_ARG_LIMIT, BOOST_PHOENIX_DECLARE_ARG, _) #undef BOOST_PHOENIX_DECLARE_ARG } // // Begin implementation of if_/else_ here // namespace tag { struct if_ {}; struct else_ {}; } namespace detail { // Proto transform for evaluating lambdas like: if_(foo)[bar] struct if_evaluator : proto::transform { template struct impl : proto::transform_impl { typedef void result_type; void operator()( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d ) const { if(evaluator()(proto::child_c<0>(e), s, d)) { evaluator()(proto::child_c<1>(e), s, d); } } }; }; // Proto transform for evaluating lambdas like: if_(foo)[bar].else_[baz] struct else_evaluator : proto::transform { template struct impl : proto::transform_impl { typedef void result_type; void operator()( typename impl::expr_param e , typename impl::state_param s , typename impl::data_param d ) const { if(evaluator()(proto::child_c<0>(e), s, d)) { evaluator()(proto::child_c<1>(e), s, d); } else { evaluator()(proto::child_c<2>(e), s, d); } } }; }; } //////////////////////////////////////////////////////////////////////////////////////////// template struct actor_with_else { BOOST_PROTO_BASIC_EXTENDS(Expr, actor_with_else, detail::domain) template struct result : detail::result {}; // TODO: handle nullary lambdas #define BOOST_PROTO_LOCAL_MACRO BOOST_PHOENIX_INVOKE #define BOOST_PROTO_LOCAL_a BOOST_PROTO_a #define BOOST_PROTO_LOCAL_LIMITS (1, BOOST_PHOENIX_ARG_LIMIT) #include BOOST_PROTO_LOCAL_ITERATE() typedef typename proto::result_of::child_c::type A; typedef typename proto::result_of::child_c::type B; // if_ statements get an else_ defined thusly: struct else_type { template typename proto::result_of::make_expr::type operator[](C const &c) const { actor_with_else const & cond = *(actor_with_else const *) ((char *)this - BOOST_PROTO_OFFSETOF(actor_with_else, else_)); return proto::make_expr( boost::ref(proto::child_c<0>(cond)) , boost::ref(proto::child_c<1>(cond)) , boost::ref(c) ); } } else_; }; //////////////////////////////////////////////////////////////////////////////////////////// struct make_actor_with_else : proto::call(proto::_)> {}; //////////////////////////////////////////////////////////////////////////////////////////// struct if_type { template struct stmt { template typename proto::result_of::make_expr::type operator[](B const &b) const { return proto::make_expr(boost::ref(a), boost::ref(b)); } A const &a; }; template stmt operator()(A const &a) const { stmt ret = {a}; return ret; } } const if_ = {}; //////////////////////////////////////////////////////////////////////////////////////////// // This instructs Proto to wrap if_ expressions in actor_with_else template<> struct generator_cases::case_ : proto::when {}; //////////////////////////////////////////////////////////////////////////////////////////// // This tells Proto how to evaluate if_ statements with the if_evaluator template<> struct evaluator_cases::case_ : proto::when {}; //////////////////////////////////////////////////////////////////////////////////////////// // This tells Proto how to evaluate else_ statements with the else_evaluator template<> struct evaluator_cases::case_ : proto::when {}; } } #include #include namespace proto = boost::proto; namespace phoenix = boost::phoenix; using namespace phoenix::arg_names; int main() { proto::display_expr(_1 + _2); int j = (_1 + _2)(1, 2); std::cout << j << "\n"; j = (_2 * 2)(1, 2); std::cout << j << "\n"; char const *name = typeid(phoenix::if_(_1)[_2].else_).name(); std::cout << name << "\n"; name = typeid(phoenix::if_(_1)[_2].else_[_1]).name(); std::cout << name << "\n"; phoenix::if_(_1)[_2].else_[_3](1,2,3); phoenix::if_(_1)[_2].else_[_3](0,2,3); }