Skip to main content

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