]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/attr.rs
rollup merge of #18407 : thestinger/arena
[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::{spanned, Spanned, mk_sp, Span};
14 use parse::common::*; //resolve bug?
15 use parse::token;
16 use parse::parser::Parser;
17 use ptr::P;
18
19 /// A parser that can parse attributes.
20 pub trait ParserAttr {
21     fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute>;
22     fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
23     fn parse_inner_attrs_and_next(&mut self)
24                                   -> (Vec<ast::Attribute>, Vec<ast::Attribute>);
25     fn parse_meta_item(&mut self) -> P<ast::MetaItem>;
26     fn parse_meta_seq(&mut self) -> Vec<P<ast::MetaItem>>;
27     fn parse_optional_meta(&mut self) -> Vec<P<ast::MetaItem>>;
28 }
29
30 impl<'a> ParserAttr for Parser<'a> {
31     /// Parse attributes that appear before an item
32     fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> {
33         let mut attrs: Vec<ast::Attribute> = Vec::new();
34         loop {
35             debug!("parse_outer_attributes: self.token={}",
36                    self.token);
37             match self.token {
38               token::Pound => {
39                 attrs.push(self.parse_attribute(false));
40               }
41               token::DocComment(s) => {
42                 let attr = ::attr::mk_sugared_doc_attr(
43                     attr::mk_attr_id(),
44                     self.id_to_interned_str(s.ident()),
45                     self.span.lo,
46                     self.span.hi
47                 );
48                 if attr.node.style != ast::AttrOuter {
49                   self.fatal("expected outer comment");
50                 }
51                 attrs.push(attr);
52                 self.bump();
53               }
54               _ => break
55             }
56         }
57         return attrs;
58     }
59
60     /// Matches `attribute = # ! [ meta_item ]`
61     ///
62     /// If permit_inner is true, then a leading `!` indicates an inner
63     /// attribute
64     fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
65         debug!("parse_attributes: permit_inner={} self.token={}",
66                permit_inner, self.token);
67         let (span, value, mut style) = match self.token {
68             token::Pound => {
69                 let lo = self.span.lo;
70                 self.bump();
71
72                 let style = if self.eat(&token::Not) {
73                     if !permit_inner {
74                         let span = self.span;
75                         self.span_err(span,
76                                       "an inner attribute is not permitted in \
77                                        this context");
78                     }
79                     ast::AttrInner
80                 } else {
81                     ast::AttrOuter
82                 };
83
84                 self.expect(&token::LBracket);
85                 let meta_item = self.parse_meta_item();
86                 let hi = self.span.hi;
87                 self.expect(&token::RBracket);
88
89                 (mk_sp(lo, hi), meta_item, style)
90             }
91             _ => {
92                 let token_str = self.this_token_to_string();
93                 self.fatal(format!("expected `#`, found `{}`",
94                                    token_str).as_slice());
95             }
96         };
97
98         if permit_inner && self.eat(&token::Semi) {
99             self.span_warn(span, "this inner attribute syntax is deprecated. \
100                            The new syntax is `#![foo]`, with a bang and no semicolon.");
101             style = ast::AttrInner;
102         }
103
104         return Spanned {
105             span: span,
106             node: ast::Attribute_ {
107                 id: attr::mk_attr_id(),
108                 style: style,
109                 value: value,
110                 is_sugared_doc: false
111             }
112         };
113     }
114
115     /// Parse attributes that appear after the opening of an item. These should
116     /// be preceded by an exclamation mark, but we accept and warn about one
117     /// terminated by a semicolon. In addition to a vector of inner attributes,
118     /// this function also returns a vector that may contain the first outer
119     /// attribute of the next item (since we can't know whether the attribute
120     /// is an inner attribute of the containing item or an outer attribute of
121     /// the first contained item until we see the semi).
122
123     /// matches inner_attrs* outer_attr?
124     /// you can make the 'next' field an Option, but the result is going to be
125     /// more useful as a vector.
126     fn parse_inner_attrs_and_next(&mut self)
127                                   -> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
128         let mut inner_attrs: Vec<ast::Attribute> = Vec::new();
129         let mut next_outer_attrs: Vec<ast::Attribute> = Vec::new();
130         loop {
131             let attr = match self.token {
132                 token::Pound => {
133                     self.parse_attribute(true)
134                 }
135                 token::DocComment(s) => {
136                     // we need to get the position of this token before we bump.
137                     let Span { lo, hi, .. } = self.span;
138                     self.bump();
139                     attr::mk_sugared_doc_attr(attr::mk_attr_id(),
140                                               self.id_to_interned_str(s.ident()),
141                                               lo,
142                                               hi)
143                 }
144                 _ => {
145                     break;
146                 }
147             };
148             if attr.node.style == ast::AttrInner {
149                 inner_attrs.push(attr);
150             } else {
151                 next_outer_attrs.push(attr);
152                 break;
153             }
154         }
155         (inner_attrs, next_outer_attrs)
156     }
157
158     /// matches meta_item = IDENT
159     /// | IDENT = lit
160     /// | IDENT meta_seq
161     fn parse_meta_item(&mut self) -> P<ast::MetaItem> {
162         let nt_meta = match self.token {
163             token::Interpolated(token::NtMeta(ref e)) => {
164                 Some(e.clone())
165             }
166             _ => None
167         };
168
169         match nt_meta {
170             Some(meta) => {
171                 self.bump();
172                 return meta;
173             }
174             None => {}
175         }
176
177         let lo = self.span.lo;
178         let ident = self.parse_ident();
179         let name = self.id_to_interned_str(ident);
180         match self.token {
181             token::Eq => {
182                 self.bump();
183                 let lit = self.parse_lit();
184                 // FIXME #623 Non-string meta items are not serialized correctly;
185                 // just forbid them for now
186                 match lit.node {
187                     ast::LitStr(..) => {}
188                     _ => {
189                         self.span_err(
190                             lit.span,
191                             "non-string literals are not allowed in meta-items");
192                     }
193                 }
194                 let hi = self.span.hi;
195                 P(spanned(lo, hi, ast::MetaNameValue(name, lit)))
196             }
197             token::LParen => {
198                 let inner_items = self.parse_meta_seq();
199                 let hi = self.span.hi;
200                 P(spanned(lo, hi, ast::MetaList(name, inner_items)))
201             }
202             _ => {
203                 let hi = self.last_span.hi;
204                 P(spanned(lo, hi, ast::MetaWord(name)))
205             }
206         }
207     }
208
209     /// matches meta_seq = ( COMMASEP(meta_item) )
210     fn parse_meta_seq(&mut self) -> Vec<P<ast::MetaItem>> {
211         self.parse_seq(&token::LParen,
212                        &token::RParen,
213                        seq_sep_trailing_disallowed(token::Comma),
214                        |p| p.parse_meta_item()).node
215     }
216
217     fn parse_optional_meta(&mut self) -> Vec<P<ast::MetaItem>> {
218         match self.token {
219             token::LParen => self.parse_meta_seq(),
220             _ => Vec::new()
221         }
222     }
223 }