blob: 9c772542a6eb5c8bd89c5645186aae76a769e36a [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::*;
David Tolnayf2cfd722017-12-31 18:02:51 -050010use punctuated::Punctuated;
David Tolnayf38cdf62016-09-23 19:07:09 -070011
Alex Crichton62a0a592017-05-22 13:58:53 -070012ast_struct! {
13 /// An enum variant.
David Tolnay461d98e2018-01-07 11:07:19 -080014 ///
15 /// *This type is available if Syn is built with the `"derive"` or `"full"`
16 /// feature.*
Alex Crichton62a0a592017-05-22 13:58:53 -070017 pub struct Variant {
Alex Crichton62a0a592017-05-22 13:58:53 -070018 /// Attributes tagged on the variant.
19 pub attrs: Vec<Attribute>,
Clar Charrd22b5702017-03-10 15:24:56 -050020
David Tolnay4a3f59a2017-12-28 21:21:12 -050021 /// Name of the variant.
22 pub ident: Ident,
23
David Tolnaye3d41b72017-12-31 15:24:00 -050024 /// Content stored in the variant.
25 pub fields: Fields,
Clar Charrd22b5702017-03-10 15:24:56 -050026
David Tolnay05658502018-01-07 09:56:37 -080027 /// Explicit discriminant: `Variant = 1`
David Tolnaye67902a2017-12-28 22:12:00 -050028 pub discriminant: Option<(Token![=], Expr)>,
Alex Crichton62a0a592017-05-22 13:58:53 -070029 }
David Tolnayf38cdf62016-09-23 19:07:09 -070030}
31
David Tolnaye3d41b72017-12-31 15:24:00 -050032ast_enum_of_structs! {
Alex Crichton62a0a592017-05-22 13:58:53 -070033 /// Data stored within an enum variant or struct.
David Tolnay614a0142018-01-07 10:25:43 -080034 ///
David Tolnay461d98e2018-01-07 11:07:19 -080035 /// *This type is available if Syn is built with the `"derive"` or `"full"`
36 /// feature.*
37 ///
David Tolnay614a0142018-01-07 10:25:43 -080038 /// # Syntax tree enum
39 ///
40 /// This type is a [syntax tree enum].
41 ///
42 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnaye3d41b72017-12-31 15:24:00 -050043 pub enum Fields {
44 /// Named fields of a struct or struct variant such as `Point { x: f64,
45 /// y: f64 }`.
David Tolnay461d98e2018-01-07 11:07:19 -080046 ///
47 /// *This type is available if Syn is built with the `"derive"` or
48 /// `"full"` feature.*
David Tolnaye3d41b72017-12-31 15:24:00 -050049 pub Named(FieldsNamed {
50 pub brace_token: token::Brace,
David Tolnaybdafb102018-01-01 19:39:10 -080051 pub named: Punctuated<Field, Token![,]>,
David Tolnaye3d41b72017-12-31 15:24:00 -050052 }),
Clar Charrd22b5702017-03-10 15:24:56 -050053
David Tolnaye3d41b72017-12-31 15:24:00 -050054 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
David Tolnay461d98e2018-01-07 11:07:19 -080055 ///
56 /// *This type is available if Syn is built with the `"derive"` or
57 /// `"full"` feature.*
David Tolnaye3d41b72017-12-31 15:24:00 -050058 pub Unnamed(FieldsUnnamed {
59 pub paren_token: token::Paren,
David Tolnaybdafb102018-01-01 19:39:10 -080060 pub unnamed: Punctuated<Field, Token![,]>,
David Tolnaye3d41b72017-12-31 15:24:00 -050061 }),
Clar Charrd22b5702017-03-10 15:24:56 -050062
David Tolnaye3d41b72017-12-31 15:24:00 -050063 /// Unit struct or unit variant such as `None`.
64 pub Unit,
Alex Crichton62a0a592017-05-22 13:58:53 -070065 }
David Tolnayf38cdf62016-09-23 19:07:09 -070066}
67
Nika Layzell5680dcc2018-01-16 15:14:27 -050068impl Fields {
Michael Bradshaw0b13ae62018-08-02 23:43:15 -060069 /// Get an iterator over the borrowed [`Field`] items in this object. This
70 /// iterator can be used to iterate over a named or unnamed struct or
71 /// variant's fields uniformly.
Nika Layzell5680dcc2018-01-16 15:14:27 -050072 ///
73 /// [`Field`]: struct.Field.html
David Tolnay8095c302018-03-31 19:34:17 +020074 pub fn iter(&self) -> punctuated::Iter<Field> {
Nika Layzell5680dcc2018-01-16 15:14:27 -050075 match *self {
David Tolnay96a09d92018-01-16 22:24:03 -080076 Fields::Unit => punctuated::Iter::private_empty(),
77 Fields::Named(ref f) => f.named.iter(),
78 Fields::Unnamed(ref f) => f.unnamed.iter(),
Nika Layzell5680dcc2018-01-16 15:14:27 -050079 }
80 }
Michael Bradshaw0b13ae62018-08-02 23:43:15 -060081
82 /// Get an iterator over the mutably borrowed [`Field`] items in this
83 /// object. This iterator can be used to iterate over a named or unnamed
84 /// struct or variant's fields uniformly.
85 ///
86 /// [`Field`]: struct.Field.html
87 pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
88 match *self {
89 Fields::Unit => punctuated::IterMut::private_empty(),
90 Fields::Named(ref mut f) => f.named.iter_mut(),
91 Fields::Unnamed(ref mut f) => f.unnamed.iter_mut(),
92 }
93 }
Nika Layzell5680dcc2018-01-16 15:14:27 -050094}
95
96impl<'a> IntoIterator for &'a Fields {
97 type Item = &'a Field;
David Tolnay8095c302018-03-31 19:34:17 +020098 type IntoIter = punctuated::Iter<'a, Field>;
Nika Layzell5680dcc2018-01-16 15:14:27 -050099
100 fn into_iter(self) -> Self::IntoIter {
101 self.iter()
102 }
103}
104
Michael Bradshaw0b13ae62018-08-02 23:43:15 -0600105impl<'a> IntoIterator for &'a mut Fields {
106 type Item = &'a mut Field;
107 type IntoIter = punctuated::IterMut<'a, Field>;
108
109 fn into_iter(self) -> Self::IntoIter {
110 self.iter_mut()
111 }
112}
113
Alex Crichton62a0a592017-05-22 13:58:53 -0700114ast_struct! {
115 /// A field of a struct or enum variant.
David Tolnay461d98e2018-01-07 11:07:19 -0800116 ///
117 /// *This type is available if Syn is built with the `"derive"` or `"full"`
118 /// feature.*
Alex Crichton62a0a592017-05-22 13:58:53 -0700119 pub struct Field {
David Tolnay4a3f59a2017-12-28 21:21:12 -0500120 /// Attributes tagged on the field.
121 pub attrs: Vec<Attribute>,
122
123 /// Visibility of the field.
124 pub vis: Visibility,
125
Alex Crichton62a0a592017-05-22 13:58:53 -0700126 /// Name of the field, if any.
127 ///
128 /// Fields of tuple structs have no names.
129 pub ident: Option<Ident>,
Clar Charrd22b5702017-03-10 15:24:56 -0500130
David Tolnay4a3f59a2017-12-28 21:21:12 -0500131 pub colon_token: Option<Token![:]>,
Clar Charrd22b5702017-03-10 15:24:56 -0500132
Alex Crichton62a0a592017-05-22 13:58:53 -0700133 /// Type of the field.
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800134 pub ty: Type,
Alex Crichton62a0a592017-05-22 13:58:53 -0700135 }
David Tolnayf38cdf62016-09-23 19:07:09 -0700136}
137
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700138ast_enum_of_structs! {
David Tolnay05658502018-01-07 09:56:37 -0800139 /// The visibility level of an item: inherited or `pub` or
140 /// `pub(restricted)`.
David Tolnay614a0142018-01-07 10:25:43 -0800141 ///
David Tolnay461d98e2018-01-07 11:07:19 -0800142 /// *This type is available if Syn is built with the `"derive"` or `"full"`
143 /// feature.*
144 ///
David Tolnay614a0142018-01-07 10:25:43 -0800145 /// # Syntax tree enum
146 ///
147 /// This type is a [syntax tree enum].
148 ///
149 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
Alex Crichton62a0a592017-05-22 13:58:53 -0700150 pub enum Visibility {
David Tolnay05658502018-01-07 09:56:37 -0800151 /// A public visibility level: `pub`.
David Tolnay461d98e2018-01-07 11:07:19 -0800152 ///
153 /// *This type is available if Syn is built with the `"derive"` or
154 /// `"full"` feature.*
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700155 pub Public(VisPublic {
David Tolnayf8db7ba2017-11-11 22:52:16 -0800156 pub pub_token: Token![pub],
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700157 }),
Clar Charrd22b5702017-03-10 15:24:56 -0500158
David Tolnayc8ecb362018-04-01 11:01:09 +0200159 /// A crate-level visibility: `crate`.
David Tolnay461d98e2018-01-07 11:07:19 -0800160 ///
161 /// *This type is available if Syn is built with the `"derive"` or
162 /// `"full"` feature.*
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700163 pub Crate(VisCrate {
David Tolnayf8db7ba2017-11-11 22:52:16 -0800164 pub crate_token: Token![crate],
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700165 }),
Clar Charrd22b5702017-03-10 15:24:56 -0500166
David Tolnay05658502018-01-07 09:56:37 -0800167 /// A visibility level restricted to some path: `pub(self)` or
David Tolnayc8ecb362018-04-01 11:01:09 +0200168 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
David Tolnay461d98e2018-01-07 11:07:19 -0800169 ///
170 /// *This type is available if Syn is built with the `"derive"` or
171 /// `"full"` feature.*
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700172 pub Restricted(VisRestricted {
David Tolnayf8db7ba2017-11-11 22:52:16 -0800173 pub pub_token: Token![pub],
David Tolnay32954ef2017-12-26 22:43:16 -0500174 pub paren_token: token::Paren,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800175 pub in_token: Option<Token![in]>,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700176 pub path: Box<Path>,
177 }),
Clar Charrd22b5702017-03-10 15:24:56 -0500178
David Tolnay05658502018-01-07 09:56:37 -0800179 /// An inherited visibility, which usually means private.
David Tolnayfcfb9002017-12-28 22:04:29 -0500180 pub Inherited,
Alex Crichton62a0a592017-05-22 13:58:53 -0700181 }
David Tolnayf38cdf62016-09-23 19:07:09 -0700182}
183
David Tolnayf38cdf62016-09-23 19:07:09 -0700184#[cfg(feature = "parsing")]
185pub mod parsing {
186 use super::*;
David Tolnayf38cdf62016-09-23 19:07:09 -0700187
David Tolnay898bb742018-08-25 16:40:11 -0400188 use parse::{Parse, ParseStream, Result};
189 use synom::ext::IdentExt;
Michael Layzell92639a52017-06-01 00:07:44 -0400190 use synom::Synom;
David Tolnayf38cdf62016-09-23 19:07:09 -0700191
David Tolnay3a515a02018-08-25 21:08:27 -0400192 impl Parse for Variant {
193 fn parse(input: ParseStream) -> Result<Self> {
194 Ok(Variant {
David Tolnayf8106f82018-08-25 21:17:45 -0400195 attrs: input.call(Attribute::parse_outer)?,
David Tolnay3a515a02018-08-25 21:08:27 -0400196 ident: input.parse()?,
197 fields: {
198 if input.peek(token::Brace) {
199 Fields::Named(input.parse_synom(FieldsNamed::parse)?)
200 } else if input.peek(token::Paren) {
201 Fields::Unnamed(input.parse_synom(FieldsUnnamed::parse)?)
202 } else {
203 Fields::Unit
204 }
205 },
206 discriminant: {
207 if input.peek(Token![=]) {
208 Some((input.parse()?, input.parse_synom(Expr::parse)?))
209 } else {
210 None
211 }
212 },
David Tolnaye3d41b72017-12-31 15:24:00 -0500213 })
David Tolnaye3d41b72017-12-31 15:24:00 -0500214 }
215 }
216
217 impl Synom for FieldsNamed {
218 named!(parse -> Self, map!(
David Tolnayf2cfd722017-12-31 18:02:51 -0500219 braces!(call!(Punctuated::parse_terminated_with, Field::parse_named)),
David Tolnaye3d41b72017-12-31 15:24:00 -0500220 |(brace, fields)| FieldsNamed {
221 brace_token: brace,
David Tolnaybdafb102018-01-01 19:39:10 -0800222 named: fields,
David Tolnaye3d41b72017-12-31 15:24:00 -0500223 }
224 ));
David Tolnay79777332018-01-07 10:04:42 -0800225
226 fn description() -> Option<&'static str> {
227 Some("named fields in a struct or struct variant")
228 }
David Tolnaye3d41b72017-12-31 15:24:00 -0500229 }
230
231 impl Synom for FieldsUnnamed {
232 named!(parse -> Self, map!(
David Tolnayf2cfd722017-12-31 18:02:51 -0500233 parens!(call!(Punctuated::parse_terminated_with, Field::parse_unnamed)),
David Tolnaye3d41b72017-12-31 15:24:00 -0500234 |(paren, fields)| FieldsUnnamed {
235 paren_token: paren,
David Tolnaybdafb102018-01-01 19:39:10 -0800236 unnamed: fields,
David Tolnaye3d41b72017-12-31 15:24:00 -0500237 }
238 ));
David Tolnay79777332018-01-07 10:04:42 -0800239
240 fn description() -> Option<&'static str> {
241 Some("unnamed fields in a tuple struct or tuple variant")
242 }
David Tolnaye3d41b72017-12-31 15:24:00 -0500243 }
244
Alex Crichton954046c2017-05-30 21:49:42 -0700245 impl Field {
David Tolnaye3d41b72017-12-31 15:24:00 -0500246 named!(pub parse_named -> Self, do_parse!(
David Tolnayf8106f82018-08-25 21:17:45 -0400247 attrs: many0!(Attribute::old_parse_outer) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400248 vis: syn!(Visibility) >>
249 id: syn!(Ident) >>
David Tolnayf8db7ba2017-11-11 22:52:16 -0800250 colon: punct!(:) >>
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800251 ty: syn!(Type) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400252 (Field {
253 ident: Some(id),
254 vis: vis,
255 attrs: attrs,
256 ty: ty,
257 colon_token: Some(colon),
258 })
259 ));
David Tolnayf38cdf62016-09-23 19:07:09 -0700260
David Tolnaye3d41b72017-12-31 15:24:00 -0500261 named!(pub parse_unnamed -> Self, do_parse!(
David Tolnayf8106f82018-08-25 21:17:45 -0400262 attrs: many0!(Attribute::old_parse_outer) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400263 vis: syn!(Visibility) >>
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800264 ty: syn!(Type) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400265 (Field {
266 ident: None,
267 colon_token: None,
268 vis: vis,
269 attrs: attrs,
270 ty: ty,
271 })
272 ));
Michael Layzell416724e2017-05-24 21:12:34 -0400273 }
274
David Tolnay898bb742018-08-25 16:40:11 -0400275 impl Parse for Visibility {
276 fn parse(input: ParseStream) -> Result<Self> {
277 if input.peek(Token![pub]) {
278 Self::parse_pub(input)
279 } else if input.peek(Token![crate]) {
280 Self::parse_crate(input)
281 } else {
282 Ok(Visibility::Inherited)
283 }
284 }
285 }
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800286
David Tolnay898bb742018-08-25 16:40:11 -0400287 impl Visibility {
288 fn parse_pub(input: ParseStream) -> Result<Self> {
289 let pub_token = input.parse::<Token![pub]>()?;
290
291 if input.peek(token::Paren) {
292 let ahead = input.fork();
293 let mut content;
294 parenthesized!(content in ahead);
295
296 if content.peek(Token![crate])
297 || content.peek(Token![self])
298 || content.peek(Token![super])
299 {
300 return Ok(Visibility::Restricted(VisRestricted {
301 pub_token: pub_token,
302 paren_token: parenthesized!(content in input),
303 in_token: None,
304 path: Box::new(Path::from(content.parse_synom(Ident::parse_any)?)),
305 }));
306 } else if content.peek(Token![in]) {
307 return Ok(Visibility::Restricted(VisRestricted {
308 pub_token: pub_token,
309 paren_token: parenthesized!(content in input),
310 in_token: Some(content.parse()?),
311 path: Box::new(content.parse_synom(Path::parse_mod_style)?),
312 }));
313 }
314 }
315
316 Ok(Visibility::Public(VisPublic {
317 pub_token: pub_token,
318 }))
319 }
320
321 fn parse_crate(input: ParseStream) -> Result<Self> {
322 let followed_by_colons = {
323 let ahead = input.fork();
324 ahead.parse::<Token![crate]>()?;
325 ahead.peek(Token![::])
326 };
327
328 if followed_by_colons {
329 Ok(Visibility::Inherited)
330 } else {
331 Ok(Visibility::Crate(VisCrate {
332 crate_token: input.parse()?,
333 }))
334 }
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800335 }
Alex Crichton954046c2017-05-30 21:49:42 -0700336 }
David Tolnayf38cdf62016-09-23 19:07:09 -0700337}
338
339#[cfg(feature = "printing")]
340mod printing {
341 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700342 use proc_macro2::TokenStream;
343 use quote::{ToTokens, TokenStreamExt};
David Tolnayf38cdf62016-09-23 19:07:09 -0700344
345 impl ToTokens for Variant {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700346 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700347 tokens.append_all(&self.attrs);
David Tolnayf38cdf62016-09-23 19:07:09 -0700348 self.ident.to_tokens(tokens);
David Tolnaye3d41b72017-12-31 15:24:00 -0500349 self.fields.to_tokens(tokens);
David Tolnaye67902a2017-12-28 22:12:00 -0500350 if let Some((ref eq_token, ref disc)) = self.discriminant {
351 eq_token.to_tokens(tokens);
Michael Layzell3936ceb2017-07-08 00:28:36 -0400352 disc.to_tokens(tokens);
353 }
David Tolnayf38cdf62016-09-23 19:07:09 -0700354 }
355 }
356
David Tolnaye3d41b72017-12-31 15:24:00 -0500357 impl ToTokens for FieldsNamed {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700358 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnaye3d41b72017-12-31 15:24:00 -0500359 self.brace_token.surround(tokens, |tokens| {
David Tolnaybdafb102018-01-01 19:39:10 -0800360 self.named.to_tokens(tokens);
David Tolnaye3d41b72017-12-31 15:24:00 -0500361 });
362 }
363 }
364
365 impl ToTokens for FieldsUnnamed {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700366 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnaye3d41b72017-12-31 15:24:00 -0500367 self.paren_token.surround(tokens, |tokens| {
David Tolnaybdafb102018-01-01 19:39:10 -0800368 self.unnamed.to_tokens(tokens);
David Tolnaye3d41b72017-12-31 15:24:00 -0500369 });
David Tolnayf38cdf62016-09-23 19:07:09 -0700370 }
371 }
372
373 impl ToTokens for Field {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700374 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700375 tokens.append_all(&self.attrs);
David Tolnay47a877c2016-10-01 16:50:55 -0700376 self.vis.to_tokens(tokens);
Michael Layzell3936ceb2017-07-08 00:28:36 -0400377 if let Some(ref ident) = self.ident {
378 ident.to_tokens(tokens);
Alex Crichton259ee532017-07-14 06:51:02 -0700379 TokensOrDefault(&self.colon_token).to_tokens(tokens);
Michael Layzell3936ceb2017-07-08 00:28:36 -0400380 }
David Tolnayf38cdf62016-09-23 19:07:09 -0700381 self.ty.to_tokens(tokens);
382 }
383 }
384
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700385 impl ToTokens for VisPublic {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700386 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700387 self.pub_token.to_tokens(tokens)
388 }
389 }
Arnaviond32b2942017-04-29 17:18:02 -0700390
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700391 impl ToTokens for VisCrate {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700392 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnayfe58b5a2018-03-31 18:20:40 +0200393 self.crate_token.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700394 }
395 }
Arnaviond32b2942017-04-29 17:18:02 -0700396
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700397 impl ToTokens for VisRestricted {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700398 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700399 self.pub_token.to_tokens(tokens);
400 self.paren_token.surround(tokens, |tokens| {
David Tolnayfe58b5a2018-03-31 18:20:40 +0200401 // XXX: If we have a path which is not "self" or "super" or
402 // "crate", automatically add the "in" token.
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700403 self.in_token.to_tokens(tokens);
404 self.path.to_tokens(tokens);
405 });
406 }
407 }
David Tolnayf38cdf62016-09-23 19:07:09 -0700408}