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/type_traits/is_same.hpp>
8
9#include <boost/spirit/include/qi_operator.hpp>
10#include <boost/spirit/include/qi_char.hpp>
11#include <boost/phoenix/core.hpp>
12#include <boost/phoenix/operator.hpp>
13
14#include <iterator>
15#include "test.hpp"
16
17
18namespace testns
19{
20
21 BOOST_SPIRIT_TERMINAL_NAME_EX( ops, ops_type )
22
23
24#ifdef _MSC_VER
25# pragma warning(push)
26# pragma warning(disable: 4512) // assignment operator could not be generated.
27#endif
28 ///////////////////////////////////////////////////////////////////////////
29 // Parsers
30 ///////////////////////////////////////////////////////////////////////////
31
32 template <typename T1>
33 struct ops_1_parser
34 : boost::spirit::qi::primitive_parser<ops_1_parser<T1> >
35 {
36 ops_1_parser(T1 t1)
37 : t1(t1)
38 {}
39
40 template <typename Context, typename Iterator>
41 struct attribute
42 {
43 typedef int type; // Number of parsed chars.
44 };
45
46 template <typename Iterator, typename Context
47 , typename Skipper, typename Attribute>
48 bool parse(Iterator& first, Iterator const& last
49 , Context& /*context*/, Skipper const& skipper
50 , Attribute& attr) const
51 {
52 boost::spirit::qi::skip_over(first, last, skipper);
53
54 int count = 0;
55
56 Iterator it = first;
57 typedef typename std::iterator_traits<Iterator>::value_type Char;
58 for (T1 t = 0; t < t1; t++, count++)
59 if (it == last || *it++ != Char('+'))
60 return false;
61
62 boost::spirit::traits::assign_to(count, attr);
63 first = it;
64 return true;
65 }
66
67 template <typename Context>
68 boost::spirit::qi::info what(Context& /*context*/) const
69 {
70 return boost::spirit::qi::info("ops_1");
71 }
72
73 const T1 t1;
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 {
80 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>
93 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>
116 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
125 template <typename T1, typename T2, typename T3>
126 struct ops_3_parser
127 : boost::spirit::qi::primitive_parser<ops_3_parser<T1, T2, T3> >
128 {
129 ops_3_parser(T1 t1, T2 t2, T3 t3)
130 : t1(t1)
131 , t2(t2)
132 , t3(t3)
133 {}
134
135 template <typename Context, typename Iterator>
136 struct attribute
137 {
138 typedef int type; // Number of parsed chars.
139 };
140
141 template <typename Iterator, typename Context
142 , typename Skipper, typename Attribute>
143 bool parse(Iterator& first, Iterator const& last
144 , Context& /*context*/, Skipper const& skipper
145 , Attribute& attr) const
146 {
147 boost::spirit::qi::skip_over(first, last, skipper);
148
149 int count = 0;
150
151 Iterator it = first;
152 typedef typename std::iterator_traits<Iterator>::value_type Char;
153 for (T1 t = 0; t < t1; t++, count++)
154 if (it == last || *it++ != Char('+'))
155 return false;
156 for (T2 t = 0; t < t2; t++, count++)
157 if (it == last || *it++ != Char('-'))
158 return false;
159 for (T3 t = 0; t < t3; t++, count++)
160 if (it == last || *it++ != Char('*'))
161 return false;
162
163 boost::spirit::traits::assign_to(count, attr);
164 first = it;
165 return true;
166 }
167
168 template <typename Context>
169 boost::spirit::qi::info what(Context& /*context*/) const
170 {
171 return boost::spirit::qi::info("ops_3");
172 }
173
174 const T1 t1;
175 const T2 t2;
176 const T3 t3;
177 };
178#ifdef _MSC_VER
179# pragma warning(pop)
180#endif
181
182}
183
184
185namespace boost { namespace spirit
186{
187
188 ///////////////////////////////////////////////////////////////////////////
189 // Enablers
190 ///////////////////////////////////////////////////////////////////////////
191
192 template <typename T1>
193 struct use_terminal<qi::domain
194 , terminal_ex<testns::tag::ops, fusion::vector1<T1> > >
195 : mpl::true_ {};
196
197 template <typename T1, typename T2>
198 struct use_terminal<qi::domain
199 , terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> > >
200 : mpl::true_ {};
201
202 template <typename T1, typename T2, typename T3>
203 struct use_terminal<qi::domain
204 , terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> > >
205 : mpl::true_ {};
206
207 template <>
208 struct use_lazy_terminal<qi::domain, testns::tag::ops, 1>
209 : mpl::true_ {};
210
211 template <>
212 struct use_lazy_terminal<qi::domain, testns::tag::ops, 2>
213 : mpl::true_ {};
214
215 template <>
216 struct use_lazy_terminal<qi::domain, testns::tag::ops, 3>
217 : mpl::true_ {};
218
219}}
220
221namespace boost { namespace spirit { namespace qi
222{
223
224 ///////////////////////////////////////////////////////////////////////////
225 // Parser generators: make_xxx function (objects)
226 ///////////////////////////////////////////////////////////////////////////
227
228 template <typename Modifiers, typename T1>
229 struct make_primitive<
230 terminal_ex<testns::tag::ops, fusion::vector1<T1> >
231 , Modifiers>
232 {
233 typedef testns::ops_1_parser<T1> result_type;
234 template <typename Terminal>
235 result_type operator()(const Terminal& term, unused_type) const
236 {
237 return result_type(
238 fusion::at_c<0>(term.args)
239 );
240 }
241 };
242
243 template <typename Modifiers, typename T1, typename T2>
244 struct make_primitive<
245 terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> >
246 , Modifiers>
247 {
248 typedef testns::ops_2_parser<T1, T2> result_type;
249 template <typename Terminal>
250 result_type operator()(const Terminal& term, unused_type) const
251 {
252 return result_type(
253 fusion::at_c<0>(term.args)
254 , fusion::at_c<1>(term.args)
255 );
256 }
257 };
258
259 template <typename Modifiers, typename T1, typename T2, typename T3>
260 struct make_primitive<
261 terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> >
262 , Modifiers>
263 {
264 typedef testns::ops_3_parser<T1, T2, T3> result_type;
265 template <typename Terminal>
266 result_type operator()(const Terminal& term, unused_type) const
267 {
268 return result_type(
269 fusion::at_c<0>(term.args)
270 , fusion::at_c<1>(term.args)
271 , fusion::at_c<2>(term.args)
272 );
273 }
274 };
275
276}}}
277
278
279namespace testns
280{
281 template <typename T1, typename T>
282 void check_type_1(const T& /*t*/)
283 {
284 BOOST_STATIC_ASSERT(( boost::is_same<T
285 , typename boost::spirit::terminal<testns::tag::ops>::result<T1>::type >::value ));
286 }
287
288 template <typename T1, typename T2, typename T>
289 void check_type_2(const T& /*t*/)
290 {
291 BOOST_STATIC_ASSERT(( boost::is_same<T
292 , typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2>::type >::value ));
293 }
294
295 template <typename T1, typename T2, typename T3, typename T>
296 void check_type_3(const T& /*t*/)
297 {
298 BOOST_STATIC_ASSERT(( boost::is_same<T
299 , typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2, T3>::type >::value ));
300 }
301}
302
303
304int
305main()
306{
307 using spirit_test::test_attr;
308 using spirit_test::test;
309
310 using testns::ops;
311 using testns::check_type_1;
312 using testns::check_type_2;
313 using testns::check_type_3;
314
315 { // immediate args
316 int c = 0;
317#define IP1 ops(2)
318 check_type_1<int>(IP1);
319 BOOST_TEST(test_attr("++/", IP1 >> '/', c) && c == 2);
320
321 c = 0;
322#define IP2 ops(2, 3)
323 check_type_2<int, int>(IP2);
324 BOOST_TEST(test_attr("++---/", IP2 >> '/', c) && c == 5);
325
326 c = 0;
327#define IP3 ops(2, 3, 4)
328 check_type_3<int, int, int>(IP3);
329 BOOST_TEST(!test("++---***/", IP3 >> '/'));
330#define IP4 ops(2, 3, 4)
331 check_type_3<int, int, int>(IP4);
332 BOOST_TEST(test_attr("++---****/", IP4 >> '/', c) && c == 9);
333 }
334
335 using boost::phoenix::val;
336 using boost::phoenix::actor;
337 using boost::phoenix::expression::value;
338
339 { // all lazy args
340 int c = 0;
341#define LP1 ops(val(1))
342 check_type_1<value<int>::type>(LP1);
343 BOOST_TEST(test_attr("+/", LP1 >> '/', c) && c == 1);
344
345 c = 0;
346#define LP2 ops(val(1), val(4))
347 check_type_2<value<int>::type, value<int>::type>(LP2);
348 BOOST_TEST(test_attr("+----/", LP2 >> '/', c) && c == 5);
349
350 c = 0;
351#define LP3 ops(val((char)2), val(3.), val(4))
352 check_type_3<value<char>::type, value<double>::type, value<int>::type>(LP3);
353 BOOST_TEST(!test("++---***/", LP3 >> '/'));
354#define LP4 ops(val(1), val(2), val(3))
355 check_type_3<value<int>::type, value<int>::type, value<int>::type>(LP4);
356 BOOST_TEST(test_attr("+--***/", LP4 >> '/', c) && c == 6);
357 }
358
359 { // mixed immediate and lazy args
360 namespace fusion = boost::fusion;
361 namespace phx = boost::phoenix;
362
363 int c = 0;
364#define MP1 ops(val(3), 2)
365 check_type_2<value<int>::type, int>(MP1);
366 BOOST_TEST(test_attr("+++--/", MP1 >> '/', c) && c == 5);
367
368 c = 0;
369#define MP2 ops(4, val(1))
370 check_type_2<int, value<int>::type>(MP2);
371 BOOST_TEST(test_attr("++++-/", MP2 >> '/', c) && c == 5);
372
373 c = 0;
374#define MP3 ops(2, val(2), val(2))
375 check_type_3<int, value<int>::type, value<int>::type>(MP3);
376 BOOST_TEST(!test("++-**/", MP3 >> '/'));
377#define MP4 ops(2, val(2), 2)
378 check_type_3<int, value<int>::type, int>(MP4);
379 BOOST_TEST(test_attr("++--**/", MP4 >> '/', c) && c == 6);
380
381 c = 0;
382#define MP5 ops(val(5) - val(3), 2, val(2))
383 check_type_3<phx::expression::minus<value<int>::type, value<int>::type>::type, int, value<int>::type>(MP5);
384 BOOST_TEST(test_attr("++--**/", MP5 >> '/', c) && c == 6);
385 }
386
387 return boost::report_errors();
388}
389
390

source code of boost/libs/spirit/test/qi/terminal_ex.cpp