Unnamed repository; edit this file 'description' to name the repository.
Handle `macro_rules!` as MACRO_CALL
It's a call of the third token is neither IDENT or TRY
Johann Hemmann 2024-01-17
parent 2b02df2 · commit 5916da2
-rw-r--r--crates/parser/src/grammar/items.rs26
-rw-r--r--crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast25
-rw-r--r--crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs2
-rw-r--r--crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast84
-rw-r--r--crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs7
5 files changed, 142 insertions, 2 deletions
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
index 34fd3420f1..5050cad5e8 100644
--- a/crates/parser/src/grammar/items.rs
+++ b/crates/parser/src/grammar/items.rs
@@ -58,7 +58,21 @@ pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) {
Err(m) => m,
};
- if paths::is_use_path_start(p) {
+ // test macro_rules_as_macro_name
+ // macro_rules! {}
+ // macro_rules! {};
+ // macro_rules! ();
+ // macro_rules! [];
+ // fn main() {
+ // let foo = macro_rules!();
+ // }
+
+ // test_err macro_rules_as_macro_name
+ // macro_rules! ()
+ // macro_rules! []
+ if paths::is_use_path_start(p)
+ || (p.at_contextual_kw(T![macro_rules]) && p.nth_at(1, BANG) && !p.nth_at(2, IDENT))
+ {
match macro_call(p) {
BlockLike::Block => (),
BlockLike::NotBlock => {
@@ -228,7 +242,15 @@ fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marke
IDENT if p.at_contextual_kw(T![union]) && p.nth(1) == IDENT => adt::union(p, m),
T![macro] => macro_def(p, m),
- IDENT if p.at_contextual_kw(T![macro_rules]) && p.nth(1) == BANG => macro_rules(p, m),
+ // check if current token is "macro_rules" followed by "!" followed by an identifier or "try"
+ // try is keyword since the 2018 edition and the parser is not edition aware (yet!)
+ IDENT
+ if p.at_contextual_kw(T![macro_rules])
+ && p.nth_at(1, BANG)
+ && (p.nth_at(2, IDENT) || p.nth_at(2, T![try])) =>
+ {
+ macro_rules(p, m)
+ }
T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m),
T![static] if (la == IDENT || la == T![_] || la == T![mut]) => consts::static_(p, m),
diff --git a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast
new file mode 100644
index 0000000000..d5ab611629
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rast
@@ -0,0 +1,25 @@
+SOURCE_FILE
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_BRACK "["
+ R_BRACK "]"
+ WHITESPACE "\n"
+error 15: expected SEMICOLON
+error 31: expected SEMICOLON
diff --git a/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs
new file mode 100644
index 0000000000..be633aa699
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0026_macro_rules_as_macro_name.rs
@@ -0,0 +1,2 @@
+macro_rules! ()
+macro_rules! []
diff --git a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast
new file mode 100644
index 0000000000..c3e0f8a5e0
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rast
@@ -0,0 +1,84 @@
+SOURCE_FILE
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_BRACK "["
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_rules"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs
new file mode 100644
index 0000000000..2ab949b636
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0208_macro_rules_as_macro_name.rs
@@ -0,0 +1,7 @@
+macro_rules! {}
+macro_rules! {};
+macro_rules! ();
+macro_rules! [];
+fn main() {
+ let foo = macro_rules!();
+}