From 0383806bc778a15e299943d63bd079c45bd77d82 Mon Sep 17 00:00:00 2001 From: Matt Stark Date: Wed, 19 Jun 2024 09:27:16 +1000 Subject: [PATCH] refactor: Allow the aliases map to map to arbitrary types. For #3673, we will have aliases such as: ```toml 'upload(revision)' = [ ["fix", "-r", "$revision"], ["lint", "-r", "$revision"], ["git", "push", "-r", "$revision"], ] ``` Template aliases: 1) Start as Config::Value 2) Are converted to String 3) Are placed in the alias map 4) Expand to a TemplateExpression type via expand_defn. However, command aliases: 1) Start as Config::Value 2) Are converted to Vec> 3) Are placed in an alias map 4) Do not expand Thus, AliasesMap will need to support non-string values. --- lib/src/dsl_util.rs | 58 ++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/lib/src/dsl_util.rs b/lib/src/dsl_util.rs index 4ceb00dcc0..5189646a48 100644 --- a/lib/src/dsl_util.rs +++ b/lib/src/dsl_util.rs @@ -17,6 +17,7 @@ use std::array; use std::collections::HashMap; use std::fmt; +use std::ops::Deref; use std::slice; use itertools::Itertools as _; @@ -423,16 +424,28 @@ impl StringLiteralParser { } /// Map of symbol and function aliases. -#[derive(Clone, Debug, Default)] -pub struct AliasesMap

{ - symbol_aliases: HashMap, +#[derive(Clone, Debug)] +pub struct AliasesMap { + symbol_aliases: HashMap, // name: [(params, defn)] (sorted by arity) - function_aliases: HashMap, String)>>, + function_aliases: HashMap, V)>>, // Parser type P helps prevent misuse of AliasesMap of different language. parser: P, } -impl

AliasesMap

{ +// Unfortunately, #[derive(Default)] doesn't work correctly since V isn't +// Default. https://stackoverflow.com/questions/59538071/the-trait-bound-t-stddefaultdefault-is-not-satisfied-when-using-phantomda +impl Default for AliasesMap { + fn default() -> Self { + Self { + symbol_aliases: Default::default(), + function_aliases: Default::default(), + parser: Default::default(), + } + } +} + +impl AliasesMap { /// Creates an empty aliases map with default-constructed parser. pub fn new() -> Self where @@ -445,7 +458,7 @@ impl

AliasesMap

{ /// /// Returns error if `decl` is invalid. The `defn` part isn't checked. A bad /// `defn` will be reported when the alias is substituted. - pub fn insert(&mut self, decl: impl AsRef, defn: impl Into) -> Result<(), P::Error> + pub fn insert(&mut self, decl: impl AsRef, defn: impl Into) -> Result<(), P::Error> where P: AliasDeclarationParser, { @@ -475,46 +488,53 @@ impl

AliasesMap

{ } /// Looks up symbol alias by name. Returns identifier and definition text. - pub fn get_symbol(&self, name: &str) -> Option<(AliasId<'_>, &str)> { + pub fn get_symbol(&self, name: &str) -> Option<(AliasId<'_>, &::Target)> { self.symbol_aliases .get_key_value(name) - .map(|(name, defn)| (AliasId::Symbol(name), defn.as_ref())) + .map(|(name, defn)| (AliasId::Symbol(name), defn.deref())) } /// Looks up function alias by name and arity. Returns identifier, list of /// parameter names, and definition text. - pub fn get_function(&self, name: &str, arity: usize) -> Option<(AliasId<'_>, &[String], &str)> { + pub fn get_function( + &self, + name: &str, + arity: usize, + ) -> Option<(AliasId<'_>, &[String], &::Target)> { let overloads = self.get_function_overloads(name)?; overloads.find_by_arity(arity) } /// Looks up function aliases by name. - fn get_function_overloads(&self, name: &str) -> Option> { + fn get_function_overloads(&self, name: &str) -> Option> { let (name, overloads) = self.function_aliases.get_key_value(name)?; Some(AliasFunctionOverloads { name, overloads }) } } #[derive(Clone, Copy, Debug)] -struct AliasFunctionOverloads<'a> { +struct AliasFunctionOverloads<'a, V: Deref> { name: &'a String, - overloads: &'a Vec<(Vec, String)>, + overloads: &'a Vec<(Vec, V)>, } -impl<'a> AliasFunctionOverloads<'a> { - fn arities(self) -> impl DoubleEndedIterator + ExactSizeIterator + 'a { +impl<'a, V: Deref> AliasFunctionOverloads<'a, V> { + fn arities(&self) -> impl DoubleEndedIterator + ExactSizeIterator + 'a { self.overloads.iter().map(|(params, _)| params.len()) } - fn min_arity(self) -> usize { + fn min_arity(&self) -> usize { self.arities().next().unwrap() } - fn max_arity(self) -> usize { + fn max_arity(&self) -> usize { self.arities().next_back().unwrap() } - fn find_by_arity(self, arity: usize) -> Option<(AliasId<'a>, &'a [String], &'a str)> { + fn find_by_arity( + &self, + arity: usize, + ) -> Option<(AliasId<'a>, &'a [String], &'a ::Target)> { let index = self .overloads .binary_search_by_key(&arity, |(params, _)| params.len()) @@ -609,7 +629,7 @@ pub trait AliasExpandError: Sized { #[derive(Debug)] struct AliasExpander<'i, T, P> { /// Alias symbols and functions that are globally available. - aliases_map: &'i AliasesMap

, + aliases_map: &'i AliasesMap, /// Stack of aliases and local parameters currently expanding. states: Vec>, } @@ -708,7 +728,7 @@ where /// Expands aliases recursively. pub fn expand_aliases<'i, T, P>( node: ExpressionNode<'i, T>, - aliases_map: &'i AliasesMap

, + aliases_map: &'i AliasesMap, ) -> Result, P::Error> where T: AliasExpandableExpression<'i> + Clone,