I'm writing a simple parser for my calculator and i want to have a variant operator to be passed as the argument to construct an expression.
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/support/attributes_fwd.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace client {
namespace ast {
namespace x3 = boost::spirit::x3;
struct PlusOp {};
struct MinusOp {};
struct BinaryOp : x3::variant<PlusOp, MinusOp> {
using base_type::base_type;
using base_type::operator=;
};
} // namespace ast
} // namespace client
BOOST_FUSION_ADAPT_STRUCT(client::ast::BinaryOp)
namespace client {
namespace parser {
namespace x3 = boost::spirit::x3;
using x3::ascii::char_;
x3::rule<class BinOp, ast::BinaryOp> const binaryOp = "BinaryOp";
x3::rule<class PlusOp, ast::PlusOp> const plusOp = "PlusOp";
x3::rule<class MinusOp, ast::MinusOp> const minusOp = "MinusOp";
auto const plusOp_def = &char_('+');
auto const minusOp_def = &char_('-');
auto const binaryOp_def = plusOp | minusOp;
BOOST_SPIRIT_DEFINE(plusOp, binaryOp, minusOp);
} // namespace parser
} // namespace client
int main(int argc, char *argv[]) {
using boost::spirit::x3::phrase_parse;
using boost::spirit::x3::ascii::space;
std::string plus = "+";
client::ast::BinaryOp op;
phrase_parse(plus.begin(), plus.end(), client::parser::binaryOp, space, op);
return 0;
}
In file included from /usr/include/boost/spirit/home/x3/auxiliary/any_parser.hpp:17,
from /usr/include/boost/spirit/home/x3/auxiliary.hpp:11,
from /usr/include/boost/spirit/home/x3.hpp:62,
from spirit.cc:3:
/usr/include/boost/spirit/home/x3/support/traits/move_to.hpp: In instantiation of ‘void boost::spirit::x3::traits::move_to(Source&&, Dest&) [with Source = client::ast::PlusOp; Dest = client::ast::BinaryOp]’:
/usr/include/boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp:30:28: required from ‘static void boost::spirit::x3::default_transform_attribute<Exposed, Transformed>::post(Exposed&, Transformed&&) [with Exposed = client::ast::BinaryOp; Transformed = client::ast::PlusOp]’
/usr/include/boost/spirit/home/x3/nonterminal/rule.hpp:156:32: required from ‘bool boost::spirit::x3::rule<ID, Attribute, force_attribute>::parse(Iterator&, const Iterator&, const Context&, boost::spirit::x3::unused_type, Attribute_&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type>; Attribute_ = client::ast::BinaryOp; ID = client::parser::PlusOp; Attribute = client::ast::PlusOp; bool force_attribute_ = false]’
/usr/include/boost/spirit/home/x3/nonterminal/detail/rule.hpp:209:31: required from ‘static bool boost::spirit::x3::detail::rule_parser<Attribute, ID, skip_definition_injection>::parse_rhs_main(const RHS&, Iterator&, const Iterator&, const Context&, RContext&, ActualAttribute&, mpl_::false_) [with RHS = boost::spirit::x3::rule<client::parser::PlusOp, client::ast::PlusOp>; Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type>; RContext = client::ast::BinaryOp; ActualAttribute = client::ast::BinaryOp; Attribute = client::ast::BinaryOp; ID = client::parser::BinOp; bool skip_definition_injection = true; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/spirit/home/x3/nonterminal/detail/rule.hpp:265:34: required from ‘static bool boost::spirit::x3::detail::rule_parser<Attribute, ID, skip_definition_injection>::parse_rhs_main(const RHS&, Iterator&, const Iterator&, const Context&, RContext&, ActualAttribute&) [with RHS = boost::spirit::x3::rule<client::parser::PlusOp, client::ast::PlusOp>; Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type>; RContext = client::ast::BinaryOp; ActualAttribute = client::ast::BinaryOp; Attribute = client::ast::BinaryOp; ID = client::parser::BinOp; bool skip_definition_injection = true]’
/usr/include/boost/spirit/home/x3/nonterminal/detail/rule.hpp:279:34: required from ‘static bool boost::spirit::x3::detail::rule_parser<Attribute, ID, skip_definition_injection>::parse_rhs(const RHS&, Iterator&, const Iterator&, const Context&, RContext&, ActualAttribute&, mpl_::false_) [with RHS = boost::spirit::x3::rule<client::parser::PlusOp, client::ast::PlusOp>; Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type>; RContext = client::ast::BinaryOp; ActualAttribute = client::ast::BinaryOp; Attribute = client::ast::BinaryOp; ID = client::parser::BinOp; bool skip_definition_injection = true; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/spirit/home/x3/nonterminal/detail/rule.hpp:328:37: required from ‘static bool boost::spirit::x3::detail::rule_parser<Attribute, ID, skip_definition_injection>::call_rule_definition(const RHS&, const char*, Iterator&, const Iterator&, const Context&, ActualAttribute&, ExplicitAttrPropagation) [with RHS = boost::spirit::x3::rule<client::parser::PlusOp, client::ast::PlusOp>; Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type>; ActualAttribute = client::ast::BinaryOp; ExplicitAttrPropagation = mpl_::bool_<false>; Attribute = client::ast::BinaryOp; ID = client::parser::BinOp; bool skip_definition_injection = true]’
spirit.cc:38:1: required from ‘bool client::parser::parse_rule(boost::spirit::x3::detail::rule_id<BinOp>, Iterator&, const Iterator&, const Context&, boost::spirit::x3::rule<BinOp, client::ast::BinaryOp>::attribute_type&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type>; boost::spirit::x3::rule<BinOp, client::ast::BinaryOp>::attribute_type = client::ast::BinaryOp]’
/usr/include/boost/spirit/home/x3/nonterminal/rule.hpp:155:27: required from ‘bool boost::spirit::x3::rule<ID, Attribute, force_attribute>::parse(Iterator&, const Iterator&, const Context&, boost::spirit::x3::unused_type, Attribute_&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type>; Attribute_ = client::ast::BinaryOp; ID = client::parser::BinOp; Attribute = client::ast::BinaryOp; bool force_attribute_ = false]’
/usr/include/boost/spirit/home/x3/core/parse.hpp:119:36: required from ‘bool boost::spirit::x3::phrase_parse_main(Iterator&, Iterator, const Parser&, const Skipper&, Attribute&, skip_flag) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Parser = rule<client::parser::BinOp, client::ast::BinaryOp>; Skipper = char_class<boost::spirit::char_encoding::ascii, space_tag>; Attribute = client::ast::BinaryOp]’
/usr/include/boost/spirit/home/x3/core/parse.hpp:151:33: required from ‘bool boost::spirit::x3::phrase_parse(const Iterator&, Iterator, const Parser&, const Skipper&, Attribute&, skip_flag) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Parser = rule<client::parser::BinOp, client::ast::BinaryOp>; Skipper = char_class<boost::spirit::char_encoding::ascii, space_tag>; Attribute = client::ast::BinaryOp]’
spirit.cc:48:15: required from here
/usr/include/boost/spirit/home/x3/support/traits/move_to.hpp:196:71: error: ambiguous template instantiation for ‘struct boost::spirit::x3::traits::attribute_category<client::ast::BinaryOp, void>’
196 | detail::move_to(src, dest, typename attribute_category<Dest>::type());
| ^~~~~~
In file included from /usr/include/boost/spirit/home/x3/support/traits/move_to.hpp:12:
/usr/include/boost/spirit/home/x3/support/traits/attribute_category.hpp:60:12: note: candidates are: ‘template<class T> struct boost::spirit::x3::traits::attribute_category<T, typename boost::enable_if<boost::mpl::and_<boost::fusion::traits::is_sequence<Sequence>, boost::mpl::not_<boost::fusion::traits::is_associative<Sequence1> > > >::type> [with T = client::ast::BinaryOp]’
60 | struct attribute_category< T
| ^~~~~~~~~~~~~~~~~~~~~
61 | , typename enable_if<
| ~~~~~~~~~~~~~~~~~~~~~
62 | mpl::and_<
| ~~~~~~~~~~
63 | fusion::traits::is_sequence<T>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
64 | , mpl::not_<fusion::traits::is_associative<T> >
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65 | > >::type >
| ~~~~~~~~~~~
/usr/include/boost/spirit/home/x3/support/traits/attribute_category.hpp:69:12: note: ‘template<class T> struct boost::spirit::x3::traits::attribute_category<T, typename boost::enable_if<boost::spirit::x3::traits::is_variant<T> >::type> [with T = client::ast::BinaryOp]’
69 | struct attribute_category<T,
| ^~~~~~~~~~~~~~~~~~~~~
70 | typename enable_if<traits::is_variant<T>>::type>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/spirit/home/x3/support/traits/move_to.hpp:196:71: error: invalid use of incomplete type ‘struct boost::spirit::x3::traits::attribute_category<client::ast::BinaryOp, void>’
196 | detail::move_to(src, dest, typename attribute_category<Dest>::type());
| ^~~~~~
/usr/include/boost/spirit/home/x3/support/traits/attribute_category.hpp:38:12: note: declaration of ‘struct boost::spirit::x3::traits::attribute_category<client::ast::BinaryOp, void>’
38 | struct attribute_category
| ^~~~~~~~~~~~~~~~~~
Do not really know what's happening here as i've already declared the binary op as a variant and should be compiled. I've been working on it for a couple of hours and simply don't have a clue. Any help will be appreciated. Much thanks.
Variants are already synthesized by spirit. The sequence adaptation (
BOOST_FUSION_ADAPT_STRUCT) adds no value (there are, by definition, no struct members). However it does make attribute propagation ambiguous: should the variant support be used, or the sequence support?My prediction is the dropping the adaptation makes the error go away.
Indeed it does:
Live On Compiler Explorer