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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user