]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/parse/attr.rs
Imported Upstream version 1.10.0+dfsg1
[rustc.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::SeqSep;
15 use parse::PResult;
16 use parse::token;
17 use parse::parser::{Parser, TokenType};
18 use ptr::P;
19
20 impl<'a> Parser<'a> {
21 /// Parse attributes that appear before an item
22 pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
23 let mut attrs: Vec<ast::Attribute> = Vec::new();
24 loop {
25 debug!("parse_outer_attributes: self.token={:?}", self.token);
26 match self.token {
27 token::Pound => {
28 attrs.push(self.parse_attribute(false)?);
29 }
30 token::DocComment(s) => {
31 let attr = ::attr::mk_sugared_doc_attr(
32 attr::mk_attr_id(),
33 self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)),
34 self.span.lo,
35 self.span.hi
36 );
37 if attr.node.style != ast::AttrStyle::Outer {
38 let mut err = self.fatal("expected outer doc comment");
39 err.note("inner doc comments like this (starting with \
40 `//!` or `/*!`) can only appear before items");
41 return Err(err);
42 }
43 attrs.push(attr);
44 self.bump();
45 }
46 _ => break,
47 }
48 }
49 return Ok(attrs);
50 }
51
52 /// Matches `attribute = # ! [ meta_item ]`
53 ///
54 /// If permit_inner is true, then a leading `!` indicates an inner
55 /// attribute
56 pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
57 debug!("parse_attributes: permit_inner={:?} self.token={:?}",
58 permit_inner,
59 self.token);
60 let (span, value, mut style) = match self.token {
61 token::Pound => {
62 let lo = self.span.lo;
63 self.bump();
64
65 if permit_inner {
66 self.expected_tokens.push(TokenType::Token(token::Not));
67 }
68 let style = if self.token == token::Not {
69 self.bump();
70 if !permit_inner {
71 let span = self.span;
72 self.diagnostic()
73 .struct_span_err(span,
74 "an inner attribute is not permitted in this context")
75 .help("place inner attribute at the top of the module or \
76 block")
77 .emit()
78 }
79 ast::AttrStyle::Inner
80 } else {
81 ast::AttrStyle::Outer
82 };
83
84 self.expect(&token::OpenDelim(token::Bracket))?;
85 let meta_item = self.parse_meta_item()?;
86 let hi = self.span.hi;
87 self.expect(&token::CloseDelim(token::Bracket))?;
88
89 (mk_sp(lo, hi), meta_item, style)
90 }
91 _ => {
92 let token_str = self.this_token_to_string();
93 return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
94 }
95 };
96
97 if permit_inner && self.token == token::Semi {
98 self.bump();
99 self.span_warn(span,
100 "this inner attribute syntax is deprecated. The new syntax is \
101 `#![foo]`, with a bang and no semicolon");
102 style = ast::AttrStyle::Inner;
103 }
104
105 Ok(Spanned {
106 span: span,
107 node: ast::Attribute_ {
108 id: attr::mk_attr_id(),
109 style: style,
110 value: value,
111 is_sugared_doc: false,
112 },
113 })
114 }
115
116 /// Parse attributes that appear after the opening of an item. These should
117 /// be preceded by an exclamation mark, but we accept and warn about one
118 /// terminated by a semicolon.
119
120 /// matches inner_attrs*
121 pub fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
122 let mut attrs: Vec<ast::Attribute> = vec![];
123 loop {
124 match self.token {
125 token::Pound => {
126 // Don't even try to parse if it's not an inner attribute.
127 if !self.look_ahead(1, |t| t == &token::Not) {
128 break;
129 }
130
131 let attr = self.parse_attribute(true)?;
132 assert!(attr.node.style == ast::AttrStyle::Inner);
133 attrs.push(attr);
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 let str = self.id_to_interned_str(ast::Ident::with_empty_ctxt(s));
139 let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), str, lo, hi);
140 if attr.node.style == ast::AttrStyle::Inner {
141 attrs.push(attr);
142 self.bump();
143 } else {
144 break;
145 }
146 }
147 _ => break,
148 }
149 }
150 Ok(attrs)
151 }
152
153 /// matches meta_item = IDENT
154 /// | IDENT = lit
155 /// | IDENT meta_seq
156 pub fn parse_meta_item(&mut self) -> PResult<'a, P<ast::MetaItem>> {
157 let nt_meta = match self.token {
158 token::Interpolated(token::NtMeta(ref e)) => Some(e.clone()),
159 _ => None,
160 };
161
162 match nt_meta {
163 Some(meta) => {
164 self.bump();
165 return Ok(meta);
166 }
167 None => {}
168 }
169
170 let lo = self.span.lo;
171 let ident = self.parse_ident()?;
172 let name = self.id_to_interned_str(ident);
173 match self.token {
174 token::Eq => {
175 self.bump();
176 let lit = self.parse_lit()?;
177 // FIXME #623 Non-string meta items are not serialized correctly;
178 // just forbid them for now
179 match lit.node {
180 ast::LitKind::Str(..) => {}
181 _ => {
182 self.span_err(lit.span,
183 "non-string literals are not allowed in meta-items");
184 }
185 }
186 let hi = self.span.hi;
187 Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit))))
188 }
189 token::OpenDelim(token::Paren) => {
190 let inner_items = self.parse_meta_seq()?;
191 let hi = self.span.hi;
192 Ok(P(spanned(lo, hi, ast::MetaItemKind::List(name, inner_items))))
193 }
194 _ => {
195 let hi = self.last_span.hi;
196 Ok(P(spanned(lo, hi, ast::MetaItemKind::Word(name))))
197 }
198 }
199 }
200
201 /// matches meta_seq = ( COMMASEP(meta_item) )
202 fn parse_meta_seq(&mut self) -> PResult<'a, Vec<P<ast::MetaItem>>> {
203 self.parse_unspanned_seq(&token::OpenDelim(token::Paren),
204 &token::CloseDelim(token::Paren),
205 SeqSep::trailing_allowed(token::Comma),
206 |p: &mut Parser<'a>| p.parse_meta_item())
207 }
208 }