diff options
Diffstat (limited to 'src/boost/libs/proto/test')
24 files changed, 4832 insertions, 0 deletions
diff --git a/src/boost/libs/proto/test/Jamfile.v2 b/src/boost/libs/proto/test/Jamfile.v2 new file mode 100644 index 000000000..d765eae99 --- /dev/null +++ b/src/boost/libs/proto/test/Jamfile.v2 @@ -0,0 +1,50 @@ +# (C) Copyright 2004: 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) + +# bring in rules for testing +import testing ; + +project + : requirements + <toolset>intel:<debug-symbols>off + <toolset>msvc-7.1:<debug-symbols>off + <toolset>msvc-8.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-8.0:<define>_CRT_SECURE_NO_DEPRECATE + <toolset>msvc-9.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-10.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-11.0:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc-11.0:<define>_SCL_SECURE_NO_WARNINGS + <toolset>gcc:<cxxflags>-ftemplate-depth-1024 + <library>/boost/test//boost_unit_test_framework + <link>static +# <define>BOOST_PROTO_DONT_USE_PREPROCESSED_FILES + ; + +test-suite "proto" + : + [ run calculator.cpp ] + [ run constrained_ops.cpp ] + [ run cpp-next_bug.cpp ] + [ run deep_copy.cpp ] + [ run display_expr.cpp ] + [ run deduce_domain.cpp ] + [ run env_var.cpp ] + [ run examples.cpp ] + [ run external_transforms.cpp ] + [ run lambda.cpp ] + [ run make_expr.cpp ] + [ run matches.cpp ] + [ run flatten.cpp ] + [ run switch.cpp ] + [ run toy_spirit.cpp ] + [ run toy_spirit2.cpp ] + [ run make.cpp ] + [ run mem_ptr.cpp : : : <toolset>msvc:<cxxflags>/wd4355 ] + [ run mpl.cpp ] + [ run noinvoke.cpp ] + [ run pack_expansion.cpp ] + [ run protect.cpp ] + [ compile bug2407.cpp ] + ; + diff --git a/src/boost/libs/proto/test/bug2407.cpp b/src/boost/libs/proto/test/bug2407.cpp new file mode 100644 index 000000000..c67bd55cd --- /dev/null +++ b/src/boost/libs/proto/test/bug2407.cpp @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////// +// bug2407.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 <iostream> +#include <boost/proto/proto.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<class E> +struct e; + +struct g + : proto::or_< + proto::terminal<int> + , proto::plus<g,g> + > +{}; + +struct d + : proto::domain<proto::generator<e>, g> +{}; + +template<class E> +struct e + : proto::extends<E, e<E>, d> +{ + BOOST_MPL_ASSERT((proto::matches<E, g>)); + + e(E const &x = E()) + : proto::extends<E, e<E>, d>(x) + {} +}; + +e<proto::terminal<int>::type> i; + +template<class E> +std::ostream &operator<<(std::ostream &sout, e<E> const &x) +{ + return sout; +} + +int main() +{ + std::cout << (i+i); +} diff --git a/src/boost/libs/proto/test/calculator.cpp b/src/boost/libs/proto/test/calculator.cpp new file mode 100644 index 000000000..ceea6c72a --- /dev/null +++ b/src/boost/libs/proto/test/calculator.cpp @@ -0,0 +1,109 @@ +/////////////////////////////////////////////////////////////////////////////// +// calculator.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 <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/test/unit_test.hpp> + +using namespace boost; + +struct placeholder {}; +proto::terminal<placeholder>::type const _1 = {{}}; + +struct calculator : proto::callable_context<calculator const> +{ + typedef int result_type; + + calculator(int i) + : i_(i) + {} + + int operator ()(proto::tag::terminal, placeholder) const + { + return this->i_; + } + + int operator ()(proto::tag::terminal, int j) const + { + return j; + } + + template<typename Left, typename Right> + int operator ()(proto::tag::plus, Left const &left, Right const &right) const + { + return proto::eval(left, *this) + proto::eval(right, *this); + } + + template<typename Left, typename Right> + int operator ()(proto::tag::minus, Left const &left, Right const &right) const + { + return proto::eval(left, *this) - proto::eval(right, *this); + } + + template<typename Left, typename Right> + int operator ()(proto::tag::multiplies, Left const &left, Right const &right) const + { + return proto::eval(left, *this) * proto::eval(right, *this); + } + + template<typename Left, typename Right> + int operator ()(proto::tag::divides, Left const &left, Right const &right) const + { + return proto::eval(left, *this) / proto::eval(right, *this); + } + +private: + int i_; +}; + +template<typename Fun, typename Expr> +struct functional +{ + typedef typename proto::result_of::eval<Expr, Fun>::type result_type; + + functional(Expr const &expr) + : expr_(expr) + {} + + template<typename T> + result_type operator ()(T const &t) const + { + Fun fun(t); + return proto::eval(this->expr_, fun); + } + +private: + Expr const &expr_; +}; + +template<typename Fun, typename Expr> +functional<Fun, Expr> as(Expr const &expr) +{ + return functional<Fun, Expr>(expr); +} + +void test_calculator() +{ + BOOST_CHECK_EQUAL(10, proto::eval(((_1 + 42)-3)/4, calculator(1))); + BOOST_CHECK_EQUAL(11, proto::eval(((_1 + 42)-3)/4, calculator(5))); + + BOOST_CHECK_EQUAL(10, as<calculator>(((_1 + 42)-3)/4)(1)); + BOOST_CHECK_EQUAL(11, as<calculator>(((_1 + 42)-3)/4)(5)); +} + +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 immediate evaluation of proto parse trees"); + + test->add(BOOST_TEST_CASE(&test_calculator)); + + return test; +} diff --git a/src/boost/libs/proto/test/constrained_ops.cpp b/src/boost/libs/proto/test/constrained_ops.cpp new file mode 100644 index 000000000..c638ddc36 --- /dev/null +++ b/src/boost/libs/proto/test/constrained_ops.cpp @@ -0,0 +1,131 @@ +/////////////////////////////////////////////////////////////////////////////// +// constrained_ops.cpp +// +// Copyright 2010 Thomas Heller +// Copyright 2011 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 <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +using namespace boost; + +typedef proto::terminal<int>::type term; + +struct equation; + +struct addition: + proto::or_ + < + proto::terminal<proto::_>, + proto::plus<addition, addition> + > +{}; + +struct equation: + proto::or_ + < + proto::equal_to<addition, addition> + > +{}; + +template<class Expr> +struct extension; + +struct my_domain: + proto::domain + < + proto::pod_generator<extension>, + equation, + proto::default_domain + > +{}; + +template<class Expr> +struct lhs_extension; + +struct my_lhs_domain: + proto::domain + < + proto::pod_generator<lhs_extension>, + addition, + my_domain + > +{}; + +template<class Expr> +struct rhs_extension; + +struct my_rhs_domain: + proto::domain + < + proto::pod_generator<rhs_extension>, + addition, + my_domain + > +{}; + +template<class Expr> +struct extension +{ + BOOST_PROTO_BASIC_EXTENDS( + Expr + , extension<Expr> + , my_domain + ) + + void test() const + {} +}; + +template<class Expr> +struct lhs_extension +{ + BOOST_PROTO_BASIC_EXTENDS( + Expr + , lhs_extension<Expr> + , my_lhs_domain + ) +}; + +template<class Expr> +struct rhs_extension +{ + BOOST_PROTO_BASIC_EXTENDS( + Expr + , rhs_extension<Expr> + , my_rhs_domain + ) +}; + +void test_constrained_ops() +{ + lhs_extension<term> const i = {}; + rhs_extension<term> const j = {}; + + proto::assert_matches_not<equation>(i); // false + proto::assert_matches_not<equation>(j); // false + proto::assert_matches_not<equation>(i + i); // false + proto::assert_matches_not<equation>(j + j); // false +#if 0 + proto::assert_matches_not<equation>(i + j); // compile error (by design) + proto::assert_matches_not<equation>(j + i); // compile error (by design) +#endif + proto::assert_matches<equation>(i == j); // true + proto::assert_matches<equation>(i == j + j); // true + proto::assert_matches<equation>(i + i == j); // true + proto::assert_matches<equation>(i + i == j + j); // true +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test constrained EDSLs"); + test->add(BOOST_TEST_CASE(&test_constrained_ops)); + return test; +} diff --git a/src/boost/libs/proto/test/cpp-next_bug.cpp b/src/boost/libs/proto/test/cpp-next_bug.cpp new file mode 100644 index 000000000..2f4b8b474 --- /dev/null +++ b/src/boost/libs/proto/test/cpp-next_bug.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////// +// cpp-next_bug.hpp +// +// Copyright 2012 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 <vector> +#include <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +namespace linear_algebra +{ + // A trait that returns true only for std::vector + template<typename T> + struct is_std_vector + : mpl::false_ + {}; + + template<typename T, typename A> + struct is_std_vector<std::vector<T, A> > + : mpl::true_ + {}; + + // A type used as a domain for linear algebra expressions + struct linear_algebra_domain + : proto::domain<> + {}; + + // Define all the operator overloads for combining std::vectors + BOOST_PROTO_DEFINE_OPERATORS(is_std_vector, linear_algebra_domain) + + // Take any expression and turn each node + // into a subscript expression, using the + // state as the RHS. + struct Distribute + : proto::or_< + proto::when<proto::terminal<_>, proto::_make_subscript(_, proto::_state)> + , proto::plus<Distribute, Distribute> + > + {}; + + struct Optimize + : proto::or_< + proto::when< + proto::subscript<Distribute, proto::terminal<_> >, + Distribute(proto::_left, proto::_right) + > + , proto::plus<Optimize, Optimize> + , proto::terminal<_> + > + {}; +} + +static const int celems = 4; +static int const value[celems] = {1,2,3,4}; +std::vector<int> A(value, value+celems), B(A); + +void test1() +{ + using namespace linear_algebra; + proto::_default<> eval; + BOOST_CHECK_EQUAL(8, eval(Optimize()((A + B)[3]))); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test for a problem reported on the cpp-next.com blog"); + + test->add(BOOST_TEST_CASE(&test1)); + + return test; +} diff --git a/src/boost/libs/proto/test/deduce_domain.cpp b/src/boost/libs/proto/test/deduce_domain.cpp new file mode 100644 index 000000000..47215fdc5 --- /dev/null +++ b/src/boost/libs/proto/test/deduce_domain.cpp @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////// +// deduce_domain.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) + +// Avoid a compile-time check inside the deduce_domain code. +#define BOOST_PROTO_ASSERT_VALID_DOMAIN(DOM) typedef DOM DOM ## _ + +#include <boost/proto/core.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> + +namespace proto = boost::proto; +using proto::_; + +struct D0 : proto::domain<> +{ +}; + +struct D1 : proto::domain<proto::default_generator, _, D0> +{ +}; + +struct D2 : proto::domain<proto::default_generator, _, D0> +{ +}; + +struct D3 : proto::domain<> +{ +}; + +struct DD0 : proto::domain<proto::default_generator, _, proto::default_domain> +{ +}; + +struct DD1 : proto::domain<proto::default_generator, _, proto::default_domain> +{ +}; + +struct DD2 : proto::domain<proto::default_generator, _, proto::default_domain> +{ +}; + +struct DD3 : proto::domain<proto::default_generator, _, DD2> +{ +}; + +struct DD4 : proto::domain<proto::default_generator, _, DD2> +{ +}; + +void test1() +{ + using boost::is_same; + + //* + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, proto::default_domain, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, proto::default_domain>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, proto::default_domain, proto::default_domain>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, D0, proto::default_domain>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, proto::default_domain, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, proto::default_domain, proto::default_domain>::type, proto::default_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, DD0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, DD0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, DD0, DD0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, D0, DD0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, DD0, DD0>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, proto::default_domain, DD0>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, proto::default_domain>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, proto::default_domain, DD0>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<proto::default_domain, DD0, proto::default_domain>::type, DD0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, proto::default_domain>::type, DD0>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D1, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D1, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D0, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D0, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D0>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D1>::type, D1>)); + + // Very tricky to get right + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D2, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D1, D2>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D1, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D2, D2>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D2, D1>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D2>::type, D0>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D1, D1>::type, D1>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D0, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D3, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D0, D3>::type, proto::detail::not_a_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D1, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D0, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D3, D0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D3, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D0, D1, D3>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D0, D3>::type, proto::detail::not_a_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D1, D2>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D3, D2, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D3, D2>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D3, D1>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D2, D1, D3>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<D1, D2, D3>::type, proto::detail::not_a_domain>)); + + // These should be ambiguous. + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD1, DD0, DD0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD1, DD0>::type, proto::detail::not_a_domain>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD0, DD0, DD1>::type, proto::detail::not_a_domain>)); + + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD3, DD2, DD2>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD2, DD3, DD2>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD2, DD2, DD3>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD3, DD4, DD4>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD4, DD3, DD4>::type, DD2>)); + BOOST_MPL_ASSERT((is_same<proto::detail::common_domain3<DD4, DD4, DD3>::type, DD2>)); + //*/ +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test deducing domains from sub-domains"); + + test->add(BOOST_TEST_CASE(&test1)); + + return test; +} diff --git a/src/boost/libs/proto/test/deep_copy.cpp b/src/boost/libs/proto/test/deep_copy.cpp new file mode 100644 index 000000000..42d752828 --- /dev/null +++ b/src/boost/libs/proto/test/deep_copy.cpp @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////// +// deep_copy.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 <iostream> +#include <boost/utility/addressof.hpp> +#include <boost/proto/core.hpp> +#include <boost/test/unit_test.hpp> + +using namespace boost; + +void foo() {} + +void test1() +{ + using namespace proto; + + int i = 42; + terminal<int &>::type t1 = {i}; + terminal<int>::type r1 = deep_copy(t1); + BOOST_CHECK_EQUAL(42, value(r1)); + + plus<terminal<int>::type, terminal<int>::type>::type r2 = deep_copy(t1 + 24); + BOOST_CHECK_EQUAL(42, value(left(r2))); + BOOST_CHECK_EQUAL(24, value(right(r2))); + + char buf[16] = {'\0'}; + terminal<char (&)[16]>::type t3 = {buf}; + terminal<char[16]>::type r3 = deep_copy(t3); + + terminal<void(&)()>::type t4 = {foo}; + plus<terminal<void(&)()>::type, terminal<int>::type>::type r4 = deep_copy(t4 + t1); + BOOST_CHECK_EQUAL(42, value(right(r4))); + BOOST_CHECK_EQUAL(&foo, &value(left(r4))); + + terminal<std::ostream &>::type cout_ = {std::cout}; + shift_left<terminal<std::ostream &>::type, terminal<int>::type>::type r5 = deep_copy(cout_ << t1); + BOOST_CHECK_EQUAL(42, value(right(r5))); + BOOST_CHECK_EQUAL(boost::addressof(std::cout), boost::addressof(value(left(r5)))); +} + +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 deep_copy of proto parse trees"); + + test->add(BOOST_TEST_CASE(&test1)); + + return test; +} diff --git a/src/boost/libs/proto/test/display_expr.cpp b/src/boost/libs/proto/test/display_expr.cpp new file mode 100644 index 000000000..05c47ff5f --- /dev/null +++ b/src/boost/libs/proto/test/display_expr.cpp @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////////// +// display_expr.cpp +// +// Copyright 2010 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 <sstream> +#include <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +struct A {}; +struct B : A {}; +std::ostream& operator<<( std::ostream& out, const A& ) { return out << "this is A!"; } + +struct C {}; + +void test_display_expr() +{ + // https://svn.boost.org/trac/boost/ticket/4910 + proto::terminal<int>::type i = {0}; + + { + std::stringstream sout; + proto::display_expr(i + A(), sout); + BOOST_CHECK_EQUAL(sout.str(), std::string( + "plus(\n" + " terminal(0)\n" + " , terminal(this is A!)\n" + ")\n")); + } + + { + std::stringstream sout; + proto::display_expr(i + B(), sout); + BOOST_CHECK_EQUAL(sout.str(), std::string( + "plus(\n" + " terminal(0)\n" + " , terminal(this is A!)\n" + ")\n")); + } + + { + std::stringstream sout; + char const * Cname = BOOST_CORE_TYPEID(C).name(); + proto::display_expr(i + C(), sout); + BOOST_CHECK_EQUAL(sout.str(), std::string( + "plus(\n" + " terminal(0)\n" + " , terminal(") + Cname + std::string(")\n" + ")\n")); + } +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test display_expr() function"); + test->add(BOOST_TEST_CASE(&test_display_expr)); + return test; +} diff --git a/src/boost/libs/proto/test/env_var.cpp b/src/boost/libs/proto/test/env_var.cpp new file mode 100644 index 000000000..14ce8be9b --- /dev/null +++ b/src/boost/libs/proto/test/env_var.cpp @@ -0,0 +1,297 @@ +/////////////////////////////////////////////////////////////////////////////// +// env_var.cpp +// +// Copyright 2012 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 <cstring> +#include <sstream> +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +namespace proto = boost::proto; + +BOOST_PROTO_DEFINE_ENV_VAR(tag0_type, tag0); + +struct abstract +{ + virtual ~abstract() = 0; +}; + +abstract::~abstract() {} + +struct concrete : abstract +{ + ~concrete() {} +}; + +template<typename Tag, typename Env> +void assert_has_env_var(Env const &) +{ + BOOST_MPL_ASSERT((proto::result_of::has_env_var<Env, Tag>)); +} + +template<typename Tag, typename Env> +void assert_has_env_var_not(Env const &) +{ + BOOST_MPL_ASSERT_NOT((proto::result_of::has_env_var<Env, Tag>)); +} + +void test_is_env() +{ + BOOST_MPL_ASSERT_NOT((proto::is_env<int>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<int &>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<int const &>)); + + BOOST_MPL_ASSERT_NOT((proto::is_env<abstract>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<abstract &>)); + BOOST_MPL_ASSERT_NOT((proto::is_env<abstract const &>)); + + BOOST_MPL_ASSERT((proto::is_env<proto::empty_env>)); + BOOST_MPL_ASSERT((proto::is_env<proto::empty_env &>)); + BOOST_MPL_ASSERT((proto::is_env<proto::empty_env const &>)); + + BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> >)); + BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> &>)); + BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> const &>)); +} + +void test_as_env() +{ + proto::env<proto::data_type, int> e0 = proto::as_env(2); + BOOST_CHECK_EQUAL(e0[proto::data], 2); + assert_has_env_var<proto::data_type>(e0); + assert_has_env_var_not<tag0_type>(e0); + + int i = 39; + proto::env<proto::data_type, int &> e1 = proto::as_env(boost::ref(i)); + assert_has_env_var<proto::data_type>(i); + assert_has_env_var_not<tag0_type>(i); + BOOST_CHECK_EQUAL(e1[proto::data], 39); + BOOST_CHECK_EQUAL(&e1[proto::data], &i); + + proto::empty_env e2 = proto::as_env(proto::empty_env()); + proto::env<proto::data_type, int &> e3 = proto::as_env(e1); + proto::env<proto::data_type, int &> & e4 = proto::as_env(boost::ref(e1)); + BOOST_CHECK_EQUAL(&e4, &e1); + + concrete c; + abstract &a = c; + std::stringstream sout; + int rgi[2] = {}; + proto::env<proto::data_type, abstract &> e5 = proto::as_env(a); + proto::env<proto::data_type, std::stringstream &> e6 = proto::as_env(sout); + BOOST_CHECK_EQUAL(&e6[proto::data], &sout); + proto::env<proto::data_type, int(&)[2]> e7 = proto::as_env(rgi); + BOOST_CHECK_EQUAL(&e7[proto::data][0], &rgi[0]); + proto::env<proto::data_type, void(&)()> e8 = proto::as_env(test_as_env); + BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); +} + +void test_comma() +{ + proto::env<proto::data_type, int> e0 = (proto::data = 1); + BOOST_CHECK_EQUAL(e0[proto::data], 1); + + int i = 39; + proto::env<proto::data_type, int &> e1 = (proto::data = boost::ref(i)); + BOOST_CHECK_EQUAL(e1[proto::data], 39); + BOOST_CHECK_EQUAL(&e1[proto::data], &i); + + concrete c; + abstract &a = c; + std::stringstream sout; + int rgi[2] = {}; + proto::env<proto::data_type, abstract &> e5 = (proto::data = a); + proto::env<proto::data_type, std::stringstream &> e6 = (proto::data = sout); + BOOST_CHECK_EQUAL(&e6[proto::data], &sout); + proto::env<proto::data_type, int(&)[2]> e7 = (proto::data = rgi); + BOOST_CHECK_EQUAL(&e7[proto::data][0], &rgi[0]); + // The test below fails on msvc due to a compiler bug + // note: <https://connect.microsoft.com/VisualStudio/feedback/details/754684/premature-decay-of-function-types-in-overloaded-assignment-operator> +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) + proto::env<proto::data_type, void(&)()> e8 = (proto::data = boost::ref(test_as_env)); + BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); +#else + proto::env<proto::data_type, void(&)()> e8 = (proto::data = test_as_env); + BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); +#endif + + proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, int> + > e9 = (proto::data = 1, tag0 = "hello"); + BOOST_CHECK_EQUAL(e9[proto::data], 1); + BOOST_CHECK_EQUAL(0, std::strcmp(e9[tag0], "hello")); + + proto::env< + tag0_type + , int + , proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, int> + > + > e10 = (proto::data = 1, tag0 = "hello", tag0 = 42); + BOOST_CHECK_EQUAL(e10[proto::data], 1); + BOOST_CHECK_EQUAL(e10[tag0], 42); + + proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, abstract &> + > e11 = (a, tag0 = "hello"); + BOOST_CHECK_EQUAL(&e11[proto::data], &a); + BOOST_CHECK_EQUAL(0, std::strcmp(e11[tag0], "hello")); + + proto::env< + tag0_type + , int + , proto::env< + tag0_type + , char const (&)[6] + , proto::env<proto::data_type, abstract &> + > + > e12 = (a, tag0 = "hello", tag0 = 42); + BOOST_CHECK_EQUAL(&e12[proto::data], &a); + BOOST_CHECK_EQUAL(e12[tag0], 42); + + proto::env<tag0_type, int> e13 = (proto::empty_env(), tag0 = 42); + BOOST_CHECK_EQUAL(e13[tag0], 42); + assert_has_env_var<tag0_type>(e13); + assert_has_env_var_not<proto::data_type>(e13); + + proto::empty_env empty; + proto::env<tag0_type, int> e14 = (boost::ref(empty), tag0 = 42); + BOOST_CHECK_EQUAL(e14[tag0], 42); + + proto::env< + proto::data_type + , char const (&)[6] + , proto::env<tag0_type, int> + > e15 = (boost::ref(e14), proto::data = "hello"); + BOOST_CHECK_EQUAL(e15[tag0], 42); + BOOST_CHECK_EQUAL(0, std::strcmp(e15[proto::data], "hello")); + + proto::env< + proto::data_type + , char const (&)[6] + , proto::env<tag0_type, int> + > e16 = (proto::as_env(boost::ref(e14)), proto::data = "hello"); + BOOST_CHECK_EQUAL(e16[tag0], 42); + BOOST_CHECK_EQUAL(0, std::strcmp(e16[proto::data], "hello")); +} + +void test_result_of_env_var() +{ + typedef proto::empty_env env0_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type, proto::data_type>::type, proto::key_not_found>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type &, proto::data_type>::type, proto::key_not_found>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type const &, proto::data_type>::type, proto::key_not_found>)); + + typedef proto::env<proto::data_type, int> env1_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type, proto::data_type>::type, int>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type &, proto::data_type>::type, int>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type const &, proto::data_type>::type, int>)); + + typedef proto::env<proto::data_type, int &> env2_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type, proto::data_type>::type, int &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type &, proto::data_type>::type, int &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type const &, proto::data_type>::type, int &>)); + + typedef proto::env<proto::data_type, double, proto::env<tag0_type, abstract &> > env3_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type, proto::data_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type, tag0_type>::type, abstract &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type &, proto::data_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type &, tag0_type>::type, abstract &>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type const &, proto::data_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type const &, tag0_type>::type, abstract &>)); + + typedef proto::env<tag0_type, double, proto::env<tag0_type, abstract &> > env4_type; + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type, tag0_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type &, tag0_type>::type, double>)); + BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type const &, tag0_type>::type, double>)); +} + +void test_env_var() +{ + proto::key_not_found x0 = proto::env_var<proto::data_type>(proto::empty_env()); + proto::key_not_found x1 = proto::env_var<proto::data_type>(tag0 = 42); + int x2 = proto::env_var<tag0_type>(tag0 = 42); + BOOST_CHECK_EQUAL(x2, 42); + int x3 = proto::functional::env_var<tag0_type>()(tag0 = 42); + BOOST_CHECK_EQUAL(x3, 42); + + int i = 43; + int & x4 = proto::env_var<tag0_type>(tag0 = boost::ref(i)); + BOOST_CHECK_EQUAL(&x4, &i); + int & x5 = proto::functional::env_var<tag0_type>()(tag0 = boost::ref(i)); + BOOST_CHECK_EQUAL(&x5, &i); + + concrete c; + abstract &a = c; + abstract &x6 = proto::env_var<tag0_type>(tag0 = a); + BOOST_CHECK_EQUAL(&x6, &a); + abstract &x7 = proto::functional::env_var<tag0_type>()(tag0 = a); + BOOST_CHECK_EQUAL(&x7, &a); + + abstract &x8 = proto::env_var<tag0_type>((42, tag0 = a)); + BOOST_CHECK_EQUAL(&x8, &a); + abstract &x9 = proto::functional::env_var<tag0_type>()((42, tag0 = a)); + BOOST_CHECK_EQUAL(&x9, &a); +} + +void test_env_var_tfx() +{ + typedef proto::terminal<int>::type int_; + int_ i = {42}; + + // tests for _env + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &)>::type, proto::empty_env>)); + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int)>::type, proto::empty_env>)); + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float &)>::type, float &>)); + + // Bummer, is there any way around this? +#ifdef BOOST_RESULT_OF_USE_DECLTYPE + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float)>::type, float const &>)); + BOOST_MPL_ASSERT((boost::is_same<boost::tr1_result_of<proto::_env(int_ &, int &, float)>::type, float>)); +#else + BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float)>::type, float>)); + BOOST_MPL_ASSERT((boost::is_same<boost::tr1_result_of<proto::_env(int_ &, int &, float)>::type, float>)); +#endif + + double d = 3.14; + double & rd = proto::_env()(i, 0, d); + BOOST_CHECK_EQUAL(&d, &rd); + + proto::env<proto::data_type, int> e0 = proto::_env()(i, 0, proto::as_env(42)); + BOOST_CHECK_EQUAL(e0[proto::data], 42); + + proto::env<proto::data_type, int> e1 = proto::_env()(i, 0, proto::functional::as_env()(42)); + BOOST_CHECK_EQUAL(e1[proto::data], 42); + + proto::env<proto::data_type, int> e2 = proto::_env()(i, 0, (proto::data = 42)); + BOOST_CHECK_EQUAL(e2[proto::data], 42); + + proto::env<proto::data_type, int, proto::env<proto::data_type, int> > e3 = proto::_env()(i, 0, (42, proto::data = 43)); + BOOST_CHECK_EQUAL(e3[proto::data], 43); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test for environment variables"); + test->add(BOOST_TEST_CASE(&test_as_env)); + test->add(BOOST_TEST_CASE(&test_comma)); + test->add(BOOST_TEST_CASE(&test_result_of_env_var)); + test->add(BOOST_TEST_CASE(&test_env_var)); + test->add(BOOST_TEST_CASE(&test_env_var_tfx)); + return test; +} diff --git a/src/boost/libs/proto/test/examples.cpp b/src/boost/libs/proto/test/examples.cpp new file mode 100644 index 000000000..35769bca2 --- /dev/null +++ b/src/boost/libs/proto/test/examples.cpp @@ -0,0 +1,498 @@ +/////////////////////////////////////////////////////////////////////////////// +// examples.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 <iostream> +#include <boost/config.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/proto/functional/fusion.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/fusion/include/cons.hpp> +#include <boost/fusion/include/tuple.hpp> +#include <boost/fusion/include/pop_front.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +template<int I> +struct placeholder +{}; + +namespace test1 +{ +//[ CalcGrammar + // This is the grammar for calculator expressions, + // to which we will attach transforms for computing + // the expressions' arity. + /*<< A Calculator expression is ... >>*/ + struct CalcArity + : proto::or_< + /*<< _1, or ... >>*/ + proto::terminal< placeholder<0> > + /*<< _2, or ... >>*/ + , proto::terminal< placeholder<1> > + /*<< some other terminal, or ... >>*/ + , proto::terminal< _ > + /*<< a unary expression where the operand is a calculator expression, or ... >>*/ + , proto::unary_expr< _, CalcArity > + /*<< a binary expression where the operands are calculator expressions >>*/ + , proto::binary_expr< _, CalcArity, CalcArity > + > + {}; +//] +} + +//[ binary_arity +/*<< The `CalculatorArity` is a transform for calculating +the arity of a calculator expression. It will be define in +terms of `binary_arity`, which is defined in terms of +`CalculatorArity`; hence, the definition is recursive.>>*/ +struct CalculatorArity; + +// A custom transform that returns the arity of a unary +// calculator expression by finding the arity of the +// child expression. +struct unary_arity + /*<< Custom transforms should inherit from + transform<>. In some cases, (e.g., when the transform + is a template), it is also necessary to specialize + the proto::is_callable<> trait. >>*/ + : proto::transform<unary_arity> +{ + template<typename Expr, typename State, typename Data> + /*<< Transforms have a nested `impl<>` that is + a valid TR1 function object. >>*/ + struct impl + : proto::transform_impl<Expr, State, Data> + { + /*<< Get the child. >>*/ + typedef typename proto::result_of::child<Expr>::type child_expr; + + /*<< Apply `CalculatorArity` to find the arity of the child. >>*/ + typedef typename boost::result_of<CalculatorArity(child_expr, State, Data)>::type result_type; + + /*<< The `unary_arity` transform doesn't have an interesting + runtime counterpart, so just return a default-constructed object + of the correct type. >>*/ + result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const + { + return result_type(); + } + }; +}; + +// A custom transform that returns the arity of a binary +// calculator expression by finding the maximum of the +// arities of the mpl::int_<2> child expressions. +struct binary_arity + /*<< All custom transforms should inherit from + transform. In some cases, (e.g., when the transform + is a template), it is also necessary to specialize + the proto::is_callable<> trait. >>*/ + : proto::transform<binary_arity> +{ + template<typename Expr, typename State, typename Data> + /*<< Transforms have a nested `impl<>` that is + a valid TR1 function object. >>*/ + struct impl + : proto::transform_impl<Expr, State, Data> + { + /*<< Get the left and right children. >>*/ + typedef typename proto::result_of::left<Expr>::type left_expr; + typedef typename proto::result_of::right<Expr>::type right_expr; + + /*<< Apply `CalculatorArity` to find the arity of the left and right children. >>*/ + typedef typename boost::result_of<CalculatorArity(left_expr, State, Data)>::type left_arity; + typedef typename boost::result_of<CalculatorArity(right_expr, State, Data)>::type right_arity; + + /*<< The return type is the maximum of the children's arities. >>*/ + typedef typename mpl::max<left_arity, right_arity>::type result_type; + + /*<< The `unary_arity` transform doesn't have an interesting + runtime counterpart, so just return a default-constructed object + of the correct type. >>*/ + result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const + { + return result_type(); + } + }; +}; +//] + +proto::terminal< placeholder<0> >::type const _1 = {}; +proto::terminal< placeholder<1> >::type const _2 = {}; + +//[ CalculatorArityGrammar +struct CalculatorArity + : proto::or_< + proto::when< proto::terminal< placeholder<0> >, mpl::int_<1>() > + , proto::when< proto::terminal< placeholder<1> >, mpl::int_<2>() > + , proto::when< proto::terminal<_>, mpl::int_<0>() > + , proto::when< proto::unary_expr<_, _>, unary_arity > + , proto::when< proto::binary_expr<_, _, _>, binary_arity > + > +{}; +//] + +//[ CalcArity +struct CalcArity + : proto::or_< + proto::when< proto::terminal< placeholder<0> >, + mpl::int_<1>() + > + , proto::when< proto::terminal< placeholder<1> >, + mpl::int_<2>() + > + , proto::when< proto::terminal<_>, + mpl::int_<0>() + > + , proto::when< proto::unary_expr<_, CalcArity>, + CalcArity(proto::_child) + > + , proto::when< proto::binary_expr<_, CalcArity, CalcArity>, + mpl::max<CalcArity(proto::_left), + CalcArity(proto::_right)>() + > + > +{}; +//] + +// BUGBUG find workaround for this +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#define _pop_front(x) call<proto::_pop_front(x)> +#define _value(x) call<proto::_value(x)> +#endif + +//[ AsArgList +// This transform matches function invocations such as foo(1,'a',"b") +// and transforms them into Fusion cons lists of their arguments. In this +// case, the result would be cons(1, cons('a', cons("b", nil()))). +struct ArgsAsList + : proto::when< + proto::function<proto::terminal<_>, proto::vararg<proto::terminal<_> > > + /*<< Use a `fold<>` transform to iterate over the children of this + node in forward order, building a fusion list from front to back. >>*/ + , proto::fold< + /*<< The first child expression of a `function<>` node is the + function being invoked. We don't want that in our list, so use + `pop_front()` to remove it. >>*/ + proto::_pop_front(_) + /*<< `nil` is the initial state used by the `fold<>` transform. >>*/ + , fusion::nil() + /*<< Put the rest of the function arguments in a fusion cons + list. >>*/ + , proto::functional::push_back(proto::_state, proto::_value) + > + > +{}; +//] + +//[ FoldTreeToList +// This transform matches expressions of the form (_1=1,'a',"b") +// (note the use of the comma operator) and transforms it into a +// Fusion cons list of their arguments. In this case, the result +// would be cons(1, cons('a', cons("b", nil()))). +struct FoldTreeToList + : proto::or_< + // This grammar describes what counts as the terminals in expressions + // of the form (_1=1,'a',"b"), which will be flattened using + // reverse_fold_tree<> below. + proto::when< proto::assign<_, proto::terminal<_> > + , proto::_value(proto::_right) + > + , proto::when< proto::terminal<_> + , proto::_value + > + , proto::when< + proto::comma<FoldTreeToList, FoldTreeToList> + /*<< Fold all terminals that are separated by commas into a Fusion cons list. >>*/ + , proto::reverse_fold_tree< + _ + , fusion::nil() + , fusion::cons<FoldTreeToList, proto::_state>(FoldTreeToList, proto::_state) + > + > + > +{}; +//] + +//[ Promote +// This transform finds all float terminals in an expression and promotes +// them to doubles. +struct Promote + : proto::or_< + /*<< Match a `terminal<float>`, then construct a + `terminal<double>::type` with the `float`. >>*/ + proto::when<proto::terminal<float>, proto::terminal<double>::type(proto::_value) > + , proto::when<proto::terminal<_> > + /*<< `nary_expr<>` has a pass-through transform which + will transform each child sub-expression using the + `Promote` transform. >>*/ + , proto::when<proto::nary_expr<_, proto::vararg<Promote> > > + > +{}; +//] + +//[ LazyMakePair +struct make_pair_tag {}; +proto::terminal<make_pair_tag>::type const make_pair_ = {{}}; + +// This transform matches lazy function invocations like +// `make_pair_(1, 3.14)` and actually builds a `std::pair<>` +// from the arguments. +struct MakePair + : proto::when< + /*<< Match expressions like `make_pair_(1, 3.14)` >>*/ + proto::function< + proto::terminal<make_pair_tag> + , proto::terminal<_> + , proto::terminal<_> + > + /*<< Return `std::pair<F,S>(f,s)` where `f` and `s` are the + first and second arguments to the lazy `make_pair_()` function. + (This uses `proto::make<>` under the covers to evaluate the + transform.)>>*/ + , std::pair< + proto::_value(proto::_child1) + , proto::_value(proto::_child2) + >( + proto::_value(proto::_child1) + , proto::_value(proto::_child2) + ) + > +{}; +//] + +namespace lazy_make_pair2 +{ + //[ LazyMakePair2 + struct make_pair_tag {}; + proto::terminal<make_pair_tag>::type const make_pair_ = {{}}; + + // Like std::make_pair(), only as a function object. + /*<<Inheriting from `proto::callable` lets Proto know + that this is a callable transform, so we can use it + without having to wrap it in `proto::call<>`.>>*/ + struct make_pair : proto::callable + { + template<typename Sig> struct result; + + template<typename This, typename First, typename Second> + struct result<This(First, Second)> + { + typedef + std::pair< + BOOST_PROTO_UNCVREF(First) + , BOOST_PROTO_UNCVREF(Second) + > + type; + }; + + template<typename First, typename Second> + std::pair<First, Second> + operator()(First const &first, Second const &second) const + { + return std::make_pair(first, second); + } + }; + + // This transform matches lazy function invocations like + // `make_pair_(1, 3.14)` and actually builds a `std::pair<>` + // from the arguments. + struct MakePair + : proto::when< + /*<< Match expressions like `make_pair_(1, 3.14)` >>*/ + proto::function< + proto::terminal<make_pair_tag> + , proto::terminal<_> + , proto::terminal<_> + > + /*<< Return `make_pair()(f,s)` where `f` and `s` are the + first and second arguments to the lazy `make_pair_()` function. + (This uses `proto::call<>` under the covers to evaluate the + transform.)>>*/ + , make_pair( + proto::_value(proto::_child1) + , proto::_value(proto::_child2) + ) + > + {}; + //] +} + + +//[ NegateInt +struct NegateInt + : proto::when<proto::terminal<int>, proto::negate<_>(_)> +{}; +//] + +#ifndef BOOST_MSVC +//[ SquareAndPromoteInt +struct SquareAndPromoteInt + : proto::when< + proto::terminal<int> + , proto::_make_multiplies( + proto::terminal<long>::type(proto::_value) + , proto::terminal<long>::type(proto::_value) + ) + > +{}; +//] +#endif + +namespace lambda_transform +{ + //[LambdaTransform + template<typename N> + struct placeholder : N {}; + + // A function object that calls fusion::at() + struct at : proto::callable + { + template<typename Sig> + struct result; + + template<typename This, typename Cont, typename Index> + struct result<This(Cont, Index)> + : fusion::result_of::at< + typename boost::remove_reference<Cont>::type + , typename boost::remove_reference<Index>::type + > + {}; + + template<typename Cont, typename Index> + typename fusion::result_of::at<Cont, Index>::type + operator ()(Cont &cont, Index const &) const + { + return fusion::at<Index>(cont); + } + }; + + // A transform that evaluates a lambda expression. + struct LambdaEval + : proto::or_< + /*<<When you match a placeholder ...>>*/ + proto::when< + proto::terminal<placeholder<_> > + /*<<... call at() with the data parameter, which + is a tuple, and the placeholder, which is an MPL + Integral Constant.>>*/ + , at(proto::_data, proto::_value) + > + /*<<Otherwise, use the _default<> transform, which + gives the operators their usual C++ meanings.>>*/ + , proto::otherwise< proto::_default<LambdaEval> > + > + {}; + + // Define the lambda placeholders + proto::terminal<placeholder<mpl::int_<0> > >::type const _1 = {}; + proto::terminal<placeholder<mpl::int_<1> > >::type const _2 = {}; + + void test_lambda() + { + // a tuple that contains the values + // of _1 and _2 + fusion::tuple<int, int> tup(2,3); + + // Use LambdaEval to evaluate a lambda expression + int j = LambdaEval()( _2 - _1, 0, tup ); + BOOST_CHECK_EQUAL(j, 1); + + // You can mutate leaves in an expression tree + proto::literal<int> k(42); + int &l = LambdaEval()( k += 4, 0, tup ); + BOOST_CHECK_EQUAL(k.get(), 46); + BOOST_CHECK_EQUAL(&l, &k.get()); + + // You can mutate the values in the tuple, too. + LambdaEval()( _1 += 4, 0, tup ); + BOOST_CHECK_EQUAL(6, fusion::at_c<0>(tup)); + } + //] +} + +void test_examples() +{ + //[ CalculatorArityTest + int i = 0; // not used, dummy state and data parameter + + std::cout << CalculatorArity()( proto::lit(100) * 200, i, i) << '\n'; + std::cout << CalculatorArity()( (_1 - _1) / _1 * 100, i, i) << '\n'; + std::cout << CalculatorArity()( (_2 - _1) / _2 * 100, i, i) << '\n'; + //] + + BOOST_CHECK_EQUAL(0, CalculatorArity()( proto::lit(100) * 200, i, i)); + BOOST_CHECK_EQUAL(1, CalculatorArity()( (_1 - _1) / _1 * 100, i, i)); + BOOST_CHECK_EQUAL(2, CalculatorArity()( (_2 - _1) / _2 * 100, i, i)); + + BOOST_CHECK_EQUAL(0, CalcArity()( proto::lit(100) * 200, i, i)); + BOOST_CHECK_EQUAL(1, CalcArity()( (_1 - _1) / _1 * 100, i, i)); + BOOST_CHECK_EQUAL(2, CalcArity()( (_2 - _1) / _2 * 100, i, i)); + + using boost::fusion::cons; + using boost::fusion::nil; + cons<int, cons<char, cons<std::string> > > args(ArgsAsList()( _1(1, 'a', std::string("b")), i, i )); + BOOST_CHECK_EQUAL(args.car, 1); + BOOST_CHECK_EQUAL(args.cdr.car, 'a'); + BOOST_CHECK_EQUAL(args.cdr.cdr.car, std::string("b")); + + cons<int, cons<char, cons<std::string> > > lst(FoldTreeToList()( (_1 = 1, 'a', std::string("b")), i, i )); + BOOST_CHECK_EQUAL(lst.car, 1); + BOOST_CHECK_EQUAL(lst.cdr.car, 'a'); + BOOST_CHECK_EQUAL(lst.cdr.cdr.car, std::string("b")); + + proto::plus< + proto::terminal<double>::type + , proto::terminal<double>::type + >::type p = Promote()( proto::lit(1.f) + 2.f, i, i ); + + //[ LazyMakePairTest + int j = 0; // not used, dummy state and data parameter + + std::pair<int, double> p2 = MakePair()( make_pair_(1, 3.14), j, j ); + + std::cout << p2.first << std::endl; + std::cout << p2.second << std::endl; + //] + + BOOST_CHECK_EQUAL(p2.first, 1); + BOOST_CHECK_EQUAL(p2.second, 3.14); + + std::pair<int, double> p3 = lazy_make_pair2::MakePair()( lazy_make_pair2::make_pair_(1, 3.14), j, j ); + + std::cout << p3.first << std::endl; + std::cout << p3.second << std::endl; + + BOOST_CHECK_EQUAL(p3.first, 1); + BOOST_CHECK_EQUAL(p3.second, 3.14); + + NegateInt()(proto::lit(1), i, i); + #ifndef BOOST_MSVC + SquareAndPromoteInt()(proto::lit(1), i, i); + #endif + + lambda_transform::test_lambda(); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test examples from the documentation"); + + test->add(BOOST_TEST_CASE(&test_examples)); + + return test; +} diff --git a/src/boost/libs/proto/test/external_transforms.cpp b/src/boost/libs/proto/test/external_transforms.cpp new file mode 100644 index 000000000..f72e94587 --- /dev/null +++ b/src/boost/libs/proto/test/external_transforms.cpp @@ -0,0 +1,185 @@ +// Copyright 2011 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) +// +// This is an example of how to specify a transform externally so +// that a single grammar can be used to drive multiple differnt +// calculations. In particular, it defines a calculator grammar +// that computes the result of an expression with either checked +// or non-checked division. + +#include <iostream> +#include <boost/mpl/int.hpp> +#include <boost/mpl/next.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/fusion/container/vector.hpp> +#include <boost/fusion/container/generation/make_vector.hpp> +#include <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +// The argument placeholder type +template<typename I> struct placeholder : I {}; + +// Give each rule in the grammar a "name". This is so that we +// can easily dispatch on it later. +struct calc_grammar; +struct divides_rule : proto::divides<calc_grammar, calc_grammar> {}; + +// Use external transforms in calc_gramar +struct calc_grammar + : proto::or_< + proto::when< + proto::terminal<placeholder<_> > + , proto::functional::at(proto::_state, proto::_value) + > + , proto::when< + proto::terminal<proto::convertible_to<double> > + , proto::_value + > + , proto::when< + proto::plus<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + , proto::when< + proto::minus<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + , proto::when< + proto::multiplies<calc_grammar, calc_grammar> + , proto::_default<calc_grammar> + > + // Note that we don't specify how division nodes are + // handled here. Proto::external_transform is a placeholder + // for an actual transform. + , proto::when< + divides_rule + , proto::external_transform + > + > +{}; + +template<typename E> struct calc_expr; +struct calc_domain : proto::domain<proto::generator<calc_expr> > {}; + +template<typename E> +struct calc_expr + : proto::extends<E, calc_expr<E>, calc_domain> +{ + calc_expr(E const &e = E()) : calc_expr::proto_extends(e) {} +}; + +calc_expr<proto::terminal<placeholder<mpl::int_<0> > >::type> _1; +calc_expr<proto::terminal<placeholder<mpl::int_<1> > >::type> _2; + +// Use proto::external_transforms to map from named grammar rules to +// transforms. +struct non_checked_division + : proto::external_transforms< + proto::when< divides_rule, proto::_default<calc_grammar> > + > +{}; + +struct division_by_zero : std::exception {}; + +struct do_checked_divide + : proto::callable +{ + typedef int result_type; + int operator()(int left, int right) const + { + if (right == 0) throw division_by_zero(); + return left / right; + } +}; + +// Use proto::external_transforms again, this time to map the divides_rule +// to a transforms that performs checked division. +struct checked_division + : proto::external_transforms< + proto::when< + divides_rule + , do_checked_divide(calc_grammar(proto::_left), calc_grammar(proto::_right)) + > + > +{}; + +BOOST_PROTO_DEFINE_ENV_VAR(mydata_tag, mydata); + +void test_external_transforms() +{ + non_checked_division non_checked; + int result1 = calc_grammar()(_1 / _2, fusion::make_vector(6, 2), non_checked); + BOOST_CHECK_EQUAL(result1, 3); + + // check that additional data slots are ignored + int result2 = calc_grammar()(_1 / _2, fusion::make_vector(8, 2), (non_checked, mydata = "foo")); + BOOST_CHECK_EQUAL(result2, 4); + + // check that we can use the dedicated slot for this purpose + int result3 = calc_grammar()(_1 / _2, fusion::make_vector(8, 2), (42, proto::transforms = non_checked, mydata = "foo")); + BOOST_CHECK_EQUAL(result2, 4); + + checked_division checked; + try + { + // This should throw + int result3 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), checked); + BOOST_CHECK(!"Didn't throw an exception"); // shouldn't get here! + } + catch(division_by_zero) + { + ; // OK + } + catch(...) + { + BOOST_CHECK(!"Unexpected exception"); // shouldn't get here! + } + + try + { + // This should throw + int result4 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), (checked, mydata = test_external_transforms)); + BOOST_CHECK(!"Didn't throw an exception"); // shouldn't get here! + } + catch(division_by_zero) + { + ; // OK + } + catch(...) + { + BOOST_CHECK(!"Unexpected exception"); // shouldn't get here! + } + + try + { + // This should throw + int result5 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), (42, proto::transforms = checked, mydata = test_external_transforms)); + BOOST_CHECK(!"Didn't throw an exception"); // shouldn't get here! + } + catch(division_by_zero) + { + ; // OK + } + catch(...) + { + BOOST_CHECK(!"Unexpected exception"); // shouldn't get here! + } +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test for external transforms"); + + test->add(BOOST_TEST_CASE(&test_external_transforms)); + + return test; +} diff --git a/src/boost/libs/proto/test/flatten.cpp b/src/boost/libs/proto/test/flatten.cpp new file mode 100644 index 000000000..fd19474bf --- /dev/null +++ b/src/boost/libs/proto/test/flatten.cpp @@ -0,0 +1,211 @@ +/////////////////////////////////////////////////////////////////////////////// +// proto_fusion_s.cpp +// +// 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 <boost/proto/core.hpp> +#include <boost/proto/fusion.hpp> +#include <boost/fusion/include/for_each.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/utility/addressof.hpp> +#include <sstream> + +std::ostream &operator <<(std::ostream &sout, boost::proto::tag::shift_right) +{ + return sout << ">>"; +} + +std::ostream &operator <<(std::ostream &sout, boost::proto::tag::bitwise_or) +{ + return sout << "|"; +} + +template<typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::expr<boost::proto::tag::terminal, Args, 0> const *op) +{ + return sout << boost::proto::value(*op); +} + +template<typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<boost::proto::tag::terminal, Args, 0> const *op) +{ + return sout << boost::proto::value(*op); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::expr<Tag, Args, 1> const *op) +{ + return sout << Tag() << boost::addressof(boost::proto::child(*op).proto_base()); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<Tag, Args, 1> const *op) +{ + return sout << Tag() << boost::addressof(boost::proto::child(*op).proto_base()); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::expr<Tag, Args, 2> const *op) +{ + return sout << boost::addressof(boost::proto::left(*op).proto_base()) << Tag() << boost::addressof(boost::proto::right(*op).proto_base()); +} + +template<typename Tag, typename Args> +std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<Tag, Args, 2> const *op) +{ + return sout << boost::addressof(boost::proto::left(*op).proto_base()) << Tag() << boost::addressof(boost::proto::right(*op).proto_base()); +} + +/////////////////////////////////////////////////////////////////////////////// +// to_string +// +struct to_string +{ + to_string(std::ostream &sout) + : sout_(sout) + {} + + template<typename Op> + void operator ()(Op const &op) const + { + this->sout_ << '(' << boost::addressof(op.proto_base()) << ')'; + } +private: + std::ostream &sout_; +}; + +void test1() +{ + using boost::proto::flatten; + + boost::proto::terminal<char>::type a_ = {'a'}; + boost::proto::terminal<char>::type b_ = {'b'}; + boost::proto::terminal<char>::type c_ = {'c'}; + boost::proto::terminal<char>::type d_ = {'d'}; + boost::proto::terminal<char>::type e_ = {'e'}; + boost::proto::terminal<char>::type f_ = {'f'}; + boost::proto::terminal<char>::type g_ = {'g'}; + boost::proto::terminal<char>::type h_ = {'h'}; + boost::proto::terminal<char>::type i_ = {'i'}; + + std::stringstream sout; + + // Test for 1-way branching "tree" + sout.str(""); + boost::fusion::for_each(flatten(!!!!(a_ >> b_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)", sout.str()); + + // Tests for 2-way branching trees + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ >> c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ | c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ >> c_ | d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b>>c)(d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f|g>>h)", sout.str()); + + // Test for n-way branching tree + sout.str(""); + boost::fusion::for_each(flatten(a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c>>d)(e|f)(g>>h)(i)", sout.str()); +} + +//////////////////////////////////////////////////////////////////////// +// Test that EXTENDS expression wrappers are also valid fusion sequences + +template<typename Expr> +struct My; + +struct MyDomain + : boost::proto::domain<boost::proto::pod_generator<My> > +{}; + +template<typename Expr> +struct My +{ + BOOST_PROTO_EXTENDS(Expr, My<Expr>, MyDomain) +}; + +void test2() +{ + using boost::proto::flatten; + + My<boost::proto::terminal<char>::type> a_ = {{'a'}}; + My<boost::proto::terminal<char>::type> b_ = {{'b'}}; + My<boost::proto::terminal<char>::type> c_ = {{'c'}}; + My<boost::proto::terminal<char>::type> d_ = {{'d'}}; + My<boost::proto::terminal<char>::type> e_ = {{'e'}}; + My<boost::proto::terminal<char>::type> f_ = {{'f'}}; + My<boost::proto::terminal<char>::type> g_ = {{'g'}}; + My<boost::proto::terminal<char>::type> h_ = {{'h'}}; + My<boost::proto::terminal<char>::type> i_ = {{'i'}}; + + std::stringstream sout; + + // Test for 1-way branching "tree" + sout.str(""); + boost::fusion::for_each(flatten(!!!!(a_ >> b_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)", sout.str()); + + // Tests for 2-way branching trees + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ >> c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ | c_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ | b_ >> c_ | d_), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b>>c)(d)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)", sout.str()); + + sout.str(""); + boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), to_string(sout)); + BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f|g>>h)", sout.str()); + + // Test for n-way branching tree + sout.str(""); + boost::fusion::for_each(flatten(a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), to_string(sout)); + BOOST_CHECK_EQUAL("(a)(b)(c>>d)(e|f)(g>>h)(i)", sout.str()); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test proto and segmented fusion integration"); + + test->add(BOOST_TEST_CASE(&test1)); + test->add(BOOST_TEST_CASE(&test2)); + + return test; +} diff --git a/src/boost/libs/proto/test/lambda.cpp b/src/boost/libs/proto/test/lambda.cpp new file mode 100644 index 000000000..807f7cdb9 --- /dev/null +++ b/src/boost/libs/proto/test/lambda.cpp @@ -0,0 +1,188 @@ +/////////////////////////////////////////////////////////////////////////////// +// lambda.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 <sstream> +#include <boost/mpl/int.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/mpl/eval_if.hpp> +#include <boost/mpl/identity.hpp> +#include <boost/mpl/next_prior.hpp> +#include <boost/fusion/tuple.hpp> +#include <boost/typeof/typeof.hpp> +#include <boost/typeof/std/sstream.hpp> +#include <boost/typeof/std/ostream.hpp> +#include <boost/typeof/std/iostream.hpp> +#include <boost/type_traits/add_const.hpp> +#include <boost/type_traits/add_reference.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/proto/transform.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/floating_point_comparison.hpp> + +using namespace boost; + +// Forward declaration of the lambda expression wrapper +template<typename T> +struct lambda; + +struct lambda_domain + : proto::domain<proto::pod_generator<lambda> > +{}; + +template<typename I> +struct placeholder +{ + typedef I arity; +}; + +template<typename T> +struct placeholder_arity +{ + typedef typename T::arity type; +}; + +namespace grammar +{ + using namespace proto; + + // The lambda grammar, with the transforms for calculating the max arity + struct Lambda + : or_< + when< terminal< placeholder<_> >, mpl::next<placeholder_arity<_value> >() > + , when< terminal<_>, mpl::int_<0>() > + , when< nary_expr<_, vararg<_> >, fold<_, mpl::int_<0>(), mpl::max<Lambda,_state>()> > + > + {}; +} + +// simple wrapper for calculating a lambda expression's arity. +template<typename Expr> +struct lambda_arity + : boost::result_of<grammar::Lambda(Expr, mpl::void_, mpl::void_)> +{}; + +// The lambda context is the same as the default context +// with the addition of special handling for lambda placeholders +template<typename Tuple> +struct lambda_context + : proto::callable_context<lambda_context<Tuple> const> +{ + lambda_context(Tuple const &args) + : args_(args) + {} + + template<typename Sig> + struct result; + + template<typename This, typename I> + struct result<This(proto::tag::terminal, placeholder<I> const &)> + : fusion::result_of::at<Tuple, I> + {}; + + template<typename I> + typename fusion::result_of::at<Tuple, I>::type + operator ()(proto::tag::terminal, placeholder<I> const &) const + { + return fusion::at<I>(this->args_); + } + + Tuple args_; +}; + +// The lambda<> expression wrapper makes expressions polymorphic +// function objects +template<typename T> +struct lambda +{ + BOOST_PROTO_BASIC_EXTENDS(T, lambda<T>, lambda_domain) + BOOST_PROTO_EXTENDS_ASSIGN() + BOOST_PROTO_EXTENDS_SUBSCRIPT() + + // Careful not to evaluate the return type of the nullary function + // unless we have a nullary lambda! + typedef typename mpl::eval_if< + typename lambda_arity<T>::type + , mpl::identity<void> + , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > > + >::type nullary_type; + + // Define our operator () that evaluates the lambda expression. + nullary_type operator ()() const + { + fusion::tuple<> args; + lambda_context<fusion::tuple<> > ctx(args); + return proto::eval(*this, ctx); + } + + #define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \ + template<typename_A(N)> \ + typename proto::result_of::eval<T const, lambda_context<fusion::tuple<A_const_ref(N)> > >::type \ + operator ()(A_const_ref_a(N)) const \ + { \ + fusion::tuple<A_const_ref(N)> args(ref_a(N)); \ + lambda_context<fusion::tuple<A_const_ref(N)> > ctx(args); \ + return proto::eval(*this, ctx); \ + } \ + /**/ + BOOST_PROTO_REPEAT_FROM_TO(1, 4, M0) + #undef M0 +}; + +// Define some lambda placeholders +lambda<proto::terminal<placeholder<mpl::int_<0> > >::type> const _1 = {{}}; +lambda<proto::terminal<placeholder<mpl::int_<1> > >::type> const _2 = {{}}; +lambda<proto::terminal<placeholder<mpl::int_<3> > >::type> const _3 = {{}}; + +template<typename T> +lambda<typename proto::terminal<T>::type> const val(T const &t) +{ + lambda<typename proto::terminal<T>::type> that = {{t}}; + return that; +} + +template<typename T> +lambda<typename proto::terminal<T &>::type> const var(T &t) +{ + lambda<typename proto::terminal<T &>::type> that = {{t}}; + return that; +} + +void test_lambda() +{ + BOOST_CHECK_EQUAL(11, ( (_1 + 2) / 4 )(42)); + BOOST_CHECK_EQUAL(-11, ( (-(_1 + 2)) / 4 )(42)); + BOOST_CHECK_CLOSE(2.58, ( (4 - _2) * 3 )(42, 3.14), 0.1); + + // check non-const ref terminals + std::stringstream sout; + (sout << _1 << " -- " << _2)(42, "Life, the Universe and Everything!"); + BOOST_CHECK_EQUAL("42 -- Life, the Universe and Everything!", sout.str()); + + // check nullary lambdas + BOOST_CHECK_EQUAL(3, (val(1) + val(2))()); + + // check array indexing for kicks + int integers[5] = {0}; + (var(integers)[2] = 2)(); + (var(integers)[_1] = _1)(3); + BOOST_CHECK_EQUAL(2, integers[2]); + BOOST_CHECK_EQUAL(3, integers[3]); +} + +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 expression template domains"); + + test->add(BOOST_TEST_CASE(&test_lambda)); + + return test; +} diff --git a/src/boost/libs/proto/test/make.cpp b/src/boost/libs/proto/test/make.cpp new file mode 100644 index 000000000..17675aa22 --- /dev/null +++ b/src/boost/libs/proto/test/make.cpp @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// make.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 <boost/proto/core.hpp> +#include <boost/proto/transform/arg.hpp> +#include <boost/proto/transform/make.hpp> +#include <boost/mpl/identity.hpp> +#include <boost/test/unit_test.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<typename T> +struct type2type {}; + +template<typename T> +struct wrapper +{ + T t_; + explicit wrapper(T const & t = T()) : t_(t) {} +}; + +template<typename T> +struct careful +{ + typedef typename T::not_there not_there; +}; + +// Test that when no substitution is done, we don't instantiate templates +struct MakeTest1 + : proto::make< type2type< careful<int> > > +{}; + +void make_test1() +{ + proto::terminal<int>::type i = {42}; + type2type< careful<int> > res = MakeTest1()(i); +} + +// Test that when substitution is done, and there is no nested ::type +// typedef, the result is the wrapper +struct MakeTest2 + : proto::make< wrapper< proto::_value > > +{}; + +void make_test2() +{ + proto::terminal<int>::type i = {42}; + wrapper<int> res = MakeTest2()(i); + BOOST_CHECK_EQUAL(res.t_, 0); +} + +// Test that when substitution is done, and there is no nested ::type +// typedef, the result is the wrapper +struct MakeTest3 + : proto::make< wrapper< proto::_value >(proto::_value) > +{}; + +void make_test3() +{ + proto::terminal<int>::type i = {42}; + wrapper<int> res = MakeTest3()(i); + BOOST_CHECK_EQUAL(res.t_, 42); +} + +// Test that when substitution is done, and there is no nested ::type +// typedef, the result is the wrapper +struct MakeTest4 + : proto::make< mpl::identity< proto::_value >(proto::_value) > +{}; + +void make_test4() +{ + proto::terminal<int>::type i = {42}; + int res = MakeTest4()(i); + BOOST_CHECK_EQUAL(res, 42); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test the make transform"); + + test->add(BOOST_TEST_CASE(&make_test1)); + test->add(BOOST_TEST_CASE(&make_test2)); + test->add(BOOST_TEST_CASE(&make_test3)); + test->add(BOOST_TEST_CASE(&make_test4)); + + return test; +} diff --git a/src/boost/libs/proto/test/make_expr.cpp b/src/boost/libs/proto/test/make_expr.cpp new file mode 100644 index 000000000..d59f75748 --- /dev/null +++ b/src/boost/libs/proto/test/make_expr.cpp @@ -0,0 +1,407 @@ +/////////////////////////////////////////////////////////////////////////////// +// proto::make_expr.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 <sstream> +#include <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/utility/addressof.hpp> +#include <boost/fusion/tuple.hpp> +#include <boost/test/unit_test.hpp> + +namespace fusion = boost::fusion; +namespace proto = boost::proto; + +template<typename E> struct ewrap; + +struct mydomain + : proto::domain<proto::generator<ewrap> > +{}; + +template<typename E> struct ewrap + : proto::extends<E, ewrap<E>, mydomain> +{ + explicit ewrap(E const &e = E()) + : proto::extends<E, ewrap<E>, mydomain>(e) + {} +}; + +void test_make_expr() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(1); + proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(i); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(1); + proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p3_type; + p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::make_expr<proto::tag::plus>(p3, 0); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_make_expr_ref() +{ + int i = 42; + int const ci = 84; + proto::terminal<int const &>::type t1 = proto::make_expr<proto::tag::terminal>(boost::cref(ci)); + proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(boost::ref(i)); + BOOST_CHECK_EQUAL(&i, &proto::value(t2)); + proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(boost::cref(ci)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::make_expr<proto::tag::plus>(boost::ref(p3), 0); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_make_expr_functional() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(1); + proto::terminal<int>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(i); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(1); + proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p3_type; + p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(i); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(p3, 0); +} + +void test_make_expr_functional_ref() +{ + int i = 42; + int const ci = 84; + proto::terminal<int const &>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(boost::cref(ci)); + proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(i)); + BOOST_CHECK_EQUAL(&i, &proto::value(t2)); + proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::cref(ci)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(boost::ref(i)); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(boost::ref(p3), 0); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_unpack_expr() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(1)); + proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(boost::ref(i))); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(1)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::unpack_expr<proto::tag::unary_plus, mydomain>(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::unpack_expr<proto::tag::plus>(fusion::make_tuple(boost::ref(p3), 0)); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +void test_unpack_expr_functional() +{ + int i = 42; + proto::terminal<int>::type t1 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(1)); + proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(boost::ref(i))); + proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(1)); + proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::unary_plus + , proto::list1< + ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > + > + > + > + p3_type; + p3_type p3 = proto::functional::unpack_expr<proto::tag::unary_plus, mydomain>()(fusion::make_tuple(boost::ref(i))); + BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); + + typedef + ewrap< + proto::basic_expr< + proto::tag::plus + , proto::list2< + p3_type & + , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > + > + > + > + p4_type; + p4_type p4 = proto::functional::unpack_expr<proto::tag::plus>()(fusion::make_tuple(boost::ref(p3), 0)); + BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); +} + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#define _byref(x) call<proto::_byref(x)> +#define _byval(x) call<proto::_byval(x)> +#define Minus(x) proto::call<Minus(x)> +#endif + +// Turn all terminals held by reference into ones held by value +struct ByVal + : proto::or_< + proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byval(proto::_value))> + , proto::when<proto::nary_expr<proto::_, proto::vararg<ByVal> > > + > +{}; + +// Turn all terminals held by value into ones held by reference (not safe in general) +struct ByRef + : proto::or_< + proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byref(proto::_value))> + , proto::when<proto::nary_expr<proto::_, proto::vararg<ByRef> > > + > +{}; + +// turn all proto::plus nodes to minus nodes: +struct Minus + : proto::or_< + proto::when<proto::terminal<proto::_> > + , proto::when<proto::plus<Minus, Minus>, proto::_make_minus(Minus(proto::_left), Minus(proto::_right)) > + > +{}; + +struct Square + : proto::or_< + // Not creating new proto::terminal nodes here, + // so hold the existing terminals by reference: + proto::when<proto::terminal<proto::_>, proto::_make_multiplies(proto::_, proto::_)> + , proto::when<proto::plus<Square, Square> > + > +{}; + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#undef _byref +#undef _byval +#undef Minus +#endif + +void test_make_expr_transform() +{ + proto::plus< + proto::terminal<int>::type + , proto::terminal<int>::type + >::type t1 = ByVal()(proto::as_expr(1) + 1); + + proto::plus< + proto::terminal<int const &>::type + , proto::terminal<int const &>::type + >::type t2 = ByRef()(proto::as_expr(1) + 1); + + proto::minus< + proto::terminal<int>::type const & + , proto::terminal<int const &>::type const & + >::type t3 = Minus()(proto::as_expr(1) + 1); + + proto::plus< + proto::multiplies<proto::terminal<int>::type const &, proto::terminal<int>::type const &>::type + , proto::multiplies<proto::terminal<int const &>::type const &, proto::terminal<int const &>::type const &>::type + >::type t4 = Square()(proto::as_expr(1) + 1); +} + + +struct length_impl {}; +struct dot_impl {}; + +proto::terminal<length_impl>::type const length = {{}}; +proto::terminal<dot_impl>::type const dot = {{}}; + +// work around msvc bugs... +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +#define _byref(a) call<proto::_byref(a)> +#define _byval(a) call<proto::_byval(a)> +#define _child1(a) call<proto::_child1(a)> +#define _make_terminal(a) call<proto::_make_terminal(a)> +#define _make_function(a,b,c) call<proto::_make_function(a,b,c)> +#define dot_impl() proto::make<dot_impl()> +#endif + +// convert length(a) < length(b) to dot(a,a) < dot(b,b) +struct Convert + : proto::when< + proto::less< + proto::function<proto::terminal<length_impl>, proto::_> + , proto::function<proto::terminal<length_impl>, proto::_> + > + , proto::_make_less( + proto::_make_function( + proto::_make_terminal(dot_impl()) + , proto::_child1(proto::_child0) + , proto::_child1(proto::_child0) + ) + , proto::_make_function( + proto::_make_terminal(dot_impl()) + , proto::_child1(proto::_child1) + , proto::_child1(proto::_child1) + ) + ) + > +{}; + +template<typename Expr> +void test_make_expr_transform2_test(Expr const &expr) +{ + void const *addr1 = boost::addressof(proto::child_c<1>(proto::child_c<0>(expr))); + void const *addr2 = boost::addressof(proto::child_c<1>(proto::child_c<0>(Convert()(expr)))); + BOOST_CHECK_EQUAL(addr1, addr2); + + BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(expr)))); + BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(Convert()(expr))))); +} + +void test_make_expr_transform2() +{ + test_make_expr_transform2_test(length(1) < length(2)); +} + +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +#undef _byref +#undef _byval +#undef _child1 +#undef _make_terminal +#undef _make_function +#undef dot_impl +#endif + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test proto::make_expr, proto::unpack_expr and friends"); + + test->add(BOOST_TEST_CASE(&test_make_expr)); + test->add(BOOST_TEST_CASE(&test_make_expr_ref)); + test->add(BOOST_TEST_CASE(&test_make_expr_functional)); + test->add(BOOST_TEST_CASE(&test_make_expr_functional_ref)); + test->add(BOOST_TEST_CASE(&test_unpack_expr)); + test->add(BOOST_TEST_CASE(&test_unpack_expr_functional)); + test->add(BOOST_TEST_CASE(&test_make_expr_transform)); + test->add(BOOST_TEST_CASE(&test_make_expr_transform2)); + + return test; +} diff --git a/src/boost/libs/proto/test/matches.cpp b/src/boost/libs/proto/test/matches.cpp new file mode 100644 index 000000000..60b8f7257 --- /dev/null +++ b/src/boost/libs/proto/test/matches.cpp @@ -0,0 +1,319 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; + +struct int_convertible +{ + int_convertible() {} + operator int() const { return 0; } +}; + +struct Input + : proto::or_< + proto::shift_right< proto::terminal< std::istream & >, proto::_ > + , proto::shift_right< Input, proto::_ > + > +{}; + +struct Output + : proto::or_< + proto::shift_left< proto::terminal< std::ostream & >, proto::_ > + , proto::shift_left< Output, proto::_ > + > +{}; + +proto::terminal< std::istream & >::type const cin_ = {std::cin}; +proto::terminal< std::ostream & >::type const cout_ = {std::cout}; + +struct Anything + : proto::or_< + proto::terminal<proto::_> + , proto::nary_expr<proto::_, proto::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 +{}; + +template<typename Expr> +struct my_expr; + +struct my_domain + : proto::domain<proto::pod_generator<my_expr> > +{}; + +template<typename Expr> +struct my_expr +{ + BOOST_PROTO_BASIC_EXTENDS(Expr, my_expr, my_domain) +}; + +void test_matches() +{ + proto::assert_matches< proto::_ >( proto::lit(1) ); + proto::assert_matches< proto::_ >( proto::as_child(1) ); + proto::assert_matches< proto::_ >( proto::as_expr(1) ); + + proto::assert_matches< proto::terminal<int> >( proto::lit(1) ); + proto::assert_matches< proto::terminal<int> >( proto::as_child(1) ); + proto::assert_matches< proto::terminal<int> >( proto::as_expr(1) ); + + proto::assert_matches_not< proto::terminal<int> >( proto::lit('a') ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_child('a') ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_expr('a') ); + + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit('a') ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child('a') ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr('a') ); + + proto::assert_matches_not< proto::terminal<int> >( proto::lit((int_convertible())) ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_child((int_convertible())) ); + proto::assert_matches_not< proto::terminal<int> >( proto::as_expr((int_convertible())) ); + + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::lit((int_convertible())) ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_child((int_convertible())) ); + proto::assert_matches< proto::terminal<proto::convertible_to<int> > >( proto::as_expr((int_convertible())) ); + + proto::assert_matches< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit(1) ); + proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>() > >( proto::lit('a') ); + + proto::assert_matches< + proto::and_< + proto::terminal<proto::_> + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit(1) ); + + proto::assert_matches_not< + proto::and_< + proto::terminal<proto::_> + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit('a') ); + + proto::assert_matches< proto::terminal<char const *> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char const *> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char const *> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char const[6]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char const (&)[6]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char const[6]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char [6]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char [6]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char [6]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char const (&)[proto::N]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char const[proto::N]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<char [proto::N]> >( proto::lit("hello") ); + proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_child("hello") ); + proto::assert_matches< proto::terminal<char [proto::N]> >( proto::as_expr("hello") ); + + proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::lit(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t const (&)[proto::N]> >( proto::as_child(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t const[proto::N]> >( proto::as_expr(L"hello") ); + + proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::lit(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_child(L"hello") ); + proto::assert_matches< proto::terminal<wchar_t [proto::N]> >( proto::as_expr(L"hello") ); + + proto::assert_matches_not< proto::if_<boost::is_same<proto::_value, int>()> >( proto::lit("hello") ); + + proto::assert_matches< proto::terminal<std::string> >( proto::lit(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::string> >( proto::as_child(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::string> >( proto::as_expr(std::string("hello")) ); + + proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::lit(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(std::string("hello")) ); + proto::assert_matches< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(std::string("hello")) ); + + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::lit(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_child(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> > >( proto::as_expr(1) ); + + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::lit(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::as_child(1) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_,proto::_,proto::_> > >( proto::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 + + proto::assert_matches< proto::terminal<std::basic_string<proto::_> const & > >( proto::lit(const_string("hello")) ); + proto::assert_matches< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_child(const_string("hello")) ); + proto::assert_matches_not< proto::terminal<std::basic_string<proto::_> const & > >( proto::as_expr(const_string("hello")) ); + + proto::assert_matches< proto::terminal< void(&)() > >( proto::lit(a_function) ); + proto::assert_matches< proto::terminal< void(&)() > >( proto::as_child(a_function) ); + proto::assert_matches< proto::terminal< void(&)() > >( proto::as_expr(a_function) ); + + proto::assert_matches_not< proto::terminal< void(*)() > >( proto::lit(a_function) ); + proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_child(a_function) ); + proto::assert_matches_not< proto::terminal< void(*)() > >( proto::as_expr(a_function) ); + + proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::lit(a_function) ); + proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_child(a_function) ); + proto::assert_matches< proto::terminal< proto::convertible_to<void(*)()> > >( proto::as_expr(a_function) ); + + proto::assert_matches< proto::terminal< void(*)() > >( proto::lit(&a_function) ); + proto::assert_matches< proto::terminal< void(*)() > >( proto::as_child(&a_function) ); + proto::assert_matches< proto::terminal< void(*)() > >( proto::as_expr(&a_function) ); + + proto::assert_matches< proto::terminal< void(* const &)() > >( proto::lit(&a_function) ); + proto::assert_matches< proto::terminal< void(* const &)() > >( proto::as_child(&a_function) ); + proto::assert_matches_not< proto::terminal< void(* const &)() > >( proto::as_expr(&a_function) ); + + proto::assert_matches< + proto::or_< + proto::if_<boost::is_same<proto::_value, char>() > + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit(1) ); + + proto::assert_matches_not< + proto::or_< + proto::if_<boost::is_same<proto::_value, char>() > + , proto::if_<boost::is_same<proto::_value, int>() > + > + >( proto::lit(1u) ); + + proto::assert_matches< Input >( cin_ >> 1 >> 2 >> 3 ); + proto::assert_matches_not< Output >( cin_ >> 1 >> 2 >> 3 ); + + proto::assert_matches< Output >( cout_ << 1 << 2 << 3 ); + proto::assert_matches_not< Input >( cout_ << 1 << 2 << 3 ); + + proto::assert_matches< proto::function< proto::terminal<int>, proto::vararg< proto::terminal<char> > > >( proto::lit(1)('a','b','c','d') ); + proto::assert_matches_not< proto::function< proto::terminal<int>, proto::vararg< proto::terminal<char> > > >( proto::lit(1)('a','b','c',"d") ); + + proto::assert_matches< Anything >( cout_ << 1 << +proto::lit('a') << proto::lit(1)('a','b','c',"d") ); + + proto::assert_matches< proto::switch_<MyCases> >( proto::lit(1) >> 'a' ); + proto::assert_matches< proto::switch_<MyCases> >( proto::lit(1) + 'a' ); + proto::assert_matches_not< proto::switch_<MyCases> >( proto::lit(1) << 'a' ); + + number<int, two_complement_c> num; + proto::assert_matches<NumberGrammar>(proto::as_expr(num)); + + // check custom terminal types + { + proto::nullary_expr<my_terminal, int>::type i = {0}; + + proto::assert_matches<proto::nullary_expr<my_terminal, proto::_> >( i ); + proto::assert_matches_not<proto::terminal<proto::_> >( i ); + + proto::terminal<int>::type j = {0}; + proto::assert_matches<proto::terminal<proto::_> >( j ); + proto::assert_matches_not<proto::nullary_expr<my_terminal, proto::_> >( j ); + + proto::assert_matches<proto::nullary_expr<proto::_, proto::_> >( i ); + } + + // check 0 and 1 arg forms or or_ and and_ + { + proto::assert_matches< proto::and_<> >( proto::lit(1) ); + proto::assert_matches_not< proto::or_<> >( proto::lit(1) ); + + proto::assert_matches< proto::and_<proto::terminal<int> > >( proto::lit(1) ); + proto::assert_matches< proto::or_<proto::terminal<int> > >( proto::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; + proto::assert_matches< proto::terminal< a_template<proto::_> > >( proto::lit(a) ); + } + + // Test that the actual derived expression type makes it through to proto::if_ + { + my_expr<proto::terminal<int>::type> e = {{1}}; + proto::assert_matches< proto::if_<boost::is_same<proto::domain_of<proto::_>, my_domain>()> >( e ); + } +} + +using namespace boost::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; +} + diff --git a/src/boost/libs/proto/test/mem_ptr.cpp b/src/boost/libs/proto/test/mem_ptr.cpp new file mode 100644 index 000000000..5326c665b --- /dev/null +++ b/src/boost/libs/proto/test/mem_ptr.cpp @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// mem_ptr.hpp +// +// Copyright 2009 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 <boost/mpl/print.hpp> +#include <iostream> +#include <boost/shared_ptr.hpp> +#include <boost/proto/proto.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/test/unit_test.hpp> + +namespace proto = boost::proto; +using proto::_; + +struct evaluator + : proto::when<_, proto::_default<evaluator> > +{}; + +template<typename Ret, typename Expr> +void assert_result_type(Expr &) +{ + // check that the return type as calculated by the _default transform + // is correct. + BOOST_MPL_ASSERT(( + boost::is_same< + Ret + , typename boost::result_of<evaluator(Expr &)>::type + > + )); + + // check that the return type as calculated by the default_context + // is correct. + BOOST_MPL_ASSERT(( + boost::is_same< + Ret + , typename boost::result_of<proto::functional::eval(Expr &, proto::default_context &)>::type + > + )); +} + +/////////////////////////////////////////////////////////////////////////////// +struct S +{ + S() : x(-42) {} + int x; +}; + +// like a normal terminal except with an operator() that can +// accept non-const lvalues (Proto's only accepts const lvalues) +template<typename T, typename Dummy = proto::is_proto_expr> +struct my_terminal +{ + typedef typename proto::terminal<T>::type my_terminal_base; + BOOST_PROTO_BASIC_EXTENDS(my_terminal_base, my_terminal, proto::default_domain) + + template<typename A0> + typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 &>::type const + operator()(A0 &a0) const + { + return proto::make_expr<proto::tag::function>(boost::ref(*this), boost::ref(a0)); + } + + template<typename A0> + typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 const &>::type const + operator()(A0 const &a0) const + { + return proto::make_expr<proto::tag::function>(boost::ref(*this), boost::ref(a0)); + } +}; + +my_terminal<int S::*> test1 = {{ &S::x }}; + +// Some tests with the default transform +void test_refs_transform() +{ + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // non-const lvalue argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(s)); + evaluator()(test1(s)) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + // Ditto for reference_wrappers + assert_result_type<int &>(test1(boost::ref(s))); + evaluator()(test1(boost::ref(s))) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(rcs)); + int const &s_x = evaluator()(test1(rcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x); +} + +// Some tests with the default context +void test_refs_context() +{ + proto::default_context ctx; + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // non-const lvalue argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(s)); + proto::eval(test1(s), ctx) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + // Ditto for reference_wrappers + assert_result_type<int &>(test1(boost::ref(s))); + proto::eval(test1(boost::ref(s)), ctx) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(rcs)); + int const &s_x = proto::eval(test1(rcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x); +} + +void test_ptrs_transform() +{ + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // pointer to a non-const argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(&s)); + evaluator()(test1(&s)) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + S* ps = &s; + assert_result_type<int &>(test1(ps)); + evaluator()(test1(ps)) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + boost::shared_ptr<S> const sp(new S); + BOOST_REQUIRE_EQUAL(sp->x, -42); + + // Ditto for shared_ptr (which hook the get_pointer() + // customization point) + assert_result_type<int &>(test1(sp)); + evaluator()(test1(sp)) = 0; + BOOST_CHECK_EQUAL(sp->x, 0); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(&rcs)); + int const &s_x0 = evaluator()(test1(&rcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x0); + + S const *pcs = &s; + assert_result_type<int const &>(test1(pcs)); + int const &s_x1 = evaluator()(test1(pcs)); + BOOST_CHECK_EQUAL(&s.x, &s_x1); + + boost::shared_ptr<S const> spc(new S); + BOOST_REQUIRE_EQUAL(spc->x, -42); + + assert_result_type<int const &>(test1(spc)); + int const &s_x2 = evaluator()(test1(spc)); + BOOST_CHECK_EQUAL(&spc->x, &s_x2); +} + +void test_ptrs_context() +{ + proto::default_context ctx; + S s; + BOOST_REQUIRE_EQUAL(s.x, -42); + + // Check that evaluating a memptr invocation with a + // pointer to a non-const argument yields the member as a + // non-const lvalue + assert_result_type<int &>(test1(&s)); + proto::eval(test1(&s), ctx) = 0; + BOOST_CHECK_EQUAL(s.x, 0); + + S* ps = &s; + assert_result_type<int &>(test1(ps)); + proto::eval(test1(ps), ctx) = 42; + BOOST_CHECK_EQUAL(s.x, 42); + + boost::shared_ptr<S> const sp(new S); + BOOST_REQUIRE_EQUAL(sp->x, -42); + + // Ditto for shared_ptr (which hook the get_pointer() + // customization point) + assert_result_type<int &>(test1(sp)); + proto::eval(test1(sp), ctx) = 0; + BOOST_CHECK_EQUAL(sp->x, 0); + + // Check that evaluating a memptr invocation with a + // const lvalue argument yields the member as a + // const lvalue + S const &rcs = s; + assert_result_type<int const &>(test1(&rcs)); + int const &s_x0 = proto::eval(test1(&rcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x0); + + S const *pcs = &s; + assert_result_type<int const &>(test1(pcs)); + int const &s_x1 = proto::eval(test1(pcs), ctx); + BOOST_CHECK_EQUAL(&s.x, &s_x1); + + boost::shared_ptr<S const> spc(new S); + BOOST_REQUIRE_EQUAL(spc->x, -42); + + assert_result_type<int const &>(test1(spc)); + int const &s_x2 = proto::eval(test1(spc), ctx); + BOOST_CHECK_EQUAL(&spc->x, &s_x2); +} + +/////////////////////////////////////////////////////////////////////////////// +struct T +{ + int x; +}; + +proto::terminal<int T::*>::type test2 = { &T::x }; + +int const *get_pointer(T const &t) +{ + return &t.x; +} + +void with_get_pointer_transform() +{ + T t; + evaluator()(test2(t)); +} + +/////////////////////////////////////////////////////////////////////////////// +template<typename T> +struct dumb_ptr +{ + dumb_ptr(T *p_) : p(p_) {} + + friend T const *get_pointer(dumb_ptr const &p) + { + return p.p; + } + + T *p; +}; + +struct U : dumb_ptr<U> +{ + U() : dumb_ptr<U>(this), x(42) {} + int x; +}; + +my_terminal<U *dumb_ptr<U>::*> U_p = {{&U::p}}; +my_terminal<int U::*> U_x = {{&U::x}}; + +void potentially_ambiguous_transform() +{ + U u; + + // This should yield a non-const reference to a pointer-to-const + U *&up = evaluator()(U_p(u)); + BOOST_CHECK_EQUAL(&up, &u.p); + + // This should yield a non-const reference to a pointer-to-const + int &ux = evaluator()(U_x(u)); + BOOST_CHECK_EQUAL(&ux, &u.x); +} + + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test handling of member pointers by the default transform and default contexts"); + + test->add(BOOST_TEST_CASE(&test_refs_transform)); + test->add(BOOST_TEST_CASE(&test_refs_context)); + + test->add(BOOST_TEST_CASE(&test_ptrs_transform)); + test->add(BOOST_TEST_CASE(&test_ptrs_context)); + + test->add(BOOST_TEST_CASE(&with_get_pointer_transform)); + + test->add(BOOST_TEST_CASE(&potentially_ambiguous_transform)); + + return test; +} diff --git a/src/boost/libs/proto/test/mpl.cpp b/src/boost/libs/proto/test/mpl.cpp new file mode 100644 index 000000000..292e582bd --- /dev/null +++ b/src/boost/libs/proto/test/mpl.cpp @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////// +// mpl.hpp +// +// Copyright 2012 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 <boost/proto/proto.hpp> +#include <boost/fusion/mpl.hpp> +#include <boost/mpl/pop_back.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/static_assert.hpp> +#include <boost/test/unit_test.hpp> +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +template<class E> +struct my_expr; + +struct my_domain + : proto::domain<proto::generator<my_expr> > +{}; + +template<class E> +struct my_expr + : proto::extends<E, my_expr<E>, my_domain> +{ + my_expr(E const &e = E()) + : proto::extends<E, my_expr<E>, my_domain>(e) + {} + + typedef fusion::fusion_sequence_tag tag; +}; + +template<typename T> +void test_impl(T const &) +{ + typedef typename mpl::pop_back<T>::type result_type; + BOOST_STATIC_ASSERT( + (boost::is_same< + result_type + , my_expr<proto::basic_expr<proto::tag::plus, proto::list1<my_expr<proto::terminal<int>::type>&> > > + >::value) + ); +} + +// Test that we can call mpl algorithms on proto expression types, and get proto expression types back +void test_mpl() +{ + my_expr<proto::terminal<int>::type> i; + test_impl(i + i); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test proto mpl integration via fusion"); + + test->add(BOOST_TEST_CASE(&test_mpl)); + + return test; +} diff --git a/src/boost/libs/proto/test/noinvoke.cpp b/src/boost/libs/proto/test/noinvoke.cpp new file mode 100644 index 000000000..05e738a11 --- /dev/null +++ b/src/boost/libs/proto/test/noinvoke.cpp @@ -0,0 +1,116 @@ +/////////////////////////////////////////////////////////////////////////////// +// noinvoke.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 <boost/proto/core.hpp> +#include <boost/proto/transform/make.hpp> +#include <boost/type_traits/add_pointer.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/test/unit_test.hpp> +namespace proto=boost::proto; +using proto::_; + +struct Test + : proto::when< + _ + , proto::noinvoke< + // This remove_pointer invocation is bloked by noinvoke + boost::remove_pointer< + // This add_pointer invocation is *not* blocked by noinvoke + boost::add_pointer<_> + > + >() + > +{}; + +struct Test2 + : proto::when< + _ + // This add_pointer gets invoked because a substitution takes place + // within it. + , boost::add_pointer< + proto::noinvoke< + // This remove_pointer invocation is bloked by noinvoke + boost::remove_pointer< + // This add_pointer invocation is *not* blocked by noinvoke + boost::add_pointer<_> + > + > + >() + > +{}; + +template<typename T, typename U> +struct select2nd +{ + typedef U type; +}; + +struct Test3 + : proto::when< + _ + // This add_pointer gets invoked because a substitution takes place + // within it. + , select2nd< + void + , proto::noinvoke< + // This remove_pointer invocation is bloked by noinvoke + select2nd< + void + // This add_pointer invocation is *not* blocked by noinvoke + , boost::add_pointer<_> + > + > + >() + > +{}; + + +void test_noinvoke() +{ + typedef proto::terminal<int>::type Int; + Int i = {42}; + + BOOST_MPL_ASSERT(( + boost::is_same< + boost::result_of<Test(Int)>::type + , boost::remove_pointer<Int *> + > + )); + + boost::remove_pointer<Int *> t = Test()(i); + + BOOST_MPL_ASSERT(( + boost::is_same< + boost::result_of<Test2(Int)>::type + , boost::remove_pointer<Int *> * + > + )); + + boost::remove_pointer<Int *> * t2 = Test2()(i); + + BOOST_MPL_ASSERT(( + boost::is_same< + boost::result_of<Test3(Int)>::type + , select2nd<void, Int *> + > + )); + + select2nd<void, Int *> t3 = Test3()(i); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test proto::noinvoke"); + + test->add(BOOST_TEST_CASE(&test_noinvoke)); + + return test; +} diff --git a/src/boost/libs/proto/test/pack_expansion.cpp b/src/boost/libs/proto/test/pack_expansion.cpp new file mode 100644 index 000000000..7aacb32f4 --- /dev/null +++ b/src/boost/libs/proto/test/pack_expansion.cpp @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////// +// pack_expansion.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 <boost/proto/proto.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/typeof/typeof.hpp> + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +using proto::_; + +template<typename T> T declval(); + +struct eval_ : proto::callable +{ + template<typename Sig> + struct result; + +#define UNARY_OP(TAG, OP) \ + template<typename This, typename Arg> \ + struct result<This(proto::tag::TAG, Arg)> \ + { \ + BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (OP declval<Arg>())) \ + typedef typename nested::type type; \ + }; \ + \ + template<typename Arg> \ + typename result<eval_(proto::tag::TAG, Arg)>::type \ + operator()(proto::tag::TAG, Arg arg) const \ + { \ + return OP arg; \ + } \ + /**/ + +#define BINARY_OP(TAG, OP) \ + template<typename This, typename Left, typename Right> \ + struct result<This(proto::tag::TAG, Left, Right)> \ + { \ + BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (declval<Left>() OP declval<Right>())) \ + typedef typename nested::type type; \ + }; \ + \ + template<typename Left, typename Right> \ + typename result<eval_(proto::tag::TAG, Left, Right)>::type \ + operator()(proto::tag::TAG, Left left, Right right) const \ + { \ + return left OP right; \ + } \ + /**/ + + UNARY_OP(negate, -) + BINARY_OP(plus, +) + BINARY_OP(minus, -) + BINARY_OP(multiplies, *) + BINARY_OP(divides, /) + /*... others ...*/ +}; + +struct eval1 + : proto::or_< + proto::when<proto::terminal<_>, proto::_value> + , proto::otherwise<eval_(proto::tag_of<_>(), eval1(proto::pack(_))...)> + > +{}; + +struct eval2 + : proto::or_< + proto::when<proto::terminal<_>, proto::_value> + , proto::otherwise<proto::call<eval_(proto::tag_of<_>(), eval2(proto::pack(_))...)> > + > +{}; + +void test_call_pack() +{ + proto::terminal<int>::type i = {42}; + int res = eval1()(i); + BOOST_CHECK_EQUAL(res, 42); + res = eval1()(i + 2); + BOOST_CHECK_EQUAL(res, 44); + res = eval1()(i * 2); + BOOST_CHECK_EQUAL(res, 84); + res = eval1()(i * 2 + 4); + BOOST_CHECK_EQUAL(res, 88); + + res = eval2()(i + 2); + BOOST_CHECK_EQUAL(res, 44); + res = eval2()(i * 2); + BOOST_CHECK_EQUAL(res, 84); + res = eval2()(i * 2 + 4); + BOOST_CHECK_EQUAL(res, 88); +} + +struct make_pair + : proto::when< + proto::binary_expr<_, proto::terminal<int>, proto::terminal<int> > + , std::pair<int, int>(proto::_value(proto::pack(_))...) + > +{}; + +void test_make_pack() +{ + proto::terminal<int>::type i = {42}; + std::pair<int, int> p = make_pair()(i + 43); + BOOST_CHECK_EQUAL(p.first, 42); + BOOST_CHECK_EQUAL(p.second, 43); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test immediate evaluation of proto parse trees"); + + test->add(BOOST_TEST_CASE(&test_call_pack)); + test->add(BOOST_TEST_CASE(&test_make_pack)); + + return test; +} diff --git a/src/boost/libs/proto/test/protect.cpp b/src/boost/libs/proto/test/protect.cpp new file mode 100644 index 000000000..33b055198 --- /dev/null +++ b/src/boost/libs/proto/test/protect.cpp @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////// +// protect.hpp +// +// Copyright 2012 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 <boost/proto/core.hpp> +#include <boost/proto/transform/make.hpp> +#include <boost/type_traits/add_pointer.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/test/unit_test.hpp> +namespace proto=boost::proto; +using proto::_; + +template<typename T> +struct identity +{ + typedef T type; +}; + +struct TestWithMake + : proto::make< proto::protect<_> > +{}; + +struct TestWithMake1 + : proto::make< identity<proto::protect<_> > > +{}; + +struct TestWithMake2 + : proto::make< identity<proto::protect<int> > > +{}; + +struct TestWithMake3 + : proto::make< identity<proto::protect<identity<_> > > > +{}; + +struct TestWithMake4 + : proto::make< identity<proto::protect<identity<int> > > > +{}; + +struct TestWithMake5 + : proto::make< identity<proto::protect<identity<identity<int> > > > > +{}; + +void test_protect_with_make() +{ + proto::terminal<int>::type i = {42}; + + _ t = TestWithMake()(i); + _ t1 = TestWithMake1()(i); + int t2 = TestWithMake2()(i); + identity<_> t3 = TestWithMake3()(i); + identity<int> t4 = TestWithMake4()(i); + identity<identity<int> > t5 = TestWithMake5()(i); +} + +//struct TestWithWhen +// : proto::when<_, proto::protect<_>() > +//{}; + +struct TestWithWhen1 + : proto::when<_, identity<proto::protect<_> >() > +{}; + +struct TestWithWhen2 + : proto::when<_, identity<proto::protect<int> >() > +{}; + +struct TestWithWhen3 + : proto::when<_, identity<proto::protect<identity<_> > >() > +{}; + +struct TestWithWhen4 + : proto::when<_, identity<proto::protect<identity<int> > >() > +{}; + +struct TestWithWhen5 + : proto::when<_, identity<proto::protect<identity<identity<int> > > >() > +{}; + +void test_protect_with_when() +{ + proto::terminal<int>::type i = {42}; + + //_ t = TestWithWhen()(i); + _ t1 = TestWithWhen1()(i); + int t2 = TestWithWhen2()(i); + identity<_> t3 = TestWithWhen3()(i); + identity<int> t4 = TestWithWhen4()(i); + identity<identity<int> > t5 = TestWithWhen5()(i); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test proto::protect"); + + test->add(BOOST_TEST_CASE(&test_protect_with_make)); + test->add(BOOST_TEST_CASE(&test_protect_with_when)); + + return test; +} diff --git a/src/boost/libs/proto/test/switch.cpp b/src/boost/libs/proto/test/switch.cpp new file mode 100644 index 000000000..be5881f54 --- /dev/null +++ b/src/boost/libs/proto/test/switch.cpp @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////////////////////////// +// new_switch.cpp +// +// Copyright 2011 Eric Niebler +// Copyright Pierre Esterie & Joel Falcou. +// 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/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/proto/debug.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/mpl/long.hpp> +#include <boost/mpl/bool.hpp> + +namespace proto = boost::proto; + +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::_ +{}; + +struct ArityOf; + +struct ArityOfCases +{ + template<typename ArityOf> + struct case_ + : proto::not_<proto::_> + {}; +}; + + +template<> +struct ArityOfCases::case_<boost::mpl::long_<1> > + : boost::proto::when<boost::proto::_, boost::mpl::false_()> +{}; + +template<> +struct ArityOfCases::case_<boost::mpl::long_<2> > + : boost::proto::when<boost::proto::_, boost::mpl::true_()> +{}; + +struct ArityOf + : boost::proto::switch_< + ArityOfCases + , proto::arity_of<proto::_>() + > +{}; + +void test_switch() +{ + // Tests for backward compatibility + proto::assert_matches<proto::switch_<MyCases> >(proto::lit(1) >> 'a'); + proto::assert_matches<proto::switch_<MyCases> >(proto::lit(1) + 'a'); + proto::assert_matches_not<proto::switch_<MyCases> >(proto::lit(1) << 'a'); + + //Test new matching on the Transform result type + ArityOf ar; + + proto::assert_matches_not<ArityOf>(proto::lit(1)); + proto::assert_matches<ArityOf>(proto::lit(1) + 2); + proto::assert_matches<ArityOf>(!proto::lit(1)); + BOOST_CHECK_EQUAL(ar(!proto::lit(1)), false); + BOOST_CHECK_EQUAL(ar(proto::lit(1) + 2), true); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite(int argc, char* argv[]) +{ + test_suite *test = BOOST_TEST_SUITE("test proto::switch_<>"); + + test->add(BOOST_TEST_CASE(&test_switch)); + + return test; +} + diff --git a/src/boost/libs/proto/test/toy_spirit.cpp b/src/boost/libs/proto/test/toy_spirit.cpp new file mode 100644 index 000000000..6d2fcad97 --- /dev/null +++ b/src/boost/libs/proto/test/toy_spirit.cpp @@ -0,0 +1,665 @@ +/////////////////////////////////////////////////////////////////////////////// +// toy_spirit.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 <cctype> +#include <string> +#include <cstring> +#include <iostream> +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/test/unit_test.hpp> + +namespace boost +{ + // global tags + struct char_tag {}; + struct ichar_tag {}; + struct istring_tag {}; + struct ichar_range_tag {}; + struct never_tag {}; + struct always_tag {}; + struct space_tag {}; + + // global primitives + proto::terminal<char_tag>::type const char_ = {{}}; + proto::terminal<space_tag>::type const space = {{}}; + + using proto::lit; + using proto::literal; +} + +namespace boost { namespace spirit2 +{ + + // handy typedefs + typedef proto::terminal<char_tag>::type anychar_p; + typedef proto::terminal<ichar_tag>::type ianychar_p; + typedef proto::terminal<istring_tag>::type ianystr_p; + typedef proto::terminal<ichar_range_tag>::type ianychar_range_p; + typedef proto::terminal<never_tag>::type never_p; + typedef proto::terminal<space_tag>::type space_p; + + struct SpiritGrammar; + struct SkipperGrammar; + struct SpiritPrimitives; + template<typename Grammar> + struct SpiritComposites; + + struct CharLiteral + : proto::terminal<char> + {}; + + struct NTBSLiteral + : proto::terminal<char const *> + {}; + + struct StdStringLiteral + : proto::terminal<std::string> + {}; + + struct CharParser + : proto::function<anychar_p, CharLiteral> + {}; + + struct ICharParser + : proto::function<ianychar_p, CharLiteral, CharLiteral> + {}; + + struct CharRangeParser + : proto::function<anychar_p, CharLiteral, CharLiteral> + {}; + + struct IStrParser + : proto::function<ianystr_p, StdStringLiteral> + {}; + + struct ICharRangeParser + : proto::function<ianychar_range_p, CharLiteral, CharLiteral> + {}; + + ianychar_p const ichar_ = {{}}; + ianystr_p const istr_ = {{}}; + ianychar_range_p const ichar_range_ = {{}}; + + namespace utility + { + inline bool char_icmp(char ch, char lo, char hi) + { + return ch == lo || ch == hi; + } + + template<typename FwdIter> + inline bool string_cmp(char const *sz, FwdIter &begin, FwdIter end) + { + FwdIter tmp = begin; + for(; *sz; ++tmp, ++sz) + if(tmp == end || *tmp != *sz) + return false; + begin = tmp; + return true; + } + + template<typename FwdIter> + inline bool string_icmp(std::string const &str, FwdIter &begin, FwdIter end) + { + BOOST_ASSERT(0 == str.size() % 2); + FwdIter tmp = begin; + std::string::const_iterator istr = str.begin(), estr = str.end(); + for(; istr != estr; ++tmp, istr += 2) + if(tmp == end || (*tmp != *istr && *tmp != *(istr+1))) + return false; + begin = tmp; + return true; + } + + inline bool in_range(char ch, char lo, char hi) + { + return ch >= lo && ch <= hi; + } + + inline bool in_irange(char ch, char lo, char hi) + { + return in_range(ch, lo, hi) + || in_range(std::tolower(ch), lo, hi) + || in_range(std::toupper(ch), lo, hi); + } + + inline std::string to_istr(char const *sz) + { + std::string res; + res.reserve(std::strlen(sz) * 2); + for(; *sz; ++sz) + { + res.push_back(std::tolower(*sz)); + res.push_back(std::toupper(*sz)); + } + return res; + } + } // namespace utility + + template<typename FwdIter, typename Skipper = never_p> + struct spirit_context + : std::pair<FwdIter, FwdIter> + , proto::callable_context<spirit_context<FwdIter, Skipper> > + { + typedef bool result_type; + typedef FwdIter iterator; + + spirit_context(FwdIter first, FwdIter second, Skipper const &skip = Skipper()) + : std::pair<FwdIter, FwdIter>(first, second) + , skip_(skip) + , in_skip_(false) + {} + + // parse function for anychar_p + bool operator()(proto::tag::terminal, char_tag) + { + this->skip(); + if(this->first == this->second) + return false; + ++this->first; + return true; + } + + // parse function for char_('a') + template<typename Expr> + bool operator()(proto::tag::function, anychar_p, Expr const &expr) + { + this->skip(); + return proto::eval(expr, *this); + } + + // parse function for space_p + bool operator()(proto::tag::terminal, space_tag) + { + this->skip(); + if(this->first == this->second || !std::isspace(*this->first)) + return false; + ++this->first; + return true; + } + + // parse function for bare character literals + bool operator()(proto::tag::terminal, char ch) + { + this->skip(); + if(this->first == this->second || *this->first != ch) + return false; + ++this->first; + return true; + } + + // case-insensitive character parser + template<typename Arg1, typename Arg2> + bool operator()(proto::tag::function, ianychar_p, Arg1 const &arg1, Arg2 const &arg2) + { + this->skip(); + if(this->first == this->second + || !utility::char_icmp(*this->first, proto::value(arg1), proto::value(arg2))) + return false; + ++this->first; + return true; + } + + // parse function for NTBS literals + bool operator()(proto::tag::terminal, char const *sz) + { + this->skip(); + return utility::string_cmp(sz, this->first, this->second); + } + + // parse function for istr_("hello") + template<typename Expr> + bool operator()(proto::tag::function, ianystr_p, Expr const &expr) + { + this->skip(); + return utility::string_icmp(proto::value(expr), this->first, this->second); + } + + // parse function for char_('a','z') + template<typename Arg1, typename Arg2> + bool operator()(proto::tag::function, anychar_p, Arg1 const &arg1, Arg2 const &arg2) + { + BOOST_ASSERT(proto::value(arg1) <= proto::value(arg2)); + this->skip(); + if(this->first == this->second + || !utility::in_range(*this->first, proto::value(arg1), proto::value(arg2))) + return false; + ++this->first; + return true; + } + + // parse function for ichar_range_('a','z') + template<typename Arg1, typename Arg2> + bool operator()(proto::tag::function, ianychar_range_p, Arg1 const &arg1, Arg2 const &arg2) + { + BOOST_ASSERT(proto::value(arg1) <= proto::value(arg2)); + this->skip(); + if(this->first == this->second + || !utility::in_irange(*this->first, proto::value(arg1), proto::value(arg2))) + return false; + ++this->first; + return true; + } + + // parse function for complemented thingies (where thingies are assumed + // to be 1 character wide). + template<typename Expr> + bool operator()(proto::tag::complement, Expr const &expr) + { + this->skip(); + iterator where = this->first; + if(proto::eval(expr, *this)) + return this->first = where, false; + this->first = ++where; + return true; + } + + // never_p parse function always returns false. + bool operator()(proto::tag::terminal, never_tag) + { + return false; + } + + // for A >> B, succeeds if A and B matches. + template<typename Left, typename Right> + bool operator()(proto::tag::shift_right, Left const &left, Right const &right) + { + return proto::eval(left, *this) && proto::eval(right, *this); + } + + // for A | B, succeeds if either A or B matches at this point. + template<typename Left, typename Right> + bool operator()(proto::tag::bitwise_or, Left const &left, Right const &right) + { + iterator where = this->first; + return proto::eval(left, *this) || proto::eval(right, this->reset(where)); + } + + // for *A, greedily match A as many times as possible. + template<typename Expr> + bool operator()(proto::tag::dereference, Expr const &expr) + { + iterator where = this->first; + while(proto::eval(expr, *this)) + where = this->first; + // make sure that when we return true, the iterator is at the correct position! + this->first = where; + return true; + } + + // for +A, greedily match A one or more times. + template<typename Expr> + bool operator()(proto::tag::unary_plus, Expr const &expr) + { + return proto::eval(expr, *this) && proto::eval(*expr, *this); + } + + // for !A, optionally match A. + template<typename Expr> + bool operator()(proto::tag::logical_not, Expr const &expr) + { + iterator where = this->first; + if(!proto::eval(expr, *this)) + this->first = where; + return true; + } + + // for (A - B), matches when A but not B matches. + template<typename Left, typename Right> + bool operator()(proto::tag::minus, Left const &left, Right const &right) + { + iterator where = this->first; + return !proto::eval(right, *this) && proto::eval(left, this->reset(where)); + } + private: + spirit_context &reset(iterator where) + { + this->first = where; + return *this; + } + + void skip() + { + if(!this->in_skip_) + { + this->in_skip_ = true; + while(proto::eval(this->skip_, *this)) + {} + this->in_skip_ = false; + } + } + + Skipper skip_; + bool in_skip_; + }; + + struct as_ichar_parser : proto::callable + { + typedef proto::function< + ianychar_p + , proto::terminal<char>::type + , proto::terminal<char>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + char lo = std::tolower(proto::value(proto::child_c<1>(expr))); + char hi = std::toupper(proto::value(proto::child_c<1>(expr))); + result_type that = {ichar_, {lo}, {hi}}; + return that; + } + }; + + struct as_ichar_range_parser : proto::callable + { + typedef proto::function< + ianychar_range_p + , proto::terminal<char>::type + , proto::terminal<char>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + char lo = proto::value(proto::child_c<1>(expr)); + char hi = proto::value(proto::child_c<2>(expr)); + result_type that = {ichar_range_, {lo}, {hi}}; + return that; + } + }; + + struct as_ichar_literal : proto::callable + { + typedef proto::function< + ianychar_p + , proto::terminal<char>::type + , proto::terminal<char>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + char lo = std::tolower(proto::value(expr)); + char hi = std::toupper(proto::value(expr)); + result_type that = {ichar_, {lo}, {hi}}; + return that; + } + }; + + struct as_intbs_literal : proto::callable + { + typedef proto::function< + ianystr_p + , proto::terminal<std::string>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + result_type that = {istr_, {utility::to_istr(proto::value(expr))}}; + return that; + } + }; + + struct as_istdstring_literal : proto::callable + { + typedef proto::function< + ianystr_p + , proto::terminal<std::string>::type + >::type result_type; + + template<typename Expr> + result_type operator()(Expr const &expr) const + { + result_type that = {istr_, {utility::to_istr(proto::value(expr).c_str())}}; + return that; + } + }; + + /////////////////////////////////////////////////////////////////////////// + // Transforms + /////////////////////////////////////////////////////////////////////////// + + struct skip_primitives : proto::transform<skip_primitives> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::shift_right< + typename proto::dereference<State>::type + , Expr + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + result_type that = {{state}, expr}; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////// + // Grammar + /////////////////////////////////////////////////////////////////////////// + using proto::_; + + struct SpiritGrammar; + + struct SpiritCaseSensitivePrimitives + : proto::or_< + proto::when<CharParser, as_ichar_parser(_)> + , proto::when<CharLiteral, as_ichar_literal(_)> + , proto::when<NTBSLiteral, as_intbs_literal(_)> + , proto::when<CharRangeParser, as_ichar_range_parser(_)> + , proto::when<StdStringLiteral, as_istdstring_literal(_)> + > + {}; + + struct SpiritCaseInsensitivePrimitives + : proto::or_< + anychar_p + , IStrParser + , ICharParser + , ICharRangeParser + , proto::complement<SpiritPrimitives> + > + {}; + + struct SpiritPrimitives + : proto::or_< + SpiritCaseSensitivePrimitives + , SpiritCaseInsensitivePrimitives + > + {}; + + template<typename Grammar> + struct SpiritComposites + : proto::or_< + proto::bitwise_or< Grammar, Grammar > + , proto::shift_right< Grammar, Grammar > + , proto::minus< Grammar, Grammar > + , proto::dereference< Grammar > + , proto::unary_plus< Grammar > + , proto::logical_not< Grammar > + > + {}; + + // Regular Spirit grammar, has no-case transforms + struct SpiritGrammar + : proto::or_< + SpiritComposites<SpiritGrammar> + , SpiritPrimitives + > + {}; + + // Spirit grammar with the skipper transform + struct SkipperGrammar + : proto::or_< + SpiritComposites<SkipperGrammar> + , proto::when<SpiritPrimitives, skip_primitives> + > + {}; + + /////////////////////////////////////////////////////////////////////////// + // Directives + /////////////////////////////////////////////////////////////////////////// + + struct no_case_directive + { + template<typename Expr> + typename boost::result_of<SpiritGrammar(Expr const &)>::type const + operator [](Expr const &expr) const + { + return SpiritGrammar()(expr); + } + }; + + // no_case + no_case_directive const no_case = {}; + + template<typename Skipper> + struct skip_directive + { + skip_directive(Skipper const &skip) + : skip_(skip) + {} + + template<typename Expr> + typename boost::result_of<SkipperGrammar(Expr const &, Skipper const &)>::type const + operator [](Expr const &expr) const + { + return SkipperGrammar()(expr, this->skip_); + } + private: + Skipper skip_; + }; + + // skip + template<typename Skipper> + skip_directive<Skipper> skip(Skipper const &skip) + { + return skip_directive<Skipper>(skip); + } + + /////////////////////////////////////////////////////////////////////////// + // parse + /////////////////////////////////////////////////////////////////////////// + + template<typename FwdIter, typename Rule> + bool parse(FwdIter begin, FwdIter end, Rule const &rule) + { + // make sure the rule corresponds to the Spirit grammar: + BOOST_MPL_ASSERT((proto::matches<Rule, SpiritGrammar>)); + + spirit_context<FwdIter> ctx(begin, end); + return proto::eval(rule, ctx); + } + + // parse with a skip parser can be implemented in one of two ways: + // Method 1) + // The skip parser is passed to all the parsers which invoke it + // before they invoke themselves. This is how Spirit-1 does it, + // and it is the cause of the Scanner Business. However, it has + // the advantage of not needing a parser transformation phase. + // Method 2) + // Transform the expression template to insert the skip parser + // in between all sequenced parsers. That is, transform (A >> B) + // to (*skip >> A >> *skip >> B). This has the advantage of making + // it unnecessary to pass the scanner to all the parsers, which + // means its type doesn't show up in function signatures, avoiding + // the Scanner Business. + // Recommendation: + // Both methods should be supported. Method 1 should be preferred + // when calling parse with parsers defined inline. Method 2 should + // be preferred when a parser expression is assigned to a rule<>, + // thereby making the type of the rule<> independent of the skip + // parser used. I imagine a syntax like: + // rule<> r = skip(space)[A >> B >> C] + template<typename FwdIter, typename Rule, typename Skipper> + bool parse(FwdIter begin, FwdIter end, Rule const &rule, Skipper const &skipper) + { + // make sure the rule corresponds to the Spirit grammar: + BOOST_MPL_ASSERT((proto::matches<Rule, SpiritGrammar>)); + + //// Method 1: pass skip parser in the context structure. + //spirit_context<FwdIter, Skipper> ctx(begin, end, skipper); + //return proto::eval(rule, ctx); + + // Method 2: Embed skip parser via tree transformation. + spirit_context<FwdIter> ctx(begin, end); + return proto::eval(spirit2::skip(skipper)[rule], ctx); + } + +}} + +using namespace boost; +using namespace spirit2; + +void test_toy_spirit() +{ + std::string str("abcd"); + + // This will fail: + BOOST_CHECK(!spirit2::parse(str.begin(), str.end() + , char_ >> char_('a'))); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , char_ >> char_('b') >> char_ >> 'd')); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , 'a' >> ('c' >> char_ | 'b' >> char_('d') | 'b' >> char_('c')) >> 'd')); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , *(char_ - 'd'))); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , no_case[char_('A') >> 'B' >> "CD"])); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , no_case[*char_('A','Z')])); + + literal<char> a = lit('a'); + literal<char const *> bcd = lit("bcd"); + + // This will succeed: + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , +~~a >> no_case[bcd])); + + // Scanner Business: R.I.P. :-) + str = "a b cd"; + BOOST_CHECK(spirit2::parse(str.begin(), str.end() + , char_('a') >> 'b' >> 'c' >> 'd', space >> space)); + +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test proto and and toy spirit-2"); + + test->add(BOOST_TEST_CASE(&test_toy_spirit)); + + return test; +} diff --git a/src/boost/libs/proto/test/toy_spirit2.cpp b/src/boost/libs/proto/test/toy_spirit2.cpp new file mode 100644 index 000000000..a0f246f3f --- /dev/null +++ b/src/boost/libs/proto/test/toy_spirit2.cpp @@ -0,0 +1,466 @@ +/////////////////////////////////////////////////////////////////////////////// +// toy_spirit3.cpp +// +// 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 <cctype> +#include <string> +#include <cstring> +#include <iomanip> +#include <iostream> +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/transform.hpp> +#include <boost/fusion/include/for_each.hpp> +#include <boost/fusion/include/fold.hpp> +#include <boost/fusion/include/cons.hpp> +#include <boost/fusion/include/any.hpp> +#include <boost/test/unit_test.hpp> + +namespace boost +{ + // global tags + struct char_tag {}; + struct space_tag {}; + + // global primitives + proto::terminal<char_tag>::type const char_ = {{}}; + proto::terminal<space_tag>::type const space = {{}}; + + using proto::lit; + using proto::literal; +} + +namespace boost { namespace spirit2 +{ + namespace utility + { + inline bool char_icmp(char ch, char lo, char hi) + { + return ch == lo || ch == hi; + } + + template<typename FwdIter> + inline bool string_cmp(char const *sz, FwdIter &begin, FwdIter end) + { + FwdIter tmp = begin; + for(; *sz; ++tmp, ++sz) + if(tmp == end || *tmp != *sz) + return false; + begin = tmp; + return true; + } + + template<typename FwdIter> + inline bool string_icmp(std::string const &str, FwdIter &begin, FwdIter end) + { + BOOST_ASSERT(0 == str.size() % 2); + FwdIter tmp = begin; + std::string::const_iterator istr = str.begin(), estr = str.end(); + for(; istr != estr; ++tmp, istr += 2) + if(tmp == end || (*tmp != *istr && *tmp != *(istr+1))) + return false; + begin = tmp; + return true; + } + + inline bool in_range(char ch, char lo, char hi) + { + return ch >= lo && ch <= hi; + } + + inline bool in_irange(char ch, char lo, char hi) + { + return in_range(ch, lo, hi) + || in_range(std::tolower(ch), lo, hi) + || in_range(std::toupper(ch), lo, hi); + } + + inline std::string to_istr(char const *sz) + { + std::string res; + res.reserve(std::strlen(sz) * 2); + for(; *sz; ++sz) + { + res.push_back(std::tolower(*sz)); + res.push_back(std::toupper(*sz)); + } + return res; + } + } // namespace utility + + template<typename List> + struct alternate + { + explicit alternate(List const &list) + : elems(list) + {} + List elems; + }; + + template<typename List> + struct sequence + { + explicit sequence(List const &list) + : elems(list) + {} + List elems; + }; + + struct char_range + : std::pair<char, char> + { + char_range(char from, char to) + : std::pair<char, char>(from, to) + {} + }; + + struct ichar + { + ichar(char ch) + : lo_(std::tolower(ch)) + , hi_(std::toupper(ch)) + {} + + char lo_, hi_; + }; + + struct istr + { + istr(char const *sz) + : str_(utility::to_istr(sz)) + {} + + std::string str_; + }; + + struct ichar_range + : std::pair<char, char> + { + ichar_range(char from, char to) + : std::pair<char, char>(from, to) + {} + }; + + // The no-case directive + struct no_case_tag {}; + + struct True : mpl::true_ {}; + + /////////////////////////////////////////////////////////////////////////////// + /// Begin Spirit grammar here + /////////////////////////////////////////////////////////////////////////////// + namespace grammar + { + using namespace proto; + using namespace fusion; + + struct SpiritExpr; + + struct AnyChar + : terminal<char_tag> + {}; + + struct CharLiteral + : terminal<char> + {}; + + struct NTBSLiteral + : terminal<char const *> + {}; + + struct CharParser + : proto::function<AnyChar, CharLiteral> + {}; + + struct CharRangeParser + : proto::function<AnyChar, CharLiteral, CharLiteral> + {}; + + struct NoCase + : terminal<no_case_tag> + {}; + + // The data determines the case-sensitivity of the terminals + typedef _data _icase; + + // Ugh, would be nice to find a work-around for this: + #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + #define _value(x) call<_value(x)> + #define True() make<True()> + #endif + + // Extract the child from terminals + struct SpiritTerminal + : or_< + when< AnyChar, _value > + , when< CharLiteral, if_<_icase, ichar(_value), _value> > + , when< CharParser, if_<_icase, ichar(_value(_child1)), _value(_child1)> > // char_('a') + , when< NTBSLiteral, if_<_icase, istr(_value), char const*(_value)> > + , when< CharRangeParser, if_<_icase + , ichar_range(_value(_child1), _value(_child2)) + , char_range(_value(_child1), _value(_child2))> > // char_('a','z') + > + {}; + + struct FoldToList + : reverse_fold_tree<_, nil(), cons<SpiritExpr, _state>(SpiritExpr, _state)> + {}; + + // sequence rule folds all >>'s together into a list + // and wraps the result in a sequence<> wrapper + struct SpiritSequence + : when< shift_right<SpiritExpr, SpiritExpr>, sequence<FoldToList>(FoldToList) > + {}; + + // alternate rule folds all |'s together into a list + // and wraps the result in a alternate<> wrapper + struct SpiritAlternate + : when< bitwise_or<SpiritExpr, SpiritExpr>, alternate<FoldToList>(FoldToList) > + {}; + + // Directives such as no_case are handled here + struct SpiritDirective + : when< subscript<NoCase, SpiritExpr>, SpiritExpr(_right, _state, True()) > + {}; + + // A SpiritExpr is an alternate, a sequence, a directive or a terminal + struct SpiritExpr + : or_< + SpiritSequence + , SpiritAlternate + , SpiritDirective + , SpiritTerminal + > + {}; + + } // namespace grammar + + using grammar::SpiritExpr; + using grammar::NoCase; + + /////////////////////////////////////////////////////////////////////////////// + /// End SpiritExpr + /////////////////////////////////////////////////////////////////////////////// + + // Globals + NoCase::type const no_case = {{}}; + + template<typename Iterator> + struct parser; + + template<typename Iterator> + struct fold_alternate + { + parser<Iterator> const &parse; + + explicit fold_alternate(parser<Iterator> const &p) + : parse(p) + {} + + template<typename T> + bool operator ()(T const &t) const + { + Iterator tmp = this->parse.first; + if(this->parse(t)) + return true; + this->parse.first = tmp; + return false; + } + }; + + template<typename Iterator> + struct fold_sequence + { + parser<Iterator> const &parse; + + explicit fold_sequence(parser<Iterator> const &p) + : parse(p) + {} + + typedef bool result_type; + + template<typename T> + bool operator ()(bool success, T const &t) const + { + return success && this->parse(t); + } + }; + + template<typename Iterator> + struct parser + { + mutable Iterator first; + Iterator second; + + parser(Iterator begin, Iterator end) + : first(begin) + , second(end) + {} + + bool done() const + { + return this->first == this->second; + } + + template<typename List> + bool operator ()(alternate<List> const &alternates) const + { + return fusion::any(alternates.elems, fold_alternate<Iterator>(*this)); + } + + template<typename List> + bool operator ()(sequence<List> const &sequence) const + { + return fusion::fold(sequence.elems, true, fold_sequence<Iterator>(*this)); + } + + bool operator ()(char_tag ch) const + { + if(this->done()) + return false; + ++this->first; + return true; + } + + bool operator ()(char ch) const + { + if(this->done() || ch != *this->first) + return false; + ++this->first; + return true; + } + + bool operator ()(ichar ich) const + { + if(this->done() || !utility::char_icmp(*this->first, ich.lo_, ich.hi_)) + return false; + ++this->first; + return true; + } + + bool operator ()(char const *sz) const + { + return utility::string_cmp(sz, this->first, this->second); + } + + bool operator ()(istr const &s) const + { + return utility::string_icmp(s.str_, this->first, this->second); + } + + bool operator ()(char_range rng) const + { + if(this->done() || !utility::in_range(*this->first, rng.first, rng.second)) + return false; + ++this->first; + return true; + } + + bool operator ()(ichar_range rng) const + { + if(this->done() || !utility::in_irange(*this->first, rng.first, rng.second)) + return false; + ++this->first; + return true; + } + }; + + template<typename Rule, typename Iterator> + typename enable_if<proto::matches< Rule, SpiritExpr >, bool >::type + parse_impl(Rule const &rule, Iterator begin, Iterator end) + { + mpl::false_ is_case_sensitive; + parser<Iterator> parse_fun(begin, end); + return parse_fun(SpiritExpr()(rule, proto::ignore(), is_case_sensitive)); + } + + // 2nd overload provides a short error message for invalid rules + template<typename Rule, typename Iterator> + typename disable_if<proto::matches< Rule, SpiritExpr >, bool >::type + parse_impl(Rule const &rule, Iterator begin, Iterator end) + { + BOOST_MPL_ASSERT((proto::matches<Rule, SpiritExpr>)); + return false; + } + + // parse() converts rule literals to proto expressions if necessary + // and dispatches to parse_impl + template<typename Rule, typename Iterator> + bool parse(Rule const &rule, Iterator begin, Iterator end) + { + return parse_impl(proto::as_expr(rule), begin, end); + } + +}} + +void test_toy_spirit3() +{ + using boost::spirit2::no_case; + using boost::char_; + std::string hello("abcd"); + + BOOST_CHECK( + boost::spirit2::parse( + "abcd" + , hello.begin() + , hello.end() + ) + ); + + BOOST_CHECK( + boost::spirit2::parse( + char_ >> char_('b') >> 'c' >> char_ + , hello.begin() + , hello.end() + ) + ); + + BOOST_CHECK( + !boost::spirit2::parse( + char_ >> char_('b') >> 'c' >> 'D' + , hello.begin() + , hello.end() + ) + ); + + BOOST_CHECK( + boost::spirit2::parse( + char_ >> char_('b') >> 'c' >> 'e' + | char_ >> no_case[char_('B') >> "C" >> char_('D','Z')] + , hello.begin() + , hello.end() + ) + ); + + std::string nest_alt_input("abd"); + BOOST_CHECK( + boost::spirit2::parse( + char_('a') + >> ( char_('b') + | char_('c') + ) + >> char_('d') + , nest_alt_input.begin() + , nest_alt_input.end() + ) + ); +} + +using namespace boost::unit_test; +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("test proto, grammars and tree transforms"); + + test->add(BOOST_TEST_CASE(&test_toy_spirit3)); + + return test; +} |