diff options
Diffstat (limited to 'crates/ra_mbe/src/lib.rs')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 1138 |
1 files changed, 1 insertions, 1137 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index ea2104b1c..c146252a4 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -15,7 +15,6 @@ macro_rules! impl_froms { | |||
15 | } | 15 | } |
16 | } | 16 | } |
17 | 17 | ||
18 | // mod tt_cursor; | ||
19 | mod mbe_parser; | 18 | mod mbe_parser; |
20 | mod mbe_expander; | 19 | mod mbe_expander; |
21 | mod syntax_bridge; | 20 | mod syntax_bridge; |
@@ -155,1139 +154,4 @@ pub(crate) struct Var { | |||
155 | } | 154 | } |
156 | 155 | ||
157 | #[cfg(test)] | 156 | #[cfg(test)] |
158 | mod tests { | 157 | mod tests; |
159 | use ra_syntax::{ast, AstNode}; | ||
160 | |||
161 | use super::*; | ||
162 | |||
163 | // Good first issue (although a slightly challenging one): | ||
164 | // | ||
165 | // * Pick a random test from here | ||
166 | // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt | ||
167 | // * Port the test to rust and add it to this module | ||
168 | // * Make it pass :-) | ||
169 | |||
170 | #[test] | ||
171 | fn test_convert_tt() { | ||
172 | let macro_definition = r#" | ||
173 | macro_rules! impl_froms { | ||
174 | ($e:ident: $($v:ident),*) => { | ||
175 | $( | ||
176 | impl From<$v> for $e { | ||
177 | fn from(it: $v) -> $e { | ||
178 | $e::$v(it) | ||
179 | } | ||
180 | } | ||
181 | )* | ||
182 | } | ||
183 | } | ||
184 | "#; | ||
185 | |||
186 | let macro_invocation = r#" | ||
187 | impl_froms!(TokenTree: Leaf, Subtree); | ||
188 | "#; | ||
189 | |||
190 | let source_file = ast::SourceFile::parse(macro_definition); | ||
191 | let macro_definition = | ||
192 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
193 | |||
194 | let source_file = ast::SourceFile::parse(macro_invocation); | ||
195 | let macro_invocation = | ||
196 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
197 | |||
198 | let (definition_tt, _) = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap(); | ||
199 | let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); | ||
200 | let rules = crate::MacroRules::parse(&definition_tt).unwrap(); | ||
201 | let expansion = rules.expand(&invocation_tt).unwrap(); | ||
202 | assert_eq!( | ||
203 | expansion.to_string(), | ||
204 | "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \ | ||
205 | impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}" | ||
206 | ) | ||
207 | } | ||
208 | |||
209 | pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { | ||
210 | let source_file = ast::SourceFile::parse(macro_definition); | ||
211 | let macro_definition = | ||
212 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
213 | |||
214 | let (definition_tt, _) = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap(); | ||
215 | crate::MacroRules::parse(&definition_tt).unwrap() | ||
216 | } | ||
217 | |||
218 | pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree { | ||
219 | let source_file = ast::SourceFile::parse(invocation); | ||
220 | let macro_invocation = | ||
221 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
222 | |||
223 | let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); | ||
224 | |||
225 | rules.expand(&invocation_tt).unwrap() | ||
226 | } | ||
227 | |||
228 | pub(crate) fn expand_to_items( | ||
229 | rules: &MacroRules, | ||
230 | invocation: &str, | ||
231 | ) -> ra_syntax::TreeArc<ast::MacroItems> { | ||
232 | let expanded = expand(rules, invocation); | ||
233 | token_tree_to_macro_items(&expanded).unwrap() | ||
234 | } | ||
235 | |||
236 | #[allow(unused)] | ||
237 | pub(crate) fn expand_to_stmts( | ||
238 | rules: &MacroRules, | ||
239 | invocation: &str, | ||
240 | ) -> ra_syntax::TreeArc<ast::MacroStmts> { | ||
241 | let expanded = expand(rules, invocation); | ||
242 | token_tree_to_macro_stmts(&expanded).unwrap() | ||
243 | } | ||
244 | |||
245 | pub(crate) fn expand_to_expr( | ||
246 | rules: &MacroRules, | ||
247 | invocation: &str, | ||
248 | ) -> ra_syntax::TreeArc<ast::Expr> { | ||
249 | let expanded = expand(rules, invocation); | ||
250 | token_tree_to_expr(&expanded).unwrap() | ||
251 | } | ||
252 | |||
253 | pub(crate) fn assert_expansion( | ||
254 | rules: &MacroRules, | ||
255 | invocation: &str, | ||
256 | expansion: &str, | ||
257 | ) -> tt::Subtree { | ||
258 | let expanded = expand(rules, invocation); | ||
259 | assert_eq!(expanded.to_string(), expansion); | ||
260 | |||
261 | // FIXME: Temp comment below code | ||
262 | // It is because after the lexer change, | ||
263 | // The SyntaxNode structure cannot be matched easily | ||
264 | |||
265 | // let tree = token_tree_to_macro_items(&expanded); | ||
266 | |||
267 | // // Eat all white space by parse it back and forth | ||
268 | // // Because $crate will seperate in two token , will do some special treatment here | ||
269 | // let expansion = expansion.replace("$crate", "C_C__C"); | ||
270 | // let expansion = ast::SourceFile::parse(&expansion); | ||
271 | // let expansion = syntax_node_to_token_tree(expansion.syntax()).unwrap().0; | ||
272 | // let file = token_tree_to_macro_items(&expansion); | ||
273 | // let file = file.unwrap().syntax().debug_dump().trim().to_string(); | ||
274 | // let tree = tree.unwrap().syntax().debug_dump().trim().to_string(); | ||
275 | |||
276 | // let file = file.replace("C_C__C", "$crate"); | ||
277 | // assert_eq!(tree, file,); | ||
278 | |||
279 | expanded | ||
280 | } | ||
281 | |||
282 | #[test] | ||
283 | fn test_fail_match_pattern_by_first_token() { | ||
284 | let rules = create_rules( | ||
285 | r#" | ||
286 | macro_rules! foo { | ||
287 | ($ i:ident) => ( | ||
288 | mod $ i {} | ||
289 | ); | ||
290 | (= $ i:ident) => ( | ||
291 | fn $ i() {} | ||
292 | ); | ||
293 | (+ $ i:ident) => ( | ||
294 | struct $ i; | ||
295 | ) | ||
296 | } | ||
297 | "#, | ||
298 | ); | ||
299 | |||
300 | assert_expansion(&rules, "foo! { foo }", "mod foo {}"); | ||
301 | assert_expansion(&rules, "foo! { = bar }", "fn bar () {}"); | ||
302 | assert_expansion(&rules, "foo! { + Baz }", "struct Baz ;"); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn test_fail_match_pattern_by_last_token() { | ||
307 | let rules = create_rules( | ||
308 | r#" | ||
309 | macro_rules! foo { | ||
310 | ($ i:ident) => ( | ||
311 | mod $ i {} | ||
312 | ); | ||
313 | ($ i:ident =) => ( | ||
314 | fn $ i() {} | ||
315 | ); | ||
316 | ($ i:ident +) => ( | ||
317 | struct $ i; | ||
318 | ) | ||
319 | } | ||
320 | "#, | ||
321 | ); | ||
322 | |||
323 | assert_expansion(&rules, "foo! { foo }", "mod foo {}"); | ||
324 | assert_expansion(&rules, "foo! { bar = }", "fn bar () {}"); | ||
325 | assert_expansion(&rules, "foo! { Baz + }", "struct Baz ;"); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn test_fail_match_pattern_by_word_token() { | ||
330 | let rules = create_rules( | ||
331 | r#" | ||
332 | macro_rules! foo { | ||
333 | ($ i:ident) => ( | ||
334 | mod $ i {} | ||
335 | ); | ||
336 | (spam $ i:ident) => ( | ||
337 | fn $ i() {} | ||
338 | ); | ||
339 | (eggs $ i:ident) => ( | ||
340 | struct $ i; | ||
341 | ) | ||
342 | } | ||
343 | "#, | ||
344 | ); | ||
345 | |||
346 | assert_expansion(&rules, "foo! { foo }", "mod foo {}"); | ||
347 | assert_expansion(&rules, "foo! { spam bar }", "fn bar () {}"); | ||
348 | assert_expansion(&rules, "foo! { eggs Baz }", "struct Baz ;"); | ||
349 | } | ||
350 | |||
351 | #[test] | ||
352 | fn test_match_group_pattern_by_separator_token() { | ||
353 | let rules = create_rules( | ||
354 | r#" | ||
355 | macro_rules! foo { | ||
356 | ($ ($ i:ident),*) => ($ ( | ||
357 | mod $ i {} | ||
358 | )*); | ||
359 | ($ ($ i:ident)#*) => ($ ( | ||
360 | fn $ i() {} | ||
361 | )*); | ||
362 | ($ i:ident ,# $ j:ident) => ( | ||
363 | struct $ i; | ||
364 | struct $ j; | ||
365 | ) | ||
366 | } | ||
367 | "#, | ||
368 | ); | ||
369 | |||
370 | assert_expansion(&rules, "foo! { foo, bar }", "mod foo {} mod bar {}"); | ||
371 | assert_expansion(&rules, "foo! { foo# bar }", "fn foo () {} fn bar () {}"); | ||
372 | assert_expansion(&rules, "foo! { Foo,# Bar }", "struct Foo ; struct Bar ;"); | ||
373 | } | ||
374 | |||
375 | #[test] | ||
376 | fn test_match_group_pattern_with_multiple_defs() { | ||
377 | let rules = create_rules( | ||
378 | r#" | ||
379 | macro_rules! foo { | ||
380 | ($ ($ i:ident),*) => ( struct Bar { $ ( | ||
381 | fn $ i {} | ||
382 | )*} ); | ||
383 | } | ||
384 | "#, | ||
385 | ); | ||
386 | |||
387 | assert_expansion(&rules, "foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}"); | ||
388 | } | ||
389 | |||
390 | #[test] | ||
391 | fn test_match_group_pattern_with_multiple_statement() { | ||
392 | let rules = create_rules( | ||
393 | r#" | ||
394 | macro_rules! foo { | ||
395 | ($ ($ i:ident),*) => ( fn baz { $ ( | ||
396 | $ i (); | ||
397 | )*} ); | ||
398 | } | ||
399 | "#, | ||
400 | ); | ||
401 | |||
402 | assert_expansion(&rules, "foo! { foo, bar }", "fn baz {foo () ; bar () ;}"); | ||
403 | } | ||
404 | |||
405 | #[test] | ||
406 | fn test_match_group_pattern_with_multiple_statement_without_semi() { | ||
407 | let rules = create_rules( | ||
408 | r#" | ||
409 | macro_rules! foo { | ||
410 | ($ ($ i:ident),*) => ( fn baz { $ ( | ||
411 | $i() | ||
412 | );*} ); | ||
413 | } | ||
414 | "#, | ||
415 | ); | ||
416 | |||
417 | assert_expansion(&rules, "foo! { foo, bar }", "fn baz {foo () ;bar ()}"); | ||
418 | } | ||
419 | |||
420 | #[test] | ||
421 | fn test_match_group_empty_fixed_token() { | ||
422 | let rules = create_rules( | ||
423 | r#" | ||
424 | macro_rules! foo { | ||
425 | ($ ($ i:ident)* #abc) => ( fn baz { $ ( | ||
426 | $ i (); | ||
427 | )*} ); | ||
428 | } | ||
429 | "#, | ||
430 | ); | ||
431 | |||
432 | assert_expansion(&rules, "foo! {#abc}", "fn baz {}"); | ||
433 | } | ||
434 | |||
435 | #[test] | ||
436 | fn test_match_group_in_subtree() { | ||
437 | let rules = create_rules( | ||
438 | r#" | ||
439 | macro_rules! foo { | ||
440 | (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ ( | ||
441 | $ i (); | ||
442 | )*} ); | ||
443 | }"#, | ||
444 | ); | ||
445 | |||
446 | assert_expansion(&rules, "foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}"); | ||
447 | } | ||
448 | |||
449 | #[test] | ||
450 | fn test_match_group_with_multichar_sep() { | ||
451 | let rules = create_rules( | ||
452 | r#" | ||
453 | macro_rules! foo { | ||
454 | (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} ); | ||
455 | }"#, | ||
456 | ); | ||
457 | |||
458 | assert_expansion(&rules, "foo! (fn baz {true true} )", "fn baz () -> bool {true &&true}"); | ||
459 | } | ||
460 | |||
461 | #[test] | ||
462 | fn test_match_group_zero_match() { | ||
463 | let rules = create_rules( | ||
464 | r#" | ||
465 | macro_rules! foo { | ||
466 | ( $($i:ident)* ) => (); | ||
467 | }"#, | ||
468 | ); | ||
469 | |||
470 | assert_expansion(&rules, "foo! ()", ""); | ||
471 | } | ||
472 | |||
473 | #[test] | ||
474 | fn test_match_group_in_group() { | ||
475 | let rules = create_rules( | ||
476 | r#" | ||
477 | macro_rules! foo { | ||
478 | { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* ); | ||
479 | }"#, | ||
480 | ); | ||
481 | |||
482 | assert_expansion(&rules, "foo! ( (a b) )", "(a b)"); | ||
483 | } | ||
484 | |||
485 | #[test] | ||
486 | fn test_expand_to_item_list() { | ||
487 | let rules = create_rules( | ||
488 | " | ||
489 | macro_rules! structs { | ||
490 | ($($i:ident),*) => { | ||
491 | $(struct $i { field: u32 } )* | ||
492 | } | ||
493 | } | ||
494 | ", | ||
495 | ); | ||
496 | let expansion = expand(&rules, "structs!(Foo, Bar)"); | ||
497 | let tree = token_tree_to_macro_items(&expansion); | ||
498 | assert_eq!( | ||
499 | tree.unwrap().syntax().debug_dump().trim(), | ||
500 | r#" | ||
501 | MACRO_ITEMS@[0; 40) | ||
502 | STRUCT_DEF@[0; 20) | ||
503 | STRUCT_KW@[0; 6) "struct" | ||
504 | NAME@[6; 9) | ||
505 | IDENT@[6; 9) "Foo" | ||
506 | NAMED_FIELD_DEF_LIST@[9; 20) | ||
507 | L_CURLY@[9; 10) "{" | ||
508 | NAMED_FIELD_DEF@[10; 19) | ||
509 | NAME@[10; 15) | ||
510 | IDENT@[10; 15) "field" | ||
511 | COLON@[15; 16) ":" | ||
512 | PATH_TYPE@[16; 19) | ||
513 | PATH@[16; 19) | ||
514 | PATH_SEGMENT@[16; 19) | ||
515 | NAME_REF@[16; 19) | ||
516 | IDENT@[16; 19) "u32" | ||
517 | R_CURLY@[19; 20) "}" | ||
518 | STRUCT_DEF@[20; 40) | ||
519 | STRUCT_KW@[20; 26) "struct" | ||
520 | NAME@[26; 29) | ||
521 | IDENT@[26; 29) "Bar" | ||
522 | NAMED_FIELD_DEF_LIST@[29; 40) | ||
523 | L_CURLY@[29; 30) "{" | ||
524 | NAMED_FIELD_DEF@[30; 39) | ||
525 | NAME@[30; 35) | ||
526 | IDENT@[30; 35) "field" | ||
527 | COLON@[35; 36) ":" | ||
528 | PATH_TYPE@[36; 39) | ||
529 | PATH@[36; 39) | ||
530 | PATH_SEGMENT@[36; 39) | ||
531 | NAME_REF@[36; 39) | ||
532 | IDENT@[36; 39) "u32" | ||
533 | R_CURLY@[39; 40) "}""# | ||
534 | .trim() | ||
535 | ); | ||
536 | } | ||
537 | |||
538 | #[test] | ||
539 | fn test_expand_literals_to_token_tree() { | ||
540 | fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree { | ||
541 | if let tt::TokenTree::Subtree(subtree) = tt { | ||
542 | return &subtree; | ||
543 | } | ||
544 | unreachable!("It is not a subtree"); | ||
545 | } | ||
546 | |||
547 | fn to_literal(tt: &tt::TokenTree) -> &tt::Literal { | ||
548 | if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt { | ||
549 | return lit; | ||
550 | } | ||
551 | unreachable!("It is not a literal"); | ||
552 | } | ||
553 | |||
554 | let rules = create_rules( | ||
555 | r#" | ||
556 | macro_rules! literals { | ||
557 | ($i:ident) => { | ||
558 | { | ||
559 | let a = 'c'; | ||
560 | let c = 1000; | ||
561 | let f = 12E+99_f64; | ||
562 | let s = "rust1"; | ||
563 | } | ||
564 | } | ||
565 | } | ||
566 | "#, | ||
567 | ); | ||
568 | let expansion = expand(&rules, "literals!(foo)"); | ||
569 | let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees; | ||
570 | |||
571 | // [let] [a] [=] ['c'] [;] | ||
572 | assert_eq!(to_literal(&stm_tokens[3]).text, "'c'"); | ||
573 | // [let] [c] [=] [1000] [;] | ||
574 | assert_eq!(to_literal(&stm_tokens[5 + 3]).text, "1000"); | ||
575 | // [let] [f] [=] [12E+99_f64] [;] | ||
576 | assert_eq!(to_literal(&stm_tokens[10 + 3]).text, "12E+99_f64"); | ||
577 | // [let] [s] [=] ["rust1"] [;] | ||
578 | assert_eq!(to_literal(&stm_tokens[15 + 3]).text, "\"rust1\""); | ||
579 | } | ||
580 | |||
581 | #[test] | ||
582 | fn test_two_idents() { | ||
583 | let rules = create_rules( | ||
584 | r#" | ||
585 | macro_rules! foo { | ||
586 | ($ i:ident, $ j:ident) => { | ||
587 | fn foo() { let a = $ i; let b = $j; } | ||
588 | } | ||
589 | } | ||
590 | "#, | ||
591 | ); | ||
592 | assert_expansion(&rules, "foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}"); | ||
593 | } | ||
594 | |||
595 | #[test] | ||
596 | fn test_tt_to_stmts() { | ||
597 | let rules = create_rules( | ||
598 | r#" | ||
599 | macro_rules! foo { | ||
600 | () => { | ||
601 | let a = 0; | ||
602 | a = 10 + 1; | ||
603 | a | ||
604 | } | ||
605 | } | ||
606 | "#, | ||
607 | ); | ||
608 | |||
609 | let expanded = expand(&rules, "foo!{}"); | ||
610 | let stmts = token_tree_to_macro_stmts(&expanded); | ||
611 | |||
612 | assert_eq!( | ||
613 | stmts.unwrap().syntax().debug_dump().trim(), | ||
614 | r#"MACRO_STMTS@[0; 15) | ||
615 | LET_STMT@[0; 7) | ||
616 | LET_KW@[0; 3) "let" | ||
617 | BIND_PAT@[3; 4) | ||
618 | NAME@[3; 4) | ||
619 | IDENT@[3; 4) "a" | ||
620 | EQ@[4; 5) "=" | ||
621 | LITERAL@[5; 6) | ||
622 | INT_NUMBER@[5; 6) "0" | ||
623 | SEMI@[6; 7) ";" | ||
624 | EXPR_STMT@[7; 14) | ||
625 | BIN_EXPR@[7; 13) | ||
626 | PATH_EXPR@[7; 8) | ||
627 | PATH@[7; 8) | ||
628 | PATH_SEGMENT@[7; 8) | ||
629 | NAME_REF@[7; 8) | ||
630 | IDENT@[7; 8) "a" | ||
631 | EQ@[8; 9) "=" | ||
632 | BIN_EXPR@[9; 13) | ||
633 | LITERAL@[9; 11) | ||
634 | INT_NUMBER@[9; 11) "10" | ||
635 | PLUS@[11; 12) "+" | ||
636 | LITERAL@[12; 13) | ||
637 | INT_NUMBER@[12; 13) "1" | ||
638 | SEMI@[13; 14) ";" | ||
639 | EXPR_STMT@[14; 15) | ||
640 | PATH_EXPR@[14; 15) | ||
641 | PATH@[14; 15) | ||
642 | PATH_SEGMENT@[14; 15) | ||
643 | NAME_REF@[14; 15) | ||
644 | IDENT@[14; 15) "a""#, | ||
645 | ); | ||
646 | } | ||
647 | |||
648 | // The following tests are port from intellij-rust directly | ||
649 | // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt | ||
650 | |||
651 | #[test] | ||
652 | fn test_path() { | ||
653 | let rules = create_rules( | ||
654 | r#" | ||
655 | macro_rules! foo { | ||
656 | ($ i:path) => { | ||
657 | fn foo() { let a = $ i; } | ||
658 | } | ||
659 | } | ||
660 | "#, | ||
661 | ); | ||
662 | assert_expansion(&rules, "foo! { foo }", "fn foo () {let a = foo ;}"); | ||
663 | assert_expansion( | ||
664 | &rules, | ||
665 | "foo! { bar::<u8>::baz::<u8> }", | ||
666 | "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}", | ||
667 | ); | ||
668 | } | ||
669 | |||
670 | #[test] | ||
671 | fn test_two_paths() { | ||
672 | let rules = create_rules( | ||
673 | r#" | ||
674 | macro_rules! foo { | ||
675 | ($ i:path, $ j:path) => { | ||
676 | fn foo() { let a = $ i; let b = $j; } | ||
677 | } | ||
678 | } | ||
679 | "#, | ||
680 | ); | ||
681 | assert_expansion(&rules, "foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}"); | ||
682 | } | ||
683 | |||
684 | #[test] | ||
685 | fn test_path_with_path() { | ||
686 | let rules = create_rules( | ||
687 | r#" | ||
688 | macro_rules! foo { | ||
689 | ($ i:path) => { | ||
690 | fn foo() { let a = $ i :: bar; } | ||
691 | } | ||
692 | } | ||
693 | "#, | ||
694 | ); | ||
695 | assert_expansion(&rules, "foo! { foo }", "fn foo () {let a = foo :: bar ;}"); | ||
696 | } | ||
697 | |||
698 | #[test] | ||
699 | fn test_expr() { | ||
700 | let rules = create_rules( | ||
701 | r#" | ||
702 | macro_rules! foo { | ||
703 | ($ i:expr) => { | ||
704 | fn bar() { $ i; } | ||
705 | } | ||
706 | } | ||
707 | "#, | ||
708 | ); | ||
709 | |||
710 | assert_expansion( | ||
711 | &rules, | ||
712 | "foo! { 2 + 2 * baz(3).quux() }", | ||
713 | "fn bar () {2 + 2 * baz (3) . quux () ;}", | ||
714 | ); | ||
715 | } | ||
716 | |||
717 | #[test] | ||
718 | fn test_expr_order() { | ||
719 | let rules = create_rules( | ||
720 | r#" | ||
721 | macro_rules! foo { | ||
722 | ($ i:expr) => { | ||
723 | fn bar() { $ i * 2; } | ||
724 | } | ||
725 | } | ||
726 | "#, | ||
727 | ); | ||
728 | |||
729 | assert_eq!( | ||
730 | expand_to_items(&rules, "foo! { 1 + 1 }").syntax().debug_dump().trim(), | ||
731 | r#"MACRO_ITEMS@[0; 15) | ||
732 | FN_DEF@[0; 15) | ||
733 | FN_KW@[0; 2) "fn" | ||
734 | NAME@[2; 5) | ||
735 | IDENT@[2; 5) "bar" | ||
736 | PARAM_LIST@[5; 7) | ||
737 | L_PAREN@[5; 6) "(" | ||
738 | R_PAREN@[6; 7) ")" | ||
739 | BLOCK@[7; 15) | ||
740 | L_CURLY@[7; 8) "{" | ||
741 | EXPR_STMT@[8; 14) | ||
742 | BIN_EXPR@[8; 13) | ||
743 | BIN_EXPR@[8; 11) | ||
744 | LITERAL@[8; 9) | ||
745 | INT_NUMBER@[8; 9) "1" | ||
746 | PLUS@[9; 10) "+" | ||
747 | LITERAL@[10; 11) | ||
748 | INT_NUMBER@[10; 11) "1" | ||
749 | STAR@[11; 12) "*" | ||
750 | LITERAL@[12; 13) | ||
751 | INT_NUMBER@[12; 13) "2" | ||
752 | SEMI@[13; 14) ";" | ||
753 | R_CURLY@[14; 15) "}""#, | ||
754 | ); | ||
755 | } | ||
756 | |||
757 | #[test] | ||
758 | fn test_last_expr() { | ||
759 | let rules = create_rules( | ||
760 | r#" | ||
761 | macro_rules! vec { | ||
762 | ($($item:expr),*) => { | ||
763 | { | ||
764 | let mut v = Vec::new(); | ||
765 | $( | ||
766 | v.push($item); | ||
767 | )* | ||
768 | v | ||
769 | } | ||
770 | }; | ||
771 | } | ||
772 | "#, | ||
773 | ); | ||
774 | assert_expansion( | ||
775 | &rules, | ||
776 | "vec!(1,2,3)", | ||
777 | "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}", | ||
778 | ); | ||
779 | } | ||
780 | |||
781 | #[test] | ||
782 | fn test_ty() { | ||
783 | let rules = create_rules( | ||
784 | r#" | ||
785 | macro_rules! foo { | ||
786 | ($ i:ty) => ( | ||
787 | fn bar() -> $ i { unimplemented!() } | ||
788 | ) | ||
789 | } | ||
790 | "#, | ||
791 | ); | ||
792 | assert_expansion( | ||
793 | &rules, | ||
794 | "foo! { Baz<u8> }", | ||
795 | "fn bar () -> Baz < u8 > {unimplemented ! ()}", | ||
796 | ); | ||
797 | } | ||
798 | |||
799 | #[test] | ||
800 | fn test_ty_with_complex_type() { | ||
801 | let rules = create_rules( | ||
802 | r#" | ||
803 | macro_rules! foo { | ||
804 | ($ i:ty) => ( | ||
805 | fn bar() -> $ i { unimplemented!() } | ||
806 | ) | ||
807 | } | ||
808 | "#, | ||
809 | ); | ||
810 | |||
811 | // Reference lifetime struct with generic type | ||
812 | assert_expansion( | ||
813 | &rules, | ||
814 | "foo! { &'a Baz<u8> }", | ||
815 | "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}", | ||
816 | ); | ||
817 | |||
818 | // extern "Rust" func type | ||
819 | assert_expansion( | ||
820 | &rules, | ||
821 | r#"foo! { extern "Rust" fn() -> Ret }"#, | ||
822 | r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#, | ||
823 | ); | ||
824 | } | ||
825 | |||
826 | #[test] | ||
827 | fn test_pat_() { | ||
828 | let rules = create_rules( | ||
829 | r#" | ||
830 | macro_rules! foo { | ||
831 | ($ i:pat) => { fn foo() { let $ i; } } | ||
832 | } | ||
833 | "#, | ||
834 | ); | ||
835 | assert_expansion(&rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); | ||
836 | } | ||
837 | |||
838 | #[test] | ||
839 | fn test_stmt() { | ||
840 | let rules = create_rules( | ||
841 | r#" | ||
842 | macro_rules! foo { | ||
843 | ($ i:stmt) => ( | ||
844 | fn bar() { $ i; } | ||
845 | ) | ||
846 | } | ||
847 | "#, | ||
848 | ); | ||
849 | assert_expansion(&rules, "foo! { 2 }", "fn bar () {2 ;}"); | ||
850 | assert_expansion(&rules, "foo! { let a = 0 }", "fn bar () {let a = 0 ;}"); | ||
851 | } | ||
852 | |||
853 | #[test] | ||
854 | fn test_single_item() { | ||
855 | let rules = create_rules( | ||
856 | r#" | ||
857 | macro_rules! foo { | ||
858 | ($ i:item) => ( | ||
859 | $ i | ||
860 | ) | ||
861 | } | ||
862 | "#, | ||
863 | ); | ||
864 | assert_expansion(&rules, "foo! {mod c {}}", "mod c {}"); | ||
865 | } | ||
866 | |||
867 | #[test] | ||
868 | fn test_all_items() { | ||
869 | let rules = create_rules( | ||
870 | r#" | ||
871 | macro_rules! foo { | ||
872 | ($ ($ i:item)*) => ($ ( | ||
873 | $ i | ||
874 | )*) | ||
875 | } | ||
876 | "#, | ||
877 | ); | ||
878 | assert_expansion(&rules, r#" | ||
879 | foo! { | ||
880 | extern crate a; | ||
881 | mod b; | ||
882 | mod c {} | ||
883 | use d; | ||
884 | const E: i32 = 0; | ||
885 | static F: i32 = 0; | ||
886 | impl G {} | ||
887 | struct H; | ||
888 | enum I { Foo } | ||
889 | trait J {} | ||
890 | fn h() {} | ||
891 | extern {} | ||
892 | type T = u8; | ||
893 | } | ||
894 | "#, r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#); | ||
895 | } | ||
896 | |||
897 | #[test] | ||
898 | fn test_block() { | ||
899 | let rules = create_rules( | ||
900 | r#" | ||
901 | macro_rules! foo { | ||
902 | ($ i:block) => { fn foo() $ i } | ||
903 | } | ||
904 | "#, | ||
905 | ); | ||
906 | assert_expansion(&rules, "foo! { { 1; } }", "fn foo () {1 ;}"); | ||
907 | } | ||
908 | |||
909 | #[test] | ||
910 | fn test_meta() { | ||
911 | let rules = create_rules( | ||
912 | r#" | ||
913 | macro_rules! foo { | ||
914 | ($ i:meta) => ( | ||
915 | #[$ i] | ||
916 | fn bar() {} | ||
917 | ) | ||
918 | } | ||
919 | "#, | ||
920 | ); | ||
921 | assert_expansion( | ||
922 | &rules, | ||
923 | r#"foo! { cfg(target_os = "windows") }"#, | ||
924 | r#"# [cfg (target_os = "windows")] fn bar () {}"#, | ||
925 | ); | ||
926 | } | ||
927 | |||
928 | #[test] | ||
929 | // fn test_tt_block() { | ||
930 | // let rules = create_rules( | ||
931 | // r#" | ||
932 | // macro_rules! foo { | ||
933 | // ($ i:tt) => { fn foo() $ i } | ||
934 | // } | ||
935 | // "#, | ||
936 | // ); | ||
937 | // assert_expansion(&rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); | ||
938 | // } | ||
939 | |||
940 | // #[test] | ||
941 | // fn test_tt_group() { | ||
942 | // let rules = create_rules( | ||
943 | // r#" | ||
944 | // macro_rules! foo { | ||
945 | // ($($ i:tt)*) => { $($ i)* } | ||
946 | // } | ||
947 | // "#, | ||
948 | // ); | ||
949 | // assert_expansion(&rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); | ||
950 | // } | ||
951 | #[test] | ||
952 | fn test_lifetime() { | ||
953 | let rules = create_rules( | ||
954 | r#" | ||
955 | macro_rules! foo { | ||
956 | ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } } | ||
957 | } | ||
958 | "#, | ||
959 | ); | ||
960 | assert_expansion(&rules, r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#); | ||
961 | } | ||
962 | |||
963 | #[test] | ||
964 | fn test_literal() { | ||
965 | let rules = create_rules( | ||
966 | r#" | ||
967 | macro_rules! foo { | ||
968 | ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; | ||
969 | } | ||
970 | "#, | ||
971 | ); | ||
972 | assert_expansion(&rules, r#"foo!(u8 0)"#, r#"const VALUE : u8 = 0 ;"#); | ||
973 | } | ||
974 | |||
975 | #[test] | ||
976 | fn test_vis() { | ||
977 | let rules = create_rules( | ||
978 | r#" | ||
979 | macro_rules! foo { | ||
980 | ($ vis:vis $ name:ident) => { $ vis fn $ name() {}}; | ||
981 | } | ||
982 | "#, | ||
983 | ); | ||
984 | assert_expansion(&rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#); | ||
985 | } | ||
986 | |||
987 | // The following tests are based on real world situations | ||
988 | #[test] | ||
989 | fn test_vec() { | ||
990 | let rules = create_rules( | ||
991 | r#" | ||
992 | macro_rules! vec { | ||
993 | ($($item:expr),*) => { | ||
994 | { | ||
995 | let mut v = Vec::new(); | ||
996 | $( | ||
997 | v.push($item); | ||
998 | )* | ||
999 | v | ||
1000 | } | ||
1001 | }; | ||
1002 | } | ||
1003 | "#, | ||
1004 | ); | ||
1005 | assert_expansion(&rules, r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#); | ||
1006 | assert_expansion( | ||
1007 | &rules, | ||
1008 | r#"vec![1u32,2]"#, | ||
1009 | r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, | ||
1010 | ); | ||
1011 | |||
1012 | assert_eq!( | ||
1013 | expand_to_expr(&rules, r#"vec![1u32,2]"#).syntax().debug_dump().trim(), | ||
1014 | r#"BLOCK_EXPR@[0; 45) | ||
1015 | BLOCK@[0; 45) | ||
1016 | L_CURLY@[0; 1) "{" | ||
1017 | LET_STMT@[1; 20) | ||
1018 | LET_KW@[1; 4) "let" | ||
1019 | BIND_PAT@[4; 8) | ||
1020 | MUT_KW@[4; 7) "mut" | ||
1021 | NAME@[7; 8) | ||
1022 | IDENT@[7; 8) "v" | ||
1023 | EQ@[8; 9) "=" | ||
1024 | CALL_EXPR@[9; 19) | ||
1025 | PATH_EXPR@[9; 17) | ||
1026 | PATH@[9; 17) | ||
1027 | PATH@[9; 12) | ||
1028 | PATH_SEGMENT@[9; 12) | ||
1029 | NAME_REF@[9; 12) | ||
1030 | IDENT@[9; 12) "Vec" | ||
1031 | COLONCOLON@[12; 14) "::" | ||
1032 | PATH_SEGMENT@[14; 17) | ||
1033 | NAME_REF@[14; 17) | ||
1034 | IDENT@[14; 17) "new" | ||
1035 | ARG_LIST@[17; 19) | ||
1036 | L_PAREN@[17; 18) "(" | ||
1037 | R_PAREN@[18; 19) ")" | ||
1038 | SEMI@[19; 20) ";" | ||
1039 | EXPR_STMT@[20; 33) | ||
1040 | METHOD_CALL_EXPR@[20; 32) | ||
1041 | PATH_EXPR@[20; 21) | ||
1042 | PATH@[20; 21) | ||
1043 | PATH_SEGMENT@[20; 21) | ||
1044 | NAME_REF@[20; 21) | ||
1045 | IDENT@[20; 21) "v" | ||
1046 | DOT@[21; 22) "." | ||
1047 | NAME_REF@[22; 26) | ||
1048 | IDENT@[22; 26) "push" | ||
1049 | ARG_LIST@[26; 32) | ||
1050 | L_PAREN@[26; 27) "(" | ||
1051 | LITERAL@[27; 31) | ||
1052 | INT_NUMBER@[27; 31) "1u32" | ||
1053 | R_PAREN@[31; 32) ")" | ||
1054 | SEMI@[32; 33) ";" | ||
1055 | EXPR_STMT@[33; 43) | ||
1056 | METHOD_CALL_EXPR@[33; 42) | ||
1057 | PATH_EXPR@[33; 34) | ||
1058 | PATH@[33; 34) | ||
1059 | PATH_SEGMENT@[33; 34) | ||
1060 | NAME_REF@[33; 34) | ||
1061 | IDENT@[33; 34) "v" | ||
1062 | DOT@[34; 35) "." | ||
1063 | NAME_REF@[35; 39) | ||
1064 | IDENT@[35; 39) "push" | ||
1065 | ARG_LIST@[39; 42) | ||
1066 | L_PAREN@[39; 40) "(" | ||
1067 | LITERAL@[40; 41) | ||
1068 | INT_NUMBER@[40; 41) "2" | ||
1069 | R_PAREN@[41; 42) ")" | ||
1070 | SEMI@[42; 43) ";" | ||
1071 | PATH_EXPR@[43; 44) | ||
1072 | PATH@[43; 44) | ||
1073 | PATH_SEGMENT@[43; 44) | ||
1074 | NAME_REF@[43; 44) | ||
1075 | IDENT@[43; 44) "v" | ||
1076 | R_CURLY@[44; 45) "}""# | ||
1077 | ); | ||
1078 | } | ||
1079 | |||
1080 | #[test] | ||
1081 | fn test_winapi_struct() { | ||
1082 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366 | ||
1083 | |||
1084 | let rules = create_rules( | ||
1085 | r#" | ||
1086 | macro_rules! STRUCT { | ||
1087 | ($(#[$attrs:meta])* struct $name:ident { | ||
1088 | $($field:ident: $ftype:ty,)+ | ||
1089 | }) => ( | ||
1090 | #[repr(C)] #[derive(Copy)] $(#[$attrs])* | ||
1091 | pub struct $name { | ||
1092 | $(pub $field: $ftype,)+ | ||
1093 | } | ||
1094 | impl Clone for $name { | ||
1095 | #[inline] | ||
1096 | fn clone(&self) -> $name { *self } | ||
1097 | } | ||
1098 | #[cfg(feature = "impl-default")] | ||
1099 | impl Default for $name { | ||
1100 | #[inline] | ||
1101 | fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } } | ||
1102 | } | ||
1103 | ); | ||
1104 | } | ||
1105 | "#, | ||
1106 | ); | ||
1107 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs | ||
1108 | assert_expansion(&rules, r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#, | ||
1109 | "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); | ||
1110 | assert_expansion(&rules, r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#, | ||
1111 | "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); | ||
1112 | } | ||
1113 | |||
1114 | #[test] | ||
1115 | fn test_int_base() { | ||
1116 | let rules = create_rules( | ||
1117 | r#" | ||
1118 | macro_rules! int_base { | ||
1119 | ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { | ||
1120 | #[stable(feature = "rust1", since = "1.0.0")] | ||
1121 | impl fmt::$Trait for $T { | ||
1122 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
1123 | $Radix.fmt_int(*self as $U, f) | ||
1124 | } | ||
1125 | } | ||
1126 | } | ||
1127 | } | ||
1128 | "#, | ||
1129 | ); | ||
1130 | |||
1131 | assert_expansion(&rules, r#" int_base!{Binary for isize as usize -> Binary}"#, | ||
1132 | "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}" | ||
1133 | ); | ||
1134 | } | ||
1135 | |||
1136 | #[test] | ||
1137 | fn test_generate_pattern_iterators() { | ||
1138 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs | ||
1139 | let rules = create_rules( | ||
1140 | r#" | ||
1141 | macro_rules! generate_pattern_iterators { | ||
1142 | { double ended; with $(#[$common_stability_attribute:meta])*, | ||
1143 | $forward_iterator:ident, | ||
1144 | $reverse_iterator:ident, $iterty:ty | ||
1145 | } => { | ||
1146 | fn foo(){} | ||
1147 | } | ||
1148 | } | ||
1149 | "#, | ||
1150 | ); | ||
1151 | |||
1152 | assert_expansion(&rules, r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str )"#, | ||
1153 | "fn foo () {}"); | ||
1154 | } | ||
1155 | |||
1156 | #[test] | ||
1157 | fn test_impl_fn_for_zst() { | ||
1158 | // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs | ||
1159 | let rules = create_rules( | ||
1160 | r#" | ||
1161 | macro_rules! impl_fn_for_zst { | ||
1162 | { $( $( #[$attr: meta] )* | ||
1163 | struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn = | ||
1164 | |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty | ||
1165 | $body: block; )+ | ||
1166 | } => { | ||
1167 | $( | ||
1168 | $( #[$attr] )* | ||
1169 | struct $Name; | ||
1170 | |||
1171 | impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name { | ||
1172 | #[inline] | ||
1173 | extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { | ||
1174 | $body | ||
1175 | } | ||
1176 | } | ||
1177 | |||
1178 | impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name { | ||
1179 | #[inline] | ||
1180 | extern "rust-call" fn call_mut( | ||
1181 | &mut self, | ||
1182 | ($( $arg, )*): ($( $ArgTy, )*) | ||
1183 | ) -> $ReturnTy { | ||
1184 | Fn::call(&*self, ($( $arg, )*)) | ||
1185 | } | ||
1186 | } | ||
1187 | |||
1188 | impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name { | ||
1189 | type Output = $ReturnTy; | ||
1190 | |||
1191 | #[inline] | ||
1192 | extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { | ||
1193 | Fn::call(&self, ($( $arg, )*)) | ||
1194 | } | ||
1195 | } | ||
1196 | )+ | ||
1197 | } | ||
1198 | } | ||
1199 | } | ||
1200 | "#, | ||
1201 | ); | ||
1202 | |||
1203 | assert_expansion(&rules, r#" | ||
1204 | impl_fn_for_zst ! { | ||
1205 | # [ derive ( Clone ) ] | ||
1206 | struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug { | ||
1207 | c . escape_debug_ext ( false ) | ||
1208 | } ; | ||
1209 | |||
1210 | # [ derive ( Clone ) ] | ||
1211 | struct CharEscapeUnicode impl Fn = | c : char | -> char :: EscapeUnicode { | ||
1212 | c . escape_unicode ( ) | ||
1213 | } ; | ||
1214 | # [ derive ( Clone ) ] | ||
1215 | struct CharEscapeDefault impl Fn = | c : char | -> char :: EscapeDefault { | ||
1216 | c . escape_default ( ) | ||
1217 | } ; | ||
1218 | } | ||
1219 | "#, | ||
1220 | "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"); | ||
1221 | } | ||
1222 | |||
1223 | #[test] | ||
1224 | fn test_impl_nonzero_fmt() { | ||
1225 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12 | ||
1226 | let rules = create_rules( | ||
1227 | r#" | ||
1228 | macro_rules! impl_nonzero_fmt { | ||
1229 | ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { | ||
1230 | fn foo() {} | ||
1231 | } | ||
1232 | } | ||
1233 | "#, | ||
1234 | ); | ||
1235 | |||
1236 | assert_expansion(&rules, r#"impl_nonzero_fmt ! { # [ stable ( feature = "nonzero" , since = "1.28.0" ) ] ( Debug , Display , Binary , Octal , LowerHex , UpperHex ) for NonZeroU8 }"#, | ||
1237 | "fn foo () {}"); | ||
1238 | } | ||
1239 | |||
1240 | #[test] | ||
1241 | fn test_cfg_if_items() { | ||
1242 | // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986 | ||
1243 | let rules = create_rules( | ||
1244 | r#" | ||
1245 | macro_rules! __cfg_if_items { | ||
1246 | (($($not:meta,)*) ; ) => {}; | ||
1247 | (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { | ||
1248 | __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } | ||
1249 | } | ||
1250 | } | ||
1251 | "#, | ||
1252 | ); | ||
1253 | |||
1254 | assert_expansion(&rules, r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#, | ||
1255 | "__cfg_if_items ! {(rustdoc , ) ; }"); | ||
1256 | } | ||
1257 | |||
1258 | #[test] | ||
1259 | fn test_cfg_if_main() { | ||
1260 | // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9 | ||
1261 | let rules = create_rules( | ||
1262 | r#" | ||
1263 | macro_rules! cfg_if { | ||
1264 | ($( | ||
1265 | if #[cfg($($meta:meta),*)] { $($it:item)* } | ||
1266 | ) else * else { | ||
1267 | $($it2:item)* | ||
1268 | }) => { | ||
1269 | __cfg_if_items! { | ||
1270 | () ; | ||
1271 | $( ( ($($meta),*) ($($it)*) ), )* | ||
1272 | ( () ($($it2)*) ), | ||
1273 | } | ||
1274 | } | ||
1275 | } | ||
1276 | "#, | ||
1277 | ); | ||
1278 | |||
1279 | assert_expansion(&rules, r#" | ||
1280 | cfg_if ! { | ||
1281 | if # [ cfg ( target_env = "msvc" ) ] { | ||
1282 | // no extra unwinder support needed | ||
1283 | } else if # [ cfg ( all ( target_arch = "wasm32" , not ( target_os = "emscripten" ) ) ) ] { | ||
1284 | // no unwinder on the system! | ||
1285 | } else { | ||
1286 | mod libunwind ; | ||
1287 | pub use libunwind :: * ; | ||
1288 | } | ||
1289 | } | ||
1290 | "#, | ||
1291 | "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); | ||
1292 | } | ||
1293 | } | ||