forked from mirrors/jj
templater: migrate to generic dsl_util::AliasesMap type
This commit is contained in:
parent
2cbc4f9996
commit
c04fb7d33a
2 changed files with 25 additions and 91 deletions
|
@ -13,11 +13,12 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::{error, fmt, mem};
|
use std::{error, mem};
|
||||||
|
|
||||||
use itertools::Itertools as _;
|
use itertools::Itertools as _;
|
||||||
use jj_lib::dsl_util::{
|
use jj_lib::dsl_util::{
|
||||||
collect_similar, AliasDeclaration, AliasDeclarationParser, StringLiteralParser,
|
collect_similar, AliasDeclaration, AliasDeclarationParser, AliasId, AliasesMap,
|
||||||
|
StringLiteralParser,
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use pest::iterators::{Pair, Pairs};
|
use pest::iterators::{Pair, Pairs};
|
||||||
|
@ -169,14 +170,12 @@ impl TemplateParseError {
|
||||||
TemplateParseError::with_span(TemplateParseErrorKind::Expression(message.into()), span)
|
TemplateParseError::with_span(TemplateParseErrorKind::Expression(message.into()), span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn within_alias_expansion(self, id: TemplateAliasId<'_>, span: pest::Span<'_>) -> Self {
|
pub fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
|
||||||
let kind = match id {
|
let kind = match id {
|
||||||
TemplateAliasId::Symbol(_) | TemplateAliasId::Function(_) => {
|
AliasId::Symbol(_) | AliasId::Function(_) => {
|
||||||
TemplateParseErrorKind::BadAliasExpansion(id.to_string())
|
TemplateParseErrorKind::BadAliasExpansion(id.to_string())
|
||||||
}
|
}
|
||||||
TemplateAliasId::Parameter(_) => {
|
AliasId::Parameter(_) => TemplateParseErrorKind::BadParameterExpansion(id.to_string()),
|
||||||
TemplateParseErrorKind::BadParameterExpansion(id.to_string())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
TemplateParseError::with_span(kind, span).with_source(self)
|
TemplateParseError::with_span(kind, span).with_source(self)
|
||||||
}
|
}
|
||||||
|
@ -215,8 +214,8 @@ impl TemplateParseError {
|
||||||
|
|
||||||
/// Expands keyword/function candidates with the given aliases.
|
/// Expands keyword/function candidates with the given aliases.
|
||||||
pub fn extend_alias_candidates(self, aliases_map: &TemplateAliasesMap) -> Self {
|
pub fn extend_alias_candidates(self, aliases_map: &TemplateAliasesMap) -> Self {
|
||||||
self.extend_keyword_candidates(aliases_map.symbol_aliases.keys())
|
self.extend_keyword_candidates(aliases_map.symbol_names())
|
||||||
.extend_function_candidates(aliases_map.function_aliases.keys())
|
.extend_function_candidates(aliases_map.function_names())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> &TemplateParseErrorKind {
|
pub fn kind(&self) -> &TemplateParseErrorKind {
|
||||||
|
@ -273,7 +272,7 @@ pub enum ExpressionKind<'i> {
|
||||||
MethodCall(Box<MethodCallNode<'i>>),
|
MethodCall(Box<MethodCallNode<'i>>),
|
||||||
Lambda(Box<LambdaNode<'i>>),
|
Lambda(Box<LambdaNode<'i>>),
|
||||||
/// Identity node to preserve the span in the source template text.
|
/// Identity node to preserve the span in the source template text.
|
||||||
AliasExpanded(TemplateAliasId<'i>, Box<ExpressionNode<'i>>),
|
AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
|
@ -498,62 +497,10 @@ pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type TemplateAliasesMap = AliasesMap<TemplateAliasParser>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct TemplateAliasesMap {
|
pub struct TemplateAliasParser;
|
||||||
symbol_aliases: HashMap<String, String>,
|
|
||||||
function_aliases: HashMap<String, (Vec<String>, String)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TemplateAliasesMap {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn symbol_names(&self) -> impl Iterator<Item = &str> {
|
|
||||||
self.symbol_aliases.keys().map(|s| s.as_str())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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>,
|
|
||||||
) -> TemplateParseResult<()> {
|
|
||||||
match TemplateAliasParser.parse_declaration(decl.as_ref())? {
|
|
||||||
AliasDeclaration::Symbol(name) => {
|
|
||||||
self.symbol_aliases.insert(name, defn.into());
|
|
||||||
}
|
|
||||||
AliasDeclaration::Function(name, params) => {
|
|
||||||
self.function_aliases.insert(name, (params, defn.into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_symbol(&self, name: &str) -> Option<(TemplateAliasId<'_>, &str)> {
|
|
||||||
self.symbol_aliases
|
|
||||||
.get_key_value(name)
|
|
||||||
.map(|(name, defn)| (TemplateAliasId::Symbol(name), defn.as_ref()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_function(&self, name: &str) -> Option<(TemplateAliasId<'_>, &[String], &str)> {
|
|
||||||
self.function_aliases
|
|
||||||
.get_key_value(name)
|
|
||||||
.map(|(name, (params, defn))| {
|
|
||||||
(
|
|
||||||
TemplateAliasId::Function(name),
|
|
||||||
params.as_ref(),
|
|
||||||
defn.as_ref(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct TemplateAliasParser;
|
|
||||||
|
|
||||||
impl AliasDeclarationParser for TemplateAliasParser {
|
impl AliasDeclarationParser for TemplateAliasParser {
|
||||||
type Error = TemplateParseError;
|
type Error = TemplateParseError;
|
||||||
|
@ -582,24 +529,6 @@ impl AliasDeclarationParser for TemplateAliasParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrowed reference to identify alias expression.
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
||||||
pub enum TemplateAliasId<'a> {
|
|
||||||
Symbol(&'a str),
|
|
||||||
Function(&'a str),
|
|
||||||
Parameter(&'a str),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TemplateAliasId<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
TemplateAliasId::Symbol(name) => write!(f, "{name}"),
|
|
||||||
TemplateAliasId::Function(name) => write!(f, "{name}()"),
|
|
||||||
TemplateAliasId::Parameter(name) => write!(f, "{name}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expand aliases recursively.
|
/// Expand aliases recursively.
|
||||||
pub fn expand_aliases<'i>(
|
pub fn expand_aliases<'i>(
|
||||||
node: ExpressionNode<'i>,
|
node: ExpressionNode<'i>,
|
||||||
|
@ -608,12 +537,12 @@ pub fn expand_aliases<'i>(
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct State<'a, 'i> {
|
struct State<'a, 'i> {
|
||||||
aliases_map: &'i TemplateAliasesMap,
|
aliases_map: &'i TemplateAliasesMap,
|
||||||
aliases_expanding: &'a [TemplateAliasId<'a>],
|
aliases_expanding: &'a [AliasId<'a>],
|
||||||
locals: &'a HashMap<&'a str, ExpressionNode<'i>>,
|
locals: &'a HashMap<&'a str, ExpressionNode<'i>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_defn<'i>(
|
fn expand_defn<'i>(
|
||||||
id: TemplateAliasId<'i>,
|
id: AliasId<'i>,
|
||||||
defn: &'i str,
|
defn: &'i str,
|
||||||
locals: &HashMap<&str, ExpressionNode<'i>>,
|
locals: &HashMap<&str, ExpressionNode<'i>>,
|
||||||
span: pest::Span<'i>,
|
span: pest::Span<'i>,
|
||||||
|
@ -670,10 +599,7 @@ pub fn expand_aliases<'i>(
|
||||||
let kind = match kind {
|
let kind = match kind {
|
||||||
ExpressionKind::Identifier(name) => {
|
ExpressionKind::Identifier(name) => {
|
||||||
if let Some(subst) = state.locals.get(name) {
|
if let Some(subst) = state.locals.get(name) {
|
||||||
ExpressionKind::AliasExpanded(
|
ExpressionKind::AliasExpanded(AliasId::Parameter(name), Box::new(subst.clone()))
|
||||||
TemplateAliasId::Parameter(name),
|
|
||||||
Box::new(subst.clone()),
|
|
||||||
)
|
|
||||||
} else if let Some((id, defn)) = state.aliases_map.get_symbol(name) {
|
} else if let Some((id, defn)) = state.aliases_map.get_symbol(name) {
|
||||||
let locals = HashMap::new(); // Don't spill out the current scope
|
let locals = HashMap::new(); // Don't spill out the current scope
|
||||||
expand_defn(id, defn, &locals, span, state)?
|
expand_defn(id, defn, &locals, span, state)?
|
||||||
|
@ -1240,11 +1166,11 @@ mod tests {
|
||||||
aliases_map.insert("func(a)", r#""is function""#).unwrap();
|
aliases_map.insert("func(a)", r#""is function""#).unwrap();
|
||||||
|
|
||||||
let (id, defn) = aliases_map.get_symbol("sym").unwrap();
|
let (id, defn) = aliases_map.get_symbol("sym").unwrap();
|
||||||
assert_eq!(id, TemplateAliasId::Symbol("sym"));
|
assert_eq!(id, AliasId::Symbol("sym"));
|
||||||
assert_eq!(defn, r#""is symbol""#);
|
assert_eq!(defn, r#""is symbol""#);
|
||||||
|
|
||||||
let (id, params, defn) = aliases_map.get_function("func").unwrap();
|
let (id, params, defn) = aliases_map.get_function("func").unwrap();
|
||||||
assert_eq!(id, TemplateAliasId::Function("func"));
|
assert_eq!(id, AliasId::Function("func"));
|
||||||
assert_eq!(params, ["a"]);
|
assert_eq!(params, ["a"]);
|
||||||
assert_eq!(defn, r#""is function""#);
|
assert_eq!(defn, r#""is function""#);
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,11 @@ impl<P> AliasesMap<P> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterates symbol names in arbitrary order.
|
||||||
|
pub fn symbol_names(&self) -> impl Iterator<Item = &str> {
|
||||||
|
self.symbol_aliases.keys().map(|n| n.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterates function names in arbitrary order.
|
/// Iterates function names in arbitrary order.
|
||||||
pub fn function_names(&self) -> impl Iterator<Item = &str> {
|
pub fn function_names(&self) -> impl Iterator<Item = &str> {
|
||||||
self.function_aliases.keys().map(|n| n.as_ref())
|
self.function_aliases.keys().map(|n| n.as_ref())
|
||||||
|
@ -120,6 +125,8 @@ pub enum AliasId<'a> {
|
||||||
Symbol(&'a str),
|
Symbol(&'a str),
|
||||||
/// Function name.
|
/// Function name.
|
||||||
Function(&'a str),
|
Function(&'a str),
|
||||||
|
/// Function parameter name.
|
||||||
|
Parameter(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for AliasId<'_> {
|
impl fmt::Display for AliasId<'_> {
|
||||||
|
@ -127,6 +134,7 @@ impl fmt::Display for AliasId<'_> {
|
||||||
match self {
|
match self {
|
||||||
AliasId::Symbol(name) => write!(f, "{name}"),
|
AliasId::Symbol(name) => write!(f, "{name}"),
|
||||||
AliasId::Function(name) => write!(f, "{name}()"),
|
AliasId::Function(name) => write!(f, "{name}()"),
|
||||||
|
AliasId::Parameter(name) => write!(f, "{name}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue