//! Module for parsing code. The main enum is [`Parse`].
use crate::prelude::*;
mod attributes;
mod body;
mod data_type;
mod generics;
mod utils;
mod visibility;
pub use self::attributes::{Attribute, AttributeAccess, AttributeLocation, FromAttribute};
pub use self::body::{EnumBody, EnumVariant, Fields, IdentOrIndex, StructBody, UnnamedField};
pub(crate) use self::data_type::DataType;
pub use self::generics::{Generic, GenericConstraints, Generics, Lifetime, SimpleGeneric};
pub use self::visibility::Visibility;
use crate::generate::Generator;
/// Parser for Enum and Struct derives.
///
/// You can generate this enum by calling
///
/// ```ignore
/// use virtue::prelude::*;
///
/// #[proc_macro_derive(YourDerive)]
/// pub fn derive_your_derive(input: TokenStream) -> TokenStream {
/// let parse = Parse::new(input).unwrap();
/// // rest
/// # unimplemented!()
/// }
/// ```
#[non_exhaustive]
pub enum Parse {
/// The given input is a struct
Struct {
/// The attributes of the struct
attributes: Vec<Attribute>,
/// The visibility of the struct
visibility: Visibility,
/// The name of the struct
name: Ident,
/// The generics of the struct, e.g. `struct Foo<F> { ... }` will be `F`
generics: Option<Generics>,
/// The generic constraits of the struct, e.g. `struct Foo<F> { ... } where F: Display` will be `F: Display`
generic_constraints: Option<GenericConstraints>,
/// The body of the struct
body: StructBody,
},
/// The given input is an enum
Enum {
/// The attributes of the enum
attributes: Vec<Attribute>,
/// The visibility of the enum
visibility: Visibility,
/// The name of the enum
name: Ident,
/// The generics of the enum, e.g. `enum Foo<F> { ... }` will be `F`
generics: Option<Generics>,
/// The generic constraits of the enum, e.g. `enum Foo<F> { ... } where F: Display` will be `F: Display`
generic_constraints: Option<GenericConstraints>,
/// The body of the enum
body: EnumBody,
},
}
impl Parse {
/// Parse the given [`TokenStream`] and return the result.
pub fn new(input: TokenStream) -> Result<Self> {
let source = &mut input.into_iter().peekable();
let attributes = Attribute::try_take(AttributeLocation::Container, source)?;
let visibility = Visibility::try_take(source)?;
let (datatype, name) = DataType::take(source)?;
let generics = Generics::try_take(source)?;
let generic_constraints = GenericConstraints::try_take(source)?;
match datatype {
DataType::Struct => {
let body = StructBody::take(source)?;
Ok(Self::Struct {
attributes,
visibility,
name,
generics,
generic_constraints,
body,
})
}
DataType::Enum => {
let body = EnumBody::take(source)?;
Ok(Self::Enum {
attributes,
visibility,
name,
generics,
generic_constraints,
body,
})
}
}
}
/// Split this struct or enum into a [`Generator`], list of [`Attribute`] and [`Body`].
pub fn into_generator(self) -> (Generator, Vec<Attribute>, Body) {
match self {
Parse::Struct {
name,
generics,
generic_constraints,
body,
attributes,
..
} => (
Generator::new(name, generics, generic_constraints),
attributes,
Body::Struct(body),
),
Parse::Enum {
name,
generics,
generic_constraints,
body,
attributes,
..
} => (
Generator::new(name, generics, generic_constraints),
attributes,
Body::Enum(body),
),
}
}
}
/// The body of the enum or struct
#[allow(missing_docs)]
pub enum Body {
Struct(StructBody),
Enum(EnumBody),
}