mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Add mbe stmt matcher
This commit is contained in:
parent
546d9be2a7
commit
57e4122b89
7 changed files with 136 additions and 89 deletions
|
@ -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 ;}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue