Search code examples
c++boostboost-spiritboost-spirit-x3

Spirit X3: attribute of alternative parser, not `char`, but `variant<char, char>`


According to spirit x3 attribute collapsing rule, the attribute of an anternative parser with 2 alternation having same attribute, should collapse, i.e. a: A, b: A --> (a | b): A, but the code below shows its not, is it a bug or my fault?

Here is the spirit x3 documentation of compound attribute rules https://www.boost.org/doc/libs/develop/libs/spirit/doc/x3/html/spirit_x3/quick_reference/compound_attribute_rules.html

I've got a code snippet to reproduce this question

Here is the code https://wandbox.org/permlink/7MvN03yiX7ir3esE

And the original code in case the link expired

#include <boost/spirit/home/x3.hpp>
#include <iostream>

namespace x3 = boost::spirit::x3;
namespace fusion = boost::fusion;

using x3::_val;
using x3::_attr;
using x3::_where;
using fusion::at_c;

auto const string_def = x3::lexeme["\"" >> *(x3::symbols<char>({ {"\\\"", '"'} }) | (x3::print - '\"')) > "\""][([](auto& ctx) {
    std::cout << typeid(_attr(ctx)).name();
    //should _attr(ctx) be a vector<char>, according to attribute collapsing rule?
})];

int main() {
    std::string input = R"__("hello\"world")__";
    x3::parse(input.begin(), input.end(), string_def);
}

Bascally, the code parse a string literal, which contains a number of chars (*), which is either a character except '"' (x3::print-'"'), or a escape sequence "\\\"" representing the character '"' (x3::symbol<char>...), both of them has a attribute of char, and char | char should be char, not variant<char, char>.

the cout part of the code shows result like St6vectorIN5boost7variantINS0_6detail7variant13over_sequenceINS0_3mpl6l_itemIN4mpl_5long_ILl2EEEcNS6_INS8_ILl1EEEcNS5_5l_endEEEEEEEJEEESaISF_EE, after demangling, it is vector<variant<over_sequence<...>>> and variant<over_sequence<> is basically a workaround of variant<T...> in pre-C++11 times.

So what's wrong with the code, should it be vector<char>, not vector<variant>? And BTW, can I customize attribute collapsing rule myself?


Solution

  • As @IgorR. mentioned in comment, semantic action suppresses attribute propagation, I ignored that point. So problem solved, I might need just parse this into std::string.

    For some reason I need parsing this into a unique_ptr object, so I need separate the parser into a rule<StringContent, std::string> and a rule<StringLiteral, std::unique_ptr<ast::StringLiteral>, true>, problem solved