Macro DSL "expected identifier" in valid output

I'm writing a DSL with function-like procedural macros.
Currently I'm parsing an existing struct, to which I'll add a generic parameter _State and a field _state: ::core::marker::PhantomData<_State>.
To achieve such goal I'm currently writing the following DSL code:

ts! {
    struct Drone {
        var: i32,
    }
}

The code responsible for the generation is:

fn gen_struct(&self) -> proc_macro2::TokenStream {
    let strct = self.strct.clone();
    let attrs = strct.attrs;
    let fields = strct.fields;
    let mut generics = strct.generics;
    generics.params.push(parse_quote!(_State));
    let vis = strct.vis;
    let ident = strct.ident;
    quote!(
        #(#attrs)*
        #vis struct #ident #generics {
            _state: ::core::marker::PhantomData<_State>,
            #fields
        }
    )
}

The struct expands to what seems to be valid Rust:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
use typestate_impl::*;
struct Drone<_State> {
    _state: ::core::marker::PhantomData<_State>,
}
fn main() {}

Yet, I get an error which I've been trying (without progress) to understand its cause:

error: expected identifier, found `{`
 --> impl/src/main.rs:4:18
  |
4 |       struct Drone {
  |  __________________^
5 | |         var: i32,
6 | |     }
  | |_____^ expected identifier
error: could not compile `typestate-impl`
To learn more, run the command again with --verbose.

The code in question can be found in https://github.com/rustype/typestate-rs/tree/proc_macro

I thank everyone who took time to read this!
Any help is welcome (even suggestions to make my code better)

@Yandros solved this on the Rust Language Community Server
What is happening is that the code gets expanded to:

struct Drone<_State> {
    _state: ::core::marker::PhantomData<_State>,
    { var: i32 }
}

I can simply push the field but I forgot to disambiguate between the possible named and unnamed, doing so fixes the problem:

if let syn::Fields::Named(fields) = strct.fields {
    fields.named.push(...);
}
1 Like