Add mbe stmt matcher

This commit is contained in:
Edwin Cheng 2019-04-17 12:34:43 +08:00
parent 546d9be2a7
commit 57e4122b89
7 changed files with 136 additions and 89 deletions

View file

@ -582,4 +582,19 @@ SOURCE_FILE@[0; 40)
); );
assert_expansion(&rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); 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 ;}");
}
} }

View file

@ -157,6 +157,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
let pat = input.eat_pat().ok_or(ExpandError::UnexpectedToken)?.clone(); let pat = input.eat_pat().ok_or(ExpandError::UnexpectedToken)?.clone();
res.inner.insert(text.clone(), Binding::Simple(pat.into())); res.inner.insert(text.clone(), Binding::Simple(pat.into()));
} }
"stmt" => {
let pat = input.eat_stmt().ok_or(ExpandError::UnexpectedToken)?.clone();
res.inner.insert(text.clone(), Binding::Simple(pat.into()));
}
_ => return Err(ExpandError::UnexpectedToken), _ => return Err(ExpandError::UnexpectedToken),
} }
} }

View file

@ -42,6 +42,10 @@ impl<'a> Parser<'a> {
self.parse(ra_parser::parse_pat) self.parse(ra_parser::parse_pat)
} }
pub fn parse_stmt(self) -> Option<tt::TokenTree> {
self.parse(|src, sink| ra_parser::parse_stmt(src, sink, false))
}
fn parse<F>(self, f: F) -> Option<tt::TokenTree> fn parse<F>(self, f: F) -> Option<tt::TokenTree>
where where
F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), F: FnOnce(&dyn TokenSource, &mut dyn TreeSink),

View file

@ -99,6 +99,11 @@ impl<'a> TtCursor<'a> {
parser.parse_pat() parser.parse_pat()
} }
pub(crate) fn eat_stmt(&mut self) -> Option<tt::TokenTree> {
let parser = Parser::new(&mut self.pos, self.subtree);
parser.parse_stmt()
}
pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> { pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> {
if self.at_char(char) { if self.at_char(char) {
self.bump(); self.bump();

View file

@ -65,6 +65,10 @@ pub(crate) fn pattern(p: &mut Parser) {
patterns::pattern(p) patterns::pattern(p)
} }
pub(crate) fn stmt(p: &mut Parser, with_semi: bool) {
expressions::stmt(p, with_semi)
}
pub(crate) fn reparser( pub(crate) fn reparser(
node: SyntaxKind, node: SyntaxKind,
first_child: Option<SyntaxKind>, first_child: Option<SyntaxKind>,

View file

@ -48,20 +48,7 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
} }
} }
pub(crate) fn expr_block_contents(p: &mut Parser) { pub(super) fn stmt(p: &mut Parser, with_semi: bool) {
// 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;
}
// test block_items // test block_items
// fn a() { fn b() {} } // fn a() { fn b() {} }
let m = p.start(); let m = p.start();
@ -74,13 +61,14 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
// } // }
let has_attrs = p.at(POUND); let has_attrs = p.at(POUND);
attributes::outer_attributes(p); attributes::outer_attributes(p);
if p.at(LET_KW) { if p.at(LET_KW) {
let_stmt(p, m); let_stmt(p, m, with_semi);
continue; return;
} }
let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) { let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) {
Ok(()) => continue, Ok(()) => return,
Err(m) => m, Err(m) => m,
}; };
@ -123,13 +111,14 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
// } // }
// test!{} // test!{}
// } // }
if with_semi {
if blocklike.is_block() { if blocklike.is_block() {
p.eat(SEMI); p.eat(SEMI);
} else { } else {
p.expect(SEMI); p.expect(SEMI);
} }
m.complete(p, EXPR_STMT);
} }
m.complete(p, EXPR_STMT);
} }
// test let_stmt; // test let_stmt;
@ -139,7 +128,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
// let c = 92; // let c = 92;
// let d: i32 = 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)); assert!(p.at(LET_KW));
p.bump(); p.bump();
patterns::pattern(p); patterns::pattern(p);
@ -149,11 +138,32 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
if p.eat(EQ) { if p.eat(EQ) {
expressions::expr(p); expressions::expr(p);
} }
if with_semi {
p.expect(SEMI); p.expect(SEMI);
}
m.complete(p, LET_STMT); 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)] #[derive(Clone, Copy)]
struct Restrictions { struct Restrictions {
forbid_structs: bool, forbid_structs: bool,

View file

@ -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_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. /// A parsing function for a specific braced-block.
pub struct Reparser(fn(&mut parser::Parser)); pub struct Reparser(fn(&mut parser::Parser));