2012-12-03 16:48:01 -08:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-05-20 00:07:24 -07:00
|
|
|
use attr;
|
2012-12-23 17:41:37 -05:00
|
|
|
use ast;
|
2014-05-22 22:55:48 +10:00
|
|
|
use codemap::{spanned, Spanned, mk_sp, Span};
|
2012-12-13 13:05:22 -08:00
|
|
|
use parse::common::*; //resolve bug?
|
2012-12-23 17:41:37 -05:00
|
|
|
use parse::token;
|
2013-02-25 14:11:21 -05:00
|
|
|
use parse::parser::Parser;
|
2013-08-08 13:28:06 -04:00
|
|
|
use parse::token::INTERPOLATED;
|
2012-12-23 17:41:37 -05:00
|
|
|
|
2014-05-16 00:16:13 -07:00
|
|
|
use std::gc::Gc;
|
|
|
|
|
2013-02-11 13:36:24 -08:00
|
|
|
// a parser that can parse attributes.
|
2014-01-09 15:05:33 +02:00
|
|
|
pub trait ParserAttr {
|
2014-05-16 00:16:13 -07:00
|
|
|
fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute>;
|
2013-12-30 14:04:00 -08:00
|
|
|
fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
|
|
|
|
fn parse_inner_attrs_and_next(&mut self)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> (Vec<ast::Attribute>, Vec<ast::Attribute>);
|
|
|
|
fn parse_meta_item(&mut self) -> Gc<ast::MetaItem>;
|
|
|
|
fn parse_meta_seq(&mut self) -> Vec<Gc<ast::MetaItem>>;
|
|
|
|
fn parse_optional_meta(&mut self) -> Vec<Gc<ast::MetaItem>>;
|
2012-07-11 15:00:40 -07:00
|
|
|
}
|
|
|
|
|
2014-03-09 16:54:34 +02:00
|
|
|
impl<'a> ParserAttr for Parser<'a> {
|
2012-05-24 13:44:42 -07:00
|
|
|
// Parse attributes that appear before an item
|
2014-02-28 13:09:09 -08:00
|
|
|
fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> {
|
|
|
|
let mut attrs: Vec<ast::Attribute> = Vec::new();
|
2012-06-30 11:54:54 +01:00
|
|
|
loop {
|
2013-10-21 13:08:31 -07:00
|
|
|
debug!("parse_outer_attributes: self.token={:?}",
|
2013-08-08 13:28:06 -04:00
|
|
|
self.token);
|
2013-12-30 15:09:41 -08:00
|
|
|
match self.token {
|
2012-08-03 19:59:04 -07:00
|
|
|
token::POUND => {
|
2013-08-08 13:28:06 -04:00
|
|
|
attrs.push(self.parse_attribute(false));
|
2012-06-30 11:54:54 +01:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
token::DOC_COMMENT(s) => {
|
2012-06-30 11:54:54 +01:00
|
|
|
let attr = ::attr::mk_sugared_doc_attr(
|
2014-05-20 00:07:24 -07:00
|
|
|
attr::mk_attr_id(),
|
2014-01-10 14:02:36 -08:00
|
|
|
self.id_to_interned_str(s),
|
2013-02-26 06:35:36 -08:00
|
|
|
self.span.lo,
|
|
|
|
self.span.hi
|
|
|
|
);
|
2013-07-19 21:51:37 +10:00
|
|
|
if attr.node.style != ast::AttrOuter {
|
2013-05-19 01:07:44 -04:00
|
|
|
self.fatal("expected outer comment");
|
2012-06-30 11:54:54 +01:00
|
|
|
}
|
2013-06-11 19:13:42 -07:00
|
|
|
attrs.push(attr);
|
2012-06-30 11:54:54 +01:00
|
|
|
self.bump();
|
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => break
|
2012-06-30 11:54:54 +01:00
|
|
|
}
|
2012-05-24 13:44:42 -07:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return attrs;
|
2012-04-19 20:51:31 -07:00
|
|
|
}
|
|
|
|
|
2014-03-20 11:21:17 -07:00
|
|
|
// matches attribute = # ! [ meta_item ]
|
2013-08-08 13:28:06 -04:00
|
|
|
//
|
2014-03-20 11:21:17 -07:00
|
|
|
// if permit_inner is true, then a leading `!` indicates an inner
|
2013-08-08 13:28:06 -04:00
|
|
|
// attribute
|
2013-12-30 14:04:00 -08:00
|
|
|
fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
|
2013-10-21 13:08:31 -07:00
|
|
|
debug!("parse_attributes: permit_inner={:?} self.token={:?}",
|
2013-08-08 13:28:06 -04:00
|
|
|
permit_inner, self.token);
|
2014-03-20 11:21:17 -07:00
|
|
|
let (span, value, mut style) = match self.token {
|
2013-08-08 13:28:06 -04:00
|
|
|
token::POUND => {
|
|
|
|
let lo = self.span.lo;
|
|
|
|
self.bump();
|
2014-02-24 19:42:40 -07:00
|
|
|
|
2014-03-20 11:21:17 -07:00
|
|
|
let style = if self.eat(&token::NOT) {
|
2014-02-24 19:42:40 -07:00
|
|
|
if !permit_inner {
|
2014-03-20 11:21:17 -07:00
|
|
|
self.span_err(self.span,
|
|
|
|
"an inner attribute is not permitted in \
|
|
|
|
this context");
|
2014-02-24 19:42:40 -07:00
|
|
|
}
|
2014-03-20 11:21:17 -07:00
|
|
|
ast::AttrInner
|
2014-02-24 19:42:40 -07:00
|
|
|
} else {
|
2014-03-20 11:21:17 -07:00
|
|
|
ast::AttrOuter
|
|
|
|
};
|
2014-02-24 19:42:40 -07:00
|
|
|
|
2013-08-08 13:28:06 -04:00
|
|
|
self.expect(&token::LBRACKET);
|
|
|
|
let meta_item = self.parse_meta_item();
|
|
|
|
self.expect(&token::RBRACKET);
|
2014-02-24 19:42:40 -07:00
|
|
|
|
2013-08-08 13:28:06 -04:00
|
|
|
let hi = self.span.hi;
|
2014-03-20 11:21:17 -07:00
|
|
|
(mk_sp(lo, hi), meta_item, style)
|
2013-08-08 13:28:06 -04:00
|
|
|
}
|
2014-05-28 09:24:28 -07:00
|
|
|
#[cfg(stage0)]
|
2013-08-08 13:28:06 -04:00
|
|
|
_ => {
|
2013-12-30 14:04:00 -08:00
|
|
|
let token_str = self.this_token_to_str();
|
2013-09-27 21:01:58 -07:00
|
|
|
self.fatal(format!("expected `\\#` but found `{}`",
|
2014-05-16 10:45:16 -07:00
|
|
|
token_str).as_slice());
|
2013-08-08 13:28:06 -04:00
|
|
|
}
|
2014-05-28 09:24:28 -07:00
|
|
|
#[cfg(not(stage0))]
|
|
|
|
_ => {
|
|
|
|
let token_str = self.this_token_to_str();
|
|
|
|
self.fatal(format!("expected `#` but found `{}`",
|
|
|
|
token_str).as_slice());
|
|
|
|
}
|
2013-08-08 13:28:06 -04:00
|
|
|
};
|
2014-02-24 19:42:40 -07:00
|
|
|
|
2014-03-20 11:21:17 -07:00
|
|
|
if permit_inner && self.eat(&token::SEMI) {
|
2014-03-21 18:05:05 -07:00
|
|
|
self.span_warn(span, "this inner attribute syntax is deprecated. \
|
|
|
|
The new syntax is `#![foo]`, with a bang and no semicolon.");
|
2014-03-20 11:21:17 -07:00
|
|
|
style = ast::AttrInner;
|
|
|
|
}
|
2014-02-24 19:42:40 -07:00
|
|
|
|
2013-08-31 18:13:04 +02:00
|
|
|
return Spanned {
|
2013-08-08 13:28:06 -04:00
|
|
|
span: span,
|
|
|
|
node: ast::Attribute_ {
|
2014-05-20 00:07:24 -07:00
|
|
|
id: attr::mk_attr_id(),
|
2013-08-08 13:28:06 -04:00
|
|
|
style: style,
|
|
|
|
value: value,
|
|
|
|
is_sugared_doc: false
|
|
|
|
}
|
|
|
|
};
|
2012-05-24 13:44:42 -07:00
|
|
|
}
|
2012-04-19 20:51:31 -07:00
|
|
|
|
2014-05-03 21:24:06 +01:00
|
|
|
// Parse attributes that appear after the opening of an item. These should
|
2014-06-09 00:00:52 -04:00
|
|
|
// be preceded by an exclamation mark, but we accept and warn about one
|
2012-05-24 13:44:42 -07:00
|
|
|
// terminated by a semicolon. In addition to a vector of inner attributes,
|
|
|
|
// this function also returns a vector that may contain the first outer
|
|
|
|
// attribute of the next item (since we can't know whether the attribute
|
|
|
|
// is an inner attribute of the containing item or an outer attribute of
|
|
|
|
// the first contained item until we see the semi).
|
2013-02-11 13:36:24 -08:00
|
|
|
|
2013-03-29 12:51:10 -07:00
|
|
|
// matches inner_attrs* outer_attr?
|
2013-02-11 13:36:24 -08:00
|
|
|
// you can make the 'next' field an Option, but the result is going to be
|
|
|
|
// more useful as a vector.
|
2013-12-30 14:04:00 -08:00
|
|
|
fn parse_inner_attrs_and_next(&mut self)
|
2014-02-28 13:09:09 -08:00
|
|
|
-> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
|
|
|
|
let mut inner_attrs: Vec<ast::Attribute> = Vec::new();
|
|
|
|
let mut next_outer_attrs: Vec<ast::Attribute> = Vec::new();
|
2012-06-30 11:54:54 +01:00
|
|
|
loop {
|
2013-12-30 15:09:41 -08:00
|
|
|
let attr = match self.token {
|
2013-08-08 13:28:06 -04:00
|
|
|
token::POUND => {
|
|
|
|
self.parse_attribute(true)
|
|
|
|
}
|
|
|
|
token::DOC_COMMENT(s) => {
|
2014-05-22 22:55:48 +10:00
|
|
|
// we need to get the position of this token before we bump.
|
|
|
|
let Span { lo, hi, .. } = self.span;
|
2012-06-30 11:54:54 +01:00
|
|
|
self.bump();
|
2014-05-23 08:39:26 -07:00
|
|
|
attr::mk_sugared_doc_attr(attr::mk_attr_id(),
|
|
|
|
self.id_to_interned_str(s),
|
|
|
|
lo,
|
|
|
|
hi)
|
2012-06-30 11:54:54 +01:00
|
|
|
}
|
2013-08-08 13:28:06 -04:00
|
|
|
_ => {
|
|
|
|
break;
|
2012-06-30 11:54:54 +01:00
|
|
|
}
|
2013-08-08 13:28:06 -04:00
|
|
|
};
|
|
|
|
if attr.node.style == ast::AttrInner {
|
|
|
|
inner_attrs.push(attr);
|
|
|
|
} else {
|
|
|
|
next_outer_attrs.push(attr);
|
|
|
|
break;
|
2012-05-24 13:44:42 -07:00
|
|
|
}
|
2012-04-19 20:51:31 -07:00
|
|
|
}
|
2013-02-21 00:16:31 -08:00
|
|
|
(inner_attrs, next_outer_attrs)
|
2012-05-24 13:44:42 -07:00
|
|
|
}
|
|
|
|
|
2013-03-29 12:51:10 -07:00
|
|
|
// matches meta_item = IDENT
|
|
|
|
// | IDENT = lit
|
|
|
|
// | IDENT meta_seq
|
2014-05-16 00:16:13 -07:00
|
|
|
fn parse_meta_item(&mut self) -> Gc<ast::MetaItem> {
|
2014-03-26 16:14:07 -07:00
|
|
|
match self.token {
|
|
|
|
token::INTERPOLATED(token::NtMeta(e)) => {
|
|
|
|
self.bump();
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2012-05-24 13:44:42 -07:00
|
|
|
let lo = self.span.lo;
|
2013-12-30 14:04:00 -08:00
|
|
|
let ident = self.parse_ident();
|
2014-01-08 10:35:15 -08:00
|
|
|
let name = self.id_to_interned_str(ident);
|
2013-12-30 15:09:41 -08:00
|
|
|
match self.token {
|
2013-02-14 07:34:21 -08:00
|
|
|
token::EQ => {
|
|
|
|
self.bump();
|
|
|
|
let lit = self.parse_lit();
|
2013-10-29 17:47:11 -07:00
|
|
|
// FIXME #623 Non-string meta items are not serialized correctly;
|
|
|
|
// just forbid them for now
|
|
|
|
match lit.node {
|
2014-01-09 15:05:33 +02:00
|
|
|
ast::LitStr(..) => {}
|
2013-10-29 17:47:11 -07:00
|
|
|
_ => {
|
|
|
|
self.span_err(
|
|
|
|
lit.span,
|
|
|
|
"non-string literals are not allowed in meta-items");
|
|
|
|
}
|
|
|
|
}
|
2013-04-12 01:10:31 -04:00
|
|
|
let hi = self.span.hi;
|
2014-05-16 00:16:13 -07:00
|
|
|
box(GC) spanned(lo, hi, ast::MetaNameValue(name, lit))
|
2013-02-14 07:34:21 -08:00
|
|
|
}
|
|
|
|
token::LPAREN => {
|
|
|
|
let inner_items = self.parse_meta_seq();
|
2013-04-12 01:10:31 -04:00
|
|
|
let hi = self.span.hi;
|
2014-05-16 00:16:13 -07:00
|
|
|
box(GC) spanned(lo, hi, ast::MetaList(name, inner_items))
|
2013-02-14 07:34:21 -08:00
|
|
|
}
|
|
|
|
_ => {
|
2013-05-03 02:36:24 +09:00
|
|
|
let hi = self.last_span.hi;
|
2014-05-16 00:16:13 -07:00
|
|
|
box(GC) spanned(lo, hi, ast::MetaWord(name))
|
2013-02-14 07:34:21 -08:00
|
|
|
}
|
2012-04-19 20:51:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-29 12:51:10 -07:00
|
|
|
// matches meta_seq = ( COMMASEP(meta_item) )
|
2014-05-16 00:16:13 -07:00
|
|
|
fn parse_meta_seq(&mut self) -> Vec<Gc<ast::MetaItem>> {
|
2013-07-02 12:47:32 -07:00
|
|
|
self.parse_seq(&token::LPAREN,
|
|
|
|
&token::RPAREN,
|
|
|
|
seq_sep_trailing_disallowed(token::COMMA),
|
|
|
|
|p| p.parse_meta_item()).node
|
2012-04-19 20:51:31 -07:00
|
|
|
}
|
|
|
|
|
2014-05-16 00:16:13 -07:00
|
|
|
fn parse_optional_meta(&mut self) -> Vec<Gc<ast::MetaItem>> {
|
2013-12-30 15:09:41 -08:00
|
|
|
match self.token {
|
2013-02-24 20:51:56 -08:00
|
|
|
token::LPAREN => self.parse_meta_seq(),
|
2014-02-28 13:09:09 -08:00
|
|
|
_ => Vec::new()
|
2012-08-03 19:59:04 -07:00
|
|
|
}
|
2012-05-24 13:44:42 -07:00
|
|
|
}
|
2012-04-19 20:51:31 -07:00
|
|
|
}
|