From 57e4122b890d56c11f9d74c1bdfed40f186331a4 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 17 Apr 2019 12:34:43 +0800 Subject: Add mbe stmt matcher --- crates/ra_mbe/src/lib.rs | 15 +++ crates/ra_mbe/src/mbe_expander.rs | 4 + 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/grammar/expressions.rs | 154 +++++++++++++++------------- crates/ra_parser/src/lib.rs | 5 + 7 files changed, 119 insertions(+), 72 deletions(-) diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index a530f3b03..a1f438906 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs @@ -582,4 +582,19 @@ SOURCE_FILE@[0; 40) ); assert_expansion(&rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); } + + #[test] + fn test_stmt() { + let rules = create_rules( + r#" + macro_rules! foo { + ($ i:stmt) => ( + fn bar() { $ i; } + ) + } +"#, + ); + assert_expansion(&rules, "foo! { 2 }", "fn bar () {2 ;}"); + assert_expansion(&rules, "foo! { let a = 0 }", "fn bar () {let a = 0 ;}"); + } } diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 7a259f338..7587b575d 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs @@ -157,6 +157,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result { + let pat = input.eat_stmt().ok_or(ExpandError::UnexpectedToken)?.clone(); + res.inner.insert(text.clone(), Binding::Simple(pat.into())); + } _ => return Err(ExpandError::UnexpectedToken), } } diff --git a/crates/ra_mbe/src/subtree_parser.rs b/crates/ra_mbe/src/subtree_parser.rs index 13d5d2169..f075ce245 100644 --- a/crates/ra_mbe/src/subtree_parser.rs +++ b/crates/ra_mbe/src/subtree_parser.rs @@ -42,6 +42,10 @@ impl<'a> Parser<'a> { self.parse(ra_parser::parse_pat) } + pub fn parse_stmt(self) -> Option { + self.parse(|src, sink| ra_parser::parse_stmt(src, sink, false)) + } + 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 f6cefe087..adfe5520d 100644 --- a/crates/ra_mbe/src/tt_cursor.rs +++ b/crates/ra_mbe/src/tt_cursor.rs @@ -99,6 +99,11 @@ impl<'a> TtCursor<'a> { parser.parse_pat() } + pub(crate) fn eat_stmt(&mut self) -> Option { + let parser = Parser::new(&mut self.pos, self.subtree); + parser.parse_stmt() + } + 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 5a7a55141..2c2f785d0 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs @@ -65,6 +65,10 @@ pub(crate) fn pattern(p: &mut Parser) { patterns::pattern(p) } +pub(crate) fn stmt(p: &mut Parser, with_semi: bool) { + expressions::stmt(p, with_semi) +} + pub(crate) fn reparser( node: SyntaxKind, first_child: Option, diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 295577325..06f2b45b1 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs @@ -48,88 +48,77 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { } } -pub(crate) fn expr_block_contents(p: &mut Parser) { - // This is checked by a validator - attributes::inner_attributes(p); - - while !p.at(EOF) && !p.at(R_CURLY) { - // test nocontentexpr - // fn foo(){ - // ;;;some_expr();;;;{;;;};;;;Ok(()) - // } - if p.current() == SEMI { - p.bump(); - continue; - } +pub(super) fn stmt(p: &mut Parser, with_semi: bool) { + // test block_items + // fn a() { fn b() {} } + let m = p.start(); + // test attr_on_expr_stmt + // fn foo() { + // #[A] foo(); + // #[B] bar!{} + // #[C] #[D] {} + // #[D] return (); + // } + let has_attrs = p.at(POUND); + attributes::outer_attributes(p); - // test block_items - // fn a() { fn b() {} } - let m = p.start(); - // test attr_on_expr_stmt - // fn foo() { - // #[A] foo(); - // #[B] bar!{} - // #[C] #[D] {} - // #[D] return (); - // } - let has_attrs = p.at(POUND); - attributes::outer_attributes(p); - if p.at(LET_KW) { - let_stmt(p, m); - continue; - } + if p.at(LET_KW) { + let_stmt(p, m, with_semi); + return; + } - let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) { - Ok(()) => continue, - Err(m) => m, - }; + let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) { + Ok(()) => return, + Err(m) => m, + }; - let (cm, blocklike) = expr_stmt(p); - let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR); + let (cm, blocklike) = expr_stmt(p); + let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR); - if has_attrs && !is_expr_stmt_attr_allowed(kind) { - // test_err attr_on_expr_not_allowed - // fn foo() { - // #[A] 1 + 2; - // #[B] if true {}; - // } - p.error(format!("attributes are not allowed on {:?}", kind)); - } + if has_attrs && !is_expr_stmt_attr_allowed(kind) { + // test_err attr_on_expr_not_allowed + // fn foo() { + // #[A] 1 + 2; + // #[B] if true {}; + // } + p.error(format!("attributes are not allowed on {:?}", kind)); + } - if p.at(R_CURLY) { - // test attr_on_last_expr_in_block - // fn foo() { - // { #[A] bar!()? } - // #[B] &() - // } - if let Some(cm) = cm { - cm.undo_completion(p).abandon(p); - m.complete(p, kind); - } else { - m.abandon(p); - } + if p.at(R_CURLY) { + // test attr_on_last_expr_in_block + // fn foo() { + // { #[A] bar!()? } + // #[B] &() + // } + if let Some(cm) = cm { + cm.undo_completion(p).abandon(p); + m.complete(p, kind); } else { - // test no_semi_after_block - // fn foo() { - // if true {} - // loop {} - // match () {} - // while true {} - // for _ in () {} - // {} - // {} - // macro_rules! test { - // () => {} - // } - // test!{} - // } + m.abandon(p); + } + } else { + // test no_semi_after_block + // fn foo() { + // if true {} + // loop {} + // match () {} + // while true {} + // for _ in () {} + // {} + // {} + // macro_rules! test { + // () => {} + // } + // test!{} + // } + if with_semi { if blocklike.is_block() { p.eat(SEMI); } else { p.expect(SEMI); } - m.complete(p, EXPR_STMT); } + m.complete(p, EXPR_STMT); } // test let_stmt; @@ -139,7 +128,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { // let c = 92; // let d: i32 = 92; // } - fn let_stmt(p: &mut Parser, m: Marker) { + fn let_stmt(p: &mut Parser, m: Marker, with_semi: bool) { assert!(p.at(LET_KW)); p.bump(); patterns::pattern(p); @@ -149,11 +138,32 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { if p.eat(EQ) { expressions::expr(p); } - p.expect(SEMI); + + if with_semi { + p.expect(SEMI); + } m.complete(p, LET_STMT); } } +pub(crate) fn expr_block_contents(p: &mut Parser) { + // This is checked by a validator + attributes::inner_attributes(p); + + while !p.at(EOF) && !p.at(R_CURLY) { + // test nocontentexpr + // fn foo(){ + // ;;;some_expr();;;;{;;;};;;;Ok(()) + // } + if p.current() == SEMI { + p.bump(); + continue; + } + + stmt(p, true) + } +} + #[derive(Clone, Copy)] struct Restrictions { forbid_structs: bool, diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs index 56755c394..9133c1b8a 100644 --- a/crates/ra_parser/src/lib.rs +++ b/crates/ra_parser/src/lib.rs @@ -88,6 +88,11 @@ pub fn parse_pat(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { parse_from_tokens(token_source, tree_sink, grammar::pattern); } +/// Parse given tokens into the given sink as a statement +pub fn parse_stmt(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink, with_semi: bool) { + parse_from_tokens(token_source, tree_sink, |p| grammar::stmt(p, with_semi)); +} + /// A parsing function for a specific braced-block. pub struct Reparser(fn(&mut parser::Parser)); -- cgit v1.2.3