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
test_call_pack()77 void test_call_pack()
78 {
79 proto::terminal<int>::type i = {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
test_make_pack()104 void test_make_pack()
105 {
106 proto::terminal<int>::type i = {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 //
init_unit_test_suite(int argc,char * argv[])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