1use std::collections::HashMap;
16use std::error;
17use std::mem;
18
19use itertools::Itertools as _;
20use jj_lib::dsl_util;
21use jj_lib::dsl_util::collect_similar;
22use jj_lib::dsl_util::AliasDeclaration;
23use jj_lib::dsl_util::AliasDeclarationParser;
24use jj_lib::dsl_util::AliasDefinitionParser;
25use jj_lib::dsl_util::AliasExpandError;
26use jj_lib::dsl_util::AliasExpandableExpression;
27use jj_lib::dsl_util::AliasId;
28use jj_lib::dsl_util::AliasesMap;
29use jj_lib::dsl_util::Diagnostics;
30use jj_lib::dsl_util::ExpressionFolder;
31use jj_lib::dsl_util::FoldableExpression;
32use jj_lib::dsl_util::FunctionCallParser;
33use jj_lib::dsl_util::InvalidArguments;
34use jj_lib::dsl_util::StringLiteralParser;
35use once_cell::sync::Lazy;
36use pest::iterators::Pair;
37use pest::iterators::Pairs;
38use pest::pratt_parser::Assoc;
39use pest::pratt_parser::Op;
40use pest::pratt_parser::PrattParser;
41use pest::Parser as _;
42use pest_derive::Parser;
43use thiserror::Error;
44
45#[derive(Parser)]
46#[grammar = "template.pest"]
47struct TemplateParser;
48
49const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
50 content_rule: Rule::string_content,
51 escape_rule: Rule::string_escape,
52};
53const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser {
54 function_name_rule: Rule::identifier,
55 function_arguments_rule: Rule::function_arguments,
56 keyword_argument_rule: Rule::keyword_argument,
57 argument_name_rule: Rule::identifier,
58 argument_value_rule: Rule::template,
59};
60
61impl Rule {
62 fn to_symbol(self) -> Option<&'static str> {
63 match self {
64 Rule::EOI => None,
65 Rule::whitespace => None,
66 Rule::string_escape => None,
67 Rule::string_content_char => None,
68 Rule::string_content => None,
69 Rule::string_literal => None,
70 Rule::raw_string_content => None,
71 Rule::raw_string_literal => None,
72 Rule::integer_literal => None,
73 Rule::identifier => None,
74 Rule::concat_op => Some("++"),
75 Rule::logical_or_op => Some("||"),
76 Rule::logical_and_op => Some("&&"),
77 Rule::eq_op => Some("=="),
78 Rule::ne_op => Some("!="),
79 Rule::ge_op => Some(">="),
80 Rule::gt_op => Some(">"),
81 Rule::le_op => Some("<="),
82 Rule::lt_op => Some("<"),
83 Rule::logical_not_op => Some("!"),
84 Rule::negate_op => Some("-"),
85 Rule::prefix_ops => None,
86 Rule::infix_ops => None,
87 Rule::function => None,
88 Rule::keyword_argument => None,
89 Rule::argument => None,
90 Rule::function_arguments => None,
91 Rule::lambda => None,
92 Rule::formal_parameters => None,
93 Rule::primary => None,
94 Rule::term => None,
95 Rule::expression => None,
96 Rule::template => None,
97 Rule::program => None,
98 Rule::function_alias_declaration => None,
99 Rule::alias_declaration => None,
100 }
101 }
102}
103
104pub type TemplateDiagnostics = Diagnostics<TemplateParseError>;
106
107pub type TemplateParseResult<T> = Result<T, TemplateParseError>;
108
109#[derive(Debug, Error)]
110#[error("{pest_error}")]
111pub struct TemplateParseError {
112 kind: TemplateParseErrorKind,
113 pest_error: Box<pest::error::Error<Rule>>,
114 source: Option<Box<dyn error::Error + Send + Sync>>,
115}
116
117#[derive(Clone, Debug, Eq, Error, PartialEq)]
118pub enum TemplateParseErrorKind {
119 #[error("Syntax error")]
120 SyntaxError,
121 #[error("Keyword `{name}` doesn't exist")]
122 NoSuchKeyword {
123 name: String,
124 candidates: Vec<String>,
125 },
126 #[error("Function `{name}` doesn't exist")]
127 NoSuchFunction {
128 name: String,
129 candidates: Vec<String>,
130 },
131 #[error("Method `{name}` doesn't exist for type `{type_name}`")]
132 NoSuchMethod {
133 type_name: String,
134 name: String,
135 candidates: Vec<String>,
136 },
137 #[error("Function `{name}`: {message}")]
138 InvalidArguments { name: String, message: String },
139 #[error("Redefinition of function parameter")]
140 RedefinedFunctionParameter,
141 #[error("{0}")]
142 Expression(String),
143 #[error("In alias `{0}`")]
144 InAliasExpansion(String),
145 #[error("In function parameter `{0}`")]
146 InParameterExpansion(String),
147 #[error("Alias `{0}` expanded recursively")]
148 RecursiveAlias(String),
149}
150
151impl TemplateParseError {
152 pub fn with_span(kind: TemplateParseErrorKind, span: pest::Span<'_>) -> Self {
153 let message = kind.to_string();
154 let pest_error = Box::new(pest::error::Error::new_from_span(
155 pest::error::ErrorVariant::CustomError { message },
156 span,
157 ));
158 TemplateParseError {
159 kind,
160 pest_error,
161 source: None,
162 }
163 }
164
165 pub fn with_source(mut self, source: impl Into<Box<dyn error::Error + Send + Sync>>) -> Self {
166 self.source = Some(source.into());
167 self
168 }
169
170 pub(crate) fn no_such_method(
172 type_name: impl Into<String>,
173 function: &FunctionCallNode,
174 ) -> Self {
175 TemplateParseError::with_span(
176 TemplateParseErrorKind::NoSuchMethod {
177 type_name: type_name.into(),
178 name: function.name.to_owned(),
179 candidates: vec![],
180 },
181 function.name_span,
182 )
183 }
184
185 pub fn expected_type(expected: &str, actual: &str, span: pest::Span<'_>) -> Self {
186 let message =
187 format!("Expected expression of type `{expected}`, but actual type is `{actual}`");
188 TemplateParseError::expression(message, span)
189 }
190
191 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
193 TemplateParseError::with_span(TemplateParseErrorKind::Expression(message.into()), span)
194 }
195
196 pub fn extend_keyword_candidates<I>(mut self, other_keywords: I) -> Self
199 where
200 I: IntoIterator,
201 I::Item: AsRef<str>,
202 {
203 if let TemplateParseErrorKind::NoSuchKeyword { name, candidates } = &mut self.kind {
204 let other_candidates = collect_similar(name, other_keywords);
205 *candidates = itertools::merge(mem::take(candidates), other_candidates)
206 .dedup()
207 .collect();
208 }
209 self
210 }
211
212 pub fn extend_function_candidates<I>(mut self, other_functions: I) -> Self
215 where
216 I: IntoIterator,
217 I::Item: AsRef<str>,
218 {
219 if let TemplateParseErrorKind::NoSuchFunction { name, candidates } = &mut self.kind {
220 let other_candidates = collect_similar(name, other_functions);
221 *candidates = itertools::merge(mem::take(candidates), other_candidates)
222 .dedup()
223 .collect();
224 }
225 self
226 }
227
228 pub fn extend_alias_candidates(self, aliases_map: &TemplateAliasesMap) -> Self {
230 self.extend_keyword_candidates(aliases_map.symbol_names())
231 .extend_function_candidates(aliases_map.function_names())
232 }
233
234 pub fn kind(&self) -> &TemplateParseErrorKind {
235 &self.kind
236 }
237
238 pub fn origin(&self) -> Option<&Self> {
240 self.source.as_ref().and_then(|e| e.downcast_ref())
241 }
242}
243
244impl AliasExpandError for TemplateParseError {
245 fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
246 err.into()
247 }
248
249 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
250 Self::with_span(TemplateParseErrorKind::RecursiveAlias(id.to_string()), span)
251 }
252
253 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
254 let kind = match id {
255 AliasId::Symbol(_) | AliasId::Function(..) => {
256 TemplateParseErrorKind::InAliasExpansion(id.to_string())
257 }
258 AliasId::Parameter(_) => TemplateParseErrorKind::InParameterExpansion(id.to_string()),
259 };
260 Self::with_span(kind, span).with_source(self)
261 }
262}
263
264impl From<pest::error::Error<Rule>> for TemplateParseError {
265 fn from(err: pest::error::Error<Rule>) -> Self {
266 TemplateParseError {
267 kind: TemplateParseErrorKind::SyntaxError,
268 pest_error: Box::new(rename_rules_in_pest_error(err)),
269 source: None,
270 }
271 }
272}
273
274impl From<InvalidArguments<'_>> for TemplateParseError {
275 fn from(err: InvalidArguments<'_>) -> Self {
276 let kind = TemplateParseErrorKind::InvalidArguments {
277 name: err.name.to_owned(),
278 message: err.message,
279 };
280 Self::with_span(kind, err.span)
281 }
282}
283
284fn rename_rules_in_pest_error(err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
285 err.renamed_rules(|rule| {
286 rule.to_symbol()
287 .map(|sym| format!("`{sym}`"))
288 .unwrap_or_else(|| format!("<{rule:?}>"))
289 })
290}
291
292#[derive(Clone, Debug, PartialEq)]
293pub enum ExpressionKind<'i> {
294 Identifier(&'i str),
295 Boolean(bool),
296 Integer(i64),
297 String(String),
298 Unary(UnaryOp, Box<ExpressionNode<'i>>),
299 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
300 Concat(Vec<ExpressionNode<'i>>),
301 FunctionCall(Box<FunctionCallNode<'i>>),
302 MethodCall(Box<MethodCallNode<'i>>),
303 Lambda(Box<LambdaNode<'i>>),
304 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
306}
307
308impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
309 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
310 where
311 F: ExpressionFolder<'i, Self> + ?Sized,
312 {
313 match self {
314 ExpressionKind::Identifier(name) => folder.fold_identifier(name, span),
315 ExpressionKind::Boolean(_) | ExpressionKind::Integer(_) | ExpressionKind::String(_) => {
316 Ok(self)
317 }
318 ExpressionKind::Unary(op, arg) => {
319 let arg = Box::new(folder.fold_expression(*arg)?);
320 Ok(ExpressionKind::Unary(op, arg))
321 }
322 ExpressionKind::Binary(op, lhs, rhs) => {
323 let lhs = Box::new(folder.fold_expression(*lhs)?);
324 let rhs = Box::new(folder.fold_expression(*rhs)?);
325 Ok(ExpressionKind::Binary(op, lhs, rhs))
326 }
327 ExpressionKind::Concat(nodes) => Ok(ExpressionKind::Concat(
328 dsl_util::fold_expression_nodes(folder, nodes)?,
329 )),
330 ExpressionKind::FunctionCall(function) => folder.fold_function_call(function, span),
331 ExpressionKind::MethodCall(method) => {
332 let method = Box::new(MethodCallNode {
334 object: folder.fold_expression(method.object)?,
335 function: dsl_util::fold_function_call_args(folder, method.function)?,
336 });
337 Ok(ExpressionKind::MethodCall(method))
338 }
339 ExpressionKind::Lambda(lambda) => {
340 let lambda = Box::new(LambdaNode {
341 params: lambda.params,
342 params_span: lambda.params_span,
343 body: folder.fold_expression(lambda.body)?,
344 });
345 Ok(ExpressionKind::Lambda(lambda))
346 }
347 ExpressionKind::AliasExpanded(id, subst) => {
348 let subst = Box::new(folder.fold_expression(*subst)?);
349 Ok(ExpressionKind::AliasExpanded(id, subst))
350 }
351 }
352 }
353}
354
355impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
356 fn identifier(name: &'i str) -> Self {
357 ExpressionKind::Identifier(name)
358 }
359
360 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
361 ExpressionKind::FunctionCall(function)
362 }
363
364 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
365 ExpressionKind::AliasExpanded(id, subst)
366 }
367}
368
369#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
370pub enum UnaryOp {
371 LogicalNot,
373 Negate,
375}
376
377#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
378pub enum BinaryOp {
379 LogicalOr,
381 LogicalAnd,
383 Eq,
385 Ne,
387 Ge,
389 Gt,
391 Le,
393 Lt,
395}
396
397pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
398pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
399
400#[derive(Clone, Debug, PartialEq)]
401pub struct MethodCallNode<'i> {
402 pub object: ExpressionNode<'i>,
403 pub function: FunctionCallNode<'i>,
404}
405
406#[derive(Clone, Debug, PartialEq)]
407pub struct LambdaNode<'i> {
408 pub params: Vec<&'i str>,
409 pub params_span: pest::Span<'i>,
410 pub body: ExpressionNode<'i>,
411}
412
413fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind {
414 assert_eq!(pair.as_rule(), Rule::identifier);
415 match pair.as_str() {
416 "false" => ExpressionKind::Boolean(false),
417 "true" => ExpressionKind::Boolean(true),
418 name => ExpressionKind::Identifier(name),
419 }
420}
421
422fn parse_identifier_name(pair: Pair<Rule>) -> TemplateParseResult<&str> {
423 let span = pair.as_span();
424 if let ExpressionKind::Identifier(name) = parse_identifier_or_literal(pair) {
425 Ok(name)
426 } else {
427 Err(TemplateParseError::expression("Expected identifier", span))
428 }
429}
430
431fn parse_formal_parameters(params_pair: Pair<Rule>) -> TemplateParseResult<Vec<&str>> {
432 assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
433 let params_span = params_pair.as_span();
434 let params: Vec<_> = params_pair
435 .into_inner()
436 .map(parse_identifier_name)
437 .try_collect()?;
438 if params.iter().all_unique() {
439 Ok(params)
440 } else {
441 Err(TemplateParseError::with_span(
442 TemplateParseErrorKind::RedefinedFunctionParameter,
443 params_span,
444 ))
445 }
446}
447
448fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> {
449 assert_eq!(pair.as_rule(), Rule::lambda);
450 let mut inner = pair.into_inner();
451 let params_pair = inner.next().unwrap();
452 let params_span = params_pair.as_span();
453 let body_pair = inner.next().unwrap();
454 let params = parse_formal_parameters(params_pair)?;
455 let body = parse_template_node(body_pair)?;
456 Ok(LambdaNode {
457 params,
458 params_span,
459 body,
460 })
461}
462
463fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
464 assert_eq!(pair.as_rule(), Rule::term);
465 let mut inner = pair.into_inner();
466 let expr = inner.next().unwrap();
467 let span = expr.as_span();
468 let primary = match expr.as_rule() {
469 Rule::string_literal => {
470 let text = STRING_LITERAL_PARSER.parse(expr.into_inner());
471 ExpressionNode::new(ExpressionKind::String(text), span)
472 }
473 Rule::raw_string_literal => {
474 let [content] = expr.into_inner().collect_array().unwrap();
475 assert_eq!(content.as_rule(), Rule::raw_string_content);
476 let text = content.as_str().to_owned();
477 ExpressionNode::new(ExpressionKind::String(text), span)
478 }
479 Rule::integer_literal => {
480 let value = expr.as_str().parse().map_err(|err| {
481 TemplateParseError::expression("Invalid integer literal", span).with_source(err)
482 })?;
483 ExpressionNode::new(ExpressionKind::Integer(value), span)
484 }
485 Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span),
486 Rule::function => {
487 let function = Box::new(FUNCTION_CALL_PARSER.parse(
488 expr,
489 parse_identifier_name,
490 parse_template_node,
491 )?);
492 ExpressionNode::new(ExpressionKind::FunctionCall(function), span)
493 }
494 Rule::lambda => {
495 let lambda = Box::new(parse_lambda_node(expr)?);
496 ExpressionNode::new(ExpressionKind::Lambda(lambda), span)
497 }
498 Rule::template => parse_template_node(expr)?,
499 other => panic!("unexpected term: {other:?}"),
500 };
501 inner.try_fold(primary, |object, chain| {
502 assert_eq!(chain.as_rule(), Rule::function);
503 let span = object.span.start_pos().span(&chain.as_span().end_pos());
504 let method = Box::new(MethodCallNode {
505 object,
506 function: FUNCTION_CALL_PARSER.parse(
507 chain,
508 parse_identifier_name,
509 parse_template_node,
510 )?,
511 });
512 Ok(ExpressionNode::new(
513 ExpressionKind::MethodCall(method),
514 span,
515 ))
516 })
517}
518
519fn parse_expression_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
520 assert_eq!(pair.as_rule(), Rule::expression);
521 static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| {
522 PrattParser::new()
523 .op(Op::infix(Rule::logical_or_op, Assoc::Left))
524 .op(Op::infix(Rule::logical_and_op, Assoc::Left))
525 .op(Op::infix(Rule::eq_op, Assoc::Left) | Op::infix(Rule::ne_op, Assoc::Left))
526 .op(Op::infix(Rule::ge_op, Assoc::Left)
527 | Op::infix(Rule::gt_op, Assoc::Left)
528 | Op::infix(Rule::le_op, Assoc::Left)
529 | Op::infix(Rule::lt_op, Assoc::Left))
530 .op(Op::prefix(Rule::logical_not_op) | Op::prefix(Rule::negate_op))
531 });
532 PRATT
533 .map_primary(parse_term_node)
534 .map_prefix(|op, rhs| {
535 let op_kind = match op.as_rule() {
536 Rule::logical_not_op => UnaryOp::LogicalNot,
537 Rule::negate_op => UnaryOp::Negate,
538 r => panic!("unexpected prefix operator rule {r:?}"),
539 };
540 let rhs = Box::new(rhs?);
541 let span = op.as_span().start_pos().span(&rhs.span.end_pos());
542 let expr = ExpressionKind::Unary(op_kind, rhs);
543 Ok(ExpressionNode::new(expr, span))
544 })
545 .map_infix(|lhs, op, rhs| {
546 let op_kind = match op.as_rule() {
547 Rule::logical_or_op => BinaryOp::LogicalOr,
548 Rule::logical_and_op => BinaryOp::LogicalAnd,
549 Rule::eq_op => BinaryOp::Eq,
550 Rule::ne_op => BinaryOp::Ne,
551 Rule::ge_op => BinaryOp::Ge,
552 Rule::gt_op => BinaryOp::Gt,
553 Rule::le_op => BinaryOp::Le,
554 Rule::lt_op => BinaryOp::Lt,
555 r => panic!("unexpected infix operator rule {r:?}"),
556 };
557 let lhs = Box::new(lhs?);
558 let rhs = Box::new(rhs?);
559 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
560 let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
561 Ok(ExpressionNode::new(expr, span))
562 })
563 .parse(pair.into_inner())
564}
565
566fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
567 assert_eq!(pair.as_rule(), Rule::template);
568 let span = pair.as_span();
569 let inner = pair.into_inner();
570 let mut nodes: Vec<_> = inner
571 .filter_map(|pair| match pair.as_rule() {
572 Rule::concat_op => None,
573 Rule::expression => Some(parse_expression_node(pair)),
574 r => panic!("unexpected template item rule {r:?}"),
575 })
576 .try_collect()?;
577 if nodes.len() == 1 {
578 Ok(nodes.pop().unwrap())
579 } else {
580 Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span))
581 }
582}
583
584pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode> {
586 let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?;
587 let first_pair = pairs.next().unwrap();
588 if first_pair.as_rule() == Rule::EOI {
589 let span = first_pair.as_span();
590 Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span))
591 } else {
592 parse_template_node(first_pair)
593 }
594}
595
596pub type TemplateAliasesMap = AliasesMap<TemplateAliasParser, String>;
597
598#[derive(Clone, Debug, Default)]
599pub struct TemplateAliasParser;
600
601impl AliasDeclarationParser for TemplateAliasParser {
602 type Error = TemplateParseError;
603
604 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
605 let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?;
606 let first = pairs.next().unwrap();
607 match first.as_rule() {
608 Rule::identifier => {
609 let name = parse_identifier_name(first)?.to_owned();
610 Ok(AliasDeclaration::Symbol(name))
611 }
612 Rule::function_alias_declaration => {
613 let mut inner = first.into_inner();
614 let name_pair = inner.next().unwrap();
615 let params_pair = inner.next().unwrap();
616 let name = parse_identifier_name(name_pair)?.to_owned();
617 let params = parse_formal_parameters(params_pair)?
618 .into_iter()
619 .map(|s| s.to_owned())
620 .collect();
621 Ok(AliasDeclaration::Function(name, params))
622 }
623 r => panic!("unexpected alias declaration rule {r:?}"),
624 }
625 }
626}
627
628impl AliasDefinitionParser for TemplateAliasParser {
629 type Output<'i> = ExpressionKind<'i>;
630 type Error = TemplateParseError;
631
632 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
633 parse_template(source)
634 }
635}
636
637pub fn parse<'i>(
641 template_text: &'i str,
642 aliases_map: &'i TemplateAliasesMap,
643) -> TemplateParseResult<ExpressionNode<'i>> {
644 let node = parse_template(template_text)?;
645 dsl_util::expand_aliases(node, aliases_map)
646}
647
648pub fn expect_string_literal_with<'a, 'i, T>(
650 node: &'a ExpressionNode<'i>,
651 f: impl FnOnce(&'a str, pest::Span<'i>) -> TemplateParseResult<T>,
652) -> TemplateParseResult<T> {
653 match &node.kind {
654 ExpressionKind::String(s) => f(s, node.span),
655 ExpressionKind::Identifier(_)
656 | ExpressionKind::Boolean(_)
657 | ExpressionKind::Integer(_)
658 | ExpressionKind::Unary(..)
659 | ExpressionKind::Binary(..)
660 | ExpressionKind::Concat(_)
661 | ExpressionKind::FunctionCall(_)
662 | ExpressionKind::MethodCall(_)
663 | ExpressionKind::Lambda(_) => Err(TemplateParseError::expression(
664 "Expected string literal",
665 node.span,
666 )),
667 ExpressionKind::AliasExpanded(id, subst) => expect_string_literal_with(subst, f)
668 .map_err(|e| e.within_alias_expansion(*id, node.span)),
669 }
670}
671
672pub fn expect_lambda_with<'a, 'i, T>(
674 node: &'a ExpressionNode<'i>,
675 f: impl FnOnce(&'a LambdaNode<'i>, pest::Span<'i>) -> TemplateParseResult<T>,
676) -> TemplateParseResult<T> {
677 match &node.kind {
678 ExpressionKind::Lambda(lambda) => f(lambda, node.span),
679 ExpressionKind::Identifier(_)
680 | ExpressionKind::Boolean(_)
681 | ExpressionKind::Integer(_)
682 | ExpressionKind::String(_)
683 | ExpressionKind::Unary(..)
684 | ExpressionKind::Binary(..)
685 | ExpressionKind::Concat(_)
686 | ExpressionKind::FunctionCall(_)
687 | ExpressionKind::MethodCall(_) => Err(TemplateParseError::expression(
688 "Expected lambda expression",
689 node.span,
690 )),
691 ExpressionKind::AliasExpanded(id, subst) => {
692 expect_lambda_with(subst, f).map_err(|e| e.within_alias_expansion(*id, node.span))
693 }
694 }
695}
696
697pub fn lookup_function<'a, V>(
699 table: &'a HashMap<&str, V>,
700 function: &FunctionCallNode,
701) -> TemplateParseResult<&'a V> {
702 if let Some(value) = table.get(function.name) {
703 Ok(value)
704 } else {
705 let candidates = collect_similar(function.name, table.keys());
706 Err(TemplateParseError::with_span(
707 TemplateParseErrorKind::NoSuchFunction {
708 name: function.name.to_owned(),
709 candidates,
710 },
711 function.name_span,
712 ))
713 }
714}
715
716pub fn lookup_method<'a, V>(
718 type_name: impl Into<String>,
719 table: &'a HashMap<&str, V>,
720 function: &FunctionCallNode,
721) -> TemplateParseResult<&'a V> {
722 if let Some(value) = table.get(function.name) {
723 Ok(value)
724 } else {
725 let candidates = collect_similar(function.name, table.keys());
726 Err(TemplateParseError::with_span(
727 TemplateParseErrorKind::NoSuchMethod {
728 type_name: type_name.into(),
729 name: function.name.to_owned(),
730 candidates,
731 },
732 function.name_span,
733 ))
734 }
735}
736
737#[cfg(test)]
738mod tests {
739 use assert_matches::assert_matches;
740 use jj_lib::dsl_util::KeywordArgument;
741
742 use super::*;
743
744 #[derive(Debug)]
745 struct WithTemplateAliasesMap(TemplateAliasesMap);
746
747 impl WithTemplateAliasesMap {
748 fn parse<'i>(&'i self, template_text: &'i str) -> TemplateParseResult<ExpressionNode<'i>> {
749 parse(template_text, &self.0)
750 }
751
752 fn parse_normalized<'i>(&'i self, template_text: &'i str) -> ExpressionNode<'i> {
753 normalize_tree(self.parse(template_text).unwrap())
754 }
755 }
756
757 fn with_aliases(
758 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
759 ) -> WithTemplateAliasesMap {
760 let mut aliases_map = TemplateAliasesMap::new();
761 for (decl, defn) in aliases {
762 aliases_map.insert(decl, defn).unwrap();
763 }
764 WithTemplateAliasesMap(aliases_map)
765 }
766
767 fn parse_into_kind(template_text: &str) -> Result<ExpressionKind, TemplateParseErrorKind> {
768 parse_template(template_text)
769 .map(|node| node.kind)
770 .map_err(|err| err.kind)
771 }
772
773 fn parse_normalized(template_text: &str) -> ExpressionNode {
774 normalize_tree(parse_template(template_text).unwrap())
775 }
776
777 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
779 fn empty_span() -> pest::Span<'static> {
780 pest::Span::new("", 0, 0).unwrap()
781 }
782
783 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
784 nodes.into_iter().map(normalize_tree).collect()
785 }
786
787 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
788 FunctionCallNode {
789 name: function.name,
790 name_span: empty_span(),
791 args: normalize_list(function.args),
792 keyword_args: function
793 .keyword_args
794 .into_iter()
795 .map(|arg| KeywordArgument {
796 name: arg.name,
797 name_span: empty_span(),
798 value: normalize_tree(arg.value),
799 })
800 .collect(),
801 args_span: empty_span(),
802 }
803 }
804
805 let normalized_kind = match node.kind {
806 ExpressionKind::Identifier(_)
807 | ExpressionKind::Boolean(_)
808 | ExpressionKind::Integer(_)
809 | ExpressionKind::String(_) => node.kind,
810 ExpressionKind::Unary(op, arg) => {
811 let arg = Box::new(normalize_tree(*arg));
812 ExpressionKind::Unary(op, arg)
813 }
814 ExpressionKind::Binary(op, lhs, rhs) => {
815 let lhs = Box::new(normalize_tree(*lhs));
816 let rhs = Box::new(normalize_tree(*rhs));
817 ExpressionKind::Binary(op, lhs, rhs)
818 }
819 ExpressionKind::Concat(nodes) => ExpressionKind::Concat(normalize_list(nodes)),
820 ExpressionKind::FunctionCall(function) => {
821 let function = Box::new(normalize_function_call(*function));
822 ExpressionKind::FunctionCall(function)
823 }
824 ExpressionKind::MethodCall(method) => {
825 let method = Box::new(MethodCallNode {
826 object: normalize_tree(method.object),
827 function: normalize_function_call(method.function),
828 });
829 ExpressionKind::MethodCall(method)
830 }
831 ExpressionKind::Lambda(lambda) => {
832 let lambda = Box::new(LambdaNode {
833 params: lambda.params,
834 params_span: empty_span(),
835 body: normalize_tree(lambda.body),
836 });
837 ExpressionKind::Lambda(lambda)
838 }
839 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
840 };
841 ExpressionNode {
842 kind: normalized_kind,
843 span: empty_span(),
844 }
845 }
846
847 #[test]
848 fn test_parse_tree_eq() {
849 assert_eq!(
850 normalize_tree(parse_template(r#" commit_id.short(1 ) ++ description"#).unwrap()),
851 normalize_tree(parse_template(r#"commit_id.short( 1 )++(description)"#).unwrap()),
852 );
853 assert_ne!(
854 normalize_tree(parse_template(r#" "ab" "#).unwrap()),
855 normalize_tree(parse_template(r#" "a" ++ "b" "#).unwrap()),
856 );
857 assert_ne!(
858 normalize_tree(parse_template(r#" "foo" ++ "0" "#).unwrap()),
859 normalize_tree(parse_template(r#" "foo" ++ 0 "#).unwrap()),
860 );
861 }
862
863 #[test]
864 fn test_parse_whitespace() {
865 let ascii_whitespaces: String = ('\x00'..='\x7f')
866 .filter(char::is_ascii_whitespace)
867 .collect();
868 assert_eq!(
869 parse_normalized(&format!("{ascii_whitespaces}f()")),
870 parse_normalized("f()"),
871 );
872 }
873
874 #[test]
875 fn test_parse_operator_syntax() {
876 assert_eq!(parse_normalized("!!x"), parse_normalized("!(!x)"));
878 assert_eq!(
879 parse_normalized("!x.f() || !g()"),
880 parse_normalized("(!(x.f())) || (!(g()))"),
881 );
882 assert_eq!(
883 parse_normalized("!x.f() <= !x.f()"),
884 parse_normalized("((!(x.f())) <= (!(x.f())))"),
885 );
886 assert_eq!(
887 parse_normalized("!x.f() < !x.f() == !x.f() >= !x.f() || !g() != !g()"),
888 parse_normalized(
889 "((!(x.f()) < (!(x.f()))) == ((!(x.f())) >= (!(x.f())))) || ((!(g())) != (!(g())))"
890 ),
891 );
892 assert_eq!(
893 parse_normalized("x.f() || y == y || z"),
894 parse_normalized("((x.f()) || (y == y)) || z"),
895 );
896 assert_eq!(
897 parse_normalized("x || y == y && z.h() == z"),
898 parse_normalized("x || ((y == y) && ((z.h()) == z))"),
899 );
900 assert_eq!(
901 parse_normalized("x == y || y != z && !z"),
902 parse_normalized("(x == y) || ((y != z) && (!z))"),
903 );
904
905 assert_eq!(
908 parse_normalized(r"x && y ++ z"),
909 parse_normalized(r"(x && y) ++ z"),
910 );
911 assert_eq!(
912 parse_normalized(r"x ++ y || z"),
913 parse_normalized(r"x ++ (y || z)"),
914 );
915 assert_eq!(
916 parse_normalized(r"x == y ++ z"),
917 parse_normalized(r"(x == y) ++ z"),
918 );
919 assert_eq!(
920 parse_normalized(r"x != y ++ z"),
921 parse_normalized(r"(x != y) ++ z"),
922 );
923
924 assert_eq!(parse_template(" ! x ").unwrap().span.as_str(), "! x");
926 assert_eq!(parse_template(" x ||y ").unwrap().span.as_str(), "x ||y");
927 }
928
929 #[test]
930 fn test_function_call_syntax() {
931 assert!(parse_template(r#" "".first_line() "#).is_ok());
933 assert!(parse_template(r#" "".first_line(,) "#).is_err());
934
935 assert!(parse_template(r#" "".contains("") "#).is_ok());
937 assert!(parse_template(r#" "".contains("",) "#).is_ok());
938 assert!(parse_template(r#" "".contains("" , ) "#).is_ok());
939 assert!(parse_template(r#" "".contains(,"") "#).is_err());
940 assert!(parse_template(r#" "".contains("",,) "#).is_err());
941 assert!(parse_template(r#" "".contains("" , , ) "#).is_err());
942 assert!(parse_template(r#" label("","") "#).is_ok());
943 assert!(parse_template(r#" label("","",) "#).is_ok());
944 assert!(parse_template(r#" label("",,"") "#).is_err());
945
946 assert!(parse_template("f(foo = bar)").is_ok());
948 assert!(parse_template("f( foo=bar )").is_ok());
949 assert!(parse_template("x.f(foo, bar=0, baz=1)").is_ok());
950
951 assert!(parse_template("false()").is_err());
953 assert!(parse_template("f(false=0)").is_err());
955 assert!(parse_template("f(false)").is_ok());
957 }
958
959 #[test]
960 fn test_method_call_syntax() {
961 assert_eq!(
962 parse_normalized("x.f().g()"),
963 parse_normalized("(x.f()).g()"),
964 );
965
966 assert_eq!(parse_template(" x.f() ").unwrap().span.as_str(), "x.f()");
968 assert_eq!(
969 parse_template(" x.f().g() ").unwrap().span.as_str(),
970 "x.f().g()",
971 );
972 }
973
974 #[test]
975 fn test_lambda_syntax() {
976 fn unwrap_lambda(node: ExpressionNode<'_>) -> Box<LambdaNode<'_>> {
977 match node.kind {
978 ExpressionKind::Lambda(lambda) => lambda,
979 _ => panic!("unexpected expression: {node:?}"),
980 }
981 }
982
983 let lambda = unwrap_lambda(parse_template("|| a").unwrap());
984 assert_eq!(lambda.params.len(), 0);
985 assert_eq!(lambda.body.kind, ExpressionKind::Identifier("a"));
986 let lambda = unwrap_lambda(parse_template("|foo| a").unwrap());
987 assert_eq!(lambda.params.len(), 1);
988 let lambda = unwrap_lambda(parse_template("|foo, b| a").unwrap());
989 assert_eq!(lambda.params.len(), 2);
990
991 assert!(parse_template("||").is_err());
993
994 assert_eq!(
996 parse_normalized("|| x ++ y"),
997 parse_normalized("|| (x ++ y)"),
998 );
999 assert_eq!(
1000 parse_normalized("f( || x, || y)"),
1001 parse_normalized("f((|| x), (|| y))"),
1002 );
1003 assert_eq!(
1004 parse_normalized("|| x ++ || y"),
1005 parse_normalized("|| (x ++ (|| y))"),
1006 );
1007
1008 assert_eq!(parse_normalized("x||||y"), parse_normalized("x || (|| y)"));
1010 assert_eq!(parse_normalized("||||x"), parse_normalized("|| (|| x)"));
1011
1012 assert!(parse_template("|,| a").is_err());
1014 assert!(parse_template("|x,| a").is_ok());
1015 assert!(parse_template("|x , | a").is_ok());
1016 assert!(parse_template("|,x| a").is_err());
1017 assert!(parse_template("| x,y,| a").is_ok());
1018 assert!(parse_template("|x,,y| a").is_err());
1019
1020 assert_eq!(
1022 parse_template("|x, x| a").unwrap_err().kind,
1023 TemplateParseErrorKind::RedefinedFunctionParameter
1024 );
1025
1026 assert!(parse_template("|false| a").is_err());
1028 }
1029
1030 #[test]
1031 fn test_keyword_literal() {
1032 assert_eq!(parse_into_kind("false"), Ok(ExpressionKind::Boolean(false)));
1033 assert_eq!(parse_into_kind("(true)"), Ok(ExpressionKind::Boolean(true)));
1034 assert_eq!(
1036 parse_into_kind("False"),
1037 Ok(ExpressionKind::Identifier("False")),
1038 );
1039 assert_eq!(
1040 parse_into_kind("tRue"),
1041 Ok(ExpressionKind::Identifier("tRue")),
1042 );
1043 }
1044
1045 #[test]
1046 fn test_string_literal() {
1047 assert_eq!(
1049 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1050 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned())),
1051 );
1052
1053 assert_eq!(
1055 parse_into_kind(r#" "\y" "#),
1056 Err(TemplateParseErrorKind::SyntaxError),
1057 );
1058
1059 assert_eq!(
1061 parse_into_kind(r#" '' "#),
1062 Ok(ExpressionKind::String("".to_owned())),
1063 );
1064 assert_eq!(
1065 parse_into_kind(r#" 'a\n' "#),
1066 Ok(ExpressionKind::String(r"a\n".to_owned())),
1067 );
1068 assert_eq!(
1069 parse_into_kind(r#" '\' "#),
1070 Ok(ExpressionKind::String(r"\".to_owned())),
1071 );
1072 assert_eq!(
1073 parse_into_kind(r#" '"' "#),
1074 Ok(ExpressionKind::String(r#"""#.to_owned())),
1075 );
1076
1077 assert_eq!(
1079 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1080 Ok(ExpressionKind::String("aeiou".to_owned())),
1081 );
1082 assert_eq!(
1083 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1084 Ok(ExpressionKind::String("àèìðù".to_owned())),
1085 );
1086 assert_eq!(
1087 parse_into_kind(r#""\x""#),
1088 Err(TemplateParseErrorKind::SyntaxError),
1089 );
1090 assert_eq!(
1091 parse_into_kind(r#""\xf""#),
1092 Err(TemplateParseErrorKind::SyntaxError),
1093 );
1094 assert_eq!(
1095 parse_into_kind(r#""\xgg""#),
1096 Err(TemplateParseErrorKind::SyntaxError),
1097 );
1098 }
1099
1100 #[test]
1101 fn test_integer_literal() {
1102 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Integer(0)));
1103 assert_eq!(parse_into_kind("(42)"), Ok(ExpressionKind::Integer(42)));
1104 assert_eq!(
1105 parse_into_kind("00"),
1106 Err(TemplateParseErrorKind::SyntaxError),
1107 );
1108
1109 assert_eq!(
1110 parse_into_kind(&format!("{}", i64::MAX)),
1111 Ok(ExpressionKind::Integer(i64::MAX)),
1112 );
1113 assert_matches!(
1114 parse_into_kind(&format!("{}", (i64::MAX as u64) + 1)),
1115 Err(TemplateParseErrorKind::Expression(_))
1116 );
1117 }
1118
1119 #[test]
1120 fn test_parse_alias_decl() {
1121 let mut aliases_map = TemplateAliasesMap::new();
1122 aliases_map.insert("sym", r#""is symbol""#).unwrap();
1123 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1124 aliases_map
1125 .insert("func(a, b)", r#""is function 2""#)
1126 .unwrap();
1127 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1128 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1129
1130 let (id, defn) = aliases_map.get_symbol("sym").unwrap();
1131 assert_eq!(id, AliasId::Symbol("sym"));
1132 assert_eq!(defn, r#""is symbol""#);
1133
1134 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1135 assert_eq!(id, AliasId::Function("func", &[]));
1136 assert!(params.is_empty());
1137 assert_eq!(defn, r#""is function 0""#);
1138
1139 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1140 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1141 assert_eq!(params, ["b"]);
1142 assert_eq!(defn, r#""is function b""#);
1143
1144 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1145 assert_eq!(
1146 id,
1147 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1148 );
1149 assert_eq!(params, ["a", "b"]);
1150 assert_eq!(defn, r#""is function 2""#);
1151
1152 assert!(aliases_map.get_function("func", 3).is_none());
1153
1154 assert_eq!(
1156 aliases_map.insert("f(a, a)", r#""""#).unwrap_err().kind,
1157 TemplateParseErrorKind::RedefinedFunctionParameter
1158 );
1159
1160 assert!(aliases_map.insert("false", r#"""#).is_err());
1162 assert!(aliases_map.insert("true()", r#"""#).is_err());
1163 assert!(aliases_map.insert("f(false)", r#"""#).is_err());
1164
1165 assert!(aliases_map.insert("f(,)", r#"""#).is_err());
1167 assert!(aliases_map.insert("g(a,)", r#"""#).is_ok());
1169 assert!(aliases_map.insert("h(a , )", r#"""#).is_ok());
1170 assert!(aliases_map.insert("i(,a)", r#"""#).is_err());
1171 assert!(aliases_map.insert("j(a,,)", r#"""#).is_err());
1172 assert!(aliases_map.insert("k(a , , )", r#"""#).is_err());
1173 assert!(aliases_map.insert("l(a,b,)", r#"""#).is_ok());
1174 assert!(aliases_map.insert("m(a,,b)", r#"""#).is_err());
1175 }
1176
1177 #[test]
1178 fn test_expand_symbol_alias() {
1179 assert_eq!(
1180 with_aliases([("AB", "a ++ b")]).parse_normalized("AB ++ c"),
1181 parse_normalized("(a ++ b) ++ c"),
1182 );
1183 assert_eq!(
1184 with_aliases([("AB", "a ++ b")]).parse_normalized("if(AB, label(c, AB))"),
1185 parse_normalized("if((a ++ b), label(c, (a ++ b)))"),
1186 );
1187
1188 assert_eq!(
1190 with_aliases([("A", "BC"), ("BC", "b ++ C"), ("C", "c")]).parse_normalized("A"),
1191 parse_normalized("b ++ c"),
1192 );
1193
1194 assert_eq!(
1196 with_aliases([("AB", "a || b")]).parse_normalized("AB ++ c"),
1197 parse_normalized("(a || b) ++ c"),
1198 );
1199
1200 assert_eq!(
1202 with_aliases([("A", "a"), ("B", "b")]).parse_normalized("A || !B"),
1203 parse_normalized("a || !b"),
1204 );
1205
1206 assert_eq!(
1208 with_aliases([("A", "a")]).parse_normalized("A.f()"),
1209 parse_normalized("a.f()"),
1210 );
1211 assert_eq!(
1212 with_aliases([("A", "a"), ("B", "b")]).parse_normalized("x.f(A, B)"),
1213 parse_normalized("x.f(a, b)"),
1214 );
1215
1216 assert_eq!(
1218 with_aliases([("A", "a")]).parse_normalized("|| A"),
1219 parse_normalized("|| a"),
1220 );
1221 assert_eq!(
1225 with_aliases([("A", "a ++ b")]).parse_normalized("|A| A"),
1226 parse_normalized("|A| (a ++ b)"),
1227 );
1228
1229 assert_eq!(
1231 with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1232 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1233 );
1234 assert_eq!(
1235 with_aliases([("A", "B"), ("B", "b ++ C"), ("C", "c ++ B")])
1236 .parse("A")
1237 .unwrap_err()
1238 .kind,
1239 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1240 );
1241
1242 assert_eq!(
1244 with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1245 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1246 );
1247 }
1248
1249 #[test]
1250 fn test_expand_function_alias() {
1251 assert_eq!(
1252 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1253 parse_normalized("a"),
1254 );
1255 assert_eq!(
1256 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1257 parse_normalized("a"),
1258 );
1259 assert_eq!(
1260 with_aliases([("F( x, y )", "x ++ y")]).parse_normalized("F(a, b)"),
1261 parse_normalized("a ++ b"),
1262 );
1263
1264 assert_eq!(
1266 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x ++ y")]).parse_normalized("F(a)"),
1267 parse_normalized("a ++ b")
1268 );
1269
1270 assert_eq!(
1272 with_aliases([("F(x,y)", "if(x, y)")]).parse_normalized("F(a ++ y, b ++ x)"),
1273 parse_normalized("if((a ++ y), (b ++ x))"),
1274 );
1275 assert_eq!(
1277 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(a)"),
1278 parse_normalized("if((x ++ a), y)"),
1279 );
1280 assert_eq!(
1282 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(G(a))"),
1283 parse_normalized("if((x ++ (x ++ a)), y)"),
1284 );
1285
1286 assert_eq!(
1288 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a) ++ X"),
1289 parse_normalized("a ++ x"),
1290 );
1291
1292 assert_eq!(
1294 with_aliases([("F(x)", "x ++ A"), ("A", "x")]).parse_normalized("F(a)"),
1295 parse_normalized("a ++ x"),
1296 );
1297
1298 assert_eq!(
1300 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1301 parse_normalized("a"),
1302 );
1303
1304 assert_eq!(
1306 with_aliases([("F()", "f()")]).parse_normalized("x.F()"),
1307 parse_normalized("x.F()"),
1308 );
1309
1310 assert_eq!(
1313 with_aliases([("F(x)", "|x| x")]).parse_normalized("F(a ++ b)"),
1314 parse_normalized("|x| (a ++ b)"),
1315 );
1316
1317 assert_matches!(
1319 with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1320 TemplateParseErrorKind::InvalidArguments { .. }
1321 );
1322 assert_matches!(
1323 with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1324 TemplateParseErrorKind::InvalidArguments { .. }
1325 );
1326 assert_matches!(
1327 with_aliases([("F(x,y)", "x ++ y")])
1328 .parse("F(a,b,c)")
1329 .unwrap_err()
1330 .kind,
1331 TemplateParseErrorKind::InvalidArguments { .. }
1332 );
1333
1334 assert_eq!(
1336 with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1337 .parse("F(a)")
1338 .unwrap_err()
1339 .kind,
1340 TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned()),
1341 );
1342 assert_eq!(
1343 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1344 .parse("F(a)")
1345 .unwrap_err()
1346 .kind,
1347 TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned())
1348 );
1349 }
1350}