aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src')
-rw-r--r--crates/mbe/src/parser.rs11
-rw-r--r--crates/mbe/src/syntax_bridge.rs3
-rw-r--r--crates/mbe/src/tests.rs36
3 files changed, 46 insertions, 4 deletions
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 6cd0ed205..9958a33a0 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -1020,6 +1020,42 @@ fn test_underscore() {
1020} 1020}
1021 1021
1022#[test] 1022#[test]
1023fn test_underscore_not_greedily() {
1024 parse_macro(
1025 r#"
1026macro_rules! q {
1027 ($($a:ident)* _) => {0};
1028}
1029"#,
1030 )
1031 // `_` overlaps with `$a:ident` but rustc matches it under the `_` token
1032 .assert_expand_items(r#"q![a b c d _]"#, r#"0"#);
1033
1034 parse_macro(
1035 r#"
1036macro_rules! q {
1037 ($($a:expr => $b:ident)* _ => $c:expr) => {0};
1038}
1039"#,
1040 )
1041 // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`
1042 .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#);
1043}
1044
1045#[test]
1046fn test_underscore_as_type() {
1047 parse_macro(
1048 r#"
1049macro_rules! q {
1050 ($a:ty) => {0};
1051}
1052"#,
1053 )
1054 // Underscore is a type
1055 .assert_expand_items(r#"q![_]"#, r#"0"#);
1056}
1057
1058#[test]
1023fn test_vertical_bar_with_pat() { 1059fn test_vertical_bar_with_pat() {
1024 parse_macro( 1060 parse_macro(
1025 r#" 1061 r#"