Skip to content

Commit a6c0b0b

Browse files
committed
X3: rollback iterator when rule fails to parse
This commit adjusts work of commit 2db3fde. It corrected error_handler which should not skip whitespaces but introduced a regression where handlers returning fail were still moving the iterator forward. This commit adds iterator rollback and synchronizes rule's and guard's iterators behavior.
1 parent 07c58b4 commit a6c0b0b

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

include/boost/spirit/home/x3/nonterminal/detail/rule.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,13 +236,16 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
236236
{
237237
for (;;)
238238
{
239+
Iterator it = first;
240+
239241
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
240242
try
241243
#endif
242244
{
243245
if (parse_rhs_main(
244-
rhs, first, last, context, rcontext, attr, mpl::false_()))
246+
rhs, it, last, context, rcontext, attr, mpl::false_()))
245247
{
248+
first = it;
246249
return true;
247250
}
248251
}

test/x3/rule4.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <string>
1313
#include <cstring>
1414
#include <iostream>
15+
#include <vector>
1516
#include "test.hpp"
1617

1718
namespace x3 = boost::spirit::x3;
@@ -90,6 +91,8 @@ main()
9091
using boost::spirit::x3::rule;
9192
using boost::spirit::x3::int_;
9293
using boost::spirit::x3::lit;
94+
using boost::spirit::x3::lexeme;
95+
using boost::spirit::x3::eol;
9396

9497
{ // show that ra = rb and ra %= rb works as expected
9598
rule<class a, int> ra;
@@ -144,6 +147,8 @@ main()
144147
auto r = rule<my_rule_class, char const*>()
145148
= '(' > int_ > ',' > int_ > ')';
146149

150+
got_it = 0;
151+
147152
BOOST_TEST(test("(123,456)", r));
148153
BOOST_TEST(!test("(abc,def)", r));
149154
BOOST_TEST(!test("(123,456]", r));
@@ -153,6 +158,22 @@ main()
153158
BOOST_TEST(got_it == 1);
154159
}
155160

161+
{ // regression test for #833
162+
// rules which return error_handler_result::fail should trigger iterator rollback
163+
164+
auto string_literal = rule<my_rule_class, std::string>()
165+
= lexeme['"' > *~char_("\"\n\r") > '"'];
166+
auto r = rule<class r_id, std::vector<std::string>>()
167+
= *string_literal > eol;
168+
169+
got_it = 0;
170+
171+
BOOST_TEST(test("\"abc\"\n", r));
172+
BOOST_TEST_THROWS(test("\"abc\n", r), x3::expectation_failure<char const*>);
173+
174+
BOOST_TEST(got_it == 1);
175+
}
176+
156177
{ // on_success gets pre-skipped iterator
157178
auto r = rule<on_success_gets_preskipped_iterator, char const*>()
158179
= lit("b");

0 commit comments

Comments
 (0)