From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- src/boost/libs/proto/test/external_transforms.cpp | 185 ++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/boost/libs/proto/test/external_transforms.cpp (limited to 'src/boost/libs/proto/test/external_transforms.cpp') diff --git a/src/boost/libs/proto/test/external_transforms.cpp b/src/boost/libs/proto/test/external_transforms.cpp new file mode 100644 index 00000000..f72e9458 --- /dev/null +++ b/src/boost/libs/proto/test/external_transforms.cpp @@ -0,0 +1,185 @@ +// Copyright 2011 Eric Niebler. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is an example of how to specify a transform externally so +// that a single grammar can be used to drive multiple differnt +// calculations. In particular, it defines a calculator grammar +// that computes the result of an expression with either checked +// or non-checked division. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mpl = boost::mpl; +namespace proto = boost::proto; +namespace fusion = boost::fusion; +using proto::_; + +// The argument placeholder type +template 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 {}; + +// Use external transforms in calc_gramar +struct calc_grammar + : proto::or_< + proto::when< + proto::terminal > + , proto::functional::at(proto::_state, proto::_value) + > + , proto::when< + proto::terminal > + , proto::_value + > + , proto::when< + proto::plus + , proto::_default + > + , proto::when< + proto::minus + , proto::_default + > + , proto::when< + proto::multiplies + , proto::_default + > + // 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 struct calc_expr; +struct calc_domain : proto::domain > {}; + +template +struct calc_expr + : proto::extends, calc_domain> +{ + calc_expr(E const &e = E()) : calc_expr::proto_extends(e) {} +}; + +calc_expr > >::type> _1; +calc_expr > >::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 > + > +{}; + +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; +} -- cgit v1.2.3