From e944fd059de93f305d6a8c40cfac5ebe84548771 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Thu, 18 Apr 2019 10:21:36 +0800 Subject: Add `item` matcher in mbe --- crates/ra_mbe/src/lib.rs | 44 +++++++++++++++++++++++++++++++++++++ crates/ra_mbe/src/mbe_expander.rs | 8 +++++++ crates/ra_mbe/src/subtree_parser.rs | 4 ++++ crates/ra_mbe/src/tt_cursor.rs | 5 +++++ crates/ra_parser/src/grammar.rs | 4 ++++ crates/ra_parser/src/lib.rs | 5 +++++ 6 files changed, 70 insertions(+) diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index a1f438906..2f47e32d3 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs @@ -597,4 +597,48 @@ SOURCE_FILE@[0; 40) assert_expansion(&rules, "foo! { 2 }", "fn bar () {2 ;}"); assert_expansion(&rules, "foo! { let a = 0 }", "fn bar () {let a = 0 ;}"); } + + #[test] + fn test_single_item() { + let rules = create_rules( + r#" + macro_rules! foo { + ($ i:item) => ( + $ i + ) + } +"#, + ); + assert_expansion(&rules, "foo! {mod c {}}", "mod c {}"); + } + + #[test] + fn test_all_items() { + let rules = create_rules( + r#" + macro_rules! foo { + ($ ($ i:item)*) => ($ ( + $ i + )*) + } +"#, + ); + assert_expansion(&rules, r#" + foo! { + extern crate a; + mod b; + mod c {} + use d; + const E: i32 = 0; + static F: i32 = 0; + impl G {} + struct H; + enum I { Foo } + trait J {} + fn h() {} + extern {} + type T = u8; + } +"#, r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#); + } } diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 7587b575d..acba42809 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs @@ -161,6 +161,11 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result { + let item = + input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone(); + res.inner.insert(text.clone(), Binding::Simple(item.into())); + } _ => return Err(ExpandError::UnexpectedToken), } } @@ -278,6 +283,9 @@ mod tests { assert_err("($i) => ($i)", "foo!{a}", ExpandError::UnexpectedToken); assert_err("($i:) => ($i)", "foo!{a}", ExpandError::UnexpectedToken); + + // FIXME: + // Add an err test case for ($($i:ident)) => ($()) } fn assert_err(macro_body: &str, invocation: &str, err: ExpandError) { diff --git a/crates/ra_mbe/src/subtree_parser.rs b/crates/ra_mbe/src/subtree_parser.rs index f075ce245..195e4c3ac 100644 --- a/crates/ra_mbe/src/subtree_parser.rs +++ b/crates/ra_mbe/src/subtree_parser.rs @@ -46,6 +46,10 @@ impl<'a> Parser<'a> { self.parse(|src, sink| ra_parser::parse_stmt(src, sink, false)) } + pub fn parse_item(self) -> Option { + self.parse(ra_parser::parse_item) + } + fn parse(self, f: F) -> Option where F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs index adfe5520d..484437b0e 100644 --- a/crates/ra_mbe/src/tt_cursor.rs +++ b/crates/ra_mbe/src/tt_cursor.rs @@ -104,6 +104,11 @@ impl<'a> TtCursor<'a> { parser.parse_stmt() } + pub(crate) fn eat_item(&mut self) -> Option { + let parser = Parser::new(&mut self.pos, self.subtree); + parser.parse_item() + } + pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> { if self.at_char(char) { self.bump(); diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index 2c2f785d0..f8ed1299a 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs @@ -69,6 +69,10 @@ pub(crate) fn stmt(p: &mut Parser, with_semi: bool) { expressions::stmt(p, with_semi) } +pub(crate) fn item(p: &mut Parser) { + items::item_or_macro(p, true, items::ItemFlavor::Mod) +} + pub(crate) fn reparser( node: SyntaxKind, first_child: Option, diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs index 9133c1b8a..11b5b9a75 100644 --- a/crates/ra_parser/src/lib.rs +++ b/crates/ra_parser/src/lib.rs @@ -93,6 +93,11 @@ pub fn parse_stmt(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink, parse_from_tokens(token_source, tree_sink, |p| grammar::stmt(p, with_semi)); } +/// Parse given tokens into the given sink as an item +pub fn parse_item(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { + parse_from_tokens(token_source, tree_sink, grammar::item); +} + /// A parsing function for a specific braced-block. pub struct Reparser(fn(&mut parser::Parser)); -- cgit v1.2.3