295ad6710a
Commit (almost) automatically generated with the following sed command: sed -i -ne '1h;1!H;${g;s|\n[[:blank:]]*private:\n\([[:blank:]]*\)// silence MSVC warning C4512: assignment operator could not be generated\n\([[:blank:]]*\)\([^\n]\+\);\n|\n\1// silence MSVC warning C4512: assignment operator could not be generated\n\2BOOST_DELETED_FUNCTION(\3);\n|g;p}' $(git ls-files) Then all files in the x3 subfolder were reverted to HEAD, and manually updated to use " = delete" instead of BOOST_DELETED_FUNCTION.
393 lines
12 KiB
C++
393 lines
12 KiB
C++
/*=============================================================================
|
|
Copyright (c) 2008 Francois Barel
|
|
|
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
=============================================================================*/
|
|
#include <boost/detail/lightweight_test.hpp>
|
|
#include <boost/type_traits/is_same.hpp>
|
|
|
|
#include <boost/spirit/include/qi_operator.hpp>
|
|
#include <boost/spirit/include/qi_char.hpp>
|
|
#include <boost/spirit/include/phoenix_core.hpp>
|
|
#include <boost/spirit/include/phoenix_operator.hpp>
|
|
|
|
#include <iterator>
|
|
#include "test.hpp"
|
|
|
|
|
|
namespace testns
|
|
{
|
|
|
|
BOOST_SPIRIT_TERMINAL_NAME_EX( ops, ops_type )
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Parsers
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename T1>
|
|
struct ops_1_parser
|
|
: boost::spirit::qi::primitive_parser<ops_1_parser<T1> >
|
|
{
|
|
ops_1_parser(T1 t1)
|
|
: t1(t1)
|
|
{}
|
|
|
|
template <typename Context, typename Iterator>
|
|
struct attribute
|
|
{
|
|
typedef int type; // Number of parsed chars.
|
|
};
|
|
|
|
template <typename Iterator, typename Context
|
|
, typename Skipper, typename Attribute>
|
|
bool parse(Iterator& first, Iterator const& last
|
|
, Context& /*context*/, Skipper const& skipper
|
|
, Attribute& attr) const
|
|
{
|
|
boost::spirit::qi::skip_over(first, last, skipper);
|
|
|
|
int count = 0;
|
|
|
|
Iterator it = first;
|
|
typedef typename std::iterator_traits<Iterator>::value_type Char;
|
|
for (T1 t = 0; t < t1; t++, count++)
|
|
if (it == last || *it++ != Char('+'))
|
|
return false;
|
|
|
|
boost::spirit::traits::assign_to(count, attr);
|
|
first = it;
|
|
return true;
|
|
}
|
|
|
|
template <typename Context>
|
|
boost::spirit::qi::info what(Context& /*context*/) const
|
|
{
|
|
return boost::spirit::qi::info("ops_1");
|
|
}
|
|
|
|
const T1 t1;
|
|
|
|
// silence MSVC warning C4512: assignment operator could not be generated
|
|
BOOST_DELETED_FUNCTION(ops_1_parser& operator= (ops_1_parser const&));
|
|
};
|
|
|
|
template <typename T1, typename T2>
|
|
struct ops_2_parser
|
|
: boost::spirit::qi::primitive_parser<ops_2_parser<T1, T2> >
|
|
{
|
|
ops_2_parser(T1 t1, T2 t2)
|
|
: t1(t1)
|
|
, t2(t2)
|
|
{}
|
|
|
|
template <typename Context, typename Iterator>
|
|
struct attribute
|
|
{
|
|
typedef int type; // Number of parsed chars.
|
|
};
|
|
|
|
template <typename Iterator, typename Context
|
|
, typename Skipper, typename Attribute>
|
|
bool parse(Iterator& first, Iterator const& last
|
|
, Context& /*context*/, Skipper const& skipper
|
|
, Attribute& attr) const
|
|
{
|
|
boost::spirit::qi::skip_over(first, last, skipper);
|
|
|
|
int count = 0;
|
|
|
|
Iterator it = first;
|
|
typedef typename std::iterator_traits<Iterator>::value_type Char;
|
|
for (T1 t = 0; t < t1; t++, count++)
|
|
if (it == last || *it++ != Char('+'))
|
|
return false;
|
|
for (T2 t = 0; t < t2; t++, count++)
|
|
if (it == last || *it++ != Char('-'))
|
|
return false;
|
|
|
|
boost::spirit::traits::assign_to(count, attr);
|
|
first = it;
|
|
return true;
|
|
}
|
|
|
|
template <typename Context>
|
|
boost::spirit::qi::info what(Context& /*context*/) const
|
|
{
|
|
return boost::spirit::qi::info("ops_2");
|
|
}
|
|
|
|
const T1 t1;
|
|
const T2 t2;
|
|
|
|
// silence MSVC warning C4512: assignment operator could not be generated
|
|
BOOST_DELETED_FUNCTION(ops_2_parser& operator= (ops_2_parser const&));
|
|
};
|
|
|
|
template <typename T1, typename T2, typename T3>
|
|
struct ops_3_parser
|
|
: boost::spirit::qi::primitive_parser<ops_3_parser<T1, T2, T3> >
|
|
{
|
|
ops_3_parser(T1 t1, T2 t2, T3 t3)
|
|
: t1(t1)
|
|
, t2(t2)
|
|
, t3(t3)
|
|
{}
|
|
|
|
template <typename Context, typename Iterator>
|
|
struct attribute
|
|
{
|
|
typedef int type; // Number of parsed chars.
|
|
};
|
|
|
|
template <typename Iterator, typename Context
|
|
, typename Skipper, typename Attribute>
|
|
bool parse(Iterator& first, Iterator const& last
|
|
, Context& /*context*/, Skipper const& skipper
|
|
, Attribute& attr) const
|
|
{
|
|
boost::spirit::qi::skip_over(first, last, skipper);
|
|
|
|
int count = 0;
|
|
|
|
Iterator it = first;
|
|
typedef typename std::iterator_traits<Iterator>::value_type Char;
|
|
for (T1 t = 0; t < t1; t++, count++)
|
|
if (it == last || *it++ != Char('+'))
|
|
return false;
|
|
for (T2 t = 0; t < t2; t++, count++)
|
|
if (it == last || *it++ != Char('-'))
|
|
return false;
|
|
for (T3 t = 0; t < t3; t++, count++)
|
|
if (it == last || *it++ != Char('*'))
|
|
return false;
|
|
|
|
boost::spirit::traits::assign_to(count, attr);
|
|
first = it;
|
|
return true;
|
|
}
|
|
|
|
template <typename Context>
|
|
boost::spirit::qi::info what(Context& /*context*/) const
|
|
{
|
|
return boost::spirit::qi::info("ops_3");
|
|
}
|
|
|
|
const T1 t1;
|
|
const T2 t2;
|
|
const T3 t3;
|
|
|
|
// silence MSVC warning C4512: assignment operator could not be generated
|
|
BOOST_DELETED_FUNCTION(ops_3_parser& operator= (ops_3_parser const&));
|
|
};
|
|
|
|
}
|
|
|
|
|
|
namespace boost { namespace spirit
|
|
{
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Enablers
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename T1>
|
|
struct use_terminal<qi::domain
|
|
, terminal_ex<testns::tag::ops, fusion::vector1<T1> > >
|
|
: mpl::true_ {};
|
|
|
|
template <typename T1, typename T2>
|
|
struct use_terminal<qi::domain
|
|
, terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> > >
|
|
: mpl::true_ {};
|
|
|
|
template <typename T1, typename T2, typename T3>
|
|
struct use_terminal<qi::domain
|
|
, terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> > >
|
|
: mpl::true_ {};
|
|
|
|
template <>
|
|
struct use_lazy_terminal<qi::domain, testns::tag::ops, 1>
|
|
: mpl::true_ {};
|
|
|
|
template <>
|
|
struct use_lazy_terminal<qi::domain, testns::tag::ops, 2>
|
|
: mpl::true_ {};
|
|
|
|
template <>
|
|
struct use_lazy_terminal<qi::domain, testns::tag::ops, 3>
|
|
: mpl::true_ {};
|
|
|
|
}}
|
|
|
|
namespace boost { namespace spirit { namespace qi
|
|
{
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Parser generators: make_xxx function (objects)
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename Modifiers, typename T1>
|
|
struct make_primitive<
|
|
terminal_ex<testns::tag::ops, fusion::vector1<T1> >
|
|
, Modifiers>
|
|
{
|
|
typedef testns::ops_1_parser<T1> result_type;
|
|
template <typename Terminal>
|
|
result_type operator()(const Terminal& term, unused_type) const
|
|
{
|
|
return result_type(
|
|
fusion::at_c<0>(term.args)
|
|
);
|
|
}
|
|
};
|
|
|
|
template <typename Modifiers, typename T1, typename T2>
|
|
struct make_primitive<
|
|
terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> >
|
|
, Modifiers>
|
|
{
|
|
typedef testns::ops_2_parser<T1, T2> result_type;
|
|
template <typename Terminal>
|
|
result_type operator()(const Terminal& term, unused_type) const
|
|
{
|
|
return result_type(
|
|
fusion::at_c<0>(term.args)
|
|
, fusion::at_c<1>(term.args)
|
|
);
|
|
}
|
|
};
|
|
|
|
template <typename Modifiers, typename T1, typename T2, typename T3>
|
|
struct make_primitive<
|
|
terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> >
|
|
, Modifiers>
|
|
{
|
|
typedef testns::ops_3_parser<T1, T2, T3> result_type;
|
|
template <typename Terminal>
|
|
result_type operator()(const Terminal& term, unused_type) const
|
|
{
|
|
return result_type(
|
|
fusion::at_c<0>(term.args)
|
|
, fusion::at_c<1>(term.args)
|
|
, fusion::at_c<2>(term.args)
|
|
);
|
|
}
|
|
};
|
|
|
|
}}}
|
|
|
|
|
|
namespace testns
|
|
{
|
|
template <typename T1, typename T>
|
|
void check_type_1(const T& /*t*/)
|
|
{
|
|
BOOST_STATIC_ASSERT(( boost::is_same<T
|
|
, typename boost::spirit::terminal<testns::tag::ops>::result<T1>::type >::value ));
|
|
}
|
|
|
|
template <typename T1, typename T2, typename T>
|
|
void check_type_2(const T& /*t*/)
|
|
{
|
|
BOOST_STATIC_ASSERT(( boost::is_same<T
|
|
, typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2>::type >::value ));
|
|
}
|
|
|
|
template <typename T1, typename T2, typename T3, typename T>
|
|
void check_type_3(const T& /*t*/)
|
|
{
|
|
BOOST_STATIC_ASSERT(( boost::is_same<T
|
|
, typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2, T3>::type >::value ));
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
main()
|
|
{
|
|
using spirit_test::test_attr;
|
|
using spirit_test::test;
|
|
|
|
using testns::ops;
|
|
using testns::check_type_1;
|
|
using testns::check_type_2;
|
|
using testns::check_type_3;
|
|
|
|
{ // immediate args
|
|
int c = 0;
|
|
#define IP1 ops(2)
|
|
check_type_1<int>(IP1);
|
|
BOOST_TEST(test_attr("++/", IP1 >> '/', c) && c == 2);
|
|
|
|
c = 0;
|
|
#define IP2 ops(2, 3)
|
|
check_type_2<int, int>(IP2);
|
|
BOOST_TEST(test_attr("++---/", IP2 >> '/', c) && c == 5);
|
|
|
|
c = 0;
|
|
#define IP3 ops(2, 3, 4)
|
|
check_type_3<int, int, int>(IP3);
|
|
BOOST_TEST(!test("++---***/", IP3 >> '/'));
|
|
#define IP4 ops(2, 3, 4)
|
|
check_type_3<int, int, int>(IP4);
|
|
BOOST_TEST(test_attr("++---****/", IP4 >> '/', c) && c == 9);
|
|
}
|
|
|
|
using boost::phoenix::val;
|
|
using boost::phoenix::actor;
|
|
using boost::phoenix::expression::value;
|
|
|
|
{ // all lazy args
|
|
int c = 0;
|
|
#define LP1 ops(val(1))
|
|
check_type_1<value<int>::type>(LP1);
|
|
BOOST_TEST(test_attr("+/", LP1 >> '/', c) && c == 1);
|
|
|
|
c = 0;
|
|
#define LP2 ops(val(1), val(4))
|
|
check_type_2<value<int>::type, value<int>::type>(LP2);
|
|
BOOST_TEST(test_attr("+----/", LP2 >> '/', c) && c == 5);
|
|
|
|
c = 0;
|
|
#define LP3 ops(val((char)2), val(3.), val(4))
|
|
check_type_3<value<char>::type, value<double>::type, value<int>::type>(LP3);
|
|
BOOST_TEST(!test("++---***/", LP3 >> '/'));
|
|
#define LP4 ops(val(1), val(2), val(3))
|
|
check_type_3<value<int>::type, value<int>::type, value<int>::type>(LP4);
|
|
BOOST_TEST(test_attr("+--***/", LP4 >> '/', c) && c == 6);
|
|
}
|
|
|
|
{ // mixed immediate and lazy args
|
|
namespace fusion = boost::fusion;
|
|
namespace phx = boost::phoenix;
|
|
|
|
int c = 0;
|
|
#define MP1 ops(val(3), 2)
|
|
check_type_2<value<int>::type, int>(MP1);
|
|
BOOST_TEST(test_attr("+++--/", MP1 >> '/', c) && c == 5);
|
|
|
|
c = 0;
|
|
#define MP2 ops(4, val(1))
|
|
check_type_2<int, value<int>::type>(MP2);
|
|
BOOST_TEST(test_attr("++++-/", MP2 >> '/', c) && c == 5);
|
|
|
|
c = 0;
|
|
#define MP3 ops(2, val(2), val(2))
|
|
check_type_3<int, value<int>::type, value<int>::type>(MP3);
|
|
BOOST_TEST(!test("++-**/", MP3 >> '/'));
|
|
#define MP4 ops(2, val(2), 2)
|
|
check_type_3<int, value<int>::type, int>(MP4);
|
|
BOOST_TEST(test_attr("++--**/", MP4 >> '/', c) && c == 6);
|
|
|
|
c = 0;
|
|
#define MP5 ops(val(5) - val(3), 2, val(2))
|
|
check_type_3<phx::expression::minus<value<int>::type, value<int>::type>::type, int, value<int>::type>(MP5);
|
|
BOOST_TEST(test_attr("++--**/", MP5 >> '/', c) && c == 6);
|
|
}
|
|
|
|
return boost::report_errors();
|
|
}
|
|
|