Skip to content

Commit c674e94

Browse files
committed
Don't reuse the attribute-generating path in rule_parser's out-param overload
of call. Doing so was wiping out previous partial results, in cases like foo >> bar, where foo produces a T, and bar is a rule that produces vector<T>. Fixes #248.
1 parent 84ee288 commit c674e94

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

include/boost/parser/parser.hpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5411,9 +5411,28 @@ namespace boost { namespace parser {
54115411
if constexpr (CanUseCallbacks && Context::use_callbacks) {
54125412
call(first, last, context, skip, flags, success);
54135413
} else {
5414-
auto attr = call(first, last, context, skip, flags, success);
5415-
if (success)
5416-
detail::assign(retval, std::move(attr));
5414+
locals_type locals = detail::make_locals<locals_type>(context);
5415+
auto params = detail::resolve_rule_params(context, params_);
5416+
tag_type * const tag_ptr = nullptr;
5417+
auto const rule_context = detail::make_rule_context(
5418+
context, tag_ptr, retval, locals, params);
5419+
5420+
[[maybe_unused]] auto _ = detail::scoped_trace(
5421+
*this, first, last, rule_context, flags, retval);
5422+
5423+
bool dont_assign = false;
5424+
parse_rule(
5425+
tag_ptr,
5426+
first,
5427+
last,
5428+
rule_context,
5429+
skip,
5430+
flags,
5431+
success,
5432+
dont_assign,
5433+
retval);
5434+
if (!success || dont_assign)
5435+
retval = Attribute_();
54175436
}
54185437
}
54195438

test/github_issues.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,63 @@ void github_issue_223()
287287
}
288288
}
289289

290+
namespace github_issue_248_ {
291+
namespace bp = boost::parser;
292+
293+
static constexpr bp::rule<struct symbol, int> symbol = "//";
294+
static constexpr bp::rule<struct vector, std::vector<int>> list =
295+
"<int>(,<int>)*";
296+
static constexpr bp::rule<struct working, std::vector<int>> working =
297+
"working";
298+
static constexpr bp::rule<struct failing, std::vector<int>> failing =
299+
"failing";
300+
301+
static auto const symbol_def = bp::symbols<int>{{"//", 0}};
302+
static constexpr auto list_def = bp::int_ % ',';
303+
static constexpr auto working_def = -symbol >> (bp::int_ % ',');
304+
static constexpr auto failing_def = -symbol >> list;
305+
306+
BOOST_PARSER_DEFINE_RULES(symbol, list, working, failing);
307+
}
308+
309+
void github_issue_248()
310+
{
311+
namespace bp = boost::parser;
312+
313+
using namespace github_issue_248_;
314+
315+
{
316+
auto const result = bp::parse("//1,2,3", working, bp::ws);
317+
auto const expected = std::vector<int>{0, 1, 2, 3};
318+
BOOST_TEST(result.has_value());
319+
bool const equal = std::equal(
320+
result->begin(), result->end(), expected.begin(), expected.end());
321+
BOOST_TEST(equal);
322+
if (!equal) {
323+
std::cout << "contents of *result:\n";
324+
for (auto x : *result) {
325+
std::cout << x << '\n';
326+
}
327+
std::cout << '\n';
328+
}
329+
}
330+
{
331+
auto const result = bp::parse("//1,2,3", failing, bp::ws);
332+
auto const expected = std::vector<int>{0, 1, 2, 3};
333+
BOOST_TEST(result.has_value());
334+
bool const equal = std::equal(
335+
result->begin(), result->end(), expected.begin(), expected.end());
336+
BOOST_TEST(equal);
337+
if (!equal) {
338+
std::cout << "contents of *result:\n";
339+
for (auto x : *result) {
340+
std::cout << x << '\n';
341+
}
342+
std::cout << '\n';
343+
}
344+
}
345+
}
346+
290347

291348
int main()
292349
{
@@ -298,5 +355,6 @@ int main()
298355
github_issue_125();
299356
github_issue_209();
300357
github_issue_223();
358+
github_issue_248();
301359
return boost::report_errors();
302360
}

0 commit comments

Comments
 (0)