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