boostorg / spirit

Boost.org spirit module
http://boost.org/libs/spirit
392 stars 161 forks source link

X3: Missing `as` directive #352

Closed akimd closed 6 years ago

akimd commented 6 years ago

In my grammar there are keywords whose semantic value is their string. I need the opposite of omit, and if I understand correctly the documentation, I'm looking for as_string, or as_string. Neither exist, there's just a commented include .

Thanks!

akimd commented 6 years ago

I finally understood that x3::string does what I need. I suppose as_string should be removed from the documentation?

Kojoley commented 6 years ago

It is already. See #244.

akimd commented 6 years ago

Doesn't this show that as would be a useful addition? https://stackoverflow.com/a/33817135/1353549

djowel commented 6 years ago

I'm OK either way. I'll leave it up to @Kojoley to decide if it's worth having.

Kojoley commented 6 years ago

The example actually shows need not in as parser, but in a simple collapse protection (less verbose, no need to specify a type).

I am 50/50 for having as. If you open a PR adding it I will merge it.

Kojoley commented 6 years ago

The example actually shows need not in as parser, but in a simple collapse protection (less verbose, no need to specify a type).

I was talking about this:

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

namespace boost { namespace spirit { namespace x3
{
    template <typename Subject>
    struct protect_directive : Subject
    {
        typedef Subject base_type;

        protect_directive(Subject const& subject)
          : base_type(subject) {}
    };

    struct protect_gen
    {
        template <typename Subject>
        protect_directive<typename extension::as_parser<Subject>::value_type>
        operator[](Subject const& subject) const
        {
            return { as_parser(subject) };
        }
    };

    auto const protect = protect_gen{};
}}}

namespace boost { namespace spirit { namespace x3 { namespace traits
{
    template <typename Subject, typename Context>
    struct attribute_of<x3::protect_directive<Subject>, Context>
        : attribute_of<Subject, Context> {};
}}}}

int main()
{
    namespace x3 = boost::spirit::x3;
    const std::string s = "abcd";
    std::string::const_iterator it = s.begin();
    boost::fusion::vector<
        boost::fusion::vector<char, char>
      , boost::fusion::vector<char, char>
    > r; // this emulates some complex structure adapted by fusion
    if (x3::phrase_parse(it, s.end(),
              x3::protect[x3::char_ >> x3::char_] >> x3::protect[x3::char_ >> x3::char_]
            , x3::space, r)) {
        std::cout << s << ": " << r << std::endl;
        return 0;
    }

    std::cout << "failed" << std::endl;
    return 1;
}

The SO example will look like this int_ >> ':' >> protect[int_ >> *(',' >> int_)].

@djowel what you think about such directive?

Possible names for it:

djowel commented 6 years ago

I like it! I think "protect" best reflects what it does, but "unit" sounds good too. Yes, I need that directive every now and then. What I do when I need it is place the 'protected' stuff in a rule, which inherently 'protects' collapse. Will you also write the doc for it?

Also, I'm convinced now that we should add "as". Perhaps with "as" added, we don't need "protect"?

Kojoley commented 6 years ago

I think embed is also a good name.

Will you also write the doc for it?

Sure.

I'm convinced now that we should add "as".

I don't see usages for it. May be you have a good example?

Perhaps with "as" added, we don't need "protect"?

I think as in this example is only a less verbose workaround to rule.

Comparison:

mtd parameters
rule ID, Attribute
as Attribute
unit None

rule

auto record_value = rule<struct r_record_value, Record::values_type>{} = int_ >> *(',' >> int_);
auto record = int_ >> ':' >> record_value;

as

auto record = int_ >> ':' >> as<Record::values_type>[int_ >> *(',' >> int_)];

unit

auto record = int_ >> ':' >> unit[int_ >> *(',' >> int_)];

For me unit is definitely the best way to do it.

Kojoley commented 6 years ago

I have updated the directive code above, inheriting from underlying parser makes it simple.

djowel commented 6 years ago

I think we need both. "as" can be a good (non-verbose) substitute for non-recursive rules as it supplies the attribute type. I like "unit". Let's go for that.

akimd commented 5 years ago

So, were there any updates since then?