diff options
Diffstat (limited to 'crates/mbe/src')
-rw-r--r-- | crates/mbe/src/mbe_expander/matcher.rs | 40 | ||||
-rw-r--r-- | crates/mbe/src/parser.rs | 11 | ||||
-rw-r--r-- | crates/mbe/src/syntax_bridge.rs | 3 | ||||
-rw-r--r-- | crates/mbe/src/tests.rs | 64 |
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] |
764 | fn test_expr_with_attr() { | ||
765 | parse_macro( | ||
766 | r#" | ||
767 | macro_rules! m { | ||
768 | ($a:expr) => {0} | ||
769 | } | ||
770 | "#, | ||
771 | ) | ||
772 | .assert_expand_items("m!(#[allow(a)]())", "0"); | ||
773 | } | ||
774 | |||
775 | #[test] | ||
764 | fn test_ty() { | 776 | fn 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] |
1007 | fn 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] | ||
995 | fn test_underscore() { | 1023 | fn 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] |
1035 | fn test_underscore_not_greedily() { | ||
1036 | parse_macro( | ||
1037 | r#" | ||
1038 | macro_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#" | ||
1048 | macro_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] | ||
1058 | fn test_underscore_as_type() { | ||
1059 | parse_macro( | ||
1060 | r#" | ||
1061 | macro_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] | ||
1007 | fn test_vertical_bar_with_pat() { | 1071 | fn test_vertical_bar_with_pat() { |
1008 | parse_macro( | 1072 | parse_macro( |
1009 | r#" | 1073 | r#" |