BoostPhoenix3: miniphoenix2.cpp

File miniphoenix2.cpp, 7.8 KB (added by Eric Niebler, 12 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}