blob: 5c1bb17c6e10d0e25e9b918153849450731085f8 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnayf38cdf62016-09-23 19:07:09 -07009use super::*;
Nika Layzell5680dcc2018-01-16 15:14:27 -050010use punctuated::Punctuated;
David Tolnayf38cdf62016-09-23 19:07:09 -070011
Alex Crichton62a0a592017-05-22 13:58:53 -070012ast_struct! {
David Tolnaye3d41b72017-12-31 15:24:00 -050013 /// Data structure sent to a `proc_macro_derive` macro.
David Tolnay461d98e2018-01-07 11:07:19 -080014 ///
15 /// *This type is available if Syn is built with the `"derive"` feature.*
Alex Crichton62a0a592017-05-22 13:58:53 -070016 pub struct DeriveInput {
David Tolnay4a3f59a2017-12-28 21:21:12 -050017 /// Attributes tagged on the whole struct or enum.
18 pub attrs: Vec<Attribute>,
Clar Charrd22b5702017-03-10 15:24:56 -050019
Alex Crichton62a0a592017-05-22 13:58:53 -070020 /// Visibility of the struct or enum.
21 pub vis: Visibility,
Clar Charrd22b5702017-03-10 15:24:56 -050022
David Tolnay4a3f59a2017-12-28 21:21:12 -050023 /// Name of the struct or enum.
24 pub ident: Ident,
Clar Charrd22b5702017-03-10 15:24:56 -050025
Alex Crichton62a0a592017-05-22 13:58:53 -070026 /// Generics required to complete the definition.
27 pub generics: Generics,
Clar Charrd22b5702017-03-10 15:24:56 -050028
Alex Crichton62a0a592017-05-22 13:58:53 -070029 /// Data within the struct or enum.
David Tolnaye3d41b72017-12-31 15:24:00 -050030 pub data: Data,
Alex Crichton62a0a592017-05-22 13:58:53 -070031 }
David Tolnayf38cdf62016-09-23 19:07:09 -070032}
33
Alex Crichtonccbb45d2017-05-23 10:58:24 -070034ast_enum_of_structs! {
David Tolnaye3d41b72017-12-31 15:24:00 -050035 /// The storage of a struct, enum or union data structure.
David Tolnay614a0142018-01-07 10:25:43 -080036 ///
David Tolnay461d98e2018-01-07 11:07:19 -080037 /// *This type is available if Syn is built with the `"derive"` feature.*
38 ///
David Tolnay614a0142018-01-07 10:25:43 -080039 /// # Syntax tree enum
40 ///
41 /// This type is a [syntax tree enum].
42 ///
43 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnaye3d41b72017-12-31 15:24:00 -050044 pub enum Data {
David Tolnayd2aa8832018-01-07 01:05:09 -080045 /// A struct input to a `proc_macro_derive` macro.
David Tolnay461d98e2018-01-07 11:07:19 -080046 ///
47 /// *This type is available if Syn is built with the `"derive"`
48 /// feature.*
David Tolnaye3d41b72017-12-31 15:24:00 -050049 pub Struct(DataStruct {
50 pub struct_token: Token![struct],
51 pub fields: Fields,
52 pub semi_token: Option<Token![;]>,
53 }),
54
David Tolnayd2aa8832018-01-07 01:05:09 -080055 /// An enum input to a `proc_macro_derive` macro.
David Tolnay461d98e2018-01-07 11:07:19 -080056 ///
57 /// *This type is available if Syn is built with the `"derive"`
58 /// feature.*
David Tolnaye3d41b72017-12-31 15:24:00 -050059 pub Enum(DataEnum {
David Tolnayf8db7ba2017-11-11 22:52:16 -080060 pub enum_token: Token![enum],
David Tolnay32954ef2017-12-26 22:43:16 -050061 pub brace_token: token::Brace,
David Tolnayf2cfd722017-12-31 18:02:51 -050062 pub variants: Punctuated<Variant, Token![,]>,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070063 }),
Alex Crichton62a0a592017-05-22 13:58:53 -070064
David Tolnayd2aa8832018-01-07 01:05:09 -080065 /// A tagged union input to a `proc_macro_derive` macro.
David Tolnay461d98e2018-01-07 11:07:19 -080066 ///
67 /// *This type is available if Syn is built with the `"derive"`
68 /// feature.*
David Tolnaye3d41b72017-12-31 15:24:00 -050069 pub Union(DataUnion {
70 pub union_token: Token![union],
71 pub fields: FieldsNamed,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070072 }),
Alex Crichton62a0a592017-05-22 13:58:53 -070073 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -070074
75 do_not_generate_to_tokens
David Tolnayf38cdf62016-09-23 19:07:09 -070076}
77
78#[cfg(feature = "parsing")]
79pub mod parsing {
80 use super::*;
David Tolnayf38cdf62016-09-23 19:07:09 -070081
David Tolnay3ecbcaf2018-08-25 23:03:26 -040082 use parse::{Parse, ParseStream, Result};
Alex Crichton954046c2017-05-30 21:49:42 -070083
David Tolnay3ecbcaf2018-08-25 23:03:26 -040084 impl Parse for DeriveInput {
85 fn parse(input: ParseStream) -> Result<Self> {
86 let attrs = input.call(Attribute::parse_outer)?;
87 let vis = input.parse::<Visibility>()?;
David Tolnayb022d062018-07-21 18:59:36 -070088
David Tolnay3ecbcaf2018-08-25 23:03:26 -040089 let lookahead = input.lookahead1();
90 if lookahead.peek(Token![struct]) {
91 let struct_token = input.parse::<Token![struct]>()?;
92 let ident = input.parse::<Ident>()?;
David Tolnay1b8e2852018-08-26 08:25:18 -040093 let generics = input.parse::<Generics>()?;
David Tolnay3ecbcaf2018-08-25 23:03:26 -040094 let (where_clause, fields, semi) = data_struct(input)?;
95 Ok(DeriveInput {
Michael Layzell92639a52017-06-01 00:07:44 -040096 attrs: attrs,
David Tolnay3ecbcaf2018-08-25 23:03:26 -040097 vis: vis,
98 ident: ident,
Michael Layzell92639a52017-06-01 00:07:44 -040099 generics: Generics {
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400100 where_clause: where_clause,
David Tolnayd142fc52018-07-21 15:09:53 -0700101 ..generics
Michael Layzell92639a52017-06-01 00:07:44 -0400102 },
David Tolnaye3d41b72017-12-31 15:24:00 -0500103 data: Data::Struct(DataStruct {
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400104 struct_token: struct_token,
David Tolnaye3d41b72017-12-31 15:24:00 -0500105 fields: fields,
Michael Layzell92639a52017-06-01 00:07:44 -0400106 semi_token: semi,
107 }),
108 })
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400109 } else if lookahead.peek(Token![enum]) {
110 let enum_token = input.parse::<Token![enum]>()?;
111 let ident = input.parse::<Ident>()?;
David Tolnay1b8e2852018-08-26 08:25:18 -0400112 let generics = input.parse::<Generics>()?;
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400113 let (where_clause, brace, variants) = data_enum(input)?;
114 Ok(DeriveInput {
Michael Layzell92639a52017-06-01 00:07:44 -0400115 attrs: attrs,
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400116 vis: vis,
117 ident: ident,
Michael Layzell92639a52017-06-01 00:07:44 -0400118 generics: Generics {
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400119 where_clause: where_clause,
David Tolnayd142fc52018-07-21 15:09:53 -0700120 ..generics
Michael Layzell92639a52017-06-01 00:07:44 -0400121 },
David Tolnaye3d41b72017-12-31 15:24:00 -0500122 data: Data::Enum(DataEnum {
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400123 enum_token: enum_token,
Michael Layzell92639a52017-06-01 00:07:44 -0400124 brace_token: brace,
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400125 variants: variants,
Michael Layzell92639a52017-06-01 00:07:44 -0400126 }),
127 })
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400128 } else if lookahead.peek(Token![union]) {
129 let union_token = input.parse::<Token![union]>()?;
130 let ident = input.parse::<Ident>()?;
David Tolnay1b8e2852018-08-26 08:25:18 -0400131 let generics = input.parse::<Generics>()?;
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400132 let (where_clause, fields) = data_union(input)?;
133 Ok(DeriveInput {
David Tolnayb022d062018-07-21 18:59:36 -0700134 attrs: attrs,
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400135 vis: vis,
136 ident: ident,
David Tolnayb022d062018-07-21 18:59:36 -0700137 generics: Generics {
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400138 where_clause: where_clause,
David Tolnayb022d062018-07-21 18:59:36 -0700139 ..generics
140 },
141 data: Data::Union(DataUnion {
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400142 union_token: union_token,
David Tolnayb022d062018-07-21 18:59:36 -0700143 fields: fields,
144 }),
145 })
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400146 } else {
147 Err(lookahead.error())
148 }
Alex Crichton954046c2017-05-30 21:49:42 -0700149 }
150 }
151
David Tolnay6a170ce2018-08-26 22:29:24 -0700152 pub fn data_struct(
153 input: ParseStream,
154 ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> {
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400155 let mut lookahead = input.lookahead1();
156 let mut where_clause = None;
157 if lookahead.peek(Token![where]) {
David Tolnay1b8e2852018-08-26 08:25:18 -0400158 where_clause = Some(input.parse()?);
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400159 lookahead = input.lookahead1();
160 }
Alex Crichton954046c2017-05-30 21:49:42 -0700161
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400162 if where_clause.is_none() && lookahead.peek(token::Paren) {
163 let fields = input.parse()?;
David Tolnayb022d062018-07-21 18:59:36 -0700164
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400165 lookahead = input.lookahead1();
166 if lookahead.peek(Token![where]) {
David Tolnay1b8e2852018-08-26 08:25:18 -0400167 where_clause = Some(input.parse()?);
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400168 lookahead = input.lookahead1();
169 }
170
171 if lookahead.peek(Token![;]) {
172 let semi = input.parse()?;
173 Ok((where_clause, Fields::Unnamed(fields), Some(semi)))
174 } else {
175 Err(lookahead.error())
176 }
177 } else if lookahead.peek(token::Brace) {
178 let fields = input.parse()?;
179 Ok((where_clause, Fields::Named(fields), None))
180 } else if lookahead.peek(Token![;]) {
181 let semi = input.parse()?;
182 Ok((where_clause, Fields::Unit, Some(semi)))
183 } else {
184 Err(lookahead.error())
185 }
186 }
187
David Tolnay6a170ce2018-08-26 22:29:24 -0700188 pub fn data_enum(
David Tolnay4fb71232018-08-25 23:14:50 -0400189 input: ParseStream,
190 ) -> Result<(
191 Option<WhereClause>,
192 token::Brace,
193 Punctuated<Variant, Token![,]>,
194 )> {
David Tolnay1b8e2852018-08-26 08:25:18 -0400195 let where_clause = input.parse()?;
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400196
197 let content;
198 let brace = braced!(content in input);
David Tolnay60484fe2018-08-30 18:43:04 -0700199 let variants = content.parse_terminated(Variant::parse)?;
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400200
201 Ok((where_clause, brace, variants))
202 }
203
David Tolnay6a170ce2018-08-26 22:29:24 -0700204 pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
David Tolnay1b8e2852018-08-26 08:25:18 -0400205 let where_clause = input.parse()?;
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400206 let fields = input.parse()?;
David Tolnay3ecbcaf2018-08-25 23:03:26 -0400207 Ok((where_clause, fields))
208 }
David Tolnayf38cdf62016-09-23 19:07:09 -0700209}
210
David Tolnayc2dfbf42016-09-23 23:52:15 -0700211#[cfg(feature = "printing")]
David Tolnayf38cdf62016-09-23 19:07:09 -0700212mod printing {
213 use super::*;
David Tolnay64023912018-08-31 09:51:12 -0700214
Alex Crichtona74a1c82018-05-16 10:20:44 -0700215 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700216 use quote::ToTokens;
David Tolnayf38cdf62016-09-23 19:07:09 -0700217
David Tolnay64023912018-08-31 09:51:12 -0700218 use attr::FilterAttrs;
219 use print::TokensOrDefault;
220
David Tolnay0e837402016-12-22 17:25:55 -0500221 impl ToTokens for DeriveInput {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700222 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay4a51dc72016-10-01 00:40:31 -0700223 for attr in self.attrs.outer() {
David Tolnayf38cdf62016-09-23 19:07:09 -0700224 attr.to_tokens(tokens);
225 }
David Tolnay47a877c2016-10-01 16:50:55 -0700226 self.vis.to_tokens(tokens);
David Tolnaye3d41b72017-12-31 15:24:00 -0500227 match self.data {
228 Data::Struct(ref d) => d.struct_token.to_tokens(tokens),
229 Data::Enum(ref d) => d.enum_token.to_tokens(tokens),
230 Data::Union(ref d) => d.union_token.to_tokens(tokens),
David Tolnayf38cdf62016-09-23 19:07:09 -0700231 }
232 self.ident.to_tokens(tokens);
233 self.generics.to_tokens(tokens);
David Tolnaye3d41b72017-12-31 15:24:00 -0500234 match self.data {
David Tolnay61037c62018-01-05 16:21:03 -0800235 Data::Struct(ref data) => match data.fields {
236 Fields::Named(ref fields) => {
237 self.generics.where_clause.to_tokens(tokens);
238 fields.to_tokens(tokens);
David Tolnaye3d41b72017-12-31 15:24:00 -0500239 }
David Tolnay61037c62018-01-05 16:21:03 -0800240 Fields::Unnamed(ref fields) => {
241 fields.to_tokens(tokens);
242 self.generics.where_clause.to_tokens(tokens);
243 TokensOrDefault(&data.semi_token).to_tokens(tokens);
244 }
245 Fields::Unit => {
246 self.generics.where_clause.to_tokens(tokens);
247 TokensOrDefault(&data.semi_token).to_tokens(tokens);
248 }
249 },
David Tolnaye3d41b72017-12-31 15:24:00 -0500250 Data::Enum(ref data) => {
David Tolnay28c1db62016-10-27 22:48:18 -0700251 self.generics.where_clause.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700252 data.brace_token.surround(tokens, |tokens| {
253 data.variants.to_tokens(tokens);
254 });
David Tolnayf38cdf62016-09-23 19:07:09 -0700255 }
David Tolnaye3d41b72017-12-31 15:24:00 -0500256 Data::Union(ref data) => {
257 self.generics.where_clause.to_tokens(tokens);
258 data.fields.to_tokens(tokens);
David Tolnayf38cdf62016-09-23 19:07:09 -0700259 }
260 }
261 }
262 }
263}