Re: How to adapt an AST involving forward declared meta data

Michael Powell <[email protected]> Thu, 1 Nov 2018 17:27:15 -0400
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <CAMEoF_HOosZ1VsXc=zDv_uoKE1r_Zx89HYcLA6qGeEDwfpt-dA@mail.gmail.com>
On Thu, Nov 1, 2018 at 10:05 AM Michael Powell <[email protected]> wrote:
>
> 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.

I'm wondering if this possibly has something to do with recursive
descent, boost::recursive_wrappers, etc? Perhaps I should even be type
defining some of these variants, etc?

Another question popped out of my background reading, whether I should
be aiming for X3; but that's a whole other can of worms I think. I'm
trying to keep the AST as minimalist as I possibly can.

I can try to pull together another web compiler example around  this,
but the scope has increased beyond the "simple" version parser,
obviously.

Thoughts?

> 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