1 ///////////////////////////////////////////////////////////////////////////////
2 // proto::make_expr.hpp
3 //
4 // Copyright 2008 Eric Niebler. Distributed under the Boost
5 // Software License, Version 1.0. (See accompanying file
6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8 #include <sstream>
9 #include <boost/proto/core.hpp>
10 #include <boost/proto/transform.hpp>
11 #include <boost/utility/addressof.hpp>
12 #include <boost/fusion/tuple.hpp>
13 #include <boost/test/unit_test.hpp>
14
15 namespace fusion = boost::fusion;
16 namespace proto = boost::proto;
17
18 template<typename E> struct ewrap;
19
20 struct mydomain
21 : proto::domain<proto::generator<ewrap> >
22 {};
23
24 template<typename E> struct ewrap
25 : proto::extends<E, ewrap<E>, mydomain>
26 {
ewrapewrap27 explicit ewrap(E const &e = E())
28 : proto::extends<E, ewrap<E>, mydomain>(e)
29 {}
30 };
31
test_make_expr()32 void test_make_expr()
33 {
34 int i = 42;
35 proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(1);
36 proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(i);
37 proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(1);
38 proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(i);
39 BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
40
41 typedef
42 ewrap<
43 proto::basic_expr<
44 proto::tag::unary_plus
45 , proto::list1<
46 ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
47 >
48 >
49 >
50 p3_type;
51 p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(i);
52 BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
53
54 typedef
55 ewrap<
56 proto::basic_expr<
57 proto::tag::plus
58 , proto::list2<
59 p3_type
60 , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
61 >
62 >
63 >
64 p4_type;
65 p4_type p4 = proto::make_expr<proto::tag::plus>(p3, 0);
66 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
67 }
68
test_make_expr_ref()69 void test_make_expr_ref()
70 {
71 int i = 42;
72 int const ci = 84;
73 proto::terminal<int const &>::type t1 = proto::make_expr<proto::tag::terminal>(boost::cref(ci));
74 proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(boost::ref(i));
75 BOOST_CHECK_EQUAL(&i, &proto::value(t2));
76 proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(boost::cref(ci));
77 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(boost::ref(i));
78 BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
79
80 typedef
81 ewrap<
82 proto::basic_expr<
83 proto::tag::unary_plus
84 , proto::list1<
85 ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
86 >
87 >
88 >
89 p3_type;
90 p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(boost::ref(i));
91 BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
92
93 typedef
94 ewrap<
95 proto::basic_expr<
96 proto::tag::plus
97 , proto::list2<
98 p3_type &
99 , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
100 >
101 >
102 >
103 p4_type;
104 p4_type p4 = proto::make_expr<proto::tag::plus>(boost::ref(p3), 0);
105 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
106 }
107
test_make_expr_functional()108 void test_make_expr_functional()
109 {
110 int i = 42;
111 proto::terminal<int>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(1);
112 proto::terminal<int>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(i);
113 proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(1);
114 proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(i);
115 BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
116
117 typedef
118 ewrap<
119 proto::basic_expr<
120 proto::tag::unary_plus
121 , proto::list1<
122 ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
123 >
124 >
125 >
126 p3_type;
127 p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(i);
128 BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
129
130 typedef
131 ewrap<
132 proto::basic_expr<
133 proto::tag::plus
134 , proto::list2<
135 p3_type
136 , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
137 >
138 >
139 >
140 p4_type;
141 p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(p3, 0);
142 }
143
test_make_expr_functional_ref()144 void test_make_expr_functional_ref()
145 {
146 int i = 42;
147 int const ci = 84;
148 proto::terminal<int const &>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(boost::cref(ci));
149 proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(i));
150 BOOST_CHECK_EQUAL(&i, &proto::value(t2));
151 proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::cref(ci));
152 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(i));
153 BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
154
155 typedef
156 ewrap<
157 proto::basic_expr<
158 proto::tag::unary_plus
159 , proto::list1<
160 ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
161 >
162 >
163 >
164 p3_type;
165 p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(boost::ref(i));
166 BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
167
168 typedef
169 ewrap<
170 proto::basic_expr<
171 proto::tag::plus
172 , proto::list2<
173 p3_type &
174 , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
175 >
176 >
177 >
178 p4_type;
179 p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(boost::ref(p3), 0);
180 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
181 }
182
test_unpack_expr()183 void test_unpack_expr()
184 {
185 int i = 42;
186 proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(1));
187 proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(boost::ref(i)));
188 proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(1));
189 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(boost::ref(i)));
190 BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
191
192 typedef
193 ewrap<
194 proto::basic_expr<
195 proto::tag::unary_plus
196 , proto::list1<
197 ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
198 >
199 >
200 >
201 p3_type;
202 p3_type p3 = proto::unpack_expr<proto::tag::unary_plus, mydomain>(fusion::make_tuple(boost::ref(i)));
203 BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
204
205 typedef
206 ewrap<
207 proto::basic_expr<
208 proto::tag::plus
209 , proto::list2<
210 p3_type &
211 , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
212 >
213 >
214 >
215 p4_type;
216 p4_type p4 = proto::unpack_expr<proto::tag::plus>(fusion::make_tuple(boost::ref(p3), 0));
217 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
218 }
219
test_unpack_expr_functional()220 void test_unpack_expr_functional()
221 {
222 int i = 42;
223 proto::terminal<int>::type t1 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(1));
224 proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(boost::ref(i)));
225 proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(1));
226 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(boost::ref(i)));
227 BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
228
229 typedef
230 ewrap<
231 proto::basic_expr<
232 proto::tag::unary_plus
233 , proto::list1<
234 ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
235 >
236 >
237 >
238 p3_type;
239 p3_type p3 = proto::functional::unpack_expr<proto::tag::unary_plus, mydomain>()(fusion::make_tuple(boost::ref(i)));
240 BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
241
242 typedef
243 ewrap<
244 proto::basic_expr<
245 proto::tag::plus
246 , proto::list2<
247 p3_type &
248 , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
249 >
250 >
251 >
252 p4_type;
253 p4_type p4 = proto::functional::unpack_expr<proto::tag::plus>()(fusion::make_tuple(boost::ref(p3), 0));
254 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
255 }
256
257 #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
258 #define _byref(x) call<proto::_byref(x)>
259 #define _byval(x) call<proto::_byval(x)>
260 #define Minus(x) proto::call<Minus(x)>
261 #endif
262
263 // Turn all terminals held by reference into ones held by value
264 struct ByVal
265 : proto::or_<
266 proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byval(proto::_value))>
267 , proto::when<proto::nary_expr<proto::_, proto::vararg<ByVal> > >
268 >
269 {};
270
271 // Turn all terminals held by value into ones held by reference (not safe in general)
272 struct ByRef
273 : proto::or_<
274 proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byref(proto::_value))>
275 , proto::when<proto::nary_expr<proto::_, proto::vararg<ByRef> > >
276 >
277 {};
278
279 // turn all proto::plus nodes to minus nodes:
280 struct Minus
281 : proto::or_<
282 proto::when<proto::terminal<proto::_> >
283 , proto::when<proto::plus<Minus, Minus>, proto::_make_minus(Minus(proto::_left), Minus(proto::_right)) >
284 >
285 {};
286
287 struct Square
288 : proto::or_<
289 // Not creating new proto::terminal nodes here,
290 // so hold the existing terminals by reference:
291 proto::when<proto::terminal<proto::_>, proto::_make_multiplies(proto::_, proto::_)>
292 , proto::when<proto::plus<Square, Square> >
293 >
294 {};
295
296 #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
297 #undef _byref
298 #undef _byval
299 #undef Minus
300 #endif
301
test_make_expr_transform()302 void test_make_expr_transform()
303 {
304 proto::plus<
305 proto::terminal<int>::type
306 , proto::terminal<int>::type
307 >::type t1 = ByVal()(proto::as_expr(1) + 1);
308
309 proto::plus<
310 proto::terminal<int const &>::type
311 , proto::terminal<int const &>::type
312 >::type t2 = ByRef()(proto::as_expr(1) + 1);
313
314 proto::minus<
315 proto::terminal<int>::type const &
316 , proto::terminal<int const &>::type const &
317 >::type t3 = Minus()(proto::as_expr(1) + 1);
318
319 proto::plus<
320 proto::multiplies<proto::terminal<int>::type const &, proto::terminal<int>::type const &>::type
321 , proto::multiplies<proto::terminal<int const &>::type const &, proto::terminal<int const &>::type const &>::type
322 >::type t4 = Square()(proto::as_expr(1) + 1);
323 }
324
325
326 struct length_impl {};
327 struct dot_impl {};
328
329 proto::terminal<length_impl>::type const length = {{}};
330 proto::terminal<dot_impl>::type const dot = {{}};
331
332 // work around msvc bugs...
333 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
334 #define _byref(a) call<proto::_byref(a)>
335 #define _byval(a) call<proto::_byval(a)>
336 #define _child1(a) call<proto::_child1(a)>
337 #define _make_terminal(a) call<proto::_make_terminal(a)>
338 #define _make_function(a,b,c) call<proto::_make_function(a,b,c)>
339 #define dot_impl() proto::make<dot_impl()>
340 #endif
341
342 // convert length(a) < length(b) to dot(a,a) < dot(b,b)
343 struct Convert
344 : proto::when<
345 proto::less<
346 proto::function<proto::terminal<length_impl>, proto::_>
347 , proto::function<proto::terminal<length_impl>, proto::_>
348 >
349 , proto::_make_less(
350 proto::_make_function(
351 proto::_make_terminal(dot_impl())
352 , proto::_child1(proto::_child0)
353 , proto::_child1(proto::_child0)
354 )
355 , proto::_make_function(
356 proto::_make_terminal(dot_impl())
357 , proto::_child1(proto::_child1)
358 , proto::_child1(proto::_child1)
359 )
360 )
361 >
362 {};
363
364 template<typename Expr>
test_make_expr_transform2_test(Expr const & expr)365 void test_make_expr_transform2_test(Expr const &expr)
366 {
367 void const *addr1 = boost::addressof(proto::child_c<1>(proto::child_c<0>(expr)));
368 void const *addr2 = boost::addressof(proto::child_c<1>(proto::child_c<0>(Convert()(expr))));
369 BOOST_CHECK_EQUAL(addr1, addr2);
370
371 BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(expr))));
372 BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(Convert()(expr)))));
373 }
374
test_make_expr_transform2()375 void test_make_expr_transform2()
376 {
377 test_make_expr_transform2_test(length(1) < length(2));
378 }
379
380 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
381 #undef _byref
382 #undef _byval
383 #undef _child1
384 #undef _make_terminal
385 #undef _make_function
386 #undef dot_impl
387 #endif
388
389 using namespace boost::unit_test;
390 ///////////////////////////////////////////////////////////////////////////////
391 // init_unit_test_suite
392 //
init_unit_test_suite(int argc,char * argv[])393 test_suite* init_unit_test_suite( int argc, char* argv[] )
394 {
395 test_suite *test = BOOST_TEST_SUITE("test proto::make_expr, proto::unpack_expr and friends");
396
397 test->add(BOOST_TEST_CASE(&test_make_expr));
398 test->add(BOOST_TEST_CASE(&test_make_expr_ref));
399 test->add(BOOST_TEST_CASE(&test_make_expr_functional));
400 test->add(BOOST_TEST_CASE(&test_make_expr_functional_ref));
401 test->add(BOOST_TEST_CASE(&test_unpack_expr));
402 test->add(BOOST_TEST_CASE(&test_unpack_expr_functional));
403 test->add(BOOST_TEST_CASE(&test_make_expr_transform));
404 test->add(BOOST_TEST_CASE(&test_make_expr_transform2));
405
406 return test;
407 }
408