tzlaine / parser

A C++ parser combinator library.
Boost Software License 1.0
70 stars 12 forks source link

Nested aggregate structures do not work #50

Closed akrzemi1 closed 6 months ago

akrzemi1 commented 6 months ago

Sorry, one more. The following case where we have an indirectly nested aggregate doesn't compile:

#include <boost/parser/parser.hpp>
#include <vector>

struct X {
  char a;
  int b;
};

struct Y {
  std::vector<X> x;
  int c;
};

int main()
{
  namespace bp = boost::parser;
  auto parse_x = bp::char_ >> bp::int_;
  auto parse_y = +parse_x >> bp::int_;

  Y y;
  auto b = bp::parse("d 3 4", parse_y, bp::ws, y);
}

The Boost.Spirit analogue compiles fine:

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>

struct X {
  char a;
  int b;
};

struct Y {
  std::vector<X> x;
  int c;
};

BOOST_FUSION_ADAPT_STRUCT(X, a, b);
BOOST_FUSION_ADAPT_STRUCT(Y, x, c);

int main()
{
  namespace bp = boost::spirit::qi;
  auto parse_x = bp::char_ >> bp::int_;
  auto parse_y = +parse_x >> bp::int_;

  Y y;
  std::string input = "d 3 4";
  auto begin = input.begin();
  bool b = bp::phrase_parse(begin, input.end(), parse_y, bp::ascii::space, y);
}
tzlaine commented 6 months ago

Don't be sorry! I appreciate the early review. I'll investigate this this weekend.

tzlaine commented 6 months ago

Even worse, this also does not work:

#include <boost/parser/parser.hpp>
#include <vector>

struct X {
  char a;
  int b;
};

struct SimplerY {
  X x;
  int c;
};

int main()
{
  namespace bp = boost::parser;
  auto parse_x = bp::char_ >> bp::int_;
  auto parse_y = parse_x >> bp::int_;

  SimplerY y;
  auto b = bp::parse("d 3 4", parse_y, bp::ws, y);
}

I have some work to do it seems.

tzlaine commented 6 months ago

Ok, after thinking about this a bit, there's no bug with my "simplified" case above. When you write parse_x >> bp::int_ as the definition of parse_y, the sequence-parser parse_x combines with bp::int_, just as if you wrote it all on the same line. IOW, parse_y is equivalent to bp::char_ >> bp::int_ >> bp::int_. When you then try to parse that into an object of type Y, it has to map the three elements the parse expects onto the two data members of `Y.

akrzemi1 commented 6 months ago

Correct. Boost.Spirit also rejects your simplified example.