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