]>
Commit | Line | Data |
---|---|---|
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 | 11 | use attr; |
223e47cc | 12 | use ast; |
1a4d82fc | 13 | use codemap::{spanned, Spanned, mk_sp, Span}; |
7453a54e | 14 | use parse::common::SeqSep; |
92a42be0 | 15 | use parse::PResult; |
223e47cc | 16 | use parse::token; |
85aaf69f | 17 | use parse::parser::{Parser, TokenType}; |
1a4d82fc | 18 | use ptr::P; |
223e47cc | 19 | |
92a42be0 | 20 | impl<'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 | } |