| /////////////////////////////////////////////////////////////////////////////// |
| // matches.hpp |
| // |
| // Copyright 2008 Eric Niebler. 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 <string> |
| #include <iostream> |
| #include <boost/config.hpp> |
| #include <boost/detail/workaround.hpp> |
| #include <boost/mpl/assert.hpp> |
| #include <boost/mpl/placeholders.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/proto/core.hpp> |
| #include <boost/proto/debug.hpp> |
| #include <boost/proto/transform/arg.hpp> |
| #include <boost/test/unit_test.hpp> |
| |
| using namespace boost; |
| using namespace proto; |
| |
| struct int_convertible |
| { |
| int_convertible() {} |
| operator int() const { return 0; } |
| }; |
| |
| struct Input |
| : or_< |
| shift_right< terminal< std::istream & >, _ > |
| , shift_right< Input, _ > |
| > |
| {}; |
| |
| struct Output |
| : or_< |
| shift_left< terminal< std::ostream & >, _ > |
| , shift_left< Output, _ > |
| > |
| {}; |
| |
| terminal< std::istream & >::type const cin_ = {std::cin}; |
| terminal< std::ostream & >::type const cout_ = {std::cout}; |
| |
| struct Anything |
| : or_< |
| terminal<_> |
| , nary_expr<_, vararg<Anything> > |
| > |
| {}; |
| |
| void a_function() {} |
| |
| struct MyCases |
| { |
| template<typename Tag> |
| struct case_ |
| : proto::not_<proto::_> |
| {}; |
| }; |
| |
| template<> |
| struct MyCases::case_<proto::tag::shift_right> |
| : proto::_ |
| {}; |
| |
| template<> |
| struct MyCases::case_<proto::tag::plus> |
| : proto::_ |
| {}; |
| |
| enum binary_representation_enum |
| { |
| magnitude |
| , two_complement |
| }; |
| |
| typedef |
| mpl::integral_c<binary_representation_enum, magnitude> |
| magnitude_c; |
| |
| typedef |
| mpl::integral_c<binary_representation_enum, two_complement> |
| two_complement_c; |
| |
| template<typename Type, typename Representation> |
| struct number |
| {}; |
| |
| struct NumberGrammar |
| : proto::or_ < |
| proto::terminal<number<proto::_, two_complement_c> > |
| , proto::terminal<number<proto::_, magnitude_c> > |
| > |
| {}; |
| |
| struct my_terminal |
| {}; |
| |
| template<typename T> |
| struct a_template |
| {}; |
| |
| void test_matches() |
| { |
| assert_matches< _ >( lit(1) ); |
| assert_matches< _ >( as_child(1) ); |
| assert_matches< _ >( as_expr(1) ); |
| |
| assert_matches< terminal<int> >( lit(1) ); |
| assert_matches< terminal<int> >( as_child(1) ); |
| assert_matches< terminal<int> >( as_expr(1) ); |
| |
| assert_matches_not< terminal<int> >( lit('a') ); |
| assert_matches_not< terminal<int> >( as_child('a') ); |
| assert_matches_not< terminal<int> >( as_expr('a') ); |
| |
| assert_matches< terminal<convertible_to<int> > >( lit('a') ); |
| assert_matches< terminal<convertible_to<int> > >( as_child('a') ); |
| assert_matches< terminal<convertible_to<int> > >( as_expr('a') ); |
| |
| assert_matches_not< terminal<int> >( lit((int_convertible())) ); |
| assert_matches_not< terminal<int> >( as_child((int_convertible())) ); |
| assert_matches_not< terminal<int> >( as_expr((int_convertible())) ); |
| |
| assert_matches< terminal<convertible_to<int> > >( lit((int_convertible())) ); |
| assert_matches< terminal<convertible_to<int> > >( as_child((int_convertible())) ); |
| assert_matches< terminal<convertible_to<int> > >( as_expr((int_convertible())) ); |
| |
| assert_matches< if_<is_same<_value, int>() > >( lit(1) ); |
| assert_matches_not< if_<is_same<_value, int>() > >( lit('a') ); |
| |
| assert_matches< |
| and_< |
| terminal<_> |
| , if_<is_same<_value, int>() > |
| > |
| >( lit(1) ); |
| |
| assert_matches_not< |
| and_< |
| terminal<_> |
| , if_<is_same<_value, int>() > |
| > |
| >( lit('a') ); |
| |
| assert_matches< terminal<char const *> >( lit("hello") ); |
| assert_matches< terminal<char const *> >( as_child("hello") ); |
| assert_matches< terminal<char const *> >( as_expr("hello") ); |
| |
| assert_matches< terminal<char const[6]> >( lit("hello") ); |
| assert_matches< terminal<char const (&)[6]> >( as_child("hello") ); |
| assert_matches< terminal<char const[6]> >( as_expr("hello") ); |
| |
| assert_matches< terminal<char [6]> >( lit("hello") ); |
| assert_matches< terminal<char [6]> >( as_child("hello") ); |
| assert_matches< terminal<char [6]> >( as_expr("hello") ); |
| |
| assert_matches< terminal<char const[N]> >( lit("hello") ); |
| assert_matches< terminal<char const (&)[N]> >( as_child("hello") ); |
| assert_matches< terminal<char const[N]> >( as_expr("hello") ); |
| |
| assert_matches< terminal<char [N]> >( lit("hello") ); |
| assert_matches< terminal<char [N]> >( as_child("hello") ); |
| assert_matches< terminal<char [N]> >( as_expr("hello") ); |
| |
| assert_matches< terminal<wchar_t const[N]> >( lit(L"hello") ); |
| assert_matches< terminal<wchar_t const (&)[N]> >( as_child(L"hello") ); |
| assert_matches< terminal<wchar_t const[N]> >( as_expr(L"hello") ); |
| |
| assert_matches< terminal<wchar_t [N]> >( lit(L"hello") ); |
| assert_matches< terminal<wchar_t [N]> >( as_child(L"hello") ); |
| assert_matches< terminal<wchar_t [N]> >( as_expr(L"hello") ); |
| |
| assert_matches_not< if_<is_same<_value, int>()> >( lit("hello") ); |
| |
| assert_matches< terminal<std::string> >( lit(std::string("hello")) ); |
| assert_matches< terminal<std::string> >( as_child(std::string("hello")) ); |
| assert_matches< terminal<std::string> >( as_expr(std::string("hello")) ); |
| |
| assert_matches< terminal<std::basic_string<_> > >( lit(std::string("hello")) ); |
| assert_matches< terminal<std::basic_string<_> > >( as_child(std::string("hello")) ); |
| assert_matches< terminal<std::basic_string<_> > >( as_expr(std::string("hello")) ); |
| |
| assert_matches_not< terminal<std::basic_string<_> > >( lit(1) ); |
| assert_matches_not< terminal<std::basic_string<_> > >( as_child(1) ); |
| assert_matches_not< terminal<std::basic_string<_> > >( as_expr(1) ); |
| |
| assert_matches_not< terminal<std::basic_string<_,_,_> > >( lit(1) ); |
| assert_matches_not< terminal<std::basic_string<_,_,_> > >( as_child(1) ); |
| assert_matches_not< terminal<std::basic_string<_,_,_> > >( as_expr(1) ); |
| |
| #if BOOST_WORKAROUND(__HP_aCC, BOOST_TESTED_AT(61700)) |
| typedef std::string const const_string; |
| #else |
| typedef std::string const_string; |
| #endif |
| |
| assert_matches< terminal<std::basic_string<_> const & > >( lit(const_string("hello")) ); |
| assert_matches< terminal<std::basic_string<_> const & > >( as_child(const_string("hello")) ); |
| assert_matches_not< terminal<std::basic_string<_> const & > >( as_expr(const_string("hello")) ); |
| |
| assert_matches< terminal< void(&)() > >( lit(a_function) ); |
| assert_matches< terminal< void(&)() > >( as_child(a_function) ); |
| assert_matches< terminal< void(&)() > >( as_expr(a_function) ); |
| |
| assert_matches_not< terminal< void(*)() > >( lit(a_function) ); |
| assert_matches_not< terminal< void(*)() > >( as_child(a_function) ); |
| assert_matches_not< terminal< void(*)() > >( as_expr(a_function) ); |
| |
| assert_matches< terminal< convertible_to<void(*)()> > >( lit(a_function) ); |
| assert_matches< terminal< convertible_to<void(*)()> > >( as_child(a_function) ); |
| assert_matches< terminal< convertible_to<void(*)()> > >( as_expr(a_function) ); |
| |
| assert_matches< terminal< void(*)() > >( lit(&a_function) ); |
| assert_matches< terminal< void(*)() > >( as_child(&a_function) ); |
| assert_matches< terminal< void(*)() > >( as_expr(&a_function) ); |
| |
| assert_matches< terminal< void(* const &)() > >( lit(&a_function) ); |
| assert_matches< terminal< void(* const &)() > >( as_child(&a_function) ); |
| assert_matches_not< terminal< void(* const &)() > >( as_expr(&a_function) ); |
| |
| assert_matches< |
| or_< |
| if_<is_same<_value, char>() > |
| , if_<is_same<_value, int>() > |
| > |
| >( lit(1) ); |
| |
| assert_matches_not< |
| or_< |
| if_<is_same<_value, char>() > |
| , if_<is_same<_value, int>() > |
| > |
| >( lit(1u) ); |
| |
| assert_matches< Input >( cin_ >> 1 >> 2 >> 3 ); |
| assert_matches_not< Output >( cin_ >> 1 >> 2 >> 3 ); |
| |
| assert_matches< Output >( cout_ << 1 << 2 << 3 ); |
| assert_matches_not< Input >( cout_ << 1 << 2 << 3 ); |
| |
| assert_matches< function< terminal<int>, vararg< terminal<char> > > >( lit(1)('a','b','c','d') ); |
| assert_matches_not< function< terminal<int>, vararg< terminal<char> > > >( lit(1)('a','b','c',"d") ); |
| |
| assert_matches< Anything >( cout_ << 1 << +lit('a') << lit(1)('a','b','c',"d") ); |
| |
| assert_matches< proto::switch_<MyCases> >( lit(1) >> 'a' ); |
| assert_matches< proto::switch_<MyCases> >( lit(1) + 'a' ); |
| assert_matches_not< proto::switch_<MyCases> >( lit(1) << 'a' ); |
| |
| number<int, two_complement_c> num; |
| assert_matches<NumberGrammar>(proto::as_expr(num)); |
| |
| // check custom terminal types |
| { |
| proto::nullary_expr<my_terminal, int>::type i = {0}; |
| |
| assert_matches<proto::nullary_expr<my_terminal, _> >( i ); |
| assert_matches_not<proto::terminal<_> >( i ); |
| |
| proto::terminal<int>::type j = {0}; |
| assert_matches<proto::terminal<_> >( j ); |
| assert_matches_not<proto::nullary_expr<my_terminal, _> >( j ); |
| |
| assert_matches<proto::nullary_expr<_, _> >( i ); |
| } |
| |
| // check 0 and 1 arg forms or or_ and and_ |
| { |
| assert_matches< proto::and_<> >( lit(1) ); |
| assert_matches_not< proto::or_<> >( lit(1) ); |
| |
| assert_matches< proto::and_<proto::terminal<int> > >( lit(1) ); |
| assert_matches< proto::or_<proto::terminal<int> > >( lit(1) ); |
| } |
| |
| // Test lambda matches with arrays, a corner case that had |
| // a bug that was reported by Antoine de Maricourt on boost@lists.boost.org |
| { |
| a_template<int[3]> a; |
| assert_matches< proto::terminal< a_template<_> > >( lit(a) ); |
| } |
| } |
| |
| using namespace unit_test; |
| /////////////////////////////////////////////////////////////////////////////// |
| // init_unit_test_suite |
| // |
| test_suite* init_unit_test_suite( int argc, char* argv[] ) |
| { |
| test_suite *test = BOOST_TEST_SUITE("test proto::matches<>"); |
| |
| test->add(BOOST_TEST_CASE(&test_matches)); |
| |
| return test; |
| } |
| |