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?
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