Skip to content

Commit 0eacce6

Browse files
committed
Add special-casing of nope attributes in seq_parser, so that seq_parser does
not assign over valid values in a sequence's attribute after successfully parsing a subsquent nope-attributes parser. Test cases by Andreas Buhr. Fixes #279 Fixes #285
1 parent 5e61ba4 commit 0eacce6

File tree

2 files changed

+114
-23
lines changed

2 files changed

+114
-23
lines changed

include/boost/parser/parser.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4533,7 +4533,8 @@ namespace boost { namespace parser {
45334533

45344534
if constexpr (
45354535
(out_container == attr_container &&
4536-
!was_merged_into_adjacent_container) ||
4536+
!was_merged_into_adjacent_container &&
4537+
!detail::is_nope_v<attr_t>) ||
45374538
is_in_a_group) {
45384539
parser.call(
45394540
first, last, context, skip, flags, success, out);
@@ -4559,7 +4560,9 @@ namespace boost { namespace parser {
45594560
}
45604561
using just_x = attr_t;
45614562
using just_out = detail::remove_cv_ref_t<decltype(out)>;
4562-
if constexpr (
4563+
if constexpr (detail::is_nope_v<attr_t>) {
4564+
// nothing to do
4565+
} if constexpr (
45634566
(!out_container ||
45644567
!std::is_same_v<just_x, just_out>) &&
45654568
std::is_assignable_v<just_out &, just_x &&> &&
@@ -4732,7 +4735,7 @@ namespace boost { namespace parser {
47324735
} else {
47334736
// If you see an error here, it's because you are using an
47344737
// invocable for a semantic action that returns a non-void
4735-
// type Ret, but values fo type Ret is not assignable to
4738+
// type Ret, but values of type Ret is not assignable to
47364739
// _val(ctx). To fix this, only use this invocable within
47374740
// a rule whose attribute type is assignable from Ret, or
47384741
// remove the non-void return statement(s) from your

test/github_issues.cpp

Lines changed: 108 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -348,22 +348,36 @@ void github_issue_248()
348348
namespace github_issue_268_ {
349349
namespace bp = boost::parser;
350350
constexpr bp::rule<struct name, std::string_view> name = "name";
351-
auto name_def = bp::string_view[bp::lexeme[+(bp::lower | bp::upper | bp::digit | bp::char_("_"))]];
351+
auto name_def = bp::string_view[bp::lexeme[+(
352+
bp::lower | bp::upper | bp::digit | bp::char_("_"))]];
352353
BOOST_PARSER_DEFINE_RULES(name)
353354
constexpr bp::rule<struct qd_vec, std::vector<double>> qd_vec = "qd_vec";
354-
auto qd_vec_def = bp::lit("\"") >> bp::double_ % (bp::lit(",") | (bp::lit("\"") >> bp::lit(",") >> bp::lit("\""))) >> bp::lit('\"');
355+
auto qd_vec_def = bp::lit("\"") >>
356+
bp::double_ %
357+
(bp::lit(",") |
358+
(bp::lit("\"") >> bp::lit(",") >> bp::lit("\""))) >>
359+
bp::lit('\"');
355360
BOOST_PARSER_DEFINE_RULES(qd_vec)
356361
struct lu_table_template_1
357362
{
358363
std::vector<double> index_1;
359364
std::string_view variable_1;
360365
};
361-
constexpr boost::parser::rule<struct lu_table_template_1_tag, lu_table_template_1> lu_table_template_1_rule = "lu_table_template_1";
362-
auto lu_table_template_1_rule_def = (bp::lit("index_1") >> '(' >> qd_vec >> ')' >> ';') >> (bp::lit("variable_1") >> ':' >> name >> ';');
366+
constexpr boost::parser::
367+
rule<struct lu_table_template_1_tag, lu_table_template_1>
368+
lu_table_template_1_rule = "lu_table_template_1";
369+
auto lu_table_template_1_rule_def = (bp::lit("index_1") >> '(' >> qd_vec >>
370+
')' >> ';') >>
371+
(bp::lit("variable_1") >> ':' >> name >>
372+
';');
363373
BOOST_PARSER_DEFINE_RULES(lu_table_template_1_rule)
364374

365-
constexpr boost::parser::rule<struct lu_table_template_1_permut_tag, lu_table_template_1> lu_table_template_1_permut_rule = "lu_table_template_1";
366-
auto lu_table_template_1_permut_rule_def = (bp::lit("index_1") >> '(' >> qd_vec >> ')' >> ';') || (bp::lit("variable_1") >> ':' >> name >> ';');
375+
constexpr boost::parser::
376+
rule<struct lu_table_template_1_permut_tag, lu_table_template_1>
377+
lu_table_template_1_permut_rule = "lu_table_template_1";
378+
auto lu_table_template_1_permut_rule_def =
379+
(bp::lit("index_1") >> '(' >> qd_vec >> ')' >> ';') ||
380+
(bp::lit("variable_1") >> ':' >> name >> ';');
367381
BOOST_PARSER_DEFINE_RULES(lu_table_template_1_permut_rule)
368382
}
369383
#endif
@@ -377,22 +391,32 @@ void github_issue_268()
377391

378392
auto const def_result = bp::parse(
379393
inputstring, lu_table_template_1_rule_def, bp::blank, bp::trace::off);
380-
std::cout<< "seq_parser generates this type:\n" << typeid(def_result.value()).name() << std::endl;
394+
std::cout << "seq_parser generates this type:\n"
395+
<< typeid(def_result.value()).name() << std::endl;
381396
BOOST_TEST(def_result);
382397

383398
auto const permut_def_result = bp::parse(
384-
inputstring, lu_table_template_1_permut_rule_def, bp::blank, bp::trace::off);
385-
std::cout<< "permut_parser generates this type:\n" << typeid(permut_def_result.value()).name() << std::endl;
399+
inputstring,
400+
lu_table_template_1_permut_rule_def,
401+
bp::blank,
402+
bp::trace::off);
403+
std::cout << "permut_parser generates this type:\n"
404+
<< typeid(permut_def_result.value()).name() << std::endl;
386405
BOOST_TEST(permut_def_result);
387406

388407
auto const result = bp::parse(
389408
inputstring, lu_table_template_1_rule, bp::blank, bp::trace::off);
390-
std::cout<< "seq_parser in rule generates this type:\n" << typeid(result.value()).name() << std::endl;
409+
std::cout << "seq_parser in rule generates this type:\n"
410+
<< typeid(result.value()).name() << std::endl;
391411
BOOST_TEST(result);
392412

393413
auto const permut_result = bp::parse(
394-
inputstring, lu_table_template_1_permut_rule, bp::blank, bp::trace::off);
395-
std::cout<< "permut_parser generates this type:\n" << typeid(permut_result.value()).name() << std::endl;
414+
inputstring,
415+
lu_table_template_1_permut_rule,
416+
bp::blank,
417+
bp::trace::off);
418+
std::cout << "permut_parser generates this type:\n"
419+
<< typeid(permut_result.value()).name() << std::endl;
396420
BOOST_TEST(permut_result);
397421
#endif
398422
}
@@ -401,17 +425,80 @@ void github_issue_279()
401425
{
402426
namespace bp = boost::parser;
403427

404-
constexpr auto condition_clause = bp::lit(U"while") >
405-
bp::lit(U"someexpression") >> bp::attr(true);
428+
{
429+
constexpr auto condition_clause =
430+
bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true);
406431

407-
constexpr auto do_statement =
408-
bp::lexeme[bp::lit(U"do") >> &bp::ws] > -condition_clause > bp::eol;
432+
constexpr auto do_statement =
433+
bp::lexeme[bp::lit(U"do") >> &bp::ws] > -condition_clause > bp::eol;
409434

410-
auto const result = bp::parse(
411-
U"do\n", do_statement, bp::blank, bp::trace::off);
435+
auto const result =
436+
bp::parse(U"do\n", do_statement, bp::blank, bp::trace::off);
437+
BOOST_TEST(result);
438+
std::optional<bool> const & condition = result.value();
439+
BOOST_TEST(!condition.has_value());
440+
}
441+
442+
{
443+
constexpr auto condition_clause =
444+
bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true);
445+
446+
constexpr auto do_statement_reverse =
447+
-condition_clause > bp::lexeme[bp::lit(U"do") >> &bp::ws] > bp::eol;
448+
449+
auto const result =
450+
bp::parse(U"do\n", do_statement_reverse, bp::blank, bp::trace::off);
451+
BOOST_TEST(result);
452+
std::optional<bool> const & condition = result.value();
453+
BOOST_TEST(!condition.has_value());
454+
}
455+
}
456+
457+
namespace github_issue_285_ {
458+
namespace bp = boost::parser;
459+
460+
struct Content
461+
{
462+
~Content()
463+
{
464+
int setbreakpointhere = 0;
465+
(void)setbreakpointhere;
466+
}
467+
};
468+
constexpr bp::rule<struct content_tag, std::shared_ptr<Content>> content =
469+
"content";
470+
constexpr auto content_action = [](auto & ctx) {
471+
std::shared_ptr<Content> & result = _val(ctx);
472+
result = std::make_shared<Content>();
473+
};
474+
constexpr auto content_def =
475+
(bp::lit(U"content") >> bp::eol)[content_action];
476+
BOOST_PARSER_DEFINE_RULES(content);
477+
}
478+
479+
void github_issue_285()
480+
{
481+
using namespace github_issue_285_;
482+
namespace bp = boost::parser;
483+
484+
constexpr auto prolog = bp::lit(U"prolog") >> bp::eol;
485+
486+
constexpr auto epilog =
487+
bp::no_case[bp::lexeme[bp::lit(U"epi") >> bp::lit(U"log")]] >> bp::eol;
488+
489+
constexpr auto full_parser = prolog >> content >> epilog;
490+
491+
std::string teststring =
492+
"prolog\n"
493+
"content\n"
494+
"epilog\n";
495+
496+
// "content" produces a shared_ptr with the result.
497+
// The "epilog" parser must not delete the result.
498+
499+
auto const result = bp::parse(teststring, full_parser, bp::blank);
412500
BOOST_TEST(result);
413-
std::optional<bool> const & condition = result.value();
414-
BOOST_TEST(!condition.has_value());
501+
BOOST_TEST(result.value().get() != nullptr);
415502
}
416503

417504

@@ -428,5 +515,6 @@ int main()
428515
github_issue_248();
429516
github_issue_268();
430517
github_issue_279();
518+
github_issue_285();
431519
return boost::report_errors();
432520
}

0 commit comments

Comments
 (0)