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::add_op => Some("+"),
84 Rule::sub_op => Some("-"),
85 Rule::mul_op => Some("*"),
86 Rule::div_op => Some("/"),
87 Rule::rem_op => Some("%"),
88 Rule::logical_not_op => Some("!"),
89 Rule::negate_op => Some("-"),
90 Rule::prefix_ops => None,
91 Rule::infix_ops => None,
92 Rule::function => None,
93 Rule::keyword_argument => None,
94 Rule::argument => None,
95 Rule::function_arguments => None,
96 Rule::lambda => None,
97 Rule::formal_parameters => None,
98 Rule::primary => None,
99 Rule::term => None,
100 Rule::expression => None,
101 Rule::template => None,
102 Rule::program => None,
103 Rule::function_alias_declaration => None,
104 Rule::alias_declaration => None,
105 }
106 }
107}
108
109pub type TemplateDiagnostics = Diagnostics<TemplateParseError>;
111
112pub type TemplateParseResult<T> = Result<T, TemplateParseError>;
113
114#[derive(Debug, Error)]
115#[error("{pest_error}")]
116pub struct TemplateParseError {
117 kind: TemplateParseErrorKind,
118 pest_error: Box<pest::error::Error<Rule>>,
119 source: Option<Box<dyn error::Error + Send + Sync>>,
120}
121
122#[derive(Clone, Debug, Eq, Error, PartialEq)]
123pub enum TemplateParseErrorKind {
124 #[error("Syntax error")]
125 SyntaxError,
126 #[error("Keyword `{name}` doesn't exist")]
127 NoSuchKeyword {
128 name: String,
129 candidates: Vec<String>,
130 },
131 #[error("Function `{name}` doesn't exist")]
132 NoSuchFunction {
133 name: String,
134 candidates: Vec<String>,
135 },
136 #[error("Method `{name}` doesn't exist for type `{type_name}`")]
137 NoSuchMethod {
138 type_name: String,
139 name: String,
140 candidates: Vec<String>,
141 },
142 #[error("Function `{name}`: {message}")]
143 InvalidArguments { name: String, message: String },
144 #[error("Redefinition of function parameter")]
145 RedefinedFunctionParameter,
146 #[error("{0}")]
147 Expression(String),
148 #[error("In alias `{0}`")]
149 InAliasExpansion(String),
150 #[error("In function parameter `{0}`")]
151 InParameterExpansion(String),
152 #[error("Alias `{0}` expanded recursively")]
153 RecursiveAlias(String),
154}
155
156impl TemplateParseError {
157 pub fn with_span(kind: TemplateParseErrorKind, span: pest::Span<'_>) -> Self {
158 let message = kind.to_string();
159 let pest_error = Box::new(pest::error::Error::new_from_span(
160 pest::error::ErrorVariant::CustomError { message },
161 span,
162 ));
163 TemplateParseError {
164 kind,
165 pest_error,
166 source: None,
167 }
168 }
169
170 pub fn with_source(mut self, source: impl Into<Box<dyn error::Error + Send + Sync>>) -> Self {
171 self.source = Some(source.into());
172 self
173 }
174
175 pub fn expected_type(expected: &str, actual: &str, span: pest::Span<'_>) -> Self {
176 let message =
177 format!("Expected expression of type `{expected}`, but actual type is `{actual}`");
178 TemplateParseError::expression(message, span)
179 }
180
181 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
183 TemplateParseError::with_span(TemplateParseErrorKind::Expression(message.into()), span)
184 }
185
186 pub fn extend_keyword_candidates<I>(mut self, other_keywords: I) -> Self
189 where
190 I: IntoIterator,
191 I::Item: AsRef<str>,
192 {
193 if let TemplateParseErrorKind::NoSuchKeyword { name, candidates } = &mut self.kind {
194 let other_candidates = collect_similar(name, other_keywords);
195 *candidates = itertools::merge(mem::take(candidates), other_candidates)
196 .dedup()
197 .collect();
198 }
199 self
200 }
201
202 pub fn extend_function_candidates<I>(mut self, other_functions: I) -> Self
205 where
206 I: IntoIterator,
207 I::Item: AsRef<str>,
208 {
209 if let TemplateParseErrorKind::NoSuchFunction { name, candidates } = &mut self.kind {
210 let other_candidates = collect_similar(name, other_functions);
211 *candidates = itertools::merge(mem::take(candidates), other_candidates)
212 .dedup()
213 .collect();
214 }
215 self
216 }
217
218 pub fn extend_alias_candidates(self, aliases_map: &TemplateAliasesMap) -> Self {
220 self.extend_keyword_candidates(aliases_map.symbol_names())
221 .extend_function_candidates(aliases_map.function_names())
222 }
223
224 pub fn kind(&self) -> &TemplateParseErrorKind {
225 &self.kind
226 }
227
228 pub fn origin(&self) -> Option<&Self> {
230 self.source.as_ref().and_then(|e| e.downcast_ref())
231 }
232}
233
234impl AliasExpandError for TemplateParseError {
235 fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
236 err.into()
237 }
238
239 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
240 Self::with_span(TemplateParseErrorKind::RecursiveAlias(id.to_string()), span)
241 }
242
243 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
244 let kind = match id {
245 AliasId::Symbol(_) | AliasId::Function(..) => {
246 TemplateParseErrorKind::InAliasExpansion(id.to_string())
247 }
248 AliasId::Parameter(_) => TemplateParseErrorKind::InParameterExpansion(id.to_string()),
249 };
250 Self::with_span(kind, span).with_source(self)
251 }
252}
253
254impl From<pest::error::Error<Rule>> for TemplateParseError {
255 fn from(err: pest::error::Error<Rule>) -> Self {
256 TemplateParseError {
257 kind: TemplateParseErrorKind::SyntaxError,
258 pest_error: Box::new(rename_rules_in_pest_error(err)),
259 source: None,
260 }
261 }
262}
263
264impl From<InvalidArguments<'_>> for TemplateParseError {
265 fn from(err: InvalidArguments<'_>) -> Self {
266 let kind = TemplateParseErrorKind::InvalidArguments {
267 name: err.name.to_owned(),
268 message: err.message,
269 };
270 Self::with_span(kind, err.span)
271 }
272}
273
274fn rename_rules_in_pest_error(err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
275 err.renamed_rules(|rule| {
276 rule.to_symbol()
277 .map(|sym| format!("`{sym}`"))
278 .unwrap_or_else(|| format!("<{rule:?}>"))
279 })
280}
281
282#[derive(Clone, Debug, PartialEq)]
283pub enum ExpressionKind<'i> {
284 Identifier(&'i str),
285 Boolean(bool),
286 Integer(i64),
287 String(String),
288 Unary(UnaryOp, Box<ExpressionNode<'i>>),
289 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
290 Concat(Vec<ExpressionNode<'i>>),
291 FunctionCall(Box<FunctionCallNode<'i>>),
292 MethodCall(Box<MethodCallNode<'i>>),
293 Lambda(Box<LambdaNode<'i>>),
294 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
296}
297
298impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
299 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
300 where
301 F: ExpressionFolder<'i, Self> + ?Sized,
302 {
303 match self {
304 ExpressionKind::Identifier(name) => folder.fold_identifier(name, span),
305 ExpressionKind::Boolean(_) | ExpressionKind::Integer(_) | ExpressionKind::String(_) => {
306 Ok(self)
307 }
308 ExpressionKind::Unary(op, arg) => {
309 let arg = Box::new(folder.fold_expression(*arg)?);
310 Ok(ExpressionKind::Unary(op, arg))
311 }
312 ExpressionKind::Binary(op, lhs, rhs) => {
313 let lhs = Box::new(folder.fold_expression(*lhs)?);
314 let rhs = Box::new(folder.fold_expression(*rhs)?);
315 Ok(ExpressionKind::Binary(op, lhs, rhs))
316 }
317 ExpressionKind::Concat(nodes) => Ok(ExpressionKind::Concat(
318 dsl_util::fold_expression_nodes(folder, nodes)?,
319 )),
320 ExpressionKind::FunctionCall(function) => folder.fold_function_call(function, span),
321 ExpressionKind::MethodCall(method) => {
322 let method = Box::new(MethodCallNode {
324 object: folder.fold_expression(method.object)?,
325 function: dsl_util::fold_function_call_args(folder, method.function)?,
326 });
327 Ok(ExpressionKind::MethodCall(method))
328 }
329 ExpressionKind::Lambda(lambda) => {
330 let lambda = Box::new(LambdaNode {
331 params: lambda.params,
332 params_span: lambda.params_span,
333 body: folder.fold_expression(lambda.body)?,
334 });
335 Ok(ExpressionKind::Lambda(lambda))
336 }
337 ExpressionKind::AliasExpanded(id, subst) => {
338 let subst = Box::new(folder.fold_expression(*subst)?);
339 Ok(ExpressionKind::AliasExpanded(id, subst))
340 }
341 }
342 }
343}
344
345impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
346 fn identifier(name: &'i str) -> Self {
347 ExpressionKind::Identifier(name)
348 }
349
350 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
351 ExpressionKind::FunctionCall(function)
352 }
353
354 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
355 ExpressionKind::AliasExpanded(id, subst)
356 }
357}
358
359#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
360pub enum UnaryOp {
361 LogicalNot,
363 Negate,
365}
366
367#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
368pub enum BinaryOp {
369 LogicalOr,
371 LogicalAnd,
373 Eq,
375 Ne,
377 Ge,
379 Gt,
381 Le,
383 Lt,
385 Add,
387 Sub,
389 Mul,
391 Div,
393 Rem,
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::infix(Rule::add_op, Assoc::Left) | Op::infix(Rule::sub_op, Assoc::Left))
531 .op(Op::infix(Rule::mul_op, Assoc::Left)
532 | Op::infix(Rule::div_op, Assoc::Left)
533 | Op::infix(Rule::rem_op, Assoc::Left))
534 .op(Op::prefix(Rule::logical_not_op) | Op::prefix(Rule::negate_op))
535 });
536 PRATT
537 .map_primary(parse_term_node)
538 .map_prefix(|op, rhs| {
539 let op_kind = match op.as_rule() {
540 Rule::logical_not_op => UnaryOp::LogicalNot,
541 Rule::negate_op => UnaryOp::Negate,
542 r => panic!("unexpected prefix operator rule {r:?}"),
543 };
544 let rhs = Box::new(rhs?);
545 let span = op.as_span().start_pos().span(&rhs.span.end_pos());
546 let expr = ExpressionKind::Unary(op_kind, rhs);
547 Ok(ExpressionNode::new(expr, span))
548 })
549 .map_infix(|lhs, op, rhs| {
550 let op_kind = match op.as_rule() {
551 Rule::logical_or_op => BinaryOp::LogicalOr,
552 Rule::logical_and_op => BinaryOp::LogicalAnd,
553 Rule::eq_op => BinaryOp::Eq,
554 Rule::ne_op => BinaryOp::Ne,
555 Rule::ge_op => BinaryOp::Ge,
556 Rule::gt_op => BinaryOp::Gt,
557 Rule::le_op => BinaryOp::Le,
558 Rule::lt_op => BinaryOp::Lt,
559 Rule::add_op => BinaryOp::Add,
560 Rule::sub_op => BinaryOp::Sub,
561 Rule::mul_op => BinaryOp::Mul,
562 Rule::div_op => BinaryOp::Div,
563 Rule::rem_op => BinaryOp::Rem,
564 r => panic!("unexpected infix operator rule {r:?}"),
565 };
566 let lhs = Box::new(lhs?);
567 let rhs = Box::new(rhs?);
568 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
569 let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
570 Ok(ExpressionNode::new(expr, span))
571 })
572 .parse(pair.into_inner())
573}
574
575fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
576 assert_eq!(pair.as_rule(), Rule::template);
577 let span = pair.as_span();
578 let inner = pair.into_inner();
579 let mut nodes: Vec<_> = inner
580 .filter_map(|pair| match pair.as_rule() {
581 Rule::concat_op => None,
582 Rule::expression => Some(parse_expression_node(pair)),
583 r => panic!("unexpected template item rule {r:?}"),
584 })
585 .try_collect()?;
586 if nodes.len() == 1 {
587 Ok(nodes.pop().unwrap())
588 } else {
589 Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span))
590 }
591}
592
593pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode<'_>> {
595 let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?;
596 let first_pair = pairs.next().unwrap();
597 if first_pair.as_rule() == Rule::EOI {
598 let span = first_pair.as_span();
599 Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span))
600 } else {
601 parse_template_node(first_pair)
602 }
603}
604
605pub type TemplateAliasesMap = AliasesMap<TemplateAliasParser, String>;
606
607#[derive(Clone, Debug, Default)]
608pub struct TemplateAliasParser;
609
610impl AliasDeclarationParser for TemplateAliasParser {
611 type Error = TemplateParseError;
612
613 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
614 let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?;
615 let first = pairs.next().unwrap();
616 match first.as_rule() {
617 Rule::identifier => {
618 let name = parse_identifier_name(first)?.to_owned();
619 Ok(AliasDeclaration::Symbol(name))
620 }
621 Rule::function_alias_declaration => {
622 let mut inner = first.into_inner();
623 let name_pair = inner.next().unwrap();
624 let params_pair = inner.next().unwrap();
625 let name = parse_identifier_name(name_pair)?.to_owned();
626 let params = parse_formal_parameters(params_pair)?
627 .into_iter()
628 .map(|s| s.to_owned())
629 .collect();
630 Ok(AliasDeclaration::Function(name, params))
631 }
632 r => panic!("unexpected alias declaration rule {r:?}"),
633 }
634 }
635}
636
637impl AliasDefinitionParser for TemplateAliasParser {
638 type Output<'i> = ExpressionKind<'i>;
639 type Error = TemplateParseError;
640
641 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
642 parse_template(source)
643 }
644}
645
646pub fn parse<'i>(
650 template_text: &'i str,
651 aliases_map: &'i TemplateAliasesMap,
652) -> TemplateParseResult<ExpressionNode<'i>> {
653 let node = parse_template(template_text)?;
654 dsl_util::expand_aliases(node, aliases_map)
655}
656
657pub fn expect_string_literal<'a>(node: &'a ExpressionNode<'_>) -> TemplateParseResult<&'a str> {
659 catch_aliases_no_diagnostics(node, |node| match &node.kind {
660 ExpressionKind::String(s) => Ok(s.as_str()),
661 _ => Err(TemplateParseError::expression(
662 "Expected string literal",
663 node.span,
664 )),
665 })
666}
667
668pub fn expect_lambda<'a, 'i>(
670 node: &'a ExpressionNode<'i>,
671) -> TemplateParseResult<&'a LambdaNode<'i>> {
672 catch_aliases_no_diagnostics(node, |node| match &node.kind {
673 ExpressionKind::Lambda(lambda) => Ok(lambda.as_ref()),
674 _ => Err(TemplateParseError::expression(
675 "Expected lambda expression",
676 node.span,
677 )),
678 })
679}
680
681pub fn catch_aliases<'a, 'i, T>(
684 diagnostics: &mut TemplateDiagnostics,
685 node: &'a ExpressionNode<'i>,
686 f: impl FnOnce(&mut TemplateDiagnostics, &'a ExpressionNode<'i>) -> TemplateParseResult<T>,
687) -> TemplateParseResult<T> {
688 let (node, stack) = skip_aliases(node);
689 if stack.is_empty() {
690 f(diagnostics, node)
691 } else {
692 let mut inner_diagnostics = TemplateDiagnostics::new();
693 let result = f(&mut inner_diagnostics, node);
694 diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
695 result.map_err(|err| attach_aliases_err(err, &stack))
696 }
697}
698
699fn catch_aliases_no_diagnostics<'a, 'i, T>(
700 node: &'a ExpressionNode<'i>,
701 f: impl FnOnce(&'a ExpressionNode<'i>) -> TemplateParseResult<T>,
702) -> TemplateParseResult<T> {
703 let (node, stack) = skip_aliases(node);
704 f(node).map_err(|err| attach_aliases_err(err, &stack))
705}
706
707fn skip_aliases<'a, 'i>(
708 mut node: &'a ExpressionNode<'i>,
709) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
710 let mut stack = Vec::new();
711 while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
712 stack.push((*id, node.span));
713 node = subst;
714 }
715 (node, stack)
716}
717
718fn attach_aliases_err(
719 err: TemplateParseError,
720 stack: &[(AliasId<'_>, pest::Span<'_>)],
721) -> TemplateParseError {
722 stack
723 .iter()
724 .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
725}
726
727pub fn lookup_function<'a, V>(
729 table: &'a HashMap<&str, V>,
730 function: &FunctionCallNode,
731) -> TemplateParseResult<&'a V> {
732 if let Some(value) = table.get(function.name) {
733 Ok(value)
734 } else {
735 let candidates = collect_similar(function.name, table.keys());
736 Err(TemplateParseError::with_span(
737 TemplateParseErrorKind::NoSuchFunction {
738 name: function.name.to_owned(),
739 candidates,
740 },
741 function.name_span,
742 ))
743 }
744}
745
746pub fn lookup_method<'a, V>(
748 type_name: impl Into<String>,
749 table: &'a HashMap<&str, V>,
750 function: &FunctionCallNode,
751) -> TemplateParseResult<&'a V> {
752 if let Some(value) = table.get(function.name) {
753 Ok(value)
754 } else {
755 let candidates = collect_similar(function.name, table.keys());
756 Err(TemplateParseError::with_span(
757 TemplateParseErrorKind::NoSuchMethod {
758 type_name: type_name.into(),
759 name: function.name.to_owned(),
760 candidates,
761 },
762 function.name_span,
763 ))
764 }
765}
766
767#[cfg(test)]
768mod tests {
769 use assert_matches::assert_matches;
770 use jj_lib::dsl_util::KeywordArgument;
771
772 use super::*;
773
774 #[derive(Debug)]
775 struct WithTemplateAliasesMap(TemplateAliasesMap);
776
777 impl WithTemplateAliasesMap {
778 fn parse<'i>(&'i self, template_text: &'i str) -> TemplateParseResult<ExpressionNode<'i>> {
779 parse(template_text, &self.0)
780 }
781
782 fn parse_normalized<'i>(&'i self, template_text: &'i str) -> ExpressionNode<'i> {
783 normalize_tree(self.parse(template_text).unwrap())
784 }
785 }
786
787 fn with_aliases(
788 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
789 ) -> WithTemplateAliasesMap {
790 let mut aliases_map = TemplateAliasesMap::new();
791 for (decl, defn) in aliases {
792 aliases_map.insert(decl, defn).unwrap();
793 }
794 WithTemplateAliasesMap(aliases_map)
795 }
796
797 fn parse_into_kind(template_text: &str) -> Result<ExpressionKind<'_>, TemplateParseErrorKind> {
798 parse_template(template_text)
799 .map(|node| node.kind)
800 .map_err(|err| err.kind)
801 }
802
803 fn parse_normalized(template_text: &str) -> ExpressionNode<'_> {
804 normalize_tree(parse_template(template_text).unwrap())
805 }
806
807 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
809 fn empty_span() -> pest::Span<'static> {
810 pest::Span::new("", 0, 0).unwrap()
811 }
812
813 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
814 nodes.into_iter().map(normalize_tree).collect()
815 }
816
817 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
818 FunctionCallNode {
819 name: function.name,
820 name_span: empty_span(),
821 args: normalize_list(function.args),
822 keyword_args: function
823 .keyword_args
824 .into_iter()
825 .map(|arg| KeywordArgument {
826 name: arg.name,
827 name_span: empty_span(),
828 value: normalize_tree(arg.value),
829 })
830 .collect(),
831 args_span: empty_span(),
832 }
833 }
834
835 let normalized_kind = match node.kind {
836 ExpressionKind::Identifier(_)
837 | ExpressionKind::Boolean(_)
838 | ExpressionKind::Integer(_)
839 | ExpressionKind::String(_) => node.kind,
840 ExpressionKind::Unary(op, arg) => {
841 let arg = Box::new(normalize_tree(*arg));
842 ExpressionKind::Unary(op, arg)
843 }
844 ExpressionKind::Binary(op, lhs, rhs) => {
845 let lhs = Box::new(normalize_tree(*lhs));
846 let rhs = Box::new(normalize_tree(*rhs));
847 ExpressionKind::Binary(op, lhs, rhs)
848 }
849 ExpressionKind::Concat(nodes) => ExpressionKind::Concat(normalize_list(nodes)),
850 ExpressionKind::FunctionCall(function) => {
851 let function = Box::new(normalize_function_call(*function));
852 ExpressionKind::FunctionCall(function)
853 }
854 ExpressionKind::MethodCall(method) => {
855 let method = Box::new(MethodCallNode {
856 object: normalize_tree(method.object),
857 function: normalize_function_call(method.function),
858 });
859 ExpressionKind::MethodCall(method)
860 }
861 ExpressionKind::Lambda(lambda) => {
862 let lambda = Box::new(LambdaNode {
863 params: lambda.params,
864 params_span: empty_span(),
865 body: normalize_tree(lambda.body),
866 });
867 ExpressionKind::Lambda(lambda)
868 }
869 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
870 };
871 ExpressionNode {
872 kind: normalized_kind,
873 span: empty_span(),
874 }
875 }
876
877 #[test]
878 fn test_parse_tree_eq() {
879 assert_eq!(
880 normalize_tree(parse_template(r#" commit_id.short(1 ) ++ description"#).unwrap()),
881 normalize_tree(parse_template(r#"commit_id.short( 1 )++(description)"#).unwrap()),
882 );
883 assert_ne!(
884 normalize_tree(parse_template(r#" "ab" "#).unwrap()),
885 normalize_tree(parse_template(r#" "a" ++ "b" "#).unwrap()),
886 );
887 assert_ne!(
888 normalize_tree(parse_template(r#" "foo" ++ "0" "#).unwrap()),
889 normalize_tree(parse_template(r#" "foo" ++ 0 "#).unwrap()),
890 );
891 }
892
893 #[test]
894 fn test_parse_whitespace() {
895 let ascii_whitespaces: String = ('\x00'..='\x7f')
896 .filter(char::is_ascii_whitespace)
897 .collect();
898 assert_eq!(
899 parse_normalized(&format!("{ascii_whitespaces}f()")),
900 parse_normalized("f()"),
901 );
902 }
903
904 #[test]
905 fn test_parse_operator_syntax() {
906 assert_eq!(parse_normalized("!!x"), parse_normalized("!(!x)"));
908 assert_eq!(
909 parse_normalized("!x.f() || !g()"),
910 parse_normalized("(!(x.f())) || (!(g()))"),
911 );
912 assert_eq!(
913 parse_normalized("!x.f() <= !x.f()"),
914 parse_normalized("((!(x.f())) <= (!(x.f())))"),
915 );
916 assert_eq!(
917 parse_normalized("!x.f() < !x.f() == !x.f() >= !x.f() || !g() != !g()"),
918 parse_normalized(
919 "((!(x.f()) < (!(x.f()))) == ((!(x.f())) >= (!(x.f())))) || ((!(g())) != (!(g())))"
920 ),
921 );
922 assert_eq!(
923 parse_normalized("x.f() || y == y || z"),
924 parse_normalized("((x.f()) || (y == y)) || z"),
925 );
926 assert_eq!(
927 parse_normalized("x || y == y && z.h() == z"),
928 parse_normalized("x || ((y == y) && ((z.h()) == z))"),
929 );
930 assert_eq!(
931 parse_normalized("x == y || y != z && !z"),
932 parse_normalized("(x == y) || ((y != z) && (!z))"),
933 );
934 assert_eq!(
935 parse_normalized("a + b * c / d % e - -f == g"),
936 parse_normalized("((a + (((b * c) / d) % e)) - (-f)) == g"),
937 );
938
939 assert_eq!(
942 parse_normalized(r"x && y ++ z"),
943 parse_normalized(r"(x && y) ++ z"),
944 );
945 assert_eq!(
946 parse_normalized(r"x ++ y || z"),
947 parse_normalized(r"x ++ (y || z)"),
948 );
949 assert_eq!(
950 parse_normalized(r"x == y ++ z"),
951 parse_normalized(r"(x == y) ++ z"),
952 );
953 assert_eq!(
954 parse_normalized(r"x != y ++ z"),
955 parse_normalized(r"(x != y) ++ z"),
956 );
957
958 assert_eq!(parse_template(" ! x ").unwrap().span.as_str(), "! x");
960 assert_eq!(parse_template(" x ||y ").unwrap().span.as_str(), "x ||y");
961 }
962
963 #[test]
964 fn test_function_call_syntax() {
965 assert!(parse_template(r#" "".first_line() "#).is_ok());
967 assert!(parse_template(r#" "".first_line(,) "#).is_err());
968
969 assert!(parse_template(r#" "".contains("") "#).is_ok());
971 assert!(parse_template(r#" "".contains("",) "#).is_ok());
972 assert!(parse_template(r#" "".contains("" , ) "#).is_ok());
973 assert!(parse_template(r#" "".contains(,"") "#).is_err());
974 assert!(parse_template(r#" "".contains("",,) "#).is_err());
975 assert!(parse_template(r#" "".contains("" , , ) "#).is_err());
976 assert!(parse_template(r#" label("","") "#).is_ok());
977 assert!(parse_template(r#" label("","",) "#).is_ok());
978 assert!(parse_template(r#" label("",,"") "#).is_err());
979
980 assert!(parse_template("f(foo = bar)").is_ok());
982 assert!(parse_template("f( foo=bar )").is_ok());
983 assert!(parse_template("x.f(foo, bar=0, baz=1)").is_ok());
984
985 assert!(parse_template("false()").is_err());
987 assert!(parse_template("f(false=0)").is_err());
989 assert!(parse_template("f(false)").is_ok());
991 }
992
993 #[test]
994 fn test_method_call_syntax() {
995 assert_eq!(
996 parse_normalized("x.f().g()"),
997 parse_normalized("(x.f()).g()"),
998 );
999
1000 assert_eq!(parse_template(" x.f() ").unwrap().span.as_str(), "x.f()");
1002 assert_eq!(
1003 parse_template(" x.f().g() ").unwrap().span.as_str(),
1004 "x.f().g()",
1005 );
1006 }
1007
1008 #[test]
1009 fn test_lambda_syntax() {
1010 fn unwrap_lambda(node: ExpressionNode<'_>) -> Box<LambdaNode<'_>> {
1011 match node.kind {
1012 ExpressionKind::Lambda(lambda) => lambda,
1013 _ => panic!("unexpected expression: {node:?}"),
1014 }
1015 }
1016
1017 let lambda = unwrap_lambda(parse_template("|| a").unwrap());
1018 assert_eq!(lambda.params.len(), 0);
1019 assert_eq!(lambda.body.kind, ExpressionKind::Identifier("a"));
1020 let lambda = unwrap_lambda(parse_template("|foo| a").unwrap());
1021 assert_eq!(lambda.params.len(), 1);
1022 let lambda = unwrap_lambda(parse_template("|foo, b| a").unwrap());
1023 assert_eq!(lambda.params.len(), 2);
1024
1025 assert!(parse_template("||").is_err());
1027
1028 assert_eq!(
1030 parse_normalized("|| x ++ y"),
1031 parse_normalized("|| (x ++ y)"),
1032 );
1033 assert_eq!(
1034 parse_normalized("f( || x, || y)"),
1035 parse_normalized("f((|| x), (|| y))"),
1036 );
1037 assert_eq!(
1038 parse_normalized("|| x ++ || y"),
1039 parse_normalized("|| (x ++ (|| y))"),
1040 );
1041
1042 assert_eq!(parse_normalized("x||||y"), parse_normalized("x || (|| y)"));
1044 assert_eq!(parse_normalized("||||x"), parse_normalized("|| (|| x)"));
1045
1046 assert!(parse_template("|,| a").is_err());
1048 assert!(parse_template("|x,| a").is_ok());
1049 assert!(parse_template("|x , | a").is_ok());
1050 assert!(parse_template("|,x| a").is_err());
1051 assert!(parse_template("| x,y,| a").is_ok());
1052 assert!(parse_template("|x,,y| a").is_err());
1053
1054 assert_eq!(
1056 parse_template("|x, x| a").unwrap_err().kind,
1057 TemplateParseErrorKind::RedefinedFunctionParameter
1058 );
1059
1060 assert!(parse_template("|false| a").is_err());
1062 }
1063
1064 #[test]
1065 fn test_keyword_literal() {
1066 assert_eq!(parse_into_kind("false"), Ok(ExpressionKind::Boolean(false)));
1067 assert_eq!(parse_into_kind("(true)"), Ok(ExpressionKind::Boolean(true)));
1068 assert_eq!(
1070 parse_into_kind("False"),
1071 Ok(ExpressionKind::Identifier("False")),
1072 );
1073 assert_eq!(
1074 parse_into_kind("tRue"),
1075 Ok(ExpressionKind::Identifier("tRue")),
1076 );
1077 }
1078
1079 #[test]
1080 fn test_string_literal() {
1081 assert_eq!(
1083 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1084 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned())),
1085 );
1086
1087 assert_eq!(
1089 parse_into_kind(r#" "\y" "#),
1090 Err(TemplateParseErrorKind::SyntaxError),
1091 );
1092
1093 assert_eq!(
1095 parse_into_kind(r#" '' "#),
1096 Ok(ExpressionKind::String("".to_owned())),
1097 );
1098 assert_eq!(
1099 parse_into_kind(r#" 'a\n' "#),
1100 Ok(ExpressionKind::String(r"a\n".to_owned())),
1101 );
1102 assert_eq!(
1103 parse_into_kind(r#" '\' "#),
1104 Ok(ExpressionKind::String(r"\".to_owned())),
1105 );
1106 assert_eq!(
1107 parse_into_kind(r#" '"' "#),
1108 Ok(ExpressionKind::String(r#"""#.to_owned())),
1109 );
1110
1111 assert_eq!(
1113 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1114 Ok(ExpressionKind::String("aeiou".to_owned())),
1115 );
1116 assert_eq!(
1117 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1118 Ok(ExpressionKind::String("àèìðù".to_owned())),
1119 );
1120 assert_eq!(
1121 parse_into_kind(r#""\x""#),
1122 Err(TemplateParseErrorKind::SyntaxError),
1123 );
1124 assert_eq!(
1125 parse_into_kind(r#""\xf""#),
1126 Err(TemplateParseErrorKind::SyntaxError),
1127 );
1128 assert_eq!(
1129 parse_into_kind(r#""\xgg""#),
1130 Err(TemplateParseErrorKind::SyntaxError),
1131 );
1132 }
1133
1134 #[test]
1135 fn test_integer_literal() {
1136 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Integer(0)));
1137 assert_eq!(parse_into_kind("(42)"), Ok(ExpressionKind::Integer(42)));
1138 assert_eq!(
1139 parse_into_kind("00"),
1140 Err(TemplateParseErrorKind::SyntaxError),
1141 );
1142
1143 assert_eq!(
1144 parse_into_kind(&format!("{}", i64::MAX)),
1145 Ok(ExpressionKind::Integer(i64::MAX)),
1146 );
1147 assert_matches!(
1148 parse_into_kind(&format!("{}", (i64::MAX as u64) + 1)),
1149 Err(TemplateParseErrorKind::Expression(_))
1150 );
1151 }
1152
1153 #[test]
1154 fn test_parse_alias_decl() {
1155 let mut aliases_map = TemplateAliasesMap::new();
1156 aliases_map.insert("sym", r#""is symbol""#).unwrap();
1157 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1158 aliases_map
1159 .insert("func(a, b)", r#""is function 2""#)
1160 .unwrap();
1161 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1162 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1163
1164 let (id, defn) = aliases_map.get_symbol("sym").unwrap();
1165 assert_eq!(id, AliasId::Symbol("sym"));
1166 assert_eq!(defn, r#""is symbol""#);
1167
1168 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1169 assert_eq!(id, AliasId::Function("func", &[]));
1170 assert!(params.is_empty());
1171 assert_eq!(defn, r#""is function 0""#);
1172
1173 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1174 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1175 assert_eq!(params, ["b"]);
1176 assert_eq!(defn, r#""is function b""#);
1177
1178 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1179 assert_eq!(
1180 id,
1181 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1182 );
1183 assert_eq!(params, ["a", "b"]);
1184 assert_eq!(defn, r#""is function 2""#);
1185
1186 assert!(aliases_map.get_function("func", 3).is_none());
1187
1188 assert_eq!(
1190 aliases_map.insert("f(a, a)", r#""""#).unwrap_err().kind,
1191 TemplateParseErrorKind::RedefinedFunctionParameter
1192 );
1193
1194 assert!(aliases_map.insert("false", r#"""#).is_err());
1196 assert!(aliases_map.insert("true()", r#"""#).is_err());
1197 assert!(aliases_map.insert("f(false)", r#"""#).is_err());
1198
1199 assert!(aliases_map.insert("f(,)", r#"""#).is_err());
1201 assert!(aliases_map.insert("g(a,)", r#"""#).is_ok());
1203 assert!(aliases_map.insert("h(a , )", r#"""#).is_ok());
1204 assert!(aliases_map.insert("i(,a)", r#"""#).is_err());
1205 assert!(aliases_map.insert("j(a,,)", r#"""#).is_err());
1206 assert!(aliases_map.insert("k(a , , )", r#"""#).is_err());
1207 assert!(aliases_map.insert("l(a,b,)", r#"""#).is_ok());
1208 assert!(aliases_map.insert("m(a,,b)", r#"""#).is_err());
1209 }
1210
1211 #[test]
1212 fn test_expand_symbol_alias() {
1213 assert_eq!(
1214 with_aliases([("AB", "a ++ b")]).parse_normalized("AB ++ c"),
1215 parse_normalized("(a ++ b) ++ c"),
1216 );
1217 assert_eq!(
1218 with_aliases([("AB", "a ++ b")]).parse_normalized("if(AB, label(c, AB))"),
1219 parse_normalized("if((a ++ b), label(c, (a ++ b)))"),
1220 );
1221
1222 assert_eq!(
1224 with_aliases([("A", "BC"), ("BC", "b ++ C"), ("C", "c")]).parse_normalized("A"),
1225 parse_normalized("b ++ c"),
1226 );
1227
1228 assert_eq!(
1230 with_aliases([("AB", "a || b")]).parse_normalized("AB ++ c"),
1231 parse_normalized("(a || b) ++ c"),
1232 );
1233
1234 assert_eq!(
1236 with_aliases([("A", "a"), ("B", "b")]).parse_normalized("A || !B"),
1237 parse_normalized("a || !b"),
1238 );
1239
1240 assert_eq!(
1242 with_aliases([("A", "a")]).parse_normalized("A.f()"),
1243 parse_normalized("a.f()"),
1244 );
1245 assert_eq!(
1246 with_aliases([("A", "a"), ("B", "b")]).parse_normalized("x.f(A, B)"),
1247 parse_normalized("x.f(a, b)"),
1248 );
1249
1250 assert_eq!(
1252 with_aliases([("A", "a")]).parse_normalized("|| A"),
1253 parse_normalized("|| a"),
1254 );
1255 assert_eq!(
1259 with_aliases([("A", "a ++ b")]).parse_normalized("|A| A"),
1260 parse_normalized("|A| (a ++ b)"),
1261 );
1262
1263 assert_eq!(
1265 with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1266 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1267 );
1268 assert_eq!(
1269 with_aliases([("A", "B"), ("B", "b ++ C"), ("C", "c ++ B")])
1270 .parse("A")
1271 .unwrap_err()
1272 .kind,
1273 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1274 );
1275
1276 assert_eq!(
1278 with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1279 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1280 );
1281 }
1282
1283 #[test]
1284 fn test_expand_function_alias() {
1285 assert_eq!(
1286 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1287 parse_normalized("a"),
1288 );
1289 assert_eq!(
1290 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1291 parse_normalized("a"),
1292 );
1293 assert_eq!(
1294 with_aliases([("F( x, y )", "x ++ y")]).parse_normalized("F(a, b)"),
1295 parse_normalized("a ++ b"),
1296 );
1297
1298 assert_eq!(
1300 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x ++ y")]).parse_normalized("F(a)"),
1301 parse_normalized("a ++ b")
1302 );
1303
1304 assert_eq!(
1306 with_aliases([("F(x,y)", "if(x, y)")]).parse_normalized("F(a ++ y, b ++ x)"),
1307 parse_normalized("if((a ++ y), (b ++ x))"),
1308 );
1309 assert_eq!(
1311 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(a)"),
1312 parse_normalized("if((x ++ a), y)"),
1313 );
1314 assert_eq!(
1316 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(G(a))"),
1317 parse_normalized("if((x ++ (x ++ a)), y)"),
1318 );
1319
1320 assert_eq!(
1322 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a) ++ X"),
1323 parse_normalized("a ++ x"),
1324 );
1325
1326 assert_eq!(
1328 with_aliases([("F(x)", "x ++ A"), ("A", "x")]).parse_normalized("F(a)"),
1329 parse_normalized("a ++ x"),
1330 );
1331
1332 assert_eq!(
1334 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1335 parse_normalized("a"),
1336 );
1337
1338 assert_eq!(
1340 with_aliases([("F()", "f()")]).parse_normalized("x.F()"),
1341 parse_normalized("x.F()"),
1342 );
1343
1344 assert_eq!(
1347 with_aliases([("F(x)", "|x| x")]).parse_normalized("F(a ++ b)"),
1348 parse_normalized("|x| (a ++ b)"),
1349 );
1350
1351 assert_matches!(
1353 with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1354 TemplateParseErrorKind::InvalidArguments { .. }
1355 );
1356 assert_matches!(
1357 with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1358 TemplateParseErrorKind::InvalidArguments { .. }
1359 );
1360 assert_matches!(
1361 with_aliases([("F(x,y)", "x ++ y")])
1362 .parse("F(a,b,c)")
1363 .unwrap_err()
1364 .kind,
1365 TemplateParseErrorKind::InvalidArguments { .. }
1366 );
1367
1368 assert_eq!(
1370 with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1371 .parse("F(a)")
1372 .unwrap_err()
1373 .kind,
1374 TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned()),
1375 );
1376 assert_eq!(
1377 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1378 .parse("F(a)")
1379 .unwrap_err()
1380 .kind,
1381 TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned())
1382 );
1383 }
1384}