]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/attr.rs
Rollup merge of #42046 - steveklabnik:update-books, r=frewsxcv
[rust.git] / src / libsyntax / parse / attr.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use attr;
12 use ast;
13 use codemap::respan;
14 use parse::common::SeqSep;
15 use parse::PResult;
16 use parse::token::{self, Nonterminal};
17 use parse::parser::{Parser, TokenType, PathStyle};
18 use tokenstream::TokenStream;
19
20 #[derive(PartialEq, Eq, Debug)]
21 enum InnerAttributeParsePolicy<'a> {
22     Permitted,
23     NotPermitted { reason: &'a str },
24 }
25
26 const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &'static str = "an inner attribute is not \
27                                                              permitted in this context";
28
29 impl<'a> Parser<'a> {
30     /// Parse attributes that appear before an item
31     pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
32         let mut attrs: Vec<ast::Attribute> = Vec::new();
33         let mut just_parsed_doc_comment = false;
34         loop {
35             debug!("parse_outer_attributes: self.token={:?}", self.token);
36             match self.token {
37                 token::Pound => {
38                     let inner_error_reason = if just_parsed_doc_comment {
39                         "an inner attribute is not permitted following an outer doc comment"
40                     } else if !attrs.is_empty() {
41                         "an inner attribute is not permitted following an outer attribute"
42                     } else {
43                         DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
44                     };
45                     let inner_parse_policy =
46                         InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason };
47                     attrs.push(self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?);
48                     just_parsed_doc_comment = false;
49                 }
50                 token::DocComment(s) => {
51                     let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
52                     if attr.style != ast::AttrStyle::Outer {
53                         let mut err = self.fatal("expected outer doc comment");
54                         err.note("inner doc comments like this (starting with \
55                                   `//!` or `/*!`) can only appear before items");
56                         return Err(err);
57                     }
58                     attrs.push(attr);
59                     self.bump();
60                     just_parsed_doc_comment = true;
61                 }
62                 _ => break,
63             }
64         }
65         Ok(attrs)
66     }
67
68     /// Matches `attribute = # ! [ meta_item ]`
69     ///
70     /// If permit_inner is true, then a leading `!` indicates an inner
71     /// attribute
72     pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
73         debug!("parse_attribute: permit_inner={:?} self.token={:?}",
74                permit_inner,
75                self.token);
76         let inner_parse_policy = if permit_inner {
77             InnerAttributeParsePolicy::Permitted
78         } else {
79             InnerAttributeParsePolicy::NotPermitted
80                 { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
81         };
82         self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
83     }
84
85     /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
86     /// that prescribes how to handle inner attributes.
87     fn parse_attribute_with_inner_parse_policy(&mut self,
88                                                inner_parse_policy: InnerAttributeParsePolicy)
89                                                -> PResult<'a, ast::Attribute> {
90         debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
91                inner_parse_policy,
92                self.token);
93         let (span, path, tokens, mut style) = match self.token {
94             token::Pound => {
95                 let lo = self.span;
96                 self.bump();
97
98                 if inner_parse_policy == InnerAttributeParsePolicy::Permitted {
99                     self.expected_tokens.push(TokenType::Token(token::Not));
100                 }
101                 let style = if self.token == token::Not {
102                     self.bump();
103                     if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy
104                     {
105                         let span = self.span;
106                         self.diagnostic()
107                             .struct_span_err(span, reason)
108                             .note("inner attributes and doc comments, like `#![no_std]` or \
109                                    `//! My crate`, annotate the item enclosing them, and are \
110                                    usually found at the beginning of source files. Outer \
111                                    attributes and doc comments, like `#[test]` and
112                                    `/// My function`, annotate the item following them.")
113                             .emit()
114                     }
115                     ast::AttrStyle::Inner
116                 } else {
117                     ast::AttrStyle::Outer
118                 };
119
120                 self.expect(&token::OpenDelim(token::Bracket))?;
121                 let (path, tokens) = self.parse_path_and_tokens()?;
122                 self.expect(&token::CloseDelim(token::Bracket))?;
123                 let hi = self.prev_span;
124
125                 (lo.to(hi), path, tokens, style)
126             }
127             _ => {
128                 let token_str = self.this_token_to_string();
129                 return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
130             }
131         };
132
133         if inner_parse_policy == InnerAttributeParsePolicy::Permitted &&
134            self.token == token::Semi {
135             self.bump();
136             self.span_warn(span,
137                            "this inner attribute syntax is deprecated. The new syntax is \
138                             `#![foo]`, with a bang and no semicolon");
139             style = ast::AttrStyle::Inner;
140         }
141
142         Ok(ast::Attribute {
143             id: attr::mk_attr_id(),
144             style: style,
145             path: path,
146             tokens: tokens,
147             is_sugared_doc: false,
148             span: span,
149         })
150     }
151
152     pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
153         let meta = match self.token {
154             token::Interpolated(ref nt) => match **nt {
155                 Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
156                 _ => None,
157             },
158             _ => None,
159         };
160         Ok(if let Some(meta) = meta {
161             self.bump();
162             (ast::Path::from_ident(meta.span, ast::Ident::with_empty_ctxt(meta.name)),
163              meta.node.tokens(meta.span))
164         } else {
165             (self.parse_path(PathStyle::Mod)?, self.parse_tokens())
166         })
167     }
168
169     /// Parse attributes that appear after the opening of an item. These should
170     /// be preceded by an exclamation mark, but we accept and warn about one
171     /// terminated by a semicolon.
172
173     /// matches inner_attrs*
174     pub fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
175         let mut attrs: Vec<ast::Attribute> = vec![];
176         loop {
177             match self.token {
178                 token::Pound => {
179                     // Don't even try to parse if it's not an inner attribute.
180                     if !self.look_ahead(1, |t| t == &token::Not) {
181                         break;
182                     }
183
184                     let attr = self.parse_attribute(true)?;
185                     assert_eq!(attr.style, ast::AttrStyle::Inner);
186                     attrs.push(attr);
187                 }
188                 token::DocComment(s) => {
189                     // we need to get the position of this token before we bump.
190                     let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
191                     if attr.style == ast::AttrStyle::Inner {
192                         attrs.push(attr);
193                         self.bump();
194                     } else {
195                         break;
196                     }
197                 }
198                 _ => break,
199             }
200         }
201         Ok(attrs)
202     }
203
204     fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
205         let lit = self.parse_lit()?;
206         debug!("Checking if {:?} is unusuffixed.", lit);
207
208         if !lit.node.is_unsuffixed() {
209             let msg = "suffixed literals are not allowed in attributes";
210             self.diagnostic().struct_span_err(lit.span, msg)
211                              .help("instead of using a suffixed literal \
212                                     (1u8, 1.0f32, etc.), use an unsuffixed version \
213                                     (1, 1.0, etc.).")
214                              .emit()
215         }
216
217         Ok(lit)
218     }
219
220     /// Per RFC#1559, matches the following grammar:
221     ///
222     /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
223     /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
224     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
225         let nt_meta = match self.token {
226             token::Interpolated(ref nt) => match **nt {
227                 token::NtMeta(ref e) => Some(e.clone()),
228                 _ => None,
229             },
230             _ => None,
231         };
232
233         if let Some(meta) = nt_meta {
234             self.bump();
235             return Ok(meta);
236         }
237
238         let lo = self.span;
239         let ident = self.parse_ident()?;
240         let node = self.parse_meta_item_kind()?;
241         Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) })
242     }
243
244     pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
245         Ok(if self.eat(&token::Eq) {
246             ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
247         } else if self.token == token::OpenDelim(token::Paren) {
248             ast::MetaItemKind::List(self.parse_meta_seq()?)
249         } else {
250             self.eat(&token::OpenDelim(token::Paren));
251             ast::MetaItemKind::Word
252         })
253     }
254
255     /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
256     fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
257         let lo = self.span;
258
259         match self.parse_unsuffixed_lit() {
260             Ok(lit) => {
261                 return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit)))
262             }
263             Err(ref mut err) => self.diagnostic().cancel(err)
264         }
265
266         match self.parse_meta_item() {
267             Ok(mi) => {
268                 return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi)))
269             }
270             Err(ref mut err) => self.diagnostic().cancel(err)
271         }
272
273         let found = self.this_token_to_string();
274         let msg = format!("expected unsuffixed literal or identifier, found {}", found);
275         Err(self.diagnostic().struct_span_err(lo, &msg))
276     }
277
278     /// matches meta_seq = ( COMMASEP(meta_item_inner) )
279     fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
280         self.parse_unspanned_seq(&token::OpenDelim(token::Paren),
281                                  &token::CloseDelim(token::Paren),
282                                  SeqSep::trailing_allowed(token::Comma),
283                                  |p: &mut Parser<'a>| p.parse_meta_item_inner())
284     }
285 }