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 primary = inner.next().unwrap();
484 assert_eq!(primary.as_rule(), Rule::primary);
485 let primary_span = primary.as_span();
486 let expr = primary.into_inner().next().unwrap();
487 let primary_kind = match expr.as_rule() {
488 Rule::string_literal => {
489 let text = STRING_LITERAL_PARSER.parse(expr.into_inner());
490 ExpressionKind::String(text)
491 }
492 Rule::raw_string_literal => {
493 let text = parse_raw_string_literal(expr);
494 ExpressionKind::String(text)
495 }
496 Rule::integer_literal => {
497 let value = expr.as_str().parse().map_err(|err| {
498 TemplateParseError::expression("Invalid integer literal", expr.as_span())
499 .with_source(err)
500 })?;
501 ExpressionKind::Integer(value)
502 }
503 Rule::string_pattern => {
504 let [kind, op, literal] = expr.into_inner().collect_array().unwrap();
505 assert_eq!(kind.as_rule(), Rule::string_pattern_identifier);
506 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
507 let kind = kind.as_str();
508 let text = match literal.as_rule() {
509 Rule::string_literal => STRING_LITERAL_PARSER.parse(literal.into_inner()),
510 Rule::raw_string_literal => parse_raw_string_literal(literal),
511 other => {
512 panic!("Unexpected literal rule in string pattern: {other:?}")
513 }
514 };
515 ExpressionKind::StringPattern { kind, value: text }
517 }
518 Rule::identifier => parse_identifier_or_literal(expr),
519 Rule::function => {
520 let function = Box::new(FUNCTION_CALL_PARSER.parse(
521 expr,
522 parse_identifier_name,
523 parse_template_node,
524 )?);
525 ExpressionKind::FunctionCall(function)
526 }
527 Rule::lambda => {
528 let lambda = Box::new(parse_lambda_node(expr)?);
529 ExpressionKind::Lambda(lambda)
530 }
531 Rule::template => parse_template_node(expr)?.kind,
533 other => panic!("unexpected term: {other:?}"),
534 };
535 let primary_node = ExpressionNode::new(primary_kind, primary_span);
536 inner.try_fold(primary_node, |object, chain| {
537 assert_eq!(chain.as_rule(), Rule::function);
538 let span = object.span.start_pos().span(&chain.as_span().end_pos());
539 let method = Box::new(MethodCallNode {
540 object,
541 function: FUNCTION_CALL_PARSER.parse(
542 chain,
543 parse_identifier_name,
544 parse_template_node,
545 )?,
546 });
547 Ok(ExpressionNode::new(
548 ExpressionKind::MethodCall(method),
549 span,
550 ))
551 })
552}
553
554fn parse_expression_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
555 assert_eq!(pair.as_rule(), Rule::expression);
556 static PRATT: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
557 PrattParser::new()
558 .op(Op::infix(Rule::logical_or_op, Assoc::Left))
559 .op(Op::infix(Rule::logical_and_op, Assoc::Left))
560 .op(Op::infix(Rule::eq_op, Assoc::Left) | Op::infix(Rule::ne_op, Assoc::Left))
561 .op(Op::infix(Rule::ge_op, Assoc::Left)
562 | Op::infix(Rule::gt_op, Assoc::Left)
563 | Op::infix(Rule::le_op, Assoc::Left)
564 | Op::infix(Rule::lt_op, Assoc::Left))
565 .op(Op::infix(Rule::add_op, Assoc::Left) | Op::infix(Rule::sub_op, Assoc::Left))
566 .op(Op::infix(Rule::mul_op, Assoc::Left)
567 | Op::infix(Rule::div_op, Assoc::Left)
568 | Op::infix(Rule::rem_op, Assoc::Left))
569 .op(Op::prefix(Rule::logical_not_op) | Op::prefix(Rule::negate_op))
570 });
571 PRATT
572 .map_primary(parse_term_node)
573 .map_prefix(|op, rhs| {
574 let op_kind = match op.as_rule() {
575 Rule::logical_not_op => UnaryOp::LogicalNot,
576 Rule::negate_op => UnaryOp::Negate,
577 r => panic!("unexpected prefix operator rule {r:?}"),
578 };
579 let rhs = Box::new(rhs?);
580 let span = op.as_span().start_pos().span(&rhs.span.end_pos());
581 let expr = ExpressionKind::Unary(op_kind, rhs);
582 Ok(ExpressionNode::new(expr, span))
583 })
584 .map_infix(|lhs, op, rhs| {
585 let op_kind = match op.as_rule() {
586 Rule::logical_or_op => BinaryOp::LogicalOr,
587 Rule::logical_and_op => BinaryOp::LogicalAnd,
588 Rule::eq_op => BinaryOp::Eq,
589 Rule::ne_op => BinaryOp::Ne,
590 Rule::ge_op => BinaryOp::Ge,
591 Rule::gt_op => BinaryOp::Gt,
592 Rule::le_op => BinaryOp::Le,
593 Rule::lt_op => BinaryOp::Lt,
594 Rule::add_op => BinaryOp::Add,
595 Rule::sub_op => BinaryOp::Sub,
596 Rule::mul_op => BinaryOp::Mul,
597 Rule::div_op => BinaryOp::Div,
598 Rule::rem_op => BinaryOp::Rem,
599 r => panic!("unexpected infix operator rule {r:?}"),
600 };
601 let lhs = Box::new(lhs?);
602 let rhs = Box::new(rhs?);
603 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
604 let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
605 Ok(ExpressionNode::new(expr, span))
606 })
607 .parse(pair.into_inner())
608}
609
610fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
611 assert_eq!(pair.as_rule(), Rule::template);
612 let span = pair.as_span();
613 let inner = pair.into_inner();
614 let mut nodes: Vec<_> = inner
615 .filter_map(|pair| match pair.as_rule() {
616 Rule::concat_op => None,
617 Rule::expression => Some(parse_expression_node(pair)),
618 r => panic!("unexpected template item rule {r:?}"),
619 })
620 .try_collect()?;
621 if nodes.len() == 1 {
622 Ok(nodes.pop().unwrap())
623 } else {
624 Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span))
625 }
626}
627
628pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode<'_>> {
630 let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?;
631 let first_pair = pairs.next().unwrap();
632 if first_pair.as_rule() == Rule::EOI {
633 let span = first_pair.as_span();
634 Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span))
635 } else {
636 parse_template_node(first_pair)
637 }
638}
639
640pub type TemplateAliasesMap = AliasesMap<TemplateAliasParser, String>;
641
642#[derive(Clone, Debug, Default)]
643pub struct TemplateAliasParser;
644
645impl AliasDeclarationParser for TemplateAliasParser {
646 type Error = TemplateParseError;
647
648 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
649 let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?;
650 let first = pairs.next().unwrap();
651 match first.as_rule() {
652 Rule::identifier => {
653 let name = parse_identifier_name(first)?.to_owned();
654 Ok(AliasDeclaration::Symbol(name))
655 }
656 Rule::function_alias_declaration => {
657 let mut inner = first.into_inner();
658 let name_pair = inner.next().unwrap();
659 let params_pair = inner.next().unwrap();
660 let name = parse_identifier_name(name_pair)?.to_owned();
661 let params = parse_formal_parameters(params_pair)?
662 .into_iter()
663 .map(|s| s.to_owned())
664 .collect();
665 Ok(AliasDeclaration::Function(name, params))
666 }
667 r => panic!("unexpected alias declaration rule {r:?}"),
668 }
669 }
670}
671
672impl AliasDefinitionParser for TemplateAliasParser {
673 type Output<'i> = ExpressionKind<'i>;
674 type Error = TemplateParseError;
675
676 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
677 parse_template(source)
678 }
679}
680
681pub fn parse<'i>(
685 template_text: &'i str,
686 aliases_map: &'i TemplateAliasesMap,
687) -> TemplateParseResult<ExpressionNode<'i>> {
688 let node = parse_template(template_text)?;
689 dsl_util::expand_aliases(node, aliases_map)
690}
691
692pub fn expect_string_literal<'a>(node: &'a ExpressionNode<'_>) -> TemplateParseResult<&'a str> {
694 catch_aliases_no_diagnostics(node, |node| match &node.kind {
695 ExpressionKind::String(s) => Ok(s.as_str()),
696 _ => Err(TemplateParseError::expression(
697 "Expected string literal",
698 node.span,
699 )),
700 })
701}
702
703pub fn expect_string_pattern(node: &ExpressionNode<'_>) -> TemplateParseResult<StringPattern> {
707 catch_aliases_no_diagnostics(node, |node| match &node.kind {
708 ExpressionKind::StringPattern { kind, value } => StringPattern::from_str_kind(value, kind)
709 .map_err(|err| {
710 TemplateParseError::expression("Bad string pattern", node.span).with_source(err)
711 }),
712 ExpressionKind::String(string) => Ok(StringPattern::Substring(string.clone())),
713 _ => Err(TemplateParseError::expression(
714 "Expected string pattern",
715 node.span,
716 )),
717 })
718}
719
720pub fn expect_lambda<'a, 'i>(
722 node: &'a ExpressionNode<'i>,
723) -> TemplateParseResult<&'a LambdaNode<'i>> {
724 catch_aliases_no_diagnostics(node, |node| match &node.kind {
725 ExpressionKind::Lambda(lambda) => Ok(lambda.as_ref()),
726 _ => Err(TemplateParseError::expression(
727 "Expected lambda expression",
728 node.span,
729 )),
730 })
731}
732
733pub fn catch_aliases<'a, 'i, T>(
736 diagnostics: &mut TemplateDiagnostics,
737 node: &'a ExpressionNode<'i>,
738 f: impl FnOnce(&mut TemplateDiagnostics, &'a ExpressionNode<'i>) -> TemplateParseResult<T>,
739) -> TemplateParseResult<T> {
740 let (node, stack) = skip_aliases(node);
741 if stack.is_empty() {
742 f(diagnostics, node)
743 } else {
744 let mut inner_diagnostics = TemplateDiagnostics::new();
745 let result = f(&mut inner_diagnostics, node);
746 diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
747 result.map_err(|err| attach_aliases_err(err, &stack))
748 }
749}
750
751fn catch_aliases_no_diagnostics<'a, 'i, T>(
752 node: &'a ExpressionNode<'i>,
753 f: impl FnOnce(&'a ExpressionNode<'i>) -> TemplateParseResult<T>,
754) -> TemplateParseResult<T> {
755 let (node, stack) = skip_aliases(node);
756 f(node).map_err(|err| attach_aliases_err(err, &stack))
757}
758
759fn skip_aliases<'a, 'i>(
760 mut node: &'a ExpressionNode<'i>,
761) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
762 let mut stack = Vec::new();
763 while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
764 stack.push((*id, node.span));
765 node = subst;
766 }
767 (node, stack)
768}
769
770fn attach_aliases_err(
771 err: TemplateParseError,
772 stack: &[(AliasId<'_>, pest::Span<'_>)],
773) -> TemplateParseError {
774 stack
775 .iter()
776 .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
777}
778
779pub fn lookup_function<'a, V>(
781 table: &'a HashMap<&str, V>,
782 function: &FunctionCallNode,
783) -> TemplateParseResult<&'a V> {
784 if let Some(value) = table.get(function.name) {
785 Ok(value)
786 } else {
787 let candidates = collect_similar(function.name, table.keys());
788 Err(TemplateParseError::with_span(
789 TemplateParseErrorKind::NoSuchFunction {
790 name: function.name.to_owned(),
791 candidates,
792 },
793 function.name_span,
794 ))
795 }
796}
797
798pub fn lookup_method<'a, V>(
800 type_name: impl Into<String>,
801 table: &'a HashMap<&str, V>,
802 function: &FunctionCallNode,
803) -> TemplateParseResult<&'a V> {
804 if let Some(value) = table.get(function.name) {
805 Ok(value)
806 } else {
807 let candidates = collect_similar(function.name, table.keys());
808 Err(TemplateParseError::with_span(
809 TemplateParseErrorKind::NoSuchMethod {
810 type_name: type_name.into(),
811 name: function.name.to_owned(),
812 candidates,
813 },
814 function.name_span,
815 ))
816 }
817}
818
819#[cfg(test)]
820mod tests {
821 use assert_matches::assert_matches;
822 use jj_lib::dsl_util::KeywordArgument;
823
824 use super::*;
825
826 #[derive(Debug)]
827 struct WithTemplateAliasesMap(TemplateAliasesMap);
828
829 impl WithTemplateAliasesMap {
830 fn parse<'i>(&'i self, template_text: &'i str) -> TemplateParseResult<ExpressionNode<'i>> {
831 parse(template_text, &self.0)
832 }
833
834 fn parse_normalized<'i>(&'i self, template_text: &'i str) -> ExpressionNode<'i> {
835 normalize_tree(self.parse(template_text).unwrap())
836 }
837 }
838
839 fn with_aliases(
840 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
841 ) -> WithTemplateAliasesMap {
842 let mut aliases_map = TemplateAliasesMap::new();
843 for (decl, defn) in aliases {
844 aliases_map.insert(decl, defn).unwrap();
845 }
846 WithTemplateAliasesMap(aliases_map)
847 }
848
849 fn parse_into_kind(template_text: &str) -> Result<ExpressionKind<'_>, TemplateParseErrorKind> {
850 parse_template(template_text)
851 .map(|node| node.kind)
852 .map_err(|err| err.kind)
853 }
854
855 fn parse_normalized(template_text: &str) -> ExpressionNode<'_> {
856 normalize_tree(parse_template(template_text).unwrap())
857 }
858
859 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
861 fn empty_span() -> pest::Span<'static> {
862 pest::Span::new("", 0, 0).unwrap()
863 }
864
865 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
866 nodes.into_iter().map(normalize_tree).collect()
867 }
868
869 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
870 FunctionCallNode {
871 name: function.name,
872 name_span: empty_span(),
873 args: normalize_list(function.args),
874 keyword_args: function
875 .keyword_args
876 .into_iter()
877 .map(|arg| KeywordArgument {
878 name: arg.name,
879 name_span: empty_span(),
880 value: normalize_tree(arg.value),
881 })
882 .collect(),
883 args_span: empty_span(),
884 }
885 }
886
887 let normalized_kind = match node.kind {
888 ExpressionKind::Identifier(_)
889 | ExpressionKind::Boolean(_)
890 | ExpressionKind::Integer(_)
891 | ExpressionKind::String(_) => node.kind,
892 ExpressionKind::StringPattern { .. } => node.kind,
893 ExpressionKind::Unary(op, arg) => {
894 let arg = Box::new(normalize_tree(*arg));
895 ExpressionKind::Unary(op, arg)
896 }
897 ExpressionKind::Binary(op, lhs, rhs) => {
898 let lhs = Box::new(normalize_tree(*lhs));
899 let rhs = Box::new(normalize_tree(*rhs));
900 ExpressionKind::Binary(op, lhs, rhs)
901 }
902 ExpressionKind::Concat(nodes) => ExpressionKind::Concat(normalize_list(nodes)),
903 ExpressionKind::FunctionCall(function) => {
904 let function = Box::new(normalize_function_call(*function));
905 ExpressionKind::FunctionCall(function)
906 }
907 ExpressionKind::MethodCall(method) => {
908 let method = Box::new(MethodCallNode {
909 object: normalize_tree(method.object),
910 function: normalize_function_call(method.function),
911 });
912 ExpressionKind::MethodCall(method)
913 }
914 ExpressionKind::Lambda(lambda) => {
915 let lambda = Box::new(LambdaNode {
916 params: lambda.params,
917 params_span: empty_span(),
918 body: normalize_tree(lambda.body),
919 });
920 ExpressionKind::Lambda(lambda)
921 }
922 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
923 };
924 ExpressionNode {
925 kind: normalized_kind,
926 span: empty_span(),
927 }
928 }
929
930 #[test]
931 fn test_parse_tree_eq() {
932 assert_eq!(
933 normalize_tree(parse_template(r#" commit_id.short(1 ) ++ description"#).unwrap()),
934 normalize_tree(parse_template(r#"commit_id.short( 1 )++(description)"#).unwrap()),
935 );
936 assert_ne!(
937 normalize_tree(parse_template(r#" "ab" "#).unwrap()),
938 normalize_tree(parse_template(r#" "a" ++ "b" "#).unwrap()),
939 );
940 assert_ne!(
941 normalize_tree(parse_template(r#" "foo" ++ "0" "#).unwrap()),
942 normalize_tree(parse_template(r#" "foo" ++ 0 "#).unwrap()),
943 );
944 }
945
946 #[test]
947 fn test_parse_whitespace() {
948 let ascii_whitespaces: String = ('\x00'..='\x7f')
949 .filter(char::is_ascii_whitespace)
950 .collect();
951 assert_eq!(
952 parse_normalized(&format!("{ascii_whitespaces}f()")),
953 parse_normalized("f()"),
954 );
955 }
956
957 #[test]
958 fn test_parse_operator_syntax() {
959 assert_eq!(parse_normalized("!!x"), parse_normalized("!(!x)"));
961 assert_eq!(
962 parse_normalized("!x.f() || !g()"),
963 parse_normalized("(!(x.f())) || (!(g()))"),
964 );
965 assert_eq!(
966 parse_normalized("!x.f() <= !x.f()"),
967 parse_normalized("((!(x.f())) <= (!(x.f())))"),
968 );
969 assert_eq!(
970 parse_normalized("!x.f() < !x.f() == !x.f() >= !x.f() || !g() != !g()"),
971 parse_normalized(
972 "((!(x.f()) < (!(x.f()))) == ((!(x.f())) >= (!(x.f())))) || ((!(g())) != (!(g())))"
973 ),
974 );
975 assert_eq!(
976 parse_normalized("x.f() || y == y || z"),
977 parse_normalized("((x.f()) || (y == y)) || z"),
978 );
979 assert_eq!(
980 parse_normalized("x || y == y && z.h() == z"),
981 parse_normalized("x || ((y == y) && ((z.h()) == z))"),
982 );
983 assert_eq!(
984 parse_normalized("x == y || y != z && !z"),
985 parse_normalized("(x == y) || ((y != z) && (!z))"),
986 );
987 assert_eq!(
988 parse_normalized("a + b * c / d % e - -f == g"),
989 parse_normalized("((a + (((b * c) / d) % e)) - (-f)) == g"),
990 );
991
992 assert_eq!(
995 parse_normalized(r"x && y ++ z"),
996 parse_normalized(r"(x && y) ++ z"),
997 );
998 assert_eq!(
999 parse_normalized(r"x ++ y || z"),
1000 parse_normalized(r"x ++ (y || z)"),
1001 );
1002 assert_eq!(
1003 parse_normalized(r"x == y ++ z"),
1004 parse_normalized(r"(x == y) ++ z"),
1005 );
1006 assert_eq!(
1007 parse_normalized(r"x != y ++ z"),
1008 parse_normalized(r"(x != y) ++ z"),
1009 );
1010
1011 assert_eq!(parse_template(" ! x ").unwrap().span.as_str(), "! x");
1013 assert_eq!(parse_template(" x ||y ").unwrap().span.as_str(), "x ||y");
1014 assert_eq!(parse_template(" (x) ").unwrap().span.as_str(), "(x)");
1015 assert_eq!(
1016 parse_template(" ! (x ||y) ").unwrap().span.as_str(),
1017 "! (x ||y)"
1018 );
1019 assert_eq!(
1020 parse_template("(x ++ y ) ").unwrap().span.as_str(),
1021 "(x ++ y )"
1022 );
1023 }
1024
1025 #[test]
1026 fn test_function_call_syntax() {
1027 fn unwrap_function_call(node: ExpressionNode<'_>) -> Box<FunctionCallNode<'_>> {
1028 match node.kind {
1029 ExpressionKind::FunctionCall(function) => function,
1030 _ => panic!("unexpected expression: {node:?}"),
1031 }
1032 }
1033
1034 assert!(parse_template(r#" "".first_line() "#).is_ok());
1036 assert!(parse_template(r#" "".first_line(,) "#).is_err());
1037
1038 assert!(parse_template(r#" "".contains("") "#).is_ok());
1040 assert!(parse_template(r#" "".contains("",) "#).is_ok());
1041 assert!(parse_template(r#" "".contains("" , ) "#).is_ok());
1042 assert!(parse_template(r#" "".contains(,"") "#).is_err());
1043 assert!(parse_template(r#" "".contains("",,) "#).is_err());
1044 assert!(parse_template(r#" "".contains("" , , ) "#).is_err());
1045 assert!(parse_template(r#" label("","") "#).is_ok());
1046 assert!(parse_template(r#" label("","",) "#).is_ok());
1047 assert!(parse_template(r#" label("",,"") "#).is_err());
1048
1049 assert!(parse_template("f(foo = bar)").is_ok());
1051 assert!(parse_template("f( foo=bar )").is_ok());
1052 assert!(parse_template("x.f(foo, bar=0, baz=1)").is_ok());
1053
1054 assert!(parse_template("false()").is_err());
1056 assert!(parse_template("f(false=0)").is_err());
1058 assert!(parse_template("f(false)").is_ok());
1060
1061 let function =
1063 unwrap_function_call(parse_template("foo( a, (b) , -(c), d = (e) )").unwrap());
1064 assert_eq!(function.name_span.as_str(), "foo");
1065 assert_eq!(function.args_span.as_str(), "a, (b) , -(c), d = (e) ");
1068 assert_eq!(function.args[0].span.as_str(), "a");
1069 assert_eq!(function.args[1].span.as_str(), "(b)");
1070 assert_eq!(function.args[2].span.as_str(), "-(c)");
1071 assert_eq!(function.keyword_args[0].name_span.as_str(), "d");
1072 assert_eq!(function.keyword_args[0].value.span.as_str(), "(e)");
1073 }
1074
1075 #[test]
1076 fn test_method_call_syntax() {
1077 assert_eq!(
1078 parse_normalized("x.f().g()"),
1079 parse_normalized("(x.f()).g()"),
1080 );
1081
1082 assert_eq!(parse_template(" x.f() ").unwrap().span.as_str(), "x.f()");
1084 assert_eq!(
1085 parse_template(" x.f().g() ").unwrap().span.as_str(),
1086 "x.f().g()",
1087 );
1088 }
1089
1090 #[test]
1091 fn test_lambda_syntax() {
1092 fn unwrap_lambda(node: ExpressionNode<'_>) -> Box<LambdaNode<'_>> {
1093 match node.kind {
1094 ExpressionKind::Lambda(lambda) => lambda,
1095 _ => panic!("unexpected expression: {node:?}"),
1096 }
1097 }
1098
1099 let lambda = unwrap_lambda(parse_template("|| a").unwrap());
1100 assert_eq!(lambda.params.len(), 0);
1101 assert_eq!(lambda.body.kind, ExpressionKind::Identifier("a"));
1102 let lambda = unwrap_lambda(parse_template("|foo| a").unwrap());
1103 assert_eq!(lambda.params.len(), 1);
1104 let lambda = unwrap_lambda(parse_template("|foo, b| a").unwrap());
1105 assert_eq!(lambda.params.len(), 2);
1106
1107 assert!(parse_template("||").is_err());
1109
1110 assert_eq!(
1112 parse_normalized("|| x ++ y"),
1113 parse_normalized("|| (x ++ y)"),
1114 );
1115 assert_eq!(
1116 parse_normalized("f( || x, || y)"),
1117 parse_normalized("f((|| x), (|| y))"),
1118 );
1119 assert_eq!(
1120 parse_normalized("|| x ++ || y"),
1121 parse_normalized("|| (x ++ (|| y))"),
1122 );
1123
1124 assert_eq!(parse_normalized("x||||y"), parse_normalized("x || (|| y)"));
1126 assert_eq!(parse_normalized("||||x"), parse_normalized("|| (|| x)"));
1127
1128 assert!(parse_template("|,| a").is_err());
1130 assert!(parse_template("|x,| a").is_ok());
1131 assert!(parse_template("|x , | a").is_ok());
1132 assert!(parse_template("|,x| a").is_err());
1133 assert!(parse_template("| x,y,| a").is_ok());
1134 assert!(parse_template("|x,,y| a").is_err());
1135
1136 assert_eq!(
1138 parse_template("|x, x| a").unwrap_err().kind,
1139 TemplateParseErrorKind::RedefinedFunctionParameter
1140 );
1141
1142 assert!(parse_template("|false| a").is_err());
1144 }
1145
1146 #[test]
1147 fn test_keyword_literal() {
1148 assert_eq!(parse_into_kind("false"), Ok(ExpressionKind::Boolean(false)));
1149 assert_eq!(parse_into_kind("(true)"), Ok(ExpressionKind::Boolean(true)));
1150 assert_eq!(
1152 parse_into_kind("False"),
1153 Ok(ExpressionKind::Identifier("False")),
1154 );
1155 assert_eq!(
1156 parse_into_kind("tRue"),
1157 Ok(ExpressionKind::Identifier("tRue")),
1158 );
1159 }
1160
1161 #[test]
1162 fn test_string_literal() {
1163 assert_eq!(
1165 parse_into_kind(r#" " " "#),
1166 Ok(ExpressionKind::String(" ".to_owned())),
1167 );
1168 assert_eq!(
1169 parse_into_kind(r#" ' ' "#),
1170 Ok(ExpressionKind::String(" ".to_owned())),
1171 );
1172
1173 assert_eq!(
1175 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1176 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned())),
1177 );
1178
1179 assert_eq!(
1181 parse_into_kind(r#" "\y" "#),
1182 Err(TemplateParseErrorKind::SyntaxError),
1183 );
1184
1185 assert_eq!(
1187 parse_into_kind(r#" '' "#),
1188 Ok(ExpressionKind::String("".to_owned())),
1189 );
1190 assert_eq!(
1191 parse_into_kind(r#" 'a\n' "#),
1192 Ok(ExpressionKind::String(r"a\n".to_owned())),
1193 );
1194 assert_eq!(
1195 parse_into_kind(r#" '\' "#),
1196 Ok(ExpressionKind::String(r"\".to_owned())),
1197 );
1198 assert_eq!(
1199 parse_into_kind(r#" '"' "#),
1200 Ok(ExpressionKind::String(r#"""#.to_owned())),
1201 );
1202
1203 assert_eq!(
1205 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1206 Ok(ExpressionKind::String("aeiou".to_owned())),
1207 );
1208 assert_eq!(
1209 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1210 Ok(ExpressionKind::String("àèìðù".to_owned())),
1211 );
1212 assert_eq!(
1213 parse_into_kind(r#""\x""#),
1214 Err(TemplateParseErrorKind::SyntaxError),
1215 );
1216 assert_eq!(
1217 parse_into_kind(r#""\xf""#),
1218 Err(TemplateParseErrorKind::SyntaxError),
1219 );
1220 assert_eq!(
1221 parse_into_kind(r#""\xgg""#),
1222 Err(TemplateParseErrorKind::SyntaxError),
1223 );
1224 }
1225
1226 #[test]
1227 fn test_string_pattern() {
1228 assert_eq!(
1229 parse_into_kind(r#"regex:"meow""#),
1230 Ok(ExpressionKind::StringPattern {
1231 kind: "regex",
1232 value: "meow".to_owned()
1233 }),
1234 );
1235 assert_eq!(
1236 parse_into_kind(r#"regex:'\r\n'"#),
1237 Ok(ExpressionKind::StringPattern {
1238 kind: "regex",
1239 value: r#"\r\n"#.to_owned()
1240 })
1241 );
1242 assert_eq!(
1243 parse_into_kind(r#"regex-i:'\r\n'"#),
1244 Ok(ExpressionKind::StringPattern {
1245 kind: "regex-i",
1246 value: r#"\r\n"#.to_owned()
1247 })
1248 );
1249 assert_eq!(
1250 parse_into_kind("regex:meow"),
1251 Err(TemplateParseErrorKind::SyntaxError),
1252 "no bare words in string patterns in templates"
1253 );
1254 assert_eq!(
1255 parse_into_kind("regex: 'with spaces'"),
1256 Err(TemplateParseErrorKind::SyntaxError),
1257 "no spaces after"
1258 );
1259 assert_eq!(
1260 parse_into_kind("regex :'with spaces'"),
1261 Err(TemplateParseErrorKind::SyntaxError),
1262 "no spaces before either"
1263 );
1264 assert_eq!(
1265 parse_into_kind("regex : 'with spaces'"),
1266 Err(TemplateParseErrorKind::SyntaxError),
1267 "certainly not both"
1268 );
1269 }
1270
1271 #[test]
1272 fn test_integer_literal() {
1273 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Integer(0)));
1274 assert_eq!(parse_into_kind("(42)"), Ok(ExpressionKind::Integer(42)));
1275 assert_eq!(
1276 parse_into_kind("00"),
1277 Err(TemplateParseErrorKind::SyntaxError),
1278 );
1279
1280 assert_eq!(
1281 parse_into_kind(&format!("{}", i64::MAX)),
1282 Ok(ExpressionKind::Integer(i64::MAX)),
1283 );
1284 assert_matches!(
1285 parse_into_kind(&format!("{}", (i64::MAX as u64) + 1)),
1286 Err(TemplateParseErrorKind::Expression(_))
1287 );
1288 }
1289
1290 #[test]
1291 fn test_parse_alias_decl() {
1292 let mut aliases_map = TemplateAliasesMap::new();
1293 aliases_map.insert("sym", r#""is symbol""#).unwrap();
1294 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1295 aliases_map
1296 .insert("func(a, b)", r#""is function 2""#)
1297 .unwrap();
1298 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1299 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1300
1301 let (id, defn) = aliases_map.get_symbol("sym").unwrap();
1302 assert_eq!(id, AliasId::Symbol("sym"));
1303 assert_eq!(defn, r#""is symbol""#);
1304
1305 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1306 assert_eq!(id, AliasId::Function("func", &[]));
1307 assert!(params.is_empty());
1308 assert_eq!(defn, r#""is function 0""#);
1309
1310 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1311 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1312 assert_eq!(params, ["b"]);
1313 assert_eq!(defn, r#""is function b""#);
1314
1315 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1316 assert_eq!(
1317 id,
1318 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1319 );
1320 assert_eq!(params, ["a", "b"]);
1321 assert_eq!(defn, r#""is function 2""#);
1322
1323 assert!(aliases_map.get_function("func", 3).is_none());
1324
1325 assert_eq!(
1327 aliases_map.insert("f(a, a)", r#""""#).unwrap_err().kind,
1328 TemplateParseErrorKind::RedefinedFunctionParameter
1329 );
1330
1331 assert!(aliases_map.insert("false", r#"""#).is_err());
1333 assert!(aliases_map.insert("true()", r#"""#).is_err());
1334 assert!(aliases_map.insert("f(false)", r#"""#).is_err());
1335
1336 assert!(aliases_map.insert("f(,)", r#"""#).is_err());
1338 assert!(aliases_map.insert("g(a,)", r#"""#).is_ok());
1340 assert!(aliases_map.insert("h(a , )", r#"""#).is_ok());
1341 assert!(aliases_map.insert("i(,a)", r#"""#).is_err());
1342 assert!(aliases_map.insert("j(a,,)", r#"""#).is_err());
1343 assert!(aliases_map.insert("k(a , , )", r#"""#).is_err());
1344 assert!(aliases_map.insert("l(a,b,)", r#"""#).is_ok());
1345 assert!(aliases_map.insert("m(a,,b)", r#"""#).is_err());
1346 }
1347
1348 #[test]
1349 fn test_expand_symbol_alias() {
1350 assert_eq!(
1351 with_aliases([("AB", "a ++ b")]).parse_normalized("AB ++ c"),
1352 parse_normalized("(a ++ b) ++ c"),
1353 );
1354 assert_eq!(
1355 with_aliases([("AB", "a ++ b")]).parse_normalized("if(AB, label(c, AB))"),
1356 parse_normalized("if((a ++ b), label(c, (a ++ b)))"),
1357 );
1358
1359 assert_eq!(
1361 with_aliases([("A", "BC"), ("BC", "b ++ C"), ("C", "c")]).parse_normalized("A"),
1362 parse_normalized("b ++ c"),
1363 );
1364
1365 assert_eq!(
1367 with_aliases([("AB", "a || b")]).parse_normalized("AB ++ c"),
1368 parse_normalized("(a || b) ++ c"),
1369 );
1370
1371 assert_eq!(
1373 with_aliases([("A", "a"), ("B", "b")]).parse_normalized("A || !B"),
1374 parse_normalized("a || !b"),
1375 );
1376
1377 assert_eq!(
1379 with_aliases([("A", "a")]).parse_normalized("A.f()"),
1380 parse_normalized("a.f()"),
1381 );
1382 assert_eq!(
1383 with_aliases([("A", "a"), ("B", "b")]).parse_normalized("x.f(A, B)"),
1384 parse_normalized("x.f(a, b)"),
1385 );
1386
1387 assert_eq!(
1389 with_aliases([("A", "a")]).parse_normalized("|| A"),
1390 parse_normalized("|| a"),
1391 );
1392 assert_eq!(
1396 with_aliases([("A", "a ++ b")]).parse_normalized("|A| A"),
1397 parse_normalized("|A| (a ++ b)"),
1398 );
1399
1400 assert_eq!(
1402 with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1403 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1404 );
1405 assert_eq!(
1406 with_aliases([("A", "B"), ("B", "b ++ C"), ("C", "c ++ B")])
1407 .parse("A")
1408 .unwrap_err()
1409 .kind,
1410 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1411 );
1412
1413 assert_eq!(
1415 with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1416 TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1417 );
1418 }
1419
1420 #[test]
1421 fn test_expand_function_alias() {
1422 assert_eq!(
1423 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1424 parse_normalized("a"),
1425 );
1426 assert_eq!(
1427 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1428 parse_normalized("a"),
1429 );
1430 assert_eq!(
1431 with_aliases([("F( x, y )", "x ++ y")]).parse_normalized("F(a, b)"),
1432 parse_normalized("a ++ b"),
1433 );
1434
1435 assert_eq!(
1437 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x ++ y")]).parse_normalized("F(a)"),
1438 parse_normalized("a ++ b")
1439 );
1440
1441 assert_eq!(
1443 with_aliases([("F(x,y)", "if(x, y)")]).parse_normalized("F(a ++ y, b ++ x)"),
1444 parse_normalized("if((a ++ y), (b ++ x))"),
1445 );
1446 assert_eq!(
1448 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(a)"),
1449 parse_normalized("if((x ++ a), y)"),
1450 );
1451 assert_eq!(
1453 with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(G(a))"),
1454 parse_normalized("if((x ++ (x ++ a)), y)"),
1455 );
1456
1457 assert_eq!(
1459 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a) ++ X"),
1460 parse_normalized("a ++ x"),
1461 );
1462
1463 assert_eq!(
1465 with_aliases([("F(x)", "x ++ A"), ("A", "x")]).parse_normalized("F(a)"),
1466 parse_normalized("a ++ x"),
1467 );
1468
1469 assert_eq!(
1471 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1472 parse_normalized("a"),
1473 );
1474
1475 assert_eq!(
1477 with_aliases([("F()", "f()")]).parse_normalized("x.F()"),
1478 parse_normalized("x.F()"),
1479 );
1480
1481 assert_eq!(
1484 with_aliases([("F(x)", "|x| x")]).parse_normalized("F(a ++ b)"),
1485 parse_normalized("|x| (a ++ b)"),
1486 );
1487
1488 assert_matches!(
1490 with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1491 TemplateParseErrorKind::InvalidArguments { .. }
1492 );
1493 assert_matches!(
1494 with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1495 TemplateParseErrorKind::InvalidArguments { .. }
1496 );
1497 assert_matches!(
1498 with_aliases([("F(x,y)", "x ++ y")])
1499 .parse("F(a,b,c)")
1500 .unwrap_err()
1501 .kind,
1502 TemplateParseErrorKind::InvalidArguments { .. }
1503 );
1504
1505 assert_eq!(
1507 with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1508 .parse("F(a)")
1509 .unwrap_err()
1510 .kind,
1511 TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned()),
1512 );
1513 assert_eq!(
1514 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1515 .parse("F(a)")
1516 .unwrap_err()
1517 .kind,
1518 TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned())
1519 );
1520 }
1521}