Re: How to adapt an AST involving forward declared meta data
Michael Powell <[email protected]> Thu, 1 Nov 2018 10:05:00 -0400
| Newsgroups | gmane.comp.parsers.spirit.general |
|---|---|
| Message-ID | <CAMEoF_GVsYNoCZEKzxwx-5KPXONp7CF4QRZev=tqJ0N8JUyfrA@mail.gmail.com> |
On Wed, Oct 31, 2018 at 10:15 PM Michael Powell <[email protected]> wrote: > > Hello, > > Like the subject says, I've got some structs in my AST that have to be > forward declared. Okay, I've worked through the basic AST concepts I think I need for this problem. However, the VS2017 C2079 error is not going away, not without modifying the approach: One possible way is to "introduce" pointers into the AST. Question along these lines, how good is Spirit Qi at working with AST, pointers, etc? Smart pointers preferred, I think, if possible. struct bool_t { std::string val; }; struct str_t { std::string quoted_text; }; struct full_id_t { std::string full_id; }; struct int_t { std::string val; }; struct float_t { std::string val; }; // TODO: TBD: we may need/want to dissect this one still further... i.e. to ident, message/enum-name, etc. struct element_type_t { std::string name; }; // TODO: TBD: let's not get too fancy with the inheritance, ... // TODO: TBD: however, scanning the other types, we could potentially do more of it, strategically, here and there struct msg_type_t : element_type_t {}; struct enum_type_t : element_type_t {}; struct package_t { std::string full_id; }; struct const_t { std::variant<full_id_t, int_t, float_t, str_t, bool_t> val; }; struct syntax_t { std::string val; }; struct import_modifier_t { std::string val; }; struct import_t { std::optional<import_modifier_t> mod; std::string target_name; }; struct option_t { std::string name; const_t val; }; struct label_t { std::string val; }; struct type_t { std::variant<std::string, msg_type_t, enum_type_t> val; }; // TODO: TBD: could potentially get more meta-dissected based on the specification: struct field_opt_t { std::string name; const_t val; }; struct field_t { label_t label; type_t type; std::string name; int number; std::vector<field_opt_t> opts; }; // TODO: TBD: msg_body_t must be forward declared ... struct msg_body_t; struct group_t { label_t label; std::string name; int number; msg_body_t body; }; struct oneof_field_t { type_t type; std::string name; int number; std::optional<std::vector<field_opt_t>> opts; }; struct oneof_t { std::string name; std::vector<oneof_field_t> choices; }; struct key_type_t { std::string val; }; struct map_field_t { key_type_t key_type; type_t type; std::string name; int number; std::optional<std::vector<field_opt_t>> opts; }; struct range_t { int min; std::optional<std::variant<int, std::string>> max; }; struct extensions_t { std::vector<range_t> ranges; }; struct reserved_t { std::variant<std::vector<range_t>, std::vector<std::string>> val; }; struct enum_val_opt_t { std::string name; const_t val; }; struct enum_field_t { std::string name; int ordinal; std::optional<std::vector<enum_val_opt_t>> opt; }; struct enum_body_t { std::vector<std::variant<option_t, enum_field_t>> items; }; struct enum_t { std::string name; enum_body_t body; }; struct msg_t { std::string name; // TODO: TBD: msg_body_t must be forward declared ... msg_body_t body; }; struct msg_body_t { // TODO: TBD: which references msg_t and group_t ... std::vector<std::variant<field_t, enum_t, msg_t, extensions_t, group_t, option_t, oneof_t, map_field_t, reserved_t>> content; }; struct extend_t { std::string msg_type; std::vector<std::variant<field_t, group_t>> content; }; struct top_level_def_t { std::variant<msg_t, enum_t, extend_t> content; }; struct proto_t { syntax_t syntax; std::vector<std::variant<import_t, package_t, option_t, top_level_def_t>> content; }; And the Fusion adapted structs: BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::msg_type_t, name) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::enum_type_t, name) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::bool_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::str_t, quoted_text) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::full_id_t, full_id) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::int_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::float_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::package_t, full_id) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::const_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::syntax_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::import_modifier_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::import_t, mod, target_name) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::label_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::type_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::field_opt_t, name, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::field_t, label, type, name, number, opts) // TODO: TBD: trying to resolve the C2079 forward declaration issue... BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::group_t, label, name, number, body) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::oneof_field_t, type, name, number, opts) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::oneof_t, name, choices) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::key_type_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::map_field_t, key_type, type, name, number, opts) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::range_t, min, max) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::extensions_t, ranges) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::reserved_t, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::enum_val_opt_t, name, val) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::enum_field_t, name, ordinal, opt) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::enum_body_t, items) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::enum_t, name, body) // TODO: TBD: ditto group_t, solving the C2079 forward declaration issue... BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::msg_t, name, body) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::msg_body_t, content) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::extend_t, msg_type, content) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::top_level_def_t, content) BOOST_FUSION_ADAPT_STRUCT(NS_PROTO_AST_H::proto_t, syntax, content) > // Must forward declare for Group to be happy as a struct. > struct msg_body_t; > > struct group_t { > label_t label; > std::string name; > int number; > msg_body_t body; > }; > > struct msg_body_t { > // TODO: TBD: ... > }; > > Specifically, Group can contain a Message Body. > > group = label "group" groupName "=" fieldNumber messageBody > > However, Message Body can also reference a Group. > > messageBody = "{" { field | enum | message | extend | extensions | group > | option | oneof | mapField | reserved | emptyStatement } "}" > > In terms of the C++ AST itself, I do not know of a way to model this > and at least <messageBody/> not be forward declared. > > However, Spirit struct adaptation is balking at this. Literally, > > 1>g:\source\kingdom > software\kingdom.ortools\standard\src\kingdom.ortools.sat.params.generator\proto_ast.h(100): > error C2079: 'kingdom::google::protobuf::proto2::ast::group_t::body' > uses undefined struct > 'kingdom::google::protobuf::proto2::ast::msg_body_t' > > I have not completely worked through the AST, but I am getting close. > So I am cautiously optimistic that once I cross the <messageBody/> > bridge, this error will go away. > > However, in the meantime, I thought I'd present the question, whether > forward declared AST posed any difficulties to Spirit Qi struct > adaptation to anyone's knowledge. > > Best regards, > > Michael Powell > > https://developers.google.com/protocol-buffers/docs/reference/proto2-spec