1#![allow( 2 clippy::assertions_on_result_states, 3 clippy::non_ascii_literal, 4 clippy::uninlined_format_args 5)] 6 7#[macro_use] 8mod macros; 9 10use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; 11use quote::{quote, ToTokens as _}; 12use syn::parse::Parser as _; 13use syn::{Block, Stmt}; 14 15#[test] 16fn test_raw_operator() { 17 let stmt = syn::parse_str::<Stmt>("let _ = &raw const x;").unwrap(); 18 19 snapshot!(stmt, @r###" 20 Stmt::Local { 21 pat: Pat::Wild, 22 init: Some(LocalInit { 23 expr: Expr::Verbatim(`& raw const x`), 24 }), 25 } 26 "###); 27} 28 29#[test] 30fn test_raw_variable() { 31 let stmt = syn::parse_str::<Stmt>("let _ = &raw;").unwrap(); 32 33 snapshot!(stmt, @r###" 34 Stmt::Local { 35 pat: Pat::Wild, 36 init: Some(LocalInit { 37 expr: Expr::Reference { 38 expr: Expr::Path { 39 path: Path { 40 segments: [ 41 PathSegment { 42 ident: "raw", 43 }, 44 ], 45 }, 46 }, 47 }, 48 }), 49 } 50 "###); 51} 52 53#[test] 54fn test_raw_invalid() { 55 assert!(syn::parse_str::<Stmt>("let _ = &raw x;").is_err()); 56} 57 58#[test] 59fn test_none_group() { 60 // <Ø async fn f() {} Ø> 61 let tokens = TokenStream::from_iter(vec![TokenTree::Group(Group::new( 62 Delimiter::None, 63 TokenStream::from_iter(vec![ 64 TokenTree::Ident(Ident::new("async", Span::call_site())), 65 TokenTree::Ident(Ident::new("fn", Span::call_site())), 66 TokenTree::Ident(Ident::new("f", Span::call_site())), 67 TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), 68 TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), 69 ]), 70 ))]); 71 snapshot!(tokens as Stmt, @r###" 72 Stmt::Item(Item::Fn { 73 vis: Visibility::Inherited, 74 sig: Signature { 75 asyncness: Some, 76 ident: "f", 77 generics: Generics, 78 output: ReturnType::Default, 79 }, 80 block: Block { 81 stmts: [], 82 }, 83 }) 84 "###); 85 86 let tokens = Group::new(Delimiter::None, quote!(let None = None)).to_token_stream(); 87 let stmts = Block::parse_within.parse2(tokens).unwrap(); 88 snapshot!(stmts, @r###" 89 [ 90 Stmt::Expr( 91 Expr::Group { 92 expr: Expr::Let { 93 pat: Pat::Ident { 94 ident: "None", 95 }, 96 expr: Expr::Path { 97 path: Path { 98 segments: [ 99 PathSegment { 100 ident: "None", 101 }, 102 ], 103 }, 104 }, 105 }, 106 }, 107 None, 108 ), 109 ] 110 "###); 111} 112 113#[test] 114fn test_let_dot_dot() { 115 let tokens = quote! { 116 let .. = 10; 117 }; 118 119 snapshot!(tokens as Stmt, @r###" 120 Stmt::Local { 121 pat: Pat::Rest, 122 init: Some(LocalInit { 123 expr: Expr::Lit { 124 lit: 10, 125 }, 126 }), 127 } 128 "###); 129} 130 131#[test] 132fn test_let_else() { 133 let tokens = quote! { 134 let Some(x) = None else { return 0; }; 135 }; 136 137 snapshot!(tokens as Stmt, @r###" 138 Stmt::Local { 139 pat: Pat::TupleStruct { 140 path: Path { 141 segments: [ 142 PathSegment { 143 ident: "Some", 144 }, 145 ], 146 }, 147 elems: [ 148 Pat::Ident { 149 ident: "x", 150 }, 151 ], 152 }, 153 init: Some(LocalInit { 154 expr: Expr::Path { 155 path: Path { 156 segments: [ 157 PathSegment { 158 ident: "None", 159 }, 160 ], 161 }, 162 }, 163 diverge: Some(Expr::Block { 164 block: Block { 165 stmts: [ 166 Stmt::Expr( 167 Expr::Return { 168 expr: Some(Expr::Lit { 169 lit: 0, 170 }), 171 }, 172 Some, 173 ), 174 ], 175 }, 176 }), 177 }), 178 } 179 "###); 180} 181 182#[test] 183fn test_macros() { 184 let tokens = quote! { 185 fn main() { 186 macro_rules! mac {} 187 thread_local! { static FOO } 188 println!(""); 189 vec![] 190 } 191 }; 192 193 snapshot!(tokens as Stmt, @r###" 194 Stmt::Item(Item::Fn { 195 vis: Visibility::Inherited, 196 sig: Signature { 197 ident: "main", 198 generics: Generics, 199 output: ReturnType::Default, 200 }, 201 block: Block { 202 stmts: [ 203 Stmt::Item(Item::Macro { 204 ident: Some("mac"), 205 mac: Macro { 206 path: Path { 207 segments: [ 208 PathSegment { 209 ident: "macro_rules", 210 }, 211 ], 212 }, 213 delimiter: MacroDelimiter::Brace, 214 tokens: TokenStream(``), 215 }, 216 }), 217 Stmt::Macro { 218 mac: Macro { 219 path: Path { 220 segments: [ 221 PathSegment { 222 ident: "thread_local", 223 }, 224 ], 225 }, 226 delimiter: MacroDelimiter::Brace, 227 tokens: TokenStream(`static FOO`), 228 }, 229 }, 230 Stmt::Macro { 231 mac: Macro { 232 path: Path { 233 segments: [ 234 PathSegment { 235 ident: "println", 236 }, 237 ], 238 }, 239 delimiter: MacroDelimiter::Paren, 240 tokens: TokenStream(`""`), 241 }, 242 semi_token: Some, 243 }, 244 Stmt::Expr( 245 Expr::Macro { 246 mac: Macro { 247 path: Path { 248 segments: [ 249 PathSegment { 250 ident: "vec", 251 }, 252 ], 253 }, 254 delimiter: MacroDelimiter::Bracket, 255 tokens: TokenStream(``), 256 }, 257 }, 258 None, 259 ), 260 ], 261 }, 262 }) 263 "###); 264} 265 266#[test] 267fn test_early_parse_loop() { 268 // The following is an Expr::Loop followed by Expr::Tuple. It is not an 269 // Expr::Call. 270 let tokens = quote! { 271 loop {} 272 () 273 }; 274 275 let stmts = Block::parse_within.parse2(tokens).unwrap(); 276 277 snapshot!(stmts, @r###" 278 [ 279 Stmt::Expr( 280 Expr::Loop { 281 body: Block { 282 stmts: [], 283 }, 284 }, 285 None, 286 ), 287 Stmt::Expr( 288 Expr::Tuple, 289 None, 290 ), 291 ] 292 "###); 293 294 let tokens = quote! { 295 'a: loop {} 296 () 297 }; 298 299 let stmts = Block::parse_within.parse2(tokens).unwrap(); 300 301 snapshot!(stmts, @r###" 302 [ 303 Stmt::Expr( 304 Expr::Loop { 305 label: Some(Label { 306 name: Lifetime { 307 ident: "a", 308 }, 309 }), 310 body: Block { 311 stmts: [], 312 }, 313 }, 314 None, 315 ), 316 Stmt::Expr( 317 Expr::Tuple, 318 None, 319 ), 320 ] 321 "###); 322} 323