aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr/src/parsing.rs
diff options
context:
space:
mode:
authorDavid Lattimore <[email protected]>2020-07-03 03:57:17 +0100
committerDavid Lattimore <[email protected]>2020-07-24 12:34:00 +0100
commit1fce8b6ba32bebba36d588d07781e9e578845728 (patch)
treec027096421e49a7e0279711e0ccd7491ca3d6a9a /crates/ra_ssr/src/parsing.rs
parent2b53639e381b1f17c829fb33f6e4135a9c930f41 (diff)
SSR: Change the way rules are stored internally.
Previously we had: - Multiple rules - Each rule had its pattern parsed as an expression, path etc This meant that there were two levels at which there could be multiple rules. Now we just have multiple rules. If a pattern can parse as more than one kind of thing, then they get stored as multiple separate rules. We also now don't have separate fields for the different kinds of things that a pattern can parse as. This makes adding new kinds of things simpler. Previously, add_search_pattern would construct a rule with a dummy replacement. Now the replacement is an Option. This is slightly cleaner and also opens the way for parsing the replacement template as the same kind of thing as the search pattern.
Diffstat (limited to 'crates/ra_ssr/src/parsing.rs')
-rw-r--r--crates/ra_ssr/src/parsing.rs106
1 files changed, 76 insertions, 30 deletions
diff --git a/crates/ra_ssr/src/parsing.rs b/crates/ra_ssr/src/parsing.rs
index 4aee97bb2..682b7011a 100644
--- a/crates/ra_ssr/src/parsing.rs
+++ b/crates/ra_ssr/src/parsing.rs
@@ -7,17 +7,24 @@
7 7
8use crate::errors::bail; 8use crate::errors::bail;
9use crate::{SsrError, SsrPattern, SsrRule}; 9use crate::{SsrError, SsrPattern, SsrRule};
10use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, T}; 10use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, T};
11use rustc_hash::{FxHashMap, FxHashSet}; 11use rustc_hash::{FxHashMap, FxHashSet};
12use std::str::FromStr; 12use std::str::FromStr;
13 13
14#[derive(Debug)]
15pub(crate) struct ParsedRule {
16 pub(crate) placeholders_by_stand_in: FxHashMap<SmolStr, Placeholder>,
17 pub(crate) pattern: SyntaxNode,
18 pub(crate) template: Option<SsrTemplate>,
19}
20
14#[derive(Clone, Debug)] 21#[derive(Clone, Debug)]
15pub(crate) struct SsrTemplate { 22pub(crate) struct SsrTemplate {
16 pub(crate) tokens: Vec<PatternElement>, 23 pub(crate) tokens: Vec<PatternElement>,
17} 24}
18 25
19#[derive(Debug)] 26#[derive(Debug)]
20pub(crate) struct RawSearchPattern { 27pub(crate) struct RawPattern {
21 tokens: Vec<PatternElement>, 28 tokens: Vec<PatternElement>,
22} 29}
23 30
@@ -54,6 +61,50 @@ pub(crate) struct Token {
54 pub(crate) text: SmolStr, 61 pub(crate) text: SmolStr,
55} 62}
56 63
64impl ParsedRule {
65 fn new(
66 pattern: &RawPattern,
67 template: Option<&SsrTemplate>,
68 ) -> Result<Vec<ParsedRule>, SsrError> {
69 let raw_pattern = pattern.as_rust_code();
70 let mut builder = RuleBuilder {
71 placeholders_by_stand_in: pattern.placeholders_by_stand_in(),
72 rules: Vec::new(),
73 };
74 builder.try_add(ast::Expr::parse(&raw_pattern), template);
75 builder.try_add(ast::TypeRef::parse(&raw_pattern), template);
76 builder.try_add(ast::ModuleItem::parse(&raw_pattern), template);
77 builder.try_add(ast::Path::parse(&raw_pattern), template);
78 builder.try_add(ast::Pat::parse(&raw_pattern), template);
79 builder.build()
80 }
81}
82
83struct RuleBuilder {
84 placeholders_by_stand_in: FxHashMap<SmolStr, Placeholder>,
85 rules: Vec<ParsedRule>,
86}
87
88impl RuleBuilder {
89 fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<&SsrTemplate>) {
90 match pattern {
91 Ok(pattern) => self.rules.push(ParsedRule {
92 placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
93 pattern: pattern.syntax().clone(),
94 template: template.cloned(),
95 }),
96 _ => {}
97 }
98 }
99
100 fn build(self) -> Result<Vec<ParsedRule>, SsrError> {
101 if self.rules.is_empty() {
102 bail!("Pattern is not a valid Rust expression, type, item, path or pattern");
103 }
104 Ok(self.rules)
105 }
106}
107
57impl FromStr for SsrRule { 108impl FromStr for SsrRule {
58 type Err = SsrError; 109 type Err = SsrError;
59 110
@@ -68,21 +119,24 @@ impl FromStr for SsrRule {
68 if it.next().is_some() { 119 if it.next().is_some() {
69 return Err(SsrError("More than one delimiter found".into())); 120 return Err(SsrError("More than one delimiter found".into()));
70 } 121 }
71 let rule = SsrRule { pattern: pattern.parse()?, template: template.parse()? }; 122 let raw_pattern = pattern.parse()?;
123 let raw_template = template.parse()?;
124 let parsed_rules = ParsedRule::new(&raw_pattern, Some(&raw_template))?;
125 let rule = SsrRule { pattern: raw_pattern, template: raw_template, parsed_rules };
72 validate_rule(&rule)?; 126 validate_rule(&rule)?;
73 Ok(rule) 127 Ok(rule)
74 } 128 }
75} 129}
76 130
77impl FromStr for RawSearchPattern { 131impl FromStr for RawPattern {
78 type Err = SsrError; 132 type Err = SsrError;
79 133
80 fn from_str(pattern_str: &str) -> Result<RawSearchPattern, SsrError> { 134 fn from_str(pattern_str: &str) -> Result<RawPattern, SsrError> {
81 Ok(RawSearchPattern { tokens: parse_pattern(pattern_str)? }) 135 Ok(RawPattern { tokens: parse_pattern(pattern_str)? })
82 } 136 }
83} 137}
84 138
85impl RawSearchPattern { 139impl RawPattern {
86 /// Returns this search pattern as Rust source code that we can feed to the Rust parser. 140 /// Returns this search pattern as Rust source code that we can feed to the Rust parser.
87 fn as_rust_code(&self) -> String { 141 fn as_rust_code(&self) -> String {
88 let mut res = String::new(); 142 let mut res = String::new();
@@ -95,7 +149,7 @@ impl RawSearchPattern {
95 res 149 res
96 } 150 }
97 151
98 fn placeholders_by_stand_in(&self) -> FxHashMap<SmolStr, Placeholder> { 152 pub(crate) fn placeholders_by_stand_in(&self) -> FxHashMap<SmolStr, Placeholder> {
99 let mut res = FxHashMap::default(); 153 let mut res = FxHashMap::default();
100 for t in &self.tokens { 154 for t in &self.tokens {
101 if let PatternElement::Placeholder(placeholder) = t { 155 if let PatternElement::Placeholder(placeholder) = t {
@@ -106,30 +160,22 @@ impl RawSearchPattern {
106 } 160 }
107} 161}
108 162
163impl ParsedRule {
164 pub(crate) fn get_placeholder(&self, token: &SyntaxToken) -> Option<&Placeholder> {
165 if token.kind() != SyntaxKind::IDENT {
166 return None;
167 }
168 self.placeholders_by_stand_in.get(token.text())
169 }
170}
171
109impl FromStr for SsrPattern { 172impl FromStr for SsrPattern {
110 type Err = SsrError; 173 type Err = SsrError;
111 174
112 fn from_str(pattern_str: &str) -> Result<SsrPattern, SsrError> { 175 fn from_str(pattern_str: &str) -> Result<SsrPattern, SsrError> {
113 let raw: RawSearchPattern = pattern_str.parse()?; 176 let raw_pattern = pattern_str.parse()?;
114 let raw_str = raw.as_rust_code(); 177 let parsed_rules = ParsedRule::new(&raw_pattern, None)?;
115 let res = SsrPattern { 178 Ok(SsrPattern { raw: raw_pattern, parsed_rules })
116 expr: ast::Expr::parse(&raw_str).ok().map(|n| n.syntax().clone()),
117 type_ref: ast::TypeRef::parse(&raw_str).ok().map(|n| n.syntax().clone()),
118 item: ast::ModuleItem::parse(&raw_str).ok().map(|n| n.syntax().clone()),
119 path: ast::Path::parse(&raw_str).ok().map(|n| n.syntax().clone()),
120 pattern: ast::Pat::parse(&raw_str).ok().map(|n| n.syntax().clone()),
121 placeholders_by_stand_in: raw.placeholders_by_stand_in(),
122 raw,
123 };
124 if res.expr.is_none()
125 && res.type_ref.is_none()
126 && res.item.is_none()
127 && res.path.is_none()
128 && res.pattern.is_none()
129 {
130 bail!("Pattern is not a valid Rust expression, type, item, path or pattern");
131 }
132 Ok(res)
133 } 179 }
134} 180}
135 181
@@ -173,7 +219,7 @@ fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
173/// pattern didn't define. 219/// pattern didn't define.
174fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> { 220fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
175 let mut defined_placeholders = FxHashSet::default(); 221 let mut defined_placeholders = FxHashSet::default();
176 for p in &rule.pattern.raw.tokens { 222 for p in &rule.pattern.tokens {
177 if let PatternElement::Placeholder(placeholder) = p { 223 if let PatternElement::Placeholder(placeholder) = p {
178 defined_placeholders.insert(&placeholder.ident); 224 defined_placeholders.insert(&placeholder.ident);
179 } 225 }
@@ -316,7 +362,7 @@ mod tests {
316 } 362 }
317 let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap(); 363 let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap();
318 assert_eq!( 364 assert_eq!(
319 result.pattern.raw.tokens, 365 result.pattern.tokens,
320 vec![ 366 vec![
321 token(SyntaxKind::IDENT, "foo"), 367 token(SyntaxKind::IDENT, "foo"),
322 token(T!['('], "("), 368 token(T!['('], "("),