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