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 {
int_convertibleint_convertible26     int_convertible() {}
operator intint_convertible27     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_ = {std::cin};
45 proto::terminal< std::ostream & >::type const cout_ = {std::cout};
46 
47 struct Anything
48   : proto::or_<
49         proto::terminal<proto::_>
50       , proto::nary_expr<proto::_, proto::vararg<Anything> >
51     >
52 {};
53 
a_function()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 
test_matches()119 void test_matches()
120 {
121     proto::assert_matches< proto::_ >( proto::lit(1) );
122     proto::assert_matches< proto::_ >( proto::as_child(1) );
123     proto::assert_matches< proto::_ >( proto::as_expr(1) );
124 
125     proto::assert_matches< proto::terminal<int> >( proto::lit(1) );
126     proto::assert_matches< proto::terminal<int> >( proto::as_child(1) );
127     proto::assert_matches< proto::terminal<int> >( proto::as_expr(1) );
128 
129     proto::assert_matches_not< proto::terminal<int> >( proto::lit('a') );
130     proto::assert_matches_not< proto::terminal<int> >( proto::as_child('a') );
131     proto::assert_matches_not< proto::terminal<int> >( proto::as_expr('a') );
132 
133     proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit('a') );
134     proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child('a') );
135     proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr('a') );
136 
137     proto::assert_matches_not< proto::terminal<int> >( proto::lit((int_convertible())) );
138     proto::assert_matches_not< proto::terminal<int> >( proto::as_child((int_convertible())) );
139     proto::assert_matches_not< proto::terminal<int> >( proto::as_expr((int_convertible())) );
140 
141     proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit((int_convertible())) );
142     proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child((int_convertible())) );
143     proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr((int_convertible())) );
144 
145     proto::assert_matches< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit(1) );
146     proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit('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(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('a') );
161 
162     proto::assert_matches< proto::terminal<char const *> >( proto::lit("hello") );
163     proto::assert_matches< proto::terminal<char const *> >( proto::as_child("hello") );
164     proto::assert_matches< proto::terminal<char const *> >( proto::as_expr("hello") );
165 
166     proto::assert_matches< proto::terminal<char const[6]> >( proto::lit("hello") );
167     proto::assert_matches< proto::terminal<char const (&)[6]> >( proto::as_child("hello") );
168     proto::assert_matches< proto::terminal<char const[6]> >( proto::as_expr("hello") );
169 
170     proto::assert_matches< proto::terminal<char [6]> >( proto::lit("hello") );
171     proto::assert_matches< proto::terminal<char [6]> >( proto::as_child("hello") );
172     proto::assert_matches< proto::terminal<char [6]> >( proto::as_expr("hello") );
173 
174     proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::lit("hello") );
175     proto::assert_matches< proto::terminal<char const (&)[proto::N]> >( proto::as_child("hello") );
176     proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::as_expr("hello") );
177 
178     proto::assert_matches< proto::terminal<char [proto::N]> >( proto::lit("hello") );
179     proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_child("hello") );
180     proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_expr("hello") );
181 
182     proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::lit(L"hello") );
183     proto::assert_matches< proto::terminal<wchar_t const (&)[proto::N]> >( proto::as_child(L"hello") );
184     proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::as_expr(L"hello") );
185 
186     proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::lit(L"hello") );
187     proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_child(L"hello") );
188     proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_expr(L"hello") );
189 
190     proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>()> >( proto::lit("hello") );
191 
192     proto::assert_matches< proto::terminal<std::string> >( proto::lit(std::string("hello")) );
193     proto::assert_matches< proto::terminal<std::string> >( proto::as_child(std::string("hello")) );
194     proto::assert_matches< proto::terminal<std::string> >( proto::as_expr(std::string("hello")) );
195 
196     proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::lit(std::string("hello")) );
197     proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(std::string("hello")) );
198     proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(std::string("hello")) );
199 
200     proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::lit(1) );
201     proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(1) );
202     proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(1) );
203 
204     proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::lit(1) );
205     proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::as_child(1) );
206     proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::as_expr(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(const_string("hello")) );
215     proto::assert_matches< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_child(const_string("hello")) );
216     proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_expr(const_string("hello")) );
217 
218     proto::assert_matches< proto::terminal< void(&)() > >( proto::lit(a_function) );
219     proto::assert_matches< proto::terminal< void(&)() > >( proto::as_child(a_function) );
220     proto::assert_matches< proto::terminal< void(&)() > >( proto::as_expr(a_function) );
221 
222     proto::assert_matches_not< proto::terminal< void(*)() > >( proto::lit(a_function) );
223     proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_child(a_function) );
224     proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_expr(a_function) );
225 
226     proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::lit(a_function) );
227     proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_child(a_function) );
228     proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_expr(a_function) );
229 
230     proto::assert_matches< proto::terminal< void(*)() > >( proto::lit(&a_function) );
231     proto::assert_matches< proto::terminal< void(*)() > >( proto::as_child(&a_function) );
232     proto::assert_matches< proto::terminal< void(*)() > >( proto::as_expr(&a_function) );
233 
234     proto::assert_matches< proto::terminal< void(* const &)() > >( proto::lit(&a_function) );
235     proto::assert_matches< proto::terminal< void(* const &)() > >( proto::as_child(&a_function) );
236     proto::assert_matches_not< proto::terminal< void(* const &)() > >( proto::as_expr(&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(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(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(1)('a','b','c','d') );
259     proto::assert_matches_not< proto::function< proto::terminal<int>, proto::vararg< proto::terminal<char> > > >( proto::lit(1)('a','b','c',"d") );
260 
261     proto::assert_matches< Anything >( cout_ << 1 << +proto::lit('a') << proto::lit(1)('a','b','c',"d") );
262 
263     proto::assert_matches< proto::switch_<MyCases> >( proto::lit(1) >> 'a' );
264     proto::assert_matches< proto::switch_<MyCases> >( proto::lit(1) + 'a' );
265     proto::assert_matches_not< proto::switch_<MyCases> >( proto::lit(1) << 'a' );
266 
267     number<int, two_complement_c> num;
268     proto::assert_matches<NumberGrammar>(proto::as_expr(num));
269 
270     // check custom terminal types
271     {
272         proto::nullary_expr<my_terminal, int>::type i = {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 = {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(1) );
287         proto::assert_matches_not< proto::or_<> >( proto::lit(1) );
288 
289         proto::assert_matches< proto::and_<proto::terminal<int> > >( proto::lit(1) );
290         proto::assert_matches< proto::or_<proto::terminal<int> > >( proto::lit(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(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 = {{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 //
init_unit_test_suite(int argc,char * argv[])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