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