1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // pack_expansion.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 <boost/proto/proto.hpp> |
9 | #include <boost/test/unit_test.hpp> |
10 | #include <boost/typeof/typeof.hpp> |
11 | |
12 | namespace mpl = boost::mpl; |
13 | namespace proto = boost::proto; |
14 | using proto::_; |
15 | |
16 | template<typename T> T declval(); |
17 | |
18 | struct eval_ : proto::callable |
19 | { |
20 | template<typename Sig> |
21 | struct result; |
22 | |
23 | #define UNARY_OP(TAG, OP) \ |
24 | template<typename This, typename Arg> \ |
25 | struct result<This(proto::tag::TAG, Arg)> \ |
26 | { \ |
27 | BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (OP declval<Arg>())) \ |
28 | typedef typename nested::type type; \ |
29 | }; \ |
30 | \ |
31 | template<typename Arg> \ |
32 | typename result<eval_(proto::tag::TAG, Arg)>::type \ |
33 | operator()(proto::tag::TAG, Arg arg) const \ |
34 | { \ |
35 | return OP arg; \ |
36 | } \ |
37 | /**/ |
38 | |
39 | #define BINARY_OP(TAG, OP) \ |
40 | template<typename This, typename Left, typename Right> \ |
41 | struct result<This(proto::tag::TAG, Left, Right)> \ |
42 | { \ |
43 | BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (declval<Left>() OP declval<Right>())) \ |
44 | typedef typename nested::type type; \ |
45 | }; \ |
46 | \ |
47 | template<typename Left, typename Right> \ |
48 | typename result<eval_(proto::tag::TAG, Left, Right)>::type \ |
49 | operator()(proto::tag::TAG, Left left, Right right) const \ |
50 | { \ |
51 | return left OP right; \ |
52 | } \ |
53 | /**/ |
54 | |
55 | UNARY_OP(negate, -) |
56 | BINARY_OP(plus, +) |
57 | BINARY_OP(minus, -) |
58 | BINARY_OP(multiplies, *) |
59 | BINARY_OP(divides, /) |
60 | /*... others ...*/ |
61 | }; |
62 | |
63 | struct eval1 |
64 | : proto::or_< |
65 | proto::when<proto::terminal<_>, proto::_value> |
66 | , proto::otherwise<eval_(proto::tag_of<_>(), eval1(proto::pack(_))...)> |
67 | > |
68 | {}; |
69 | |
70 | struct eval2 |
71 | : proto::or_< |
72 | proto::when<proto::terminal<_>, proto::_value> |
73 | , proto::otherwise<proto::call<eval_(proto::tag_of<_>(), eval2(proto::pack(_))...)> > |
74 | > |
75 | {}; |
76 | |
77 | void test_call_pack() |
78 | { |
79 | proto::terminal<int>::type i = {.child0: 42}; |
80 | int res = eval1()(i); |
81 | BOOST_CHECK_EQUAL(res, 42); |
82 | res = eval1()(i + 2); |
83 | BOOST_CHECK_EQUAL(res, 44); |
84 | res = eval1()(i * 2); |
85 | BOOST_CHECK_EQUAL(res, 84); |
86 | res = eval1()(i * 2 + 4); |
87 | BOOST_CHECK_EQUAL(res, 88); |
88 | |
89 | res = eval2()(i + 2); |
90 | BOOST_CHECK_EQUAL(res, 44); |
91 | res = eval2()(i * 2); |
92 | BOOST_CHECK_EQUAL(res, 84); |
93 | res = eval2()(i * 2 + 4); |
94 | BOOST_CHECK_EQUAL(res, 88); |
95 | } |
96 | |
97 | struct make_pair |
98 | : proto::when< |
99 | proto::binary_expr<_, proto::terminal<int>, proto::terminal<int> > |
100 | , std::pair<int, int>(proto::_value(proto::pack(_))...) |
101 | > |
102 | {}; |
103 | |
104 | void test_make_pack() |
105 | { |
106 | proto::terminal<int>::type i = {.child0: 42}; |
107 | std::pair<int, int> p = make_pair()(i + 43); |
108 | BOOST_CHECK_EQUAL(p.first, 42); |
109 | BOOST_CHECK_EQUAL(p.second, 43); |
110 | } |
111 | |
112 | using namespace boost::unit_test; |
113 | /////////////////////////////////////////////////////////////////////////////// |
114 | // init_unit_test_suite |
115 | // |
116 | test_suite* init_unit_test_suite( int argc, char* argv[] ) |
117 | { |
118 | test_suite *test = BOOST_TEST_SUITE("test immediate evaluation of proto parse trees" ); |
119 | |
120 | test->add(BOOST_TEST_CASE(&test_call_pack)); |
121 | test->add(BOOST_TEST_CASE(&test_make_pack)); |
122 | |
123 | return test; |
124 | } |
125 | |