BoostPhoenix3: miniphoenix2.cpp

File miniphoenix2.cpp, 7.8 KB (added by Eric Niebler, 9 years ago)

A cleaner, simpler design for the mini-phoenix example

Line 
1#include <algorithm>
2#include <boost/mpl/if.hpp>
3#include <boost/fusion/container/vector.hpp>
4#include <boost/proto/proto.hpp>
5
6namespace boost
7{
8namespace phoenix
9{
10using namespace proto;
11
12//////////////////////////////
13// phoenix expression wrapper
14template<class Expr>
15struct actor;
16
17//////////////////////////////
18struct phoenix_domain
19  : domain<pod_generator<actor> >
20{};
21
22//////////////////////////////
23// phoenix grammar and expression evaluator
24struct eval
25  : switch_<struct eval_cases>
26{};
27
28//////////////////////////////
29struct eval_cases
30{
31    template<class Tag>
32    struct case_
33      : _default<eval>
34    {};
35};
36
37//////////////////////////////
38template<class Sig>
39struct actor_result;
40
41#define BOOST_PROTO_LOCAL_MACRO(N, class_A, A, A_const_ref_a, a)\
42template<class Actor, class_A(N)>                               \
43struct actor_result<Actor(A(N))>                                \
44  : boost::result_of<eval(Actor&, fusion::vector<A(N)> &)>      \
45{};
46
47#define BOOST_PROTO_LOCAL_A BOOST_PROTO_A
48#include BOOST_PROTO_LOCAL_ITERATE()
49
50//////////////////////////////
51template<class Expr>
52struct actor
53{
54#define BOOST_PHOENIX_ACTOR(Base, Derived, Domain)                      \
55    BOOST_PROTO_BASIC_EXTENDS(Base, Derived, Domain)                    \
56    BOOST_PROTO_EXTENDS_ASSIGN()                                        \
57    BOOST_PROTO_EXTENDS_SUBSCRIPT()                                     \
58                                                                        \
59    template<class Sig>                                                 \
60    struct result : actor_result<Sig>                                   \
61    {};                                                                 \
62                                                                        \
63    typedef Derived actor_type;                                         \
64    BOOST_PROTO_REPEAT(BOOST_PHOENIX_INVOKE)                            \
65    /**/
66
67#define BOOST_PHOENIX_INVOKE(N, class_A, A_const_ref, A_const_ref_a, a) \
68    template<class_A(N)>                                                \
69    typename boost::result_of<actor_type(A_const_ref(N))>::type         \
70    operator()(A_const_ref_a(N)) const                                  \
71    {                                                                   \
72        BOOST_PROTO_ASSERT_MATCHES(*this, eval);                        \
73        fusion::vector<A_const_ref(N)> args(a(N));                      \
74        return eval()(*this, args);                                     \
75    }                                                                   \
76    /**/
77
78    BOOST_PHOENIX_ACTOR(Expr, actor<Expr>, phoenix_domain)
79};
80
81//////////////////////////////
82// Begin implementation of _1, _2, _3 argument placeholders
83//
84struct arg_tag {};
85
86//////////////////////////////
87struct at : callable
88{
89    template<class Sig>
90    struct result;
91
92    template<class This, class Cont, class N>
93    struct result<This(Cont &, N &)>
94      : fusion::result_of::at<Cont, N>
95    {};
96
97    template<class Cont, class N>
98    typename fusion::result_of::at<Cont, N>::type
99    operator ()(Cont &cont, N) const
100    {
101        return fusion::at<N>(cont);
102    }
103};
104
105//////////////////////////////
106actor<nullary_expr<arg_tag, mpl::int_<0> >::type> const _1 = {{{}}};
107actor<nullary_expr<arg_tag, mpl::int_<1> >::type> const _2 = {{{}}};
108actor<nullary_expr<arg_tag, mpl::int_<2> >::type> const _3 = {{{}}};
109
110//////////////////////////////
111template<>
112struct eval_cases::case_<arg_tag>
113  : when<nullary_expr<arg_tag, _>, at(_state, _value)>
114{};
115
116//////////////////////////////
117// Begin implementation of if_/else_ here
118//
119struct if_tag {};
120struct else_tag {};
121struct if_else_tag {};
122
123template<class Expr>
124struct if_else_actor;
125
126// if_(x)[y]
127struct if_stmt
128  : subscript<function<terminal<if_tag>, eval>, eval>
129{};
130
131// if_(x)[y].else_[z]
132struct if_else_stmt
133  : subscript<
134        member<unary_expr<if_tag, if_stmt>, terminal<else_tag> >
135      , eval
136    >
137{};
138
139typedef functional::make_expr<if_tag>       make_if;
140typedef functional::make_expr<if_else_tag>  make_if_else;
141typedef pod_generator<if_else_actor>        make_if_else_actor;
142
143//////////////////////////////
144struct if_else_generator
145  : or_<
146        // if_(this)[that]
147        when<
148            if_stmt
149            // wrap in if_else_actor and unary if_tag expr
150          , make_if_else_actor(make_if(_byval(_)))
151        >
152        // if_(this)[that].else_[other]
153      , when<
154            if_else_stmt
155            // wrap in if_else_actor and unary if_else_tag expr
156          , make_if_else_actor(make_if_else(_byval(_)))
157        >
158      , otherwise<
159            make_if_else_actor(_)
160        >
161    >
162{};
163
164//////////////////////////////
165struct if_else_domain
166  : domain<if_else_generator>
167{};
168
169//////////////////////////////
170struct complete_if_else_stmt
171  : or_<
172        unary_expr<if_tag, if_stmt>
173      , unary_expr<if_else_tag, if_else_stmt>
174    >
175{};
176
177//////////////////////////////
178template<class Expr>
179struct if_else_actor
180{
181    typedef typename
182        mpl::if_<matches<Expr, complete_if_else_stmt>, phoenix_domain, if_else_domain>::type
183    domain_;
184
185    BOOST_PHOENIX_ACTOR(Expr, if_else_actor<Expr>, domain_)
186
187    // Declare a member named else_ that is a
188    // terminal<if_else_tag> in if_else_domain.
189    BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(
190        ((else_tag,   else_))
191      , if_else_domain
192    )
193};
194
195// Function for evaluating lambdas like: if_(foo)[bar]
196struct if_eval : callable
197{
198    typedef void result_type;
199
200    template<class I, class T, class S>
201    void operator()(I const & i, T const & t, S & s) const
202    {
203        if( eval()(i, s) )
204            eval()(t, s);
205    }
206};
207
208// Function for evaluating lambdas like: if_(foo)[bar].else_[baz]
209struct if_else_eval : callable
210{
211    typedef void result_type;
212
213    template<class I, class T, class E, class S>
214    void operator()(I const & i, T const & t, E const & e, S & s) const
215    {
216        if( eval()(i, s) )
217            eval()(t, s);
218        else
219            eval()(e, s);
220    }
221};
222
223//////////////////////////////
224typedef functional::make_expr<tag::function, if_else_domain> make_fun;
225
226template<class E>
227typename boost::result_of<make_fun(if_tag, E const &)>::type const
228if_(E const & e)
229{
230    return make_fun()(if_tag(), ref(e));
231}
232
233//////////////////////////////
234// This tells Proto how to evaluate if_(x)[y] statements with if_eval
235template<>
236struct eval_cases::case_<if_tag>
237  : when<
238        unary_expr<if_tag, if_stmt>
239      , if_eval(_right(_left(_left)), _right(_left), _state)
240    >
241{};
242
243//////////////////////////////
244// This tells Proto how to evaluate if(x)[y].else_[z] statements with if_else_eval
245template<>
246struct eval_cases::case_<if_else_tag>
247  : when<
248        unary_expr<if_else_tag, if_else_stmt>
249      , if_else_eval(
250            _right(_left(_left(_left(_left(_left)))))
251          , _right(_left(_left(_left(_left))))
252          , _right(_left)
253          , _state
254        )
255    >
256{};
257
258} // namespace phoenix
259} // namespace boost
260
261#include <iostream>
262using namespace boost;
263using namespace phoenix;
264
265int main()
266{
267    int j = (_1 + _2)(1, 2);
268    std::cout << j << "\n";
269
270    j = (_2 * 2)(1, 2);
271    std::cout << j << "\n";
272
273    phoenix::if_(_1)[std::cout << _2 << "\n"] + _1;
274
275    phoenix::if_(_1)[std::cout << _2 << "\n"](1,2,3);
276    phoenix::if_(_1)[std::cout << _2 << "\n"].else_[std::cout << _3 << "\n"](1,2,3);
277    phoenix::if_(_1)[std::cout << _2 << "\n"].else_[std::cout << _3 << "\n"](0,2,3);
278
279    int x[] = { 1, 2, 3, 4 };
280    int y[] = { 2, 4, 6, 8 };
281    int z[4];
282
283    // Use a Phoenix lambda with std algorithms
284    std::transform( x, x + 4, y, z, _1 * _2 );
285}