From 3d9997889bfe536a96e70535ab208a6e7ff3bc12 Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Tue, 23 Jun 2020 19:07:42 +1000 Subject: SSR: Add initial support for placeholder constraints --- crates/ra_ssr/src/matching.rs | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'crates/ra_ssr/src/matching.rs') diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs index 53d802e77..ce53d46d2 100644 --- a/crates/ra_ssr/src/matching.rs +++ b/crates/ra_ssr/src/matching.rs @@ -2,7 +2,7 @@ //! process of matching, placeholder values are recorded. use crate::{ - parsing::{Placeholder, SsrTemplate}, + parsing::{Constraint, NodeKind, Placeholder, SsrTemplate}, SsrMatches, SsrPattern, SsrRule, }; use hir::Semantics; @@ -11,6 +11,7 @@ use ra_syntax::ast::{AstNode, AstToken}; use ra_syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken}; use rustc_hash::FxHashMap; use std::{cell::Cell, iter::Peekable}; +use test_utils::mark; // Creates a match error. If we're currently attempting to match some code that we thought we were // going to match, as indicated by the --debug-snippet flag, then populate the reason field. @@ -169,6 +170,9 @@ impl<'db, 'sema> MatchState<'db, 'sema> { if let Some(placeholder) = match_inputs.get_placeholder(&SyntaxElement::Node(pattern.clone())) { + for constraint in &placeholder.constraints { + self.check_constraint(constraint, code)?; + } if self.match_out.is_none() { return Ok(()); } @@ -292,6 +296,24 @@ impl<'db, 'sema> MatchState<'db, 'sema> { Ok(()) } + fn check_constraint( + &self, + constraint: &Constraint, + code: &SyntaxNode, + ) -> Result<(), MatchFailed> { + match constraint { + Constraint::Kind(kind) => { + kind.matches(code)?; + } + Constraint::Not(sub) => { + if self.check_constraint(&*sub, code).is_ok() { + fail_match!("Constraint {:?} failed for '{}'", constraint, code.text()); + } + } + } + Ok(()) + } + /// We want to allow the records to match in any order, so we have special matching logic for /// them. fn attempt_match_record_field_list( @@ -515,6 +537,21 @@ impl SsrPattern { } } +impl NodeKind { + fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> { + let ok = match self { + Self::Literal => { + mark::hit!(literal_constraint); + ast::Literal::can_cast(node.kind()) + } + }; + if !ok { + fail_match!("Code '{}' isn't of kind {:?}", node.text(), self); + } + Ok(()) + } +} + // If `node` contains nothing but an ident then return it, otherwise return None. fn only_ident(element: SyntaxElement) -> Option { match element { -- cgit v1.2.3