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.
13 use codemap::{spanned, Spanned, mk_sp, Span};
14 use parse::common::*; //resolve bug?
16 use parse::parser::Parser;
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>>;
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();
35 debug!("parse_outer_attributes: self.token={:?}",
39 attrs.push(self.parse_attribute(false));
41 token::DocComment(s) => {
42 let attr = ::attr::mk_sugared_doc_attr(
44 self.id_to_interned_str(s.ident()),
48 if attr.node.style != ast::AttrOuter {
49 self.fatal("expected outer comment");
60 /// Matches `attribute = # ! [ meta_item ]`
62 /// If permit_inner is true, then a leading `!` indicates an inner
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 {
69 let lo = self.span.lo;
72 let style = if self.eat(&token::Not) {
76 "an inner attribute is not permitted in \
79 "place inner attribute at the top of the module or block");
86 self.expect(&token::OpenDelim(token::Bracket));
87 let meta_item = self.parse_meta_item();
88 let hi = self.span.hi;
89 self.expect(&token::CloseDelim(token::Bracket));
91 (mk_sp(lo, hi), meta_item, style)
94 let token_str = self.this_token_to_string();
95 self.fatal(format!("expected `#`, found `{}`", token_str).index(&FullRange));
99 if permit_inner && self.eat(&token::Semi) {
100 self.span_warn(span, "this inner attribute syntax is deprecated. \
101 The new syntax is `#![foo]`, with a bang and no semicolon");
102 style = ast::AttrInner;
107 node: ast::Attribute_ {
108 id: attr::mk_attr_id(),
111 is_sugared_doc: false
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. In addition to a vector of inner attributes,
119 /// this function also returns a vector that may contain the first outer
120 /// attribute of the next item (since we can't know whether the attribute
121 /// is an inner attribute of the containing item or an outer attribute of
122 /// the first contained item until we see the semi).
124 /// matches inner_attrs* outer_attr?
125 /// you can make the 'next' field an Option, but the result is going to be
126 /// more useful as a vector.
127 fn parse_inner_attrs_and_next(&mut self)
128 -> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
129 let mut inner_attrs: Vec<ast::Attribute> = Vec::new();
130 let mut next_outer_attrs: Vec<ast::Attribute> = Vec::new();
132 let attr = match self.token {
134 self.parse_attribute(true)
136 token::DocComment(s) => {
137 // we need to get the position of this token before we bump.
138 let Span { lo, hi, .. } = self.span;
140 attr::mk_sugared_doc_attr(attr::mk_attr_id(),
141 self.id_to_interned_str(s.ident()),
149 if attr.node.style == ast::AttrInner {
150 inner_attrs.push(attr);
152 next_outer_attrs.push(attr);
156 (inner_attrs, next_outer_attrs)
159 /// matches meta_item = IDENT
162 fn parse_meta_item(&mut self) -> P<ast::MetaItem> {
163 let nt_meta = match self.token {
164 token::Interpolated(token::NtMeta(ref e)) => {
178 let lo = self.span.lo;
179 let ident = self.parse_ident();
180 let name = self.id_to_interned_str(ident);
184 let lit = self.parse_lit();
185 // FIXME #623 Non-string meta items are not serialized correctly;
186 // just forbid them for now
188 ast::LitStr(..) => {}
192 "non-string literals are not allowed in meta-items");
195 let hi = self.span.hi;
196 P(spanned(lo, hi, ast::MetaNameValue(name, lit)))
198 token::OpenDelim(token::Paren) => {
199 let inner_items = self.parse_meta_seq();
200 let hi = self.span.hi;
201 P(spanned(lo, hi, ast::MetaList(name, inner_items)))
204 let hi = self.last_span.hi;
205 P(spanned(lo, hi, ast::MetaWord(name)))
210 /// matches meta_seq = ( COMMASEP(meta_item) )
211 fn parse_meta_seq(&mut self) -> Vec<P<ast::MetaItem>> {
212 self.parse_seq(&token::OpenDelim(token::Paren),
213 &token::CloseDelim(token::Paren),
214 seq_sep_trailing_allowed(token::Comma),
215 |p| p.parse_meta_item()).node
218 fn parse_optional_meta(&mut self) -> Vec<P<ast::MetaItem>> {
220 token::OpenDelim(token::Paren) => self.parse_meta_seq(),