2
0
mirror of https://github.com/boostorg/spirit.git synced 2026-01-19 04:42:11 +00:00

Update exposed attribute for alternative parser

Alternative parser type now exposes the inner attribute directly when both
branches are identical instead of wrapping it in a variant type.
This commit is contained in:
Lee Clagett
2016-04-07 21:15:06 -04:00
parent 586c4bad52
commit 8616d3ff3e
3 changed files with 49 additions and 74 deletions

View File

@@ -75,30 +75,4 @@ namespace boost { namespace spirit { namespace x3
auto const expect = expect_gen{};
}}}
namespace boost { namespace spirit { namespace x3 { namespace detail
{
// Special case handling for expect expressions.
template <typename Subject, typename Context, typename RContext>
struct parse_into_container_impl<expect_directive<Subject>, Context, RContext>
{
template <typename Iterator, typename Attribute>
static bool call(
expect_directive<Subject> const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr)
{
bool r = parse_into_container(
parser.subject, first, last, context, rcontext, attr);
if (!r)
{
boost::throw_exception(
expectation_failure<Iterator>(
first, what(parser.subject)));
}
return r;
}
};
}}}}
#endif

View File

@@ -17,10 +17,16 @@
#include <boost/variant/variant.hpp>
#include <boost/mpl/copy_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/unique.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/fusion/include/front.hpp>
@@ -211,13 +217,21 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
>::type
filtered_types;
// Build a variant if filtered_types is not empty,
// else just return unused_type
// remove duplicate types and normalize to a 1+ element mpl sequence
typedef typename
mpl::eval_if<
mpl::empty<filtered_types>
, mpl::identity<unused_type>
, make_variant_over<filtered_types>
, mpl::vector<unused_type>
, mpl::unique<filtered_types, is_same<mpl::_1, mpl::_2>>
>::type
unique_types;
// build a variant if there is more than one unique type
typedef typename
mpl::eval_if<
mpl::equal_to<mpl::size<unique_types>, mpl::int_<1>>
, mpl::front<unique_types>
, make_variant_over<unique_types>
>::type
type;
};
@@ -255,46 +269,6 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
return false;
}
template <typename Left, typename Right, typename Context, typename RContext>
struct parse_into_container_impl<alternative<Left, Right>, Context, RContext>
{
typedef alternative<Left, Right> parser_type;
template <typename Iterator, typename Attribute>
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
{
return parse_alternative(parser, first, last, context, rcontext, attr);
}
template <typename Iterator, typename Attribute>
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
{
return parse_into_container_base_impl<parser_type>::call(
parser, first, last, context, rcontext, attr);
}
template <typename Iterator, typename Attribute>
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr)
{
typedef typename
traits::attribute_of<parser_type, Context>::type
attribute_type;
return call(parser, first, last, context, rcontext, attr
, traits::variant_has_substitute<attribute_type, Attribute>());
}
};
}}}}
#endif

View File

@@ -133,7 +133,7 @@ main()
rule<class r1, wchar_t> r1;
rule<class r2, wchar_t> r2;
rule<class r3, wchar_t> r3;
auto f = [&](auto& ctx){ _val(ctx) = _attr(ctx); };
r3 = ((eps >> r1))[f];
@@ -227,6 +227,33 @@ main()
BOOST_TEST(boost::get<long>(&boost::fusion::front(attr_)) != nullptr);
BOOST_TEST(boost::get<char>(&boost::fusion::front(attr_)) == nullptr);
}
// from boost bug 12094
{
const auto r =
boost::spirit::x3::rule<class r, std::string>{} = +char_;
std::string output;
BOOST_TEST(test_attr("abcd", 'a' > (r | r), output));
BOOST_TEST(output == "bcd");
}
{
const auto r =
int_ >> (
(" :left: " >> int_ >> " :right: ") |
(" :right: " >> int_ >> " :left: ")
) >> int_;
boost::fusion::vector<int, int, int> out;
BOOST_TEST(test_attr("100 :left: 101 :right: 102", r, out));
BOOST_TEST(boost::fusion::at_c<0>(out) == 100);
BOOST_TEST(boost::fusion::at_c<1>(out) == 101);
BOOST_TEST(boost::fusion::at_c<2>(out) == 102);
BOOST_TEST(test_attr("200 :right: 201 :left: 202", r, out));
BOOST_TEST(boost::fusion::at_c<0>(out) == 200);
BOOST_TEST(boost::fusion::at_c<1>(out) == 201);
BOOST_TEST(boost::fusion::at_c<2>(out) == 202);
}
return boost::report_errors();
}