]>
Commit | Line | Data |
---|---|---|
92a42be0 SL |
1 | // Copyright 2015 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 | // ignore-cross-compile | |
12 | ||
13 | #![feature(rustc_private)] | |
14 | ||
15 | extern crate syntax; | |
16 | ||
17 | use syntax::ast::*; | |
18 | use syntax::attr::*; | |
19 | use syntax::ast; | |
20 | use syntax::parse; | |
21 | use syntax::parse::{ParseSess,filemap_to_tts, PResult}; | |
22 | use syntax::parse::new_parser_from_source_str; | |
23 | use syntax::parse::parser::Parser; | |
24 | use syntax::parse::token; | |
25 | use syntax::ptr::P; | |
26 | use syntax::str::char_at; | |
27 | use syntax::parse::attr::*; | |
28 | use syntax::print::pprust; | |
29 | use std::fmt; | |
30 | ||
31 | // Copied out of syntax::util::parser_testing | |
32 | ||
33 | pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> { | |
34 | new_parser_from_source_str(ps, | |
35 | Vec::new(), | |
36 | "bogofile".to_string(), | |
37 | source_str) | |
38 | } | |
39 | ||
9cc50fc6 SL |
40 | fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> PResult<'a, T> where |
41 | F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>, | |
92a42be0 | 42 | { |
92a42be0 SL |
43 | let mut p = string_to_parser(&ps, s); |
44 | let x = f(&mut p); | |
45 | ||
9cc50fc6 SL |
46 | if ps.span_diagnostic.has_errors() || p.token != token::Eof { |
47 | if let Err(mut e) = x { | |
48 | e.cancel(); | |
49 | } | |
92a42be0 SL |
50 | return Err(p.fatal("parse error")); |
51 | } | |
52 | ||
53 | x | |
54 | } | |
55 | ||
9cc50fc6 SL |
56 | fn expr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P<ast::Expr>> { |
57 | with_error_checking_parse(s.to_string(), ps, |p| { | |
92a42be0 SL |
58 | p.parse_expr() |
59 | }) | |
60 | } | |
61 | ||
9cc50fc6 SL |
62 | fn stmt<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P<ast::Stmt>> { |
63 | with_error_checking_parse(s.to_string(), ps, |p| { | |
92a42be0 SL |
64 | p.parse_stmt().map(|s| s.unwrap()) |
65 | }) | |
66 | } | |
67 | ||
9cc50fc6 SL |
68 | fn attr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, ast::Attribute> { |
69 | with_error_checking_parse(s.to_string(), ps, |p| { | |
92a42be0 SL |
70 | p.parse_attribute(true) |
71 | }) | |
72 | } | |
73 | ||
74 | fn str_compare<T, F: Fn(&T) -> String>(e: &str, expected: &[T], actual: &[T], f: F) { | |
75 | let expected: Vec<_> = expected.iter().map(|e| f(e)).collect(); | |
76 | let actual: Vec<_> = actual.iter().map(|e| f(e)).collect(); | |
77 | ||
78 | if expected != actual { | |
79 | panic!("parsed `{}` as {:?}, expected {:?}", e, actual, expected); | |
80 | } | |
81 | } | |
82 | ||
83 | fn check_expr_attrs(es: &str, expected: &[&str]) { | |
9cc50fc6 SL |
84 | let ps = ParseSess::new(); |
85 | let e = expr(es, &ps).expect("parse error"); | |
92a42be0 SL |
86 | let actual = &e.attrs; |
87 | str_compare(es, | |
9cc50fc6 | 88 | &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(), |
92a42be0 SL |
89 | actual.as_attr_slice(), |
90 | pprust::attribute_to_string); | |
91 | } | |
92 | ||
93 | fn check_stmt_attrs(es: &str, expected: &[&str]) { | |
9cc50fc6 SL |
94 | let ps = ParseSess::new(); |
95 | let e = stmt(es, &ps).expect("parse error"); | |
92a42be0 SL |
96 | let actual = e.node.attrs(); |
97 | str_compare(es, | |
9cc50fc6 | 98 | &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(), |
92a42be0 SL |
99 | actual, |
100 | pprust::attribute_to_string); | |
101 | } | |
102 | ||
103 | fn reject_expr_parse(es: &str) { | |
9cc50fc6 SL |
104 | let ps = ParseSess::new(); |
105 | match expr(es, &ps) { | |
106 | Ok(_) => panic!("parser did not reject `{}`", es), | |
107 | Err(mut e) => e.cancel(), | |
108 | }; | |
92a42be0 SL |
109 | } |
110 | ||
111 | fn reject_stmt_parse(es: &str) { | |
9cc50fc6 SL |
112 | let ps = ParseSess::new(); |
113 | match stmt(es, &ps) { | |
114 | Ok(_) => panic!("parser did not reject `{}`", es), | |
115 | Err(mut e) => e.cancel(), | |
116 | }; | |
92a42be0 SL |
117 | } |
118 | ||
119 | fn main() { | |
120 | let both = &["#[attr]", "#![attr]"]; | |
121 | let outer = &["#[attr]"]; | |
122 | let none = &[]; | |
123 | ||
124 | check_expr_attrs("#[attr] box 0", outer); | |
125 | reject_expr_parse("box #![attr] 0"); | |
126 | ||
127 | check_expr_attrs("#[attr] 0 <- #[attr] 0", none); | |
128 | check_expr_attrs("#[attr] (0 <- 0)", outer); | |
129 | reject_expr_parse("0 #[attr] <- 0"); | |
130 | reject_expr_parse("0 <- #![attr] 0"); | |
131 | ||
132 | check_expr_attrs("in #[attr] 0 {#[attr] 0}", none); | |
133 | check_expr_attrs("#[attr] (in 0 {0})", outer); | |
134 | reject_expr_parse("in 0 #[attr] {0}"); | |
135 | reject_expr_parse("in 0 {#![attr] 0}"); | |
136 | ||
137 | check_expr_attrs("#[attr] [#![attr]]", both); | |
138 | check_expr_attrs("#[attr] [#![attr] 0]", both); | |
139 | check_expr_attrs("#[attr] [#![attr] 0; 0]", both); | |
140 | check_expr_attrs("#[attr] [#![attr] 0, 0, 0]", both); | |
141 | reject_expr_parse("[#[attr]]"); | |
142 | ||
143 | check_expr_attrs("#[attr] foo()", outer); | |
144 | check_expr_attrs("#[attr] x.foo()", outer); | |
145 | reject_expr_parse("foo#[attr]()"); | |
146 | reject_expr_parse("foo(#![attr])"); | |
147 | reject_expr_parse("x.foo(#![attr])"); | |
148 | reject_expr_parse("x.#[attr]foo()"); | |
149 | reject_expr_parse("x.#![attr]foo()"); | |
150 | ||
151 | check_expr_attrs("#[attr] (#![attr])", both); | |
152 | check_expr_attrs("#[attr] (#![attr] #[attr] 0,)", both); | |
153 | check_expr_attrs("#[attr] (#![attr] #[attr] 0, 0)", both); | |
154 | ||
155 | check_expr_attrs("#[attr] 0 + #[attr] 0", none); | |
156 | check_expr_attrs("#[attr] 0 / #[attr] 0", none); | |
157 | check_expr_attrs("#[attr] 0 & #[attr] 0", none); | |
158 | check_expr_attrs("#[attr] 0 % #[attr] 0", none); | |
159 | check_expr_attrs("#[attr] (0 + 0)", outer); | |
160 | reject_expr_parse("0 + #![attr] 0"); | |
161 | ||
162 | check_expr_attrs("#[attr] !0", outer); | |
163 | check_expr_attrs("#[attr] -0", outer); | |
164 | reject_expr_parse("!#![attr] 0"); | |
165 | reject_expr_parse("-#![attr] 0"); | |
166 | ||
167 | check_expr_attrs("#[attr] false", outer); | |
168 | check_expr_attrs("#[attr] 0", outer); | |
169 | check_expr_attrs("#[attr] 'c'", outer); | |
170 | ||
171 | check_expr_attrs("#[attr] x as Y", none); | |
172 | check_expr_attrs("#[attr] (x as Y)", outer); | |
173 | reject_expr_parse("x #![attr] as Y"); | |
174 | ||
175 | reject_expr_parse("#[attr] if false {}"); | |
176 | reject_expr_parse("if false #[attr] {}"); | |
177 | reject_expr_parse("if false {#![attr]}"); | |
178 | reject_expr_parse("if false {} #[attr] else {}"); | |
179 | reject_expr_parse("if false {} else #[attr] {}"); | |
180 | reject_expr_parse("if false {} else {#![attr]}"); | |
181 | reject_expr_parse("if false {} else #[attr] if true {}"); | |
182 | reject_expr_parse("if false {} else if true #[attr] {}"); | |
183 | reject_expr_parse("if false {} else if true {#![attr]}"); | |
184 | ||
185 | reject_expr_parse("#[attr] if let Some(false) = false {}"); | |
186 | reject_expr_parse("if let Some(false) = false #[attr] {}"); | |
187 | reject_expr_parse("if let Some(false) = false {#![attr]}"); | |
188 | reject_expr_parse("if let Some(false) = false {} #[attr] else {}"); | |
189 | reject_expr_parse("if let Some(false) = false {} else #[attr] {}"); | |
190 | reject_expr_parse("if let Some(false) = false {} else {#![attr]}"); | |
191 | reject_expr_parse("if let Some(false) = false {} else #[attr] if let Some(false) = true {}"); | |
192 | reject_expr_parse("if let Some(false) = false {} else if let Some(false) = true #[attr] {}"); | |
193 | reject_expr_parse("if let Some(false) = false {} else if let Some(false) = true {#![attr]}"); | |
194 | ||
195 | check_expr_attrs("#[attr] while true {#![attr]}", both); | |
196 | ||
197 | check_expr_attrs("#[attr] while let Some(false) = true {#![attr]}", both); | |
198 | ||
199 | check_expr_attrs("#[attr] for x in y {#![attr]}", both); | |
200 | ||
201 | check_expr_attrs("#[attr] loop {#![attr]}", both); | |
202 | ||
203 | check_expr_attrs("#[attr] match true {#![attr] #[attr] _ => false}", both); | |
204 | ||
205 | check_expr_attrs("#[attr] || #[attr] foo", outer); | |
206 | check_expr_attrs("#[attr] move || #[attr] foo", outer); | |
207 | check_expr_attrs("#[attr] || #[attr] { #![attr] foo }", outer); | |
208 | check_expr_attrs("#[attr] move || #[attr] { #![attr] foo }", outer); | |
209 | check_expr_attrs("#[attr] || { #![attr] foo }", outer); | |
210 | check_expr_attrs("#[attr] move || { #![attr] foo }", outer); | |
211 | reject_expr_parse("|| #![attr] foo"); | |
212 | reject_expr_parse("move || #![attr] foo"); | |
213 | reject_expr_parse("|| #![attr] {foo}"); | |
214 | reject_expr_parse("move || #![attr] {foo}"); | |
215 | ||
216 | check_expr_attrs("#[attr] { #![attr] }", both); | |
217 | check_expr_attrs("#[attr] { #![attr] let _ = (); }", both); | |
218 | check_expr_attrs("#[attr] { #![attr] let _ = (); foo }", both); | |
219 | ||
220 | check_expr_attrs("#[attr] x = y", none); | |
221 | check_expr_attrs("#[attr] (x = y)", outer); | |
222 | ||
223 | check_expr_attrs("#[attr] x += y", none); | |
224 | check_expr_attrs("#[attr] (x += y)", outer); | |
225 | ||
226 | check_expr_attrs("#[attr] foo.bar", outer); | |
227 | check_expr_attrs("(#[attr] foo).bar", none); | |
228 | ||
229 | check_expr_attrs("#[attr] foo.0", outer); | |
230 | check_expr_attrs("(#[attr] foo).0", none); | |
231 | ||
232 | check_expr_attrs("#[attr] foo[bar]", outer); | |
233 | check_expr_attrs("(#[attr] foo)[bar]", none); | |
234 | ||
235 | check_expr_attrs("#[attr] 0..#[attr] 0", none); | |
236 | check_expr_attrs("#[attr] 0..", none); | |
237 | reject_expr_parse("#[attr] ..#[attr] 0"); | |
238 | reject_expr_parse("#[attr] .."); | |
239 | ||
240 | check_expr_attrs("#[attr] (0..0)", outer); | |
241 | check_expr_attrs("#[attr] (0..)", outer); | |
242 | check_expr_attrs("#[attr] (..0)", outer); | |
243 | check_expr_attrs("#[attr] (..)", outer); | |
244 | ||
245 | check_expr_attrs("#[attr] foo::bar::baz", outer); | |
246 | ||
247 | check_expr_attrs("#[attr] &0", outer); | |
248 | check_expr_attrs("#[attr] &mut 0", outer); | |
249 | check_expr_attrs("#[attr] & #[attr] 0", outer); | |
250 | check_expr_attrs("#[attr] &mut #[attr] 0", outer); | |
251 | reject_expr_parse("#[attr] &#![attr] 0"); | |
252 | reject_expr_parse("#[attr] &mut #![attr] 0"); | |
253 | ||
254 | check_expr_attrs("#[attr] break", outer); | |
255 | check_expr_attrs("#[attr] continue", outer); | |
256 | check_expr_attrs("#[attr] return", outer); | |
257 | ||
258 | check_expr_attrs("#[attr] foo!()", outer); | |
259 | check_expr_attrs("#[attr] foo!(#![attr])", outer); | |
260 | check_expr_attrs("#[attr] foo![]", outer); | |
261 | check_expr_attrs("#[attr] foo![#![attr]]", outer); | |
262 | check_expr_attrs("#[attr] foo!{}", outer); | |
263 | check_expr_attrs("#[attr] foo!{#![attr]}", outer); | |
264 | ||
265 | check_expr_attrs("#[attr] Foo { #![attr] bar: baz }", both); | |
266 | check_expr_attrs("#[attr] Foo { #![attr] ..foo }", both); | |
267 | check_expr_attrs("#[attr] Foo { #![attr] bar: baz, ..foo }", both); | |
268 | ||
269 | check_expr_attrs("#[attr] (#![attr] 0)", both); | |
270 | ||
271 | // Look at statements in their natural habitat... | |
272 | check_expr_attrs("{ | |
273 | #[attr] let _ = 0; | |
274 | #[attr] 0; | |
275 | #[attr] foo!(); | |
276 | #[attr] foo!{} | |
277 | #[attr] foo![]; | |
278 | }", none); | |
279 | ||
280 | check_stmt_attrs("#[attr] let _ = 0", outer); | |
281 | check_stmt_attrs("#[attr] 0", outer); | |
282 | check_stmt_attrs("#[attr] {#![attr]}", both); | |
283 | check_stmt_attrs("#[attr] foo!()", outer); | |
284 | check_stmt_attrs("#[attr] foo![]", outer); | |
285 | check_stmt_attrs("#[attr] foo!{}", outer); | |
286 | ||
287 | reject_stmt_parse("#[attr] #![attr] let _ = 0"); | |
288 | reject_stmt_parse("#[attr] #![attr] 0"); | |
289 | reject_stmt_parse("#[attr] #![attr] foo!()"); | |
290 | reject_stmt_parse("#[attr] #![attr] foo![]"); | |
291 | reject_stmt_parse("#[attr] #![attr] foo!{}"); | |
292 | ||
293 | // FIXME: Allow attributes in pattern constexprs? | |
294 | // would require parens in patterns to allow disambiguation... | |
295 | ||
296 | reject_expr_parse("match 0 { | |
297 | 0...#[attr] 10 => () | |
298 | }"); | |
299 | reject_expr_parse("match 0 { | |
300 | 0...#[attr] -10 => () | |
301 | }"); | |
302 | reject_expr_parse("match 0 { | |
303 | 0...-#[attr] 10 => () | |
304 | }"); | |
305 | reject_expr_parse("match 0 { | |
306 | 0...#[attr] FOO => () | |
307 | }"); | |
308 | ||
309 | // make sure we don't catch this bug again... | |
310 | reject_expr_parse("{ | |
311 | fn foo() { | |
312 | #[attr]; | |
313 | } | |
314 | }"); | |
315 | reject_expr_parse("{ | |
316 | fn foo() { | |
317 | #[attr] | |
318 | } | |
319 | }"); | |
320 | } |