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
15namespace fusion = boost::fusion;
16namespace proto = boost::proto;
17
18template<typename E> struct ewrap;
19
20struct mydomain
21 : proto::domain<proto::generator<ewrap> >
22{};
23
24template<typename E> struct ewrap
25 : proto::extends<E, ewrap<E>, mydomain>
26{
27 explicit ewrap(E const &e = E())
28 : proto::extends<E, ewrap<E>, mydomain>(e)
29 {}
30};
31
32void test_make_expr()
33{
34 int i = 42;
35 proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(a0: 1);
36 proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(a0: i);
37 proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(a0: 1);
38 proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(a0: 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>(c0: 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>(a0: p3, a1: 0);
66 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
67}
68
69void 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>(a0: boost::cref(t: ci));
74 proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(a0: boost::ref(t&: 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>(a0: boost::cref(t: ci));
77 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(a0: boost::ref(t&: 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>(c0: boost::ref(t&: 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>(a0: boost::ref(t&: p3), a1: 0);
105 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
106}
107
108void 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
144void 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(t: ci));
149 proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(t&: 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(t: ci));
152 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(t&: 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(t&: 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(t&: p3), 0);
180 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
181}
182
183void test_unpack_expr()
184{
185 int i = 42;
186 proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(sequence: fusion::make_tuple(arg: 1));
187 proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(sequence: fusion::make_tuple(arg: boost::ref(t&: i)));
188 proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(sequence: fusion::make_tuple(arg: 1));
189 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(sequence: fusion::make_tuple(arg: boost::ref(t&: 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>(sequence2: fusion::make_tuple(arg: boost::ref(t&: 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>(sequence: fusion::make_tuple(arg: boost::ref(t&: p3), arg: 0));
217 BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
218}
219
220void 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(arg: 1));
224 proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(arg: boost::ref(t&: i)));
225 proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(arg: 1));
226 proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(arg: boost::ref(t&: 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(arg: boost::ref(t&: 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(arg: boost::ref(t&: p3), arg: 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
264struct 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)
272struct 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:
280struct 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
287struct 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
302void 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(t: 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(t: 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(t: 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(t: 1) + 1);
323}
324
325
326struct length_impl {};
327struct dot_impl {};
328
329proto::terminal<length_impl>::type const length = {.child0: {}};
330proto::terminal<dot_impl>::type const dot = {.child0: {}};
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)
343struct 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
364template<typename Expr>
365void 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
375void test_make_expr_transform2()
376{
377 test_make_expr_transform2_test(expr: 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
389using namespace boost::unit_test;
390///////////////////////////////////////////////////////////////////////////////
391// init_unit_test_suite
392//
393test_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

source code of boost/libs/proto/test/make_expr.cpp