| #[macro_use] |
| mod macros; |
| |
| use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; |
| use quote::quote; |
| use std::iter::FromIterator; |
| use syn::{Expr, ExprRange}; |
| |
| #[test] |
| fn test_expr_parse() { |
| let tokens = quote!(..100u32); |
| snapshot!(tokens as Expr, @r###" |
| Expr::Range { |
| limits: HalfOpen, |
| to: Some(Expr::Lit { |
| lit: 100u32, |
| }), |
| } |
| "###); |
| |
| let tokens = quote!(..100u32); |
| snapshot!(tokens as ExprRange, @r###" |
| ExprRange { |
| limits: HalfOpen, |
| to: Some(Expr::Lit { |
| lit: 100u32, |
| }), |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_await() { |
| // Must not parse as Expr::Field. |
| let tokens = quote!(fut.await); |
| |
| snapshot!(tokens as Expr, @r###" |
| Expr::Await { |
| base: Expr::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "fut", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| } |
| "###); |
| } |
| |
| #[rustfmt::skip] |
| #[test] |
| fn test_tuple_multi_index() { |
| for &input in &[ |
| "tuple.0.0", |
| "tuple .0.0", |
| "tuple. 0.0", |
| "tuple.0 .0", |
| "tuple.0. 0", |
| "tuple . 0 . 0", |
| ] { |
| snapshot!(input as Expr, @r###" |
| Expr::Field { |
| base: Expr::Field { |
| base: Expr::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "tuple", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| member: Unnamed(Index { |
| index: 0, |
| }), |
| }, |
| member: Unnamed(Index { |
| index: 0, |
| }), |
| } |
| "###); |
| } |
| |
| for tokens in vec![ |
| quote!(tuple.0.0), |
| quote!(tuple .0.0), |
| quote!(tuple. 0.0), |
| quote!(tuple.0 .0), |
| quote!(tuple.0. 0), |
| quote!(tuple . 0 . 0), |
| ] { |
| snapshot!(tokens as Expr, @r###" |
| Expr::Field { |
| base: Expr::Field { |
| base: Expr::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "tuple", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| member: Unnamed(Index { |
| index: 0, |
| }), |
| }, |
| member: Unnamed(Index { |
| index: 0, |
| }), |
| } |
| "###); |
| } |
| } |
| |
| #[test] |
| fn test_macro_variable_func() { |
| // mimics the token stream corresponding to `$fn()` |
| let tokens = TokenStream::from_iter(vec![ |
| TokenTree::Group(Group::new(Delimiter::None, quote! { f })), |
| TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), |
| ]); |
| |
| snapshot!(tokens as Expr, @r###" |
| Expr::Call { |
| func: Expr::Group { |
| expr: Expr::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "f", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| }, |
| } |
| "###); |
| |
| let tokens = TokenStream::from_iter(vec![ |
| TokenTree::Punct(Punct::new('#', Spacing::Alone)), |
| TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })), |
| TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })), |
| TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), |
| ]); |
| |
| snapshot!(tokens as Expr, @r###" |
| Expr::Call { |
| attrs: [ |
| Attribute { |
| style: Outer, |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "outside", |
| arguments: None, |
| }, |
| ], |
| }, |
| tokens: TokenStream(``), |
| }, |
| ], |
| func: Expr::Group { |
| expr: Expr::Path { |
| attrs: [ |
| Attribute { |
| style: Outer, |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "inside", |
| arguments: None, |
| }, |
| ], |
| }, |
| tokens: TokenStream(``), |
| }, |
| ], |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "f", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| }, |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_macro_variable_macro() { |
| // mimics the token stream corresponding to `$macro!()` |
| let tokens = TokenStream::from_iter(vec![ |
| TokenTree::Group(Group::new(Delimiter::None, quote! { m })), |
| TokenTree::Punct(Punct::new('!', Spacing::Alone)), |
| TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), |
| ]); |
| |
| snapshot!(tokens as Expr, @r###" |
| Expr::Macro { |
| mac: Macro { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "m", |
| arguments: None, |
| }, |
| ], |
| }, |
| delimiter: Paren, |
| tokens: TokenStream(``), |
| }, |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_macro_variable_struct() { |
| // mimics the token stream corresponding to `$struct {}` |
| let tokens = TokenStream::from_iter(vec![ |
| TokenTree::Group(Group::new(Delimiter::None, quote! { S })), |
| TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), |
| ]); |
| |
| snapshot!(tokens as Expr, @r###" |
| Expr::Struct { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "S", |
| arguments: None, |
| }, |
| ], |
| }, |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_macro_variable_match_arm() { |
| // mimics the token stream corresponding to `match v { _ => $expr }` |
| let tokens = TokenStream::from_iter(vec![ |
| TokenTree::Ident(Ident::new("match", Span::call_site())), |
| TokenTree::Ident(Ident::new("v", Span::call_site())), |
| TokenTree::Group(Group::new( |
| Delimiter::Brace, |
| TokenStream::from_iter(vec![ |
| TokenTree::Punct(Punct::new('_', Spacing::Alone)), |
| TokenTree::Punct(Punct::new('=', Spacing::Joint)), |
| TokenTree::Punct(Punct::new('>', Spacing::Alone)), |
| TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })), |
| ]), |
| )), |
| ]); |
| |
| snapshot!(tokens as Expr, @r###" |
| Expr::Match { |
| expr: Expr::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "v", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| arms: [ |
| Arm { |
| pat: Pat::Wild, |
| body: Expr::Group { |
| expr: Expr::Tuple { |
| attrs: [ |
| Attribute { |
| style: Outer, |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "a", |
| arguments: None, |
| }, |
| ], |
| }, |
| tokens: TokenStream(``), |
| }, |
| ], |
| }, |
| }, |
| }, |
| ], |
| } |
| "###); |
| } |