2

Buon giorno, I have to parse something such as:

foo: 123
"bar": 456

The quotes should be removed if they are here. I tried:

((+x3::alnum) | ('"' >> (+x3::alnum) >> '"'))

But the parser actions for this are of type variant<string, string> ; is there a way to make it so that the parser understands that those two are equivalent, and for my action to only get a single std::string as argument in its call?

edit: minimal repro (live on godbolt: https://gcc.godbolt.org/z/GcE8Pj4r5) :

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

using namespace boost::spirit;
// action handlers
struct handlers {
  void create_member(const std::string& str) { }
};

// rules
static const x3::rule<struct id_obj_mem> obj_mem = "obj_mem";

#define EVENT(e) ([](auto& ctx) { x3::get<handlers>(ctx).e(x3::_attr(ctx)); })

static const auto obj_mem_def = ((
    ((+x3::alnum) | ('"' >> (+x3::alnum) >> '"'))
     >> ':' >> x3::lit("123"))[EVENT(create_member)] % ',');
BOOST_SPIRIT_DEFINE(obj_mem)

// execution
int main()
{
  handlers r;
  std::string str = "foo: 123";
  auto first = str.begin();
  auto last = str.end();
  bool res = phrase_parse(
      first,
      last,
      boost::spirit::x3::with<handlers>(r)[obj_mem_def],
      boost::spirit::x3::ascii::space);
}
Jean-Michaël Celerier
  • 7,412
  • 3
  • 54
  • 75
  • hmm, actually I wonder if this isn't a bug as here: https://www.boost.org/doc/libs/master/libs/spirit/doc/x3/html/spirit_x3/quick_reference/compound_attribute_rules.html compound operation for a:A | b:A is supposed to yield A. boost::variant does not even seem to support retrieving by index which makes things kinda useless. – Jean-Michaël Celerier Oct 11 '22 at 16:30
  • Can you post a [reprex] showing where you get a `variant`? – interjay Oct 11 '22 at 16:42

1 Answers1

2

I too consider this a kind of defect. X3 is definitely less "friendly" in terms of the synthesized attribute types. I guess it's just a tacit side-effect of being more core-language oriented, where attribute assignment is effectively done via default "visitor" actions.

Although I understand the value of keeping the magic to a minimum, and staying close to "pure C++", I vastly prefer the Qi way of synthesizing attributes here. I believe it has proven a hard problem to fix, as this problem has been coming/going in some iterations of X3.

I've long decided to basically fix it myself with variations of this idiom:

template <typename T> struct as_type {
    auto operator()(auto p) const { return x3::rule<struct Tag, T>{} = p; }
};
static constexpr as_type<std::string> as_string{};

Now I'd write that as:

auto quoted  = '"' >> +x3::alnum >> '"';
auto name    = as_string(+x3::alnum | quoted);
auto prop    = (name >> ':' >> "123")[EVENT(create_member)] % ',';

That will compile no problem:

Live On Coliru

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

namespace x3 = boost::spirit::x3;

struct handlers {
    void create_member(std::string const& str) {
        std::cerr << __FUNCTION__ << " " << std::quoted(str) << "\n";
    }
};

namespace Parser {
    #define EVENT(e) ([](auto& ctx) { get<handlers>(ctx).e(_attr(ctx)); })

    template <typename T> struct as_type {
        auto operator()(auto p) const { return x3::rule<struct Tag, T>{} = p; }
    };
    static constexpr as_type<std::string> as_string{};

    auto quoted  = '"' >> +x3::alnum >> '"';
    auto name    = as_string(+x3::alnum | quoted);
    auto prop    = (name >> ':' >> "123")[EVENT(create_member)] % ',';

    auto grammar = x3::skip(x3::space)[prop];
} // namespace Parser

int main() {
    handlers          r;
    std::string const str = "foo: 123";

    auto first = str.begin(), last = str.end();
    bool res = parse(first, last, x3::with<handlers>(r)[Parser::grammar]);

    return res ? 1 : 0;
}

Prints

create_member "foo"

Interesting Links

etc.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • what would be the process to get this fixed at the source ? is x3 currently maintained? – Jean-Michaël Celerier Oct 12 '22 at 04:23
  • [Absolutely](https://github.com/boostorg/spirit). I don't have high hopes though, because I think it's been patched and recurred before. It's a little bit like the "single-element-sequence" edge-case in Qi, it just resists fixing? I don't personally feel like spending time to fix it either, as I'm pretty fine with the workaround(s). – sehe Oct 12 '22 at 10:02
  • (Well, more importantly, I am intimidated by the attribute propagation machinery and how it ties into rule invocation; I don't have a clue how it conceptually should work, so don't know in which of several directions to try and fix it) – sehe Oct 12 '22 at 10:04