1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! 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::{
    ConstGeneric, 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),
}