Opened 7 years ago
Closed 7 years ago
#12094 closed Bugs (fixed)
Operator > changes attribute type
Reported by: | Owned by: | Joel de Guzman | |
---|---|---|---|
Milestone: | To Be Determined | Component: | spirit |
Version: | Boost 1.61.0 | Severity: | Problem |
Keywords: | Cc: |
Description
Following code should compile, but it does not.
#include <boost/spirit/home/x3.hpp> #include <string> using namespace boost::spirit::x3; auto r = rule<class r, std::string>{} = +char_; int main() { std::string input = ""; std::string output; auto b = std::begin(input); auto e = std::end(input); parse(b, e, 'a' > (r | r), output); }
Change History (15)
comment:2 by , 7 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
comment:3 by , 7 years ago
Why 'a' >> (r | r) compiles then? :-)
I'd expect attr of (r | r) to be std::string because attr of r is std::string, why it should be variant?
comment:4 by , 7 years ago
Resolution: | wontfix |
---|---|
Status: | closed → reopened |
Sorry, I had to reopen this issue - not sure if commenting on closed issues does anything.
'a' >> (r | r) - compiles, attr is std::string
*('a' >> (r | r)) - compiles, attr is std::string
'a' > (r | r) - does not compile
*('a' > (r | r)) - attr is std::vector<std::string>. Wat?
comment:5 by , 7 years ago
Hmmm... Does 'a' >> (r | r) give you the correct behavior? It's not enough that it compiles.
comment:6 by , 7 years ago
Yes, it works as expected http://melpon.org/wandbox/permlink/htuj4CIXodD02pSb (skips character 'a', stores 'b'). I don't quite see why it shouldn't.
comment:7 by , 7 years ago
I see that now and I know the reason why: I made some special treatment for alternatives. Alas the special case handling does not apply for expect_directive<alternative>, or whatever else that might hold an alternative. I'm not sure if I should 'fix' this. But that special case becomes a precedent indeed ;-/
In any case, allow me to repeat myself again: don't fight the attribute mechanism. Try to form your attributes as closely as possible to the rules and grammars that models it.
follow-up: 10 comment:8 by , 7 years ago
So, I could write ('a' >> expect[r | r]) instead? Does not compile, but now it is as expected. :-)
About "don't fight":
std::string input = "\\n\\t\\u1234"; ... parse(b, e, *('\\' > (escape_seq | unicode)), ...);
What type of attribute it should return? It can be std::vector<boost::variant<esc_ast, unicode_ast>> (where esc_ast and unicode_ast are inheriting from x3::position_tagged because you need this) or in can be simple std::string. I think you can't tell the attribute type just by looking at the rule.
follow-up: 11 comment:9 by , 7 years ago
So you say "Does not compile, but now it is as expected. :-)". Actually, this:
'a' > (r | r)
is the same as this:
'a' >> expect[r | r]
But you say that the first is not expected and the second is expected.
comment:10 by , 7 years ago
Replying to mikhail.strelnikov@…:
About "don't fight":
std::string input = "\\n\\t\\u1234"; ... parse(b, e, *('\\' > (escape_seq | unicode)), ...);What type of attribute it should return? It can be std::vector<boost::variant<esc_ast, unicode_ast>> (where esc_ast and unicode_ast are inheriting from x3::position_tagged because you need this) or in can be simple std::string. I think you can't tell the attribute type just by looking at the rule.
If esc_ast, unicode_ast can both be a string, then the natural attribute would be vector<std::string>. An attribute of std::string is just pushing it.
follow-up: 12 comment:11 by , 7 years ago
Why this works?
#include <boost/spirit/home/x3.hpp> #include <string> using namespace boost::spirit::x3; auto r = rule<class r, std::string>{} = +char_; auto r_or_r = rule<class r, std::string>{} = r | r; auto expect_r_or_r = rule<class r, std::string>{} = expect[r_or_r]; auto a_expect_r_or_r = rule<class r, std::string>{} = 'a' > expect_r_or_r; int main() { std::string input = "a"; std::string output; auto b = std::begin(input); auto e = std::end(input); parse(b, e, a_expect_r_or_r, output); }
comment:12 by , 7 years ago
Replying to mikhail.strelnikov@…:
Why this works?
[snip]
Why? Because you placed it in a rule with an exact attribute. Spirit does not have to deduce (guess) what you want.
comment:13 by , 7 years ago
OK, alright, I pushed a "fix" for this issue. The reason I did it anyway, despite my comments above, is that the special case handling for alternatives became a precedent and it would be unwise not to give the expect operator another spacial treatment due to the implicit nature of the expression:
a > (b | c)
comment:15 by , 7 years ago
Resolution: | → fixed |
---|---|
Status: | reopened → closed |
Oh and BTW, thanks for your persistence! I really appreciate it.
It may be unintuitive, but it is not really a bug. Sequences (including expect operators in x3) may accept a tuple or container (e.g. string). If it gets a container, it expects its nodes to have an attribute of either a container, or the container's value type. See http://www.boost.org/doc/libs/1_60_0/libs/spirit/doc/html/spirit/qi/reference/operator/sequence.html
But what is the natural (inherent) attribute type of (r | r)? It is a variant, not a container. That is why X3 got tripped. It can't handle the ambiguity. X3's attribute handling mechanism is not perfect. As it descends into the alternative, it already decided that its attribute cannot handle the container, and thus tries to pass the element type of the container.
Tip: Don't fight the attribute mechanism. Try to form your attributes as closely as possible to the rules and grammars that models it.