diff options
Diffstat (limited to 'src/boost/libs/spirit/test/qi/terminal_ex.cpp')
-rw-r--r-- | src/boost/libs/spirit/test/qi/terminal_ex.cpp | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/src/boost/libs/spirit/test/qi/terminal_ex.cpp b/src/boost/libs/spirit/test/qi/terminal_ex.cpp new file mode 100644 index 00000000..8514f113 --- /dev/null +++ b/src/boost/libs/spirit/test/qi/terminal_ex.cpp @@ -0,0 +1,392 @@ +/*============================================================================= + 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(); +} + |