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 ast;
12 use codemap::{spanned, Spanned, mk_sp};
13 use parse::common::*; //resolve bug?
14 use parse::token;
15 use parse::parser::Parser;
16 use parse::token::INTERPOLATED;
17
18 // a parser that can parse attributes.
19 pub trait ParserAttr {
20 fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> ;
21 fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
22 fn parse_inner_attrs_and_next(&mut self)
23 -> (Vec<ast::Attribute> , Vec<ast::Attribute> );
24 fn parse_meta_item(&mut self) -> @ast::MetaItem;
25 fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> ;
26 fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> ;
27 }
28
29 impl<'a> ParserAttr for Parser<'a> {
30 // Parse attributes that appear before an item
31 fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> {
32 let mut attrs: Vec<ast::Attribute> = Vec::new();
33 loop {
34 debug!("parse_outer_attributes: self.token={:?}",
35 self.token);
36 match self.token {
37 token::POUND => {
38 attrs.push(self.parse_attribute(false));
39 }
40 token::DOC_COMMENT(s) => {
41 let attr = ::attr::mk_sugared_doc_attr(
42 self.id_to_interned_str(s),
43 self.span.lo,
44 self.span.hi
45 );
46 if attr.node.style != ast::AttrOuter {
47 self.fatal("expected outer comment");
48 }
49 attrs.push(attr);
50 self.bump();
51 }
52 _ => break
53 }
54 }
55 return attrs;
56 }
57
58 // matches attribute = # ! [ meta_item ]
59 //
60 // if permit_inner is true, then a leading `!` indicates an inner
61 // attribute
62 fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
63 debug!("parse_attributes: permit_inner={:?} self.token={:?}",
64 permit_inner, self.token);
65 let (span, value, mut style) = match self.token {
66 token::POUND => {
67 let lo = self.span.lo;
68 self.bump();
69
70 let style = if self.eat(&token::NOT) {
71 if !permit_inner {
72 self.span_err(self.span,
73 "an inner attribute is not permitted in \
74 this context");
75 }
76 ast::AttrInner
77 } else {
78 ast::AttrOuter
79 };
80
81 self.expect(&token::LBRACKET);
82 let meta_item = self.parse_meta_item();
83 self.expect(&token::RBRACKET);
84
85 let hi = self.span.hi;
86 (mk_sp(lo, hi), meta_item, style)
87 }
88 _ => {
89 let token_str = self.this_token_to_str();
90 self.fatal(format!("expected `\\#` but found `{}`",
91 token_str));
92 }
93 };
94
95 if permit_inner && self.eat(&token::SEMI) {
96 self.span_warn(span, "this inner attribute syntax is deprecated. \
97 The new syntax is `#![foo]`, with a bang and no semicolon.");
98 style = ast::AttrInner;
99 }
100
101 return Spanned {
102 span: span,
103 node: ast::Attribute_ {
104 style: style,
105 value: value,
106 is_sugared_doc: false
107 }
108 };
109 }
110
111 // Parse attributes that appear after the opening of an item. These should
112 // be preceded by an exclaimation mark, but we accept and warn about one
113 // terminated by a semicolon. In addition to a vector of inner attributes,
114 // this function also returns a vector that may contain the first outer
115 // attribute of the next item (since we can't know whether the attribute
116 // is an inner attribute of the containing item or an outer attribute of
117 // the first contained item until we see the semi).
118
119 // matches inner_attrs* outer_attr?
120 // you can make the 'next' field an Option, but the result is going to be
121 // more useful as a vector.
122 fn parse_inner_attrs_and_next(&mut self)
123 -> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
124 let mut inner_attrs: Vec<ast::Attribute> = Vec::new();
125 let mut next_outer_attrs: Vec<ast::Attribute> = Vec::new();
126 loop {
127 let attr = match self.token {
128 token::POUND => {
129 self.parse_attribute(true)
130 }
131 token::DOC_COMMENT(s) => {
132 self.bump();
133 ::attr::mk_sugared_doc_attr(self.id_to_interned_str(s),
134 self.span.lo,
135 self.span.hi)
136 }
137 _ => {
138 break;
139 }
140 };
141 if attr.node.style == ast::AttrInner {
142 inner_attrs.push(attr);
143 } else {
144 next_outer_attrs.push(attr);
145 break;
146 }
147 }
148 (inner_attrs, next_outer_attrs)
149 }
150
151 // matches meta_item = IDENT
152 // | IDENT = lit
153 // | IDENT meta_seq
154 fn parse_meta_item(&mut self) -> @ast::MetaItem {
155 match self.token {
156 token::INTERPOLATED(token::NtMeta(e)) => {
157 self.bump();
158 return e
159 }
160 _ => {}
161 }
162
163 let lo = self.span.lo;
164 let ident = self.parse_ident();
165 let name = self.id_to_interned_str(ident);
166 match self.token {
167 token::EQ => {
168 self.bump();
169 let lit = self.parse_lit();
170 // FIXME #623 Non-string meta items are not serialized correctly;
171 // just forbid them for now
172 match lit.node {
173 ast::LitStr(..) => {}
174 _ => {
175 self.span_err(
176 lit.span,
177 "non-string literals are not allowed in meta-items");
178 }
179 }
180 let hi = self.span.hi;
181 @spanned(lo, hi, ast::MetaNameValue(name, lit))
182 }
183 token::LPAREN => {
184 let inner_items = self.parse_meta_seq();
185 let hi = self.span.hi;
186 @spanned(lo, hi, ast::MetaList(name, inner_items))
187 }
188 _ => {
189 let hi = self.last_span.hi;
190 @spanned(lo, hi, ast::MetaWord(name))
191 }
192 }
193 }
194
195 // matches meta_seq = ( COMMASEP(meta_item) )
196 fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> {
197 self.parse_seq(&token::LPAREN,
198 &token::RPAREN,
199 seq_sep_trailing_disallowed(token::COMMA),
200 |p| p.parse_meta_item()).node
201 }
202
203 fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> {
204 match self.token {
205 token::LPAREN => self.parse_meta_seq(),
206 _ => Vec::new()
207 }
208 }
209 }