diff options
Diffstat (limited to 'crates/ra_ssr/src/parsing.rs')
-rw-r--r-- | crates/ra_ssr/src/parsing.rs | 106 |
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 | ||
8 | use crate::errors::bail; | 8 | use crate::errors::bail; |
9 | use crate::{SsrError, SsrPattern, SsrRule}; | 9 | use crate::{SsrError, SsrPattern, SsrRule}; |
10 | use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, T}; | 10 | use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, T}; |
11 | use rustc_hash::{FxHashMap, FxHashSet}; | 11 | use rustc_hash::{FxHashMap, FxHashSet}; |
12 | use std::str::FromStr; | 12 | use std::str::FromStr; |
13 | 13 | ||
14 | #[derive(Debug)] | ||
15 | pub(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)] |
15 | pub(crate) struct SsrTemplate { | 22 | pub(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)] |
20 | pub(crate) struct RawSearchPattern { | 27 | pub(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 | ||
64 | impl 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 | |||
83 | struct RuleBuilder { | ||
84 | placeholders_by_stand_in: FxHashMap<SmolStr, Placeholder>, | ||
85 | rules: Vec<ParsedRule>, | ||
86 | } | ||
87 | |||
88 | impl 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 | |||
57 | impl FromStr for SsrRule { | 108 | impl 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 | ||
77 | impl FromStr for RawSearchPattern { | 131 | impl 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 | ||
85 | impl RawSearchPattern { | 139 | impl 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 | ||
163 | impl 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 | |||
109 | impl FromStr for SsrPattern { | 172 | impl 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. |
174 | fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> { | 220 | fn 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!['('], "("), |