• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2008 Francois Barel
3 
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 #include <boost/detail/lightweight_test.hpp>
8 #include <boost/type_traits/is_same.hpp>
9 
10 #include <boost/spirit/include/qi_operator.hpp>
11 #include <boost/spirit/include/qi_char.hpp>
12 #include <boost/spirit/include/phoenix_core.hpp>
13 #include <boost/spirit/include/phoenix_operator.hpp>
14 
15 #include <iterator>
16 #include "test.hpp"
17 
18 
19 namespace testns
20 {
21 
22     BOOST_SPIRIT_TERMINAL_NAME_EX( ops, ops_type )
23 
24 
25     ///////////////////////////////////////////////////////////////////////////
26     // Parsers
27     ///////////////////////////////////////////////////////////////////////////
28 
29     template <typename T1>
30     struct ops_1_parser
31       : boost::spirit::qi::primitive_parser<ops_1_parser<T1> >
32     {
ops_1_parsertestns::ops_1_parser33         ops_1_parser(T1 t1)
34           : t1(t1)
35         {}
36 
37         template <typename Context, typename Iterator>
38         struct attribute
39         {
40             typedef int type;   // Number of parsed chars.
41         };
42 
43         template <typename Iterator, typename Context
44           , typename Skipper, typename Attribute>
parsetestns::ops_1_parser45         bool parse(Iterator& first, Iterator const& last
46           , Context& /*context*/, Skipper const& skipper
47           , Attribute& attr) const
48         {
49             boost::spirit::qi::skip_over(first, last, skipper);
50 
51             int count = 0;
52 
53             Iterator it = first;
54             typedef typename std::iterator_traits<Iterator>::value_type Char;
55             for (T1 t = 0; t < t1; t++, count++)
56                 if (it == last || *it++ != Char('+'))
57                     return false;
58 
59             boost::spirit::traits::assign_to(count, attr);
60             first = it;
61             return true;
62         }
63 
64         template <typename Context>
whattestns::ops_1_parser65         boost::spirit::qi::info what(Context& /*context*/) const
66         {
67             return boost::spirit::qi::info("ops_1");
68         }
69 
70         const T1 t1;
71 
72         // silence MSVC warning C4512: assignment operator could not be generated
73         BOOST_DELETED_FUNCTION(ops_1_parser& operator= (ops_1_parser const&));
74     };
75 
76     template <typename T1, typename T2>
77     struct ops_2_parser
78       : boost::spirit::qi::primitive_parser<ops_2_parser<T1, T2> >
79     {
ops_2_parsertestns::ops_2_parser80         ops_2_parser(T1 t1, T2 t2)
81           : t1(t1)
82           , t2(t2)
83         {}
84 
85         template <typename Context, typename Iterator>
86         struct attribute
87         {
88             typedef int type;   // Number of parsed chars.
89         };
90 
91         template <typename Iterator, typename Context
92           , typename Skipper, typename Attribute>
parsetestns::ops_2_parser93         bool parse(Iterator& first, Iterator const& last
94           , Context& /*context*/, Skipper const& skipper
95           , Attribute& attr) const
96         {
97             boost::spirit::qi::skip_over(first, last, skipper);
98 
99             int count = 0;
100 
101             Iterator it = first;
102             typedef typename std::iterator_traits<Iterator>::value_type Char;
103             for (T1 t = 0; t < t1; t++, count++)
104                 if (it == last || *it++ != Char('+'))
105                     return false;
106             for (T2 t = 0; t < t2; t++, count++)
107                 if (it == last || *it++ != Char('-'))
108                     return false;
109 
110             boost::spirit::traits::assign_to(count, attr);
111             first = it;
112             return true;
113         }
114 
115         template <typename Context>
whattestns::ops_2_parser116         boost::spirit::qi::info what(Context& /*context*/) const
117         {
118             return boost::spirit::qi::info("ops_2");
119         }
120 
121         const T1 t1;
122         const T2 t2;
123 
124         // silence MSVC warning C4512: assignment operator could not be generated
125         BOOST_DELETED_FUNCTION(ops_2_parser& operator= (ops_2_parser const&));
126     };
127 
128     template <typename T1, typename T2, typename T3>
129     struct ops_3_parser
130       : boost::spirit::qi::primitive_parser<ops_3_parser<T1, T2, T3> >
131     {
ops_3_parsertestns::ops_3_parser132         ops_3_parser(T1 t1, T2 t2, T3 t3)
133           : t1(t1)
134           , t2(t2)
135           , t3(t3)
136         {}
137 
138         template <typename Context, typename Iterator>
139         struct attribute
140         {
141             typedef int type;   // Number of parsed chars.
142         };
143 
144         template <typename Iterator, typename Context
145           , typename Skipper, typename Attribute>
parsetestns::ops_3_parser146         bool parse(Iterator& first, Iterator const& last
147           , Context& /*context*/, Skipper const& skipper
148           , Attribute& attr) const
149         {
150             boost::spirit::qi::skip_over(first, last, skipper);
151 
152             int count = 0;
153 
154             Iterator it = first;
155             typedef typename std::iterator_traits<Iterator>::value_type Char;
156             for (T1 t = 0; t < t1; t++, count++)
157                 if (it == last || *it++ != Char('+'))
158                     return false;
159             for (T2 t = 0; t < t2; t++, count++)
160                 if (it == last || *it++ != Char('-'))
161                     return false;
162             for (T3 t = 0; t < t3; t++, count++)
163                 if (it == last || *it++ != Char('*'))
164                     return false;
165 
166             boost::spirit::traits::assign_to(count, attr);
167             first = it;
168             return true;
169         }
170 
171         template <typename Context>
whattestns::ops_3_parser172         boost::spirit::qi::info what(Context& /*context*/) const
173         {
174             return boost::spirit::qi::info("ops_3");
175         }
176 
177         const T1 t1;
178         const T2 t2;
179         const T3 t3;
180 
181         // silence MSVC warning C4512: assignment operator could not be generated
182         BOOST_DELETED_FUNCTION(ops_3_parser& operator= (ops_3_parser const&));
183     };
184 
185 }
186 
187 
188 namespace boost { namespace spirit
189 {
190 
191     ///////////////////////////////////////////////////////////////////////////
192     // Enablers
193     ///////////////////////////////////////////////////////////////////////////
194 
195     template <typename T1>
196     struct use_terminal<qi::domain
197       , terminal_ex<testns::tag::ops, fusion::vector1<T1> > >
198       : mpl::true_ {};
199 
200     template <typename T1, typename T2>
201     struct use_terminal<qi::domain
202       , terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> > >
203       : mpl::true_ {};
204 
205     template <typename T1, typename T2, typename T3>
206     struct use_terminal<qi::domain
207       , terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> > >
208       : mpl::true_ {};
209 
210     template <>
211     struct use_lazy_terminal<qi::domain, testns::tag::ops, 1>
212       : mpl::true_ {};
213 
214     template <>
215     struct use_lazy_terminal<qi::domain, testns::tag::ops, 2>
216       : mpl::true_ {};
217 
218     template <>
219     struct use_lazy_terminal<qi::domain, testns::tag::ops, 3>
220       : mpl::true_ {};
221 
222 }}
223 
224 namespace boost { namespace spirit { namespace qi
225 {
226 
227     ///////////////////////////////////////////////////////////////////////////
228     // Parser generators: make_xxx function (objects)
229     ///////////////////////////////////////////////////////////////////////////
230 
231     template <typename Modifiers, typename T1>
232     struct make_primitive<
233         terminal_ex<testns::tag::ops, fusion::vector1<T1> >
234       , Modifiers>
235     {
236         typedef testns::ops_1_parser<T1> result_type;
237         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive238         result_type operator()(const Terminal& term, unused_type) const
239         {
240             return result_type(
241                 fusion::at_c<0>(term.args)
242             );
243         }
244     };
245 
246     template <typename Modifiers, typename T1, typename T2>
247     struct make_primitive<
248         terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> >
249       , Modifiers>
250     {
251         typedef testns::ops_2_parser<T1, T2> result_type;
252         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive253         result_type operator()(const Terminal& term, unused_type) const
254         {
255             return result_type(
256                 fusion::at_c<0>(term.args)
257               , fusion::at_c<1>(term.args)
258             );
259         }
260     };
261 
262     template <typename Modifiers, typename T1, typename T2, typename T3>
263     struct make_primitive<
264         terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> >
265       , Modifiers>
266     {
267         typedef testns::ops_3_parser<T1, T2, T3> result_type;
268         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive269         result_type operator()(const Terminal& term, unused_type) const
270         {
271             return result_type(
272                 fusion::at_c<0>(term.args)
273               , fusion::at_c<1>(term.args)
274               , fusion::at_c<2>(term.args)
275             );
276         }
277     };
278 
279 }}}
280 
281 
282 namespace testns
283 {
284     template <typename T1, typename T>
check_type_1(const T &)285     void check_type_1(const T& /*t*/)
286     {
287         BOOST_STATIC_ASSERT(( boost::is_same<T
288           , typename boost::spirit::terminal<testns::tag::ops>::result<T1>::type >::value ));
289     }
290 
291     template <typename T1, typename T2, typename T>
check_type_2(const T &)292     void check_type_2(const T& /*t*/)
293     {
294         BOOST_STATIC_ASSERT(( boost::is_same<T
295           , typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2>::type >::value ));
296     }
297 
298     template <typename T1, typename T2, typename T3, typename T>
check_type_3(const T &)299     void check_type_3(const T& /*t*/)
300     {
301         BOOST_STATIC_ASSERT(( boost::is_same<T
302           , typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2, T3>::type >::value ));
303     }
304 }
305 
306 
307 int
main()308 main()
309 {
310     using spirit_test::test_attr;
311     using spirit_test::test;
312 
313     using testns::ops;
314     using testns::check_type_1;
315     using testns::check_type_2;
316     using testns::check_type_3;
317 
318     { // immediate args
319         int c = 0;
320 #define IP1 ops(2)
321         check_type_1<int>(IP1);
322         BOOST_TEST(test_attr("++/", IP1 >> '/', c) && c == 2);
323 
324         c = 0;
325 #define IP2 ops(2, 3)
326         check_type_2<int, int>(IP2);
327         BOOST_TEST(test_attr("++---/", IP2 >> '/', c) && c == 5);
328 
329         c = 0;
330 #define IP3 ops(2, 3, 4)
331         check_type_3<int, int, int>(IP3);
332         BOOST_TEST(!test("++---***/", IP3 >> '/'));
333 #define IP4 ops(2, 3, 4)
334         check_type_3<int, int, int>(IP4);
335         BOOST_TEST(test_attr("++---****/", IP4 >> '/', c) && c == 9);
336     }
337 
338     using boost::phoenix::val;
339     using boost::phoenix::actor;
340     using boost::phoenix::expression::value;
341 
342     { // all lazy args
343         int c = 0;
344 #define LP1 ops(val(1))
345         check_type_1<value<int>::type>(LP1);
346         BOOST_TEST(test_attr("+/", LP1 >> '/', c) && c == 1);
347 
348         c = 0;
349 #define LP2 ops(val(1), val(4))
350         check_type_2<value<int>::type, value<int>::type>(LP2);
351         BOOST_TEST(test_attr("+----/", LP2 >> '/', c) && c == 5);
352 
353         c = 0;
354 #define LP3 ops(val((char)2), val(3.), val(4))
355         check_type_3<value<char>::type, value<double>::type, value<int>::type>(LP3);
356         BOOST_TEST(!test("++---***/", LP3 >> '/'));
357 #define LP4 ops(val(1), val(2), val(3))
358         check_type_3<value<int>::type, value<int>::type, value<int>::type>(LP4);
359         BOOST_TEST(test_attr("+--***/", LP4 >> '/', c) && c == 6);
360     }
361 
362     { // mixed immediate and lazy args
363         namespace fusion = boost::fusion;
364         namespace phx = boost::phoenix;
365 
366         int c = 0;
367 #define MP1 ops(val(3), 2)
368         check_type_2<value<int>::type, int>(MP1);
369         BOOST_TEST(test_attr("+++--/", MP1 >> '/', c) && c == 5);
370 
371         c = 0;
372 #define MP2 ops(4, val(1))
373         check_type_2<int, value<int>::type>(MP2);
374         BOOST_TEST(test_attr("++++-/", MP2 >> '/', c) && c == 5);
375 
376         c = 0;
377 #define MP3 ops(2, val(2), val(2))
378         check_type_3<int, value<int>::type, value<int>::type>(MP3);
379         BOOST_TEST(!test("++-**/", MP3 >> '/'));
380 #define MP4 ops(2, val(2), 2)
381         check_type_3<int, value<int>::type, int>(MP4);
382         BOOST_TEST(test_attr("++--**/", MP4 >> '/', c) && c == 6);
383 
384         c = 0;
385 #define MP5 ops(val(5) - val(3), 2, val(2))
386         check_type_3<phx::expression::minus<value<int>::type, value<int>::type>::type, int, value<int>::type>(MP5);
387         BOOST_TEST(test_attr("++--**/", MP5 >> '/', c) && c == 6);
388     }
389 
390     return boost::report_errors();
391 }
392 
393