about summary refs log tree commit diff
diff options
context:
space:
mode:
-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 34fd3420f1c..5050cad5e81 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 00000000000..d5ab611629c
--- /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 00000000000..be633aa6990
--- /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 00000000000..c3e0f8a5e02
--- /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 00000000000..2ab949b6363
--- /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!();
+}