diff options
Diffstat (limited to 'crates/ra_mbe/src/lib.rs')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 110 |
1 files changed, 87 insertions, 23 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index d2115bd67..9aad08db9 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -214,14 +214,15 @@ impl_froms!(TokenTree: Leaf, Subtree); | |||
214 | let tree = token_tree_to_macro_items(&expanded); | 214 | let tree = token_tree_to_macro_items(&expanded); |
215 | 215 | ||
216 | // Eat all white space by parse it back and forth | 216 | // Eat all white space by parse it back and forth |
217 | let expansion = ast::SourceFile::parse(expansion); | 217 | // Because $crate will seperate in two token , will do some special treatment here |
218 | let expansion = expansion.replace("$crate", "C_C__C"); | ||
219 | let expansion = ast::SourceFile::parse(&expansion); | ||
218 | let expansion = syntax_node_to_token_tree(expansion.syntax()).unwrap().0; | 220 | let expansion = syntax_node_to_token_tree(expansion.syntax()).unwrap().0; |
219 | let file = token_tree_to_macro_items(&expansion); | 221 | let file = token_tree_to_macro_items(&expansion); |
222 | let file = file.unwrap().syntax().debug_dump().trim().to_string(); | ||
223 | let file = file.replace("C_C__C", "$crate"); | ||
220 | 224 | ||
221 | assert_eq!( | 225 | assert_eq!(tree.unwrap().syntax().debug_dump().trim(), file,); |
222 | tree.unwrap().syntax().debug_dump().trim(), | ||
223 | file.unwrap().syntax().debug_dump().trim() | ||
224 | ); | ||
225 | } | 226 | } |
226 | 227 | ||
227 | #[test] | 228 | #[test] |
@@ -348,7 +349,36 @@ impl_froms!(TokenTree: Leaf, Subtree); | |||
348 | } | 349 | } |
349 | 350 | ||
350 | #[test] | 351 | #[test] |
351 | fn expand_to_item_list() { | 352 | fn test_match_group_empty_fixed_token() { |
353 | let rules = create_rules( | ||
354 | r#" | ||
355 | macro_rules! foo { | ||
356 | ($ ($ i:ident)* #abc) => ( fn baz { $ ( | ||
357 | $ i (); | ||
358 | )*} ); | ||
359 | } | ||
360 | "#, | ||
361 | ); | ||
362 | |||
363 | assert_expansion(&rules, "foo! {#abc}", "fn baz {}"); | ||
364 | } | ||
365 | |||
366 | #[test] | ||
367 | fn test_match_group_in_subtree() { | ||
368 | let rules = create_rules( | ||
369 | r#" | ||
370 | macro_rules! foo { | ||
371 | (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ ( | ||
372 | $ i (); | ||
373 | )*} ); | ||
374 | }"#, | ||
375 | ); | ||
376 | |||
377 | assert_expansion(&rules, "foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}"); | ||
378 | } | ||
379 | |||
380 | #[test] | ||
381 | fn test_expand_to_item_list() { | ||
352 | let rules = create_rules( | 382 | let rules = create_rules( |
353 | " | 383 | " |
354 | macro_rules! structs { | 384 | macro_rules! structs { |
@@ -401,7 +431,7 @@ MACRO_ITEMS@[0; 40) | |||
401 | } | 431 | } |
402 | 432 | ||
403 | #[test] | 433 | #[test] |
404 | fn expand_literals_to_token_tree() { | 434 | fn test_expand_literals_to_token_tree() { |
405 | fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree { | 435 | fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree { |
406 | if let tt::TokenTree::Subtree(subtree) = tt { | 436 | if let tt::TokenTree::Subtree(subtree) = tt { |
407 | return &subtree; | 437 | return &subtree; |
@@ -763,30 +793,29 @@ MACRO_ITEMS@[0; 40) | |||
763 | ); | 793 | ); |
764 | } | 794 | } |
765 | 795 | ||
766 | // #[test] | 796 | #[test] |
767 | // fn test_tt_block() { | 797 | // fn test_tt_block() { |
768 | // let rules = create_rules( | 798 | // let rules = create_rules( |
769 | // r#" | 799 | // r#" |
770 | // macro_rules! foo { | 800 | // macro_rules! foo { |
771 | // ($ i:tt) => { fn foo() $ i } | 801 | // ($ i:tt) => { fn foo() $ i } |
772 | // } | 802 | // } |
773 | // "#, | 803 | // "#, |
774 | // ); | 804 | // ); |
775 | // assert_expansion(&rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); | 805 | // assert_expansion(&rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); |
776 | // } | 806 | // } |
777 | 807 | ||
778 | // #[test] | 808 | // #[test] |
779 | // fn test_tt_group() { | 809 | // fn test_tt_group() { |
780 | // let rules = create_rules( | 810 | // let rules = create_rules( |
781 | // r#" | 811 | // r#" |
782 | // macro_rules! foo { | 812 | // macro_rules! foo { |
783 | // ($($ i:tt)*) => { $($ i)* } | 813 | // ($($ i:tt)*) => { $($ i)* } |
784 | // } | 814 | // } |
785 | // "#, | 815 | // "#, |
786 | // ); | 816 | // ); |
787 | // assert_expansion(&rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); | 817 | // assert_expansion(&rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); |
788 | // } | 818 | // } |
789 | |||
790 | #[test] | 819 | #[test] |
791 | fn test_lifetime() { | 820 | fn test_lifetime() { |
792 | let rules = create_rules( | 821 | let rules = create_rules( |
@@ -822,4 +851,39 @@ MACRO_ITEMS@[0; 40) | |||
822 | ); | 851 | ); |
823 | assert_expansion(&rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#); | 852 | assert_expansion(&rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#); |
824 | } | 853 | } |
854 | |||
855 | // The following tests are based on real world situations | ||
856 | #[test] | ||
857 | fn test_winapi_struct() { | ||
858 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366 | ||
859 | |||
860 | let rules = create_rules( | ||
861 | r#" | ||
862 | macro_rules! STRUCT { | ||
863 | ($(#[$attrs:meta])* struct $name:ident { | ||
864 | $($field:ident: $ftype:ty,)+ | ||
865 | }) => ( | ||
866 | #[repr(C)] #[derive(Copy)] $(#[$attrs])* | ||
867 | pub struct $name { | ||
868 | $(pub $field: $ftype,)+ | ||
869 | } | ||
870 | impl Clone for $name { | ||
871 | #[inline] | ||
872 | fn clone(&self) -> $name { *self } | ||
873 | } | ||
874 | #[cfg(feature = "impl-default")] | ||
875 | impl Default for $name { | ||
876 | #[inline] | ||
877 | fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } } | ||
878 | } | ||
879 | ); | ||
880 | } | ||
881 | "#, | ||
882 | ); | ||
883 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs | ||
884 | assert_expansion(&rules, r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#, | ||
885 | "# [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 ()}}}"); | ||
886 | assert_expansion(&rules, r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#, | ||
887 | "# [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 ()}}}"); | ||
888 | } | ||
825 | } | 889 | } |