Skip to content

Optional rule in sequence with vector rule drops the optional rule's attribute #248

@knowikow

Description

@knowikow
  • Boost version: 1.88.0
  • Environment: MS Visual Studio 2022

Here is a test that shows a possible problem that might be related to #125 -- I also checked the test from #125, and it worked for me:

#include <boost/parser/parser.hpp>
#include <boost/test/included/unit_test.hpp>
#include <boost/utility/identity_type.hpp>

#include <tuple>
#include <vector>

namespace bp = boost::parser;

static constexpr bp::rule<struct symbol, int>               symbol  = "//";
static constexpr bp::rule<struct vector, std::vector<int>>  list    = "<int>(,<int>)*";
static constexpr bp::rule<struct working, std::vector<int>> working = "working";
static constexpr bp::rule<struct failing, std::vector<int>> failing = "failing";

static auto const symbol_def = bp::symbols<int>{
    {"//",  0}
};
static constexpr auto list_def    = bp::int_ % ',';
static constexpr auto working_def = -symbol >> (bp::int_ % ',');
static constexpr auto failing_def = -symbol >> list;

BOOST_PARSER_DEFINE_RULES(
    symbol,
    list,
    working,
    failing
);

template<typename> constexpr int  rule = 0;
template<>         constexpr auto rule<decltype(working)> = working;
template<>         constexpr auto rule<decltype(failing)> = failing;

BOOST_AUTO_TEST_CASE_TEMPLATE(
    issue,
    R,
    BOOST_IDENTITY_TYPE((std::tuple<decltype(working), decltype(failing)>))
)
{
    auto const result   = bp::parse("//1,2,3", rule<R>, bp::ws, bp::trace::on);
    auto const expected = std::vector<int>{0, 1, 2, 3};
    BOOST_REQUIRE(result.has_value());
    BOOST_CHECK_EQUAL_COLLECTIONS(result->begin(), result->end(), expected.begin(), expected.end());
}

We have two top-level rules, both are parsing a comma-separated list of integers into a vector, with an optional symbol at the start that prepends 0:

  • working includes the rule for the comma-separated list directly: -symbol >> (bp::int_ % ',');
  • failing uses a separate rule named list: -symbol >> list

Referring to the tutorial section Sequence parser attribute rules

optional >> C -> C

my expectation was that both rules, when used on the string "//1,2,3", would produce a vector {0, 1, 2, 3}, but only working does. The failing rule produces the vector {1, 2, 3}, i. e., it drops the attribute from the optional symbol.
The output for the failing test is

check { result->begin(), result->end() } == { expected.begin(), expected.end() } has failed. 
Mismatch at position 0: 1 != 0
Mismatch at position 1: 2 != 1
Mismatch at position 2: 3 != 2
Collections size mismatch: 3 != 4

and the debug trace output is

[begin failing; input="//1,2,3"]
  [begin -/ >> <int>(/<int>)*; input="//1,2,3"]
    [begin -/; input="//1,2,3"]
      [begin /; input="//1,2,3"]
        [begin symbols<int>; input="//1,2,3"]
          matched "//"
          attribute: 0
        [end symbols<int>; input="1,2,3"]
        matched "//"
        attribute: 0
      [end /; input="1,2,3"]
      matched "//"
      attribute: 0
    [end -/; input="1,2,3"]
    [begin <int>(/<int>)*; input="1,2,3"]
      [begin int_ % ','; input="1,2,3"]
        [begin int_; input="1,2,3"]
          matched "1"
          attribute: 1
        [end int_; input=",2,3"]
        [begin ','; input=",2,3"]
          [begin char_(','); input=",2,3"]
            matched ","
            attribute: ','
          [end char_(','); input="2,3"]
          matched ","
        [end ','; input="2,3"]
        [begin int_; input="2,3"]
          matched "2"
          attribute: 2
        [end int_; input=",3"]
        [begin ','; input=",3"]
          [begin char_(','); input=",3"]
            matched ","
            attribute: ','
          [end char_(','); input="3"]
          matched ","
        [end ','; input="3"]
        [begin int_; input="3"]
          matched "3"
          attribute: 3
        [end int_; input=""]
        [begin ','; input=""]
          [begin char_(','); input=""]
            no match
          [end char_(','); input=""]
          no match
        [end ','; input=""]
        matched "1,2,3"
        attribute: <<unprintable-value>>
      [end int_ % ','; input=""]
      matched "1,2,3"
      attribute: <<unprintable-value>>
    [end <int>(/<int>)*; input=""]
    matched "//1,2,3"
    attribute: (<<unprintable-value>>)
  [end -/ >> <int>(/<int>)*; input=""]
  matched "//1,2,3"
  attribute: <<unprintable-value>>
[end failing; input=""]
--------------------
parse succeeded
--------------------

Did I miss something in the definition of my list rule?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions