-
Notifications
You must be signed in to change notification settings - Fork 161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
boost::spirit::x3 problem with any ast class representing a std::string #679
Comments
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Further reduced to: #include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <vector>
namespace x3 = boost::spirit::x3;
int main()
{
char const* s = "abaabb", *e = s + std::strlen(s);
using Foo = std::vector<x3::variant<int>>;
using Bar = std::vector<x3::variant<Foo, int>>;
Bar x;
parse(s, e, +('a' >> x3::attr(Foo{}) | 'b' >> x3::attr(int{})), x);
}
|
Interesting, if I replace |
It works because #include <boost/spirit/home/x3.hpp>
#include <boost/variant.hpp>
#include <vector>
namespace x3 = boost::spirit::x3;
int main()
{
char const* s = "abaabb", *e = s + std::strlen(s);
using Qaz = std::vector<boost::variant<int>>;
using Foo = std::vector<boost::variant<Qaz, int>>;
using Bar = std::vector<boost::variant<Foo, int>>;
Bar x;
parse(s, e, +('a' >> x3::attr(Foo{}) | 'b' >> x3::attr(int{})), x);
} |
That looks like an amazing reduction from the original problem. Thanks again for your work in trying to resolve this. Would you be able to explain, in X3 user terms, what you have concluded, what might be the underlying problem and if this would require a code fix, or is there a user level workaround that might be deployed? From a user level pespective, it looks like we have nested pairs of vectors and variants. You seem to be dropping some hints that it is the variants that interest you. However, I have been thinking about nesting of vectors. Please could you permit me to put forward some ideas; not that I ever expect to come any where near your expertise but in the hope that my ideas, however misguided, might just trigger a line of thought that could lead you to a solution. If the attribute (type) of the element of a nested vector is compatible with the attribute (type) of the parent vector, then, according to my very limited understanding, attribute collapsing occurs. This is an essential behaviour for synthesizing attributes, and permits, for instance a mixed sequence of chars and strings to be collapsed into a single string. Very crudely, this can be illustrated by this example:
which obviously fails to compile because the attribute is collapsed into a single (unnested) By extension, I surmise that the attribute of nested vectors of compatible variants would also get collapsed. If I apply this theory to your example:
which does compile. Therefore it would appear to me that what is needed is some mechanism to break this collapsing. Is there a directive or user level construct that would break this collapsing? |
I have another example, which I believe to be suffering from the same problem.
The starting point should be with these two defines commented:
Which gives a working parser which compiles, but for the input supplied, exits with a non-zero status because the end of statement ';' is missing from the grammar. So I now add that terminator to the grammar
and of course, I have to change the contents of the variant by adding
but this fails to compile, with the guts of the error message being:
This was a total surprise to me. Why did adding something extra to the end of my start_rule break things so dramatically? But I am becoming used to these error messages, and on a hunch, changed the collective
Can you possibly provide an explanation for this X3 behaviour? There's a hint of the collapsing attributes, mentioned above, with the workaround being similar: drop one level of vector nesting. |
With all of the workarounds suggested so far, I am still unable to get my real world parser to compile. If a gvien rule can be ligitimately collapsed to, say, a single char, then that is what is passed, obviously failing higher levels which only expect that rule, not what it might be collapsed to. I think I need some sort of trick/workaround/fix that stops attribute collapsing at a given rule, whether a variant or vector. Can anyone help? |
It works for me: https://wandbox.org/permlink/joueNN8PK1wmyMl7
I do not know what you meant, but a rule is a barrier for any trickery. |
Nikita, I'm pretty sure what Borkeman meant by "stop attribute which uses several specialized rules for:
where the specialized rules are:
By "stop attribute collapsing", I believe Borkeman
More specifically, even if either A or B were Unused or the same, The obvious advantage of "not-collapsing" from the end-user's Obviously, using only the "not-collapsing" rules would require But run-time or memory cost is insignificant complared to developement -regards, |
Attribute collapsing is something that does not exist. Sequence parser has two (three) modes: parse as container or tuple (or fusion map). It decides which one will be use solely by the actual attribute provided. When it parses a container, each sequence parser subject is invoked in "parse to container mode". If you want some part of the sequence to behave like a completely separate parser -- hide it behind a rule or some other non-passthrough parser (like #352 (comment)).
"if either A or B were Unused or the same" then "tuple<A,B>" would be simply A or B, according to the cited rules.
It is simply impossible. You need an actual attribute.
I have no idea what does it mean. |
I picked up the notion of attribute_collapsing from the employee tutorial,
You may be correct, that it does not exist per se under the hood, but the documentation uses attribute_collapsing, so it only seems fair to reference that and continue use terms that are in the documentation. |
That does not help me to understand what you want in any way. I feel like this off-topic discussion could continue forever. I have to repeat myself: If you have a future request, please, create an example - a code (as short as possible) you would like to compile and run. |
There is, I believe, a genuine problem here. Let me illustrate with another example. My starting point is
which compiles and runs without issue. Next I add
However, this fails to compile giving
essentially telling me to add a
essentially telling me to add a But this is utter madness. Why do I have to add This also breaks the notion you @Kojoley suggested that
What is going wrong with X3, or what am I doing wrong? |
I feel your frustration, but you are posting the very similar code multiple times. I cannot say for sure it is the same bug (#679 (comment)), but I am not going to investigate it right now either because there is a high probability that it is. When I or somebody else fix the MCVE above I will recheck your examples. You can use a workaround (as you did in #681) until the bug is fixed. |
Given you have stated
Please could you explain to me what the bug is so that I might devise (or you might suggest) a workaround. None of the workarounds that I have used, to get the code to compile, is acceptable because I end up with code that does not perform the inteded task. ATM I don't care how clumsy a workaround might be, as long as it can be applied consistently and scaled to my real world code. To be clear, I am not interested in any prolonged discussion about possible causes or ways to fix. I just want X3 to do the job it is supposed to. At present, I am blocked and cannot get X3 to work in several applications. |
You code that does not compile from #679 (comment) with an applied workaround: #include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace x3 = boost::spirit::x3;
namespace minimal { namespace ast
{
struct white : std::string {using std::string::string;};
struct braced {char open; std::string text; char close;};
struct gap_item : x3::variant<white,braced> {using base_type::operator=;};
struct gap : std::vector<gap_item> {};
struct start_item : x3::variant<gap,std::string> {using base_type::operator=;};
struct start : std::vector<start_item> {using std::vector<start_item>::vector;};
}}
BOOST_FUSION_ADAPT_STRUCT(minimal::ast::braced, open, text, close)
namespace minimal { namespace parser
{
using x3::char_;
using x3::space;
using x3::raw;
x3::rule<struct white, ast::white> const white = "white";
x3::rule<struct braced, ast::braced> const braced = "braced";
x3::rule<struct gap, ast::gap> const gap = "gap";
x3::rule<struct start_item, ast::start_item> const start_item = "start_item";
x3::rule<struct start, ast::start> const start = "start";
auto const white_def = raw[+space];
auto const braced_def = char_('{') >> *(char_ -'}') >> char_('}'); // { ... }
auto const gap_def = +(white | braced); // spaces etc
auto const start_item_def = gap | +(char_ - '{' - space);
auto const start_def = +start_item; // gap=container or string
BOOST_SPIRIT_DEFINE(white, gap, braced, start_item, start);
}}
int main()
{
char const* iter = "? {;};", * const end = iter + std::strlen(iter);
minimal::ast::start ast;
return !parse(iter, end, minimal::parser::start, ast) || iter!=end;
} |
Thank you very much for that code you supplied with a workaround applied. That works for me. I want a workaround that is consistent and scaleable to real world X3 applications. Your workaround appears to be: "for each instance of a container, add an additional rule in the parser specifically for the variant". This is clumsy (which I said I did not mind, in order to get me going), and by applying it everywhere, it is consistent and it has the possibility of being scalable (I can apply it through out my X3 applications, but not yet tried). However, you did not explain what is the nature of the bug and why this solution is a viable workaround. Please could you explain. Independently, and with suggestions from others, I discovered another workaround. All of the inherited classes are replaced by structures containing a single item. This means that single item tuples are created. You have warned that these might not be supported in all cases. I prefer this workaround because it changes the AST (it is just a different way of defining the class) rather than the change to the parser (which adds extra clutter and breaks the spirit of X3 [pun!]).
Please could you comment on this alternative workaround compared to yours. I need your expertise to advise me, and others, given your understanding of the underlying problem (which I would appreciate you explaining to me). |
All your questions were already answered. I have nothing more to say, and I am not going to repeat myself over and over and over and over again. |
#702 will fix the main problem and #679 (comment). The #679 (comment) as well as other code with single element tuples still gives compile errors, most likely because of #178. |
I have two, what I presume to be legitimate, ways of defining a class in my ast that represents a string, illustrated here:
or
which I use in several places for things like literals, identifiers, comments, or even white space, which I want to capture in my ast.
In some places I have to use the first form, and in other places I have to use the second form, otherwise I get compile errors with horrendous error messages:
embedded in several pages of error output with no clue regarding the line of source code which might be at fault.
How should I interpret this type of error message?
Why do I have to use a different form/style of class in different places?
This minimal example illustrates the problem (when the #defines are [un]commented)
rgw29_minimal.cpp.txt
The text was updated successfully, but these errors were encountered: