aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_mbe/src/lib.rs86
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs66
-rw-r--r--crates/ra_parser/src/grammar.rs26
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs44
-rw-r--r--crates/ra_parser/src/lib.rs8
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs4
-rw-r--r--crates/ra_syntax/src/ast/generated.rs66
-rw-r--r--crates/ra_syntax/src/grammar.ron15
8 files changed, 295 insertions, 20 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 8d5008d20..9d4744838 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -37,9 +37,19 @@ pub enum ExpandError {
37 NoMatchingRule, 37 NoMatchingRule,
38 UnexpectedToken, 38 UnexpectedToken,
39 BindingError(String), 39 BindingError(String),
40 ConversionError,
40} 41}
41 42
42pub use crate::syntax_bridge::{ast_to_token_tree, token_tree_to_ast_item_list, syntax_node_to_token_tree}; 43pub use crate::syntax_bridge::{
44 ast_to_token_tree,
45 token_tree_to_ast_item_list,
46 syntax_node_to_token_tree,
47 token_tree_to_expr,
48 token_tree_to_pat,
49 token_tree_to_ty,
50 token_tree_to_macro_items,
51 token_tree_to_macro_stmts,
52};
43 53
44/// This struct contains AST for a single `macro_rules` definition. What might 54/// This struct contains AST for a single `macro_rules` definition. What might
45/// be very confusing is that AST has almost exactly the same shape as 55/// be very confusing is that AST has almost exactly the same shape as
@@ -192,23 +202,26 @@ impl_froms!(TokenTree: Leaf, Subtree);
192 pub(crate) fn expand_to_syntax( 202 pub(crate) fn expand_to_syntax(
193 rules: &MacroRules, 203 rules: &MacroRules,
194 invocation: &str, 204 invocation: &str,
195 ) -> ra_syntax::TreeArc<ast::SourceFile> { 205 ) -> ra_syntax::TreeArc<ast::MacroItems> {
196 let expanded = expand(rules, invocation); 206 let expanded = expand(rules, invocation);
197 token_tree_to_ast_item_list(&expanded) 207 token_tree_to_macro_items(&expanded).unwrap()
198 } 208 }
199 209
200 pub(crate) fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) { 210 pub(crate) fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) {
201 let expanded = expand(rules, invocation); 211 let expanded = expand(rules, invocation);
202 assert_eq!(expanded.to_string(), expansion); 212 assert_eq!(expanded.to_string(), expansion);
203 213
204 let tree = token_tree_to_ast_item_list(&expanded); 214 let tree = token_tree_to_macro_items(&expanded);
205 215
206 // Eat all white space by parse it back and forth 216 // Eat all white space by parse it back and forth
207 let expansion = ast::SourceFile::parse(expansion); 217 let expansion = ast::SourceFile::parse(expansion);
208 let expansion = syntax_node_to_token_tree(expansion.syntax()).unwrap().0; 218 let expansion = syntax_node_to_token_tree(expansion.syntax()).unwrap().0;
209 let file = token_tree_to_ast_item_list(&expansion); 219 let file = token_tree_to_macro_items(&expansion);
210 220
211 assert_eq!(tree.syntax().debug_dump().trim(), file.syntax().debug_dump().trim()); 221 assert_eq!(
222 tree.unwrap().syntax().debug_dump().trim(),
223 file.unwrap().syntax().debug_dump().trim()
224 );
212 } 225 }
213 226
214 #[test] 227 #[test]
@@ -346,11 +359,11 @@ impl_froms!(TokenTree: Leaf, Subtree);
346 ", 359 ",
347 ); 360 );
348 let expansion = expand(&rules, "structs!(Foo, Bar)"); 361 let expansion = expand(&rules, "structs!(Foo, Bar)");
349 let tree = token_tree_to_ast_item_list(&expansion); 362 let tree = token_tree_to_macro_items(&expansion);
350 assert_eq!( 363 assert_eq!(
351 tree.syntax().debug_dump().trim(), 364 tree.unwrap().syntax().debug_dump().trim(),
352 r#" 365 r#"
353SOURCE_FILE@[0; 40) 366MACRO_ITEMS@[0; 40)
354 STRUCT_DEF@[0; 20) 367 STRUCT_DEF@[0; 20)
355 STRUCT_KW@[0; 6) "struct" 368 STRUCT_KW@[0; 6) "struct"
356 NAME@[6; 9) 369 NAME@[6; 9)
@@ -444,6 +457,59 @@ SOURCE_FILE@[0; 40)
444 assert_expansion(&rules, "foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}"); 457 assert_expansion(&rules, "foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
445 } 458 }
446 459
460 #[test]
461 fn test_tt_to_stmts() {
462 let rules = create_rules(
463 r#"
464 macro_rules! foo {
465 () => {
466 let a = 0;
467 a = 10 + 1;
468 a
469 }
470 }
471"#,
472 );
473
474 let expanded = expand(&rules, "foo!{}");
475 let stmts = token_tree_to_macro_stmts(&expanded);
476
477 assert_eq!(
478 stmts.unwrap().syntax().debug_dump().trim(),
479 r#"MACRO_STMTS@[0; 15)
480 LET_STMT@[0; 7)
481 LET_KW@[0; 3) "let"
482 BIND_PAT@[3; 4)
483 NAME@[3; 4)
484 IDENT@[3; 4) "a"
485 EQ@[4; 5) "="
486 LITERAL@[5; 6)
487 INT_NUMBER@[5; 6) "0"
488 SEMI@[6; 7) ";"
489 EXPR_STMT@[7; 14)
490 BIN_EXPR@[7; 13)
491 PATH_EXPR@[7; 8)
492 PATH@[7; 8)
493 PATH_SEGMENT@[7; 8)
494 NAME_REF@[7; 8)
495 IDENT@[7; 8) "a"
496 EQ@[8; 9) "="
497 BIN_EXPR@[9; 13)
498 LITERAL@[9; 11)
499 INT_NUMBER@[9; 11) "10"
500 PLUS@[11; 12) "+"
501 LITERAL@[12; 13)
502 INT_NUMBER@[12; 13) "1"
503 SEMI@[13; 14) ";"
504 EXPR_STMT@[14; 15)
505 PATH_EXPR@[14; 15)
506 PATH@[14; 15)
507 PATH_SEGMENT@[14; 15)
508 NAME_REF@[14; 15)
509 IDENT@[14; 15) "a""#,
510 );
511 }
512
447 // The following tests are port from intellij-rust directly 513 // The following tests are port from intellij-rust directly
448 // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt 514 // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
449 515
@@ -527,7 +593,7 @@ SOURCE_FILE@[0; 40)
527 593
528 assert_eq!( 594 assert_eq!(
529 expand_to_syntax(&rules, "foo! { 1 + 1 }").syntax().debug_dump().trim(), 595 expand_to_syntax(&rules, "foo! { 1 + 1 }").syntax().debug_dump().trim(),
530 r#"SOURCE_FILE@[0; 15) 596 r#"MACRO_ITEMS@[0; 15)
531 FN_DEF@[0; 15) 597 FN_DEF@[0; 15)
532 FN_KW@[0; 2) "fn" 598 FN_KW@[0; 2) "fn"
533 NAME@[2; 5) 599 NAME@[2; 5)
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 28ded7870..5844d3f12 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -5,6 +5,7 @@ use ra_syntax::{
5}; 5};
6 6
7use crate::subtree_source::{SubtreeTokenSource, Querier}; 7use crate::subtree_source::{SubtreeTokenSource, Querier};
8use crate::ExpandError;
8 9
9/// Maps `tt::TokenId` to the relative range of the original token. 10/// Maps `tt::TokenId` to the relative range of the original token.
10#[derive(Default)] 11#[derive(Default)]
@@ -30,6 +31,71 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke
30 Some((tt, token_map)) 31 Some((tt, token_map))
31} 32}
32 33
34// The following items are what `rustc` macro can be parsed into :
35// link: https://github.com/rust-lang/rust/blob/9ebf47851a357faa4cd97f4b1dc7835f6376e639/src/libsyntax/ext/expand.rs#L141
36// * Expr(P<ast::Expr>) -> token_tree_to_expr
37// * Pat(P<ast::Pat>) -> token_tree_to_pat
38// * Ty(P<ast::Ty>) -> token_tree_to_ty
39// * Stmts(SmallVec<[ast::Stmt; 1]>) -> token_tree_to_stmts
40// * Items(SmallVec<[P<ast::Item>; 1]>) -> token_tree_to_items
41//
42// * TraitItems(SmallVec<[ast::TraitItem; 1]>)
43// * ImplItems(SmallVec<[ast::ImplItem; 1]>)
44// * ForeignItems(SmallVec<[ast::ForeignItem; 1]>
45//
46//
47
48/// Parses the token tree (result of macro expansion) to an expression
49pub fn token_tree_to_expr(tt: &tt::Subtree) -> Result<TreeArc<ast::Expr>, ExpandError> {
50 let token_source = SubtreeTokenSource::new(tt);
51 let mut tree_sink = TtTreeSink::new(token_source.querier());
52 ra_parser::parse_expr(&token_source, &mut tree_sink);
53 let syntax = tree_sink.inner.finish();
54 ast::Expr::cast(&syntax)
55 .map(|m| m.to_owned())
56 .ok_or_else(|| crate::ExpandError::ConversionError)
57}
58
59/// Parses the token tree (result of macro expansion) to a Pattern
60pub fn token_tree_to_pat(tt: &tt::Subtree) -> Result<TreeArc<ast::Pat>, ExpandError> {
61 let token_source = SubtreeTokenSource::new(tt);
62 let mut tree_sink = TtTreeSink::new(token_source.querier());
63 ra_parser::parse_pat(&token_source, &mut tree_sink);
64 let syntax = tree_sink.inner.finish();
65 ast::Pat::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
66}
67
68/// Parses the token tree (result of macro expansion) to a Type
69pub fn token_tree_to_ty(tt: &tt::Subtree) -> Result<TreeArc<ast::TypeRef>, ExpandError> {
70 let token_source = SubtreeTokenSource::new(tt);
71 let mut tree_sink = TtTreeSink::new(token_source.querier());
72 ra_parser::parse_ty(&token_source, &mut tree_sink);
73 let syntax = tree_sink.inner.finish();
74 ast::TypeRef::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
75}
76
77/// Parses the token tree (result of macro expansion) as a sequence of stmts
78pub fn token_tree_to_macro_stmts(
79 tt: &tt::Subtree,
80) -> Result<TreeArc<ast::MacroStmts>, ExpandError> {
81 let token_source = SubtreeTokenSource::new(tt);
82 let mut tree_sink = TtTreeSink::new(token_source.querier());
83 ra_parser::parse_macro_stmts(&token_source, &mut tree_sink);
84 let syntax = tree_sink.inner.finish();
85 ast::MacroStmts::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
86}
87
88/// Parses the token tree (result of macro expansion) as a sequence of items
89pub fn token_tree_to_macro_items(
90 tt: &tt::Subtree,
91) -> Result<TreeArc<ast::MacroItems>, ExpandError> {
92 let token_source = SubtreeTokenSource::new(tt);
93 let mut tree_sink = TtTreeSink::new(token_source.querier());
94 ra_parser::parse_macro_items(&token_source, &mut tree_sink);
95 let syntax = tree_sink.inner.finish();
96 ast::MacroItems::cast(&syntax).map(|m| m.to_owned()).ok_or_else(|| ExpandError::ConversionError)
97}
98
33/// Parses the token tree (result of macro expansion) as a sequence of items 99/// Parses the token tree (result of macro expansion) as a sequence of items
34pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> TreeArc<ast::SourceFile> { 100pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> TreeArc<ast::SourceFile> {
35 let token_source = SubtreeTokenSource::new(tt); 101 let token_source = SubtreeTokenSource::new(tt);
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index f8ed1299a..e1762633e 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -49,6 +49,27 @@ pub(crate) fn root(p: &mut Parser) {
49 m.complete(p, SOURCE_FILE); 49 m.complete(p, SOURCE_FILE);
50} 50}
51 51
52pub(crate) fn macro_items(p: &mut Parser) {
53 let m = p.start();
54 items::mod_contents(p, false);
55 m.complete(p, MACRO_ITEMS);
56}
57
58pub(crate) fn macro_stmts(p: &mut Parser) {
59 let m = p.start();
60
61 while !p.at(EOF) {
62 if p.current() == SEMI {
63 p.bump();
64 continue;
65 }
66
67 expressions::stmt(p, expressions::StmtWithSemi::Optional);
68 }
69
70 m.complete(p, MACRO_STMTS);
71}
72
52pub(crate) fn path(p: &mut Parser) { 73pub(crate) fn path(p: &mut Parser) {
53 paths::type_path(p); 74 paths::type_path(p);
54} 75}
@@ -66,6 +87,11 @@ pub(crate) fn pattern(p: &mut Parser) {
66} 87}
67 88
68pub(crate) fn stmt(p: &mut Parser, with_semi: bool) { 89pub(crate) fn stmt(p: &mut Parser, with_semi: bool) {
90 let with_semi = match with_semi {
91 true => expressions::StmtWithSemi::Yes,
92 false => expressions::StmtWithSemi::No,
93 };
94
69 expressions::stmt(p, with_semi) 95 expressions::stmt(p, with_semi)
70} 96}
71 97
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 06f2b45b1..8df9035e9 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -4,6 +4,12 @@ pub(crate) use self::atom::match_arm_list;
4pub(super) use self::atom::{literal, LITERAL_FIRST}; 4pub(super) use self::atom::{literal, LITERAL_FIRST};
5use super::*; 5use super::*;
6 6
7pub(super) enum StmtWithSemi {
8 Yes,
9 No,
10 Optional,
11}
12
7const EXPR_FIRST: TokenSet = LHS_FIRST; 13const EXPR_FIRST: TokenSet = LHS_FIRST;
8 14
9pub(super) fn expr(p: &mut Parser) -> BlockLike { 15pub(super) fn expr(p: &mut Parser) -> BlockLike {
@@ -48,7 +54,7 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
48 } 54 }
49} 55}
50 56
51pub(super) fn stmt(p: &mut Parser, with_semi: bool) { 57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
52 // test block_items 58 // test block_items
53 // fn a() { fn b() {} } 59 // fn a() { fn b() {} }
54 let m = p.start(); 60 let m = p.start();
@@ -111,13 +117,23 @@ pub(super) fn stmt(p: &mut Parser, with_semi: bool) {
111 // } 117 // }
112 // test!{} 118 // test!{}
113 // } 119 // }
114 if with_semi { 120
115 if blocklike.is_block() { 121 match with_semi {
116 p.eat(SEMI); 122 StmtWithSemi::Yes => {
117 } else { 123 if blocklike.is_block() {
118 p.expect(SEMI); 124 p.eat(SEMI);
125 } else {
126 p.expect(SEMI);
127 }
128 }
129 StmtWithSemi::No => {}
130 StmtWithSemi::Optional => {
131 if p.at(SEMI) {
132 p.eat(SEMI);
133 }
119 } 134 }
120 } 135 }
136
121 m.complete(p, EXPR_STMT); 137 m.complete(p, EXPR_STMT);
122 } 138 }
123 139
@@ -128,7 +144,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: bool) {
128 // let c = 92; 144 // let c = 92;
129 // let d: i32 = 92; 145 // let d: i32 = 92;
130 // } 146 // }
131 fn let_stmt(p: &mut Parser, m: Marker, with_semi: bool) { 147 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
132 assert!(p.at(LET_KW)); 148 assert!(p.at(LET_KW));
133 p.bump(); 149 p.bump();
134 patterns::pattern(p); 150 patterns::pattern(p);
@@ -139,8 +155,16 @@ pub(super) fn stmt(p: &mut Parser, with_semi: bool) {
139 expressions::expr(p); 155 expressions::expr(p);
140 } 156 }
141 157
142 if with_semi { 158 match with_semi {
143 p.expect(SEMI); 159 StmtWithSemi::Yes => {
160 p.expect(SEMI);
161 }
162 StmtWithSemi::No => {}
163 StmtWithSemi::Optional => {
164 if p.at(SEMI) {
165 p.eat(SEMI);
166 }
167 }
144 } 168 }
145 m.complete(p, LET_STMT); 169 m.complete(p, LET_STMT);
146 } 170 }
@@ -160,7 +184,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
160 continue; 184 continue;
161 } 185 }
162 186
163 stmt(p, true) 187 stmt(p, StmtWithSemi::Yes)
164 } 188 }
165} 189}
166 190
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index 11b5b9a75..0ea942b6e 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -98,6 +98,14 @@ pub fn parse_item(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink)
98 parse_from_tokens(token_source, tree_sink, grammar::item); 98 parse_from_tokens(token_source, tree_sink, grammar::item);
99} 99}
100 100
101pub fn parse_macro_items(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
102 parse_from_tokens(token_source, tree_sink, grammar::macro_items);
103}
104
105pub fn parse_macro_stmts(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
106 parse_from_tokens(token_source, tree_sink, grammar::macro_stmts);
107}
108
101/// A parsing function for a specific braced-block. 109/// A parsing function for a specific braced-block.
102pub struct Reparser(fn(&mut parser::Parser)); 110pub struct Reparser(fn(&mut parser::Parser));
103 111
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index 498b0e164..6f984aea1 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -233,6 +233,8 @@ pub enum SyntaxKind {
233 ARG_LIST, 233 ARG_LIST,
234 TYPE_BOUND, 234 TYPE_BOUND,
235 TYPE_BOUND_LIST, 235 TYPE_BOUND_LIST,
236 MACRO_ITEMS,
237 MACRO_STMTS,
236 // Technical kind so that we can cast from u16 safely 238 // Technical kind so that we can cast from u16 safely
237 #[doc(hidden)] 239 #[doc(hidden)]
238 __LAST, 240 __LAST,
@@ -592,6 +594,8 @@ impl SyntaxKind {
592 ARG_LIST => &SyntaxInfo { name: "ARG_LIST" }, 594 ARG_LIST => &SyntaxInfo { name: "ARG_LIST" },
593 TYPE_BOUND => &SyntaxInfo { name: "TYPE_BOUND" }, 595 TYPE_BOUND => &SyntaxInfo { name: "TYPE_BOUND" },
594 TYPE_BOUND_LIST => &SyntaxInfo { name: "TYPE_BOUND_LIST" }, 596 TYPE_BOUND_LIST => &SyntaxInfo { name: "TYPE_BOUND_LIST" },
597 MACRO_ITEMS => &SyntaxInfo { name: "MACRO_ITEMS" },
598 MACRO_STMTS => &SyntaxInfo { name: "MACRO_STMTS" },
595 TOMBSTONE => &SyntaxInfo { name: "TOMBSTONE" }, 599 TOMBSTONE => &SyntaxInfo { name: "TOMBSTONE" },
596 EOF => &SyntaxInfo { name: "EOF" }, 600 EOF => &SyntaxInfo { name: "EOF" },
597 __LAST => &SyntaxInfo { name: "__LAST" }, 601 __LAST => &SyntaxInfo { name: "__LAST" },
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 774d9bcc8..17de4f058 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1770,6 +1770,72 @@ impl MacroCall {
1770 } 1770 }
1771} 1771}
1772 1772
1773// MacroItems
1774#[derive(Debug, PartialEq, Eq, Hash)]
1775#[repr(transparent)]
1776pub struct MacroItems {
1777 pub(crate) syntax: SyntaxNode,
1778}
1779unsafe impl TransparentNewType for MacroItems {
1780 type Repr = rowan::SyntaxNode;
1781}
1782
1783impl AstNode for MacroItems {
1784 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1785 match syntax.kind() {
1786 MACRO_ITEMS => Some(MacroItems::from_repr(syntax.into_repr())),
1787 _ => None,
1788 }
1789 }
1790 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1791}
1792
1793impl ToOwned for MacroItems {
1794 type Owned = TreeArc<MacroItems>;
1795 fn to_owned(&self) -> TreeArc<MacroItems> { TreeArc::cast(self.syntax.to_owned()) }
1796}
1797
1798
1799impl ast::ModuleItemOwner for MacroItems {}
1800impl ast::FnDefOwner for MacroItems {}
1801impl MacroItems {}
1802
1803// MacroStmts
1804#[derive(Debug, PartialEq, Eq, Hash)]
1805#[repr(transparent)]
1806pub struct MacroStmts {
1807 pub(crate) syntax: SyntaxNode,
1808}
1809unsafe impl TransparentNewType for MacroStmts {
1810 type Repr = rowan::SyntaxNode;
1811}
1812
1813impl AstNode for MacroStmts {
1814 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1815 match syntax.kind() {
1816 MACRO_STMTS => Some(MacroStmts::from_repr(syntax.into_repr())),
1817 _ => None,
1818 }
1819 }
1820 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1821}
1822
1823impl ToOwned for MacroStmts {
1824 type Owned = TreeArc<MacroStmts>;
1825 fn to_owned(&self) -> TreeArc<MacroStmts> { TreeArc::cast(self.syntax.to_owned()) }
1826}
1827
1828
1829impl MacroStmts {
1830 pub fn statements(&self) -> impl Iterator<Item = &Stmt> {
1831 super::children(self)
1832 }
1833
1834 pub fn expr(&self) -> Option<&Expr> {
1835 super::child_opt(self)
1836 }
1837}
1838
1773// MatchArm 1839// MatchArm
1774#[derive(Debug, PartialEq, Eq, Hash)] 1840#[derive(Debug, PartialEq, Eq, Hash)]
1775#[repr(transparent)] 1841#[repr(transparent)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index b41241287..663e3a2f9 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -247,6 +247,10 @@ Grammar(
247 "ARG_LIST", 247 "ARG_LIST",
248 "TYPE_BOUND", 248 "TYPE_BOUND",
249 "TYPE_BOUND_LIST", 249 "TYPE_BOUND_LIST",
250
251 // macro related
252 "MACRO_ITEMS",
253 "MACRO_STMTS",
250 ], 254 ],
251 ast: { 255 ast: {
252 "SourceFile": ( 256 "SourceFile": (
@@ -668,5 +672,16 @@ Grammar(
668 "TypeArg": (options: ["TypeRef"]), 672 "TypeArg": (options: ["TypeRef"]),
669 "AssocTypeArg": (options: ["NameRef", "TypeRef"]), 673 "AssocTypeArg": (options: ["NameRef", "TypeRef"]),
670 "LifetimeArg": (), 674 "LifetimeArg": (),
675
676 "MacroItems": (
677 traits: [ "ModuleItemOwner", "FnDefOwner" ],
678 ),
679
680 "MacroStmts" : (
681 options: [ "Expr" ],
682 collections: [
683 ["statements", "Stmt"],
684 ],
685 )
671 }, 686 },
672) 687)