aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src')
-rw-r--r--crates/mbe/src/mbe_expander/matcher.rs40
-rw-r--r--crates/mbe/src/parser.rs11
-rw-r--r--crates/mbe/src/syntax_bridge.rs3
-rw-r--r--crates/mbe/src/tests.rs64
4 files changed, 94 insertions, 24 deletions
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
index 7aeef7be5..44722c0f1 100644
--- a/crates/mbe/src/mbe_expander/matcher.rs
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -240,26 +240,26 @@ impl<'a> TtIter<'a> {
240 let tt3 = self.next().unwrap().clone(); 240 let tt3 = self.next().unwrap().clone();
241 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into()) 241 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
242 } 242 }
243 ('-', '=', None) 243 ('-', '=', _)
244 | ('-', '>', None) 244 | ('-', '>', _)
245 | (':', ':', None) 245 | (':', ':', _)
246 | ('!', '=', None) 246 | ('!', '=', _)
247 | ('.', '.', None) 247 | ('.', '.', _)
248 | ('*', '=', None) 248 | ('*', '=', _)
249 | ('/', '=', None) 249 | ('/', '=', _)
250 | ('&', '&', None) 250 | ('&', '&', _)
251 | ('&', '=', None) 251 | ('&', '=', _)
252 | ('%', '=', None) 252 | ('%', '=', _)
253 | ('^', '=', None) 253 | ('^', '=', _)
254 | ('+', '=', None) 254 | ('+', '=', _)
255 | ('<', '<', None) 255 | ('<', '<', _)
256 | ('<', '=', None) 256 | ('<', '=', _)
257 | ('=', '=', None) 257 | ('=', '=', _)
258 | ('=', '>', None) 258 | ('=', '>', _)
259 | ('>', '=', None) 259 | ('>', '=', _)
260 | ('>', '>', None) 260 | ('>', '>', _)
261 | ('|', '=', None) 261 | ('|', '=', _)
262 | ('|', '|', None) => { 262 | ('|', '|', _) => {
263 let tt2 = self.next().unwrap().clone(); 263 let tt2 = self.next().unwrap().clone();
264 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into()) 264 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
265 } 265 }
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index c3fdd4040..d681905f5 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -101,8 +101,15 @@ fn next_op<'a>(
101 Op::Repeat { subtree, separator, kind } 101 Op::Repeat { subtree, separator, kind }
102 } 102 }
103 tt::TokenTree::Leaf(leaf) => match leaf { 103 tt::TokenTree::Leaf(leaf) => match leaf {
104 tt::Leaf::Punct(_) => { 104 tt::Leaf::Punct(punct) => {
105 return Err(ExpandError::UnexpectedToken); 105 static UNDERSCORE: SmolStr = SmolStr::new_inline("_");
106
107 if punct.char != '_' {
108 return Err(ExpandError::UnexpectedToken);
109 }
110 let name = &UNDERSCORE;
111 let kind = eat_fragment_kind(src, mode)?;
112 Op::Var { name, kind }
106 } 113 }
107 tt::Leaf::Ident(ident) => { 114 tt::Leaf::Ident(ident) => {
108 let name = &ident.text; 115 let name = &ident.text;
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 2bec7fd49..265c0d63d 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -313,7 +313,7 @@ trait TokenConvertor {
313 return; 313 return;
314 } 314 }
315 315
316 result.push(if k.is_punct() && k != UNDERSCORE { 316 result.push(if k.is_punct() {
317 assert_eq!(range.len(), TextSize::of('.')); 317 assert_eq!(range.len(), TextSize::of('.'));
318 let delim = match k { 318 let delim = match k {
319 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), 319 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
@@ -378,7 +378,6 @@ trait TokenConvertor {
378 let leaf: tt::Leaf = match k { 378 let leaf: tt::Leaf = match k {
379 T![true] | T![false] => make_leaf!(Ident), 379 T![true] | T![false] => make_leaf!(Ident),
380 IDENT => make_leaf!(Ident), 380 IDENT => make_leaf!(Ident),
381 UNDERSCORE => make_leaf!(Ident),
382 k if k.is_keyword() => make_leaf!(Ident), 381 k if k.is_keyword() => make_leaf!(Ident),
383 k if k.is_literal() => make_leaf!(Literal), 382 k if k.is_literal() => make_leaf!(Literal),
384 LIFETIME_IDENT => { 383 LIFETIME_IDENT => {
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 451fa1456..1d9afb4fb 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -761,6 +761,18 @@ fn test_last_expr() {
761} 761}
762 762
763#[test] 763#[test]
764fn test_expr_with_attr() {
765 parse_macro(
766 r#"
767macro_rules! m {
768 ($a:expr) => {0}
769}
770"#,
771 )
772 .assert_expand_items("m!(#[allow(a)]())", "0");
773}
774
775#[test]
764fn test_ty() { 776fn test_ty() {
765 parse_macro( 777 parse_macro(
766 r#" 778 r#"
@@ -992,6 +1004,22 @@ fn test_tt_composite2() {
992} 1004}
993 1005
994#[test] 1006#[test]
1007fn test_tt_with_composite_without_space() {
1008 parse_macro(
1009 r#"
1010 macro_rules! foo {
1011 ($ op:tt, $j:path) => (
1012 0
1013 )
1014 }
1015"#,
1016 )
1017 // Test macro input without any spaces
1018 // See https://github.com/rust-analyzer/rust-analyzer/issues/6692
1019 .assert_expand_items("foo!(==,Foo::Bool)", "0");
1020}
1021
1022#[test]
995fn test_underscore() { 1023fn test_underscore() {
996 parse_macro( 1024 parse_macro(
997 r#" 1025 r#"
@@ -1004,6 +1032,42 @@ fn test_underscore() {
1004} 1032}
1005 1033
1006#[test] 1034#[test]
1035fn test_underscore_not_greedily() {
1036 parse_macro(
1037 r#"
1038macro_rules! q {
1039 ($($a:ident)* _) => {0};
1040}
1041"#,
1042 )
1043 // `_` overlaps with `$a:ident` but rustc matches it under the `_` token
1044 .assert_expand_items(r#"q![a b c d _]"#, r#"0"#);
1045
1046 parse_macro(
1047 r#"
1048macro_rules! q {
1049 ($($a:expr => $b:ident)* _ => $c:expr) => {0};
1050}
1051"#,
1052 )
1053 // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`
1054 .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#);
1055}
1056
1057#[test]
1058fn test_underscore_as_type() {
1059 parse_macro(
1060 r#"
1061macro_rules! q {
1062 ($a:ty) => {0};
1063}
1064"#,
1065 )
1066 // Underscore is a type
1067 .assert_expand_items(r#"q![_]"#, r#"0"#);
1068}
1069
1070#[test]
1007fn test_vertical_bar_with_pat() { 1071fn test_vertical_bar_with_pat() {
1008 parse_macro( 1072 parse_macro(
1009 r#" 1073 r#"