diff options
author | David Lattimore <[email protected]> | 2020-07-03 03:57:17 +0100 |
---|---|---|
committer | David Lattimore <[email protected]> | 2020-07-24 12:34:00 +0100 |
commit | 1fce8b6ba32bebba36d588d07781e9e578845728 (patch) | |
tree | c027096421e49a7e0279711e0ccd7491ca3d6a9a /crates/ra_ssr/src/matching.rs | |
parent | 2b53639e381b1f17c829fb33f6e4135a9c930f41 (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/matching.rs')
-rw-r--r-- | crates/ra_ssr/src/matching.rs | 42 |
1 files changed, 9 insertions, 33 deletions
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs index 50b29eab2..842f4b6f3 100644 --- a/crates/ra_ssr/src/matching.rs +++ b/crates/ra_ssr/src/matching.rs | |||
@@ -2,8 +2,8 @@ | |||
2 | //! process of matching, placeholder values are recorded. | 2 | //! process of matching, placeholder values are recorded. |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | parsing::{Constraint, NodeKind, Placeholder, SsrTemplate}, | 5 | parsing::{Constraint, NodeKind, ParsedRule, Placeholder, SsrTemplate}, |
6 | SsrMatches, SsrPattern, SsrRule, | 6 | SsrMatches, |
7 | }; | 7 | }; |
8 | use hir::Semantics; | 8 | use hir::Semantics; |
9 | use ra_db::FileRange; | 9 | use ra_db::FileRange; |
@@ -50,7 +50,7 @@ pub struct Match { | |||
50 | pub(crate) ignored_comments: Vec<ast::Comment>, | 50 | pub(crate) ignored_comments: Vec<ast::Comment>, |
51 | // A copy of the template for the rule that produced this match. We store this on the match for | 51 | // A copy of the template for the rule that produced this match. We store this on the match for |
52 | // if/when we do replacement. | 52 | // if/when we do replacement. |
53 | pub(crate) template: SsrTemplate, | 53 | pub(crate) template: Option<SsrTemplate>, |
54 | } | 54 | } |
55 | 55 | ||
56 | /// Represents a `$var` in an SSR query. | 56 | /// Represents a `$var` in an SSR query. |
@@ -86,7 +86,7 @@ pub(crate) struct MatchFailed { | |||
86 | /// parent module, we don't populate nested matches. | 86 | /// parent module, we don't populate nested matches. |
87 | pub(crate) fn get_match( | 87 | pub(crate) fn get_match( |
88 | debug_active: bool, | 88 | debug_active: bool, |
89 | rule: &SsrRule, | 89 | rule: &ParsedRule, |
90 | code: &SyntaxNode, | 90 | code: &SyntaxNode, |
91 | restrict_range: &Option<FileRange>, | 91 | restrict_range: &Option<FileRange>, |
92 | sema: &Semantics<ra_ide_db::RootDatabase>, | 92 | sema: &Semantics<ra_ide_db::RootDatabase>, |
@@ -102,7 +102,7 @@ struct Matcher<'db, 'sema> { | |||
102 | /// If any placeholders come from anywhere outside of this range, then the match will be | 102 | /// If any placeholders come from anywhere outside of this range, then the match will be |
103 | /// rejected. | 103 | /// rejected. |
104 | restrict_range: Option<FileRange>, | 104 | restrict_range: Option<FileRange>, |
105 | rule: &'sema SsrRule, | 105 | rule: &'sema ParsedRule, |
106 | } | 106 | } |
107 | 107 | ||
108 | /// Which phase of matching we're currently performing. We do two phases because most attempted | 108 | /// Which phase of matching we're currently performing. We do two phases because most attempted |
@@ -117,15 +117,14 @@ enum Phase<'a> { | |||
117 | 117 | ||
118 | impl<'db, 'sema> Matcher<'db, 'sema> { | 118 | impl<'db, 'sema> Matcher<'db, 'sema> { |
119 | fn try_match( | 119 | fn try_match( |
120 | rule: &'sema SsrRule, | 120 | rule: &ParsedRule, |
121 | code: &SyntaxNode, | 121 | code: &SyntaxNode, |
122 | restrict_range: &Option<FileRange>, | 122 | restrict_range: &Option<FileRange>, |
123 | sema: &'sema Semantics<'db, ra_ide_db::RootDatabase>, | 123 | sema: &'sema Semantics<'db, ra_ide_db::RootDatabase>, |
124 | ) -> Result<Match, MatchFailed> { | 124 | ) -> Result<Match, MatchFailed> { |
125 | let match_state = Matcher { sema, restrict_range: restrict_range.clone(), rule }; | 125 | let match_state = Matcher { sema, restrict_range: restrict_range.clone(), rule }; |
126 | let pattern_tree = rule.pattern.tree_for_kind(code.kind())?; | ||
127 | // First pass at matching, where we check that node types and idents match. | 126 | // First pass at matching, where we check that node types and idents match. |
128 | match_state.attempt_match_node(&mut Phase::First, &pattern_tree, code)?; | 127 | match_state.attempt_match_node(&mut Phase::First, &rule.pattern, code)?; |
129 | match_state.validate_range(&sema.original_range(code))?; | 128 | match_state.validate_range(&sema.original_range(code))?; |
130 | let mut the_match = Match { | 129 | let mut the_match = Match { |
131 | range: sema.original_range(code), | 130 | range: sema.original_range(code), |
@@ -136,7 +135,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
136 | }; | 135 | }; |
137 | // Second matching pass, where we record placeholder matches, ignored comments and maybe do | 136 | // Second matching pass, where we record placeholder matches, ignored comments and maybe do |
138 | // any other more expensive checks that we didn't want to do on the first pass. | 137 | // any other more expensive checks that we didn't want to do on the first pass. |
139 | match_state.attempt_match_node(&mut Phase::Second(&mut the_match), &pattern_tree, code)?; | 138 | match_state.attempt_match_node(&mut Phase::Second(&mut the_match), &rule.pattern, code)?; |
140 | Ok(the_match) | 139 | Ok(the_match) |
141 | } | 140 | } |
142 | 141 | ||
@@ -444,8 +443,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
444 | } | 443 | } |
445 | 444 | ||
446 | fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> { | 445 | fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> { |
447 | only_ident(element.clone()) | 446 | only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident)) |
448 | .and_then(|ident| self.rule.pattern.placeholders_by_stand_in.get(ident.text())) | ||
449 | } | 447 | } |
450 | } | 448 | } |
451 | 449 | ||
@@ -510,28 +508,6 @@ impl PlaceholderMatch { | |||
510 | } | 508 | } |
511 | } | 509 | } |
512 | 510 | ||
513 | impl SsrPattern { | ||
514 | pub(crate) fn tree_for_kind(&self, kind: SyntaxKind) -> Result<&SyntaxNode, MatchFailed> { | ||
515 | let (tree, kind_name) = if ast::Expr::can_cast(kind) { | ||
516 | (&self.expr, "expression") | ||
517 | } else if ast::TypeRef::can_cast(kind) { | ||
518 | (&self.type_ref, "type reference") | ||
519 | } else if ast::ModuleItem::can_cast(kind) { | ||
520 | (&self.item, "item") | ||
521 | } else if ast::Path::can_cast(kind) { | ||
522 | (&self.path, "path") | ||
523 | } else if ast::Pat::can_cast(kind) { | ||
524 | (&self.pattern, "pattern") | ||
525 | } else { | ||
526 | fail_match!("Matching nodes of kind {:?} is not supported", kind); | ||
527 | }; | ||
528 | match tree { | ||
529 | Some(tree) => Ok(tree), | ||
530 | None => fail_match!("Pattern cannot be parsed as a {}", kind_name), | ||
531 | } | ||
532 | } | ||
533 | } | ||
534 | |||
535 | impl NodeKind { | 511 | impl NodeKind { |
536 | fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> { | 512 | fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> { |
537 | let ok = match self { | 513 | let ok = match self { |