Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Allow the aliases map to map to arbitrary types. #4015

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/src/template_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,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
58 changes: 39 additions & 19 deletions lib/src/dsl_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//! Domain-specific language helpers.
use std::collections::HashMap;
use std::ops::Deref;
use std::{array, fmt};

use itertools::Itertools as _;
Expand Down Expand Up @@ -360,16 +361,28 @@ impl<R: RuleType> StringLiteralParser<R> {
}

/// Map of symbol and function aliases.
#[derive(Clone, Debug, Default)]
pub struct AliasesMap<P> {
symbol_aliases: HashMap<String, String>,
#[derive(Clone, Debug)]
pub struct AliasesMap<P, V: Deref> {
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> {
// 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<P: Default, V: Deref> Default for AliasesMap<P, V> {
fn default() -> Self {
Self {
symbol_aliases: Default::default(),
function_aliases: Default::default(),
parser: Default::default(),
}
}
}

impl<P, V: Deref> AliasesMap<P, V> {
/// Creates an empty aliases map with default-constructed parser.
pub fn new() -> Self
where
Expand All @@ -382,7 +395,7 @@ impl<P> AliasesMap<P> {
///
/// 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 @@ -412,46 +425,53 @@ 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 as Deref>::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], &<V as Deref>::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<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> {
struct AliasFunctionOverloads<'a, V: Deref> {
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: Deref> 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 as Deref>::Target)> {
let index = self
.overloads
.binary_search_by_key(&arity, |(params, _)| params.len())
Expand Down Expand Up @@ -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<P>,
aliases_map: &'i AliasesMap<P, String>,
/// Stack of aliases and local parameters currently expanding.
states: Vec<AliasExpandingState<'i, T>>,
}
Expand Down Expand Up @@ -645,7 +665,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 @@ -682,7 +682,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