jj_lib/
revset_parser.rs

1// Copyright 2021-2024 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
15#![expect(missing_docs)]
16
17use std::collections::HashSet;
18use std::error;
19use std::mem;
20use std::str::FromStr;
21use std::sync::LazyLock;
22
23use itertools::Itertools as _;
24use pest::Parser as _;
25use pest::iterators::Pair;
26use pest::pratt_parser::Assoc;
27use pest::pratt_parser::Op;
28use pest::pratt_parser::PrattParser;
29use pest_derive::Parser;
30use thiserror::Error;
31
32use crate::dsl_util;
33use crate::dsl_util::AliasDeclaration;
34use crate::dsl_util::AliasDeclarationParser;
35use crate::dsl_util::AliasDefinitionParser;
36use crate::dsl_util::AliasExpandError;
37use crate::dsl_util::AliasExpandableExpression;
38use crate::dsl_util::AliasId;
39use crate::dsl_util::AliasesMap;
40use crate::dsl_util::Diagnostics;
41use crate::dsl_util::ExpressionFolder;
42use crate::dsl_util::FoldableExpression;
43use crate::dsl_util::FunctionCallParser;
44use crate::dsl_util::InvalidArguments;
45use crate::dsl_util::StringLiteralParser;
46use crate::dsl_util::collect_similar;
47use crate::ref_name::RefNameBuf;
48use crate::ref_name::RemoteNameBuf;
49use crate::ref_name::RemoteRefSymbolBuf;
50
51#[derive(Parser)]
52#[grammar = "revset.pest"]
53struct RevsetParser;
54
55const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
56    content_rule: Rule::string_content,
57    escape_rule: Rule::string_escape,
58};
59const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser {
60    function_name_rule: Rule::function_name,
61    function_arguments_rule: Rule::function_arguments,
62    keyword_argument_rule: Rule::keyword_argument,
63    argument_name_rule: Rule::strict_identifier,
64    argument_value_rule: Rule::expression,
65};
66
67impl Rule {
68    /// Whether this is a placeholder rule for compatibility with the other
69    /// systems.
70    fn is_compat(&self) -> bool {
71        matches!(
72            self,
73            Self::compat_parents_op
74                | Self::compat_dag_range_op
75                | Self::compat_dag_range_pre_op
76                | Self::compat_dag_range_post_op
77                | Self::compat_add_op
78                | Self::compat_sub_op
79        )
80    }
81
82    fn to_symbol(self) -> Option<&'static str> {
83        match self {
84            Self::EOI => None,
85            Self::whitespace => None,
86            Self::identifier_part => None,
87            Self::identifier => None,
88            Self::strict_identifier_part => None,
89            Self::strict_identifier => None,
90            Self::symbol => None,
91            Self::string_escape => None,
92            Self::string_content_char => None,
93            Self::string_content => None,
94            Self::string_literal => None,
95            Self::raw_string_content => None,
96            Self::raw_string_literal => None,
97            Self::at_op => Some("@"),
98            Self::pattern_kind_op => Some(":"),
99            Self::parents_op => Some("-"),
100            Self::children_op => Some("+"),
101            Self::compat_parents_op => Some("^"),
102            Self::dag_range_op
103            | Self::dag_range_pre_op
104            | Self::dag_range_post_op
105            | Self::dag_range_all_op => Some("::"),
106            Self::compat_dag_range_op
107            | Self::compat_dag_range_pre_op
108            | Self::compat_dag_range_post_op => Some(":"),
109            Self::range_op => Some(".."),
110            Self::range_pre_op | Self::range_post_op | Self::range_all_op => Some(".."),
111            Self::range_ops => None,
112            Self::range_pre_ops => None,
113            Self::range_post_ops => None,
114            Self::range_all_ops => None,
115            Self::negate_op => Some("~"),
116            Self::union_op => Some("|"),
117            Self::intersection_op => Some("&"),
118            Self::difference_op => Some("~"),
119            Self::compat_add_op => Some("+"),
120            Self::compat_sub_op => Some("-"),
121            Self::infix_op => None,
122            Self::function => None,
123            Self::function_name => None,
124            Self::keyword_argument => None,
125            Self::argument => None,
126            Self::function_arguments => None,
127            Self::formal_parameters => None,
128            Self::string_pattern => None,
129            Self::primary => None,
130            Self::neighbors_expression => None,
131            Self::range_expression => None,
132            Self::expression => None,
133            Self::program_modifier => None,
134            Self::program_with_modifier => None,
135            Self::program => None,
136            Self::symbol_name => None,
137            Self::function_alias_declaration => None,
138            Self::alias_declaration => None,
139        }
140    }
141}
142
143/// Manages diagnostic messages emitted during revset parsing and function-call
144/// resolution.
145pub type RevsetDiagnostics = Diagnostics<RevsetParseError>;
146
147#[derive(Debug, Error)]
148#[error("{pest_error}")]
149pub struct RevsetParseError {
150    kind: Box<RevsetParseErrorKind>,
151    pest_error: Box<pest::error::Error<Rule>>,
152    source: Option<Box<dyn error::Error + Send + Sync>>,
153}
154
155#[derive(Debug, Error, PartialEq, Eq)]
156pub enum RevsetParseErrorKind {
157    #[error("Syntax error")]
158    SyntaxError,
159    #[error("`{op}` is not a prefix operator")]
160    NotPrefixOperator {
161        op: String,
162        similar_op: String,
163        description: String,
164    },
165    #[error("`{op}` is not a postfix operator")]
166    NotPostfixOperator {
167        op: String,
168        similar_op: String,
169        description: String,
170    },
171    #[error("`{op}` is not an infix operator")]
172    NotInfixOperator {
173        op: String,
174        similar_op: String,
175        description: String,
176    },
177    #[error("Modifier `{0}` doesn't exist")]
178    NoSuchModifier(String),
179    #[error("Function `{name}` doesn't exist")]
180    NoSuchFunction {
181        name: String,
182        candidates: Vec<String>,
183    },
184    #[error("Function `{name}`: {message}")]
185    InvalidFunctionArguments { name: String, message: String },
186    #[error("Cannot resolve file pattern without workspace")]
187    FsPathWithoutWorkspace,
188    #[error("Cannot resolve `@` without workspace")]
189    WorkingCopyWithoutWorkspace,
190    #[error("Redefinition of function parameter")]
191    RedefinedFunctionParameter,
192    #[error("{0}")]
193    Expression(String),
194    #[error("In alias `{0}`")]
195    InAliasExpansion(String),
196    #[error("In function parameter `{0}`")]
197    InParameterExpansion(String),
198    #[error("Alias `{0}` expanded recursively")]
199    RecursiveAlias(String),
200}
201
202impl RevsetParseError {
203    pub(super) fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self {
204        let message = kind.to_string();
205        let pest_error = Box::new(pest::error::Error::new_from_span(
206            pest::error::ErrorVariant::CustomError { message },
207            span,
208        ));
209        Self {
210            kind: Box::new(kind),
211            pest_error,
212            source: None,
213        }
214    }
215
216    pub(super) fn with_source(
217        mut self,
218        source: impl Into<Box<dyn error::Error + Send + Sync>>,
219    ) -> Self {
220        self.source = Some(source.into());
221        self
222    }
223
224    /// Some other expression error.
225    pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
226        Self::with_span(RevsetParseErrorKind::Expression(message.into()), span)
227    }
228
229    /// If this is a `NoSuchFunction` error, expands the candidates list with
230    /// the given `other_functions`.
231    pub(super) fn extend_function_candidates<I>(mut self, other_functions: I) -> Self
232    where
233        I: IntoIterator,
234        I::Item: AsRef<str>,
235    {
236        if let RevsetParseErrorKind::NoSuchFunction { name, candidates } = self.kind.as_mut() {
237            let other_candidates = collect_similar(name, other_functions);
238            *candidates = itertools::merge(mem::take(candidates), other_candidates)
239                .dedup()
240                .collect();
241        }
242        self
243    }
244
245    pub fn kind(&self) -> &RevsetParseErrorKind {
246        &self.kind
247    }
248
249    /// Original parsing error which typically occurred in an alias expression.
250    pub fn origin(&self) -> Option<&Self> {
251        self.source.as_ref().and_then(|e| e.downcast_ref())
252    }
253}
254
255impl AliasExpandError for RevsetParseError {
256    fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
257        err.into()
258    }
259
260    fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
261        Self::with_span(RevsetParseErrorKind::RecursiveAlias(id.to_string()), span)
262    }
263
264    fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
265        let kind = match id {
266            AliasId::Symbol(_) | AliasId::Function(..) => {
267                RevsetParseErrorKind::InAliasExpansion(id.to_string())
268            }
269            AliasId::Parameter(_) => RevsetParseErrorKind::InParameterExpansion(id.to_string()),
270        };
271        Self::with_span(kind, span).with_source(self)
272    }
273}
274
275impl From<pest::error::Error<Rule>> for RevsetParseError {
276    fn from(err: pest::error::Error<Rule>) -> Self {
277        Self {
278            kind: Box::new(RevsetParseErrorKind::SyntaxError),
279            pest_error: Box::new(rename_rules_in_pest_error(err)),
280            source: None,
281        }
282    }
283}
284
285impl From<InvalidArguments<'_>> for RevsetParseError {
286    fn from(err: InvalidArguments<'_>) -> Self {
287        let kind = RevsetParseErrorKind::InvalidFunctionArguments {
288            name: err.name.to_owned(),
289            message: err.message,
290        };
291        Self::with_span(kind, err.span)
292    }
293}
294
295fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
296    let pest::error::ErrorVariant::ParsingError {
297        positives,
298        negatives,
299    } = &mut err.variant
300    else {
301        return err;
302    };
303
304    // Remove duplicated symbols. Compat symbols are also removed from the
305    // (positive) suggestion.
306    let mut known_syms = HashSet::new();
307    positives.retain(|rule| {
308        !rule.is_compat() && rule.to_symbol().is_none_or(|sym| known_syms.insert(sym))
309    });
310    let mut known_syms = HashSet::new();
311    negatives.retain(|rule| rule.to_symbol().is_none_or(|sym| known_syms.insert(sym)));
312    err.renamed_rules(|rule| {
313        rule.to_symbol()
314            .map(|sym| format!("`{sym}`"))
315            .unwrap_or_else(|| format!("<{rule:?}>"))
316    })
317}
318
319#[derive(Clone, Debug, Eq, PartialEq)]
320pub enum ExpressionKind<'i> {
321    /// Unquoted symbol.
322    Identifier(&'i str),
323    /// Quoted symbol or string.
324    String(String),
325    /// `<kind>:<value>`
326    StringPattern {
327        kind: &'i str,
328        value: String,
329    },
330    /// `<name>@<remote>`
331    RemoteSymbol(RemoteRefSymbolBuf),
332    /// `<name>@`
333    AtWorkspace(String),
334    /// `@`
335    AtCurrentWorkspace,
336    /// `::`
337    DagRangeAll,
338    /// `..`
339    RangeAll,
340    Unary(UnaryOp, Box<ExpressionNode<'i>>),
341    Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
342    /// `x | y | ..`
343    UnionAll(Vec<ExpressionNode<'i>>),
344    FunctionCall(Box<FunctionCallNode<'i>>),
345    /// `name: body`
346    Modifier(Box<ModifierNode<'i>>),
347    /// Identity node to preserve the span in the source text.
348    AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
349}
350
351impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
352    fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
353    where
354        F: ExpressionFolder<'i, Self> + ?Sized,
355    {
356        match self {
357            Self::Identifier(name) => folder.fold_identifier(name, span),
358            Self::String(_)
359            | Self::StringPattern { .. }
360            | Self::RemoteSymbol(_)
361            | ExpressionKind::AtWorkspace(_)
362            | Self::AtCurrentWorkspace
363            | Self::DagRangeAll
364            | Self::RangeAll => Ok(self),
365            Self::Unary(op, arg) => {
366                let arg = Box::new(folder.fold_expression(*arg)?);
367                Ok(Self::Unary(op, arg))
368            }
369            Self::Binary(op, lhs, rhs) => {
370                let lhs = Box::new(folder.fold_expression(*lhs)?);
371                let rhs = Box::new(folder.fold_expression(*rhs)?);
372                Ok(Self::Binary(op, lhs, rhs))
373            }
374            Self::UnionAll(nodes) => {
375                let nodes = dsl_util::fold_expression_nodes(folder, nodes)?;
376                Ok(Self::UnionAll(nodes))
377            }
378            Self::FunctionCall(function) => folder.fold_function_call(function, span),
379            Self::Modifier(modifier) => {
380                let modifier = Box::new(ModifierNode {
381                    name: modifier.name,
382                    name_span: modifier.name_span,
383                    body: folder.fold_expression(modifier.body)?,
384                });
385                Ok(Self::Modifier(modifier))
386            }
387            Self::AliasExpanded(id, subst) => {
388                let subst = Box::new(folder.fold_expression(*subst)?);
389                Ok(Self::AliasExpanded(id, subst))
390            }
391        }
392    }
393}
394
395impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
396    fn identifier(name: &'i str) -> Self {
397        Self::Identifier(name)
398    }
399
400    fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
401        Self::FunctionCall(function)
402    }
403
404    fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
405        Self::AliasExpanded(id, subst)
406    }
407}
408
409#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
410pub enum UnaryOp {
411    /// `~x`
412    Negate,
413    /// `::x`
414    DagRangePre,
415    /// `x::`
416    DagRangePost,
417    /// `..x`
418    RangePre,
419    /// `x..`
420    RangePost,
421    /// `x-`
422    Parents,
423    /// `x+`
424    Children,
425}
426
427#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
428pub enum BinaryOp {
429    /// `&`
430    Intersection,
431    /// `~`
432    Difference,
433    /// `::`
434    DagRange,
435    /// `..`
436    Range,
437}
438
439pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
440pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
441
442/// Expression with modifier `name: body`.
443#[derive(Clone, Debug, Eq, PartialEq)]
444pub struct ModifierNode<'i> {
445    /// Modifier name.
446    pub name: &'i str,
447    /// Span of the modifier name.
448    pub name_span: pest::Span<'i>,
449    /// Expression body.
450    pub body: ExpressionNode<'i>,
451}
452
453fn union_nodes<'i>(lhs: ExpressionNode<'i>, rhs: ExpressionNode<'i>) -> ExpressionNode<'i> {
454    let span = lhs.span.start_pos().span(&rhs.span.end_pos());
455    let expr = match lhs.kind {
456        // Flatten "x | y | z" to save recursion stack. Machine-generated query
457        // might have long chain of unions.
458        ExpressionKind::UnionAll(mut nodes) => {
459            nodes.push(rhs);
460            ExpressionKind::UnionAll(nodes)
461        }
462        _ => ExpressionKind::UnionAll(vec![lhs, rhs]),
463    };
464    ExpressionNode::new(expr, span)
465}
466
467/// Parses text into expression tree. The text may be prefixed with `all:`.
468/// No name resolution is made at this stage.
469// TODO: drop support for legacy "all:" modifier in jj 0.38+
470pub fn parse_program_with_modifier(
471    revset_str: &str,
472) -> Result<ExpressionNode<'_>, RevsetParseError> {
473    let mut pairs = RevsetParser::parse(Rule::program_with_modifier, revset_str)?;
474    let first = pairs.next().unwrap();
475    match first.as_rule() {
476        Rule::expression => parse_expression_node(first),
477        Rule::program_modifier => {
478            let [lhs, op] = first.into_inner().collect_array().unwrap();
479            let rhs = pairs.next().unwrap();
480            assert_eq!(lhs.as_rule(), Rule::strict_identifier);
481            assert_eq!(op.as_rule(), Rule::pattern_kind_op);
482            assert_eq!(rhs.as_rule(), Rule::expression);
483            let span = lhs.as_span().start_pos().span(&rhs.as_span().end_pos());
484            let modifier = Box::new(ModifierNode {
485                name: lhs.as_str(),
486                name_span: lhs.as_span(),
487                body: parse_expression_node(rhs)?,
488            });
489            let expr = ExpressionKind::Modifier(modifier);
490            Ok(ExpressionNode::new(expr, span))
491        }
492        r => panic!("unexpected revset parse rule: {r:?}"),
493    }
494}
495
496/// Parses text into expression tree. No name resolution is made at this stage.
497pub fn parse_program(revset_str: &str) -> Result<ExpressionNode<'_>, RevsetParseError> {
498    let mut pairs = RevsetParser::parse(Rule::program, revset_str)?;
499    let first = pairs.next().unwrap();
500    assert_eq!(first.as_rule(), Rule::expression);
501    parse_expression_node(first)
502}
503
504fn parse_expression_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
505    fn not_prefix_op(
506        op: &Pair<Rule>,
507        similar_op: impl Into<String>,
508        description: impl Into<String>,
509    ) -> RevsetParseError {
510        RevsetParseError::with_span(
511            RevsetParseErrorKind::NotPrefixOperator {
512                op: op.as_str().to_owned(),
513                similar_op: similar_op.into(),
514                description: description.into(),
515            },
516            op.as_span(),
517        )
518    }
519
520    fn not_postfix_op(
521        op: &Pair<Rule>,
522        similar_op: impl Into<String>,
523        description: impl Into<String>,
524    ) -> RevsetParseError {
525        RevsetParseError::with_span(
526            RevsetParseErrorKind::NotPostfixOperator {
527                op: op.as_str().to_owned(),
528                similar_op: similar_op.into(),
529                description: description.into(),
530            },
531            op.as_span(),
532        )
533    }
534
535    fn not_infix_op(
536        op: &Pair<Rule>,
537        similar_op: impl Into<String>,
538        description: impl Into<String>,
539    ) -> RevsetParseError {
540        RevsetParseError::with_span(
541            RevsetParseErrorKind::NotInfixOperator {
542                op: op.as_str().to_owned(),
543                similar_op: similar_op.into(),
544                description: description.into(),
545            },
546            op.as_span(),
547        )
548    }
549
550    static PRATT: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
551        PrattParser::new()
552            .op(Op::infix(Rule::union_op, Assoc::Left)
553                | Op::infix(Rule::compat_add_op, Assoc::Left))
554            .op(Op::infix(Rule::intersection_op, Assoc::Left)
555                | Op::infix(Rule::difference_op, Assoc::Left)
556                | Op::infix(Rule::compat_sub_op, Assoc::Left))
557            .op(Op::prefix(Rule::negate_op))
558            // Ranges can't be nested without parentheses. Associativity doesn't matter.
559            .op(Op::infix(Rule::dag_range_op, Assoc::Left)
560                | Op::infix(Rule::compat_dag_range_op, Assoc::Left)
561                | Op::infix(Rule::range_op, Assoc::Left))
562            .op(Op::prefix(Rule::dag_range_pre_op)
563                | Op::prefix(Rule::compat_dag_range_pre_op)
564                | Op::prefix(Rule::range_pre_op))
565            .op(Op::postfix(Rule::dag_range_post_op)
566                | Op::postfix(Rule::compat_dag_range_post_op)
567                | Op::postfix(Rule::range_post_op))
568            // Neighbors
569            .op(Op::postfix(Rule::parents_op)
570                | Op::postfix(Rule::children_op)
571                | Op::postfix(Rule::compat_parents_op))
572    });
573    PRATT
574        .map_primary(|primary| {
575            let expr = match primary.as_rule() {
576                Rule::primary => return parse_primary_node(primary),
577                Rule::dag_range_all_op => ExpressionKind::DagRangeAll,
578                Rule::range_all_op => ExpressionKind::RangeAll,
579                r => panic!("unexpected primary rule {r:?}"),
580            };
581            Ok(ExpressionNode::new(expr, primary.as_span()))
582        })
583        .map_prefix(|op, rhs| {
584            let op_kind = match op.as_rule() {
585                Rule::negate_op => UnaryOp::Negate,
586                Rule::dag_range_pre_op => UnaryOp::DagRangePre,
587                Rule::compat_dag_range_pre_op => Err(not_prefix_op(&op, "::", "ancestors"))?,
588                Rule::range_pre_op => UnaryOp::RangePre,
589                r => panic!("unexpected prefix operator rule {r:?}"),
590            };
591            let rhs = Box::new(rhs?);
592            let span = op.as_span().start_pos().span(&rhs.span.end_pos());
593            let expr = ExpressionKind::Unary(op_kind, rhs);
594            Ok(ExpressionNode::new(expr, span))
595        })
596        .map_postfix(|lhs, op| {
597            let op_kind = match op.as_rule() {
598                Rule::dag_range_post_op => UnaryOp::DagRangePost,
599                Rule::compat_dag_range_post_op => Err(not_postfix_op(&op, "::", "descendants"))?,
600                Rule::range_post_op => UnaryOp::RangePost,
601                Rule::parents_op => UnaryOp::Parents,
602                Rule::children_op => UnaryOp::Children,
603                Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents"))?,
604                r => panic!("unexpected postfix operator rule {r:?}"),
605            };
606            let lhs = Box::new(lhs?);
607            let span = lhs.span.start_pos().span(&op.as_span().end_pos());
608            let expr = ExpressionKind::Unary(op_kind, lhs);
609            Ok(ExpressionNode::new(expr, span))
610        })
611        .map_infix(|lhs, op, rhs| {
612            let op_kind = match op.as_rule() {
613                Rule::union_op => return Ok(union_nodes(lhs?, rhs?)),
614                Rule::compat_add_op => Err(not_infix_op(&op, "|", "union"))?,
615                Rule::intersection_op => BinaryOp::Intersection,
616                Rule::difference_op => BinaryOp::Difference,
617                Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference"))?,
618                Rule::dag_range_op => BinaryOp::DagRange,
619                Rule::compat_dag_range_op => Err(not_infix_op(&op, "::", "DAG range"))?,
620                Rule::range_op => BinaryOp::Range,
621                r => panic!("unexpected infix operator rule {r:?}"),
622            };
623            let lhs = Box::new(lhs?);
624            let rhs = Box::new(rhs?);
625            let span = lhs.span.start_pos().span(&rhs.span.end_pos());
626            let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
627            Ok(ExpressionNode::new(expr, span))
628        })
629        .parse(pair.into_inner())
630}
631
632fn parse_primary_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
633    let span = pair.as_span();
634    let mut pairs = pair.into_inner();
635    let first = pairs.next().unwrap();
636    let expr = match first.as_rule() {
637        // Ignore inner span to preserve parenthesized expression as such.
638        Rule::expression => parse_expression_node(first)?.kind,
639        Rule::function => {
640            let function = Box::new(FUNCTION_CALL_PARSER.parse(
641                first,
642                |pair| Ok(pair.as_str()),
643                |pair| parse_expression_node(pair),
644            )?);
645            ExpressionKind::FunctionCall(function)
646        }
647        Rule::string_pattern => {
648            let [lhs, op, rhs] = first.into_inner().collect_array().unwrap();
649            assert_eq!(lhs.as_rule(), Rule::strict_identifier);
650            assert_eq!(op.as_rule(), Rule::pattern_kind_op);
651            let kind = lhs.as_str();
652            let value = parse_as_string_literal(rhs);
653            ExpressionKind::StringPattern { kind, value }
654        }
655        // Identifier without "@" may be substituted by aliases. Primary expression including "@"
656        // is considered an indecomposable unit, and no alias substitution would be made.
657        Rule::identifier if pairs.peek().is_none() => ExpressionKind::Identifier(first.as_str()),
658        Rule::identifier | Rule::string_literal | Rule::raw_string_literal => {
659            let name = parse_as_string_literal(first);
660            match pairs.next() {
661                None => ExpressionKind::String(name),
662                Some(op) => {
663                    assert_eq!(op.as_rule(), Rule::at_op);
664                    match pairs.next() {
665                        // postfix "<name>@"
666                        None => ExpressionKind::AtWorkspace(name),
667                        // infix "<name>@<remote>"
668                        Some(second) => {
669                            let name: RefNameBuf = name.into();
670                            let remote: RemoteNameBuf = parse_as_string_literal(second).into();
671                            ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf { name, remote })
672                        }
673                    }
674                }
675            }
676        }
677        // nullary "@"
678        Rule::at_op => ExpressionKind::AtCurrentWorkspace,
679        r => panic!("unexpected revset parse rule: {r:?}"),
680    };
681    Ok(ExpressionNode::new(expr, span))
682}
683
684/// Parses part of compound symbol to string.
685fn parse_as_string_literal(pair: Pair<Rule>) -> String {
686    match pair.as_rule() {
687        Rule::identifier => pair.as_str().to_owned(),
688        Rule::string_literal => STRING_LITERAL_PARSER.parse(pair.into_inner()),
689        Rule::raw_string_literal => {
690            let [content] = pair.into_inner().collect_array().unwrap();
691            assert_eq!(content.as_rule(), Rule::raw_string_content);
692            content.as_str().to_owned()
693        }
694        _ => {
695            panic!("unexpected string literal rule: {:?}", pair.as_str());
696        }
697    }
698}
699
700/// Checks if the text is a valid identifier
701pub fn is_identifier(text: &str) -> bool {
702    match RevsetParser::parse(Rule::identifier, text) {
703        Ok(mut pairs) => pairs.next().unwrap().as_span().end() == text.len(),
704        Err(_) => false,
705    }
706}
707
708/// Parses the text as a revset symbol, rejects empty string.
709pub fn parse_symbol(text: &str) -> Result<String, RevsetParseError> {
710    let mut pairs = RevsetParser::parse(Rule::symbol_name, text)?;
711    let first = pairs.next().unwrap();
712    let span = first.as_span();
713    let name = parse_as_string_literal(first);
714    if name.is_empty() {
715        Err(RevsetParseError::expression(
716            "Expected non-empty string",
717            span,
718        ))
719    } else {
720        Ok(name)
721    }
722}
723
724pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser, String>;
725
726#[derive(Clone, Debug, Default)]
727pub struct RevsetAliasParser;
728
729impl AliasDeclarationParser for RevsetAliasParser {
730    type Error = RevsetParseError;
731
732    fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
733        let mut pairs = RevsetParser::parse(Rule::alias_declaration, source)?;
734        let first = pairs.next().unwrap();
735        match first.as_rule() {
736            Rule::strict_identifier => Ok(AliasDeclaration::Symbol(first.as_str().to_owned())),
737            Rule::function_alias_declaration => {
738                let [name_pair, params_pair] = first.into_inner().collect_array().unwrap();
739                assert_eq!(name_pair.as_rule(), Rule::function_name);
740                assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
741                let name = name_pair.as_str().to_owned();
742                let params_span = params_pair.as_span();
743                let params = params_pair
744                    .into_inner()
745                    .map(|pair| match pair.as_rule() {
746                        Rule::strict_identifier => pair.as_str().to_owned(),
747                        r => panic!("unexpected formal parameter rule {r:?}"),
748                    })
749                    .collect_vec();
750                if params.iter().all_unique() {
751                    Ok(AliasDeclaration::Function(name, params))
752                } else {
753                    Err(RevsetParseError::with_span(
754                        RevsetParseErrorKind::RedefinedFunctionParameter,
755                        params_span,
756                    ))
757                }
758            }
759            r => panic!("unexpected alias declaration rule {r:?}"),
760        }
761    }
762}
763
764impl AliasDefinitionParser for RevsetAliasParser {
765    type Output<'i> = ExpressionKind<'i>;
766    type Error = RevsetParseError;
767
768    fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
769        parse_program_with_modifier(source)
770    }
771}
772
773pub(super) fn expect_string_pattern<'a>(
774    type_name: &str,
775    node: &'a ExpressionNode<'_>,
776) -> Result<(&'a str, Option<&'a str>), RevsetParseError> {
777    catch_aliases_no_diagnostics(node, |node| match &node.kind {
778        ExpressionKind::Identifier(name) => Ok((*name, None)),
779        ExpressionKind::String(name) => Ok((name, None)),
780        ExpressionKind::StringPattern { kind, value } => Ok((value, Some(*kind))),
781        _ => Err(RevsetParseError::expression(
782            format!("Expected {type_name}"),
783            node.span,
784        )),
785    })
786}
787
788pub fn expect_literal<T: FromStr>(
789    type_name: &str,
790    node: &ExpressionNode,
791) -> Result<T, RevsetParseError> {
792    catch_aliases_no_diagnostics(node, |node| {
793        let value = expect_string_literal(type_name, node)?;
794        value
795            .parse()
796            .map_err(|_| RevsetParseError::expression(format!("Expected {type_name}"), node.span))
797    })
798}
799
800pub(super) fn expect_string_literal<'a>(
801    type_name: &str,
802    node: &'a ExpressionNode<'_>,
803) -> Result<&'a str, RevsetParseError> {
804    catch_aliases_no_diagnostics(node, |node| match &node.kind {
805        ExpressionKind::Identifier(name) => Ok(*name),
806        ExpressionKind::String(name) => Ok(name),
807        _ => Err(RevsetParseError::expression(
808            format!("Expected {type_name}"),
809            node.span,
810        )),
811    })
812}
813
814/// Applies the given function to the innermost `node` by unwrapping alias
815/// expansion nodes. Appends alias expansion stack to error and diagnostics.
816pub(super) fn catch_aliases<'a, 'i, T>(
817    diagnostics: &mut RevsetDiagnostics,
818    node: &'a ExpressionNode<'i>,
819    f: impl FnOnce(&mut RevsetDiagnostics, &'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
820) -> Result<T, RevsetParseError> {
821    let (node, stack) = skip_aliases(node);
822    if stack.is_empty() {
823        f(diagnostics, node)
824    } else {
825        let mut inner_diagnostics = RevsetDiagnostics::new();
826        let result = f(&mut inner_diagnostics, node);
827        diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
828        result.map_err(|err| attach_aliases_err(err, &stack))
829    }
830}
831
832fn catch_aliases_no_diagnostics<'a, 'i, T>(
833    node: &'a ExpressionNode<'i>,
834    f: impl FnOnce(&'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
835) -> Result<T, RevsetParseError> {
836    let (node, stack) = skip_aliases(node);
837    f(node).map_err(|err| attach_aliases_err(err, &stack))
838}
839
840fn skip_aliases<'a, 'i>(
841    mut node: &'a ExpressionNode<'i>,
842) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
843    let mut stack = Vec::new();
844    while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
845        stack.push((*id, node.span));
846        node = subst;
847    }
848    (node, stack)
849}
850
851fn attach_aliases_err(
852    err: RevsetParseError,
853    stack: &[(AliasId<'_>, pest::Span<'_>)],
854) -> RevsetParseError {
855    stack
856        .iter()
857        .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
858}
859
860#[cfg(test)]
861mod tests {
862    use std::collections::HashMap;
863
864    use assert_matches::assert_matches;
865
866    use super::*;
867    use crate::dsl_util::KeywordArgument;
868
869    #[derive(Debug)]
870    struct WithRevsetAliasesMap<'i> {
871        aliases_map: RevsetAliasesMap,
872        locals: HashMap<&'i str, ExpressionNode<'i>>,
873    }
874
875    impl<'i> WithRevsetAliasesMap<'i> {
876        fn set_local(mut self, name: &'i str, value: &'i str) -> Self {
877            self.locals.insert(name, parse_program(value).unwrap());
878            self
879        }
880
881        fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
882            let node = parse_program_with_modifier(text)?;
883            dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals)
884        }
885
886        fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> {
887            normalize_tree(self.parse(text).unwrap())
888        }
889    }
890
891    fn with_aliases<'i>(
892        aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
893    ) -> WithRevsetAliasesMap<'i> {
894        let mut aliases_map = RevsetAliasesMap::new();
895        for (decl, defn) in aliases {
896            aliases_map.insert(decl, defn).unwrap();
897        }
898        WithRevsetAliasesMap {
899            aliases_map,
900            locals: HashMap::new(),
901        }
902    }
903
904    fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
905        parse_program(text)
906            .map(|node| node.kind)
907            .map_err(|err| *err.kind)
908    }
909
910    fn parse_normalized(text: &str) -> ExpressionNode<'_> {
911        normalize_tree(parse_program_with_modifier(text).unwrap())
912    }
913
914    /// Drops auxiliary data from parsed tree so it can be compared with other.
915    fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
916        fn empty_span() -> pest::Span<'static> {
917            pest::Span::new("", 0, 0).unwrap()
918        }
919
920        fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
921            nodes.into_iter().map(normalize_tree).collect()
922        }
923
924        fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
925            FunctionCallNode {
926                name: function.name,
927                name_span: empty_span(),
928                args: normalize_list(function.args),
929                keyword_args: function
930                    .keyword_args
931                    .into_iter()
932                    .map(|arg| KeywordArgument {
933                        name: arg.name,
934                        name_span: empty_span(),
935                        value: normalize_tree(arg.value),
936                    })
937                    .collect(),
938                args_span: empty_span(),
939            }
940        }
941
942        let normalized_kind = match node.kind {
943            ExpressionKind::Identifier(_)
944            | ExpressionKind::String(_)
945            | ExpressionKind::StringPattern { .. }
946            | ExpressionKind::RemoteSymbol(_)
947            | ExpressionKind::AtWorkspace(_)
948            | ExpressionKind::AtCurrentWorkspace
949            | ExpressionKind::DagRangeAll
950            | ExpressionKind::RangeAll => node.kind,
951            ExpressionKind::Unary(op, arg) => {
952                let arg = Box::new(normalize_tree(*arg));
953                ExpressionKind::Unary(op, arg)
954            }
955            ExpressionKind::Binary(op, lhs, rhs) => {
956                let lhs = Box::new(normalize_tree(*lhs));
957                let rhs = Box::new(normalize_tree(*rhs));
958                ExpressionKind::Binary(op, lhs, rhs)
959            }
960            ExpressionKind::UnionAll(nodes) => {
961                let nodes = normalize_list(nodes);
962                ExpressionKind::UnionAll(nodes)
963            }
964            ExpressionKind::FunctionCall(function) => {
965                let function = Box::new(normalize_function_call(*function));
966                ExpressionKind::FunctionCall(function)
967            }
968            ExpressionKind::Modifier(modifier) => {
969                let modifier = Box::new(ModifierNode {
970                    name: modifier.name,
971                    name_span: empty_span(),
972                    body: normalize_tree(modifier.body),
973                });
974                ExpressionKind::Modifier(modifier)
975            }
976            ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
977        };
978        ExpressionNode {
979            kind: normalized_kind,
980            span: empty_span(),
981        }
982    }
983
984    #[test]
985    fn test_parse_tree_eq() {
986        assert_eq!(
987            parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
988            parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
989        );
990        assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
991    }
992
993    #[test]
994    fn test_parse_revset() {
995        // Parse a quoted symbol
996        assert_eq!(
997            parse_into_kind("\"foo\""),
998            Ok(ExpressionKind::String("foo".to_owned()))
999        );
1000        assert_eq!(
1001            parse_into_kind("'foo'"),
1002            Ok(ExpressionKind::String("foo".to_owned()))
1003        );
1004        // Parse the "parents" operator
1005        assert_matches!(
1006            parse_into_kind("foo-"),
1007            Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
1008        );
1009        // Parse the "children" operator
1010        assert_matches!(
1011            parse_into_kind("foo+"),
1012            Ok(ExpressionKind::Unary(UnaryOp::Children, _))
1013        );
1014        // Parse the "ancestors" operator
1015        assert_matches!(
1016            parse_into_kind("::foo"),
1017            Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
1018        );
1019        // Parse the "descendants" operator
1020        assert_matches!(
1021            parse_into_kind("foo::"),
1022            Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1023        );
1024        // Parse the "dag range" operator
1025        assert_matches!(
1026            parse_into_kind("foo::bar"),
1027            Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1028        );
1029        // Parse the nullary "dag range" operator
1030        assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
1031        // Parse the "range" prefix operator
1032        assert_matches!(
1033            parse_into_kind("..foo"),
1034            Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
1035        );
1036        assert_matches!(
1037            parse_into_kind("foo.."),
1038            Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
1039        );
1040        assert_matches!(
1041            parse_into_kind("foo..bar"),
1042            Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
1043        );
1044        // Parse the nullary "range" operator
1045        assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
1046        // Parse the "negate" operator
1047        assert_matches!(
1048            parse_into_kind("~ foo"),
1049            Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1050        );
1051        assert_eq!(
1052            parse_normalized("~ ~~ foo"),
1053            parse_normalized("~(~(~(foo)))"),
1054        );
1055        // Parse the "intersection" operator
1056        assert_matches!(
1057            parse_into_kind("foo & bar"),
1058            Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1059        );
1060        // Parse the "union" operator
1061        assert_matches!(
1062            parse_into_kind("foo | bar"),
1063            Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1064        );
1065        assert_matches!(
1066            parse_into_kind("foo | bar | baz"),
1067            Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1068        );
1069        // Parse the "difference" operator
1070        assert_matches!(
1071            parse_into_kind("foo ~ bar"),
1072            Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1073        );
1074        // Parentheses are allowed before suffix operators
1075        assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1076        // Space is allowed around expressions
1077        assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1078        assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1079        // Space is not allowed around prefix operators
1080        assert_eq!(
1081            parse_into_kind(" :: foo "),
1082            Err(RevsetParseErrorKind::SyntaxError)
1083        );
1084        // Incomplete parse
1085        assert_eq!(
1086            parse_into_kind("foo | -"),
1087            Err(RevsetParseErrorKind::SyntaxError)
1088        );
1089
1090        // Expression span
1091        assert_eq!(parse_program(" ~ x ").unwrap().span.as_str(), "~ x");
1092        assert_eq!(parse_program(" x+ ").unwrap().span.as_str(), "x+");
1093        assert_eq!(parse_program(" x |y ").unwrap().span.as_str(), "x |y");
1094        assert_eq!(parse_program(" (x) ").unwrap().span.as_str(), "(x)");
1095        assert_eq!(parse_program("~( x|y) ").unwrap().span.as_str(), "~( x|y)");
1096        assert_eq!(parse_program(" ( x )- ").unwrap().span.as_str(), "( x )-");
1097    }
1098
1099    #[test]
1100    fn test_parse_revset_with_modifier() {
1101        fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
1102            parse_program_with_modifier(text)
1103                .map(|node| node.kind)
1104                .map_err(|err| *err.kind)
1105        }
1106
1107        // all: is a program modifier, but all:: isn't
1108        assert_eq!(
1109            parse_into_kind("all:"),
1110            Err(RevsetParseErrorKind::SyntaxError)
1111        );
1112        assert_matches!(
1113            parse_into_kind("all:foo"),
1114            Ok(ExpressionKind::Modifier(modifier)) if modifier.name == "all"
1115        );
1116        assert_matches!(
1117            parse_into_kind("all::"),
1118            Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1119        );
1120        assert_matches!(
1121            parse_into_kind("all::foo"),
1122            Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1123        );
1124
1125        // all::: could be parsed as all:(::), but rejected for simplicity
1126        assert_eq!(
1127            parse_into_kind("all:::"),
1128            Err(RevsetParseErrorKind::SyntaxError)
1129        );
1130        assert_eq!(
1131            parse_into_kind("all:::foo"),
1132            Err(RevsetParseErrorKind::SyntaxError)
1133        );
1134
1135        assert_eq!(parse_normalized("all:(foo)"), parse_normalized("all:foo"));
1136        assert_eq!(
1137            parse_normalized("all:all::foo"),
1138            parse_normalized("all:(all::foo)"),
1139        );
1140        assert_eq!(
1141            parse_normalized("all:all | foo"),
1142            parse_normalized("all:(all | foo)"),
1143        );
1144
1145        assert_eq!(
1146            parse_normalized("all: ::foo"),
1147            parse_normalized("all:(::foo)"),
1148        );
1149        assert_eq!(parse_normalized(" all: foo"), parse_normalized("all:foo"));
1150        assert_eq!(
1151            parse_into_kind("(all:foo)"),
1152            Ok(ExpressionKind::StringPattern {
1153                kind: "all",
1154                value: "foo".to_owned()
1155            })
1156        );
1157        assert_matches!(
1158            parse_into_kind("all :foo"),
1159            Err(RevsetParseErrorKind::SyntaxError)
1160        );
1161        assert_eq!(
1162            parse_normalized("all:all:all"),
1163            parse_normalized("all:(all:all)"),
1164        );
1165    }
1166
1167    #[test]
1168    fn test_parse_whitespace() {
1169        let ascii_whitespaces: String = ('\x00'..='\x7f')
1170            .filter(char::is_ascii_whitespace)
1171            .collect();
1172        assert_eq!(
1173            parse_normalized(&format!("{ascii_whitespaces}all()")),
1174            parse_normalized("all()"),
1175        );
1176    }
1177
1178    #[test]
1179    fn test_parse_identifier() {
1180        // Integer is a symbol
1181        assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1182        // Tag/bookmark name separated by /
1183        assert_eq!(
1184            parse_into_kind("foo_bar/baz"),
1185            Ok(ExpressionKind::Identifier("foo_bar/baz"))
1186        );
1187        // Glob literal with star
1188        assert_eq!(
1189            parse_into_kind("*/foo/**"),
1190            Ok(ExpressionKind::Identifier("*/foo/**"))
1191        );
1192
1193        // Internal '.', '-', and '+' are allowed
1194        assert_eq!(
1195            parse_into_kind("foo.bar-v1+7"),
1196            Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1197        );
1198        assert_eq!(
1199            parse_normalized("foo.bar-v1+7-"),
1200            parse_normalized("(foo.bar-v1+7)-")
1201        );
1202        // '.' is not allowed at the beginning or end
1203        assert_eq!(
1204            parse_into_kind(".foo"),
1205            Err(RevsetParseErrorKind::SyntaxError)
1206        );
1207        assert_eq!(
1208            parse_into_kind("foo."),
1209            Err(RevsetParseErrorKind::SyntaxError)
1210        );
1211        // Multiple '.', '-', '+' are not allowed
1212        assert_eq!(
1213            parse_into_kind("foo.+bar"),
1214            Err(RevsetParseErrorKind::SyntaxError)
1215        );
1216        assert_eq!(
1217            parse_into_kind("foo--bar"),
1218            Err(RevsetParseErrorKind::SyntaxError)
1219        );
1220        assert_eq!(
1221            parse_into_kind("foo+-bar"),
1222            Err(RevsetParseErrorKind::SyntaxError)
1223        );
1224
1225        // Parse a parenthesized symbol
1226        assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1227
1228        // Non-ASCII tag/bookmark name
1229        assert_eq!(
1230            parse_into_kind("柔術+jj"),
1231            Ok(ExpressionKind::Identifier("柔術+jj"))
1232        );
1233    }
1234
1235    #[test]
1236    fn test_parse_string_literal() {
1237        // "\<char>" escapes
1238        assert_eq!(
1239            parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1240            Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1241        );
1242
1243        // Invalid "\<char>" escape
1244        assert_eq!(
1245            parse_into_kind(r#" "\y" "#),
1246            Err(RevsetParseErrorKind::SyntaxError)
1247        );
1248
1249        // Single-quoted raw string
1250        assert_eq!(
1251            parse_into_kind(r#" '' "#),
1252            Ok(ExpressionKind::String("".to_owned()))
1253        );
1254        assert_eq!(
1255            parse_into_kind(r#" 'a\n' "#),
1256            Ok(ExpressionKind::String(r"a\n".to_owned()))
1257        );
1258        assert_eq!(
1259            parse_into_kind(r#" '\' "#),
1260            Ok(ExpressionKind::String(r"\".to_owned()))
1261        );
1262        assert_eq!(
1263            parse_into_kind(r#" '"' "#),
1264            Ok(ExpressionKind::String(r#"""#.to_owned()))
1265        );
1266
1267        // Hex bytes
1268        assert_eq!(
1269            parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1270            Ok(ExpressionKind::String("aeiou".to_owned()))
1271        );
1272        assert_eq!(
1273            parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1274            Ok(ExpressionKind::String("àèìðù".to_owned()))
1275        );
1276        assert_eq!(
1277            parse_into_kind(r#""\x""#),
1278            Err(RevsetParseErrorKind::SyntaxError)
1279        );
1280        assert_eq!(
1281            parse_into_kind(r#""\xf""#),
1282            Err(RevsetParseErrorKind::SyntaxError)
1283        );
1284        assert_eq!(
1285            parse_into_kind(r#""\xgg""#),
1286            Err(RevsetParseErrorKind::SyntaxError)
1287        );
1288    }
1289
1290    #[test]
1291    fn test_parse_string_pattern() {
1292        assert_eq!(
1293            parse_into_kind(r#"substring:"foo""#),
1294            Ok(ExpressionKind::StringPattern {
1295                kind: "substring",
1296                value: "foo".to_owned()
1297            })
1298        );
1299        assert_eq!(
1300            parse_into_kind(r#""exact:foo""#),
1301            Ok(ExpressionKind::String("exact:foo".to_owned()))
1302        );
1303        assert_eq!(
1304            parse_normalized(r#"(exact:"foo" )"#),
1305            parse_normalized(r#"(exact:"foo")"#),
1306        );
1307        assert_eq!(
1308            parse_into_kind(r#"exact:'\'"#),
1309            Ok(ExpressionKind::StringPattern {
1310                kind: "exact",
1311                value: r"\".to_owned()
1312            })
1313        );
1314        assert_matches!(
1315            parse_into_kind(r#"exact:("foo" )"#),
1316            Err(RevsetParseErrorKind::NotInfixOperator { .. })
1317        );
1318    }
1319
1320    #[test]
1321    fn test_parse_symbol_explicitly() {
1322        assert_matches!(parse_symbol("").as_deref(), Err(_));
1323        // empty string could be a valid ref name, but it would be super
1324        // confusing if identifier was empty.
1325        assert_matches!(parse_symbol("''").as_deref(), Err(_));
1326
1327        assert_matches!(parse_symbol("foo.bar").as_deref(), Ok("foo.bar"));
1328        assert_matches!(parse_symbol("foo@bar").as_deref(), Err(_));
1329        assert_matches!(parse_symbol("foo bar").as_deref(), Err(_));
1330
1331        assert_matches!(parse_symbol("'foo bar'").as_deref(), Ok("foo bar"));
1332        assert_matches!(parse_symbol(r#""foo\tbar""#).as_deref(), Ok("foo\tbar"));
1333
1334        // leading/trailing whitespace is NOT ignored.
1335        assert_matches!(parse_symbol(" foo").as_deref(), Err(_));
1336        assert_matches!(parse_symbol("foo ").as_deref(), Err(_));
1337
1338        // (foo) could be parsed as a symbol "foo", but is rejected because user
1339        // might expect a literal "(foo)".
1340        assert_matches!(parse_symbol("(foo)").as_deref(), Err(_));
1341    }
1342
1343    #[test]
1344    fn parse_at_workspace_and_remote_symbol() {
1345        // Parse "@" (the current working copy)
1346        assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1347        assert_eq!(
1348            parse_into_kind("main@"),
1349            Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1350        );
1351        assert_eq!(
1352            parse_into_kind("main@origin"),
1353            Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1354                name: "main".into(),
1355                remote: "origin".into()
1356            }))
1357        );
1358
1359        // Quoted component in @ expression
1360        assert_eq!(
1361            parse_into_kind(r#""foo bar"@"#),
1362            Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1363        );
1364        assert_eq!(
1365            parse_into_kind(r#""foo bar"@origin"#),
1366            Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1367                name: "foo bar".into(),
1368                remote: "origin".into()
1369            }))
1370        );
1371        assert_eq!(
1372            parse_into_kind(r#"main@"foo bar""#),
1373            Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1374                name: "main".into(),
1375                remote: "foo bar".into()
1376            }))
1377        );
1378        assert_eq!(
1379            parse_into_kind(r#"'foo bar'@'bar baz'"#),
1380            Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1381                name: "foo bar".into(),
1382                remote: "bar baz".into()
1383            }))
1384        );
1385
1386        // Quoted "@" is not interpreted as a working copy or remote symbol
1387        assert_eq!(
1388            parse_into_kind(r#""@""#),
1389            Ok(ExpressionKind::String("@".to_owned()))
1390        );
1391        assert_eq!(
1392            parse_into_kind(r#""main@""#),
1393            Ok(ExpressionKind::String("main@".to_owned()))
1394        );
1395        assert_eq!(
1396            parse_into_kind(r#""main@origin""#),
1397            Ok(ExpressionKind::String("main@origin".to_owned()))
1398        );
1399
1400        // Non-ASCII name
1401        assert_eq!(
1402            parse_into_kind("柔術@"),
1403            Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1404        );
1405        assert_eq!(
1406            parse_into_kind("柔@術"),
1407            Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1408                name: "柔".into(),
1409                remote: "術".into()
1410            }))
1411        );
1412    }
1413
1414    #[test]
1415    fn test_parse_function_call() {
1416        fn unwrap_function_call(node: ExpressionNode<'_>) -> Box<FunctionCallNode<'_>> {
1417            match node.kind {
1418                ExpressionKind::FunctionCall(function) => function,
1419                _ => panic!("unexpected expression: {node:?}"),
1420            }
1421        }
1422
1423        // Space is allowed around infix operators and function arguments
1424        assert_eq!(
1425            parse_normalized(
1426                "   description(  arg1 ) ~    file(  arg1 ,   arg2 )  ~ visible_heads(  )  ",
1427            ),
1428            parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1429        );
1430        // Space is allowed around keyword arguments
1431        assert_eq!(
1432            parse_normalized("remote_bookmarks( remote  =   foo  )"),
1433            parse_normalized("remote_bookmarks(remote=foo)"),
1434        );
1435
1436        // Trailing comma isn't allowed for empty argument
1437        assert!(parse_into_kind("bookmarks(,)").is_err());
1438        // Trailing comma is allowed for the last argument
1439        assert_eq!(
1440            parse_normalized("bookmarks(a,)"),
1441            parse_normalized("bookmarks(a)")
1442        );
1443        assert_eq!(
1444            parse_normalized("bookmarks(a ,  )"),
1445            parse_normalized("bookmarks(a)")
1446        );
1447        assert!(parse_into_kind("bookmarks(,a)").is_err());
1448        assert!(parse_into_kind("bookmarks(a,,)").is_err());
1449        assert!(parse_into_kind("bookmarks(a  , , )").is_err());
1450        assert_eq!(
1451            parse_normalized("file(a,b,)"),
1452            parse_normalized("file(a, b)")
1453        );
1454        assert!(parse_into_kind("file(a,,b)").is_err());
1455        assert_eq!(
1456            parse_normalized("remote_bookmarks(a,remote=b  , )"),
1457            parse_normalized("remote_bookmarks(a, remote=b)"),
1458        );
1459        assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1460
1461        // Expression span
1462        let function =
1463            unwrap_function_call(parse_program("foo( a, (b) , ~(c), d = (e) )").unwrap());
1464        assert_eq!(function.name_span.as_str(), "foo");
1465        assert_eq!(function.args_span.as_str(), "a, (b) , ~(c), d = (e)");
1466        assert_eq!(function.args[0].span.as_str(), "a");
1467        assert_eq!(function.args[1].span.as_str(), "(b)");
1468        assert_eq!(function.args[2].span.as_str(), "~(c)");
1469        assert_eq!(function.keyword_args[0].name_span.as_str(), "d");
1470        assert_eq!(function.keyword_args[0].value.span.as_str(), "(e)");
1471    }
1472
1473    #[test]
1474    fn test_parse_revset_alias_symbol_decl() {
1475        let mut aliases_map = RevsetAliasesMap::new();
1476        // Working copy or remote symbol cannot be used as an alias name.
1477        assert!(aliases_map.insert("@", "none()").is_err());
1478        assert!(aliases_map.insert("a@", "none()").is_err());
1479        assert!(aliases_map.insert("a@b", "none()").is_err());
1480        // Non-ASCII character isn't allowed in alias symbol. This rule can be
1481        // relaxed if needed.
1482        assert!(aliases_map.insert("柔術", "none()").is_err());
1483    }
1484
1485    #[test]
1486    fn test_parse_revset_alias_func_decl() {
1487        let mut aliases_map = RevsetAliasesMap::new();
1488        assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err());
1489        aliases_map.insert("func()", r#""is function 0""#).unwrap();
1490        aliases_map
1491            .insert("func(a, b)", r#""is function 2""#)
1492            .unwrap();
1493        aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1494        aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1495
1496        let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1497        assert_eq!(id, AliasId::Function("func", &[]));
1498        assert!(params.is_empty());
1499        assert_eq!(defn, r#""is function 0""#);
1500
1501        let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1502        assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1503        assert_eq!(params, ["b"]);
1504        assert_eq!(defn, r#""is function b""#);
1505
1506        let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1507        assert_eq!(
1508            id,
1509            AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1510        );
1511        assert_eq!(params, ["a", "b"]);
1512        assert_eq!(defn, r#""is function 2""#);
1513
1514        assert!(aliases_map.get_function("func", 3).is_none());
1515    }
1516
1517    #[test]
1518    fn test_parse_revset_alias_formal_parameter() {
1519        let mut aliases_map = RevsetAliasesMap::new();
1520        // Working copy or remote symbol cannot be used as an parameter name.
1521        assert!(aliases_map.insert("f(@)", "none()").is_err());
1522        assert!(aliases_map.insert("f(a@)", "none()").is_err());
1523        assert!(aliases_map.insert("f(a@b)", "none()").is_err());
1524        // Trailing comma isn't allowed for empty parameter
1525        assert!(aliases_map.insert("f(,)", "none()").is_err());
1526        // Trailing comma is allowed for the last parameter
1527        assert!(aliases_map.insert("g(a,)", "none()").is_ok());
1528        assert!(aliases_map.insert("h(a ,  )", "none()").is_ok());
1529        assert!(aliases_map.insert("i(,a)", "none()").is_err());
1530        assert!(aliases_map.insert("j(a,,)", "none()").is_err());
1531        assert!(aliases_map.insert("k(a  , , )", "none()").is_err());
1532        assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
1533        assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
1534    }
1535
1536    #[test]
1537    fn test_parse_revset_compat_operator() {
1538        assert_eq!(
1539            parse_into_kind(":foo"),
1540            Err(RevsetParseErrorKind::NotPrefixOperator {
1541                op: ":".to_owned(),
1542                similar_op: "::".to_owned(),
1543                description: "ancestors".to_owned(),
1544            })
1545        );
1546        assert_eq!(
1547            parse_into_kind("foo^"),
1548            Err(RevsetParseErrorKind::NotPostfixOperator {
1549                op: "^".to_owned(),
1550                similar_op: "-".to_owned(),
1551                description: "parents".to_owned(),
1552            })
1553        );
1554        assert_eq!(
1555            parse_into_kind("foo + bar"),
1556            Err(RevsetParseErrorKind::NotInfixOperator {
1557                op: "+".to_owned(),
1558                similar_op: "|".to_owned(),
1559                description: "union".to_owned(),
1560            })
1561        );
1562        assert_eq!(
1563            parse_into_kind("foo - bar"),
1564            Err(RevsetParseErrorKind::NotInfixOperator {
1565                op: "-".to_owned(),
1566                similar_op: "~".to_owned(),
1567                description: "difference".to_owned(),
1568            })
1569        );
1570    }
1571
1572    #[test]
1573    fn test_parse_revset_operator_combinations() {
1574        // Parse repeated "parents" operator
1575        assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1576        // Parse repeated "children" operator
1577        assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1578        // Set operator associativity/precedence
1579        assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y"));
1580        assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)"));
1581        assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)"));
1582        assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1583        assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1584        assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1585        assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1586        assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1587        assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1588        assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1589        // Parse repeated "ancestors"/"descendants"/"dag range"/"range" operators
1590        assert_eq!(
1591            parse_into_kind("::foo::"),
1592            Err(RevsetParseErrorKind::SyntaxError)
1593        );
1594        assert_eq!(
1595            parse_into_kind(":::foo"),
1596            Err(RevsetParseErrorKind::SyntaxError)
1597        );
1598        assert_eq!(
1599            parse_into_kind("::::foo"),
1600            Err(RevsetParseErrorKind::SyntaxError)
1601        );
1602        assert_eq!(
1603            parse_into_kind("foo:::"),
1604            Err(RevsetParseErrorKind::SyntaxError)
1605        );
1606        assert_eq!(
1607            parse_into_kind("foo::::"),
1608            Err(RevsetParseErrorKind::SyntaxError)
1609        );
1610        assert_eq!(
1611            parse_into_kind("foo:::bar"),
1612            Err(RevsetParseErrorKind::SyntaxError)
1613        );
1614        assert_eq!(
1615            parse_into_kind("foo::::bar"),
1616            Err(RevsetParseErrorKind::SyntaxError)
1617        );
1618        assert_eq!(
1619            parse_into_kind("::foo::bar"),
1620            Err(RevsetParseErrorKind::SyntaxError)
1621        );
1622        assert_eq!(
1623            parse_into_kind("foo::bar::"),
1624            Err(RevsetParseErrorKind::SyntaxError)
1625        );
1626        assert_eq!(
1627            parse_into_kind("::::"),
1628            Err(RevsetParseErrorKind::SyntaxError)
1629        );
1630        assert_eq!(
1631            parse_into_kind("....foo"),
1632            Err(RevsetParseErrorKind::SyntaxError)
1633        );
1634        assert_eq!(
1635            parse_into_kind("foo...."),
1636            Err(RevsetParseErrorKind::SyntaxError)
1637        );
1638        assert_eq!(
1639            parse_into_kind("foo.....bar"),
1640            Err(RevsetParseErrorKind::SyntaxError)
1641        );
1642        assert_eq!(
1643            parse_into_kind("..foo..bar"),
1644            Err(RevsetParseErrorKind::SyntaxError)
1645        );
1646        assert_eq!(
1647            parse_into_kind("foo..bar.."),
1648            Err(RevsetParseErrorKind::SyntaxError)
1649        );
1650        assert_eq!(
1651            parse_into_kind("...."),
1652            Err(RevsetParseErrorKind::SyntaxError)
1653        );
1654        assert_eq!(
1655            parse_into_kind("::.."),
1656            Err(RevsetParseErrorKind::SyntaxError)
1657        );
1658        // Parse combinations of "parents"/"children" operators and the range operators.
1659        // The former bind more strongly.
1660        assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1661        assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1662        assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1663        assert_eq!(
1664            parse_into_kind("::-"),
1665            Err(RevsetParseErrorKind::SyntaxError)
1666        );
1667        assert_eq!(
1668            parse_into_kind("..+"),
1669            Err(RevsetParseErrorKind::SyntaxError)
1670        );
1671    }
1672
1673    #[test]
1674    fn test_parse_revset_function() {
1675        assert_matches!(
1676            parse_into_kind("parents(foo)"),
1677            Ok(ExpressionKind::FunctionCall(_))
1678        );
1679        assert_eq!(
1680            parse_normalized("parents((foo))"),
1681            parse_normalized("parents(foo)"),
1682        );
1683        assert_eq!(
1684            parse_into_kind("parents(foo"),
1685            Err(RevsetParseErrorKind::SyntaxError)
1686        );
1687    }
1688
1689    #[test]
1690    fn test_expand_symbol_alias() {
1691        assert_eq!(
1692            with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1693            parse_normalized("(a&b)|c")
1694        );
1695        assert_eq!(
1696            with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1697            parse_normalized("(a|b)::heads(a|b)")
1698        );
1699
1700        // Not string substitution 'a&b|c', but tree substitution.
1701        assert_eq!(
1702            with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1703            parse_normalized("a&(b|c)")
1704        );
1705
1706        // String literal should not be substituted with alias.
1707        assert_eq!(
1708            with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1709            parse_normalized("a|'A'|'A'")
1710        );
1711
1712        // Part of string pattern cannot be substituted.
1713        assert_eq!(
1714            with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1715            parse_normalized("author(exact:A)")
1716        );
1717
1718        // Part of @ symbol cannot be substituted.
1719        assert_eq!(
1720            with_aliases([("A", "a")]).parse_normalized("A@"),
1721            parse_normalized("A@")
1722        );
1723        assert_eq!(
1724            with_aliases([("A", "a")]).parse_normalized("A@b"),
1725            parse_normalized("A@b")
1726        );
1727        assert_eq!(
1728            with_aliases([("B", "b")]).parse_normalized("a@B"),
1729            parse_normalized("a@B")
1730        );
1731
1732        // Modifier cannot be substituted.
1733        assert_eq!(
1734            with_aliases([("all", "ALL")]).parse_normalized("all:all"),
1735            parse_normalized("all:ALL")
1736        );
1737
1738        // Top-level alias can be substituted to modifier expression.
1739        assert_eq!(
1740            with_aliases([("A", "all:a")]).parse_normalized("A"),
1741            parse_normalized("all:a")
1742        );
1743
1744        // Multi-level substitution.
1745        assert_eq!(
1746            with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1747            parse_normalized("b|c")
1748        );
1749
1750        // Infinite recursion, where the top-level error isn't of RecursiveAlias kind.
1751        assert_eq!(
1752            *with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1753            RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1754        );
1755        assert_eq!(
1756            *with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1757                .parse("A")
1758                .unwrap_err()
1759                .kind,
1760            RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1761        );
1762
1763        // Error in alias definition.
1764        assert_eq!(
1765            *with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1766            RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1767        );
1768    }
1769
1770    #[test]
1771    fn test_expand_function_alias() {
1772        assert_eq!(
1773            with_aliases([("F(  )", "a")]).parse_normalized("F()"),
1774            parse_normalized("a")
1775        );
1776        assert_eq!(
1777            with_aliases([("F( x  )", "x")]).parse_normalized("F(a)"),
1778            parse_normalized("a")
1779        );
1780        assert_eq!(
1781            with_aliases([("F( x,  y )", "x|y")]).parse_normalized("F(a, b)"),
1782            parse_normalized("a|b")
1783        );
1784
1785        // Not recursion because functions are overloaded by arity.
1786        assert_eq!(
1787            with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1788            parse_normalized("a|b")
1789        );
1790
1791        // Arguments should be resolved in the current scope.
1792        assert_eq!(
1793            with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1794            parse_normalized("(a::y)|(b::x)")
1795        );
1796        // F(a) -> G(a)&y -> (x|a)&y
1797        assert_eq!(
1798            with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1799            parse_normalized("(x|a)&y")
1800        );
1801        // F(G(a)) -> F(x|a) -> G(x|a)&y -> (x|(x|a))&y
1802        assert_eq!(
1803            with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1804            parse_normalized("(x|(x|a))&y")
1805        );
1806
1807        // Function parameter should precede the symbol alias.
1808        assert_eq!(
1809            with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1810            parse_normalized("a|x")
1811        );
1812
1813        // Function parameter shouldn't be expanded in symbol alias.
1814        assert_eq!(
1815            with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1816            parse_normalized("a|x")
1817        );
1818
1819        // String literal should not be substituted with function parameter.
1820        assert_eq!(
1821            with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1822            parse_normalized("a|'x'")
1823        );
1824
1825        // Modifier expression body as parameter.
1826        assert_eq!(
1827            with_aliases([("F(x)", "all:x")]).parse_normalized("F(a|b)"),
1828            parse_normalized("all:(a|b)")
1829        );
1830
1831        // Function and symbol aliases reside in separate namespaces.
1832        assert_eq!(
1833            with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1834            parse_normalized("a")
1835        );
1836
1837        // Invalid number of arguments.
1838        assert_eq!(
1839            *with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1840            RevsetParseErrorKind::InvalidFunctionArguments {
1841                name: "F".to_owned(),
1842                message: "Expected 0 arguments".to_owned()
1843            }
1844        );
1845        assert_eq!(
1846            *with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1847            RevsetParseErrorKind::InvalidFunctionArguments {
1848                name: "F".to_owned(),
1849                message: "Expected 1 arguments".to_owned()
1850            }
1851        );
1852        assert_eq!(
1853            *with_aliases([("F(x,y)", "x|y")])
1854                .parse("F(a,b,c)")
1855                .unwrap_err()
1856                .kind,
1857            RevsetParseErrorKind::InvalidFunctionArguments {
1858                name: "F".to_owned(),
1859                message: "Expected 2 arguments".to_owned()
1860            }
1861        );
1862        assert_eq!(
1863            *with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1864                .parse("F()")
1865                .unwrap_err()
1866                .kind,
1867            RevsetParseErrorKind::InvalidFunctionArguments {
1868                name: "F".to_owned(),
1869                message: "Expected 1 to 2 arguments".to_owned()
1870            }
1871        );
1872        assert_eq!(
1873            *with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1874                .parse("F(a)")
1875                .unwrap_err()
1876                .kind,
1877            RevsetParseErrorKind::InvalidFunctionArguments {
1878                name: "F".to_owned(),
1879                message: "Expected 0, 2 arguments".to_owned()
1880            }
1881        );
1882
1883        // Keyword argument isn't supported for now.
1884        assert_eq!(
1885            *with_aliases([("F(x)", "x")])
1886                .parse("F(x=y)")
1887                .unwrap_err()
1888                .kind,
1889            RevsetParseErrorKind::InvalidFunctionArguments {
1890                name: "F".to_owned(),
1891                message: "Unexpected keyword arguments".to_owned()
1892            }
1893        );
1894
1895        // Infinite recursion, where the top-level error isn't of RecursiveAlias kind.
1896        assert_eq!(
1897            *with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1898                .parse("F(a)")
1899                .unwrap_err()
1900                .kind,
1901            RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1902        );
1903        assert_eq!(
1904            *with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1905                .parse("F(a)")
1906                .unwrap_err()
1907                .kind,
1908            RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1909        );
1910    }
1911
1912    #[test]
1913    fn test_expand_with_locals() {
1914        // Local variable should precede the symbol alias.
1915        assert_eq!(
1916            with_aliases([("A", "symbol")])
1917                .set_local("A", "local")
1918                .parse_normalized("A"),
1919            parse_normalized("local")
1920        );
1921
1922        // Local variable shouldn't be expanded within aliases.
1923        assert_eq!(
1924            with_aliases([("B", "A"), ("F(x)", "x&A")])
1925                .set_local("A", "a")
1926                .parse_normalized("A|B|F(A)"),
1927            parse_normalized("a|A|(a&A)")
1928        );
1929    }
1930}