From c84f98385a28eeb7595f38b7cfaf861a6e06f4ea Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Thu, 6 Aug 2020 11:30:52 +1000 Subject: Refactor SSR so that placeholders store a Var This allows lookup of placeholder bindings given a placeholder without needing to create a Var instance. --- crates/ssr/src/matching.rs | 15 +++++---------- crates/ssr/src/parsing.rs | 24 +++++++++++++++++++----- crates/ssr/src/replacing.rs | 3 +-- crates/ssr/src/tests.rs | 2 +- 4 files changed, 26 insertions(+), 18 deletions(-) (limited to 'crates/ssr/src') diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs index ffc7202ae..7f0b5061e 100644 --- a/crates/ssr/src/matching.rs +++ b/crates/ssr/src/matching.rs @@ -2,7 +2,7 @@ //! process of matching, placeholder values are recorded. use crate::{ - parsing::{Constraint, NodeKind, Placeholder}, + parsing::{Constraint, NodeKind, Placeholder, Var}, resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo}, SsrMatches, }; @@ -56,10 +56,6 @@ pub struct Match { pub(crate) rendered_template_paths: FxHashMap, } -/// Represents a `$var` in an SSR query. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct Var(pub String); - /// Information about a placeholder bound in a match. #[derive(Debug)] pub(crate) struct PlaceholderMatch { @@ -182,10 +178,9 @@ impl<'db, 'sema> Matcher<'db, 'sema> { // We validated the range for the node when we started the match, so the placeholder // probably can't fail range validation, but just to be safe... self.validate_range(&original_range)?; - matches_out.placeholder_values.insert( - Var(placeholder.ident.to_string()), - PlaceholderMatch::new(code, original_range), - ); + matches_out + .placeholder_values + .insert(placeholder.ident.clone(), PlaceholderMatch::new(code, original_range)); } return Ok(()); } @@ -487,7 +482,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { } if let Phase::Second(match_out) = phase { match_out.placeholder_values.insert( - Var(placeholder.ident.to_string()), + placeholder.ident.clone(), PlaceholderMatch::from_range(FileRange { file_id: self.sema.original_range(code).file_id, range: first_matched_token diff --git a/crates/ssr/src/parsing.rs b/crates/ssr/src/parsing.rs index 9570e96e3..05b66dcd7 100644 --- a/crates/ssr/src/parsing.rs +++ b/crates/ssr/src/parsing.rs @@ -8,7 +8,7 @@ use crate::errors::bail; use crate::{SsrError, SsrPattern, SsrRule}; use rustc_hash::{FxHashMap, FxHashSet}; -use std::str::FromStr; +use std::{fmt::Display, str::FromStr}; use syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, T}; use test_utils::mark; @@ -34,12 +34,16 @@ pub(crate) enum PatternElement { #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct Placeholder { /// The name of this placeholder. e.g. for "$a", this would be "a" - pub(crate) ident: SmolStr, + pub(crate) ident: Var, /// A unique name used in place of this placeholder when we parse the pattern as Rust code. stand_in_name: String, pub(crate) constraints: Vec, } +/// Represents a `$var` in an SSR query. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct Var(pub String); + #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum Constraint { Kind(NodeKind), @@ -205,7 +209,7 @@ fn parse_pattern(pattern_str: &str) -> Result, SsrError> { if token.kind == T![$] { let placeholder = parse_placeholder(&mut tokens)?; if !placeholder_names.insert(placeholder.ident.clone()) { - bail!("Name `{}` repeats more than once", placeholder.ident); + bail!("Placeholder `{}` repeats more than once", placeholder.ident); } res.push(PatternElement::Placeholder(placeholder)); } else { @@ -228,7 +232,7 @@ fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> { for p in &rule.template.tokens { if let PatternElement::Placeholder(placeholder) = p { if !defined_placeholders.contains(&placeholder.ident) { - undefined.push(format!("${}", placeholder.ident)); + undefined.push(placeholder.ident.to_string()); } if !placeholder.constraints.is_empty() { bail!("Replacement placeholders cannot have constraints"); @@ -344,7 +348,17 @@ impl NodeKind { impl Placeholder { fn new(name: SmolStr, constraints: Vec) -> Self { - Self { stand_in_name: format!("__placeholder_{}", name), constraints, ident: name } + Self { + stand_in_name: format!("__placeholder_{}", name), + constraints, + ident: Var(name.to_string()), + } + } +} + +impl Display for Var { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "${}", self.0) } } diff --git a/crates/ssr/src/replacing.rs b/crates/ssr/src/replacing.rs index 8f8fe6149..496a21e6e 100644 --- a/crates/ssr/src/replacing.rs +++ b/crates/ssr/src/replacing.rs @@ -1,6 +1,5 @@ //! Code for applying replacement templates for matches that have previously been found. -use crate::matching::Var; use crate::{resolving::ResolvedRule, Match, SsrMatches}; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ast::{self, AstToken}; @@ -114,7 +113,7 @@ impl ReplacementRenderer<'_> { fn render_token(&mut self, token: &SyntaxToken) { if let Some(placeholder) = self.rule.get_placeholder(&token) { if let Some(placeholder_value) = - self.match_info.placeholder_values.get(&Var(placeholder.ident.to_string())) + self.match_info.placeholder_values.get(&placeholder.ident) { let range = &placeholder_value.range.range; let mut matched_text = diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs index 0d0a00090..65cd38753 100644 --- a/crates/ssr/src/tests.rs +++ b/crates/ssr/src/tests.rs @@ -31,7 +31,7 @@ fn parser_two_delimiters() { fn parser_repeated_name() { assert_eq!( parse_error_text("foo($a, $a) ==>>"), - "Parse error: Name `a` repeats more than once" + "Parse error: Placeholder `$a` repeats more than once" ); } -- cgit v1.2.3