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.
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.
14 use parse
::common
::SeqSep
;
16 use parse
::token
::{self, Nonterminal}
;
17 use parse
::parser
::{Parser, TokenType, PathStyle}
;
18 use tokenstream
::TokenStream
;
20 #[derive(PartialEq, Eq, Debug)]
21 enum InnerAttributeParsePolicy
<'a
> {
23 NotPermitted { reason: &'a str }
,
26 const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
: &'
static str = "an inner attribute is not \
27 permitted in this context";
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;
35 debug
!("parse_outer_attributes: self.token={:?}", self.token
);
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"
43 DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
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;
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");
60 just_parsed_doc_comment
= true;
68 /// Matches `attribute = # ! [ meta_item ]`
70 /// If permit_inner is true, then a leading `!` indicates an inner
72 pub fn parse_attribute(&mut self, permit_inner
: bool
) -> PResult
<'a
, ast
::Attribute
> {
73 debug
!("parse_attribute: permit_inner={:?} self.token={:?}",
76 let inner_parse_policy
= if permit_inner
{
77 InnerAttributeParsePolicy
::Permitted
79 InnerAttributeParsePolicy
::NotPermitted
80 { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
82 self.parse_attribute_with_inner_parse_policy(inner_parse_policy
)
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={:?}",
93 let (span
, path
, tokens
, mut style
) = match self.token
{
98 if inner_parse_policy
== InnerAttributeParsePolicy
::Permitted
{
99 self.expected_tokens
.push(TokenType
::Token(token
::Not
));
101 let style
= if self.token
== token
::Not
{
103 if let InnerAttributeParsePolicy
::NotPermitted { reason }
= inner_parse_policy
105 let span
= self.span
;
107 .struct_span_err(span
, reason
)
108 .note("inner attributes, like `#![no_std]`, annotate the item \
109 enclosing them, and are usually found at the beginning of \
110 source files. Outer attributes, like `#[test]`, annotate the \
111 item following them.")
114 ast
::AttrStyle
::Inner
116 ast
::AttrStyle
::Outer
119 self.expect(&token
::OpenDelim(token
::Bracket
))?
;
120 let (path
, tokens
) = self.parse_path_and_tokens()?
;
121 self.expect(&token
::CloseDelim(token
::Bracket
))?
;
122 let hi
= self.prev_span
;
124 (lo
.to(hi
), path
, tokens
, style
)
127 let token_str
= self.this_token_to_string();
128 return Err(self.fatal(&format
!("expected `#`, found `{}`", token_str
)));
132 if inner_parse_policy
== InnerAttributeParsePolicy
::Permitted
&&
133 self.token
== token
::Semi
{
136 "this inner attribute syntax is deprecated. The new syntax is \
137 `#![foo]`, with a bang and no semicolon");
138 style
= ast
::AttrStyle
::Inner
;
142 id
: attr
::mk_attr_id(),
146 is_sugared_doc
: false,
151 pub fn parse_path_and_tokens(&mut self) -> PResult
<'a
, (ast
::Path
, TokenStream
)> {
152 let meta
= match self.token
{
153 token
::Interpolated(ref nt
) => match nt
.0 {
154 Nonterminal
::NtMeta(ref meta
) => Some(meta
.clone()),
159 Ok(if let Some(meta
) = meta
{
161 (ast
::Path
::from_ident(meta
.span
, ast
::Ident
::with_empty_ctxt(meta
.name
)),
162 meta
.node
.tokens(meta
.span
))
164 (self.parse_path(PathStyle
::Mod
)?
, self.parse_tokens())
168 /// Parse attributes that appear after the opening of an item. These should
169 /// be preceded by an exclamation mark, but we accept and warn about one
170 /// terminated by a semicolon.
172 /// matches inner_attrs*
173 pub fn parse_inner_attributes(&mut self) -> PResult
<'a
, Vec
<ast
::Attribute
>> {
174 let mut attrs
: Vec
<ast
::Attribute
> = vec
![];
178 // Don't even try to parse if it's not an inner attribute.
179 if !self.look_ahead(1, |t
| t
== &token
::Not
) {
183 let attr
= self.parse_attribute(true)?
;
184 assert_eq
!(attr
.style
, ast
::AttrStyle
::Inner
);
187 token
::DocComment(s
) => {
188 // we need to get the position of this token before we bump.
189 let attr
= attr
::mk_sugared_doc_attr(attr
::mk_attr_id(), s
, self.span
);
190 if attr
.style
== ast
::AttrStyle
::Inner
{
203 fn parse_unsuffixed_lit(&mut self) -> PResult
<'a
, ast
::Lit
> {
204 let lit
= self.parse_lit()?
;
205 debug
!("Checking if {:?} is unusuffixed.", lit
);
207 if !lit
.node
.is_unsuffixed() {
208 let msg
= "suffixed literals are not allowed in attributes";
209 self.diagnostic().struct_span_err(lit
.span
, msg
)
210 .help("instead of using a suffixed literal \
211 (1u8, 1.0f32, etc.), use an unsuffixed version \
219 /// Per RFC#1559, matches the following grammar:
221 /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
222 /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
223 pub fn parse_meta_item(&mut self) -> PResult
<'a
, ast
::MetaItem
> {
224 let nt_meta
= match self.token
{
225 token
::Interpolated(ref nt
) => match nt
.0 {
226 token
::NtMeta(ref e
) => Some(e
.clone()),
232 if let Some(meta
) = nt_meta
{
238 let ident
= self.parse_ident()?
;
239 let node
= self.parse_meta_item_kind()?
;
240 Ok(ast
::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) }
)
243 pub fn parse_meta_item_kind(&mut self) -> PResult
<'a
, ast
::MetaItemKind
> {
244 Ok(if self.eat(&token
::Eq
) {
245 ast
::MetaItemKind
::NameValue(self.parse_unsuffixed_lit()?
)
246 } else if self.eat(&token
::OpenDelim(token
::Paren
)) {
247 ast
::MetaItemKind
::List(self.parse_meta_seq()?
)
249 ast
::MetaItemKind
::Word
253 /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
254 fn parse_meta_item_inner(&mut self) -> PResult
<'a
, ast
::NestedMetaItem
> {
257 match self.parse_unsuffixed_lit() {
259 return Ok(respan(lo
.to(self.prev_span
), ast
::NestedMetaItemKind
::Literal(lit
)))
261 Err(ref mut err
) => self.diagnostic().cancel(err
)
264 match self.parse_meta_item() {
266 return Ok(respan(lo
.to(self.prev_span
), ast
::NestedMetaItemKind
::MetaItem(mi
)))
268 Err(ref mut err
) => self.diagnostic().cancel(err
)
271 let found
= self.this_token_to_string();
272 let msg
= format
!("expected unsuffixed literal or identifier, found {}", found
);
273 Err(self.diagnostic().struct_span_err(lo
, &msg
))
276 /// matches meta_seq = ( COMMASEP(meta_item_inner) )
277 fn parse_meta_seq(&mut self) -> PResult
<'a
, Vec
<ast
::NestedMetaItem
>> {
278 self.parse_seq_to_end(&token
::CloseDelim(token
::Paren
),
279 SeqSep
::trailing_allowed(token
::Comma
),
280 |p
: &mut Parser
<'a
>| p
.parse_meta_item_inner())