Skip to content

Commit

Permalink
refactor: Allow the aliases map to map to arbitrary types.
Browse files Browse the repository at this point in the history
For martinvonz#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<Vec<String>>
3) Are placed in an alias map
4) Do not expand

Thus, AliasesMap will need to support non-string values.
  • Loading branch information
matts1 committed Oct 7, 2024
1 parent 3d26af8 commit 5b2ed0a
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 22 deletions.
2 changes: 1 addition & 1 deletion cli/src/template_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode
}
}

pub type TemplateAliasesMap = AliasesMap<TemplateAliasParser>;
pub type TemplateAliasesMap = AliasesMap<TemplateAliasParser, String>;

#[derive(Clone, Debug, Default)]
pub struct TemplateAliasParser;
Expand Down
44 changes: 24 additions & 20 deletions lib/src/dsl_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,28 +424,32 @@ impl<R: RuleType> StringLiteralParser<R> {

/// Map of symbol and function aliases.
#[derive(Clone, Debug, Default)]
pub struct AliasesMap<P> {
symbol_aliases: HashMap<String, String>,
pub struct AliasesMap<P, V> {
symbol_aliases: HashMap<String, V>,
// name: [(params, defn)] (sorted by arity)
function_aliases: HashMap<String, Vec<(Vec<String>, String)>>,
function_aliases: HashMap<String, Vec<(Vec<String>, V)>>,
// Parser type P helps prevent misuse of AliasesMap of different language.
parser: P,
}

impl<P> AliasesMap<P> {
impl<P, V> AliasesMap<P, V> {
/// Creates an empty aliases map with default-constructed parser.
pub fn new() -> Self
where
P: Default,
{
Self::default()
Self {
symbol_aliases: Default::default(),
function_aliases: Default::default(),
parser: Default::default(),
}
}

/// Adds new substitution rule `decl = defn`.
///
/// 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<str>, defn: impl Into<String>) -> Result<(), P::Error>
pub fn insert(&mut self, decl: impl AsRef<str>, defn: impl Into<V>) -> Result<(), P::Error>
where
P: AliasDeclarationParser,
{
Expand Down Expand Up @@ -475,46 +479,46 @@ impl<P> AliasesMap<P> {
}

/// 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<'_>, &V)> {
self.symbol_aliases
.get_key_value(name)
.map(|(name, defn)| (AliasId::Symbol(name), defn.as_ref()))
.map(|(name, defn)| (AliasId::Symbol(name), defn))
}

/// 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], &V)> {
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<AliasFunctionOverloads<'_>> {
fn get_function_overloads(&self, name: &str) -> Option<AliasFunctionOverloads<'_, V>> {
let (name, overloads) = self.function_aliases.get_key_value(name)?;
Some(AliasFunctionOverloads { name, overloads })
}
}

#[derive(Clone, Copy, Debug)]
struct AliasFunctionOverloads<'a> {
#[derive(Clone, Debug)]
struct AliasFunctionOverloads<'a, V> {
name: &'a String,
overloads: &'a Vec<(Vec<String>, String)>,
overloads: &'a Vec<(Vec<String>, V)>,
}

impl<'a> AliasFunctionOverloads<'a> {
fn arities(self) -> impl DoubleEndedIterator<Item = usize> + ExactSizeIterator + 'a {
impl<'a, V> AliasFunctionOverloads<'a, V> {
fn arities(&self) -> impl DoubleEndedIterator<Item = usize> + 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 V)> {
let index = self
.overloads
.binary_search_by_key(&arity, |(params, _)| params.len())
Expand Down Expand Up @@ -609,7 +613,7 @@ pub trait AliasExpandError: Sized {
#[derive(Debug)]
struct AliasExpander<'i, T, P> {
/// Alias symbols and functions that are globally available.
aliases_map: &'i AliasesMap<P>,
aliases_map: &'i AliasesMap<P, String>,
/// Stack of aliases and local parameters currently expanding.
states: Vec<AliasExpandingState<'i, T>>,
}
Expand Down Expand Up @@ -708,7 +712,7 @@ where
/// Expands aliases recursively.
pub fn expand_aliases<'i, T, P>(
node: ExpressionNode<'i, T>,
aliases_map: &'i AliasesMap<P>,
aliases_map: &'i AliasesMap<P, String>,
) -> Result<ExpressionNode<'i, T>, P::Error>
where
T: AliasExpandableExpression<'i> + Clone,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/revset_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ fn parse_function_call_node(pair: Pair<Rule>) -> Result<FunctionCallNode, Revset
})
}

pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser>;
pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser, String>;

#[derive(Clone, Debug, Default)]
pub struct RevsetAliasParser;
Expand Down

0 comments on commit 5b2ed0a

Please sign in to comment.