From 23ce31e836389fce24ae63993ef78e3716d1d012 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 14:58:24 +0300 Subject: [PATCH 01/29] simplify --- crates/mbe/src/expander/matcher.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index b2d3f038f544..8d192b53f85e 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -726,10 +726,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult match input.eat_vis() { - Some(vis) => Ok(Some(vis)), - None => Ok(None), - }, + "vis" => Ok(input.eat_vis()), _ => Err(ExpandError::UnexpectedToken), }; return tt_result.map(|it| it.map(Fragment::Tokens)).into(); @@ -899,14 +896,7 @@ impl<'a> TtIter<'a> { } fn eat_vis(&mut self) -> Option { - let mut fork = self.clone(); - match fork.expect_fragment(Visibility) { - ExpandResult { value: tt, err: None } => { - *self = fork; - tt - } - ExpandResult { value: _, err: Some(_) } => None, - } + self.expect_fragment(Visibility).value } fn eat_char(&mut self, c: char) -> Option { From d3ba55bd062f985a92b4cee3732319d9b6c131c5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 15:03:05 +0300 Subject: [PATCH 02/29] cleanup imports --- crates/mbe/src/expander/matcher.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 8d192b53f85e..e589dc759f8e 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -61,18 +61,17 @@ use std::rc::Rc; +use parser::ParserEntryPoint; +use smallvec::{smallvec, SmallVec}; +use syntax::SmolStr; + use crate::{ - expander::{Binding, Bindings, Fragment}, + expander::{Binding, Bindings, ExpandResult, Fragment}, parser::{Op, RepeatKind, Separator}, tt_iter::TtIter, ExpandError, MetaTemplate, }; -use super::ExpandResult; -use parser::ParserEntryPoint::*; -use smallvec::{smallvec, SmallVec}; -use syntax::SmolStr; - impl Bindings { fn push_optional(&mut self, name: &SmolStr) { // FIXME: Do we have a better way to represent an empty token ? @@ -691,14 +690,14 @@ fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> { fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult> { let fragment = match kind { - "path" => Path, - "expr" => Expr, - "ty" => Type, - "pat" | "pat_param" => Pattern, // FIXME: edition2021 - "stmt" => Statement, - "block" => Block, - "meta" => MetaItem, - "item" => Item, + "path" => ParserEntryPoint::Path, + "expr" => ParserEntryPoint::Expr, + "ty" => ParserEntryPoint::Type, + "pat" | "pat_param" => ParserEntryPoint::Pattern, // FIXME: edition2021 + "stmt" => ParserEntryPoint::Statement, + "block" => ParserEntryPoint::Block, + "meta" => ParserEntryPoint::MetaItem, + "item" => ParserEntryPoint::Item, _ => { let tt_result = match kind { "ident" => input @@ -896,7 +895,7 @@ impl<'a> TtIter<'a> { } fn eat_vis(&mut self) -> Option { - self.expect_fragment(Visibility).value + self.expect_fragment(ParserEntryPoint::Visibility).value } fn eat_char(&mut self, c: char) -> Option { From abc658aad04db9bbe1727218df110abc8e126ec7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 15:17:48 +0300 Subject: [PATCH 03/29] internal: add prefix entry points --- crates/parser/src/grammar.rs | 12 ++++++++++++ crates/parser/src/lib.rs | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 25178ddd775a..86dce61da2d3 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -44,6 +44,18 @@ use crate::{ TokenSet, T, }; +pub(crate) mod entry { + use super::*; + + pub(crate) mod prefix { + use super::*; + + pub(crate) fn vis(p: &mut Parser) { + let _ = opt_visibility(p, false); + } + } +} + pub(crate) mod entry_points { use super::*; diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 841d2aa4e946..f0b93c4511a1 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -41,6 +41,30 @@ pub use crate::{ syntax_kind::SyntaxKind, }; +/// Parse a syntactic construct at the *start* of the input. +/// +/// This is used by macro-by-example parser to implement things like `$i:item`. +/// +/// Note that this is generally non-optional -- the result is intentionally not +/// `Option`. The way MBE work, by the time we *try* to parse `$e:expr` +/// we already commit to expression. In other words, this API by design can't be +/// used to implement "rollback and try another alternative" logic. +pub enum PrefixEntryPoint { + Vis, +} + +impl PrefixEntryPoint { + pub fn parse(self, input: &Input) -> Output { + let entry_point: fn(&'_ mut parser::Parser) = match self { + PrefixEntryPoint::Vis => grammar::entry::prefix::vis, + }; + let mut p = parser::Parser::new(input); + entry_point(&mut p); + let events = p.finish(); + event::process(events) + } +} + /// rust-analyzer parser allows you to choose one of the possible entry points. /// /// The primary consumer of this API are declarative macros, `$x:expr` matchers From 350d5dc152fe268bc33cf8d54e8ceb06531f07a4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 15:22:44 +0300 Subject: [PATCH 04/29] internal: move visibility to a prefix entry point --- crates/mbe/src/expander/matcher.rs | 2 +- crates/mbe/src/tt_iter.rs | 57 ++++++++++++++++++++++++++++++ crates/parser/src/grammar.rs | 4 --- crates/parser/src/lib.rs | 7 ++-- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index e589dc759f8e..3636979d007f 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -895,7 +895,7 @@ impl<'a> TtIter<'a> { } fn eat_vis(&mut self) -> Option { - self.expect_fragment(ParserEntryPoint::Visibility).value + self.expect_fragment2(parser::PrefixEntryPoint::Vis).value } fn eat_char(&mut self, c: char) -> Option { diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs index 2d2dbd8994f6..03d0cbee8b13 100644 --- a/crates/mbe/src/tt_iter.rs +++ b/crates/mbe/src/tt_iter.rs @@ -146,6 +146,63 @@ impl<'a> TtIter<'a> { ExpandResult { value: res, err } } + pub(crate) fn expect_fragment2( + &mut self, + entry_point: parser::PrefixEntryPoint, + ) -> ExpandResult> { + let buffer = TokenBuffer::from_tokens(self.inner.as_slice()); + let parser_input = to_parser_input(&buffer); + let tree_traversal = entry_point.parse(&parser_input); + + let mut cursor = buffer.begin(); + let mut error = false; + for step in tree_traversal.iter() { + match step { + parser::Step::Token { kind, mut n_input_tokens } => { + if kind == SyntaxKind::LIFETIME_IDENT { + n_input_tokens = 2; + } + for _ in 0..n_input_tokens { + cursor = cursor.bump_subtree(); + } + } + parser::Step::Enter { .. } | parser::Step::Exit => (), + parser::Step::Error { .. } => error = true, + } + } + + let mut err = if !cursor.is_root() || error { + Some(err!("expected {:?}", entry_point)) + } else { + None + }; + + let mut curr = buffer.begin(); + let mut res = vec![]; + + if cursor.is_root() { + while curr != cursor { + if let Some(token) = curr.token_tree() { + res.push(token); + } + curr = curr.bump(); + } + } + self.inner = self.inner.as_slice()[res.len()..].iter(); + if res.is_empty() && err.is_none() { + err = Some(err!("no tokens consumed")); + } + let res = match res.len() { + 1 => Some(res[0].cloned()), + 0 => None, + _ => Some(tt::TokenTree::Subtree(tt::Subtree { + delimiter: None, + token_trees: res.into_iter().map(|it| it.cloned()).collect(), + })), + }; + ExpandResult { value: res, err } + } + pub(crate) fn peek_n(&self, n: usize) -> Option<&tt::TokenTree> { self.inner.as_slice().get(n) } diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 86dce61da2d3..1c58f217a307 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -86,10 +86,6 @@ pub(crate) mod entry_points { expressions::stmt(p, expressions::StmtWithSemi::Optional, false); } - pub(crate) fn visibility(p: &mut Parser) { - let _ = opt_visibility(p, false); - } - // Parse a meta item , which excluded [], e.g : #[ MetaItem ] pub(crate) fn meta_item(p: &mut Parser) { attributes::meta(p); diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index f0b93c4511a1..f4ce5a21e80d 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -49,12 +49,13 @@ pub use crate::{ /// `Option`. The way MBE work, by the time we *try* to parse `$e:expr` /// we already commit to expression. In other words, this API by design can't be /// used to implement "rollback and try another alternative" logic. +#[derive(Debug)] pub enum PrefixEntryPoint { Vis, } impl PrefixEntryPoint { - pub fn parse(self, input: &Input) -> Output { + pub fn parse(&self, input: &Input) -> Output { let entry_point: fn(&'_ mut parser::Parser) = match self { PrefixEntryPoint::Vis => grammar::entry::prefix::vis, }; @@ -80,7 +81,7 @@ pub enum ParserEntryPoint { Pattern, Item, Block, - Visibility, + // Visibility, MetaItem, Items, Statements, @@ -109,7 +110,7 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::Pattern => grammar::entry_points::pattern, ParserEntryPoint::Item => grammar::entry_points::item, ParserEntryPoint::Block => grammar::entry_points::block_expr, - ParserEntryPoint::Visibility => grammar::entry_points::visibility, + // ParserEntryPoint::Visibility => grammar::entry_points::visibility, ParserEntryPoint::MetaItem => grammar::entry_points::meta_item, ParserEntryPoint::Statement => grammar::entry_points::stmt, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, From 519ee21bcb754bf972b5f127f17035c5efe196d0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 15:39:17 +0300 Subject: [PATCH 05/29] internal: move block to prefix entry point --- crates/mbe/src/expander/matcher.rs | 12 ++++++------ crates/parser/src/grammar.rs | 4 ++++ crates/parser/src/lib.rs | 2 ++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 3636979d007f..621ff791d4f7 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -695,7 +695,11 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult ParserEntryPoint::Type, "pat" | "pat_param" => ParserEntryPoint::Pattern, // FIXME: edition2021 "stmt" => ParserEntryPoint::Statement, - "block" => ParserEntryPoint::Block, + "block" => { + return input + .expect_fragment2(parser::PrefixEntryPoint::Block) + .map(|tt| tt.map(Fragment::Tokens)); + } "meta" => ParserEntryPoint::MetaItem, "item" => ParserEntryPoint::Item, _ => { @@ -725,7 +729,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult Ok(input.eat_vis()), + "vis" => Ok(input.expect_fragment2(parser::PrefixEntryPoint::Vis).value), _ => Err(ExpandError::UnexpectedToken), }; return tt_result.map(|it| it.map(Fragment::Tokens)).into(); @@ -894,10 +898,6 @@ impl<'a> TtIter<'a> { .into()) } - fn eat_vis(&mut self) -> Option { - self.expect_fragment2(parser::PrefixEntryPoint::Vis).value - } - fn eat_char(&mut self, c: char) -> Option { let mut fork = self.clone(); match fork.expect_char(c) { diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 1c58f217a307..cf17e8453bac 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -53,6 +53,10 @@ pub(crate) mod entry { pub(crate) fn vis(p: &mut Parser) { let _ = opt_visibility(p, false); } + + pub(crate) fn block(p: &mut Parser) { + expressions::block_expr(p); + } } } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index f4ce5a21e80d..778c8b10ec6d 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -52,12 +52,14 @@ pub use crate::{ #[derive(Debug)] pub enum PrefixEntryPoint { Vis, + Block, } impl PrefixEntryPoint { pub fn parse(&self, input: &Input) -> Output { let entry_point: fn(&'_ mut parser::Parser) = match self { PrefixEntryPoint::Vis => grammar::entry::prefix::vis, + PrefixEntryPoint::Block => grammar::entry::prefix::block, }; let mut p = parser::Parser::new(input); entry_point(&mut p); From f10f51833c8ea715ef512eb283f1d44f76701378 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 15:54:00 +0300 Subject: [PATCH 06/29] move stmt to entry points --- crates/mbe/src/expander/matcher.rs | 6 +++++- crates/parser/src/grammar.rs | 10 ++++------ crates/parser/src/lib.rs | 8 ++------ 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 621ff791d4f7..b5d1e098c4fc 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -694,7 +694,11 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult ParserEntryPoint::Expr, "ty" => ParserEntryPoint::Type, "pat" | "pat_param" => ParserEntryPoint::Pattern, // FIXME: edition2021 - "stmt" => ParserEntryPoint::Statement, + "stmt" => { + return input + .expect_fragment2(parser::PrefixEntryPoint::Stmt) + .map(|tt| tt.map(Fragment::Tokens)); + } "block" => { return input .expect_fragment2(parser::PrefixEntryPoint::Block) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index cf17e8453bac..f15272ce8700 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -57,6 +57,10 @@ pub(crate) mod entry { pub(crate) fn block(p: &mut Parser) { expressions::block_expr(p); } + + pub(crate) fn stmt(p: &mut Parser) { + expressions::stmt(p, expressions::StmtWithSemi::No, true); + } } } @@ -70,8 +74,6 @@ pub(crate) mod entry_points { m.complete(p, SOURCE_FILE); } - pub(crate) use expressions::block_expr; - pub(crate) use paths::type_path as path; pub(crate) use patterns::pattern_single as pattern; @@ -82,10 +84,6 @@ pub(crate) mod entry_points { let _ = expressions::expr(p); } - pub(crate) fn stmt(p: &mut Parser) { - expressions::stmt(p, expressions::StmtWithSemi::No, true); - } - pub(crate) fn stmt_optional_semi(p: &mut Parser) { expressions::stmt(p, expressions::StmtWithSemi::Optional, false); } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 778c8b10ec6d..97b717346b18 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -53,6 +53,7 @@ pub use crate::{ pub enum PrefixEntryPoint { Vis, Block, + Stmt, } impl PrefixEntryPoint { @@ -60,6 +61,7 @@ impl PrefixEntryPoint { let entry_point: fn(&'_ mut parser::Parser) = match self { PrefixEntryPoint::Vis => grammar::entry::prefix::vis, PrefixEntryPoint::Block => grammar::entry::prefix::block, + PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt, }; let mut p = parser::Parser::new(input); entry_point(&mut p); @@ -77,13 +79,10 @@ pub enum ParserEntryPoint { SourceFile, Path, Expr, - Statement, StatementOptionalSemi, Type, Pattern, Item, - Block, - // Visibility, MetaItem, Items, Statements, @@ -111,10 +110,7 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::Type => grammar::entry_points::type_, ParserEntryPoint::Pattern => grammar::entry_points::pattern, ParserEntryPoint::Item => grammar::entry_points::item, - ParserEntryPoint::Block => grammar::entry_points::block_expr, - // ParserEntryPoint::Visibility => grammar::entry_points::visibility, ParserEntryPoint::MetaItem => grammar::entry_points::meta_item, - ParserEntryPoint::Statement => grammar::entry_points::stmt, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, ParserEntryPoint::Items => grammar::entry_points::macro_items, ParserEntryPoint::Statements => grammar::entry_points::macro_stmts, From 5636bef2ecad8bde7746dcaf150a9bb4f0d6f342 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 16:06:02 +0300 Subject: [PATCH 07/29] move pat to prefix entry points --- crates/mbe/src/expander/matcher.rs | 9 ++++++++- crates/parser/src/grammar.rs | 6 ++++-- crates/parser/src/lib.rs | 7 +++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index b5d1e098c4fc..03ada8b2b9c3 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -693,7 +693,14 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult ParserEntryPoint::Path, "expr" => ParserEntryPoint::Expr, "ty" => ParserEntryPoint::Type, - "pat" | "pat_param" => ParserEntryPoint::Pattern, // FIXME: edition2021 + // FIXME: These two should actually behave differently depending on the edition. + // + // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html + "pat" | "pat_param" => { + return input + .expect_fragment2(parser::PrefixEntryPoint::Pat) + .map(|tt| tt.map(Fragment::Tokens)); + } "stmt" => { return input .expect_fragment2(parser::PrefixEntryPoint::Stmt) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index f15272ce8700..4c6106f18a82 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -61,6 +61,10 @@ pub(crate) mod entry { pub(crate) fn stmt(p: &mut Parser) { expressions::stmt(p, expressions::StmtWithSemi::No, true); } + + pub(crate) fn pat(p: &mut Parser) { + patterns::pattern_single(p); + } } } @@ -76,8 +80,6 @@ pub(crate) mod entry_points { pub(crate) use paths::type_path as path; - pub(crate) use patterns::pattern_single as pattern; - pub(crate) use types::type_; pub(crate) fn expr(p: &mut Parser) { diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 97b717346b18..a6e554c3b459 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -43,7 +43,8 @@ pub use crate::{ /// Parse a syntactic construct at the *start* of the input. /// -/// This is used by macro-by-example parser to implement things like `$i:item`. +/// This is used by macro-by-example parser to implement things like `$i:item` +/// and the naming of variants follows the naming of macro fragments. /// /// Note that this is generally non-optional -- the result is intentionally not /// `Option`. The way MBE work, by the time we *try* to parse `$e:expr` @@ -54,6 +55,7 @@ pub enum PrefixEntryPoint { Vis, Block, Stmt, + Pat, } impl PrefixEntryPoint { @@ -62,6 +64,7 @@ impl PrefixEntryPoint { PrefixEntryPoint::Vis => grammar::entry::prefix::vis, PrefixEntryPoint::Block => grammar::entry::prefix::block, PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt, + PrefixEntryPoint::Pat => grammar::entry::prefix::pat, }; let mut p = parser::Parser::new(input); entry_point(&mut p); @@ -108,7 +111,7 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::Path => grammar::entry_points::path, ParserEntryPoint::Expr => grammar::entry_points::expr, ParserEntryPoint::Type => grammar::entry_points::type_, - ParserEntryPoint::Pattern => grammar::entry_points::pattern, + ParserEntryPoint::Pattern => grammar::entry::prefix::pat, ParserEntryPoint::Item => grammar::entry_points::item, ParserEntryPoint::MetaItem => grammar::entry_points::meta_item, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, From 04ae18de295d997ad6ca0adf1de0f3efd4e1aa35 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 16:08:35 +0300 Subject: [PATCH 08/29] move ty --- crates/mbe/src/expander/matcher.rs | 6 +++++- crates/parser/src/grammar.rs | 6 ++++-- crates/parser/src/lib.rs | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 03ada8b2b9c3..c5c13590dd13 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -692,7 +692,11 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult ParserEntryPoint::Path, "expr" => ParserEntryPoint::Expr, - "ty" => ParserEntryPoint::Type, + "ty" => { + return input + .expect_fragment2(parser::PrefixEntryPoint::Ty) + .map(|tt| tt.map(Fragment::Tokens)); + } // FIXME: These two should actually behave differently depending on the edition. // // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 4c6106f18a82..539dc19b517e 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -65,6 +65,10 @@ pub(crate) mod entry { pub(crate) fn pat(p: &mut Parser) { patterns::pattern_single(p); } + + pub(crate) fn ty(p: &mut Parser) { + types::type_(p); + } } } @@ -80,8 +84,6 @@ pub(crate) mod entry_points { pub(crate) use paths::type_path as path; - pub(crate) use types::type_; - pub(crate) fn expr(p: &mut Parser) { let _ = expressions::expr(p); } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index a6e554c3b459..ebb060a5639d 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -56,6 +56,7 @@ pub enum PrefixEntryPoint { Block, Stmt, Pat, + Ty, } impl PrefixEntryPoint { @@ -65,6 +66,7 @@ impl PrefixEntryPoint { PrefixEntryPoint::Block => grammar::entry::prefix::block, PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt, PrefixEntryPoint::Pat => grammar::entry::prefix::pat, + PrefixEntryPoint::Ty => grammar::entry::prefix::ty, }; let mut p = parser::Parser::new(input); entry_point(&mut p); @@ -110,7 +112,7 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::SourceFile => grammar::entry_points::source_file, ParserEntryPoint::Path => grammar::entry_points::path, ParserEntryPoint::Expr => grammar::entry_points::expr, - ParserEntryPoint::Type => grammar::entry_points::type_, + ParserEntryPoint::Type => grammar::entry::prefix::ty, ParserEntryPoint::Pattern => grammar::entry::prefix::pat, ParserEntryPoint::Item => grammar::entry_points::item, ParserEntryPoint::MetaItem => grammar::entry_points::meta_item, From c5d8a9b341eee52ef5d83c61726700f42492ace9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 16:17:29 +0300 Subject: [PATCH 09/29] move expr --- crates/mbe/src/expander/matcher.rs | 6 +++++- crates/parser/src/grammar.rs | 3 +++ crates/parser/src/lib.rs | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index c5c13590dd13..6cc655786cb3 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -691,7 +691,11 @@ fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> { fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult> { let fragment = match kind { "path" => ParserEntryPoint::Path, - "expr" => ParserEntryPoint::Expr, + "expr" => { + return input + .expect_fragment2(parser::PrefixEntryPoint::Expr) + .map(|tt| tt.map(Fragment::Expr)); + } "ty" => { return input .expect_fragment2(parser::PrefixEntryPoint::Ty) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 539dc19b517e..6789c61f4b3d 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -69,6 +69,9 @@ pub(crate) mod entry { pub(crate) fn ty(p: &mut Parser) { types::type_(p); } + pub(crate) fn expr(p: &mut Parser) { + let _ = expressions::expr(p); + } } } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index ebb060a5639d..6aeed8a2887e 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -57,6 +57,7 @@ pub enum PrefixEntryPoint { Stmt, Pat, Ty, + Expr, } impl PrefixEntryPoint { @@ -67,6 +68,7 @@ impl PrefixEntryPoint { PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt, PrefixEntryPoint::Pat => grammar::entry::prefix::pat, PrefixEntryPoint::Ty => grammar::entry::prefix::ty, + PrefixEntryPoint::Expr => grammar::entry::prefix::expr, }; let mut p = parser::Parser::new(input); entry_point(&mut p); From 369001615f7ce8624139e51a42e2751da8584766 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 16:23:07 +0300 Subject: [PATCH 10/29] move path --- crates/mbe/src/expander/matcher.rs | 6 +++++- crates/parser/src/grammar.rs | 9 +++------ crates/parser/src/lib.rs | 6 ++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 6cc655786cb3..3137bd91cf8d 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -690,7 +690,11 @@ fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> { fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult> { let fragment = match kind { - "path" => ParserEntryPoint::Path, + "path" => { + return input + .expect_fragment2(parser::PrefixEntryPoint::Path) + .map(|tt| tt.map(Fragment::Tokens)); + } "expr" => { return input .expect_fragment2(parser::PrefixEntryPoint::Expr) diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 6789c61f4b3d..8310b38b9293 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -72,6 +72,9 @@ pub(crate) mod entry { pub(crate) fn expr(p: &mut Parser) { let _ = expressions::expr(p); } + pub(crate) fn path(p: &mut Parser) { + let _ = paths::type_path(p); + } } } @@ -85,12 +88,6 @@ pub(crate) mod entry_points { m.complete(p, SOURCE_FILE); } - pub(crate) use paths::type_path as path; - - pub(crate) fn expr(p: &mut Parser) { - let _ = expressions::expr(p); - } - pub(crate) fn stmt_optional_semi(p: &mut Parser) { expressions::stmt(p, expressions::StmtWithSemi::Optional, false); } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 6aeed8a2887e..867acc45f3f3 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -58,6 +58,7 @@ pub enum PrefixEntryPoint { Pat, Ty, Expr, + Path, } impl PrefixEntryPoint { @@ -69,6 +70,7 @@ impl PrefixEntryPoint { PrefixEntryPoint::Pat => grammar::entry::prefix::pat, PrefixEntryPoint::Ty => grammar::entry::prefix::ty, PrefixEntryPoint::Expr => grammar::entry::prefix::expr, + PrefixEntryPoint::Path => grammar::entry::prefix::path, }; let mut p = parser::Parser::new(input); entry_point(&mut p); @@ -112,8 +114,8 @@ pub fn parse_source_file(inp: &Input) -> Output { pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { let entry_point: fn(&'_ mut parser::Parser) = match entry_point { ParserEntryPoint::SourceFile => grammar::entry_points::source_file, - ParserEntryPoint::Path => grammar::entry_points::path, - ParserEntryPoint::Expr => grammar::entry_points::expr, + ParserEntryPoint::Path => grammar::entry::prefix::path, + ParserEntryPoint::Expr => grammar::entry::prefix::expr, ParserEntryPoint::Type => grammar::entry::prefix::ty, ParserEntryPoint::Pattern => grammar::entry::prefix::pat, ParserEntryPoint::Item => grammar::entry_points::item, From 8e7fc7be65791c76c363d0a1191f45902564909c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 16:28:54 +0300 Subject: [PATCH 11/29] simplify --- crates/mbe/src/expander/matcher.rs | 46 ++++++----------------- crates/mbe/src/syntax_bridge.rs | 2 +- crates/mbe/src/tt_iter.rs | 59 +----------------------------- crates/parser/src/grammar.rs | 16 ++++---- crates/parser/src/lib.rs | 8 +++- 5 files changed, 27 insertions(+), 104 deletions(-) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 3137bd91cf8d..bcda2381a486 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -61,7 +61,6 @@ use std::rc::Rc; -use parser::ParserEntryPoint; use smallvec::{smallvec, SmallVec}; use syntax::SmolStr; @@ -690,41 +689,21 @@ fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> { fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult> { let fragment = match kind { - "path" => { - return input - .expect_fragment2(parser::PrefixEntryPoint::Path) - .map(|tt| tt.map(Fragment::Tokens)); - } - "expr" => { - return input - .expect_fragment2(parser::PrefixEntryPoint::Expr) - .map(|tt| tt.map(Fragment::Expr)); - } - "ty" => { - return input - .expect_fragment2(parser::PrefixEntryPoint::Ty) - .map(|tt| tt.map(Fragment::Tokens)); - } + "path" => parser::PrefixEntryPoint::Path, + "ty" => parser::PrefixEntryPoint::Ty, // FIXME: These two should actually behave differently depending on the edition. // // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html - "pat" | "pat_param" => { + "pat" | "pat_param" => parser::PrefixEntryPoint::Pat, + "stmt" => parser::PrefixEntryPoint::Stmt, + "block" => parser::PrefixEntryPoint::Block, + "meta" => parser::PrefixEntryPoint::MetaItem, + "item" => parser::PrefixEntryPoint::Item, + "expr" => { return input - .expect_fragment2(parser::PrefixEntryPoint::Pat) - .map(|tt| tt.map(Fragment::Tokens)); + .expect_fragment(parser::PrefixEntryPoint::Expr) + .map(|tt| tt.map(Fragment::Expr)) } - "stmt" => { - return input - .expect_fragment2(parser::PrefixEntryPoint::Stmt) - .map(|tt| tt.map(Fragment::Tokens)); - } - "block" => { - return input - .expect_fragment2(parser::PrefixEntryPoint::Block) - .map(|tt| tt.map(Fragment::Tokens)); - } - "meta" => ParserEntryPoint::MetaItem, - "item" => ParserEntryPoint::Item, _ => { let tt_result = match kind { "ident" => input @@ -752,14 +731,13 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult Ok(input.expect_fragment2(parser::PrefixEntryPoint::Vis).value), + "vis" => Ok(input.expect_fragment(parser::PrefixEntryPoint::Vis).value), _ => Err(ExpandError::UnexpectedToken), }; return tt_result.map(|it| it.map(Fragment::Tokens)).into(); } }; - let result = input.expect_fragment(fragment); - result.map(|tt| if kind == "expr" { tt.map(Fragment::Expr) } else { tt.map(Fragment::Tokens) }) + input.expect_fragment(fragment).map(|it| it.map(Fragment::Tokens)) } fn collect_vars(buf: &mut Vec, pattern: &MetaTemplate) { diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index f0c1f806ffae..896e33663eff 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -106,7 +106,7 @@ pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec { let mut res = Vec::new(); while iter.peek_n(0).is_some() { - let expanded = iter.expect_fragment(ParserEntryPoint::Expr); + let expanded = iter.expect_fragment(parser::PrefixEntryPoint::Expr); res.push(match expanded.value { None => break, diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs index 03d0cbee8b13..6c9f615c7a92 100644 --- a/crates/mbe/src/tt_iter.rs +++ b/crates/mbe/src/tt_iter.rs @@ -1,7 +1,7 @@ //! A "Parser" structure for token trees. We use this when parsing a declarative //! macro definition into a list of patterns and templates. -use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult, ParserEntryPoint}; +use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult}; use syntax::SyntaxKind; use tt::buffer::TokenBuffer; @@ -90,63 +90,6 @@ impl<'a> TtIter<'a> { } pub(crate) fn expect_fragment( - &mut self, - entry_point: ParserEntryPoint, - ) -> ExpandResult> { - let buffer = TokenBuffer::from_tokens(self.inner.as_slice()); - let parser_input = to_parser_input(&buffer); - let tree_traversal = parser::parse(&parser_input, entry_point); - - let mut cursor = buffer.begin(); - let mut error = false; - for step in tree_traversal.iter() { - match step { - parser::Step::Token { kind, mut n_input_tokens } => { - if kind == SyntaxKind::LIFETIME_IDENT { - n_input_tokens = 2; - } - for _ in 0..n_input_tokens { - cursor = cursor.bump_subtree(); - } - } - parser::Step::Enter { .. } | parser::Step::Exit => (), - parser::Step::Error { .. } => error = true, - } - } - - let mut err = if !cursor.is_root() || error { - Some(err!("expected {:?}", entry_point)) - } else { - None - }; - - let mut curr = buffer.begin(); - let mut res = vec![]; - - if cursor.is_root() { - while curr != cursor { - if let Some(token) = curr.token_tree() { - res.push(token); - } - curr = curr.bump(); - } - } - self.inner = self.inner.as_slice()[res.len()..].iter(); - if res.is_empty() && err.is_none() { - err = Some(err!("no tokens consumed")); - } - let res = match res.len() { - 1 => Some(res[0].cloned()), - 0 => None, - _ => Some(tt::TokenTree::Subtree(tt::Subtree { - delimiter: None, - token_trees: res.into_iter().map(|it| it.cloned()).collect(), - })), - }; - ExpandResult { value: res, err } - } - - pub(crate) fn expect_fragment2( &mut self, entry_point: parser::PrefixEntryPoint, ) -> ExpandResult> { diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 8310b38b9293..0e663b9ac01c 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -75,6 +75,13 @@ pub(crate) mod entry { pub(crate) fn path(p: &mut Parser) { let _ = paths::type_path(p); } + pub(crate) fn item(p: &mut Parser) { + items::item_or_macro(p, true); + } + // Parse a meta item , which excluded [], e.g : #[ MetaItem ] + pub(crate) fn meta_item(p: &mut Parser) { + attributes::meta(p); + } } } @@ -92,15 +99,6 @@ pub(crate) mod entry_points { expressions::stmt(p, expressions::StmtWithSemi::Optional, false); } - // Parse a meta item , which excluded [], e.g : #[ MetaItem ] - pub(crate) fn meta_item(p: &mut Parser) { - attributes::meta(p); - } - - pub(crate) fn item(p: &mut Parser) { - items::item_or_macro(p, true); - } - pub(crate) fn macro_items(p: &mut Parser) { let m = p.start(); items::mod_contents(p, false); diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 867acc45f3f3..9039985da2b3 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -59,6 +59,8 @@ pub enum PrefixEntryPoint { Ty, Expr, Path, + Item, + MetaItem, } impl PrefixEntryPoint { @@ -71,6 +73,8 @@ impl PrefixEntryPoint { PrefixEntryPoint::Ty => grammar::entry::prefix::ty, PrefixEntryPoint::Expr => grammar::entry::prefix::expr, PrefixEntryPoint::Path => grammar::entry::prefix::path, + PrefixEntryPoint::Item => grammar::entry::prefix::item, + PrefixEntryPoint::MetaItem => grammar::entry::prefix::meta_item, }; let mut p = parser::Parser::new(input); entry_point(&mut p); @@ -118,8 +122,8 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::Expr => grammar::entry::prefix::expr, ParserEntryPoint::Type => grammar::entry::prefix::ty, ParserEntryPoint::Pattern => grammar::entry::prefix::pat, - ParserEntryPoint::Item => grammar::entry_points::item, - ParserEntryPoint::MetaItem => grammar::entry_points::meta_item, + ParserEntryPoint::Item => grammar::entry::prefix::item, + ParserEntryPoint::MetaItem => grammar::entry::prefix::meta_item, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, ParserEntryPoint::Items => grammar::entry_points::macro_items, ParserEntryPoint::Statements => grammar::entry_points::macro_stmts, From afffa096f6f83c9c7c800e369fd74bd6a8015049 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 17:54:51 +0300 Subject: [PATCH 12/29] add TopEntryPoint --- crates/hir_def/src/attr.rs | 3 +- crates/hir_expand/src/builtin_derive_macro.rs | 2 +- crates/hir_expand/src/db.rs | 10 +-- crates/hir_expand/src/eager.rs | 2 +- crates/mbe/src/lib.rs | 2 +- crates/mbe/src/syntax_bridge.rs | 8 +-- crates/parser/src/grammar.rs | 60 +++++++++--------- crates/parser/src/lib.rs | 61 ++++++++++++++++--- 8 files changed, 96 insertions(+), 52 deletions(-) diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 36e46a103c1b..383ad7f0c832 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -714,8 +714,7 @@ impl Attr { hygiene: &Hygiene, id: AttrId, ) -> Option { - let (parse, _) = - mbe::token_tree_to_syntax_node(tt, mbe::ParserEntryPoint::MetaItem).ok()?; + let (parse, _) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem).ok()?; let ast = ast::Meta::cast(parse.syntax_node())?; Self::from_src(db, ast, hygiene, id) diff --git a/crates/hir_expand/src/builtin_derive_macro.rs b/crates/hir_expand/src/builtin_derive_macro.rs index c20dae8e6f79..c1542f48f0e1 100644 --- a/crates/hir_expand/src/builtin_derive_macro.rs +++ b/crates/hir_expand/src/builtin_derive_macro.rs @@ -72,7 +72,7 @@ struct BasicAdtInfo { } fn parse_adt(tt: &tt::Subtree) -> Result { - let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::ParserEntryPoint::Items)?; // FragmentKind::Items doesn't parse attrs? + let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems)?; // FragmentKind::Items doesn't parse attrs? let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| { debug!("derive node didn't parse"); mbe::ExpandError::UnexpectedToken diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 747a19a50927..3369e3e5fedf 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs @@ -497,11 +497,11 @@ fn token_tree_to_syntax_node( expand_to: ExpandTo, ) -> Result<(Parse, mbe::TokenMap), ExpandError> { let entry_point = match expand_to { - ExpandTo::Statements => mbe::ParserEntryPoint::Statements, - ExpandTo::Items => mbe::ParserEntryPoint::Items, - ExpandTo::Pattern => mbe::ParserEntryPoint::Pattern, - ExpandTo::Type => mbe::ParserEntryPoint::Type, - ExpandTo::Expr => mbe::ParserEntryPoint::Expr, + ExpandTo::Statements => mbe::TopEntryPoint::MacroStmts, + ExpandTo::Items => mbe::TopEntryPoint::MacroItems, + ExpandTo::Pattern => mbe::TopEntryPoint::Pattern, + ExpandTo::Type => mbe::TopEntryPoint::Type, + ExpandTo::Expr => mbe::TopEntryPoint::Expr, }; mbe::token_tree_to_syntax_node(tt, entry_point) } diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index ea57c2c41012..1d29ad26307e 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs @@ -131,7 +131,7 @@ pub fn expand_eager_macro( let arg_file_id = arg_id; let parsed_args = diagnostic_sink - .result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::ParserEntryPoint::Expr))? + .result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr))? .0; let result = eager_macro_recur( db, diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 5e14a3fb5902..62e7509eb37c 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -24,7 +24,7 @@ use crate::{ }; // FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces -pub use ::parser::ParserEntryPoint; +pub use ::parser::TopEntryPoint; pub use tt::{Delimiter, DelimiterKind, Punct}; #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 896e33663eff..8bdc5e6e9463 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -9,9 +9,7 @@ use syntax::{ }; use tt::buffer::{Cursor, TokenBuffer}; -use crate::{ - to_parser_input::to_parser_input, tt_iter::TtIter, ExpandError, ParserEntryPoint, TokenMap, -}; +use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, ExpandError, TokenMap}; /// Convert the syntax node to a `TokenTree` (what macro /// will consume). @@ -46,7 +44,7 @@ pub fn syntax_node_to_token_tree_censored( pub fn token_tree_to_syntax_node( tt: &tt::Subtree, - entry_point: ParserEntryPoint, + entry_point: parser::TopEntryPoint, ) -> Result<(Parse, TokenMap), ExpandError> { let buffer = match tt { tt::Subtree { delimiter: None, token_trees } => { @@ -55,7 +53,7 @@ pub fn token_tree_to_syntax_node( _ => TokenBuffer::from_subtree(tt), }; let parser_input = to_parser_input(&buffer); - let parser_output = parser::parse(&parser_input, entry_point); + let parser_output = entry_point.parse(&parser_input); let mut tree_sink = TtTreeSink::new(buffer.begin()); for event in parser_output.iter() { match event { diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 0e663b9ac01c..5fbeca44323a 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -83,43 +83,47 @@ pub(crate) mod entry { attributes::meta(p); } } + + pub(crate) mod top { + use super::*; + + pub(crate) fn source_file(p: &mut Parser) { + let m = p.start(); + p.eat(SHEBANG); + items::mod_contents(p, false); + m.complete(p, SOURCE_FILE); + } + + pub(crate) fn macro_stmts(p: &mut Parser) { + let m = p.start(); + + while !p.at(EOF) { + if p.at(T![;]) { + p.bump(T![;]); + continue; + } + + expressions::stmt(p, expressions::StmtWithSemi::Optional, true); + } + + m.complete(p, MACRO_STMTS); + } + + pub(crate) fn macro_items(p: &mut Parser) { + let m = p.start(); + items::mod_contents(p, false); + m.complete(p, MACRO_ITEMS); + } + } } pub(crate) mod entry_points { use super::*; - pub(crate) fn source_file(p: &mut Parser) { - let m = p.start(); - p.eat(SHEBANG); - items::mod_contents(p, false); - m.complete(p, SOURCE_FILE); - } - pub(crate) fn stmt_optional_semi(p: &mut Parser) { expressions::stmt(p, expressions::StmtWithSemi::Optional, false); } - pub(crate) fn macro_items(p: &mut Parser) { - let m = p.start(); - items::mod_contents(p, false); - m.complete(p, MACRO_ITEMS); - } - - pub(crate) fn macro_stmts(p: &mut Parser) { - let m = p.start(); - - while !p.at(EOF) { - if p.at(T![;]) { - p.bump(T![;]); - continue; - } - - expressions::stmt(p, expressions::StmtWithSemi::Optional, true); - } - - m.complete(p, MACRO_STMTS); - } - pub(crate) fn attr(p: &mut Parser) { attributes::outer_attrs(p); } diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 9039985da2b3..23ce233dfd4c 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -41,7 +41,7 @@ pub use crate::{ syntax_kind::SyntaxKind, }; -/// Parse a syntactic construct at the *start* of the input. +/// Parse a prefix of the input as a given syntactic construct. /// /// This is used by macro-by-example parser to implement things like `$i:item` /// and the naming of variants follows the naming of macro fragments. @@ -83,13 +83,61 @@ impl PrefixEntryPoint { } } +/// Parse the whole of the input as a given syntactic construct. +/// +/// This covers two main use-cases: +/// +/// * Parsing a Rust file. +/// * Parsing a result of macro expansion. +/// +/// That is, for something like +/// +/// ``` +/// quick_check! { +/// fn prop() {} +/// } +/// ``` +/// +/// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and +/// the result will be [`TopEntryPoint::Items`]. +/// +/// This *should* (but currently doesn't) guarantee that all input is consumed. +#[derive(Debug)] +pub enum TopEntryPoint { + SourceFile, + MacroStmts, + MacroItems, + Pattern, + Type, + Expr, + MetaItem, +} + +impl TopEntryPoint { + pub fn parse(&self, input: &Input) -> Output { + let entry_point: fn(&'_ mut parser::Parser) = match self { + TopEntryPoint::SourceFile => grammar::entry::top::source_file, + TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts, + TopEntryPoint::MacroItems => grammar::entry::top::macro_items, + // FIXME + TopEntryPoint::Pattern => grammar::entry::prefix::pat, + TopEntryPoint::Type => grammar::entry::prefix::ty, + TopEntryPoint::Expr => grammar::entry::prefix::expr, + TopEntryPoint::MetaItem => grammar::entry::prefix::meta_item, + }; + let mut p = parser::Parser::new(input); + entry_point(&mut p); + let events = p.finish(); + event::process(events) + } +} + /// rust-analyzer parser allows you to choose one of the possible entry points. /// /// The primary consumer of this API are declarative macros, `$x:expr` matchers /// are implemented by calling into the parser with non-standard entry point. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum ParserEntryPoint { - SourceFile, Path, Expr, StatementOptionalSemi, @@ -97,14 +145,12 @@ pub enum ParserEntryPoint { Pattern, Item, MetaItem, - Items, - Statements, Attr, } /// Parse given tokens into the given sink as a rust file. -pub fn parse_source_file(inp: &Input) -> Output { - parse(inp, ParserEntryPoint::SourceFile) +pub fn parse_source_file(input: &Input) -> Output { + TopEntryPoint::SourceFile.parse(input) } /// Parses the given [`Input`] into [`Output`] assuming that the top-level @@ -117,7 +163,6 @@ pub fn parse_source_file(inp: &Input) -> Output { /// indices between the four stages. pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { let entry_point: fn(&'_ mut parser::Parser) = match entry_point { - ParserEntryPoint::SourceFile => grammar::entry_points::source_file, ParserEntryPoint::Path => grammar::entry::prefix::path, ParserEntryPoint::Expr => grammar::entry::prefix::expr, ParserEntryPoint::Type => grammar::entry::prefix::ty, @@ -125,8 +170,6 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::Item => grammar::entry::prefix::item, ParserEntryPoint::MetaItem => grammar::entry::prefix::meta_item, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, - ParserEntryPoint::Items => grammar::entry_points::macro_items, - ParserEntryPoint::Statements => grammar::entry_points::macro_stmts, ParserEntryPoint::Attr => grammar::entry_points::attr, }; From 8794892432ab08c31b9d35e0aa41a3952198afa1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 18:04:13 +0300 Subject: [PATCH 13/29] dead code --- crates/parser/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 23ce233dfd4c..6827cf8bf1a1 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -144,7 +144,6 @@ pub enum ParserEntryPoint { Type, Pattern, Item, - MetaItem, Attr, } @@ -168,7 +167,6 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::Type => grammar::entry::prefix::ty, ParserEntryPoint::Pattern => grammar::entry::prefix::pat, ParserEntryPoint::Item => grammar::entry::prefix::item, - ParserEntryPoint::MetaItem => grammar::entry::prefix::meta_item, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, ParserEntryPoint::Attr => grammar::entry_points::attr, }; From 634c7682c9b0da402fa055acab5969c88db585d4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 19:04:49 +0300 Subject: [PATCH 14/29] add missing test --- crates/ide_ssr/src/tests.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/ide_ssr/src/tests.rs b/crates/ide_ssr/src/tests.rs index 0b0c1111c466..028e0bec914f 100644 --- a/crates/ide_ssr/src/tests.rs +++ b/crates/ide_ssr/src/tests.rs @@ -792,6 +792,19 @@ fn replace_type() { "struct Result {} struct Option {} fn f1() -> Option> {foo()}" ]], ); + assert_ssr_transform( + "dyn Trait<$a> ==>> DynTrait<$a>", + r#" +trait Trait {} +struct DynTrait {} +fn f1() -> dyn Trait> {foo()} +"#, + expect![[r#" +trait Trait {} +struct DynTrait {} +fn f1() -> DynTrait> {foo()} +"#]], + ); } #[test] From b468bd664539ece8db6ac63d3d652ec0679edd9e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 19:44:45 +0300 Subject: [PATCH 15/29] internal: start isolating ssr-related parsing APIs to SSR --- crates/ide_ssr/src/fragments.rs | 21 ++++++++++++++++ crates/ide_ssr/src/lib.rs | 1 + crates/ide_ssr/src/parsing.rs | 24 +++++++++++++++++-- crates/parser/src/lib.rs | 2 -- crates/syntax/src/lib.rs | 7 ------ crates/syntax/src/tests.rs | 9 ------- .../type/err/0000_missing_close.rast | 1 - .../fragments/type/err/0000_missing_close.rs | 1 - .../parser/fragments/type/ok/0000_result.rast | 22 ----------------- .../parser/fragments/type/ok/0000_result.rs | 1 - 10 files changed, 44 insertions(+), 45 deletions(-) create mode 100644 crates/ide_ssr/src/fragments.rs delete mode 100644 crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast delete mode 100644 crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs delete mode 100644 crates/syntax/test_data/parser/fragments/type/ok/0000_result.rast delete mode 100644 crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs new file mode 100644 index 000000000000..0abf9e4d98cf --- /dev/null +++ b/crates/ide_ssr/src/fragments.rs @@ -0,0 +1,21 @@ +//! When specifying SSR rule, you generally want to map one *kind* of thing to +//! the same kind of thing: path to path, expression to expression, type to +//! type. +//! +//! The problem is, while this *kind* is generally obvious to the human, the ide +//! needs to determine it somehow. We do this in a stupid way -- by pasting SSR +//! rule into different contexts and checking what works. + +use parser::SyntaxKind; +use syntax::{ast, AstNode, SyntaxNode}; + +pub(crate) fn ty(s: &str) -> Result { + let template = "type T = {};"; + let input = template.replace("{}", s); + let parse = syntax::SourceFile::parse(&input); + if !parse.errors().is_empty() { + return Err(()); + } + let node = parse.tree().syntax().descendants().find_map(ast::Type::cast).ok_or(())?; + Ok(node.syntax().clone()) +} diff --git a/crates/ide_ssr/src/lib.rs b/crates/ide_ssr/src/lib.rs index 2fe1f5b616ed..d56bc12b680c 100644 --- a/crates/ide_ssr/src/lib.rs +++ b/crates/ide_ssr/src/lib.rs @@ -71,6 +71,7 @@ mod from_comment; mod matching; mod nester; mod parsing; +mod fragments; mod replacing; mod resolving; mod search; diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs index ae7d5b4bf156..b32efe879a47 100644 --- a/crates/ide_ssr/src/parsing.rs +++ b/crates/ide_ssr/src/parsing.rs @@ -6,7 +6,7 @@ //! e.g. expressions, type references etc. use crate::errors::bail; -use crate::{SsrError, SsrPattern, SsrRule}; +use crate::{fragments, SsrError, SsrPattern, SsrRule}; use rustc_hash::{FxHashMap, FxHashSet}; use std::{fmt::Display, str::FromStr}; use syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, T}; @@ -79,7 +79,7 @@ impl ParsedRule { } else { builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone()); } - builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse)); + builder.try_add2(fragments::ty(&raw_pattern), raw_template.map(fragments::ty)); builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); @@ -114,6 +114,26 @@ impl RuleBuilder { } } + fn try_add2( + &mut self, + pattern: Result, + template: Option>, + ) { + match (pattern, template) { + (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { + placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), + pattern, + template: Some(template), + }), + (Ok(pattern), None) => self.rules.push(ParsedRule { + placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), + pattern, + template: None, + }), + _ => {} + } + } + fn build(mut self) -> Result, SsrError> { if self.rules.is_empty() { bail!("Not a valid Rust expression, type, item, path or pattern"); diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 6827cf8bf1a1..fb5280d1977f 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -141,7 +141,6 @@ pub enum ParserEntryPoint { Path, Expr, StatementOptionalSemi, - Type, Pattern, Item, Attr, @@ -164,7 +163,6 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { let entry_point: fn(&'_ mut parser::Parser) = match entry_point { ParserEntryPoint::Path => grammar::entry::prefix::path, ParserEntryPoint::Expr => grammar::entry::prefix::expr, - ParserEntryPoint::Type => grammar::entry::prefix::ty, ParserEntryPoint::Pattern => grammar::entry::prefix::pat, ParserEntryPoint::Item => grammar::entry::prefix::item, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 65a6b7ac4e4a..b82df6616248 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -201,13 +201,6 @@ impl ast::Item { } } -impl ast::Type { - /// Returns `text`, parsed as an type reference, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Type) - } -} - impl ast::Attr { /// Returns `text`, parsed as an attribute, but only if it has no errors. pub fn parse(text: &str) -> Result { diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs index 04105dedc9ed..a632d0e6309d 100644 --- a/crates/syntax/src/tests.rs +++ b/crates/syntax/src/tests.rs @@ -95,15 +95,6 @@ fn item_parser_tests() { ); } -#[test] -fn type_parser_tests() { - fragment_parser_dir_test( - &["parser/fragments/type/ok"], - &["parser/fragments/type/err"], - crate::ast::Type::parse, - ); -} - #[test] fn stmt_parser_tests() { fragment_parser_dir_test( diff --git a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast b/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs b/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs deleted file mode 100644 index caa4d7c09275..000000000000 --- a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs +++ /dev/null @@ -1 +0,0 @@ -Result" diff --git a/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs b/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs deleted file mode 100644 index b50b3bb3bfd6..000000000000 --- a/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs +++ /dev/null @@ -1 +0,0 @@ -Result From f0fefde4017fa077a018c4ed03a66b5c6970fb8a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 20:33:33 +0300 Subject: [PATCH 16/29] remove Item::parse --- crates/ide_ssr/src/fragments.rs | 11 +++++++++++ crates/ide_ssr/src/parsing.rs | 2 +- crates/ide_ssr/src/replacing.rs | 8 +++++--- crates/parser/src/lib.rs | 2 -- crates/syntax/src/lib.rs | 7 ------- crates/syntax/src/tests.rs | 9 --------- 6 files changed, 17 insertions(+), 22 deletions(-) diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs index 0abf9e4d98cf..5eaad8b1d537 100644 --- a/crates/ide_ssr/src/fragments.rs +++ b/crates/ide_ssr/src/fragments.rs @@ -19,3 +19,14 @@ pub(crate) fn ty(s: &str) -> Result { let node = parse.tree().syntax().descendants().find_map(ast::Type::cast).ok_or(())?; Ok(node.syntax().clone()) } + +pub(crate) fn item(s: &str) -> Result { + let template = "{}"; + let input = template.replace("{}", s); + let parse = syntax::SourceFile::parse(&input); + if !parse.errors().is_empty() { + return Err(()); + } + let node = parse.tree().syntax().descendants().find_map(ast::Item::cast).ok_or(())?; + Ok(node.syntax().clone()) +} diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs index b32efe879a47..1d5633cfe007 100644 --- a/crates/ide_ssr/src/parsing.rs +++ b/crates/ide_ssr/src/parsing.rs @@ -80,7 +80,7 @@ impl ParsedRule { builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone()); } builder.try_add2(fragments::ty(&raw_pattern), raw_template.map(fragments::ty)); - builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); + builder.try_add2(fragments::item(&raw_pattern), raw_template.map(fragments::item)); builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt); diff --git a/crates/ide_ssr/src/replacing.rs b/crates/ide_ssr/src/replacing.rs index 9265af7c13a6..1c4cb6bc7704 100644 --- a/crates/ide_ssr/src/replacing.rs +++ b/crates/ide_ssr/src/replacing.rs @@ -1,5 +1,6 @@ //! Code for applying replacement templates for matches that have previously been found. +use crate::fragments; use crate::{resolving::ResolvedRule, Match, SsrMatches}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; @@ -228,9 +229,10 @@ fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option { if let Ok(expr) = ast::Expr::parse(code) { return Some(expr.syntax().clone()); } - } else if ast::Item::can_cast(kind) { - if let Ok(item) = ast::Item::parse(code) { - return Some(item.syntax().clone()); + } + if ast::Item::can_cast(kind) { + if let Ok(item) = fragments::item(code) { + return Some(item); } } None diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index fb5280d1977f..da62590ab66c 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -142,7 +142,6 @@ pub enum ParserEntryPoint { Expr, StatementOptionalSemi, Pattern, - Item, Attr, } @@ -164,7 +163,6 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { ParserEntryPoint::Path => grammar::entry::prefix::path, ParserEntryPoint::Expr => grammar::entry::prefix::expr, ParserEntryPoint::Pattern => grammar::entry::prefix::pat, - ParserEntryPoint::Item => grammar::entry::prefix::item, ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, ParserEntryPoint::Attr => grammar::entry_points::attr, }; diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index b82df6616248..a495e4aff175 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -194,13 +194,6 @@ impl ast::Expr { } } -impl ast::Item { - /// Returns `text`, parsed as an item, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Item) - } -} - impl ast::Attr { /// Returns `text`, parsed as an attribute, but only if it has no errors. pub fn parse(text: &str) -> Result { diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs index a632d0e6309d..a1f35aab680d 100644 --- a/crates/syntax/src/tests.rs +++ b/crates/syntax/src/tests.rs @@ -86,15 +86,6 @@ fn pattern_parser_tests() { ); } -#[test] -fn item_parser_tests() { - fragment_parser_dir_test( - &["parser/fragments/item/ok"], - &["parser/fragments/item/err"], - crate::ast::Item::parse, - ); -} - #[test] fn stmt_parser_tests() { fragment_parser_dir_test( From b8b965523613022633cf91eff9c2ee724da9a6eb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 20:41:17 +0300 Subject: [PATCH 17/29] add test --- crates/ide_ssr/src/tests.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/ide_ssr/src/tests.rs b/crates/ide_ssr/src/tests.rs index 028e0bec914f..30eda9d56cb5 100644 --- a/crates/ide_ssr/src/tests.rs +++ b/crates/ide_ssr/src/tests.rs @@ -331,6 +331,15 @@ fn ssr_struct_lit() { ) } +#[test] +fn ssr_struct_def() { + assert_ssr_transform( + "struct Foo { $f: $t } ==>> struct Foo($t);", + r#"struct Foo { field: i32 }"#, + expect![[r#"struct Foo(i32);"#]], + ) +} + #[test] fn ignores_whitespace() { assert_matches("1+2", "fn f() -> i32 {1 + 2}", &["1 + 2"]); From 2d373dc53cc0cbbcefcbe15bec4097ab57195703 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:05:26 +0300 Subject: [PATCH 18/29] verify during parse --- crates/ide_ssr/src/fragments.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs index 5eaad8b1d537..72d26d53a311 100644 --- a/crates/ide_ssr/src/fragments.rs +++ b/crates/ide_ssr/src/fragments.rs @@ -6,7 +6,6 @@ //! needs to determine it somehow. We do this in a stupid way -- by pasting SSR //! rule into different contexts and checking what works. -use parser::SyntaxKind; use syntax::{ast, AstNode, SyntaxNode}; pub(crate) fn ty(s: &str) -> Result { @@ -17,6 +16,9 @@ pub(crate) fn ty(s: &str) -> Result { return Err(()); } let node = parse.tree().syntax().descendants().find_map(ast::Type::cast).ok_or(())?; + if node.to_string() != s { + return Err(()); + } Ok(node.syntax().clone()) } @@ -28,5 +30,8 @@ pub(crate) fn item(s: &str) -> Result { return Err(()); } let node = parse.tree().syntax().descendants().find_map(ast::Item::cast).ok_or(())?; + if node.to_string() != s { + return Err(()); + } Ok(node.syntax().clone()) } From df2a996cb0b50046cded86ea090d839d1ddfc0da Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:13:55 +0300 Subject: [PATCH 19/29] add ssr fragment for expressions --- crates/ide_ssr/src/fragments.rs | 14 ++++++++++++++ crates/ide_ssr/src/parsing.rs | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs index 72d26d53a311..512b3ace01a4 100644 --- a/crates/ide_ssr/src/fragments.rs +++ b/crates/ide_ssr/src/fragments.rs @@ -35,3 +35,17 @@ pub(crate) fn item(s: &str) -> Result { } Ok(node.syntax().clone()) } + +pub(crate) fn expr(s: &str) -> Result { + let template = "const _: () = {};"; + let input = template.replace("{}", s); + let parse = syntax::SourceFile::parse(&input); + if !parse.errors().is_empty() { + return Err(()); + } + let node = parse.tree().syntax().descendants().find_map(ast::Expr::cast).ok_or(())?; + if node.to_string() != s { + return Err(()); + } + Ok(node.syntax().clone()) +} diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs index 1d5633cfe007..03c7fed03959 100644 --- a/crates/ide_ssr/src/parsing.rs +++ b/crates/ide_ssr/src/parsing.rs @@ -74,8 +74,8 @@ impl ParsedRule { }; let raw_template_stmt = raw_template.map(ast::Stmt::parse); - if let raw_template_expr @ Some(Ok(_)) = raw_template.map(ast::Expr::parse) { - builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_expr); + if let raw_template_expr @ Some(Ok(_)) = raw_template.map(fragments::expr) { + builder.try_add2(fragments::expr(&raw_pattern), raw_template_expr); } else { builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone()); } From 2cbfcf431ed5d22a2b32fbe87140d72b88304161 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:17:40 +0300 Subject: [PATCH 20/29] add ssr fragment for statements --- crates/ide_ssr/src/fragments.rs | 25 ++++++++++++++++++++++--- crates/ide_ssr/src/parsing.rs | 6 +++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs index 512b3ace01a4..4c768a970b19 100644 --- a/crates/ide_ssr/src/fragments.rs +++ b/crates/ide_ssr/src/fragments.rs @@ -19,7 +19,7 @@ pub(crate) fn ty(s: &str) -> Result { if node.to_string() != s { return Err(()); } - Ok(node.syntax().clone()) + Ok(node.syntax().clone_subtree()) } pub(crate) fn item(s: &str) -> Result { @@ -33,7 +33,7 @@ pub(crate) fn item(s: &str) -> Result { if node.to_string() != s { return Err(()); } - Ok(node.syntax().clone()) + Ok(node.syntax().clone_subtree()) } pub(crate) fn expr(s: &str) -> Result { @@ -47,5 +47,24 @@ pub(crate) fn expr(s: &str) -> Result { if node.to_string() != s { return Err(()); } - Ok(node.syntax().clone()) + Ok(node.syntax().clone_subtree()) +} + +pub(crate) fn stmt(s: &str) -> Result { + let template = "const _: () = { {}; };"; + let input = template.replace("{}", s); + let parse = syntax::SourceFile::parse(&input); + if !parse.errors().is_empty() { + return Err(()); + } + let mut node = + parse.tree().syntax().descendants().skip(2).find_map(ast::Stmt::cast).ok_or(())?; + if !s.ends_with(';') && node.to_string().ends_with(';') { + node = node.clone_for_update(); + node.syntax().last_token().map(|it| it.detach()); + } + if node.to_string() != s { + return Err(()); + } + Ok(node.syntax().clone_subtree()) } diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs index 03c7fed03959..7d1947dda8ba 100644 --- a/crates/ide_ssr/src/parsing.rs +++ b/crates/ide_ssr/src/parsing.rs @@ -73,17 +73,17 @@ impl ParsedRule { rules: Vec::new(), }; - let raw_template_stmt = raw_template.map(ast::Stmt::parse); + let raw_template_stmt = raw_template.map(fragments::stmt); if let raw_template_expr @ Some(Ok(_)) = raw_template.map(fragments::expr) { builder.try_add2(fragments::expr(&raw_pattern), raw_template_expr); } else { - builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone()); + builder.try_add2(fragments::expr(&raw_pattern), raw_template_stmt.clone()); } builder.try_add2(fragments::ty(&raw_pattern), raw_template.map(fragments::ty)); builder.try_add2(fragments::item(&raw_pattern), raw_template.map(fragments::item)); builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); - builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt); + builder.try_add2(fragments::stmt(&raw_pattern), raw_template_stmt); builder.build() } } From 7e9c74d20bb8b33889179315f82160285469c5f6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:26:02 +0300 Subject: [PATCH 21/29] drop dead code --- crates/ide_ssr/src/parsing.rs | 1 - crates/syntax/src/lib.rs | 7 -- crates/syntax/src/tests.rs | 18 ----- .../expr/err/0000_truncated_add.rast | 1 - .../fragments/expr/err/0000_truncated_add.rs | 1 - .../parser/fragments/expr/ok/0000_add.rast | 8 --- .../parser/fragments/expr/ok/0000_add.rs | 1 - .../parser/fragments/stmt/err/0000_attr.rast | 1 - .../parser/fragments/stmt/err/0000_attr.rs | 1 - .../stmt/err/0000_multiple_stmts.rast | 1 - .../fragments/stmt/err/0000_multiple_stmts.rs | 1 - .../stmt/err/0000_open_parenthesis.rast | 1 - .../stmt/err/0000_open_parenthesis.rs | 1 - .../fragments/stmt/err/0000_semicolon.rast | 1 - .../fragments/stmt/err/0000_semicolon.rs | 1 - .../stmt/err/0000_unterminated_expr.rast | 1 - .../stmt/err/0000_unterminated_expr.rs | 1 - .../parser/fragments/stmt/ok/0000_expr.rast | 9 --- .../parser/fragments/stmt/ok/0000_expr.rs | 1 - .../fragments/stmt/ok/0000_expr_block.rast | 70 ------------------- .../fragments/stmt/ok/0000_expr_block.rs | 5 -- .../fragments/stmt/ok/0000_fn_call.rast | 11 --- .../parser/fragments/stmt/ok/0000_fn_call.rs | 1 - .../fragments/stmt/ok/0000_let_stmt.rast | 12 ---- .../parser/fragments/stmt/ok/0000_let_stmt.rs | 1 - .../stmt/ok/0000_macro_let_stmt.rast | 21 ------ .../fragments/stmt/ok/0000_macro_let_stmt.rs | 1 - .../ok/0000_macro_unterminated_let_stmt.rast | 21 ------ .../ok/0000_macro_unterminated_let_stmt.rs | 1 - .../fragments/stmt/ok/0000_struct_item.rast | 22 ------ .../fragments/stmt/ok/0000_struct_item.rs | 3 - .../stmt/ok/0000_unterminated_fn_call.rast | 10 --- .../stmt/ok/0000_unterminated_fn_call.rs | 1 - .../stmt/ok/0000_unterminated_let_stmt.rast | 11 --- .../stmt/ok/0000_unterminated_let_stmt.rs | 1 - 35 files changed, 249 deletions(-) delete mode 100644 crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast delete mode 100644 crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs delete mode 100644 crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast delete mode 100644 crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast delete mode 100644 crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs index 7d1947dda8ba..d70823403e6b 100644 --- a/crates/ide_ssr/src/parsing.rs +++ b/crates/ide_ssr/src/parsing.rs @@ -81,7 +81,6 @@ impl ParsedRule { } builder.try_add2(fragments::ty(&raw_pattern), raw_template.map(fragments::ty)); builder.try_add2(fragments::item(&raw_pattern), raw_template.map(fragments::item)); - builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); builder.try_add2(fragments::stmt(&raw_pattern), raw_template_stmt); builder.build() diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index a495e4aff175..912bf4d1da10 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -201,13 +201,6 @@ impl ast::Attr { } } -impl ast::Stmt { - /// Returns `text`, parsed as statement, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::StatementOptionalSemi) - } -} - /// Matches a `SyntaxNode` against an `ast` type. /// /// # Example: diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs index a1f35aab680d..58c4b5b8fcd5 100644 --- a/crates/syntax/src/tests.rs +++ b/crates/syntax/src/tests.rs @@ -59,15 +59,6 @@ fn validation_tests() { }); } -#[test] -fn expr_parser_tests() { - fragment_parser_dir_test( - &["parser/fragments/expr/ok"], - &["parser/fragments/expr/err"], - crate::ast::Expr::parse, - ); -} - #[test] fn path_parser_tests() { fragment_parser_dir_test( @@ -86,15 +77,6 @@ fn pattern_parser_tests() { ); } -#[test] -fn stmt_parser_tests() { - fragment_parser_dir_test( - &["parser/fragments/stmt/ok"], - &["parser/fragments/stmt/err"], - crate::ast::Stmt::parse, - ); -} - #[test] fn parser_fuzz_tests() { for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { diff --git a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast b/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs b/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs deleted file mode 100644 index ca49acb079e2..000000000000 --- a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs +++ /dev/null @@ -1 +0,0 @@ -1 + diff --git a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast b/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast deleted file mode 100644 index fa78a02a6bf4..000000000000 --- a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast +++ /dev/null @@ -1,8 +0,0 @@ -BIN_EXPR@0..5 - LITERAL@0..1 - INT_NUMBER@0..1 "1" - WHITESPACE@1..2 " " - PLUS@2..3 "+" - WHITESPACE@3..4 " " - LITERAL@4..5 - INT_NUMBER@4..5 "2" diff --git a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs b/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs deleted file mode 100644 index e0ef5840209c..000000000000 --- a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs +++ /dev/null @@ -1 +0,0 @@ -1 + 2 diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs deleted file mode 100644 index 988df0705979..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs +++ /dev/null @@ -1 +0,0 @@ -#[foo] diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs deleted file mode 100644 index 7e3b2fd49367..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs +++ /dev/null @@ -1 +0,0 @@ -a(); b(); c() diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs deleted file mode 100644 index 2d06f376636f..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs +++ /dev/null @@ -1 +0,0 @@ -( diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs deleted file mode 100644 index 092bc2b04126..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs +++ /dev/null @@ -1 +0,0 @@ -; diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs deleted file mode 100644 index ca49acb079e2..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs +++ /dev/null @@ -1 +0,0 @@ -1 + diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast deleted file mode 100644 index 274fdf16deb9..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast +++ /dev/null @@ -1,9 +0,0 @@ -EXPR_STMT@0..5 - BIN_EXPR@0..5 - LITERAL@0..1 - INT_NUMBER@0..1 "1" - WHITESPACE@1..2 " " - PLUS@2..3 "+" - WHITESPACE@3..4 " " - LITERAL@4..5 - INT_NUMBER@4..5 "1" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs deleted file mode 100644 index 8d2f0971e2ce..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs +++ /dev/null @@ -1 +0,0 @@ -1 + 1 diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast deleted file mode 100644 index a2d4f18988a9..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast +++ /dev/null @@ -1,70 +0,0 @@ -EXPR_STMT@0..55 - BLOCK_EXPR@0..55 - STMT_LIST@0..55 - L_CURLY@0..1 "{" - WHITESPACE@1..6 "\n " - LET_STMT@6..20 - LET_KW@6..9 "let" - WHITESPACE@9..10 " " - IDENT_PAT@10..11 - NAME@10..11 - IDENT@10..11 "x" - WHITESPACE@11..12 " " - EQ@12..13 "=" - WHITESPACE@13..14 " " - CALL_EXPR@14..19 - PATH_EXPR@14..17 - PATH@14..17 - PATH_SEGMENT@14..17 - NAME_REF@14..17 - IDENT@14..17 "foo" - ARG_LIST@17..19 - L_PAREN@17..18 "(" - R_PAREN@18..19 ")" - SEMICOLON@19..20 ";" - WHITESPACE@20..25 "\n " - LET_STMT@25..39 - LET_KW@25..28 "let" - WHITESPACE@28..29 " " - IDENT_PAT@29..30 - NAME@29..30 - IDENT@29..30 "y" - WHITESPACE@30..31 " " - EQ@31..32 "=" - WHITESPACE@32..33 " " - CALL_EXPR@33..38 - PATH_EXPR@33..36 - PATH@33..36 - PATH_SEGMENT@33..36 - NAME_REF@33..36 - IDENT@33..36 "bar" - ARG_LIST@36..38 - L_PAREN@36..37 "(" - R_PAREN@37..38 ")" - SEMICOLON@38..39 ";" - WHITESPACE@39..44 "\n " - CALL_EXPR@44..53 - PATH_EXPR@44..46 - PATH@44..46 - PATH_SEGMENT@44..46 - NAME_REF@44..46 - IDENT@44..46 "Ok" - ARG_LIST@46..53 - L_PAREN@46..47 "(" - BIN_EXPR@47..52 - PATH_EXPR@47..48 - PATH@47..48 - PATH_SEGMENT@47..48 - NAME_REF@47..48 - IDENT@47..48 "x" - WHITESPACE@48..49 " " - PLUS@49..50 "+" - WHITESPACE@50..51 " " - PATH_EXPR@51..52 - PATH@51..52 - PATH_SEGMENT@51..52 - NAME_REF@51..52 - IDENT@51..52 "y" - R_PAREN@52..53 ")" - WHITESPACE@53..54 "\n" - R_CURLY@54..55 "}" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs deleted file mode 100644 index ffa5c1e66ef6..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs +++ /dev/null @@ -1,5 +0,0 @@ -{ - let x = foo(); - let y = bar(); - Ok(x + y) -} diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast deleted file mode 100644 index 8c186da93eed..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast +++ /dev/null @@ -1,11 +0,0 @@ -EXPR_STMT@0..6 - CALL_EXPR@0..5 - PATH_EXPR@0..3 - PATH@0..3 - PATH_SEGMENT@0..3 - NAME_REF@0..3 - IDENT@0..3 "foo" - ARG_LIST@3..5 - L_PAREN@3..4 "(" - R_PAREN@4..5 ")" - SEMICOLON@5..6 ";" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs deleted file mode 100644 index a280f9a5cce6..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs +++ /dev/null @@ -1 +0,0 @@ -foo(); diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast deleted file mode 100644 index 8ab38da21cb5..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast +++ /dev/null @@ -1,12 +0,0 @@ -LET_STMT@0..11 - LET_KW@0..3 "let" - WHITESPACE@3..4 " " - IDENT_PAT@4..5 - NAME@4..5 - IDENT@4..5 "x" - WHITESPACE@5..6 " " - EQ@6..7 "=" - WHITESPACE@7..8 " " - LITERAL@8..10 - INT_NUMBER@8..10 "10" - SEMICOLON@10..11 ";" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs deleted file mode 100644 index de8a7f1fc6c4..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs +++ /dev/null @@ -1 +0,0 @@ -let x = 10; diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast deleted file mode 100644 index 81d6df29a5fb..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast +++ /dev/null @@ -1,21 +0,0 @@ -EXPR_STMT@0..18 - MACRO_CALL@0..17 - PATH@0..2 - PATH_SEGMENT@0..2 - NAME_REF@0..2 - IDENT@0..2 "m1" - BANG@2..3 "!" - TOKEN_TREE@3..17 - L_CURLY@3..4 "{" - WHITESPACE@4..5 " " - LET_KW@5..8 "let" - WHITESPACE@8..9 " " - IDENT@9..10 "a" - WHITESPACE@10..11 " " - EQ@11..12 "=" - WHITESPACE@12..13 " " - INT_NUMBER@13..14 "0" - SEMICOLON@14..15 ";" - WHITESPACE@15..16 " " - R_CURLY@16..17 "}" - SEMICOLON@17..18 ";" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs deleted file mode 100644 index 075f30159b24..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs +++ /dev/null @@ -1 +0,0 @@ -m1!{ let a = 0; }; diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast deleted file mode 100644 index 81d6df29a5fb..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast +++ /dev/null @@ -1,21 +0,0 @@ -EXPR_STMT@0..18 - MACRO_CALL@0..17 - PATH@0..2 - PATH_SEGMENT@0..2 - NAME_REF@0..2 - IDENT@0..2 "m1" - BANG@2..3 "!" - TOKEN_TREE@3..17 - L_CURLY@3..4 "{" - WHITESPACE@4..5 " " - LET_KW@5..8 "let" - WHITESPACE@8..9 " " - IDENT@9..10 "a" - WHITESPACE@10..11 " " - EQ@11..12 "=" - WHITESPACE@12..13 " " - INT_NUMBER@13..14 "0" - SEMICOLON@14..15 ";" - WHITESPACE@15..16 " " - R_CURLY@16..17 "}" - SEMICOLON@17..18 ";" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs deleted file mode 100644 index 075f30159b24..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs +++ /dev/null @@ -1 +0,0 @@ -m1!{ let a = 0; }; diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast deleted file mode 100644 index 64c5d296911e..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast +++ /dev/null @@ -1,22 +0,0 @@ -STRUCT@0..28 - STRUCT_KW@0..6 "struct" - WHITESPACE@6..7 " " - NAME@7..10 - IDENT@7..10 "Foo" - WHITESPACE@10..11 " " - RECORD_FIELD_LIST@11..28 - L_CURLY@11..12 "{" - WHITESPACE@12..17 "\n " - RECORD_FIELD@17..25 - NAME@17..20 - IDENT@17..20 "bar" - COLON@20..21 ":" - WHITESPACE@21..22 " " - PATH_TYPE@22..25 - PATH@22..25 - PATH_SEGMENT@22..25 - NAME_REF@22..25 - IDENT@22..25 "u32" - COMMA@25..26 "," - WHITESPACE@26..27 "\n" - R_CURLY@27..28 "}" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs deleted file mode 100644 index e5473e3ac8d7..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs +++ /dev/null @@ -1,3 +0,0 @@ -struct Foo { - bar: u32, -} diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast deleted file mode 100644 index 9089906bcea1..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast +++ /dev/null @@ -1,10 +0,0 @@ -EXPR_STMT@0..5 - CALL_EXPR@0..5 - PATH_EXPR@0..3 - PATH@0..3 - PATH_SEGMENT@0..3 - NAME_REF@0..3 - IDENT@0..3 "foo" - ARG_LIST@3..5 - L_PAREN@3..4 "(" - R_PAREN@4..5 ")" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs deleted file mode 100644 index eb28ef4401b2..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs +++ /dev/null @@ -1 +0,0 @@ -foo() diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast deleted file mode 100644 index 37663671fafb..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast +++ /dev/null @@ -1,11 +0,0 @@ -LET_STMT@0..10 - LET_KW@0..3 "let" - WHITESPACE@3..4 " " - IDENT_PAT@4..5 - NAME@4..5 - IDENT@4..5 "x" - WHITESPACE@5..6 " " - EQ@6..7 "=" - WHITESPACE@7..8 " " - LITERAL@8..10 - INT_NUMBER@8..10 "10" diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs deleted file mode 100644 index 78364b2a96e4..000000000000 --- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs +++ /dev/null @@ -1 +0,0 @@ -let x = 10 From dacbc6a69a5bd2ea7b4f5680d58659ec8ab4369b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:33:24 +0300 Subject: [PATCH 22/29] move the rest of ssr parsing to fragments --- crates/ide_ssr/src/fragments.rs | 14 ++++++++++++ crates/ide_ssr/src/parsing.rs | 40 +++++++++------------------------ 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs index 4c768a970b19..dab214b4074b 100644 --- a/crates/ide_ssr/src/fragments.rs +++ b/crates/ide_ssr/src/fragments.rs @@ -36,6 +36,20 @@ pub(crate) fn item(s: &str) -> Result { Ok(node.syntax().clone_subtree()) } +pub(crate) fn pat(s: &str) -> Result { + let template = "const _: () = {let {} = ();};"; + let input = template.replace("{}", s); + let parse = syntax::SourceFile::parse(&input); + if !parse.errors().is_empty() { + return Err(()); + } + let node = parse.tree().syntax().descendants().find_map(ast::Pat::cast).ok_or(())?; + if node.to_string() != s { + return Err(()); + } + Ok(node.syntax().clone_subtree()) +} + pub(crate) fn expr(s: &str) -> Result { let template = "const _: () = {};"; let input = template.replace("{}", s); diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs index d70823403e6b..aaaee576b52b 100644 --- a/crates/ide_ssr/src/parsing.rs +++ b/crates/ide_ssr/src/parsing.rs @@ -4,12 +4,12 @@ //! placeholders, which start with `$`. For replacement templates, this is the final form. For //! search patterns, we go further and parse the pattern as each kind of thing that we can match. //! e.g. expressions, type references etc. +use rustc_hash::{FxHashMap, FxHashSet}; +use std::{fmt::Display, str::FromStr}; +use syntax::{SmolStr, SyntaxKind, SyntaxNode, T}; use crate::errors::bail; use crate::{fragments, SsrError, SsrPattern, SsrRule}; -use rustc_hash::{FxHashMap, FxHashSet}; -use std::{fmt::Display, str::FromStr}; -use syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, T}; #[derive(Debug)] pub(crate) struct ParsedRule { @@ -75,14 +75,14 @@ impl ParsedRule { let raw_template_stmt = raw_template.map(fragments::stmt); if let raw_template_expr @ Some(Ok(_)) = raw_template.map(fragments::expr) { - builder.try_add2(fragments::expr(&raw_pattern), raw_template_expr); + builder.try_add(fragments::expr(&raw_pattern), raw_template_expr); } else { - builder.try_add2(fragments::expr(&raw_pattern), raw_template_stmt.clone()); + builder.try_add(fragments::expr(&raw_pattern), raw_template_stmt.clone()); } - builder.try_add2(fragments::ty(&raw_pattern), raw_template.map(fragments::ty)); - builder.try_add2(fragments::item(&raw_pattern), raw_template.map(fragments::item)); - builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); - builder.try_add2(fragments::stmt(&raw_pattern), raw_template_stmt); + builder.try_add(fragments::ty(&raw_pattern), raw_template.map(fragments::ty)); + builder.try_add(fragments::item(&raw_pattern), raw_template.map(fragments::item)); + builder.try_add(fragments::pat(&raw_pattern), raw_template.map(fragments::pat)); + builder.try_add(fragments::stmt(&raw_pattern), raw_template_stmt); builder.build() } } @@ -93,27 +93,7 @@ struct RuleBuilder { } impl RuleBuilder { - fn try_add( - &mut self, - pattern: Result, - template: Option>, - ) { - match (pattern, template) { - (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { - placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), - pattern: pattern.syntax().clone(), - template: Some(template.syntax().clone()), - }), - (Ok(pattern), None) => self.rules.push(ParsedRule { - placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), - pattern: pattern.syntax().clone(), - template: None, - }), - _ => {} - } - } - - fn try_add2( + fn try_add( &mut self, pattern: Result, template: Option>, From 55f15641011b5d1211d6f86ce77a60f05b02a25b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:34:39 +0300 Subject: [PATCH 23/29] remove fragments from syntax --- crates/syntax/src/lib.rs | 7 ---- crates/syntax/src/tests.rs | 36 ------------------- .../item/err/0000_extra_keyword.rast | 1 - .../fragments/item/err/0000_extra_keyword.rs | 1 - .../parser/fragments/item/ok/0000_fn.rast | 13 ------- .../parser/fragments/item/ok/0000_fn.rs | 1 - .../path/err/0000_reserved_word.rast | 1 - .../fragments/path/err/0000_reserved_word.rs | 1 - .../fragments/path/err/0001_expression.rast | 1 - .../fragments/path/err/0001_expression.rs | 1 - .../fragments/path/ok/0000_single_ident.rast | 4 --- .../fragments/path/ok/0000_single_ident.rs | 1 - .../fragments/path/ok/0001_multipart.rast | 14 -------- .../fragments/path/ok/0001_multipart.rs | 1 - .../pattern/err/0000_reserved_word.rast | 1 - .../pattern/err/0000_reserved_word.rs | 1 - .../pattern/err/0001_missing_paren.rast | 1 - .../pattern/err/0001_missing_paren.rs | 1 - .../fragments/pattern/ok/0000_enum.rast | 10 ------ .../parser/fragments/pattern/ok/0000_enum.rs | 1 - 20 files changed, 98 deletions(-) delete mode 100644 crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast delete mode 100644 crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs delete mode 100644 crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast delete mode 100644 crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs delete mode 100644 crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast delete mode 100644 crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs delete mode 100644 crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast delete mode 100644 crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs delete mode 100644 crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast delete mode 100644 crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs delete mode 100644 crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast delete mode 100644 crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs delete mode 100644 crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast delete mode 100644 crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs delete mode 100644 crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast delete mode 100644 crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs delete mode 100644 crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast delete mode 100644 crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 912bf4d1da10..63a14ec91342 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -180,13 +180,6 @@ impl ast::Path { } } -impl ast::Pat { - /// Returns `text`, parsed as a pattern, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Pattern) - } -} - impl ast::Expr { /// Returns `text`, parsed as an expression, but only if it has no errors. pub fn parse(text: &str) -> Result { diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs index 58c4b5b8fcd5..0611143e2afe 100644 --- a/crates/syntax/src/tests.rs +++ b/crates/syntax/src/tests.rs @@ -59,24 +59,6 @@ fn validation_tests() { }); } -#[test] -fn path_parser_tests() { - fragment_parser_dir_test( - &["parser/fragments/path/ok"], - &["parser/fragments/path/err"], - crate::ast::Path::parse, - ); -} - -#[test] -fn pattern_parser_tests() { - fragment_parser_dir_test( - &["parser/fragments/pattern/ok"], - &["parser/fragments/pattern/err"], - crate::ast::Pat::parse, - ); -} - #[test] fn parser_fuzz_tests() { for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { @@ -136,24 +118,6 @@ fn assert_errors_are_present(errors: &[SyntaxError], path: &Path) { assert!(!errors.is_empty(), "There should be errors in the file {:?}", path.display()); } -fn fragment_parser_dir_test(ok_paths: &[&str], err_paths: &[&str], f: F) -where - T: crate::AstNode, - F: Fn(&str) -> Result, -{ - dir_tests(&test_data_dir(), ok_paths, "rast", |text, path| match f(text) { - Ok(node) => format!("{:#?}", crate::ast::AstNode::syntax(&node)), - Err(_) => panic!("Failed to parse '{:?}'", path), - }); - dir_tests(&test_data_dir(), err_paths, "rast", |text, path| { - if f(text).is_ok() { - panic!("'{:?}' successfully parsed when it should have errored", path); - } else { - "ERROR\n".to_owned() - } - }); -} - /// Calls callback `f` with input code and file paths for each `.rs` file in `test_data_dir` /// subdirectories defined by `paths`. /// diff --git a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast b/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs b/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs deleted file mode 100644 index dc32389bbb79..000000000000 --- a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs +++ /dev/null @@ -1 +0,0 @@ -fn fn foo() {} diff --git a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast b/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast deleted file mode 100644 index 4ff9967beac9..000000000000 --- a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast +++ /dev/null @@ -1,13 +0,0 @@ -FN@0..11 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..11 - STMT_LIST@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" diff --git a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs b/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs deleted file mode 100644 index 8f3b7ef112a0..000000000000 --- a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo() {} diff --git a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast b/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs b/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs deleted file mode 100644 index 2046de04929f..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs +++ /dev/null @@ -1 +0,0 @@ -struct diff --git a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast b/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs b/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs deleted file mode 100644 index 745e8d376f74..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs +++ /dev/null @@ -1 +0,0 @@ -a + b diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast b/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast deleted file mode 100644 index 0c5d4360fa8d..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast +++ /dev/null @@ -1,4 +0,0 @@ -PATH@0..3 - PATH_SEGMENT@0..3 - NAME_REF@0..3 - IDENT@0..3 "foo" diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs b/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs deleted file mode 100644 index 257cc5642cb1..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast b/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast deleted file mode 100644 index 4a2b45e6a968..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast +++ /dev/null @@ -1,14 +0,0 @@ -PATH@0..13 - PATH@0..8 - PATH@0..3 - PATH_SEGMENT@0..3 - NAME_REF@0..3 - IDENT@0..3 "foo" - COLON2@3..5 "::" - PATH_SEGMENT@5..8 - NAME_REF@5..8 - IDENT@5..8 "bar" - COLON2@8..10 "::" - PATH_SEGMENT@10..13 - NAME_REF@10..13 - IDENT@10..13 "baz" diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs b/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs deleted file mode 100644 index 81e0b21cd410..000000000000 --- a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs +++ /dev/null @@ -1 +0,0 @@ -foo::bar::baz diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast b/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs b/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs deleted file mode 100644 index ae26fc455660..000000000000 --- a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs +++ /dev/null @@ -1 +0,0 @@ -fn diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast b/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast deleted file mode 100644 index 5df7507e2de1..000000000000 --- a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast +++ /dev/null @@ -1 +0,0 @@ -ERROR diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs b/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs deleted file mode 100644 index 61a391d08460..000000000000 --- a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs +++ /dev/null @@ -1 +0,0 @@ -Some(x diff --git a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast b/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast deleted file mode 100644 index dcf102339aa9..000000000000 --- a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast +++ /dev/null @@ -1,10 +0,0 @@ -TUPLE_STRUCT_PAT@0..7 - PATH@0..4 - PATH_SEGMENT@0..4 - NAME_REF@0..4 - IDENT@0..4 "Some" - L_PAREN@4..5 "(" - IDENT_PAT@5..6 - NAME@5..6 - IDENT@5..6 "x" - R_PAREN@6..7 ")" diff --git a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs b/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs deleted file mode 100644 index 87114dd78814..000000000000 --- a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs +++ /dev/null @@ -1 +0,0 @@ -Some(x) From 45bba40079f85471414b4cd55b42a81d67df8b5f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:35:36 +0300 Subject: [PATCH 24/29] dead code --- crates/syntax/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 63a14ec91342..1fb3dc6a65e0 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -187,13 +187,6 @@ impl ast::Expr { } } -impl ast::Attr { - /// Returns `text`, parsed as an attribute, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Attr) - } -} - /// Matches a `SyntaxNode` against an `ast` type. /// /// # Example: From f9e06e6524c6c2da43e42aa47520c9fb3c34d1cd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Dec 2021 21:41:34 +0300 Subject: [PATCH 25/29] last use of parse api in ssr --- crates/ide_ssr/src/replacing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide_ssr/src/replacing.rs b/crates/ide_ssr/src/replacing.rs index 1c4cb6bc7704..6d21bad1eb38 100644 --- a/crates/ide_ssr/src/replacing.rs +++ b/crates/ide_ssr/src/replacing.rs @@ -226,8 +226,8 @@ fn token_is_method_call_receiver(token: &SyntaxToken) -> bool { fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option { if ast::Expr::can_cast(kind) { - if let Ok(expr) = ast::Expr::parse(code) { - return Some(expr.syntax().clone()); + if let Ok(expr) = fragments::expr(code) { + return Some(expr); } } if ast::Item::can_cast(kind) { From aa1788dc717a856a409ec76759783ad59c47bd49 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Dec 2021 15:48:07 +0300 Subject: [PATCH 26/29] clarify semantics of doc links --- crates/hir/src/attrs.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 54e95cf7c3d5..46e9c54dad65 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -11,7 +11,7 @@ use hir_def::{ }; use hir_expand::{hygiene::Hygiene, MacroDefId}; use hir_ty::db::HirDatabase; -use syntax::ast; +use syntax::{ast, AstNode}; use crate::{ Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam, @@ -147,8 +147,18 @@ fn resolve_doc_path( // FIXME AttrDefId::MacroDefId(_) => return None, }; - let path = ast::Path::parse(link).ok()?; - let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic())?; + + let modpath = { + let ast_path = ast::SourceFile::parse(&format!("type T = {};", link)) + .syntax_node() + .descendants() + .find_map(ast::Path::cast)?; + if ast_path.to_string() != link { + return None; + } + ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())? + }; + let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); let resolved = if resolved == PerNs::none() { resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)? From bfc263f1f98aece963a4b103d787005346f0c1c7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Dec 2021 18:57:13 +0300 Subject: [PATCH 27/29] introduce hacks module --- .../src/completions/attribute.rs | 2 +- crates/ide_completion/src/snippet.rs | 13 +++++------ crates/ide_db/src/helpers.rs | 13 +++++++++-- crates/syntax/src/hacks.rs | 14 ++++++++++++ crates/syntax/src/lib.rs | 21 +----------------- crates/syntax/src/parsing.rs | 22 +------------------ 6 files changed, 34 insertions(+), 51 deletions(-) create mode 100644 crates/syntax/src/hacks.rs diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index d763878834f6..f67d7d56d819 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs @@ -309,7 +309,7 @@ fn parse_comma_sep_expr(input: ast::TokenTree) -> Option> { input_expressions .into_iter() .filter_map(|(is_sep, group)| (!is_sep).then(|| group)) - .filter_map(|mut tokens| ast::Expr::parse(&tokens.join("")).ok()) + .filter_map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join(""))) .collect::>(), ) } diff --git a/crates/ide_completion/src/snippet.rs b/crates/ide_completion/src/snippet.rs index c5e2b009c7ce..98cd3f8f3370 100644 --- a/crates/ide_completion/src/snippet.rs +++ b/crates/ide_completion/src/snippet.rs @@ -212,15 +212,14 @@ fn validate_snippet( ) -> Option<(Box<[GreenNode]>, String, Option>)> { let mut imports = Vec::with_capacity(requires.len()); for path in requires.iter() { - let path = ast::Path::parse(path).ok()?; - let valid_use_path = path.segments().all(|seg| { - matches!(seg.kind(), Some(ast::PathSegmentKind::Name(_))) - || seg.generic_arg_list().is_none() - }); - if !valid_use_path { + let use_path = ast::SourceFile::parse(&format!("use {};", path)) + .syntax_node() + .descendants() + .find_map(ast::Path::cast)?; + if use_path.syntax().text() != path.as_str() { return None; } - let green = path.syntax().green().into_owned(); + let green = use_path.syntax().green().into_owned(); imports.push(green); } let snippet = snippet.iter().join("\n"); diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index e4199898bfc5..e589940dae29 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs @@ -67,7 +67,11 @@ pub fn get_path_at_cursor_in_tt(cursor: &ast::Ident) -> Option { .filter_map(SyntaxElement::into_token) .take_while(|tok| tok != cursor); - ast::Path::parse(&path_tokens.chain(iter::once(cursor.clone())).join("")).ok() + syntax::hacks::parse_expr_from_str(&path_tokens.chain(iter::once(cursor.clone())).join("")) + .and_then(|expr| match expr { + ast::Expr::PathExpr(it) => it.path(), + _ => None, + }) } /// Parses and resolves the path at the cursor position in the given attribute, if it is a derive. @@ -323,7 +327,12 @@ pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option it.path(), + _ => None, + }) + }) .collect(); Some(paths) } diff --git a/crates/syntax/src/hacks.rs b/crates/syntax/src/hacks.rs new file mode 100644 index 000000000000..112b912ade26 --- /dev/null +++ b/crates/syntax/src/hacks.rs @@ -0,0 +1,14 @@ +//! Things which exist to solve practial issues, but which shouldn't exist. +//! +//! Please avoid adding new usages of the functions in this module + +use crate::{ast, AstNode}; + +pub fn parse_expr_from_str(s: &str) -> Option { + let file = ast::SourceFile::parse(&format!("const _: () = {};", s)); + let expr = file.syntax_node().descendants().find_map(ast::Expr::cast)?; + if expr.syntax().text() != s { + return None; + } + Some(expr) +} diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 1fb3dc6a65e0..d6b1cce45ff7 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -40,6 +40,7 @@ pub mod ast; pub mod fuzz; pub mod utils; pub mod ted; +pub mod hacks; use std::{marker::PhantomData, sync::Arc}; @@ -167,26 +168,6 @@ impl SourceFile { } } -// FIXME: `parse` functions shouldn't hang directly from AST nodes, and they -// shouldn't return `Result`. -// -// We need a dedicated module for parser entry points, and they should always -// return `Parse`. - -impl ast::Path { - /// Returns `text`, parsed as a path, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Path) - } -} - -impl ast::Expr { - /// Returns `text`, parsed as an expression, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Expr) - } -} - /// Matches a `SyntaxNode` against an `ast` type. /// /// # Example: diff --git a/crates/syntax/src/parsing.rs b/crates/syntax/src/parsing.rs index 971fa2700d2f..ac1d920d69dc 100644 --- a/crates/syntax/src/parsing.rs +++ b/crates/syntax/src/parsing.rs @@ -5,7 +5,7 @@ mod reparsing; use rowan::TextRange; -use crate::{syntax_node::GreenNode, AstNode, SyntaxError, SyntaxNode, SyntaxTreeBuilder}; +use crate::{syntax_node::GreenNode, SyntaxError, SyntaxTreeBuilder}; pub(crate) use crate::parsing::reparsing::incremental_reparse; @@ -17,26 +17,6 @@ pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec) { (node, errors) } -/// Returns `text` parsed as a `T` provided there are no parse errors. -pub(crate) fn parse_text_as( - text: &str, - entry_point: parser::ParserEntryPoint, -) -> Result { - let lexed = parser::LexedStr::new(text); - if lexed.errors().next().is_some() { - return Err(()); - } - let parser_input = lexed.to_input(); - let parser_output = parser::parse(&parser_input, entry_point); - let (node, errors, eof) = build_tree(lexed, parser_output, true); - - if !errors.is_empty() || !eof { - return Err(()); - } - - SyntaxNode::new_root(node).first_child().and_then(T::cast).ok_or(()) -} - pub(crate) fn build_tree( lexed: parser::LexedStr<'_>, parser_output: parser::Output, From 660cf34d8c905d96ad47b5107d58931203d68a35 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Dec 2021 19:13:30 +0300 Subject: [PATCH 28/29] dead code --- crates/ide_assists/src/handlers/remove_dbg.rs | 5 +-- crates/parser/src/grammar.rs | 12 ------ crates/parser/src/lib.rs | 41 ------------------- crates/parser/src/shortcuts.rs | 7 ---- crates/parser/src/tests.rs | 4 +- crates/syntax/src/hacks.rs | 1 + crates/syntax/src/parsing.rs | 7 ++-- crates/syntax/src/parsing/reparsing.rs | 2 +- 8 files changed, 9 insertions(+), 70 deletions(-) diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs index b860a3b6da87..07dcfd967177 100644 --- a/crates/ide_assists/src/handlers/remove_dbg.rs +++ b/crates/ide_assists/src/handlers/remove_dbg.rs @@ -36,9 +36,8 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let input_expressions = input_expressions .into_iter() .filter_map(|(is_sep, group)| (!is_sep).then(|| group)) - .map(|mut tokens| ast::Expr::parse(&tokens.join(""))) - .collect::, _>>() - .ok()?; + .map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join(""))) + .collect::>>()?; let parent = macro_call.syntax().parent()?; let (range, text) = match &*input_expressions { diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 5fbeca44323a..42426a1df285 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -117,18 +117,6 @@ pub(crate) mod entry { } } -pub(crate) mod entry_points { - use super::*; - - pub(crate) fn stmt_optional_semi(p: &mut Parser) { - expressions::stmt(p, expressions::StmtWithSemi::Optional, false); - } - - pub(crate) fn attr(p: &mut Parser) { - attributes::outer_attrs(p); - } -} - pub(crate) fn reparser( node: SyntaxKind, first_child: Option, diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index da62590ab66c..c5014be6c336 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -132,47 +132,6 @@ impl TopEntryPoint { } } -/// rust-analyzer parser allows you to choose one of the possible entry points. -/// -/// The primary consumer of this API are declarative macros, `$x:expr` matchers -/// are implemented by calling into the parser with non-standard entry point. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub enum ParserEntryPoint { - Path, - Expr, - StatementOptionalSemi, - Pattern, - Attr, -} - -/// Parse given tokens into the given sink as a rust file. -pub fn parse_source_file(input: &Input) -> Output { - TopEntryPoint::SourceFile.parse(input) -} - -/// Parses the given [`Input`] into [`Output`] assuming that the top-level -/// syntactic construct is the given [`ParserEntryPoint`]. -/// -/// Both input and output here are fairly abstract. The overall flow is that the -/// caller has some "real" tokens, converts them to [`Input`], parses them to -/// [`Output`], and then converts that into a "real" tree. The "real" tree is -/// made of "real" tokens, so this all hinges on rather tight coordination of -/// indices between the four stages. -pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output { - let entry_point: fn(&'_ mut parser::Parser) = match entry_point { - ParserEntryPoint::Path => grammar::entry::prefix::path, - ParserEntryPoint::Expr => grammar::entry::prefix::expr, - ParserEntryPoint::Pattern => grammar::entry::prefix::pat, - ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi, - ParserEntryPoint::Attr => grammar::entry_points::attr, - }; - - let mut p = parser::Parser::new(inp); - entry_point(&mut p); - let events = p.finish(); - event::process(events) -} - /// A parsing function for a specific braced-block. pub struct Reparser(fn(&mut parser::Parser)); diff --git a/crates/parser/src/shortcuts.rs b/crates/parser/src/shortcuts.rs index 15387a85cc16..3d28f814c9f2 100644 --- a/crates/parser/src/shortcuts.rs +++ b/crates/parser/src/shortcuts.rs @@ -52,14 +52,10 @@ impl<'a> LexedStr<'a> { pub fn intersperse_trivia( &self, output: &crate::Output, - synthetic_root: bool, sink: &mut dyn FnMut(StrStep), ) -> bool { let mut builder = Builder { lexed: self, pos: 0, state: State::PendingEnter, sink }; - if synthetic_root { - builder.enter(SyntaxKind::SOURCE_FILE); - } for event in output.iter() { match event { Step::Token { kind, n_input_tokens: n_raw_tokens } => { @@ -73,9 +69,6 @@ impl<'a> LexedStr<'a> { } } } - if synthetic_root { - builder.exit(); - } match mem::replace(&mut builder.state, State::Normal) { State::PendingExit => { diff --git a/crates/parser/src/tests.rs b/crates/parser/src/tests.rs index 7a6230eaf8b2..512f7ddb95bb 100644 --- a/crates/parser/src/tests.rs +++ b/crates/parser/src/tests.rs @@ -80,12 +80,12 @@ fn parse_inline_err() { fn parse(text: &str) -> (String, bool) { let lexed = LexedStr::new(text); let input = lexed.to_input(); - let output = crate::parse_source_file(&input); + let output = crate::TopEntryPoint::SourceFile.parse(&input); let mut buf = String::new(); let mut errors = Vec::new(); let mut indent = String::new(); - lexed.intersperse_trivia(&output, false, &mut |step| match step { + lexed.intersperse_trivia(&output, &mut |step| match step { crate::StrStep::Token { kind, text } => { write!(buf, "{}", indent).unwrap(); write!(buf, "{:?} {:?}\n", kind, text).unwrap(); diff --git a/crates/syntax/src/hacks.rs b/crates/syntax/src/hacks.rs index 112b912ade26..a047f61fa03c 100644 --- a/crates/syntax/src/hacks.rs +++ b/crates/syntax/src/hacks.rs @@ -5,6 +5,7 @@ use crate::{ast, AstNode}; pub fn parse_expr_from_str(s: &str) -> Option { + let s = s.trim(); let file = ast::SourceFile::parse(&format!("const _: () = {};", s)); let expr = file.syntax_node().descendants().find_map(ast::Expr::cast)?; if expr.syntax().text() != s { diff --git a/crates/syntax/src/parsing.rs b/crates/syntax/src/parsing.rs index ac1d920d69dc..047e670c9f45 100644 --- a/crates/syntax/src/parsing.rs +++ b/crates/syntax/src/parsing.rs @@ -12,19 +12,18 @@ pub(crate) use crate::parsing::reparsing::incremental_reparse; pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec) { let lexed = parser::LexedStr::new(text); let parser_input = lexed.to_input(); - let parser_output = parser::parse_source_file(&parser_input); - let (node, errors, _eof) = build_tree(lexed, parser_output, false); + let parser_output = parser::TopEntryPoint::SourceFile.parse(&parser_input); + let (node, errors, _eof) = build_tree(lexed, parser_output); (node, errors) } pub(crate) fn build_tree( lexed: parser::LexedStr<'_>, parser_output: parser::Output, - synthetic_root: bool, ) -> (GreenNode, Vec, bool) { let mut builder = SyntaxTreeBuilder::default(); - let is_eof = lexed.intersperse_trivia(&parser_output, synthetic_root, &mut |step| match step { + let is_eof = lexed.intersperse_trivia(&parser_output, &mut |step| match step { parser::StrStep::Token { kind, text } => builder.token(kind, text), parser::StrStep::Enter { kind } => builder.start_node(kind), parser::StrStep::Exit => builder.finish_node(), diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs index dd2e01bfc4ca..701e6232d589 100644 --- a/crates/syntax/src/parsing/reparsing.rs +++ b/crates/syntax/src/parsing/reparsing.rs @@ -96,7 +96,7 @@ fn reparse_block( let tree_traversal = reparser.parse(&parser_input); - let (green, new_parser_errors, _eof) = build_tree(lexed, tree_traversal, false); + let (green, new_parser_errors, _eof) = build_tree(lexed, tree_traversal); Some((node.replace_with(green), new_parser_errors, node.text_range())) } From ea96c376c85e02ec86df5ff6522754395ad819e9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Dec 2021 19:17:34 +0300 Subject: [PATCH 29/29] compress --- crates/ide_ssr/src/fragments.rs | 62 ++++++++++----------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs index dab214b4074b..503754afe7c2 100644 --- a/crates/ide_ssr/src/fragments.rs +++ b/crates/ide_ssr/src/fragments.rs @@ -9,59 +9,19 @@ use syntax::{ast, AstNode, SyntaxNode}; pub(crate) fn ty(s: &str) -> Result { - let template = "type T = {};"; - let input = template.replace("{}", s); - let parse = syntax::SourceFile::parse(&input); - if !parse.errors().is_empty() { - return Err(()); - } - let node = parse.tree().syntax().descendants().find_map(ast::Type::cast).ok_or(())?; - if node.to_string() != s { - return Err(()); - } - Ok(node.syntax().clone_subtree()) + fragment::("type T = {};", s) } pub(crate) fn item(s: &str) -> Result { - let template = "{}"; - let input = template.replace("{}", s); - let parse = syntax::SourceFile::parse(&input); - if !parse.errors().is_empty() { - return Err(()); - } - let node = parse.tree().syntax().descendants().find_map(ast::Item::cast).ok_or(())?; - if node.to_string() != s { - return Err(()); - } - Ok(node.syntax().clone_subtree()) + fragment::("{}", s) } pub(crate) fn pat(s: &str) -> Result { - let template = "const _: () = {let {} = ();};"; - let input = template.replace("{}", s); - let parse = syntax::SourceFile::parse(&input); - if !parse.errors().is_empty() { - return Err(()); - } - let node = parse.tree().syntax().descendants().find_map(ast::Pat::cast).ok_or(())?; - if node.to_string() != s { - return Err(()); - } - Ok(node.syntax().clone_subtree()) + fragment::("const _: () = {let {} = ();};", s) } pub(crate) fn expr(s: &str) -> Result { - let template = "const _: () = {};"; - let input = template.replace("{}", s); - let parse = syntax::SourceFile::parse(&input); - if !parse.errors().is_empty() { - return Err(()); - } - let node = parse.tree().syntax().descendants().find_map(ast::Expr::cast).ok_or(())?; - if node.to_string() != s { - return Err(()); - } - Ok(node.syntax().clone_subtree()) + fragment::("const _: () = {};", s) } pub(crate) fn stmt(s: &str) -> Result { @@ -82,3 +42,17 @@ pub(crate) fn stmt(s: &str) -> Result { } Ok(node.syntax().clone_subtree()) } + +fn fragment(template: &str, s: &str) -> Result { + let s = s.trim(); + let input = template.replace("{}", s); + let parse = syntax::SourceFile::parse(&input); + if !parse.errors().is_empty() { + return Err(()); + } + let node = parse.tree().syntax().descendants().find_map(T::cast).ok_or(())?; + if node.syntax().text() != s { + return Err(()); + } + Ok(node.syntax().clone_subtree()) +}