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;
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
114/// Manages diagnostic messages emitted during template parsing and building.
115pub 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    /// Some other expression error.
187    pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
188        Self::with_span(TemplateParseErrorKind::Expression(message.into()), span)
189    }
190
191    /// If this is a `NoSuchKeyword` error, expands the candidates list with the
192    /// given `other_keywords`.
193    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    /// If this is a `NoSuchFunction` error, expands the candidates list with
208    /// the given `other_functions`.
209    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    /// Expands keyword/function candidates with the given aliases.
224    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    /// Original parsing error which typically occurred in an alias expression.
234    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    /// `<kind>:"<value>"`
294    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    /// 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            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                // Method call is syntactically different from function call.
334                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    /// `!`
373    LogicalNot,
374    /// `-`
375    Negate,
376}
377
378#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
379pub enum BinaryOp {
380    /// `||`
381    LogicalOr,
382    /// `&&`
383    LogicalAnd,
384    /// `==`
385    Eq,
386    /// `!=`
387    Ne,
388    /// `>=`
389    Ge,
390    /// `>`
391    Gt,
392    /// `<=`
393    Le,
394    /// `<`
395    Lt,
396    /// `+`
397    Add,
398    /// `-`
399    Sub,
400    /// `*`
401    Mul,
402    /// `/`
403    Div,
404    /// `%`
405    Rem,
406}
407
408pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
409pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
410
411#[derive(Clone, Debug, PartialEq)]
412pub struct MethodCallNode<'i> {
413    pub object: ExpressionNode<'i>,
414    pub function: FunctionCallNode<'i>,
415}
416
417#[derive(Clone, Debug, PartialEq)]
418pub struct LambdaNode<'i> {
419    pub params: Vec<&'i str>,
420    pub params_span: pest::Span<'i>,
421    pub body: ExpressionNode<'i>,
422}
423
424fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind {
425    assert_eq!(pair.as_rule(), Rule::identifier);
426    match pair.as_str() {
427        "false" => ExpressionKind::Boolean(false),
428        "true" => ExpressionKind::Boolean(true),
429        name => ExpressionKind::Identifier(name),
430    }
431}
432
433fn parse_identifier_name(pair: Pair<'_, Rule>) -> TemplateParseResult<&str> {
434    let span = pair.as_span();
435    if let ExpressionKind::Identifier(name) = parse_identifier_or_literal(pair) {
436        Ok(name)
437    } else {
438        Err(TemplateParseError::expression("Expected identifier", span))
439    }
440}
441
442fn parse_formal_parameters(params_pair: Pair<'_, Rule>) -> TemplateParseResult<Vec<&str>> {
443    assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
444    let params_span = params_pair.as_span();
445    let params: Vec<_> = params_pair
446        .into_inner()
447        .map(parse_identifier_name)
448        .try_collect()?;
449    if params.iter().all_unique() {
450        Ok(params)
451    } else {
452        Err(TemplateParseError::with_span(
453            TemplateParseErrorKind::RedefinedFunctionParameter,
454            params_span,
455        ))
456    }
457}
458
459fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> {
460    assert_eq!(pair.as_rule(), Rule::lambda);
461    let mut inner = pair.into_inner();
462    let params_pair = inner.next().unwrap();
463    let params_span = params_pair.as_span();
464    let body_pair = inner.next().unwrap();
465    let params = parse_formal_parameters(params_pair)?;
466    let body = parse_template_node(body_pair)?;
467    Ok(LambdaNode {
468        params,
469        params_span,
470        body,
471    })
472}
473
474fn parse_raw_string_literal(pair: Pair<Rule>) -> String {
475    let [content] = pair.into_inner().collect_array().unwrap();
476    assert_eq!(content.as_rule(), Rule::raw_string_content);
477    content.as_str().to_owned()
478}
479
480fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
481    assert_eq!(pair.as_rule(), Rule::term);
482    let mut inner = pair.into_inner();
483    let expr = inner.next().unwrap();
484    let span = expr.as_span();
485    let primary = match expr.as_rule() {
486        Rule::string_literal => {
487            let text = STRING_LITERAL_PARSER.parse(expr.into_inner());
488            ExpressionNode::new(ExpressionKind::String(text), span)
489        }
490        Rule::raw_string_literal => {
491            let text = parse_raw_string_literal(expr);
492            ExpressionNode::new(ExpressionKind::String(text), span)
493        }
494        Rule::integer_literal => {
495            let value = expr.as_str().parse().map_err(|err| {
496                TemplateParseError::expression("Invalid integer literal", span).with_source(err)
497            })?;
498            ExpressionNode::new(ExpressionKind::Integer(value), span)
499        }
500        Rule::string_pattern => {
501            let [kind, op, literal] = expr.into_inner().collect_array().unwrap();
502            assert_eq!(kind.as_rule(), Rule::string_pattern_identifier);
503            assert_eq!(op.as_rule(), Rule::pattern_kind_op);
504            let kind = kind.as_str();
505            let text = match literal.as_rule() {
506                Rule::string_literal => STRING_LITERAL_PARSER.parse(literal.into_inner()),
507                Rule::raw_string_literal => parse_raw_string_literal(literal),
508                other => {
509                    panic!("Unexpected literal rule in string pattern: {other:?}")
510                }
511            };
512            // The actual parsing and construction of the pattern is deferred to later.
513            ExpressionNode::new(ExpressionKind::StringPattern { kind, value: text }, span)
514        }
515        Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span),
516        Rule::function => {
517            let function = Box::new(FUNCTION_CALL_PARSER.parse(
518                expr,
519                parse_identifier_name,
520                parse_template_node,
521            )?);
522            ExpressionNode::new(ExpressionKind::FunctionCall(function), span)
523        }
524        Rule::lambda => {
525            let lambda = Box::new(parse_lambda_node(expr)?);
526            ExpressionNode::new(ExpressionKind::Lambda(lambda), span)
527        }
528        Rule::template => parse_template_node(expr)?,
529        other => panic!("unexpected term: {other:?}"),
530    };
531    inner.try_fold(primary, |object, chain| {
532        assert_eq!(chain.as_rule(), Rule::function);
533        let span = object.span.start_pos().span(&chain.as_span().end_pos());
534        let method = Box::new(MethodCallNode {
535            object,
536            function: FUNCTION_CALL_PARSER.parse(
537                chain,
538                parse_identifier_name,
539                parse_template_node,
540            )?,
541        });
542        Ok(ExpressionNode::new(
543            ExpressionKind::MethodCall(method),
544            span,
545        ))
546    })
547}
548
549fn parse_expression_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
550    assert_eq!(pair.as_rule(), Rule::expression);
551    static PRATT: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
552        PrattParser::new()
553            .op(Op::infix(Rule::logical_or_op, Assoc::Left))
554            .op(Op::infix(Rule::logical_and_op, Assoc::Left))
555            .op(Op::infix(Rule::eq_op, Assoc::Left) | Op::infix(Rule::ne_op, Assoc::Left))
556            .op(Op::infix(Rule::ge_op, Assoc::Left)
557                | Op::infix(Rule::gt_op, Assoc::Left)
558                | Op::infix(Rule::le_op, Assoc::Left)
559                | Op::infix(Rule::lt_op, Assoc::Left))
560            .op(Op::infix(Rule::add_op, Assoc::Left) | Op::infix(Rule::sub_op, Assoc::Left))
561            .op(Op::infix(Rule::mul_op, Assoc::Left)
562                | Op::infix(Rule::div_op, Assoc::Left)
563                | Op::infix(Rule::rem_op, Assoc::Left))
564            .op(Op::prefix(Rule::logical_not_op) | Op::prefix(Rule::negate_op))
565    });
566    PRATT
567        .map_primary(parse_term_node)
568        .map_prefix(|op, rhs| {
569            let op_kind = match op.as_rule() {
570                Rule::logical_not_op => UnaryOp::LogicalNot,
571                Rule::negate_op => UnaryOp::Negate,
572                r => panic!("unexpected prefix operator rule {r:?}"),
573            };
574            let rhs = Box::new(rhs?);
575            let span = op.as_span().start_pos().span(&rhs.span.end_pos());
576            let expr = ExpressionKind::Unary(op_kind, rhs);
577            Ok(ExpressionNode::new(expr, span))
578        })
579        .map_infix(|lhs, op, rhs| {
580            let op_kind = match op.as_rule() {
581                Rule::logical_or_op => BinaryOp::LogicalOr,
582                Rule::logical_and_op => BinaryOp::LogicalAnd,
583                Rule::eq_op => BinaryOp::Eq,
584                Rule::ne_op => BinaryOp::Ne,
585                Rule::ge_op => BinaryOp::Ge,
586                Rule::gt_op => BinaryOp::Gt,
587                Rule::le_op => BinaryOp::Le,
588                Rule::lt_op => BinaryOp::Lt,
589                Rule::add_op => BinaryOp::Add,
590                Rule::sub_op => BinaryOp::Sub,
591                Rule::mul_op => BinaryOp::Mul,
592                Rule::div_op => BinaryOp::Div,
593                Rule::rem_op => BinaryOp::Rem,
594                r => panic!("unexpected infix operator rule {r:?}"),
595            };
596            let lhs = Box::new(lhs?);
597            let rhs = Box::new(rhs?);
598            let span = lhs.span.start_pos().span(&rhs.span.end_pos());
599            let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
600            Ok(ExpressionNode::new(expr, span))
601        })
602        .parse(pair.into_inner())
603}
604
605fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
606    assert_eq!(pair.as_rule(), Rule::template);
607    let span = pair.as_span();
608    let inner = pair.into_inner();
609    let mut nodes: Vec<_> = inner
610        .filter_map(|pair| match pair.as_rule() {
611            Rule::concat_op => None,
612            Rule::expression => Some(parse_expression_node(pair)),
613            r => panic!("unexpected template item rule {r:?}"),
614        })
615        .try_collect()?;
616    if nodes.len() == 1 {
617        Ok(nodes.pop().unwrap())
618    } else {
619        Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span))
620    }
621}
622
623/// Parses text into AST nodes. No type/name checking is made at this stage.
624pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode<'_>> {
625    let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?;
626    let first_pair = pairs.next().unwrap();
627    if first_pair.as_rule() == Rule::EOI {
628        let span = first_pair.as_span();
629        Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span))
630    } else {
631        parse_template_node(first_pair)
632    }
633}
634
635pub type TemplateAliasesMap = AliasesMap<TemplateAliasParser, String>;
636
637#[derive(Clone, Debug, Default)]
638pub struct TemplateAliasParser;
639
640impl AliasDeclarationParser for TemplateAliasParser {
641    type Error = TemplateParseError;
642
643    fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
644        let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?;
645        let first = pairs.next().unwrap();
646        match first.as_rule() {
647            Rule::identifier => {
648                let name = parse_identifier_name(first)?.to_owned();
649                Ok(AliasDeclaration::Symbol(name))
650            }
651            Rule::function_alias_declaration => {
652                let mut inner = first.into_inner();
653                let name_pair = inner.next().unwrap();
654                let params_pair = inner.next().unwrap();
655                let name = parse_identifier_name(name_pair)?.to_owned();
656                let params = parse_formal_parameters(params_pair)?
657                    .into_iter()
658                    .map(|s| s.to_owned())
659                    .collect();
660                Ok(AliasDeclaration::Function(name, params))
661            }
662            r => panic!("unexpected alias declaration rule {r:?}"),
663        }
664    }
665}
666
667impl AliasDefinitionParser for TemplateAliasParser {
668    type Output<'i> = ExpressionKind<'i>;
669    type Error = TemplateParseError;
670
671    fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
672        parse_template(source)
673    }
674}
675
676/// Parses text into AST nodes, and expands aliases.
677///
678/// No type/name checking is made at this stage.
679pub fn parse<'i>(
680    template_text: &'i str,
681    aliases_map: &'i TemplateAliasesMap,
682) -> TemplateParseResult<ExpressionNode<'i>> {
683    let node = parse_template(template_text)?;
684    dsl_util::expand_aliases(node, aliases_map)
685}
686
687/// Unwraps inner value if the given `node` is a string literal.
688pub fn expect_string_literal<'a>(node: &'a ExpressionNode<'_>) -> TemplateParseResult<&'a str> {
689    catch_aliases_no_diagnostics(node, |node| match &node.kind {
690        ExpressionKind::String(s) => Ok(s.as_str()),
691        _ => Err(TemplateParseError::expression(
692            "Expected string literal",
693            node.span,
694        )),
695    })
696}
697
698/// Unwraps inner value if the given `node` is a string pattern
699///
700/// This forces it to be static so that it need not be part of the type system.
701pub fn expect_string_pattern(node: &ExpressionNode<'_>) -> TemplateParseResult<StringPattern> {
702    catch_aliases_no_diagnostics(node, |node| match &node.kind {
703        ExpressionKind::StringPattern { kind, value } => StringPattern::from_str_kind(value, kind)
704            .map_err(|err| {
705                TemplateParseError::expression("Bad string pattern", node.span).with_source(err)
706            }),
707        ExpressionKind::String(string) => Ok(StringPattern::Substring(string.clone())),
708        _ => Err(TemplateParseError::expression(
709            "Expected string pattern",
710            node.span,
711        )),
712    })
713}
714
715/// Unwraps inner node if the given `node` is a lambda.
716pub fn expect_lambda<'a, 'i>(
717    node: &'a ExpressionNode<'i>,
718) -> TemplateParseResult<&'a LambdaNode<'i>> {
719    catch_aliases_no_diagnostics(node, |node| match &node.kind {
720        ExpressionKind::Lambda(lambda) => Ok(lambda.as_ref()),
721        _ => Err(TemplateParseError::expression(
722            "Expected lambda expression",
723            node.span,
724        )),
725    })
726}
727
728/// Applies the given function to the innermost `node` by unwrapping alias
729/// expansion nodes. Appends alias expansion stack to error and diagnostics.
730pub fn catch_aliases<'a, 'i, T>(
731    diagnostics: &mut TemplateDiagnostics,
732    node: &'a ExpressionNode<'i>,
733    f: impl FnOnce(&mut TemplateDiagnostics, &'a ExpressionNode<'i>) -> TemplateParseResult<T>,
734) -> TemplateParseResult<T> {
735    let (node, stack) = skip_aliases(node);
736    if stack.is_empty() {
737        f(diagnostics, node)
738    } else {
739        let mut inner_diagnostics = TemplateDiagnostics::new();
740        let result = f(&mut inner_diagnostics, node);
741        diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
742        result.map_err(|err| attach_aliases_err(err, &stack))
743    }
744}
745
746fn catch_aliases_no_diagnostics<'a, 'i, T>(
747    node: &'a ExpressionNode<'i>,
748    f: impl FnOnce(&'a ExpressionNode<'i>) -> TemplateParseResult<T>,
749) -> TemplateParseResult<T> {
750    let (node, stack) = skip_aliases(node);
751    f(node).map_err(|err| attach_aliases_err(err, &stack))
752}
753
754fn skip_aliases<'a, 'i>(
755    mut node: &'a ExpressionNode<'i>,
756) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
757    let mut stack = Vec::new();
758    while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
759        stack.push((*id, node.span));
760        node = subst;
761    }
762    (node, stack)
763}
764
765fn attach_aliases_err(
766    err: TemplateParseError,
767    stack: &[(AliasId<'_>, pest::Span<'_>)],
768) -> TemplateParseError {
769    stack
770        .iter()
771        .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
772}
773
774/// Looks up `table` by the given function name.
775pub fn lookup_function<'a, V>(
776    table: &'a HashMap<&str, V>,
777    function: &FunctionCallNode,
778) -> TemplateParseResult<&'a V> {
779    if let Some(value) = table.get(function.name) {
780        Ok(value)
781    } else {
782        let candidates = collect_similar(function.name, table.keys());
783        Err(TemplateParseError::with_span(
784            TemplateParseErrorKind::NoSuchFunction {
785                name: function.name.to_owned(),
786                candidates,
787            },
788            function.name_span,
789        ))
790    }
791}
792
793/// Looks up `table` by the given method name.
794pub fn lookup_method<'a, V>(
795    type_name: impl Into<String>,
796    table: &'a HashMap<&str, V>,
797    function: &FunctionCallNode,
798) -> TemplateParseResult<&'a V> {
799    if let Some(value) = table.get(function.name) {
800        Ok(value)
801    } else {
802        let candidates = collect_similar(function.name, table.keys());
803        Err(TemplateParseError::with_span(
804            TemplateParseErrorKind::NoSuchMethod {
805                type_name: type_name.into(),
806                name: function.name.to_owned(),
807                candidates,
808            },
809            function.name_span,
810        ))
811    }
812}
813
814#[cfg(test)]
815mod tests {
816    use assert_matches::assert_matches;
817    use jj_lib::dsl_util::KeywordArgument;
818
819    use super::*;
820
821    #[derive(Debug)]
822    struct WithTemplateAliasesMap(TemplateAliasesMap);
823
824    impl WithTemplateAliasesMap {
825        fn parse<'i>(&'i self, template_text: &'i str) -> TemplateParseResult<ExpressionNode<'i>> {
826            parse(template_text, &self.0)
827        }
828
829        fn parse_normalized<'i>(&'i self, template_text: &'i str) -> ExpressionNode<'i> {
830            normalize_tree(self.parse(template_text).unwrap())
831        }
832    }
833
834    fn with_aliases(
835        aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
836    ) -> WithTemplateAliasesMap {
837        let mut aliases_map = TemplateAliasesMap::new();
838        for (decl, defn) in aliases {
839            aliases_map.insert(decl, defn).unwrap();
840        }
841        WithTemplateAliasesMap(aliases_map)
842    }
843
844    fn parse_into_kind(template_text: &str) -> Result<ExpressionKind<'_>, TemplateParseErrorKind> {
845        parse_template(template_text)
846            .map(|node| node.kind)
847            .map_err(|err| err.kind)
848    }
849
850    fn parse_normalized(template_text: &str) -> ExpressionNode<'_> {
851        normalize_tree(parse_template(template_text).unwrap())
852    }
853
854    /// Drops auxiliary data of AST so it can be compared with other node.
855    fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
856        fn empty_span() -> pest::Span<'static> {
857            pest::Span::new("", 0, 0).unwrap()
858        }
859
860        fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
861            nodes.into_iter().map(normalize_tree).collect()
862        }
863
864        fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
865            FunctionCallNode {
866                name: function.name,
867                name_span: empty_span(),
868                args: normalize_list(function.args),
869                keyword_args: function
870                    .keyword_args
871                    .into_iter()
872                    .map(|arg| KeywordArgument {
873                        name: arg.name,
874                        name_span: empty_span(),
875                        value: normalize_tree(arg.value),
876                    })
877                    .collect(),
878                args_span: empty_span(),
879            }
880        }
881
882        let normalized_kind = match node.kind {
883            ExpressionKind::Identifier(_)
884            | ExpressionKind::Boolean(_)
885            | ExpressionKind::Integer(_)
886            | ExpressionKind::String(_) => node.kind,
887            ExpressionKind::StringPattern { .. } => node.kind,
888            ExpressionKind::Unary(op, arg) => {
889                let arg = Box::new(normalize_tree(*arg));
890                ExpressionKind::Unary(op, arg)
891            }
892            ExpressionKind::Binary(op, lhs, rhs) => {
893                let lhs = Box::new(normalize_tree(*lhs));
894                let rhs = Box::new(normalize_tree(*rhs));
895                ExpressionKind::Binary(op, lhs, rhs)
896            }
897            ExpressionKind::Concat(nodes) => ExpressionKind::Concat(normalize_list(nodes)),
898            ExpressionKind::FunctionCall(function) => {
899                let function = Box::new(normalize_function_call(*function));
900                ExpressionKind::FunctionCall(function)
901            }
902            ExpressionKind::MethodCall(method) => {
903                let method = Box::new(MethodCallNode {
904                    object: normalize_tree(method.object),
905                    function: normalize_function_call(method.function),
906                });
907                ExpressionKind::MethodCall(method)
908            }
909            ExpressionKind::Lambda(lambda) => {
910                let lambda = Box::new(LambdaNode {
911                    params: lambda.params,
912                    params_span: empty_span(),
913                    body: normalize_tree(lambda.body),
914                });
915                ExpressionKind::Lambda(lambda)
916            }
917            ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
918        };
919        ExpressionNode {
920            kind: normalized_kind,
921            span: empty_span(),
922        }
923    }
924
925    #[test]
926    fn test_parse_tree_eq() {
927        assert_eq!(
928            normalize_tree(parse_template(r#" commit_id.short(1 )  ++ description"#).unwrap()),
929            normalize_tree(parse_template(r#"commit_id.short( 1 )++(description)"#).unwrap()),
930        );
931        assert_ne!(
932            normalize_tree(parse_template(r#" "ab" "#).unwrap()),
933            normalize_tree(parse_template(r#" "a" ++ "b" "#).unwrap()),
934        );
935        assert_ne!(
936            normalize_tree(parse_template(r#" "foo" ++ "0" "#).unwrap()),
937            normalize_tree(parse_template(r#" "foo" ++ 0 "#).unwrap()),
938        );
939    }
940
941    #[test]
942    fn test_parse_whitespace() {
943        let ascii_whitespaces: String = ('\x00'..='\x7f')
944            .filter(char::is_ascii_whitespace)
945            .collect();
946        assert_eq!(
947            parse_normalized(&format!("{ascii_whitespaces}f()")),
948            parse_normalized("f()"),
949        );
950    }
951
952    #[test]
953    fn test_parse_operator_syntax() {
954        // Operator precedence
955        assert_eq!(parse_normalized("!!x"), parse_normalized("!(!x)"));
956        assert_eq!(
957            parse_normalized("!x.f() || !g()"),
958            parse_normalized("(!(x.f())) || (!(g()))"),
959        );
960        assert_eq!(
961            parse_normalized("!x.f() <= !x.f()"),
962            parse_normalized("((!(x.f())) <= (!(x.f())))"),
963        );
964        assert_eq!(
965            parse_normalized("!x.f() < !x.f() == !x.f() >= !x.f() || !g() != !g()"),
966            parse_normalized(
967                "((!(x.f()) < (!(x.f()))) == ((!(x.f())) >= (!(x.f())))) || ((!(g())) != (!(g())))"
968            ),
969        );
970        assert_eq!(
971            parse_normalized("x.f() || y == y || z"),
972            parse_normalized("((x.f()) || (y == y)) || z"),
973        );
974        assert_eq!(
975            parse_normalized("x || y == y && z.h() == z"),
976            parse_normalized("x || ((y == y) && ((z.h()) == z))"),
977        );
978        assert_eq!(
979            parse_normalized("x == y || y != z && !z"),
980            parse_normalized("(x == y) || ((y != z) && (!z))"),
981        );
982        assert_eq!(
983            parse_normalized("a + b * c / d % e - -f == g"),
984            parse_normalized("((a + (((b * c) / d) % e)) - (-f)) == g"),
985        );
986
987        // Logical operator bounds more tightly than concatenation. This might
988        // not be so intuitive, but should be harmless.
989        assert_eq!(
990            parse_normalized(r"x && y ++ z"),
991            parse_normalized(r"(x && y) ++ z"),
992        );
993        assert_eq!(
994            parse_normalized(r"x ++ y || z"),
995            parse_normalized(r"x ++ (y || z)"),
996        );
997        assert_eq!(
998            parse_normalized(r"x == y ++ z"),
999            parse_normalized(r"(x == y) ++ z"),
1000        );
1001        assert_eq!(
1002            parse_normalized(r"x != y ++ z"),
1003            parse_normalized(r"(x != y) ++ z"),
1004        );
1005
1006        // Expression span
1007        assert_eq!(parse_template(" ! x ").unwrap().span.as_str(), "! x");
1008        assert_eq!(parse_template(" x ||y ").unwrap().span.as_str(), "x ||y");
1009    }
1010
1011    #[test]
1012    fn test_function_call_syntax() {
1013        // Trailing comma isn't allowed for empty argument
1014        assert!(parse_template(r#" "".first_line() "#).is_ok());
1015        assert!(parse_template(r#" "".first_line(,) "#).is_err());
1016
1017        // Trailing comma is allowed for the last argument
1018        assert!(parse_template(r#" "".contains("") "#).is_ok());
1019        assert!(parse_template(r#" "".contains("",) "#).is_ok());
1020        assert!(parse_template(r#" "".contains("" ,  ) "#).is_ok());
1021        assert!(parse_template(r#" "".contains(,"") "#).is_err());
1022        assert!(parse_template(r#" "".contains("",,) "#).is_err());
1023        assert!(parse_template(r#" "".contains("" , , ) "#).is_err());
1024        assert!(parse_template(r#" label("","") "#).is_ok());
1025        assert!(parse_template(r#" label("","",) "#).is_ok());
1026        assert!(parse_template(r#" label("",,"") "#).is_err());
1027
1028        // Keyword arguments
1029        assert!(parse_template("f(foo = bar)").is_ok());
1030        assert!(parse_template("f( foo=bar )").is_ok());
1031        assert!(parse_template("x.f(foo, bar=0, baz=1)").is_ok());
1032
1033        // Boolean literal cannot be used as a function name
1034        assert!(parse_template("false()").is_err());
1035        // Boolean literal cannot be used as a parameter name
1036        assert!(parse_template("f(false=0)").is_err());
1037        // Function arguments can be any expression
1038        assert!(parse_template("f(false)").is_ok());
1039    }
1040
1041    #[test]
1042    fn test_method_call_syntax() {
1043        assert_eq!(
1044            parse_normalized("x.f().g()"),
1045            parse_normalized("(x.f()).g()"),
1046        );
1047
1048        // Expression span
1049        assert_eq!(parse_template(" x.f() ").unwrap().span.as_str(), "x.f()");
1050        assert_eq!(
1051            parse_template(" x.f().g() ").unwrap().span.as_str(),
1052            "x.f().g()",
1053        );
1054    }
1055
1056    #[test]
1057    fn test_lambda_syntax() {
1058        fn unwrap_lambda(node: ExpressionNode<'_>) -> Box<LambdaNode<'_>> {
1059            match node.kind {
1060                ExpressionKind::Lambda(lambda) => lambda,
1061                _ => panic!("unexpected expression: {node:?}"),
1062            }
1063        }
1064
1065        let lambda = unwrap_lambda(parse_template("|| a").unwrap());
1066        assert_eq!(lambda.params.len(), 0);
1067        assert_eq!(lambda.body.kind, ExpressionKind::Identifier("a"));
1068        let lambda = unwrap_lambda(parse_template("|foo| a").unwrap());
1069        assert_eq!(lambda.params.len(), 1);
1070        let lambda = unwrap_lambda(parse_template("|foo, b| a").unwrap());
1071        assert_eq!(lambda.params.len(), 2);
1072
1073        // No body
1074        assert!(parse_template("||").is_err());
1075
1076        // Binding
1077        assert_eq!(
1078            parse_normalized("||  x ++ y"),
1079            parse_normalized("|| (x ++ y)"),
1080        );
1081        assert_eq!(
1082            parse_normalized("f( || x,   || y)"),
1083            parse_normalized("f((|| x), (|| y))"),
1084        );
1085        assert_eq!(
1086            parse_normalized("||  x ++  || y"),
1087            parse_normalized("|| (x ++ (|| y))"),
1088        );
1089
1090        // Lambda vs logical operator: weird, but this is type error anyway
1091        assert_eq!(parse_normalized("x||||y"), parse_normalized("x || (|| y)"));
1092        assert_eq!(parse_normalized("||||x"), parse_normalized("|| (|| x)"));
1093
1094        // Trailing comma
1095        assert!(parse_template("|,| a").is_err());
1096        assert!(parse_template("|x,| a").is_ok());
1097        assert!(parse_template("|x , | a").is_ok());
1098        assert!(parse_template("|,x| a").is_err());
1099        assert!(parse_template("| x,y,| a").is_ok());
1100        assert!(parse_template("|x,,y| a").is_err());
1101
1102        // Formal parameter can't be redefined
1103        assert_eq!(
1104            parse_template("|x, x| a").unwrap_err().kind,
1105            TemplateParseErrorKind::RedefinedFunctionParameter
1106        );
1107
1108        // Boolean literal cannot be used as a parameter name
1109        assert!(parse_template("|false| a").is_err());
1110    }
1111
1112    #[test]
1113    fn test_keyword_literal() {
1114        assert_eq!(parse_into_kind("false"), Ok(ExpressionKind::Boolean(false)));
1115        assert_eq!(parse_into_kind("(true)"), Ok(ExpressionKind::Boolean(true)));
1116        // Keyword literals are case sensitive
1117        assert_eq!(
1118            parse_into_kind("False"),
1119            Ok(ExpressionKind::Identifier("False")),
1120        );
1121        assert_eq!(
1122            parse_into_kind("tRue"),
1123            Ok(ExpressionKind::Identifier("tRue")),
1124        );
1125    }
1126
1127    #[test]
1128    fn test_string_literal() {
1129        // Whitespace in string literal should be preserved
1130        assert_eq!(
1131            parse_into_kind(r#" " " "#),
1132            Ok(ExpressionKind::String(" ".to_owned())),
1133        );
1134        assert_eq!(
1135            parse_into_kind(r#" ' ' "#),
1136            Ok(ExpressionKind::String(" ".to_owned())),
1137        );
1138
1139        // "\<char>" escapes
1140        assert_eq!(
1141            parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1142            Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned())),
1143        );
1144
1145        // Invalid "\<char>" escape
1146        assert_eq!(
1147            parse_into_kind(r#" "\y" "#),
1148            Err(TemplateParseErrorKind::SyntaxError),
1149        );
1150
1151        // Single-quoted raw string
1152        assert_eq!(
1153            parse_into_kind(r#" '' "#),
1154            Ok(ExpressionKind::String("".to_owned())),
1155        );
1156        assert_eq!(
1157            parse_into_kind(r#" 'a\n' "#),
1158            Ok(ExpressionKind::String(r"a\n".to_owned())),
1159        );
1160        assert_eq!(
1161            parse_into_kind(r#" '\' "#),
1162            Ok(ExpressionKind::String(r"\".to_owned())),
1163        );
1164        assert_eq!(
1165            parse_into_kind(r#" '"' "#),
1166            Ok(ExpressionKind::String(r#"""#.to_owned())),
1167        );
1168
1169        // Hex bytes
1170        assert_eq!(
1171            parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1172            Ok(ExpressionKind::String("aeiou".to_owned())),
1173        );
1174        assert_eq!(
1175            parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1176            Ok(ExpressionKind::String("àèìðù".to_owned())),
1177        );
1178        assert_eq!(
1179            parse_into_kind(r#""\x""#),
1180            Err(TemplateParseErrorKind::SyntaxError),
1181        );
1182        assert_eq!(
1183            parse_into_kind(r#""\xf""#),
1184            Err(TemplateParseErrorKind::SyntaxError),
1185        );
1186        assert_eq!(
1187            parse_into_kind(r#""\xgg""#),
1188            Err(TemplateParseErrorKind::SyntaxError),
1189        );
1190    }
1191
1192    #[test]
1193    fn test_string_pattern() {
1194        assert_eq!(
1195            parse_into_kind(r#"regex:"meow""#),
1196            Ok(ExpressionKind::StringPattern {
1197                kind: "regex",
1198                value: "meow".to_owned()
1199            }),
1200        );
1201        assert_eq!(
1202            parse_into_kind(r#"regex:'\r\n'"#),
1203            Ok(ExpressionKind::StringPattern {
1204                kind: "regex",
1205                value: r#"\r\n"#.to_owned()
1206            })
1207        );
1208        assert_eq!(
1209            parse_into_kind(r#"regex-i:'\r\n'"#),
1210            Ok(ExpressionKind::StringPattern {
1211                kind: "regex-i",
1212                value: r#"\r\n"#.to_owned()
1213            })
1214        );
1215        assert_eq!(
1216            parse_into_kind("regex:meow"),
1217            Err(TemplateParseErrorKind::SyntaxError),
1218            "no bare words in string patterns in templates"
1219        );
1220        assert_eq!(
1221            parse_into_kind("regex: 'with spaces'"),
1222            Err(TemplateParseErrorKind::SyntaxError),
1223            "no spaces after"
1224        );
1225        assert_eq!(
1226            parse_into_kind("regex :'with spaces'"),
1227            Err(TemplateParseErrorKind::SyntaxError),
1228            "no spaces before either"
1229        );
1230        assert_eq!(
1231            parse_into_kind("regex : 'with spaces'"),
1232            Err(TemplateParseErrorKind::SyntaxError),
1233            "certainly not both"
1234        );
1235    }
1236
1237    #[test]
1238    fn test_integer_literal() {
1239        assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Integer(0)));
1240        assert_eq!(parse_into_kind("(42)"), Ok(ExpressionKind::Integer(42)));
1241        assert_eq!(
1242            parse_into_kind("00"),
1243            Err(TemplateParseErrorKind::SyntaxError),
1244        );
1245
1246        assert_eq!(
1247            parse_into_kind(&format!("{}", i64::MAX)),
1248            Ok(ExpressionKind::Integer(i64::MAX)),
1249        );
1250        assert_matches!(
1251            parse_into_kind(&format!("{}", (i64::MAX as u64) + 1)),
1252            Err(TemplateParseErrorKind::Expression(_))
1253        );
1254    }
1255
1256    #[test]
1257    fn test_parse_alias_decl() {
1258        let mut aliases_map = TemplateAliasesMap::new();
1259        aliases_map.insert("sym", r#""is symbol""#).unwrap();
1260        aliases_map.insert("func()", r#""is function 0""#).unwrap();
1261        aliases_map
1262            .insert("func(a, b)", r#""is function 2""#)
1263            .unwrap();
1264        aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1265        aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1266
1267        let (id, defn) = aliases_map.get_symbol("sym").unwrap();
1268        assert_eq!(id, AliasId::Symbol("sym"));
1269        assert_eq!(defn, r#""is symbol""#);
1270
1271        let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1272        assert_eq!(id, AliasId::Function("func", &[]));
1273        assert!(params.is_empty());
1274        assert_eq!(defn, r#""is function 0""#);
1275
1276        let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1277        assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1278        assert_eq!(params, ["b"]);
1279        assert_eq!(defn, r#""is function b""#);
1280
1281        let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1282        assert_eq!(
1283            id,
1284            AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1285        );
1286        assert_eq!(params, ["a", "b"]);
1287        assert_eq!(defn, r#""is function 2""#);
1288
1289        assert!(aliases_map.get_function("func", 3).is_none());
1290
1291        // Formal parameter 'a' can't be redefined
1292        assert_eq!(
1293            aliases_map.insert("f(a, a)", r#""""#).unwrap_err().kind,
1294            TemplateParseErrorKind::RedefinedFunctionParameter
1295        );
1296
1297        // Boolean literal cannot be used as a symbol, function, or parameter name
1298        assert!(aliases_map.insert("false", r#"""#).is_err());
1299        assert!(aliases_map.insert("true()", r#"""#).is_err());
1300        assert!(aliases_map.insert("f(false)", r#"""#).is_err());
1301
1302        // Trailing comma isn't allowed for empty parameter
1303        assert!(aliases_map.insert("f(,)", r#"""#).is_err());
1304        // Trailing comma is allowed for the last parameter
1305        assert!(aliases_map.insert("g(a,)", r#"""#).is_ok());
1306        assert!(aliases_map.insert("h(a ,  )", r#"""#).is_ok());
1307        assert!(aliases_map.insert("i(,a)", r#"""#).is_err());
1308        assert!(aliases_map.insert("j(a,,)", r#"""#).is_err());
1309        assert!(aliases_map.insert("k(a  , , )", r#"""#).is_err());
1310        assert!(aliases_map.insert("l(a,b,)", r#"""#).is_ok());
1311        assert!(aliases_map.insert("m(a,,b)", r#"""#).is_err());
1312    }
1313
1314    #[test]
1315    fn test_expand_symbol_alias() {
1316        assert_eq!(
1317            with_aliases([("AB", "a ++ b")]).parse_normalized("AB ++ c"),
1318            parse_normalized("(a ++ b) ++ c"),
1319        );
1320        assert_eq!(
1321            with_aliases([("AB", "a ++ b")]).parse_normalized("if(AB, label(c, AB))"),
1322            parse_normalized("if((a ++ b), label(c, (a ++ b)))"),
1323        );
1324
1325        // Multi-level substitution.
1326        assert_eq!(
1327            with_aliases([("A", "BC"), ("BC", "b ++ C"), ("C", "c")]).parse_normalized("A"),
1328            parse_normalized("b ++ c"),
1329        );
1330
1331        // Operator expression can be expanded in concatenation.
1332        assert_eq!(
1333            with_aliases([("AB", "a || b")]).parse_normalized("AB ++ c"),
1334            parse_normalized("(a || b) ++ c"),
1335        );
1336
1337        // Operands should be expanded.
1338        assert_eq!(
1339            with_aliases([("A", "a"), ("B", "b")]).parse_normalized("A || !B"),
1340            parse_normalized("a || !b"),
1341        );
1342
1343        // Method receiver and arguments should be expanded.
1344        assert_eq!(
1345            with_aliases([("A", "a")]).parse_normalized("A.f()"),
1346            parse_normalized("a.f()"),
1347        );
1348        assert_eq!(
1349            with_aliases([("A", "a"), ("B", "b")]).parse_normalized("x.f(A, B)"),
1350            parse_normalized("x.f(a, b)"),
1351        );
1352
1353        // Lambda expression body should be expanded.
1354        assert_eq!(
1355            with_aliases([("A", "a")]).parse_normalized("|| A"),
1356            parse_normalized("|| a"),
1357        );
1358        // No matter if 'A' is a formal parameter. Alias substitution isn't scoped.
1359        // If we don't like this behavior, maybe we can turn off alias substitution
1360        // for lambda parameters.
1361        assert_eq!(
1362            with_aliases([("A", "a ++ b")]).parse_normalized("|A| A"),
1363            parse_normalized("|A| (a ++ b)"),
1364        );
1365
1366        // Infinite recursion, where the top-level error isn't of RecursiveAlias kind.
1367        assert_eq!(
1368            with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1369            TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1370        );
1371        assert_eq!(
1372            with_aliases([("A", "B"), ("B", "b ++ C"), ("C", "c ++ B")])
1373                .parse("A")
1374                .unwrap_err()
1375                .kind,
1376            TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1377        );
1378
1379        // Error in alias definition.
1380        assert_eq!(
1381            with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1382            TemplateParseErrorKind::InAliasExpansion("A".to_owned()),
1383        );
1384    }
1385
1386    #[test]
1387    fn test_expand_function_alias() {
1388        assert_eq!(
1389            with_aliases([("F(  )", "a")]).parse_normalized("F()"),
1390            parse_normalized("a"),
1391        );
1392        assert_eq!(
1393            with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1394            parse_normalized("a"),
1395        );
1396        assert_eq!(
1397            with_aliases([("F( x, y )", "x ++ y")]).parse_normalized("F(a, b)"),
1398            parse_normalized("a ++ b"),
1399        );
1400
1401        // Not recursion because functions are overloaded by arity.
1402        assert_eq!(
1403            with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x ++ y")]).parse_normalized("F(a)"),
1404            parse_normalized("a ++ b")
1405        );
1406
1407        // Arguments should be resolved in the current scope.
1408        assert_eq!(
1409            with_aliases([("F(x,y)", "if(x, y)")]).parse_normalized("F(a ++ y, b ++ x)"),
1410            parse_normalized("if((a ++ y), (b ++ x))"),
1411        );
1412        // F(a) -> if(G(a), y) -> if((x ++ a), y)
1413        assert_eq!(
1414            with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(a)"),
1415            parse_normalized("if((x ++ a), y)"),
1416        );
1417        // F(G(a)) -> F(x ++ a) -> if(G(x ++ a), y) -> if((x ++ (x ++ a)), y)
1418        assert_eq!(
1419            with_aliases([("F(x)", "if(G(x), y)"), ("G(y)", "x ++ y")]).parse_normalized("F(G(a))"),
1420            parse_normalized("if((x ++ (x ++ a)), y)"),
1421        );
1422
1423        // Function parameter should precede the symbol alias.
1424        assert_eq!(
1425            with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a) ++ X"),
1426            parse_normalized("a ++ x"),
1427        );
1428
1429        // Function parameter shouldn't be expanded in symbol alias.
1430        assert_eq!(
1431            with_aliases([("F(x)", "x ++ A"), ("A", "x")]).parse_normalized("F(a)"),
1432            parse_normalized("a ++ x"),
1433        );
1434
1435        // Function and symbol aliases reside in separate namespaces.
1436        assert_eq!(
1437            with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1438            parse_normalized("a"),
1439        );
1440
1441        // Method call shouldn't be substituted by function alias.
1442        assert_eq!(
1443            with_aliases([("F()", "f()")]).parse_normalized("x.F()"),
1444            parse_normalized("x.F()"),
1445        );
1446
1447        // Formal parameter shouldn't be substituted by alias parameter, but
1448        // the expression should be substituted.
1449        assert_eq!(
1450            with_aliases([("F(x)", "|x| x")]).parse_normalized("F(a ++ b)"),
1451            parse_normalized("|x| (a ++ b)"),
1452        );
1453
1454        // Invalid number of arguments.
1455        assert_matches!(
1456            with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1457            TemplateParseErrorKind::InvalidArguments { .. }
1458        );
1459        assert_matches!(
1460            with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1461            TemplateParseErrorKind::InvalidArguments { .. }
1462        );
1463        assert_matches!(
1464            with_aliases([("F(x,y)", "x ++ y")])
1465                .parse("F(a,b,c)")
1466                .unwrap_err()
1467                .kind,
1468            TemplateParseErrorKind::InvalidArguments { .. }
1469        );
1470
1471        // Infinite recursion, where the top-level error isn't of RecursiveAlias kind.
1472        assert_eq!(
1473            with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1474                .parse("F(a)")
1475                .unwrap_err()
1476                .kind,
1477            TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned()),
1478        );
1479        assert_eq!(
1480            with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1481                .parse("F(a)")
1482                .unwrap_err()
1483                .kind,
1484            TemplateParseErrorKind::InAliasExpansion("F(x)".to_owned())
1485        );
1486    }
1487}