jj_cli/
template_parser.rs

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