blob: f953e6d657cd26da8582dcb0d015c8c691fe6446 [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
David Tolnay02d77cc2016-10-02 09:52:08 -070010impl Attribute {
11 pub fn name(&self) -> &str {
12 self.value.name()
13 }
14}
15
David Tolnayb79ee962016-09-04 09:39:20 -070016/// A compile-time attribute item.
17///
18/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
19#[derive(Debug, Clone, Eq, PartialEq)]
20pub enum MetaItem {
21 /// Word meta item.
22 ///
23 /// E.g. `test` as in `#[test]`
24 Word(Ident),
25 /// List meta item.
26 ///
27 /// E.g. `derive(..)` as in `#[derive(..)]`
28 List(Ident, Vec<MetaItem>),
29 /// Name value meta item.
30 ///
31 /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
David Tolnayf4bbbd92016-09-23 14:41:55 -070032 NameValue(Ident, Lit),
David Tolnayb79ee962016-09-04 09:39:20 -070033}
34
David Tolnay8e661e22016-09-27 00:00:04 -070035impl MetaItem {
36 pub fn name(&self) -> &str {
37 match *self {
David Tolnay590cdfd2016-10-01 08:51:55 -070038 MetaItem::Word(ref name) |
39 MetaItem::List(ref name, _) |
David Tolnay8e661e22016-09-27 00:00:04 -070040 MetaItem::NameValue(ref name, _) => name.as_ref(),
41 }
42 }
43}
44
David Tolnay86eca752016-09-04 11:26:41 -070045#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -070046pub mod parsing {
47 use super::*;
David Tolnay55337722016-09-11 12:58:56 -070048 use ident::parsing::ident;
David Tolnayf4bbbd92016-09-23 14:41:55 -070049 use lit::{Lit, StrStyle};
50 use lit::parsing::lit;
David Tolnayb79ee962016-09-04 09:39:20 -070051
David Tolnayb5a7b142016-09-13 22:46:39 -070052 named!(pub attribute -> Attribute, alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -070053 do_parse!(
54 punct!("#") >>
55 punct!("[") >>
56 meta_item: meta_item >>
57 punct!("]") >>
58 (Attribute {
59 value: meta_item,
60 is_sugared_doc: false,
61 })
62 )
63 |
64 do_parse!(
65 punct!("///") >>
David Tolnayc91dd672016-10-01 01:03:56 -070066 not!(peek!(tag!("/"))) >>
David Tolnayb5a7b142016-09-13 22:46:39 -070067 content: take_until!("\n") >>
David Tolnay9d8f1972016-09-04 11:58:48 -070068 (Attribute {
69 value: MetaItem::NameValue(
David Tolnay42f50292016-09-04 13:54:21 -070070 "doc".into(),
David Tolnayf4bbbd92016-09-23 14:41:55 -070071 Lit::Str(
David Tolnayc91dd672016-10-01 01:03:56 -070072 format!("///{}", content),
David Tolnayf4bbbd92016-09-23 14:41:55 -070073 StrStyle::Cooked,
74 ),
David Tolnay9d8f1972016-09-04 11:58:48 -070075 ),
76 is_sugared_doc: true,
77 })
78 )
79 ));
David Tolnayb79ee962016-09-04 09:39:20 -070080
David Tolnayb5a7b142016-09-13 22:46:39 -070081 named!(meta_item -> MetaItem, alt!(
David Tolnay9d8f1972016-09-04 11:58:48 -070082 do_parse!(
David Tolnay55337722016-09-11 12:58:56 -070083 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -070084 punct!("(") >>
85 inner: separated_list!(punct!(","), meta_item) >>
86 punct!(")") >>
David Tolnay55337722016-09-11 12:58:56 -070087 (MetaItem::List(id, inner))
David Tolnay9d8f1972016-09-04 11:58:48 -070088 )
89 |
90 do_parse!(
David Tolnayf4bbbd92016-09-23 14:41:55 -070091 name: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -070092 punct!("=") >>
David Tolnayf4bbbd92016-09-23 14:41:55 -070093 value: lit >>
94 (MetaItem::NameValue(name, value))
David Tolnay9d8f1972016-09-04 11:58:48 -070095 )
96 |
David Tolnay55337722016-09-11 12:58:56 -070097 map!(ident, MetaItem::Word)
David Tolnay9d8f1972016-09-04 11:58:48 -070098 ));
99}
David Tolnay87d0b442016-09-04 11:52:12 -0700100
101#[cfg(feature = "printing")]
102mod printing {
103 use super::*;
David Tolnayc91dd672016-10-01 01:03:56 -0700104 use lit::{Lit, StrStyle};
David Tolnay87d0b442016-09-04 11:52:12 -0700105 use quote::{Tokens, ToTokens};
106
107 impl ToTokens for Attribute {
108 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnayc91dd672016-10-01 01:03:56 -0700109 match *self {
110 Attribute {
111 value: MetaItem::NameValue(
112 ref name,
113 Lit::Str(ref value, StrStyle::Cooked),
114 ),
115 is_sugared_doc: true,
116 } if name == "doc" && value.starts_with("///") => {
117 tokens.append(&format!("{}\n", value));
118 }
119 _ => {
120 tokens.append("#");
121 tokens.append("[");
122 self.value.to_tokens(tokens);
123 tokens.append("]");
124 }
125 }
David Tolnay87d0b442016-09-04 11:52:12 -0700126 }
127 }
128
129 impl ToTokens for MetaItem {
130 fn to_tokens(&self, tokens: &mut Tokens) {
131 match *self {
David Tolnay26469072016-09-04 13:59:48 -0700132 MetaItem::Word(ref ident) => {
133 ident.to_tokens(tokens);
134 }
David Tolnay87d0b442016-09-04 11:52:12 -0700135 MetaItem::List(ref ident, ref inner) => {
David Tolnay26469072016-09-04 13:59:48 -0700136 ident.to_tokens(tokens);
David Tolnay87d0b442016-09-04 11:52:12 -0700137 tokens.append("(");
David Tolnay94ebdf92016-09-04 13:33:16 -0700138 tokens.append_separated(inner, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700139 tokens.append(")");
140 }
141 MetaItem::NameValue(ref name, ref value) => {
David Tolnay26469072016-09-04 13:59:48 -0700142 name.to_tokens(tokens);
David Tolnay87d0b442016-09-04 11:52:12 -0700143 tokens.append("=");
144 value.to_tokens(tokens);
145 }
146 }
147 }
148 }
149}