1#[macro_use]
2mod macros;
3
4use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
5use quote::quote;
6use std::iter::FromIterator;
7use syn::{Expr, ExprRange};
8
9#[test]
10fn test_expr_parse() {
11 let tokens = quote!(..100u32);
12 snapshot!(tokens as Expr, @r###"
13 Expr::Range {
14 limits: HalfOpen,
15 to: Some(Expr::Lit {
16 lit: 100u32,
17 }),
18 }
19 "###);
20
21 let tokens = quote!(..100u32);
22 snapshot!(tokens as ExprRange, @r###"
23 ExprRange {
24 limits: HalfOpen,
25 to: Some(Expr::Lit {
26 lit: 100u32,
27 }),
28 }
29 "###);
30}
31
32#[test]
33fn test_await() {
34 // Must not parse as Expr::Field.
35 let tokens = quote!(fut.await);
36
37 snapshot!(tokens as Expr, @r###"
38 Expr::Await {
39 base: Expr::Path {
40 path: Path {
41 segments: [
42 PathSegment {
43 ident: "fut",
44 arguments: None,
45 },
46 ],
47 },
48 },
49 }
50 "###);
51}
52
53#[rustfmt::skip]
54#[test]
55fn test_tuple_multi_index() {
56 let expected = snapshot!("tuple.0.0" as Expr, @r###"
57 Expr::Field {
58 base: Expr::Field {
59 base: Expr::Path {
60 path: Path {
61 segments: [
62 PathSegment {
63 ident: "tuple",
64 arguments: None,
65 },
66 ],
67 },
68 },
69 member: Unnamed(Index {
70 index: 0,
71 }),
72 },
73 member: Unnamed(Index {
74 index: 0,
75 }),
76 }
77 "###);
78
79 for &input in &[
80 "tuple .0.0",
81 "tuple. 0.0",
82 "tuple.0 .0",
83 "tuple.0. 0",
84 "tuple . 0 . 0",
85 ] {
86 assert_eq!(expected, syn::parse_str(input).unwrap());
87 }
88
89 for tokens in vec![
90 quote!(tuple.0.0),
91 quote!(tuple .0.0),
92 quote!(tuple. 0.0),
93 quote!(tuple.0 .0),
94 quote!(tuple.0. 0),
95 quote!(tuple . 0 . 0),
96 ] {
97 assert_eq!(expected, syn::parse2(tokens).unwrap());
98 }
99}
100
101#[test]
102fn test_macro_variable_func() {
103 // mimics the token stream corresponding to `$fn()`
104 let tokens = TokenStream::from_iter(vec![
105 TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
106 TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
107 ]);
108
109 snapshot!(tokens as Expr, @r###"
110 Expr::Call {
111 func: Expr::Group {
112 expr: Expr::Path {
113 path: Path {
114 segments: [
115 PathSegment {
116 ident: "f",
117 arguments: None,
118 },
119 ],
120 },
121 },
122 },
123 }
124 "###);
125
126 let tokens = TokenStream::from_iter(vec![
127 TokenTree::Punct(Punct::new('#', Spacing::Alone)),
128 TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
129 TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
130 TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
131 ]);
132
133 snapshot!(tokens as Expr, @r###"
134 Expr::Call {
135 attrs: [
136 Attribute {
137 style: Outer,
138 path: Path {
139 segments: [
140 PathSegment {
141 ident: "outside",
142 arguments: None,
143 },
144 ],
145 },
146 tokens: TokenStream(``),
147 },
148 ],
149 func: Expr::Group {
150 expr: Expr::Path {
151 attrs: [
152 Attribute {
153 style: Outer,
154 path: Path {
155 segments: [
156 PathSegment {
157 ident: "inside",
158 arguments: None,
159 },
160 ],
161 },
162 tokens: TokenStream(``),
163 },
164 ],
165 path: Path {
166 segments: [
167 PathSegment {
168 ident: "f",
169 arguments: None,
170 },
171 ],
172 },
173 },
174 },
175 }
176 "###);
177}
178
179#[test]
180fn test_macro_variable_macro() {
181 // mimics the token stream corresponding to `$macro!()`
182 let tokens = TokenStream::from_iter(vec![
183 TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
184 TokenTree::Punct(Punct::new('!', Spacing::Alone)),
185 TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
186 ]);
187
188 snapshot!(tokens as Expr, @r###"
189 Expr::Macro {
190 mac: Macro {
191 path: Path {
192 segments: [
193 PathSegment {
194 ident: "m",
195 arguments: None,
196 },
197 ],
198 },
199 delimiter: Paren,
200 tokens: TokenStream(``),
201 },
202 }
203 "###);
204}
205
206#[test]
207fn test_macro_variable_struct() {
208 // mimics the token stream corresponding to `$struct {}`
209 let tokens = TokenStream::from_iter(vec![
210 TokenTree::Group(Group::new(Delimiter::None, quote! { S })),
211 TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
212 ]);
213
214 snapshot!(tokens as Expr, @r###"
215 Expr::Struct {
216 path: Path {
217 segments: [
218 PathSegment {
219 ident: "S",
220 arguments: None,
221 },
222 ],
223 },
224 }
225 "###);
226}
227
228#[test]
229fn test_macro_variable_match_arm() {
230 // mimics the token stream corresponding to `match v { _ => $expr }`
231 let tokens = TokenStream::from_iter(vec![
232 TokenTree::Ident(Ident::new("match", Span::call_site())),
233 TokenTree::Ident(Ident::new("v", Span::call_site())),
234 TokenTree::Group(Group::new(
235 Delimiter::Brace,
236 TokenStream::from_iter(vec![
237 TokenTree::Punct(Punct::new('_', Spacing::Alone)),
238 TokenTree::Punct(Punct::new('=', Spacing::Joint)),
239 TokenTree::Punct(Punct::new('>', Spacing::Alone)),
240 TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })),
241 ]),
242 )),
243 ]);
244
245 snapshot!(tokens as Expr, @r###"
246 Expr::Match {
247 expr: Expr::Path {
248 path: Path {
249 segments: [
250 PathSegment {
251 ident: "v",
252 arguments: None,
253 },
254 ],
255 },
256 },
257 arms: [
258 Arm {
259 pat: Pat::Wild,
260 body: Expr::Group {
261 expr: Expr::Tuple {
262 attrs: [
263 Attribute {
264 style: Outer,
265 path: Path {
266 segments: [
267 PathSegment {
268 ident: "a",
269 arguments: None,
270 },
271 ],
272 },
273 tokens: TokenStream(``),
274 },
275 ],
276 },
277 },
278 },
279 ],
280 }
281 "###);
282}
283
284// https://github.com/dtolnay/syn/issues/1019
285#[test]
286fn test_closure_vs_rangefull() {
287 #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/4808
288 let tokens = quote!(|| .. .method());
289 snapshot!(tokens as Expr, @r###"
290 Expr::MethodCall {
291 receiver: Expr::Closure {
292 output: Default,
293 body: Expr::Range {
294 limits: HalfOpen,
295 },
296 },
297 method: "method",
298 }
299 "###);
300}
301
302#[test]
303fn test_postfix_operator_after_cast() {
304 syn::parse_str::<Expr>("|| &x as T[0]").unwrap_err();
305 syn::parse_str::<Expr>("|| () as ()()").unwrap_err();
306}
307