c++14boost-spirit-x3

Boost spirit X3: Unable to create an AST that has a optional list


I am trying to parse a optional list of things followed by a semicolon (this is a simplified example). Below is a example program:

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <iostream>
#include <optional>
#include <string>
#include <vector>

namespace x3=boost::spirit::x3;

namespace ast
{
  struct doubleOrString : x3::variant<double,std::string>{
     using base_type::base_type;
     using base_type::operator=;
  };
 
  struct pass {
     std::vector<doubleOrString> dOrs;
  };
}//ast namespace

BOOST_FUSION_ADAPT_STRUCT(ast::pass,dOrs)

x3::rule<class doubleOrString_class, ast::doubleOrString> const doubleOrString = "doubleOrString";
x3::rule<class pass_class, ast::pass> const pass = "pass";
x3::rule<class es_class, std::optional<ast::pass>> const es = "es";

auto const doubleOrString_def =x3::double_ | x3::string("AString");
auto const pass_def = doubleOrString % x3::lit(",");
auto const es_def = (pass > x3::lit(";")) | x3::lit(";");

BOOST_SPIRIT_DEFINE(doubleOrString,pass,es);

int main()
{
    using boost::spirit::x3::ascii::space;
    typedef std::string::const_iterator iterator_type;

    std::string str;
    while (getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::optional<ast::pass> esdOrs;
        iterator_type iter = str.begin();
        iterator_type const end = str.end();
        bool r = phrase_parse(iter, end, es, space, esdOrs);
        

        if (r && iter == end)
        {
            std::cout << "\nGood!\n";
        }
        else
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

However it fails to compile with the error:

usr/include/boost/spirit/home/x3/support/ast/variant.hpp:184:17: error: no match for ‘operator=’ (operand types are ‘boost::spirit::x3::variant<double, std::__cxx11::basic_string<char, std::char_traits, std::allocator<cha
r> > >::variant_type’ {aka ‘boost::variant<double, std::__cxx11::basic_string<char, std::char_traits, std::allocator > >’} and ‘std::optionalclient::ast::pass’)
26 184 | var = std::forward(rhs);

What am I doing wrong? The error is not very informative. It seems to work fine if I just do a optional of things.

I am using the following command (the file name is r1.cpp):

g++ --std=c++17 r1.cpp -o r1 

Solution

  • With the following MRE(Minimal Reproducible Example):

    #include <vector>
    
    #include <boost/fusion/adapted/struct/adapt_struct.hpp>
    #include <boost/spirit/home/x3.hpp>
    #include <boost/spirit/home/x3/support/ast/variant.hpp>
    
    namespace x3=boost::spirit::x3;
    
    namespace ast
    {
      struct doubleOrString : x3::variant<double,std::string>{
         using base_type::base_type;
         using base_type::operator=;
      };
     
      struct pass {
         std::vector<doubleOrString> dOrs;
      };
    }//ast namespace
    
    BOOST_FUSION_ADAPT_STRUCT(ast::pass,dOrs)
    
    x3::rule<class doubleOrString_class, ast::doubleOrString> const doubleOrString = "doubleOrString";
    x3::rule<class pass_class, ast::pass> const pass = "pass";
    x3::rule<class es_class, std::optional<ast::pass>> const es = "es";
    
    auto const doubleOrString_def =x3::double_ | x3::string("AString");
    auto const pass_def = doubleOrString % x3::lit(",");
    auto const es_def = (pass > x3::lit(";")) | x3::lit(";");
    
    BOOST_SPIRIT_DEFINE(doubleOrString,pass,es);
    

    I get no compiler errors. Please provide an MRE showing the error.