diff --git a/cli/src/template_builder.rs b/cli/src/template_builder.rs index 167ebbec6..f453ce09e 100644 --- a/cli/src/template_builder.rs +++ b/cli/src/template_builder.rs @@ -16,6 +16,7 @@ use std::collections::HashMap; use itertools::Itertools as _; use jj_lib::backend::{Signature, Timestamp}; +use jj_lib::dsl_util::AliasExpandError as _; use crate::template_parser::{ self, BinaryOp, ExpressionKind, ExpressionNode, FunctionCallNode, TemplateAliasesMap, diff --git a/cli/src/template_parser.rs b/cli/src/template_parser.rs index 0b7844d9e..04d186354 100644 --- a/cli/src/template_parser.rs +++ b/cli/src/template_parser.rs @@ -17,8 +17,8 @@ use std::{error, mem}; use itertools::Itertools as _; use jj_lib::dsl_util::{ - self, collect_similar, AliasDeclaration, AliasDeclarationParser, AliasExpandableExpression, - AliasId, AliasesMap, InvalidArguments, StringLiteralParser, + self, collect_similar, AliasDeclaration, AliasDeclarationParser, AliasExpandError, + AliasExpandableExpression, AliasId, AliasesMap, InvalidArguments, StringLiteralParser, }; use once_cell::sync::Lazy; use pest::iterators::{Pair, Pairs}; @@ -160,16 +160,6 @@ impl TemplateParseError { TemplateParseError::with_span(TemplateParseErrorKind::Expression(message.into()), span) } - pub fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self { - let kind = match id { - AliasId::Symbol(_) | AliasId::Function(_) => { - TemplateParseErrorKind::BadAliasExpansion(id.to_string()) - } - AliasId::Parameter(_) => TemplateParseErrorKind::BadParameterExpansion(id.to_string()), - }; - TemplateParseError::with_span(kind, span).with_source(self) - } - /// If this is a `NoSuchKeyword` error, expands the candidates list with the /// given `other_keywords`. pub fn extend_keyword_candidates(mut self, other_keywords: I) -> Self @@ -218,6 +208,26 @@ impl TemplateParseError { } } +impl AliasExpandError for TemplateParseError { + fn invalid_arguments(err: InvalidArguments<'_>) -> Self { + err.into() + } + + fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self { + Self::with_span(TemplateParseErrorKind::RecursiveAlias(id.to_string()), span) + } + + fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self { + let kind = match id { + AliasId::Symbol(_) | AliasId::Function(_) => { + TemplateParseErrorKind::BadAliasExpansion(id.to_string()) + } + AliasId::Parameter(_) => TemplateParseErrorKind::BadParameterExpansion(id.to_string()), + }; + Self::with_span(kind, span).with_source(self) + } +} + impl From> for TemplateParseError { fn from(err: pest::error::Error) -> Self { TemplateParseError { @@ -546,10 +556,7 @@ pub fn expand_aliases<'i>( ) -> TemplateParseResult> { // The stack should be short, so let's simply do linear search and duplicate. if state.aliases_expanding.contains(&id) { - return Err(TemplateParseError::with_span( - TemplateParseErrorKind::RecursiveAlias(id.to_string()), - span, - )); + return Err(TemplateParseError::recursive_expansion(id, span)); } let mut aliases_expanding = state.aliases_expanding.to_vec(); aliases_expanding.push(id); diff --git a/lib/src/dsl_util.rs b/lib/src/dsl_util.rs index fcc75202f..ed2f987bd 100644 --- a/lib/src/dsl_util.rs +++ b/lib/src/dsl_util.rs @@ -276,6 +276,16 @@ pub trait AliasExpandableExpression<'i>: Sized { fn alias_expanded(id: AliasId<'i>, subst: Box>) -> Self; } +/// Error that may occur during alias substitution. +pub trait AliasExpandError: Sized { + /// Unexpected number of arguments, or invalid combination of arguments. + fn invalid_arguments(err: InvalidArguments<'_>) -> Self; + /// Recursion detected during alias substitution. + fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self; + /// Attaches alias trace to the current error. + fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self; +} + /// Collects similar names from the `candidates` list. pub fn collect_similar(name: &str, candidates: I) -> Vec where