blob: 875f4523dc5d702412c010b30824d83f264bab71 [file] [log] [blame]
David Tolnayb79ee962016-09-04 09:39:20 -07001use super::*;
Alex Crichtonccbb45d2017-05-23 10:58:24 -07002use delimited::Delimited;
David Tolnayb79ee962016-09-04 09:39:20 -07003
David Tolnay4a51dc72016-10-01 00:40:31 -07004use std::iter;
5
David Tolnay369f0c52017-12-27 01:50:45 -05006use proc_macro2::{Delimiter, TokenNode, TokenTree, TokenStream, Spacing};
David Tolnay9c76bcb2017-12-26 23:14:59 -05007
8#[cfg(feature = "extra-traits")]
9use std::hash::{Hash, Hasher};
10#[cfg(feature = "extra-traits")]
David Tolnay369f0c52017-12-27 01:50:45 -050011use mac::TokenStreamHelper;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070012
Alex Crichton62a0a592017-05-22 13:58:53 -070013ast_struct! {
14 /// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
David Tolnay9c76bcb2017-12-26 23:14:59 -050015 pub struct Attribute #manual_extra_traits {
Alex Crichton62a0a592017-05-22 13:58:53 -070016 pub style: AttrStyle,
David Tolnayf8db7ba2017-11-11 22:52:16 -080017 pub pound_token: Token![#],
David Tolnay32954ef2017-12-26 22:43:16 -050018 pub bracket_token: token::Bracket,
Arnavion44d2bf32017-04-19 02:47:55 -070019
Alex Crichton62a0a592017-05-22 13:58:53 -070020 /// The path of the attribute.
21 ///
22 /// E.g. `derive` in `#[derive(Copy)]`
23 /// E.g. `crate::precondition` in `#[crate::precondition x < 5]`
24 pub path: Path,
Arnavion44d2bf32017-04-19 02:47:55 -070025
Alex Crichton62a0a592017-05-22 13:58:53 -070026 /// Any tokens after the path.
27 ///
28 /// E.g. `( Copy )` in `#[derive(Copy)]`
29 /// E.g. `x < 5` in `#[crate::precondition x < 5]`
David Tolnay369f0c52017-12-27 01:50:45 -050030 pub tts: TokenStream,
Arnavion44d2bf32017-04-19 02:47:55 -070031
Alex Crichton62a0a592017-05-22 13:58:53 -070032 pub is_sugared_doc: bool,
33 }
David Tolnayb79ee962016-09-04 09:39:20 -070034}
35
David Tolnay9c76bcb2017-12-26 23:14:59 -050036#[cfg(feature = "extra-traits")]
37impl Eq for Attribute {}
38
39#[cfg(feature = "extra-traits")]
40impl PartialEq for Attribute {
41 fn eq(&self, other: &Self) -> bool {
42 self.style == other.style
43 && self.pound_token == other.pound_token
44 && self.bracket_token == other.bracket_token
45 && self.path == other.path
David Tolnay369f0c52017-12-27 01:50:45 -050046 && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
David Tolnay9c76bcb2017-12-26 23:14:59 -050047 && self.is_sugared_doc == other.is_sugared_doc
48 }
49}
50
51#[cfg(feature = "extra-traits")]
52impl Hash for Attribute {
53 fn hash<H>(&self, state: &mut H)
54 where H: Hasher
55 {
56 self.style.hash(state);
57 self.pound_token.hash(state);
58 self.bracket_token.hash(state);
59 self.path.hash(state);
David Tolnay369f0c52017-12-27 01:50:45 -050060 TokenStreamHelper(&self.tts).hash(state);
David Tolnay9c76bcb2017-12-26 23:14:59 -050061 self.is_sugared_doc.hash(state);
62 }
63}
64
David Tolnay02d77cc2016-10-02 09:52:08 -070065impl Attribute {
Arnavion44d2bf32017-04-19 02:47:55 -070066 /// Parses the tokens after the path as a [`MetaItem`](enum.MetaItem.html) if possible.
Arnavionbf395bf2017-04-15 15:35:22 -070067 pub fn meta_item(&self) -> Option<MetaItem> {
Arnavion95f8a7a2017-04-19 03:29:56 -070068 let name = if self.path.segments.len() == 1 {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070069 &self.path.segments.get(0).item().ident
Arnavion95f8a7a2017-04-19 03:29:56 -070070 } else {
71 return None;
72 };
73
Arnavionbf395bf2017-04-15 15:35:22 -070074 if self.tts.is_empty() {
David Tolnaybb4ca9f2017-12-26 12:28:58 -050075 return Some(MetaItem::Term(*name));
Arnavionbf395bf2017-04-15 15:35:22 -070076 }
77
David Tolnay369f0c52017-12-27 01:50:45 -050078 let tts = self.tts.clone().into_iter().collect::<Vec<_>>();
79
80 if tts.len() == 1 {
81 if let TokenNode::Group(Delimiter::Parenthesis, ref ts) = tts[0].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070082 let tokens = ts.clone().into_iter().collect::<Vec<_>>();
83 if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(&tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -070084 return Some(MetaItem::List(MetaItemList {
David Tolnay369f0c52017-12-27 01:50:45 -050085 paren_token: token::Paren(tts[0].span),
David Tolnaybb4ca9f2017-12-26 12:28:58 -050086 ident: *name,
Alex Crichton62a0a592017-05-22 13:58:53 -070087 nested: nested_meta_items,
88 }));
Arnavionbf395bf2017-04-15 15:35:22 -070089 }
90 }
91 }
92
David Tolnay369f0c52017-12-27 01:50:45 -050093 if tts.len() == 2 {
94 if let TokenNode::Op('=', Spacing::Alone) = tts[0].kind {
95 if let TokenNode::Literal(ref lit) = tts[1].kind {
Alex Crichton62a0a592017-05-22 13:58:53 -070096 return Some(MetaItem::NameValue(MetaNameValue {
David Tolnaybb4ca9f2017-12-26 12:28:58 -050097 ident: *name,
David Tolnay369f0c52017-12-27 01:50:45 -050098 eq_token: Token![=]([tts[0].span]),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070099 lit: Lit {
100 value: LitKind::Other(lit.clone()),
David Tolnay369f0c52017-12-27 01:50:45 -0500101 span: tts[1].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700102 },
Alex Crichton62a0a592017-05-22 13:58:53 -0700103 }));
Arnavionbf395bf2017-04-15 15:35:22 -0700104 }
Arnavionbf395bf2017-04-15 15:35:22 -0700105 }
106 }
107
108 None
David Tolnay02d77cc2016-10-02 09:52:08 -0700109 }
110}
111
David Tolnay9c76bcb2017-12-26 23:14:59 -0500112fn nested_meta_item_from_tokens(tts: &[TokenTree])
113 -> Option<(NestedMetaItem, &[TokenTree])>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700114{
115 assert!(!tts.is_empty());
116
117 match tts[0].kind {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700118 TokenNode::Literal(ref lit) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700119 let lit = Lit {
120 value: LitKind::Other(lit.clone()),
David Tolnay98942562017-12-26 21:24:35 -0500121 span: tts[0].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700122 };
123 Some((NestedMetaItem::Literal(lit), &tts[1..]))
124 }
125
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700126 TokenNode::Term(sym) => {
David Tolnay98942562017-12-26 21:24:35 -0500127 let ident = Ident::new(sym, tts[0].span);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700128 if tts.len() >= 3 {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700129 if let TokenNode::Op('=', Spacing::Alone) = tts[1].kind {
130 if let TokenNode::Literal(ref lit) = tts[2].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700131 let pair = MetaNameValue {
David Tolnay98942562017-12-26 21:24:35 -0500132 ident: Ident::new(sym, tts[0].span),
133 eq_token: Token![=]([tts[1].span]),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700134 lit: Lit {
135 value: LitKind::Other(lit.clone()),
David Tolnay98942562017-12-26 21:24:35 -0500136 span: tts[2].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700137 },
138 };
139 return Some((MetaItem::NameValue(pair).into(), &tts[3..]));
140 }
141 }
142 }
143
144 if tts.len() >= 2 {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700145 if let TokenNode::Group(Delimiter::Parenthesis, ref inner_tts) = tts[1].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700146 let inner_tts = inner_tts.clone().into_iter().collect::<Vec<_>>();
147 return match list_of_nested_meta_items_from_tokens(&inner_tts) {
148 Some(nested_meta_items) => {
149 let list = MetaItemList {
150 ident: ident,
David Tolnay32954ef2017-12-26 22:43:16 -0500151 paren_token: token::Paren(tts[1].span),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700152 nested: nested_meta_items,
153 };
154 Some((MetaItem::List(list).into(), &tts[2..]))
155 }
156
157 None => None
158 };
159 }
160 }
161
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700162 Some((MetaItem::Term(ident).into(), &tts[1..]))
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700163 }
164
165 _ => None
166 }
167}
168
David Tolnay9c76bcb2017-12-26 23:14:59 -0500169fn list_of_nested_meta_items_from_tokens(mut tts: &[TokenTree])
David Tolnayf8db7ba2017-11-11 22:52:16 -0800170 -> Option<Delimited<NestedMetaItem, Token![,]>>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700171{
172 let mut delimited = Delimited::new();
173 let mut first = true;
174
175 while !tts.is_empty() {
176 let prev_comma = if first {
177 first = false;
178 None
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700179 } else if let TokenNode::Op(',', Spacing::Alone) = tts[0].kind {
David Tolnay98942562017-12-26 21:24:35 -0500180 let tok = Token![,]([tts[0].span]);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700181 tts = &tts[1..];
182 if tts.is_empty() {
183 break
184 }
185 Some(tok)
186 } else {
187 return None
188 };
189 let (nested, rest) = match nested_meta_item_from_tokens(tts) {
190 Some(pair) => pair,
191 None => return None,
192 };
193 match prev_comma {
194 Some(comma) => delimited.push_next(nested, comma),
195 None => delimited.push_first(nested),
196 }
197 tts = rest;
198 }
199
200 Some(delimited)
201}
202
203
Alex Crichton62a0a592017-05-22 13:58:53 -0700204ast_enum! {
205 /// Distinguishes between Attributes that decorate items and Attributes that
206 /// are contained as statements within items. These two cases need to be
207 /// distinguished for pretty-printing.
Alex Crichton2e0229c2017-05-23 09:34:50 -0700208 #[cfg_attr(feature = "clone-impls", derive(Copy))]
Alex Crichton62a0a592017-05-22 13:58:53 -0700209 pub enum AttrStyle {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700210 /// Attribute of the form `#[...]`.
Alex Crichton62a0a592017-05-22 13:58:53 -0700211 Outer,
Clar Charrd22b5702017-03-10 15:24:56 -0500212
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700213 /// Attribute of the form `#![...]`.
David Tolnayf8db7ba2017-11-11 22:52:16 -0800214 Inner(Token![!]),
Alex Crichton62a0a592017-05-22 13:58:53 -0700215 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700216}
217
Alex Crichton62a0a592017-05-22 13:58:53 -0700218ast_enum_of_structs! {
219 /// A compile-time attribute item.
David Tolnayb79ee962016-09-04 09:39:20 -0700220 ///
Alex Crichton62a0a592017-05-22 13:58:53 -0700221 /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
222 pub enum MetaItem {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700223 /// Term meta item.
Alex Crichton62a0a592017-05-22 13:58:53 -0700224 ///
225 /// E.g. `test` as in `#[test]`
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700226 pub Term(Ident),
Clar Charrd22b5702017-03-10 15:24:56 -0500227
Alex Crichton62a0a592017-05-22 13:58:53 -0700228 /// List meta item.
229 ///
230 /// E.g. `derive(..)` as in `#[derive(..)]`
231 pub List(MetaItemList {
232 /// Name of this attribute.
233 ///
234 /// E.g. `derive` in `#[derive(..)]`
235 pub ident: Ident,
Clar Charrd22b5702017-03-10 15:24:56 -0500236
David Tolnay32954ef2017-12-26 22:43:16 -0500237 pub paren_token: token::Paren,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700238
Alex Crichton62a0a592017-05-22 13:58:53 -0700239 /// Arguments to this attribute
240 ///
241 /// E.g. `..` in `#[derive(..)]`
David Tolnayf8db7ba2017-11-11 22:52:16 -0800242 pub nested: Delimited<NestedMetaItem, Token![,]>,
Alex Crichton62a0a592017-05-22 13:58:53 -0700243 }),
244
245 /// Name-value meta item.
246 ///
247 /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
248 pub NameValue(MetaNameValue {
249 /// Name of this attribute.
250 ///
251 /// E.g. `feature` in `#[feature = "foo"]`
252 pub ident: Ident,
253
David Tolnayf8db7ba2017-11-11 22:52:16 -0800254 pub eq_token: Token![=],
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700255
Alex Crichton62a0a592017-05-22 13:58:53 -0700256 /// Arguments to this attribute
257 ///
258 /// E.g. `"foo"` in `#[feature = "foo"]`
259 pub lit: Lit,
260 }),
261 }
Arnavion95f8a7a2017-04-19 03:29:56 -0700262}
263
264impl MetaItem {
265 /// Name of the item.
266 ///
267 /// E.g. `test` as in `#[test]`, `derive` as in `#[derive(..)]`, and
268 /// `feature` as in `#[feature = "foo"]`.
269 pub fn name(&self) -> &str {
270 match *self {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700271 MetaItem::Term(ref name) => name.as_ref(),
Alex Crichton62a0a592017-05-22 13:58:53 -0700272 MetaItem::NameValue(ref pair) => pair.ident.as_ref(),
273 MetaItem::List(ref list) => list.ident.as_ref(),
Arnavion95f8a7a2017-04-19 03:29:56 -0700274 }
275 }
David Tolnay8e661e22016-09-27 00:00:04 -0700276}
277
Alex Crichton62a0a592017-05-22 13:58:53 -0700278ast_enum_of_structs! {
279 /// Possible values inside of compile-time attribute lists.
David Tolnayb7fa2b62016-10-30 10:50:47 -0700280 ///
Alex Crichton62a0a592017-05-22 13:58:53 -0700281 /// E.g. the '..' in `#[name(..)]`.
282 pub enum NestedMetaItem {
283 /// A full `MetaItem`.
284 ///
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700285 /// E.g. `Copy` in `#[derive(Copy)]` would be a `MetaItem::Term(Ident::from("Copy"))`.
Alex Crichton62a0a592017-05-22 13:58:53 -0700286 pub MetaItem(MetaItem),
Clar Charrd22b5702017-03-10 15:24:56 -0500287
Alex Crichton62a0a592017-05-22 13:58:53 -0700288 /// A Rust literal.
289 ///
290 /// E.g. `"name"` in `#[rename("name")]`.
291 pub Literal(Lit),
292 }
David Tolnayb7fa2b62016-10-30 10:50:47 -0700293}
294
David Tolnay4a51dc72016-10-01 00:40:31 -0700295pub trait FilterAttrs<'a> {
296 type Ret: Iterator<Item = &'a Attribute>;
297
298 fn outer(self) -> Self::Ret;
299 fn inner(self) -> Self::Ret;
300}
301
David Tolnaydaaf7742016-10-03 11:11:43 -0700302impl<'a, T> FilterAttrs<'a> for T
303 where T: IntoIterator<Item = &'a Attribute>
304{
David Tolnay4a51dc72016-10-01 00:40:31 -0700305 type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
306
307 fn outer(self) -> Self::Ret {
308 fn is_outer(attr: &&Attribute) -> bool {
Alex Crichton2e0229c2017-05-23 09:34:50 -0700309 match attr.style {
310 AttrStyle::Outer => true,
311 _ => false,
312 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700313 }
314 self.into_iter().filter(is_outer)
315 }
316
317 fn inner(self) -> Self::Ret {
318 fn is_inner(attr: &&Attribute) -> bool {
Alex Crichton2e0229c2017-05-23 09:34:50 -0700319 match attr.style {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700320 AttrStyle::Inner(_) => true,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700321 _ => false,
322 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700323 }
324 self.into_iter().filter(is_inner)
325 }
326}
327
David Tolnay86eca752016-09-04 11:26:41 -0700328#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700329pub mod parsing {
330 use super::*;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500331 use cursor::Cursor;
332 use {PResult, parse_error};
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700333 use proc_macro2::{TokenNode, Spacing, TokenTree};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700334
335 fn eq() -> TokenTree {
Alex Crichton954046c2017-05-30 21:49:42 -0700336 TokenTree {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700337 span: Default::default(),
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700338 kind: TokenNode::Op('=', Spacing::Alone),
Alex Crichton954046c2017-05-30 21:49:42 -0700339 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700340 }
341
Alex Crichton954046c2017-05-30 21:49:42 -0700342 impl Attribute {
343 #[cfg(feature = "full")]
Michael Layzell92639a52017-06-01 00:07:44 -0400344 named!(pub parse_inner -> Self, alt!(
345 do_parse!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800346 pound: punct!(#) >>
347 bang: punct!(!) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400348 path_and_tts: brackets!(tuple!(
349 call!(::Path::parse_mod_style),
David Tolnay369f0c52017-12-27 01:50:45 -0500350 syn!(TokenStream)
Michael Layzell92639a52017-06-01 00:07:44 -0400351 )) >>
352 ({
353 let ((path, tts), bracket) = path_and_tts;
Alex Crichton954046c2017-05-30 21:49:42 -0700354
Michael Layzell92639a52017-06-01 00:07:44 -0400355 Attribute {
356 style: AttrStyle::Inner(bang),
357 path: path,
358 tts: tts,
359 is_sugared_doc: false,
360 pound_token: pound,
361 bracket_token: bracket,
Alex Crichton954046c2017-05-30 21:49:42 -0700362 }
Michael Layzell92639a52017-06-01 00:07:44 -0400363 })
364 )
365 |
366 map!(
367 lit_doc_comment,
368 |lit| Attribute {
David Tolnayf8db7ba2017-11-11 22:52:16 -0800369 style: AttrStyle::Inner(<Token![!]>::default()),
Michael Layzell92639a52017-06-01 00:07:44 -0400370 path: "doc".into(),
371 tts: vec![
David Tolnay9c76bcb2017-12-26 23:14:59 -0500372 eq(),
373 lit,
David Tolnay369f0c52017-12-27 01:50:45 -0500374 ].into_iter().collect(),
Michael Layzell92639a52017-06-01 00:07:44 -0400375 is_sugared_doc: true,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800376 pound_token: <Token![#]>::default(),
David Tolnay32954ef2017-12-26 22:43:16 -0500377 bracket_token: token::Bracket::default(),
Michael Layzell92639a52017-06-01 00:07:44 -0400378 }
379 )
380 ));
Alex Crichton954046c2017-05-30 21:49:42 -0700381
Michael Layzell92639a52017-06-01 00:07:44 -0400382 named!(pub parse_outer -> Self, alt!(
383 do_parse!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800384 pound: punct!(#) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400385 path_and_tts: brackets!(tuple!(
386 call!(::Path::parse_mod_style),
David Tolnay369f0c52017-12-27 01:50:45 -0500387 syn!(TokenStream)
Michael Layzell92639a52017-06-01 00:07:44 -0400388 )) >>
389 ({
390 let ((path, tts), bracket) = path_and_tts;
Alex Crichton954046c2017-05-30 21:49:42 -0700391
Michael Layzell92639a52017-06-01 00:07:44 -0400392 Attribute {
Alex Crichton954046c2017-05-30 21:49:42 -0700393 style: AttrStyle::Outer,
Michael Layzell92639a52017-06-01 00:07:44 -0400394 path: path,
395 tts: tts,
396 is_sugared_doc: false,
397 pound_token: pound,
398 bracket_token: bracket,
Alex Crichton954046c2017-05-30 21:49:42 -0700399 }
Michael Layzell92639a52017-06-01 00:07:44 -0400400 })
401 )
402 |
403 map!(
404 lit_doc_comment,
405 |lit| Attribute {
406 style: AttrStyle::Outer,
407 path: "doc".into(),
408 tts: vec![
David Tolnay9c76bcb2017-12-26 23:14:59 -0500409 eq(),
410 lit,
David Tolnay369f0c52017-12-27 01:50:45 -0500411 ].into_iter().collect(),
Michael Layzell92639a52017-06-01 00:07:44 -0400412 is_sugared_doc: true,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800413 pound_token: <Token![#]>::default(),
David Tolnay32954ef2017-12-26 22:43:16 -0500414 bracket_token: token::Bracket::default(),
Michael Layzell92639a52017-06-01 00:07:44 -0400415 }
416 )
417 ));
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700418 }
David Tolnayb79ee962016-09-04 09:39:20 -0700419
Michael Layzell92639a52017-06-01 00:07:44 -0400420 fn lit_doc_comment(input: Cursor) -> PResult<TokenTree> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400421 match input.literal() {
422 Some((rest, span, lit)) => {
423 let literal = lit.to_string();
424 if literal.starts_with("//") || literal.starts_with("/*") {
425 Ok((rest, TokenTree {
426 span: span,
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700427 kind: TokenNode::Literal(lit)
Michael Layzell589a8f42017-06-02 19:47:01 -0400428 }))
429 } else {
430 parse_error()
431 }
432 }
433 _ => parse_error()
Alex Crichton954046c2017-05-30 21:49:42 -0700434 }
435 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700436}
David Tolnay87d0b442016-09-04 11:52:12 -0700437
438#[cfg(feature = "printing")]
439mod printing {
440 use super::*;
441 use quote::{Tokens, ToTokens};
442
443 impl ToTokens for Attribute {
444 fn to_tokens(&self, tokens: &mut Tokens) {
Arnavion44d2bf32017-04-19 02:47:55 -0700445 // If this was a sugared doc, emit it in its original form instead of `#[doc = "..."]`
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700446 if self.is_sugared_doc {
447 if let Some(MetaItem::NameValue(ref pair)) = self.meta_item() {
448 if pair.ident == "doc" {
449 let value = pair.lit.value.to_string();
Alex Crichton954046c2017-05-30 21:49:42 -0700450 if value.starts_with('/') {
451 pair.lit.to_tokens(tokens);
452 return
David Tolnay14cbdeb2016-10-01 12:13:59 -0700453 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700454 }
David Tolnayc91dd672016-10-01 01:03:56 -0700455 }
456 }
David Tolnay14cbdeb2016-10-01 12:13:59 -0700457
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700458 self.pound_token.to_tokens(tokens);
459 if let AttrStyle::Inner(ref b) = self.style {
460 b.to_tokens(tokens);
David Tolnay14cbdeb2016-10-01 12:13:59 -0700461 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700462 self.bracket_token.surround(tokens, |tokens| {
463 self.path.to_tokens(tokens);
David Tolnay369f0c52017-12-27 01:50:45 -0500464 tokens.append_all(&self.tts.clone().into_iter().collect::<Vec<_>>());
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700465 });
David Tolnay87d0b442016-09-04 11:52:12 -0700466 }
467 }
468
Alex Crichton62a0a592017-05-22 13:58:53 -0700469 impl ToTokens for MetaItemList {
David Tolnay87d0b442016-09-04 11:52:12 -0700470 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -0700471 self.ident.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700472 self.paren_token.surround(tokens, |tokens| {
473 self.nested.to_tokens(tokens);
474 })
David Tolnay87d0b442016-09-04 11:52:12 -0700475 }
476 }
David Tolnayb7fa2b62016-10-30 10:50:47 -0700477
Alex Crichton62a0a592017-05-22 13:58:53 -0700478 impl ToTokens for MetaNameValue {
David Tolnayb7fa2b62016-10-30 10:50:47 -0700479 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -0700480 self.ident.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700481 self.eq_token.to_tokens(tokens);
Alex Crichton62a0a592017-05-22 13:58:53 -0700482 self.lit.to_tokens(tokens);
David Tolnayb7fa2b62016-10-30 10:50:47 -0700483 }
484 }
David Tolnay87d0b442016-09-04 11:52:12 -0700485}