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