early-access version 3088

This commit is contained in:
pineappleEA
2022-11-05 15:35:56 +01:00
parent 4e4fc25ce3
commit b601909c6d
35519 changed files with 5996896 additions and 860 deletions

View File

@@ -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 ]
;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}