blob: e41e8e7ab0a9bb4934ede1e7785922a3f367ff16 [file] [log] [blame]
David Tolnayb79ee962016-09-04 09:39:20 -07001use super::*;
2
David Tolnayaed77b02016-09-23 20:50:31 -07003/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
David Tolnayb79ee962016-09-04 09:39:20 -07004#[derive(Debug, Clone, Eq, PartialEq)]
5pub struct Attribute {
6 pub value: MetaItem,
7 pub is_sugared_doc: bool,
8}
9
10/// A compile-time attribute item.
11///
12/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
13#[derive(Debug, Clone, Eq, PartialEq)]
14pub enum MetaItem {
15 /// Word meta item.
16 ///
17 /// E.g. `test` as in `#[test]`
18 Word(Ident),
19 /// List meta item.
20 ///
21 /// E.g. `derive(..)` as in `#[derive(..)]`
22 List(Ident, Vec<MetaItem>),
23 /// Name value meta item.
24 ///
25 /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
David Tolnayf4bbbd92016-09-23 14:41:55 -070026 NameValue(Ident, Lit),
David Tolnayb79ee962016-09-04 09:39:20 -070027}
28
David Tolnay8e661e22016-09-27 00:00:04 -070029impl MetaItem {
30 pub fn name(&self) -> &str {
31 match *self {
32 MetaItem::Word(ref name) => name.as_ref(),
33 MetaItem::List(ref name, _) => name.as_ref(),
34 MetaItem::NameValue(ref name, _) => name.as_ref(),
35 }
36 }
37}
38
David Tolnay86eca752016-09-04 11:26:41 -070039#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -070040pub mod parsing {
41 use super::*;
David Tolnay55337722016-09-11 12:58:56 -070042 use ident::parsing::ident;
David Tolnayf4bbbd92016-09-23 14:41:55 -070043 use lit::{Lit, StrStyle};
44 use lit::parsing::lit;
David Tolnayb79ee962016-09-04 09:39:20 -070045
David Tolnayb5a7b142016-09-13 22:46:39 -070046 named!(pub attribute -> Attribute, alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -070047 do_parse!(
48 punct!("#") >>
49 punct!("[") >>
50 meta_item: meta_item >>
51 punct!("]") >>
52 (Attribute {
53 value: meta_item,
54 is_sugared_doc: false,
55 })
56 )
57 |
58 do_parse!(
59 punct!("///") >>
David Tolnayc91dd672016-10-01 01:03:56 -070060 not!(peek!(tag!("/"))) >>
David Tolnayb5a7b142016-09-13 22:46:39 -070061 content: take_until!("\n") >>
David Tolnay9d8f1972016-09-04 11:58:48 -070062 (Attribute {
63 value: MetaItem::NameValue(
David Tolnay42f50292016-09-04 13:54:21 -070064 "doc".into(),
David Tolnayf4bbbd92016-09-23 14:41:55 -070065 Lit::Str(
David Tolnayc91dd672016-10-01 01:03:56 -070066 format!("///{}", content),
David Tolnayf4bbbd92016-09-23 14:41:55 -070067 StrStyle::Cooked,
68 ),
David Tolnay9d8f1972016-09-04 11:58:48 -070069 ),
70 is_sugared_doc: true,
71 })
72 )
73 ));
David Tolnayb79ee962016-09-04 09:39:20 -070074
David Tolnayb5a7b142016-09-13 22:46:39 -070075 named!(meta_item -> MetaItem, alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -070076 do_parse!(
David Tolnay55337722016-09-11 12:58:56 -070077 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -070078 punct!("(") >>
79 inner: separated_list!(punct!(","), meta_item) >>
80 punct!(")") >>
David Tolnay55337722016-09-11 12:58:56 -070081 (MetaItem::List(id, inner))
David Tolnay9d8f1972016-09-04 11:58:48 -070082 )
83 |
84 do_parse!(
David Tolnayf4bbbd92016-09-23 14:41:55 -070085 name: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -070086 punct!("=") >>
David Tolnayf4bbbd92016-09-23 14:41:55 -070087 value: lit >>
88 (MetaItem::NameValue(name, value))
David Tolnay9d8f1972016-09-04 11:58:48 -070089 )
90 |
David Tolnay55337722016-09-11 12:58:56 -070091 map!(ident, MetaItem::Word)
David Tolnay9d8f1972016-09-04 11:58:48 -070092 ));
93}
David Tolnay87d0b442016-09-04 11:52:12 -070094
95#[cfg(feature = "printing")]
96mod printing {
97 use super::*;
David Tolnayc91dd672016-10-01 01:03:56 -070098 use lit::{Lit, StrStyle};
David Tolnay87d0b442016-09-04 11:52:12 -070099 use quote::{Tokens, ToTokens};
100
101 impl ToTokens for Attribute {
102 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnayc91dd672016-10-01 01:03:56 -0700103 match *self {
104 Attribute {
105 value: MetaItem::NameValue(
106 ref name,
107 Lit::Str(ref value, StrStyle::Cooked),
108 ),
109 is_sugared_doc: true,
110 } if name == "doc" && value.starts_with("///") => {
111 tokens.append(&format!("{}\n", value));
112 }
113 _ => {
114 tokens.append("#");
115 tokens.append("[");
116 self.value.to_tokens(tokens);
117 tokens.append("]");
118 }
119 }
David Tolnay87d0b442016-09-04 11:52:12 -0700120 }
121 }
122
123 impl ToTokens for MetaItem {
124 fn to_tokens(&self, tokens: &mut Tokens) {
125 match *self {
David Tolnay26469072016-09-04 13:59:48 -0700126 MetaItem::Word(ref ident) => {
127 ident.to_tokens(tokens);
128 }
David Tolnay87d0b442016-09-04 11:52:12 -0700129 MetaItem::List(ref ident, ref inner) => {
David Tolnay26469072016-09-04 13:59:48 -0700130 ident.to_tokens(tokens);
David Tolnay87d0b442016-09-04 11:52:12 -0700131 tokens.append("(");
David Tolnay94ebdf92016-09-04 13:33:16 -0700132 tokens.append_separated(inner, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700133 tokens.append(")");
134 }
135 MetaItem::NameValue(ref name, ref value) => {
David Tolnay26469072016-09-04 13:59:48 -0700136 name.to_tokens(tokens);
David Tolnay87d0b442016-09-04 11:52:12 -0700137 tokens.append("=");
138 value.to_tokens(tokens);
139 }
140 }
141 }
142 }
143}