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