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.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!['('], "("),