diff options
author | David Lattimore <[email protected]> | 2020-07-22 10:15:19 +0100 |
---|---|---|
committer | David Lattimore <[email protected]> | 2020-07-24 12:34:00 +0100 |
commit | 113abbeefee671266d2d9bebdbd517eb8b802ef8 (patch) | |
tree | a7c44c0490b09f06034cb82966b8a61f681c4433 /crates/ra_ssr/src/parsing.rs | |
parent | 1fce8b6ba32bebba36d588d07781e9e578845728 (diff) |
SSR: Parse template as Rust code.
This is in preparation for a subsequent commit where we add special
handling for paths in the template, allowing them to be qualified
differently in different contexts.
Diffstat (limited to 'crates/ra_ssr/src/parsing.rs')
-rw-r--r-- | crates/ra_ssr/src/parsing.rs | 60 |
1 files changed, 28 insertions, 32 deletions
diff --git a/crates/ra_ssr/src/parsing.rs b/crates/ra_ssr/src/parsing.rs index 682b7011a..cf7fb517f 100644 --- a/crates/ra_ssr/src/parsing.rs +++ b/crates/ra_ssr/src/parsing.rs | |||
@@ -15,12 +15,8 @@ use std::str::FromStr; | |||
15 | pub(crate) struct ParsedRule { | 15 | pub(crate) struct ParsedRule { |
16 | pub(crate) placeholders_by_stand_in: FxHashMap<SmolStr, Placeholder>, | 16 | pub(crate) placeholders_by_stand_in: FxHashMap<SmolStr, Placeholder>, |
17 | pub(crate) pattern: SyntaxNode, | 17 | pub(crate) pattern: SyntaxNode, |
18 | pub(crate) template: Option<SsrTemplate>, | 18 | pub(crate) template: Option<SyntaxNode>, |
19 | } | 19 | pub(crate) index: usize, |
20 | |||
21 | #[derive(Clone, Debug)] | ||
22 | pub(crate) struct SsrTemplate { | ||
23 | pub(crate) tokens: Vec<PatternElement>, | ||
24 | } | 20 | } |
25 | 21 | ||
26 | #[derive(Debug)] | 22 | #[derive(Debug)] |
@@ -64,18 +60,23 @@ pub(crate) struct Token { | |||
64 | impl ParsedRule { | 60 | impl ParsedRule { |
65 | fn new( | 61 | fn new( |
66 | pattern: &RawPattern, | 62 | pattern: &RawPattern, |
67 | template: Option<&SsrTemplate>, | 63 | template: Option<&RawPattern>, |
68 | ) -> Result<Vec<ParsedRule>, SsrError> { | 64 | ) -> Result<Vec<ParsedRule>, SsrError> { |
69 | let raw_pattern = pattern.as_rust_code(); | 65 | let raw_pattern = pattern.as_rust_code(); |
66 | let raw_template = template.map(|t| t.as_rust_code()); | ||
67 | let raw_template = raw_template.as_ref().map(|s| s.as_str()); | ||
70 | let mut builder = RuleBuilder { | 68 | let mut builder = RuleBuilder { |
71 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), | 69 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), |
72 | rules: Vec::new(), | 70 | rules: Vec::new(), |
73 | }; | 71 | }; |
74 | builder.try_add(ast::Expr::parse(&raw_pattern), template); | 72 | builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse)); |
75 | builder.try_add(ast::TypeRef::parse(&raw_pattern), template); | 73 | builder.try_add(ast::TypeRef::parse(&raw_pattern), raw_template.map(ast::TypeRef::parse)); |
76 | builder.try_add(ast::ModuleItem::parse(&raw_pattern), template); | 74 | builder.try_add( |
77 | builder.try_add(ast::Path::parse(&raw_pattern), template); | 75 | ast::ModuleItem::parse(&raw_pattern), |
78 | builder.try_add(ast::Pat::parse(&raw_pattern), template); | 76 | raw_template.map(ast::ModuleItem::parse), |
77 | ); | ||
78 | builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); | ||
79 | builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); | ||
79 | builder.build() | 80 | builder.build() |
80 | } | 81 | } |
81 | } | 82 | } |
@@ -86,12 +87,22 @@ struct RuleBuilder { | |||
86 | } | 87 | } |
87 | 88 | ||
88 | impl RuleBuilder { | 89 | impl RuleBuilder { |
89 | fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<&SsrTemplate>) { | 90 | fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<Result<T, ()>>) { |
90 | match pattern { | 91 | match (pattern, template) { |
91 | Ok(pattern) => self.rules.push(ParsedRule { | 92 | (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { |
93 | placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), | ||
94 | pattern: pattern.syntax().clone(), | ||
95 | template: Some(template.syntax().clone()), | ||
96 | // For now we give the rule an index of 0. It's given a proper index when the rule | ||
97 | // is added to the SsrMatcher. Using an Option<usize>, instead would be slightly | ||
98 | // more correct, but we delete this field from ParsedRule in a subsequent commit. | ||
99 | index: 0, | ||
100 | }), | ||
101 | (Ok(pattern), None) => self.rules.push(ParsedRule { | ||
92 | placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), | 102 | placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), |
93 | pattern: pattern.syntax().clone(), | 103 | pattern: pattern.syntax().clone(), |
94 | template: template.cloned(), | 104 | template: None, |
105 | index: 0, | ||
95 | }), | 106 | }), |
96 | _ => {} | 107 | _ => {} |
97 | } | 108 | } |
@@ -99,7 +110,7 @@ impl RuleBuilder { | |||
99 | 110 | ||
100 | fn build(self) -> Result<Vec<ParsedRule>, SsrError> { | 111 | fn build(self) -> Result<Vec<ParsedRule>, SsrError> { |
101 | if self.rules.is_empty() { | 112 | if self.rules.is_empty() { |
102 | bail!("Pattern is not a valid Rust expression, type, item, path or pattern"); | 113 | bail!("Not a valid Rust expression, type, item, path or pattern"); |
103 | } | 114 | } |
104 | Ok(self.rules) | 115 | Ok(self.rules) |
105 | } | 116 | } |
@@ -179,21 +190,6 @@ impl FromStr for SsrPattern { | |||
179 | } | 190 | } |
180 | } | 191 | } |
181 | 192 | ||
182 | impl FromStr for SsrTemplate { | ||
183 | type Err = SsrError; | ||
184 | |||
185 | fn from_str(pattern_str: &str) -> Result<SsrTemplate, SsrError> { | ||
186 | let tokens = parse_pattern(pattern_str)?; | ||
187 | // Validate that the template is a valid fragment of Rust code. We reuse the validation | ||
188 | // logic for search patterns since the only thing that differs is the error message. | ||
189 | if SsrPattern::from_str(pattern_str).is_err() { | ||
190 | bail!("Replacement is not a valid Rust expression, type, item, path or pattern"); | ||
191 | } | ||
192 | // Our actual template needs to preserve whitespace, so we can't reuse `tokens`. | ||
193 | Ok(SsrTemplate { tokens }) | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /// Returns `pattern_str`, parsed as a search or replace pattern. If `remove_whitespace` is true, | 193 | /// Returns `pattern_str`, parsed as a search or replace pattern. If `remove_whitespace` is true, |
198 | /// then any whitespace tokens will be removed, which we do for the search pattern, but not for the | 194 | /// then any whitespace tokens will be removed, which we do for the search pattern, but not for the |
199 | /// replace pattern. | 195 | /// replace pattern. |