1
/*=============================================================================
2
Copyright (c) 2008 Francois Barel
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>
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>
22
BOOST_SPIRIT_TERMINAL_NAME_EX( ops, ops_type )
25
///////////////////////////////////////////////////////////////////////////
27
///////////////////////////////////////////////////////////////////////////
29
template <typename T1>
31
: boost::spirit::qi::primitive_parser<ops_1_parser<T1> >
37
template <typename Context, typename Iterator>
40
typedef int type; // Number of parsed chars.
43
template <typename Iterator, typename Context
44
, typename Skipper, typename Attribute>
45
bool parse(Iterator& first, Iterator const& last
46
, Context& /*context*/, Skipper const& skipper
47
, Attribute& attr) const
49
boost::spirit::qi::skip_over(first, last, skipper);
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('+'))
59
boost::spirit::traits::assign_to(count, attr);
64
template <typename Context>
65
boost::spirit::qi::info what(Context& /*context*/) const
67
return boost::spirit::qi::info("ops_1");
73
// silence MSVC warning C4512: assignment operator could not be generated
74
ops_1_parser& operator= (ops_1_parser const&);
77
template <typename T1, typename T2>
79
: boost::spirit::qi::primitive_parser<ops_2_parser<T1, T2> >
81
ops_2_parser(T1 t1, T2 t2)
86
template <typename Context, typename Iterator>
89
typedef int type; // Number of parsed chars.
92
template <typename Iterator, typename Context
93
, typename Skipper, typename Attribute>
94
bool parse(Iterator& first, Iterator const& last
95
, Context& /*context*/, Skipper const& skipper
96
, Attribute& attr) const
98
boost::spirit::qi::skip_over(first, last, skipper);
103
typedef typename std::iterator_traits<Iterator>::value_type Char;
104
for (T1 t = 0; t < t1; t++, count++)
105
if (it == last || *it++ != Char('+'))
107
for (T2 t = 0; t < t2; t++, count++)
108
if (it == last || *it++ != Char('-'))
111
boost::spirit::traits::assign_to(count, attr);
116
template <typename Context>
117
boost::spirit::qi::info what(Context& /*context*/) const
119
return boost::spirit::qi::info("ops_2");
126
// silence MSVC warning C4512: assignment operator could not be generated
127
ops_2_parser& operator= (ops_2_parser const&);
130
template <typename T1, typename T2, typename T3>
132
: boost::spirit::qi::primitive_parser<ops_3_parser<T1, T2, T3> >
134
ops_3_parser(T1 t1, T2 t2, T3 t3)
140
template <typename Context, typename Iterator>
143
typedef int type; // Number of parsed chars.
146
template <typename Iterator, typename Context
147
, typename Skipper, typename Attribute>
148
bool parse(Iterator& first, Iterator const& last
149
, Context& /*context*/, Skipper const& skipper
150
, Attribute& attr) const
152
boost::spirit::qi::skip_over(first, last, skipper);
157
typedef typename std::iterator_traits<Iterator>::value_type Char;
158
for (T1 t = 0; t < t1; t++, count++)
159
if (it == last || *it++ != Char('+'))
161
for (T2 t = 0; t < t2; t++, count++)
162
if (it == last || *it++ != Char('-'))
164
for (T3 t = 0; t < t3; t++, count++)
165
if (it == last || *it++ != Char('*'))
168
boost::spirit::traits::assign_to(count, attr);
173
template <typename Context>
174
boost::spirit::qi::info what(Context& /*context*/) const
176
return boost::spirit::qi::info("ops_3");
184
// silence MSVC warning C4512: assignment operator could not be generated
185
ops_3_parser& operator= (ops_3_parser const&);
191
namespace boost { namespace spirit
194
///////////////////////////////////////////////////////////////////////////
196
///////////////////////////////////////////////////////////////////////////
198
template <typename T1>
199
struct use_terminal<qi::domain
200
, terminal_ex<testns::tag::ops, fusion::vector1<T1> > >
203
template <typename T1, typename T2>
204
struct use_terminal<qi::domain
205
, terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> > >
208
template <typename T1, typename T2, typename T3>
209
struct use_terminal<qi::domain
210
, terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> > >
214
struct use_lazy_terminal<qi::domain, testns::tag::ops, 1>
218
struct use_lazy_terminal<qi::domain, testns::tag::ops, 2>
222
struct use_lazy_terminal<qi::domain, testns::tag::ops, 3>
227
namespace boost { namespace spirit { namespace qi
230
///////////////////////////////////////////////////////////////////////////
231
// Parser generators: make_xxx function (objects)
232
///////////////////////////////////////////////////////////////////////////
234
template <typename Modifiers, typename T1>
235
struct make_primitive<
236
terminal_ex<testns::tag::ops, fusion::vector1<T1> >
239
typedef testns::ops_1_parser<T1> result_type;
240
template <typename Terminal>
241
result_type operator()(const Terminal& term, unused_type) const
244
fusion::at_c<0>(term.args)
249
template <typename Modifiers, typename T1, typename T2>
250
struct make_primitive<
251
terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> >
254
typedef testns::ops_2_parser<T1, T2> result_type;
255
template <typename Terminal>
256
result_type operator()(const Terminal& term, unused_type) const
259
fusion::at_c<0>(term.args)
260
, fusion::at_c<1>(term.args)
265
template <typename Modifiers, typename T1, typename T2, typename T3>
266
struct make_primitive<
267
terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> >
270
typedef testns::ops_3_parser<T1, T2, T3> result_type;
271
template <typename Terminal>
272
result_type operator()(const Terminal& term, unused_type) const
275
fusion::at_c<0>(term.args)
276
, fusion::at_c<1>(term.args)
277
, fusion::at_c<2>(term.args)
287
template <typename T1, typename T>
288
void check_type_1(const T& /*t*/)
290
namespace fusion = boost::fusion;
291
BOOST_STATIC_ASSERT(( boost::is_same<T
292
, typename boost::spirit::terminal<testns::tag::ops>::result<T1>::type >::value ));
295
template <typename T1, typename T2, typename T>
296
void check_type_2(const T& /*t*/)
298
namespace fusion = boost::fusion;
299
BOOST_STATIC_ASSERT(( boost::is_same<T
300
, typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2>::type >::value ));
303
template <typename T1, typename T2, typename T3, typename T>
304
void check_type_3(const T& /*t*/)
306
namespace fusion = boost::fusion;
307
BOOST_STATIC_ASSERT(( boost::is_same<T
308
, typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2, T3>::type >::value ));
316
using spirit_test::test_attr;
317
using spirit_test::test;
320
using testns::check_type_1;
321
using testns::check_type_2;
322
using testns::check_type_3;
327
check_type_1<int>(IP1);
328
BOOST_TEST(test_attr("++/", IP1 >> '/', c) && c == 2);
331
#define IP2 ops(2, 3)
332
check_type_2<int, int>(IP2);
333
BOOST_TEST(test_attr("++---/", IP2 >> '/', c) && c == 5);
336
#define IP3 ops(2, 3, 4)
337
check_type_3<int, int, int>(IP3);
338
BOOST_TEST(!test("++---***/", IP3 >> '/'));
339
#define IP4 ops(2, 3, 4)
340
check_type_3<int, int, int>(IP4);
341
BOOST_TEST(test_attr("++---****/", IP4 >> '/', c) && c == 9);
344
#ifndef BOOST_SPIRIT_USE_PHOENIX_V3
346
using boost::phoenix::val;
347
using boost::phoenix::actor;
348
using boost::phoenix::value;
352
#define LP1 ops(val(1))
353
check_type_1<actor<value<int> > >(LP1);
354
BOOST_TEST(test_attr("+/", LP1 >> '/', c) && c == 1);
357
#define LP2 ops(val(1), val(4))
358
check_type_2<actor<value<int> >, actor<value<int> > >(LP2);
359
BOOST_TEST(test_attr("+----/", LP2 >> '/', c) && c == 5);
362
#define LP3 ops(val((char)2), val(3.), val(4))
363
check_type_3<actor<value<char> >, actor<value<double> >, actor<value<int> > >(LP3);
364
BOOST_TEST(!test("++---***/", LP3 >> '/'));
365
#define LP4 ops(val(1), val(2), val(3))
366
check_type_3<actor<value<int> >, actor<value<int> >, actor<value<int> > >(LP4);
367
BOOST_TEST(test_attr("+--***/", LP4 >> '/', c) && c == 6);
370
{ // mixed immediate and lazy args
371
namespace fusion = boost::fusion;
372
namespace phx = boost::phoenix;
375
#define MP1 ops(val(3), 2)
376
check_type_2<actor<value<int> >, int>(MP1);
377
BOOST_TEST(test_attr("+++--/", MP1 >> '/', c) && c == 5);
380
#define MP2 ops(4, val(1))
381
check_type_2<int, actor<value<int> > >(MP2);
382
BOOST_TEST(test_attr("++++-/", MP2 >> '/', c) && c == 5);
385
#define MP3 ops(2, val(2), val(2))
386
check_type_3<int, actor<value<int> >, actor<value<int> > >(MP3);
387
BOOST_TEST(!test("++-**/", MP3 >> '/'));
388
#define MP4 ops(2, val(2), 2)
389
check_type_3<int, actor<value<int> >, int>(MP4);
390
BOOST_TEST(test_attr("++--**/", MP4 >> '/', c) && c == 6);
393
#define MP5 ops(val(5) - val(3), 2, val(2))
394
check_type_3<actor<phx::composite<phx::minus_eval, fusion::vector<value<int>, value<int> > > >, int, actor<value<int> > >(MP5);
395
BOOST_TEST(test_attr("++--**/", MP5 >> '/', c) && c == 6);
398
#else // BOOST_SPIRIT_USE_PHOENIX_V3
400
using boost::phoenix::val;
401
using boost::phoenix::actor;
402
using boost::phoenix::expression::value;
406
#define LP1 ops(val(1))
407
check_type_1<value<int>::type>(LP1);
408
BOOST_TEST(test_attr("+/", LP1 >> '/', c) && c == 1);
411
#define LP2 ops(val(1), val(4))
412
check_type_2<value<int>::type, value<int>::type>(LP2);
413
BOOST_TEST(test_attr("+----/", LP2 >> '/', c) && c == 5);
416
#define LP3 ops(val((char)2), val(3.), val(4))
417
check_type_3<value<char>::type, value<double>::type, value<int>::type>(LP3);
418
BOOST_TEST(!test("++---***/", LP3 >> '/'));
419
#define LP4 ops(val(1), val(2), val(3))
420
check_type_3<value<int>::type, value<int>::type, value<int>::type>(LP4);
421
BOOST_TEST(test_attr("+--***/", LP4 >> '/', c) && c == 6);
424
{ // mixed immediate and lazy args
425
namespace fusion = boost::fusion;
426
namespace phx = boost::phoenix;
429
#define MP1 ops(val(3), 2)
430
check_type_2<value<int>::type, int>(MP1);
431
BOOST_TEST(test_attr("+++--/", MP1 >> '/', c) && c == 5);
434
#define MP2 ops(4, val(1))
435
check_type_2<int, value<int>::type>(MP2);
436
BOOST_TEST(test_attr("++++-/", MP2 >> '/', c) && c == 5);
439
#define MP3 ops(2, val(2), val(2))
440
check_type_3<int, value<int>::type, value<int>::type>(MP3);
441
BOOST_TEST(!test("++-**/", MP3 >> '/'));
442
#define MP4 ops(2, val(2), 2)
443
check_type_3<int, value<int>::type, int>(MP4);
444
BOOST_TEST(test_attr("++--**/", MP4 >> '/', c) && c == 6);
447
#define MP5 ops(val(5) - val(3), 2, val(2))
448
check_type_3<phx::expression::minus<value<int>::type, value<int>::type>::type, int, value<int>::type>(MP5);
449
BOOST_TEST(test_attr("++--**/", MP5 >> '/', c) && c == 6);
453
return boost::report_errors();