2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-31 20:32:11 +00:00

1 Commits

Author SHA1 Message Date
Zach Laine
41d939b2bc In the out-argument overload of rule_parser::call(), always parse into a local
attr_type attribute ('attr'), rather than the one supplied ('retval').  Then,
take the parsed attribute and either combine it with retval (if they are both
containers), or assign attr to retval (if attr_type is not none).

Reproducer by Andreas Buhr.

Fixes #294.
2026-01-30 19:16:34 -06:00
2 changed files with 59 additions and 4 deletions

View File

@@ -5549,8 +5549,9 @@ namespace boost { namespace parser {
locals_type locals = detail::make_locals<locals_type>(context);
auto params = detail::resolve_rule_params(context, params_);
tag_type * const tag_ptr = nullptr;
attr_type attr{};
auto const rule_context = detail::make_rule_context(
context, tag_ptr, retval, locals, params);
context, tag_ptr, attr, locals, params);
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, rule_context, flags, retval);
@@ -5565,9 +5566,22 @@ namespace boost { namespace parser {
flags,
success,
dont_assign,
retval);
if (!success || dont_assign)
retval = Attribute_();
attr);
if (dont_assign)
return;
if (!success)
attr = attr_type{};
if constexpr (detail::is_nope_v<decltype(attr)>) {
return;
} else if constexpr (
container<Attribute_> && container<attr_type>) {
detail::move_back(retval, attr, detail::gen_attrs(flags));
} else {
detail::assign(retval, attr);
}
}
}

View File

@@ -512,6 +512,45 @@ void github_pr_290()
BOOST_TEST(*result == "foo");
}
namespace github_issue_294_ {
namespace bp = boost::parser;
struct Foo
{};
constexpr bp::rule<struct foo_parser_tag, std::shared_ptr<Foo>> foo_parser =
"foo_parser";
constexpr auto foo_parser_action = [](auto & ctx) {
std::shared_ptr<Foo> & val = _val(ctx);
val = std::shared_ptr<Foo>(new Foo{});
};
constexpr auto foo_parser_def = bp::eps[foo_parser_action];
struct Bar
{
std::shared_ptr<Foo> foo;
};
constexpr bp::rule<struct bar_parser_tag, std::shared_ptr<Bar>> bar_parser =
"bar_parser";
constexpr auto bar_parser_action = [](auto & ctx) {
std::shared_ptr<Bar> & val = _val(ctx);
val = std::shared_ptr<Bar>(new Bar{});
std::optional<std::shared_ptr<Foo>> & attr = _attr(ctx);
if (attr) {
val->foo = attr.value();
}
};
constexpr auto bar_parser_def =
(bp::lit("(") > -foo_parser > bp::lit(")"))[bar_parser_action];
BOOST_PARSER_DEFINE_RULES(bar_parser, foo_parser);
}
void github_issue_294()
{
namespace bp = boost::parser;
using namespace github_issue_294_;
bp::parse("()", bar_parser, bp::blank);
}
namespace github_pr_297_ {
namespace bp = boost::parser;
constexpr auto bar_required_f = [](auto& ctx) -> bool {
@@ -558,6 +597,7 @@ void github_pr_297()
}
}
int main()
{
github_issue_36();
@@ -573,6 +613,7 @@ int main()
github_issue_279();
github_issue_285();
github_pr_290();
github_issue_294();
github_pr_297();
return boost::report_errors();
}