blob: 61526357b458baa40413ac1352a5a2e89800d943 [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 Tolnay51382052017-12-27 13:46:21 -05006use proc_macro2::{Delimiter, Spacing, TokenNode, TokenStream, TokenTree};
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 {
David Tolnayf8db7ba2017-11-11 22:52:16 -080016 pub pound_token: Token![#],
David Tolnay4a3f59a2017-12-28 21:21:12 -050017 pub style: AttrStyle,
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 {
David Tolnay51382052017-12-27 13:46:21 -050042 self.style == other.style && self.pound_token == other.pound_token
43 && self.bracket_token == other.bracket_token && self.path == other.path
David Tolnay369f0c52017-12-27 01:50:45 -050044 && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
David Tolnay9c76bcb2017-12-26 23:14:59 -050045 && self.is_sugared_doc == other.is_sugared_doc
46 }
47}
48
49#[cfg(feature = "extra-traits")]
50impl Hash for Attribute {
51 fn hash<H>(&self, state: &mut H)
David Tolnay51382052017-12-27 13:46:21 -050052 where
53 H: Hasher,
David Tolnay9c76bcb2017-12-26 23:14:59 -050054 {
55 self.style.hash(state);
56 self.pound_token.hash(state);
57 self.bracket_token.hash(state);
58 self.path.hash(state);
David Tolnay369f0c52017-12-27 01:50:45 -050059 TokenStreamHelper(&self.tts).hash(state);
David Tolnay9c76bcb2017-12-26 23:14:59 -050060 self.is_sugared_doc.hash(state);
61 }
62}
63
David Tolnay02d77cc2016-10-02 09:52:08 -070064impl Attribute {
Arnavion44d2bf32017-04-19 02:47:55 -070065 /// Parses the tokens after the path as a [`MetaItem`](enum.MetaItem.html) if possible.
Arnavionbf395bf2017-04-15 15:35:22 -070066 pub fn meta_item(&self) -> Option<MetaItem> {
Arnavion95f8a7a2017-04-19 03:29:56 -070067 let name = if self.path.segments.len() == 1 {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070068 &self.path.segments.get(0).item().ident
Arnavion95f8a7a2017-04-19 03:29:56 -070069 } else {
70 return None;
71 };
72
Arnavionbf395bf2017-04-15 15:35:22 -070073 if self.tts.is_empty() {
David Tolnaybb4ca9f2017-12-26 12:28:58 -050074 return Some(MetaItem::Term(*name));
Arnavionbf395bf2017-04-15 15:35:22 -070075 }
76
David Tolnay369f0c52017-12-27 01:50:45 -050077 let tts = self.tts.clone().into_iter().collect::<Vec<_>>();
78
79 if tts.len() == 1 {
80 if let TokenNode::Group(Delimiter::Parenthesis, ref ts) = tts[0].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070081 let tokens = ts.clone().into_iter().collect::<Vec<_>>();
82 if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(&tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -070083 return Some(MetaItem::List(MetaItemList {
David Tolnay369f0c52017-12-27 01:50:45 -050084 paren_token: token::Paren(tts[0].span),
David Tolnaybb4ca9f2017-12-26 12:28:58 -050085 ident: *name,
Alex Crichton62a0a592017-05-22 13:58:53 -070086 nested: nested_meta_items,
87 }));
Arnavionbf395bf2017-04-15 15:35:22 -070088 }
89 }
90 }
91
David Tolnay369f0c52017-12-27 01:50:45 -050092 if tts.len() == 2 {
93 if let TokenNode::Op('=', Spacing::Alone) = tts[0].kind {
94 if let TokenNode::Literal(ref lit) = tts[1].kind {
Alex Crichton62a0a592017-05-22 13:58:53 -070095 return Some(MetaItem::NameValue(MetaNameValue {
David Tolnaybb4ca9f2017-12-26 12:28:58 -050096 ident: *name,
David Tolnay369f0c52017-12-27 01:50:45 -050097 eq_token: Token![=]([tts[0].span]),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070098 lit: Lit {
99 value: LitKind::Other(lit.clone()),
David Tolnay369f0c52017-12-27 01:50:45 -0500100 span: tts[1].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700101 },
Alex Crichton62a0a592017-05-22 13:58:53 -0700102 }));
Arnavionbf395bf2017-04-15 15:35:22 -0700103 }
Arnavionbf395bf2017-04-15 15:35:22 -0700104 }
105 }
106
107 None
David Tolnay02d77cc2016-10-02 09:52:08 -0700108 }
109}
110
David Tolnay51382052017-12-27 13:46:21 -0500111fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMetaItem, &[TokenTree])> {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700112 assert!(!tts.is_empty());
113
114 match tts[0].kind {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700115 TokenNode::Literal(ref lit) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700116 let lit = Lit {
117 value: LitKind::Other(lit.clone()),
David Tolnay98942562017-12-26 21:24:35 -0500118 span: tts[0].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700119 };
120 Some((NestedMetaItem::Literal(lit), &tts[1..]))
121 }
122
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700123 TokenNode::Term(sym) => {
David Tolnayeb771d72017-12-27 22:11:06 -0500124 let ident = Ident::new(sym.as_str(), tts[0].span);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700125 if tts.len() >= 3 {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700126 if let TokenNode::Op('=', Spacing::Alone) = tts[1].kind {
127 if let TokenNode::Literal(ref lit) = tts[2].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700128 let pair = MetaNameValue {
David Tolnayeb771d72017-12-27 22:11:06 -0500129 ident: Ident::new(sym.as_str(), tts[0].span),
David Tolnay98942562017-12-26 21:24:35 -0500130 eq_token: Token![=]([tts[1].span]),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700131 lit: Lit {
132 value: LitKind::Other(lit.clone()),
David Tolnay98942562017-12-26 21:24:35 -0500133 span: tts[2].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700134 },
135 };
136 return Some((MetaItem::NameValue(pair).into(), &tts[3..]));
137 }
138 }
139 }
140
141 if tts.len() >= 2 {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700142 if let TokenNode::Group(Delimiter::Parenthesis, ref inner_tts) = tts[1].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700143 let inner_tts = inner_tts.clone().into_iter().collect::<Vec<_>>();
144 return match list_of_nested_meta_items_from_tokens(&inner_tts) {
145 Some(nested_meta_items) => {
146 let list = MetaItemList {
147 ident: ident,
David Tolnay32954ef2017-12-26 22:43:16 -0500148 paren_token: token::Paren(tts[1].span),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700149 nested: nested_meta_items,
150 };
151 Some((MetaItem::List(list).into(), &tts[2..]))
152 }
153
David Tolnay51382052017-12-27 13:46:21 -0500154 None => None,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700155 };
156 }
157 }
158
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700159 Some((MetaItem::Term(ident).into(), &tts[1..]))
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700160 }
161
David Tolnay51382052017-12-27 13:46:21 -0500162 _ => None,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700163 }
164}
165
David Tolnay51382052017-12-27 13:46:21 -0500166fn list_of_nested_meta_items_from_tokens(
167 mut tts: &[TokenTree],
168) -> Option<Delimited<NestedMetaItem, Token![,]>> {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700169 let mut delimited = Delimited::new();
170 let mut first = true;
171
172 while !tts.is_empty() {
173 let prev_comma = if first {
174 first = false;
175 None
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700176 } else if let TokenNode::Op(',', Spacing::Alone) = tts[0].kind {
David Tolnay98942562017-12-26 21:24:35 -0500177 let tok = Token![,]([tts[0].span]);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700178 tts = &tts[1..];
179 if tts.is_empty() {
David Tolnay51382052017-12-27 13:46:21 -0500180 break;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700181 }
182 Some(tok)
183 } else {
David Tolnay51382052017-12-27 13:46:21 -0500184 return None;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700185 };
186 let (nested, rest) = match nested_meta_item_from_tokens(tts) {
187 Some(pair) => pair,
188 None => return None,
189 };
190 match prev_comma {
191 Some(comma) => delimited.push_next(nested, comma),
192 None => delimited.push_first(nested),
193 }
194 tts = rest;
195 }
196
197 Some(delimited)
198}
199
Alex Crichton62a0a592017-05-22 13:58:53 -0700200ast_enum! {
201 /// Distinguishes between Attributes that decorate items and Attributes that
202 /// are contained as statements within items. These two cases need to be
203 /// distinguished for pretty-printing.
Alex Crichton2e0229c2017-05-23 09:34:50 -0700204 #[cfg_attr(feature = "clone-impls", derive(Copy))]
Alex Crichton62a0a592017-05-22 13:58:53 -0700205 pub enum AttrStyle {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700206 /// Attribute of the form `#[...]`.
Alex Crichton62a0a592017-05-22 13:58:53 -0700207 Outer,
Clar Charrd22b5702017-03-10 15:24:56 -0500208
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700209 /// Attribute of the form `#![...]`.
David Tolnayf8db7ba2017-11-11 22:52:16 -0800210 Inner(Token![!]),
Alex Crichton62a0a592017-05-22 13:58:53 -0700211 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700212}
213
Alex Crichton62a0a592017-05-22 13:58:53 -0700214ast_enum_of_structs! {
215 /// A compile-time attribute item.
David Tolnayb79ee962016-09-04 09:39:20 -0700216 ///
Alex Crichton62a0a592017-05-22 13:58:53 -0700217 /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
218 pub enum MetaItem {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700219 /// Term meta item.
Alex Crichton62a0a592017-05-22 13:58:53 -0700220 ///
221 /// E.g. `test` as in `#[test]`
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700222 pub Term(Ident),
Clar Charrd22b5702017-03-10 15:24:56 -0500223
Alex Crichton62a0a592017-05-22 13:58:53 -0700224 /// List meta item.
225 ///
226 /// E.g. `derive(..)` as in `#[derive(..)]`
227 pub List(MetaItemList {
228 /// Name of this attribute.
229 ///
230 /// E.g. `derive` in `#[derive(..)]`
231 pub ident: Ident,
Clar Charrd22b5702017-03-10 15:24:56 -0500232
David Tolnay32954ef2017-12-26 22:43:16 -0500233 pub paren_token: token::Paren,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700234
Alex Crichton62a0a592017-05-22 13:58:53 -0700235 /// Arguments to this attribute
236 ///
237 /// E.g. `..` in `#[derive(..)]`
David Tolnayf8db7ba2017-11-11 22:52:16 -0800238 pub nested: Delimited<NestedMetaItem, Token![,]>,
Alex Crichton62a0a592017-05-22 13:58:53 -0700239 }),
240
241 /// Name-value meta item.
242 ///
243 /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
244 pub NameValue(MetaNameValue {
245 /// Name of this attribute.
246 ///
247 /// E.g. `feature` in `#[feature = "foo"]`
248 pub ident: Ident,
249
David Tolnayf8db7ba2017-11-11 22:52:16 -0800250 pub eq_token: Token![=],
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700251
Alex Crichton62a0a592017-05-22 13:58:53 -0700252 /// Arguments to this attribute
253 ///
254 /// E.g. `"foo"` in `#[feature = "foo"]`
255 pub lit: Lit,
256 }),
257 }
Arnavion95f8a7a2017-04-19 03:29:56 -0700258}
259
260impl MetaItem {
261 /// Name of the item.
262 ///
263 /// E.g. `test` as in `#[test]`, `derive` as in `#[derive(..)]`, and
264 /// `feature` as in `#[feature = "foo"]`.
265 pub fn name(&self) -> &str {
266 match *self {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700267 MetaItem::Term(ref name) => name.as_ref(),
Alex Crichton62a0a592017-05-22 13:58:53 -0700268 MetaItem::NameValue(ref pair) => pair.ident.as_ref(),
269 MetaItem::List(ref list) => list.ident.as_ref(),
Arnavion95f8a7a2017-04-19 03:29:56 -0700270 }
271 }
David Tolnay8e661e22016-09-27 00:00:04 -0700272}
273
Alex Crichton62a0a592017-05-22 13:58:53 -0700274ast_enum_of_structs! {
275 /// Possible values inside of compile-time attribute lists.
David Tolnayb7fa2b62016-10-30 10:50:47 -0700276 ///
Alex Crichton62a0a592017-05-22 13:58:53 -0700277 /// E.g. the '..' in `#[name(..)]`.
278 pub enum NestedMetaItem {
279 /// A full `MetaItem`.
280 ///
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700281 /// E.g. `Copy` in `#[derive(Copy)]` would be a `MetaItem::Term(Ident::from("Copy"))`.
Alex Crichton62a0a592017-05-22 13:58:53 -0700282 pub MetaItem(MetaItem),
Clar Charrd22b5702017-03-10 15:24:56 -0500283
Alex Crichton62a0a592017-05-22 13:58:53 -0700284 /// A Rust literal.
285 ///
286 /// E.g. `"name"` in `#[rename("name")]`.
287 pub Literal(Lit),
288 }
David Tolnayb7fa2b62016-10-30 10:50:47 -0700289}
290
David Tolnay4a51dc72016-10-01 00:40:31 -0700291pub trait FilterAttrs<'a> {
292 type Ret: Iterator<Item = &'a Attribute>;
293
294 fn outer(self) -> Self::Ret;
295 fn inner(self) -> Self::Ret;
296}
297
David Tolnaydaaf7742016-10-03 11:11:43 -0700298impl<'a, T> FilterAttrs<'a> for T
David Tolnay51382052017-12-27 13:46:21 -0500299where
300 T: IntoIterator<Item = &'a Attribute>,
David Tolnaydaaf7742016-10-03 11:11:43 -0700301{
David Tolnay4a51dc72016-10-01 00:40:31 -0700302 type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
303
304 fn outer(self) -> Self::Ret {
305 fn is_outer(attr: &&Attribute) -> bool {
Alex Crichton2e0229c2017-05-23 09:34:50 -0700306 match attr.style {
307 AttrStyle::Outer => true,
308 _ => false,
309 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700310 }
311 self.into_iter().filter(is_outer)
312 }
313
314 fn inner(self) -> Self::Ret {
315 fn is_inner(attr: &&Attribute) -> bool {
Alex Crichton2e0229c2017-05-23 09:34:50 -0700316 match attr.style {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700317 AttrStyle::Inner(_) => true,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700318 _ => false,
319 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700320 }
321 self.into_iter().filter(is_inner)
322 }
323}
324
David Tolnay86eca752016-09-04 11:26:41 -0700325#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700326pub mod parsing {
327 use super::*;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500328 use cursor::Cursor;
David Tolnay203557a2017-12-27 23:59:33 -0500329 use parse_error;
330 use synom::PResult;
David Tolnayf800fc12017-12-27 22:08:48 -0500331 use proc_macro2::{Spacing, Span, TokenNode, TokenTree};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700332
David Tolnayf800fc12017-12-27 22:08:48 -0500333 fn eq(span: Span) -> TokenTree {
Alex Crichton954046c2017-05-30 21:49:42 -0700334 TokenTree {
David Tolnayf800fc12017-12-27 22:08:48 -0500335 span: span,
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700336 kind: TokenNode::Op('=', Spacing::Alone),
Alex Crichton954046c2017-05-30 21:49:42 -0700337 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700338 }
339
Alex Crichton954046c2017-05-30 21:49:42 -0700340 impl Attribute {
341 #[cfg(feature = "full")]
Michael Layzell92639a52017-06-01 00:07:44 -0400342 named!(pub parse_inner -> Self, alt!(
343 do_parse!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800344 pound: punct!(#) >>
345 bang: punct!(!) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400346 path_and_tts: brackets!(tuple!(
347 call!(::Path::parse_mod_style),
David Tolnay369f0c52017-12-27 01:50:45 -0500348 syn!(TokenStream)
Michael Layzell92639a52017-06-01 00:07:44 -0400349 )) >>
350 ({
351 let ((path, tts), bracket) = path_and_tts;
Alex Crichton954046c2017-05-30 21:49:42 -0700352
Michael Layzell92639a52017-06-01 00:07:44 -0400353 Attribute {
354 style: AttrStyle::Inner(bang),
355 path: path,
356 tts: tts,
357 is_sugared_doc: false,
358 pound_token: pound,
359 bracket_token: bracket,
Alex Crichton954046c2017-05-30 21:49:42 -0700360 }
Michael Layzell92639a52017-06-01 00:07:44 -0400361 })
362 )
363 |
364 map!(
365 lit_doc_comment,
David Tolnayf800fc12017-12-27 22:08:48 -0500366 |lit| {
367 let span = lit.span;
368 Attribute {
369 style: AttrStyle::Inner(<Token![!]>::new(span)),
370 path: Ident::new("doc", span).into(),
371 tts: vec![
372 eq(span),
373 lit,
374 ].into_iter().collect(),
375 is_sugared_doc: true,
376 pound_token: <Token![#]>::new(span),
377 bracket_token: token::Bracket(span),
378 }
Michael Layzell92639a52017-06-01 00:07:44 -0400379 }
380 )
381 ));
Alex Crichton954046c2017-05-30 21:49:42 -0700382
Michael Layzell92639a52017-06-01 00:07:44 -0400383 named!(pub parse_outer -> Self, alt!(
384 do_parse!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800385 pound: punct!(#) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400386 path_and_tts: brackets!(tuple!(
387 call!(::Path::parse_mod_style),
David Tolnay369f0c52017-12-27 01:50:45 -0500388 syn!(TokenStream)
Michael Layzell92639a52017-06-01 00:07:44 -0400389 )) >>
390 ({
391 let ((path, tts), bracket) = path_and_tts;
Alex Crichton954046c2017-05-30 21:49:42 -0700392
Michael Layzell92639a52017-06-01 00:07:44 -0400393 Attribute {
Alex Crichton954046c2017-05-30 21:49:42 -0700394 style: AttrStyle::Outer,
Michael Layzell92639a52017-06-01 00:07:44 -0400395 path: path,
396 tts: tts,
397 is_sugared_doc: false,
398 pound_token: pound,
399 bracket_token: bracket,
Alex Crichton954046c2017-05-30 21:49:42 -0700400 }
Michael Layzell92639a52017-06-01 00:07:44 -0400401 })
402 )
403 |
404 map!(
405 lit_doc_comment,
David Tolnayf800fc12017-12-27 22:08:48 -0500406 |lit| {
407 let span = lit.span;
408 Attribute {
409 style: AttrStyle::Outer,
410 path: Ident::new("doc", span).into(),
411 tts: vec![
412 eq(span),
413 lit,
414 ].into_iter().collect(),
415 is_sugared_doc: true,
416 pound_token: <Token![#]>::new(span),
417 bracket_token: token::Bracket(span),
418 }
Michael Layzell92639a52017-06-01 00:07:44 -0400419 }
420 )
421 ));
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700422 }
David Tolnayb79ee962016-09-04 09:39:20 -0700423
Michael Layzell92639a52017-06-01 00:07:44 -0400424 fn lit_doc_comment(input: Cursor) -> PResult<TokenTree> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400425 match input.literal() {
426 Some((rest, span, lit)) => {
427 let literal = lit.to_string();
428 if literal.starts_with("//") || literal.starts_with("/*") {
David Tolnay51382052017-12-27 13:46:21 -0500429 Ok((
430 rest,
431 TokenTree {
432 span: span,
433 kind: TokenNode::Literal(lit),
434 },
435 ))
Michael Layzell589a8f42017-06-02 19:47:01 -0400436 } else {
437 parse_error()
438 }
439 }
David Tolnay51382052017-12-27 13:46:21 -0500440 _ => parse_error(),
Alex Crichton954046c2017-05-30 21:49:42 -0700441 }
442 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700443}
David Tolnay87d0b442016-09-04 11:52:12 -0700444
445#[cfg(feature = "printing")]
446mod printing {
447 use super::*;
David Tolnay51382052017-12-27 13:46:21 -0500448 use quote::{ToTokens, Tokens};
David Tolnay87d0b442016-09-04 11:52:12 -0700449
450 impl ToTokens for Attribute {
451 fn to_tokens(&self, tokens: &mut Tokens) {
Arnavion44d2bf32017-04-19 02:47:55 -0700452 // If this was a sugared doc, emit it in its original form instead of `#[doc = "..."]`
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700453 if self.is_sugared_doc {
454 if let Some(MetaItem::NameValue(ref pair)) = self.meta_item() {
455 if pair.ident == "doc" {
456 let value = pair.lit.value.to_string();
Alex Crichton954046c2017-05-30 21:49:42 -0700457 if value.starts_with('/') {
458 pair.lit.to_tokens(tokens);
David Tolnay51382052017-12-27 13:46:21 -0500459 return;
David Tolnay14cbdeb2016-10-01 12:13:59 -0700460 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700461 }
David Tolnayc91dd672016-10-01 01:03:56 -0700462 }
463 }
David Tolnay14cbdeb2016-10-01 12:13:59 -0700464
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700465 self.pound_token.to_tokens(tokens);
466 if let AttrStyle::Inner(ref b) = self.style {
467 b.to_tokens(tokens);
David Tolnay14cbdeb2016-10-01 12:13:59 -0700468 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700469 self.bracket_token.surround(tokens, |tokens| {
470 self.path.to_tokens(tokens);
David Tolnay369f0c52017-12-27 01:50:45 -0500471 tokens.append_all(&self.tts.clone().into_iter().collect::<Vec<_>>());
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700472 });
David Tolnay87d0b442016-09-04 11:52:12 -0700473 }
474 }
475
Alex Crichton62a0a592017-05-22 13:58:53 -0700476 impl ToTokens for MetaItemList {
David Tolnay87d0b442016-09-04 11:52:12 -0700477 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -0700478 self.ident.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700479 self.paren_token.surround(tokens, |tokens| {
480 self.nested.to_tokens(tokens);
481 })
David Tolnay87d0b442016-09-04 11:52:12 -0700482 }
483 }
David Tolnayb7fa2b62016-10-30 10:50:47 -0700484
Alex Crichton62a0a592017-05-22 13:58:53 -0700485 impl ToTokens for MetaNameValue {
David Tolnayb7fa2b62016-10-30 10:50:47 -0700486 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -0700487 self.ident.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700488 self.eq_token.to_tokens(tokens);
Alex Crichton62a0a592017-05-22 13:58:53 -0700489 self.lit.to_tokens(tokens);
David Tolnayb7fa2b62016-10-30 10:50:47 -0700490 }
491 }
David Tolnay87d0b442016-09-04 11:52:12 -0700492}