1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // matches.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 <string> |
9 | #include <iostream> |
10 | #include <boost/config.hpp> |
11 | #include <boost/detail/workaround.hpp> |
12 | #include <boost/mpl/assert.hpp> |
13 | #include <boost/mpl/placeholders.hpp> |
14 | #include <boost/type_traits/is_same.hpp> |
15 | #include <boost/proto/core.hpp> |
16 | #include <boost/proto/debug.hpp> |
17 | #include <boost/proto/transform/arg.hpp> |
18 | #include <boost/test/unit_test.hpp> |
19 | |
20 | namespace mpl = boost::mpl; |
21 | namespace proto = boost::proto; |
22 | namespace fusion = boost::fusion; |
23 | |
24 | struct int_convertible |
25 | { |
26 | int_convertible() {} |
27 | operator int() const { return 0; } |
28 | }; |
29 | |
30 | struct Input |
31 | : proto::or_< |
32 | proto::shift_right< proto::terminal< std::istream & >, proto::_ > |
33 | , proto::shift_right< Input, proto::_ > |
34 | > |
35 | {}; |
36 | |
37 | struct Output |
38 | : proto::or_< |
39 | proto::shift_left< proto::terminal< std::ostream & >, proto::_ > |
40 | , proto::shift_left< Output, proto::_ > |
41 | > |
42 | {}; |
43 | |
44 | proto::terminal< std::istream & >::type const cin_ = {.child0: std::cin}; |
45 | proto::terminal< std::ostream & >::type const cout_ = {.child0: std::cout}; |
46 | |
47 | struct Anything |
48 | : proto::or_< |
49 | proto::terminal<proto::_> |
50 | , proto::nary_expr<proto::_, proto::vararg<Anything> > |
51 | > |
52 | {}; |
53 | |
54 | void a_function() {} |
55 | |
56 | struct MyCases |
57 | { |
58 | template<typename Tag> |
59 | struct case_ |
60 | : proto::not_<proto::_> |
61 | {}; |
62 | }; |
63 | |
64 | template<> |
65 | struct MyCases::case_<proto::tag::shift_right> |
66 | : proto::_ |
67 | {}; |
68 | |
69 | template<> |
70 | struct MyCases::case_<proto::tag::plus> |
71 | : proto::_ |
72 | {}; |
73 | |
74 | enum binary_representation_enum |
75 | { |
76 | magnitude |
77 | , two_complement |
78 | }; |
79 | |
80 | typedef |
81 | mpl::integral_c<binary_representation_enum, magnitude> |
82 | magnitude_c; |
83 | |
84 | typedef |
85 | mpl::integral_c<binary_representation_enum, two_complement> |
86 | two_complement_c; |
87 | |
88 | template<typename Type, typename Representation> |
89 | struct number |
90 | {}; |
91 | |
92 | struct NumberGrammar |
93 | : proto::or_ < |
94 | proto::terminal<number<proto::_, two_complement_c> > |
95 | , proto::terminal<number<proto::_, magnitude_c> > |
96 | > |
97 | {}; |
98 | |
99 | struct my_terminal |
100 | {}; |
101 | |
102 | template<typename T> |
103 | struct a_template |
104 | {}; |
105 | |
106 | template<typename Expr> |
107 | struct my_expr; |
108 | |
109 | struct my_domain |
110 | : proto::domain<proto::pod_generator<my_expr> > |
111 | {}; |
112 | |
113 | template<typename Expr> |
114 | struct my_expr |
115 | { |
116 | BOOST_PROTO_BASIC_EXTENDS(Expr, my_expr, my_domain) |
117 | }; |
118 | |
119 | void test_matches() |
120 | { |
121 | proto::assert_matches< proto::_ >( proto::lit(t: 1) ); |
122 | proto::assert_matches< proto::_ >( proto::as_child(t: 1) ); |
123 | proto::assert_matches< proto::_ >( proto::as_expr(t: 1) ); |
124 | |
125 | proto::assert_matches< proto::terminal<int> >( proto::lit(t: 1) ); |
126 | proto::assert_matches< proto::terminal<int> >( proto::as_child(t: 1) ); |
127 | proto::assert_matches< proto::terminal<int> >( proto::as_expr(t: 1) ); |
128 | |
129 | proto::assert_matches_not< proto::terminal<int> >( proto::lit(t: 'a') ); |
130 | proto::assert_matches_not< proto::terminal<int> >( proto::as_child(t: 'a') ); |
131 | proto::assert_matches_not< proto::terminal<int> >( proto::as_expr(t: 'a') ); |
132 | |
133 | proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit(t: 'a') ); |
134 | proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child(t: 'a') ); |
135 | proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr(t: 'a') ); |
136 | |
137 | proto::assert_matches_not< proto::terminal<int> >( proto::lit(t: (int_convertible())) ); |
138 | proto::assert_matches_not< proto::terminal<int> >( proto::as_child(t: (int_convertible())) ); |
139 | proto::assert_matches_not< proto::terminal<int> >( proto::as_expr(t: (int_convertible())) ); |
140 | |
141 | proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit(t: (int_convertible())) ); |
142 | proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child(t: (int_convertible())) ); |
143 | proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr(t: (int_convertible())) ); |
144 | |
145 | proto::assert_matches< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit(t: 1) ); |
146 | proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit(t: 'a') ); |
147 | |
148 | proto::assert_matches< |
149 | proto::and_< |
150 | proto::terminal<proto::_> |
151 | , proto::if_<boost::is_same<proto::_value, int>() > |
152 | > |
153 | >( proto::lit(t: 1) ); |
154 | |
155 | proto::assert_matches_not< |
156 | proto::and_< |
157 | proto::terminal<proto::_> |
158 | , proto::if_<boost::is_same<proto::_value, int>() > |
159 | > |
160 | >( proto::lit(t: 'a') ); |
161 | |
162 | proto::assert_matches< proto::terminal<char const *> >( proto::lit(t: "hello" ) ); |
163 | proto::assert_matches< proto::terminal<char const *> >( proto::as_child(t: "hello" ) ); |
164 | proto::assert_matches< proto::terminal<char const *> >( proto::as_expr(t: "hello" ) ); |
165 | |
166 | proto::assert_matches< proto::terminal<char const[6]> >( proto::lit(t: "hello" ) ); |
167 | proto::assert_matches< proto::terminal<char const (&)[6]> >( proto::as_child(t: "hello" ) ); |
168 | proto::assert_matches< proto::terminal<char const[6]> >( proto::as_expr(t: "hello" ) ); |
169 | |
170 | proto::assert_matches< proto::terminal<char [6]> >( proto::lit(t: "hello" ) ); |
171 | proto::assert_matches< proto::terminal<char [6]> >( proto::as_child(t: "hello" ) ); |
172 | proto::assert_matches< proto::terminal<char [6]> >( proto::as_expr(t: "hello" ) ); |
173 | |
174 | proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::lit(t: "hello" ) ); |
175 | proto::assert_matches< proto::terminal<char const (&)[proto::N]> >( proto::as_child(t: "hello" ) ); |
176 | proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::as_expr(t: "hello" ) ); |
177 | |
178 | proto::assert_matches< proto::terminal<char [proto::N]> >( proto::lit(t: "hello" ) ); |
179 | proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_child(t: "hello" ) ); |
180 | proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_expr(t: "hello" ) ); |
181 | |
182 | proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::lit(t: L"hello" ) ); |
183 | proto::assert_matches< proto::terminal<wchar_t const (&)[proto::N]> >( proto::as_child(t: L"hello" ) ); |
184 | proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::as_expr(t: L"hello" ) ); |
185 | |
186 | proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::lit(t: L"hello" ) ); |
187 | proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_child(t: L"hello" ) ); |
188 | proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_expr(t: L"hello" ) ); |
189 | |
190 | proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>()> >( proto::lit(t: "hello" ) ); |
191 | |
192 | proto::assert_matches< proto::terminal<std::string> >( proto::lit(t: std::string("hello" )) ); |
193 | proto::assert_matches< proto::terminal<std::string> >( proto::as_child(t: std::string("hello" )) ); |
194 | proto::assert_matches< proto::terminal<std::string> >( proto::as_expr(t: std::string("hello" )) ); |
195 | |
196 | proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::lit(t: std::string("hello" )) ); |
197 | proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(t: std::string("hello" )) ); |
198 | proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(t: std::string("hello" )) ); |
199 | |
200 | proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::lit(t: 1) ); |
201 | proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(t: 1) ); |
202 | proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(t: 1) ); |
203 | |
204 | proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::lit(t: 1) ); |
205 | proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::as_child(t: 1) ); |
206 | proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::as_expr(t: 1) ); |
207 | |
208 | #if BOOST_WORKAROUND(__HP_aCC, BOOST_TESTED_AT(61700)) |
209 | typedef std::string const const_string; |
210 | #else |
211 | typedef std::string const_string; |
212 | #endif |
213 | |
214 | proto::assert_matches< proto::terminal<std::basic_string<proto::_> const & > >( proto::lit(t: const_string("hello" )) ); |
215 | proto::assert_matches< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_child(t: const_string("hello" )) ); |
216 | proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_expr(t: const_string("hello" )) ); |
217 | |
218 | proto::assert_matches< proto::terminal< void(&)() > >( proto::lit(t&: a_function) ); |
219 | proto::assert_matches< proto::terminal< void(&)() > >( proto::as_child(t&: a_function) ); |
220 | proto::assert_matches< proto::terminal< void(&)() > >( proto::as_expr(t&: a_function) ); |
221 | |
222 | proto::assert_matches_not< proto::terminal< void(*)() > >( proto::lit(t&: a_function) ); |
223 | proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_child(t&: a_function) ); |
224 | proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_expr(t&: a_function) ); |
225 | |
226 | proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::lit(t&: a_function) ); |
227 | proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_child(t&: a_function) ); |
228 | proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_expr(t&: a_function) ); |
229 | |
230 | proto::assert_matches< proto::terminal< void(*)() > >( proto::lit(t: &a_function) ); |
231 | proto::assert_matches< proto::terminal< void(*)() > >( proto::as_child(t: &a_function) ); |
232 | proto::assert_matches< proto::terminal< void(*)() > >( proto::as_expr(t: &a_function) ); |
233 | |
234 | proto::assert_matches< proto::terminal< void(* const &)() > >( proto::lit(t: &a_function) ); |
235 | proto::assert_matches< proto::terminal< void(* const &)() > >( proto::as_child(t: &a_function) ); |
236 | proto::assert_matches_not< proto::terminal< void(* const &)() > >( proto::as_expr(t: &a_function) ); |
237 | |
238 | proto::assert_matches< |
239 | proto::or_< |
240 | proto::if_<boost::is_same<proto::_value, char>() > |
241 | , proto::if_<boost::is_same<proto::_value, int>() > |
242 | > |
243 | >( proto::lit(t: 1) ); |
244 | |
245 | proto::assert_matches_not< |
246 | proto::or_< |
247 | proto::if_<boost::is_same<proto::_value, char>() > |
248 | , proto::if_<boost::is_same<proto::_value, int>() > |
249 | > |
250 | >( proto::lit(t: 1u) ); |
251 | |
252 | proto::assert_matches< Input >( cin_ >> 1 >> 2 >> 3 ); |
253 | proto::assert_matches_not< Output >( cin_ >> 1 >> 2 >> 3 ); |
254 | |
255 | proto::assert_matches< Output >( cout_ << 1 << 2 << 3 ); |
256 | proto::assert_matches_not< Input >( cout_ << 1 << 2 << 3 ); |
257 | |
258 | proto::assert_matches< proto::function< proto::terminal<int>, proto::vararg< proto::terminal<char> > > >( proto::lit(t: 1)('a','b','c','d') ); |
259 | proto::assert_matches_not< proto::function< proto::terminal<int>, proto::vararg< proto::terminal<char> > > >( proto::lit(t: 1)('a','b','c',"d" ) ); |
260 | |
261 | proto::assert_matches< Anything >( cout_ << 1 << +proto::lit(t: 'a') << proto::lit(t: 1)('a','b','c',"d" ) ); |
262 | |
263 | proto::assert_matches< proto::switch_<MyCases> >( proto::lit(t: 1) >> 'a' ); |
264 | proto::assert_matches< proto::switch_<MyCases> >( proto::lit(t: 1) + 'a' ); |
265 | proto::assert_matches_not< proto::switch_<MyCases> >( proto::lit(t: 1) << 'a' ); |
266 | |
267 | number<int, two_complement_c> num; |
268 | proto::assert_matches<NumberGrammar>(proto::as_expr(t&: num)); |
269 | |
270 | // check custom terminal types |
271 | { |
272 | proto::nullary_expr<my_terminal, int>::type i = {.child0: 0}; |
273 | |
274 | proto::assert_matches<proto::nullary_expr<my_terminal, proto::_> >( i ); |
275 | proto::assert_matches_not<proto::terminal<proto::_> >( i ); |
276 | |
277 | proto::terminal<int>::type j = {.child0: 0}; |
278 | proto::assert_matches<proto::terminal<proto::_> >( j ); |
279 | proto::assert_matches_not<proto::nullary_expr<my_terminal, proto::_> >( j ); |
280 | |
281 | proto::assert_matches<proto::nullary_expr<proto::_, proto::_> >( i ); |
282 | } |
283 | |
284 | // check 0 and 1 arg forms or or_ and and_ |
285 | { |
286 | proto::assert_matches< proto::and_<> >( proto::lit(t: 1) ); |
287 | proto::assert_matches_not< proto::or_<> >( proto::lit(t: 1) ); |
288 | |
289 | proto::assert_matches< proto::and_<proto::terminal<int> > >( proto::lit(t: 1) ); |
290 | proto::assert_matches< proto::or_<proto::terminal<int> > >( proto::lit(t: 1) ); |
291 | } |
292 | |
293 | // Test lambda matches with arrays, a corner case that had |
294 | // a bug that was reported by Antoine de Maricourt on boost@lists.boost.org |
295 | { |
296 | a_template<int[3]> a; |
297 | proto::assert_matches< proto::terminal< a_template<proto::_> > >( proto::lit(t&: a) ); |
298 | } |
299 | |
300 | // Test that the actual derived expression type makes it through to proto::if_ |
301 | { |
302 | my_expr<proto::terminal<int>::type> e = {.proto_expr_: {.child0: 1}}; |
303 | proto::assert_matches< proto::if_<boost::is_same<proto::domain_of<proto::_>, my_domain>()> >( e ); |
304 | } |
305 | } |
306 | |
307 | using namespace boost::unit_test; |
308 | /////////////////////////////////////////////////////////////////////////////// |
309 | // init_unit_test_suite |
310 | // |
311 | test_suite* init_unit_test_suite( int argc, char* argv[] ) |
312 | { |
313 | test_suite *test = BOOST_TEST_SUITE("test proto::matches<>" ); |
314 | |
315 | test->add(BOOST_TEST_CASE(&test_matches)); |
316 | |
317 | return test; |
318 | } |
319 | |
320 | |