aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr/src/parsing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ssr/src/parsing.rs')
-rw-r--r--crates/ra_ssr/src/parsing.rs60
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;
15pub(crate) struct ParsedRule { 15pub(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)]
22pub(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 {
64impl ParsedRule { 60impl 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
88impl RuleBuilder { 89impl 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
182impl 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.