From 1f0514eecbf588235f8d8cebee7efb04abf9f183 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"], ] ``` Which will require aliases to map to `Vec>` --- cli/src/template_parser.rs | 2 +- lib/src/dsl_util.rs | 58 +++++++++++++++++++++++++------------- lib/src/revset_parser.rs | 2 +- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/cli/src/template_parser.rs b/cli/src/template_parser.rs index 99f418b0e8..17ad52753a 100644 --- a/cli/src/template_parser.rs +++ b/cli/src/template_parser.rs @@ -552,7 +552,7 @@ pub fn parse_template(template_text: &str) -> TemplateParseResult; +pub type TemplateAliasesMap = AliasesMap; #[derive(Clone, Debug, Default)] pub struct TemplateAliasParser; diff --git a/lib/src/dsl_util.rs b/lib/src/dsl_util.rs index 7b21c87516..dcce1119fc 100644 --- a/lib/src/dsl_util.rs +++ b/lib/src/dsl_util.rs @@ -15,6 +15,7 @@ //! Domain-specific language helpers. use std::collections::HashMap; +use std::ops::Deref; use std::{array, fmt}; use itertools::Itertools as _; @@ -360,16 +361,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 @@ -382,7 +395,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, { @@ -412,46 +425,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()) @@ -546,7 +566,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>, } @@ -645,7 +665,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, diff --git a/lib/src/revset_parser.rs b/lib/src/revset_parser.rs index e7fef5f7e4..d99066adb2 100644 --- a/lib/src/revset_parser.rs +++ b/lib/src/revset_parser.rs @@ -682,7 +682,7 @@ fn parse_function_call_node(pair: Pair) -> Result; +pub type RevsetAliasesMap = AliasesMap; #[derive(Clone, Debug, Default)] pub struct RevsetAliasParser;