1#![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 fn is_compat(&self) -> bool {
71 matches!(
72 self,
73 Self::compat_parents_op
74 | Self::compat_dag_range_op
75 | Self::compat_dag_range_pre_op
76 | Self::compat_dag_range_post_op
77 | Self::compat_add_op
78 | Self::compat_sub_op
79 )
80 }
81
82 fn to_symbol(self) -> Option<&'static str> {
83 match self {
84 Self::EOI => None,
85 Self::whitespace => None,
86 Self::identifier_part => None,
87 Self::identifier => None,
88 Self::strict_identifier_part => None,
89 Self::strict_identifier => None,
90 Self::symbol => None,
91 Self::string_escape => None,
92 Self::string_content_char => None,
93 Self::string_content => None,
94 Self::string_literal => None,
95 Self::raw_string_content => None,
96 Self::raw_string_literal => None,
97 Self::at_op => Some("@"),
98 Self::pattern_kind_op => Some(":"),
99 Self::parents_op => Some("-"),
100 Self::children_op => Some("+"),
101 Self::compat_parents_op => Some("^"),
102 Self::dag_range_op
103 | Self::dag_range_pre_op
104 | Self::dag_range_post_op
105 | Self::dag_range_all_op => Some("::"),
106 Self::compat_dag_range_op
107 | Self::compat_dag_range_pre_op
108 | Self::compat_dag_range_post_op => Some(":"),
109 Self::range_op => Some(".."),
110 Self::range_pre_op | Self::range_post_op | Self::range_all_op => Some(".."),
111 Self::range_ops => None,
112 Self::range_pre_ops => None,
113 Self::range_post_ops => None,
114 Self::range_all_ops => None,
115 Self::negate_op => Some("~"),
116 Self::union_op => Some("|"),
117 Self::intersection_op => Some("&"),
118 Self::difference_op => Some("~"),
119 Self::compat_add_op => Some("+"),
120 Self::compat_sub_op => Some("-"),
121 Self::infix_op => None,
122 Self::function => None,
123 Self::function_name => None,
124 Self::keyword_argument => None,
125 Self::argument => None,
126 Self::function_arguments => None,
127 Self::formal_parameters => None,
128 Self::pattern => None,
129 Self::pattern_value_expression => None,
130 Self::primary => None,
131 Self::neighbors_expression => None,
132 Self::range_expression => None,
133 Self::expression => None,
134 Self::program => None,
135 Self::symbol_name => None,
136 Self::function_alias_declaration => None,
137 Self::pattern_alias_declaration => None,
138 Self::alias_declaration => None,
139 }
140 }
141}
142
143pub type RevsetDiagnostics = Diagnostics<RevsetParseError>;
146
147#[derive(Debug, Error)]
148#[error("{pest_error}")]
149pub struct RevsetParseError {
150 kind: Box<RevsetParseErrorKind>,
151 pest_error: Box<pest::error::Error<Rule>>,
152 source: Option<Box<dyn error::Error + Send + Sync>>,
153}
154
155#[derive(Debug, Error, PartialEq, Eq)]
156pub enum RevsetParseErrorKind {
157 #[error("Syntax error")]
158 SyntaxError,
159 #[error("`{op}` is not a prefix operator")]
160 NotPrefixOperator {
161 op: String,
162 similar_op: String,
163 description: String,
164 },
165 #[error("`{op}` is not a postfix operator")]
166 NotPostfixOperator {
167 op: String,
168 similar_op: String,
169 description: String,
170 },
171 #[error("`{op}` is not an infix operator")]
172 NotInfixOperator {
173 op: String,
174 similar_op: String,
175 description: String,
176 },
177 #[error("Function `{name}` doesn't exist")]
178 NoSuchFunction {
179 name: String,
180 candidates: Vec<String>,
181 },
182 #[error("Function `{name}`: {message}")]
183 InvalidFunctionArguments { name: String, message: String },
184 #[error("Cannot resolve file pattern without workspace")]
185 FsPathWithoutWorkspace,
186 #[error("Cannot resolve `@` without workspace")]
187 WorkingCopyWithoutWorkspace,
188 #[error("Redefinition of function parameter")]
189 RedefinedFunctionParameter,
190 #[error("{0}")]
191 Expression(String),
192 #[error("In alias `{0}`")]
193 InAliasExpansion(String),
194 #[error("In function parameter `{0}`")]
195 InParameterExpansion(String),
196 #[error("Alias `{0}` expanded recursively")]
197 RecursiveAlias(String),
198}
199
200impl RevsetParseError {
201 pub(super) fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self {
202 let message = kind.to_string();
203 let pest_error = Box::new(pest::error::Error::new_from_span(
204 pest::error::ErrorVariant::CustomError { message },
205 span,
206 ));
207 Self {
208 kind: Box::new(kind),
209 pest_error,
210 source: None,
211 }
212 }
213
214 pub(super) fn with_source(
215 mut self,
216 source: impl Into<Box<dyn error::Error + Send + Sync>>,
217 ) -> Self {
218 self.source = Some(source.into());
219 self
220 }
221
222 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
224 Self::with_span(RevsetParseErrorKind::Expression(message.into()), span)
225 }
226
227 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 pub fn origin(&self) -> Option<&Self> {
249 self.source.as_ref().and_then(|e| e.downcast_ref())
250 }
251}
252
253impl AliasExpandError for RevsetParseError {
254 fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
255 err.into()
256 }
257
258 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
259 Self::with_span(RevsetParseErrorKind::RecursiveAlias(id.to_string()), span)
260 }
261
262 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
263 let kind = match id {
264 AliasId::Symbol(_) | AliasId::Pattern(..) | AliasId::Function(..) => {
265 RevsetParseErrorKind::InAliasExpansion(id.to_string())
266 }
267 AliasId::Parameter(_) => RevsetParseErrorKind::InParameterExpansion(id.to_string()),
268 };
269 Self::with_span(kind, span).with_source(self)
270 }
271}
272
273impl From<pest::error::Error<Rule>> for RevsetParseError {
274 fn from(err: pest::error::Error<Rule>) -> Self {
275 Self {
276 kind: Box::new(RevsetParseErrorKind::SyntaxError),
277 pest_error: Box::new(rename_rules_in_pest_error(err)),
278 source: None,
279 }
280 }
281}
282
283impl From<InvalidArguments<'_>> for RevsetParseError {
284 fn from(err: InvalidArguments<'_>) -> Self {
285 let kind = RevsetParseErrorKind::InvalidFunctionArguments {
286 name: err.name.to_owned(),
287 message: err.message,
288 };
289 Self::with_span(kind, err.span)
290 }
291}
292
293fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
294 let pest::error::ErrorVariant::ParsingError {
295 positives,
296 negatives,
297 } = &mut err.variant
298 else {
299 return err;
300 };
301
302 let mut known_syms = HashSet::new();
305 positives.retain(|rule| {
306 !rule.is_compat() && rule.to_symbol().is_none_or(|sym| known_syms.insert(sym))
307 });
308 let mut known_syms = HashSet::new();
309 negatives.retain(|rule| rule.to_symbol().is_none_or(|sym| known_syms.insert(sym)));
310 err.renamed_rules(|rule| {
311 rule.to_symbol()
312 .map(|sym| format!("`{sym}`"))
313 .unwrap_or_else(|| format!("<{rule:?}>"))
314 })
315}
316
317#[derive(Clone, Debug, Eq, PartialEq)]
318pub enum ExpressionKind<'i> {
319 Identifier(&'i str),
321 String(String),
323 Pattern(Box<PatternNode<'i>>),
325 RemoteSymbol(RemoteRefSymbolBuf),
327 AtWorkspace(String),
329 AtCurrentWorkspace,
331 DagRangeAll,
333 RangeAll,
335 Unary(UnaryOp, Box<ExpressionNode<'i>>),
336 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
337 UnionAll(Vec<ExpressionNode<'i>>),
339 FunctionCall(Box<FunctionCallNode<'i>>),
340 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
342}
343
344impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
345 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
346 where
347 F: ExpressionFolder<'i, Self> + ?Sized,
348 {
349 match self {
350 Self::Identifier(name) => folder.fold_identifier(name, span),
351 Self::String(_) => Ok(self),
352 Self::Pattern(pattern) => folder.fold_pattern(pattern, span),
353 Self::RemoteSymbol(_)
354 | ExpressionKind::AtWorkspace(_)
355 | Self::AtCurrentWorkspace
356 | Self::DagRangeAll
357 | Self::RangeAll => Ok(self),
358 Self::Unary(op, arg) => {
359 let arg = Box::new(folder.fold_expression(*arg)?);
360 Ok(Self::Unary(op, arg))
361 }
362 Self::Binary(op, lhs, rhs) => {
363 let lhs = Box::new(folder.fold_expression(*lhs)?);
364 let rhs = Box::new(folder.fold_expression(*rhs)?);
365 Ok(Self::Binary(op, lhs, rhs))
366 }
367 Self::UnionAll(nodes) => {
368 let nodes = dsl_util::fold_expression_nodes(folder, nodes)?;
369 Ok(Self::UnionAll(nodes))
370 }
371 Self::FunctionCall(function) => folder.fold_function_call(function, span),
372 Self::AliasExpanded(id, subst) => {
373 let subst = Box::new(folder.fold_expression(*subst)?);
374 Ok(Self::AliasExpanded(id, subst))
375 }
376 }
377 }
378}
379
380impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
381 fn identifier(name: &'i str) -> Self {
382 Self::Identifier(name)
383 }
384
385 fn pattern(pattern: Box<PatternNode<'i>>) -> Self {
386 Self::Pattern(pattern)
387 }
388
389 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
390 Self::FunctionCall(function)
391 }
392
393 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
394 Self::AliasExpanded(id, subst)
395 }
396}
397
398#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
399pub enum UnaryOp {
400 Negate,
402 DagRangePre,
404 DagRangePost,
406 RangePre,
408 RangePost,
410 Parents,
412 Children,
414}
415
416#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
417pub enum BinaryOp {
418 Intersection,
420 Difference,
422 DagRange,
424 Range,
426}
427
428pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
429pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
430pub type PatternNode<'i> = dsl_util::PatternNode<'i, ExpressionKind<'i>>;
431
432fn union_nodes<'i>(lhs: ExpressionNode<'i>, rhs: ExpressionNode<'i>) -> ExpressionNode<'i> {
433 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
434 let expr = match lhs.kind {
435 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
446pub 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 .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 .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 Rule::expression => parse_expression_node(first)?.kind,
589 Rule::function => {
590 let function = Box::new(FUNCTION_CALL_PARSER.parse(
591 first,
592 |pair| Ok(pair.as_str()),
593 |pair| parse_expression_node(pair),
594 )?);
595 ExpressionKind::FunctionCall(function)
596 }
597 Rule::pattern => {
598 let [lhs, op, rhs] = first.into_inner().collect_array().unwrap();
599 assert_eq!(lhs.as_rule(), Rule::strict_identifier);
600 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
601 assert_eq!(rhs.as_rule(), Rule::pattern_value_expression);
602 let pattern = Box::new(PatternNode {
603 name: lhs.as_str(),
604 name_span: lhs.as_span(),
605 value: parse_expression_node(rhs)?,
606 });
607 ExpressionKind::Pattern(pattern)
608 }
609 Rule::identifier if pairs.peek().is_none() => ExpressionKind::Identifier(first.as_str()),
612 Rule::identifier | Rule::string_literal | Rule::raw_string_literal => {
613 let name = parse_as_string_literal(first);
614 match pairs.next() {
615 None => ExpressionKind::String(name),
616 Some(op) => {
617 assert_eq!(op.as_rule(), Rule::at_op);
618 match pairs.next() {
619 None => ExpressionKind::AtWorkspace(name),
621 Some(second) => {
623 let name: RefNameBuf = name.into();
624 let remote: RemoteNameBuf = parse_as_string_literal(second).into();
625 ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf { name, remote })
626 }
627 }
628 }
629 }
630 }
631 Rule::at_op => ExpressionKind::AtCurrentWorkspace,
633 r => panic!("unexpected revset parse rule: {r:?}"),
634 };
635 Ok(ExpressionNode::new(expr, span))
636}
637
638fn parse_as_string_literal(pair: Pair<Rule>) -> String {
640 match pair.as_rule() {
641 Rule::identifier => pair.as_str().to_owned(),
642 Rule::string_literal => STRING_LITERAL_PARSER.parse(pair.into_inner()),
643 Rule::raw_string_literal => {
644 let [content] = pair.into_inner().collect_array().unwrap();
645 assert_eq!(content.as_rule(), Rule::raw_string_content);
646 content.as_str().to_owned()
647 }
648 _ => {
649 panic!("unexpected string literal rule: {:?}", pair.as_str());
650 }
651 }
652}
653
654pub fn is_identifier(text: &str) -> bool {
656 match RevsetParser::parse(Rule::identifier, text) {
657 Ok(mut pairs) => pairs.next().unwrap().as_span().end() == text.len(),
658 Err(_) => false,
659 }
660}
661
662pub fn parse_symbol(text: &str) -> Result<String, RevsetParseError> {
664 let mut pairs = RevsetParser::parse(Rule::symbol_name, text)?;
665 let first = pairs.next().unwrap();
666 let span = first.as_span();
667 let name = parse_as_string_literal(first);
668 if name.is_empty() {
669 Err(RevsetParseError::expression(
670 "Expected non-empty string",
671 span,
672 ))
673 } else {
674 Ok(name)
675 }
676}
677
678pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser, String>;
679
680#[derive(Clone, Debug, Default)]
681pub struct RevsetAliasParser;
682
683impl AliasDeclarationParser for RevsetAliasParser {
684 type Error = RevsetParseError;
685
686 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
687 let mut pairs = RevsetParser::parse(Rule::alias_declaration, source)?;
688 let first = pairs.next().unwrap();
689 match first.as_rule() {
690 Rule::strict_identifier => Ok(AliasDeclaration::Symbol(first.as_str().to_owned())),
691 Rule::pattern_alias_declaration => {
692 let [name_pair, op, param_pair] = first.into_inner().collect_array().unwrap();
693 assert_eq!(name_pair.as_rule(), Rule::strict_identifier);
694 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
695 assert_eq!(param_pair.as_rule(), Rule::strict_identifier);
696 let name = name_pair.as_str().to_owned();
697 let param = param_pair.as_str().to_owned();
698 Ok(AliasDeclaration::Pattern(name, param))
699 }
700 Rule::function_alias_declaration => {
701 let [name_pair, params_pair] = first.into_inner().collect_array().unwrap();
702 assert_eq!(name_pair.as_rule(), Rule::function_name);
703 assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
704 let name = name_pair.as_str().to_owned();
705 let params_span = params_pair.as_span();
706 let params = params_pair
707 .into_inner()
708 .map(|pair| match pair.as_rule() {
709 Rule::strict_identifier => pair.as_str().to_owned(),
710 r => panic!("unexpected formal parameter rule {r:?}"),
711 })
712 .collect_vec();
713 if params.iter().all_unique() {
714 Ok(AliasDeclaration::Function(name, params))
715 } else {
716 Err(RevsetParseError::with_span(
717 RevsetParseErrorKind::RedefinedFunctionParameter,
718 params_span,
719 ))
720 }
721 }
722 r => panic!("unexpected alias declaration rule {r:?}"),
723 }
724 }
725}
726
727impl AliasDefinitionParser for RevsetAliasParser {
728 type Output<'i> = ExpressionKind<'i>;
729 type Error = RevsetParseError;
730
731 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
732 parse_program(source)
733 }
734}
735
736pub(super) fn expect_string_pattern<'a>(
737 type_name: &str,
738 node: &'a ExpressionNode<'_>,
739) -> Result<(&'a str, Option<&'a str>), RevsetParseError> {
740 catch_aliases_no_diagnostics(node, |node| match &node.kind {
741 ExpressionKind::Identifier(name) => Ok((*name, None)),
742 ExpressionKind::String(name) => Ok((name, None)),
743 ExpressionKind::Pattern(pattern) => {
744 let value = expect_string_literal("string", &pattern.value)?;
745 Ok((value, Some(pattern.name)))
746 }
747 _ => Err(RevsetParseError::expression(
748 format!("Expected {type_name}"),
749 node.span,
750 )),
751 })
752}
753
754pub fn expect_literal<T: FromStr>(
755 type_name: &str,
756 node: &ExpressionNode,
757) -> Result<T, RevsetParseError> {
758 catch_aliases_no_diagnostics(node, |node| {
759 let value = expect_string_literal(type_name, node)?;
760 value
761 .parse()
762 .map_err(|_| RevsetParseError::expression(format!("Expected {type_name}"), node.span))
763 })
764}
765
766pub(super) fn expect_string_literal<'a>(
767 type_name: &str,
768 node: &'a ExpressionNode<'_>,
769) -> Result<&'a str, RevsetParseError> {
770 catch_aliases_no_diagnostics(node, |node| match &node.kind {
771 ExpressionKind::Identifier(name) => Ok(*name),
772 ExpressionKind::String(name) => Ok(name),
773 _ => Err(RevsetParseError::expression(
774 format!("Expected {type_name}"),
775 node.span,
776 )),
777 })
778}
779
780pub(super) fn catch_aliases<'a, 'i, T>(
783 diagnostics: &mut RevsetDiagnostics,
784 node: &'a ExpressionNode<'i>,
785 f: impl FnOnce(&mut RevsetDiagnostics, &'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
786) -> Result<T, RevsetParseError> {
787 let (node, stack) = skip_aliases(node);
788 if stack.is_empty() {
789 f(diagnostics, node)
790 } else {
791 let mut inner_diagnostics = RevsetDiagnostics::new();
792 let result = f(&mut inner_diagnostics, node);
793 diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
794 result.map_err(|err| attach_aliases_err(err, &stack))
795 }
796}
797
798fn catch_aliases_no_diagnostics<'a, 'i, T>(
799 node: &'a ExpressionNode<'i>,
800 f: impl FnOnce(&'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
801) -> Result<T, RevsetParseError> {
802 let (node, stack) = skip_aliases(node);
803 f(node).map_err(|err| attach_aliases_err(err, &stack))
804}
805
806fn skip_aliases<'a, 'i>(
807 mut node: &'a ExpressionNode<'i>,
808) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
809 let mut stack = Vec::new();
810 while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
811 stack.push((*id, node.span));
812 node = subst;
813 }
814 (node, stack)
815}
816
817fn attach_aliases_err(
818 err: RevsetParseError,
819 stack: &[(AliasId<'_>, pest::Span<'_>)],
820) -> RevsetParseError {
821 stack
822 .iter()
823 .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
824}
825
826#[cfg(test)]
827mod tests {
828 use std::collections::HashMap;
829
830 use assert_matches::assert_matches;
831
832 use super::*;
833 use crate::dsl_util::KeywordArgument;
834
835 #[derive(Debug)]
836 struct WithRevsetAliasesMap<'i> {
837 aliases_map: RevsetAliasesMap,
838 locals: HashMap<&'i str, ExpressionNode<'i>>,
839 }
840
841 impl<'i> WithRevsetAliasesMap<'i> {
842 fn set_local(mut self, name: &'i str, value: &'i str) -> Self {
843 self.locals.insert(name, parse_program(value).unwrap());
844 self
845 }
846
847 fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
848 let node = parse_program(text)?;
849 dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals)
850 }
851
852 fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> {
853 normalize_tree(self.parse(text).unwrap())
854 }
855 }
856
857 fn with_aliases<'i>(
858 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
859 ) -> WithRevsetAliasesMap<'i> {
860 let mut aliases_map = RevsetAliasesMap::new();
861 for (decl, defn) in aliases {
862 aliases_map.insert(decl, defn).unwrap();
863 }
864 WithRevsetAliasesMap {
865 aliases_map,
866 locals: HashMap::new(),
867 }
868 }
869
870 fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
871 parse_program(text)
872 .map(|node| node.kind)
873 .map_err(|err| *err.kind)
874 }
875
876 fn parse_normalized(text: &str) -> ExpressionNode<'_> {
877 normalize_tree(parse_program(text).unwrap())
878 }
879
880 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
882 fn empty_span() -> pest::Span<'static> {
883 pest::Span::new("", 0, 0).unwrap()
884 }
885
886 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
887 nodes.into_iter().map(normalize_tree).collect()
888 }
889
890 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
891 FunctionCallNode {
892 name: function.name,
893 name_span: empty_span(),
894 args: normalize_list(function.args),
895 keyword_args: function
896 .keyword_args
897 .into_iter()
898 .map(|arg| KeywordArgument {
899 name: arg.name,
900 name_span: empty_span(),
901 value: normalize_tree(arg.value),
902 })
903 .collect(),
904 args_span: empty_span(),
905 }
906 }
907
908 let normalized_kind = match node.kind {
909 ExpressionKind::Identifier(_) | ExpressionKind::String(_) => node.kind,
910 ExpressionKind::Pattern(pattern) => {
911 let pattern = Box::new(PatternNode {
912 name: pattern.name,
913 name_span: empty_span(),
914 value: normalize_tree(pattern.value),
915 });
916 ExpressionKind::Pattern(pattern)
917 }
918 ExpressionKind::RemoteSymbol(_)
919 | ExpressionKind::AtWorkspace(_)
920 | ExpressionKind::AtCurrentWorkspace
921 | ExpressionKind::DagRangeAll
922 | ExpressionKind::RangeAll => node.kind,
923 ExpressionKind::Unary(op, arg) => {
924 let arg = Box::new(normalize_tree(*arg));
925 ExpressionKind::Unary(op, arg)
926 }
927 ExpressionKind::Binary(op, lhs, rhs) => {
928 let lhs = Box::new(normalize_tree(*lhs));
929 let rhs = Box::new(normalize_tree(*rhs));
930 ExpressionKind::Binary(op, lhs, rhs)
931 }
932 ExpressionKind::UnionAll(nodes) => {
933 let nodes = normalize_list(nodes);
934 ExpressionKind::UnionAll(nodes)
935 }
936 ExpressionKind::FunctionCall(function) => {
937 let function = Box::new(normalize_function_call(*function));
938 ExpressionKind::FunctionCall(function)
939 }
940 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
941 };
942 ExpressionNode {
943 kind: normalized_kind,
944 span: empty_span(),
945 }
946 }
947
948 #[test]
949 fn test_parse_tree_eq() {
950 assert_eq!(
951 parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
952 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
953 );
954 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
955 }
956
957 #[test]
958 fn test_parse_revset() {
959 assert_eq!(
961 parse_into_kind("\"foo\""),
962 Ok(ExpressionKind::String("foo".to_owned()))
963 );
964 assert_eq!(
965 parse_into_kind("'foo'"),
966 Ok(ExpressionKind::String("foo".to_owned()))
967 );
968 assert_matches!(
970 parse_into_kind("foo-"),
971 Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
972 );
973 assert_matches!(
975 parse_into_kind("foo+"),
976 Ok(ExpressionKind::Unary(UnaryOp::Children, _))
977 );
978 assert_matches!(
980 parse_into_kind("::foo"),
981 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
982 );
983 assert_matches!(
985 parse_into_kind("foo::"),
986 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
987 );
988 assert_matches!(
990 parse_into_kind("foo::bar"),
991 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
992 );
993 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
995 assert_matches!(
997 parse_into_kind("..foo"),
998 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
999 );
1000 assert_matches!(
1001 parse_into_kind("foo.."),
1002 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
1003 );
1004 assert_matches!(
1005 parse_into_kind("foo..bar"),
1006 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
1007 );
1008 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
1010 assert_matches!(
1012 parse_into_kind("~ foo"),
1013 Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1014 );
1015 assert_eq!(
1016 parse_normalized("~ ~~ foo"),
1017 parse_normalized("~(~(~(foo)))"),
1018 );
1019 assert_matches!(
1021 parse_into_kind("foo & bar"),
1022 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1023 );
1024 assert_matches!(
1026 parse_into_kind("foo | bar"),
1027 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1028 );
1029 assert_matches!(
1030 parse_into_kind("foo | bar | baz"),
1031 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1032 );
1033 assert_matches!(
1035 parse_into_kind("foo ~ bar"),
1036 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1037 );
1038 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1040 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1042 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1043 assert_eq!(
1045 parse_into_kind(" :: foo "),
1046 Err(RevsetParseErrorKind::SyntaxError)
1047 );
1048 assert_eq!(
1050 parse_into_kind("foo | -"),
1051 Err(RevsetParseErrorKind::SyntaxError)
1052 );
1053
1054 assert_eq!(parse_program(" ~ x ").unwrap().span.as_str(), "~ x");
1056 assert_eq!(parse_program(" x+ ").unwrap().span.as_str(), "x+");
1057 assert_eq!(parse_program(" x |y ").unwrap().span.as_str(), "x |y");
1058 assert_eq!(parse_program(" (x) ").unwrap().span.as_str(), "(x)");
1059 assert_eq!(parse_program("~( x|y) ").unwrap().span.as_str(), "~( x|y)");
1060 assert_eq!(parse_program(" ( x )- ").unwrap().span.as_str(), "( x )-");
1061 }
1062
1063 #[test]
1064 fn test_parse_whitespace() {
1065 let ascii_whitespaces: String = ('\x00'..='\x7f')
1066 .filter(char::is_ascii_whitespace)
1067 .collect();
1068 assert_eq!(
1069 parse_normalized(&format!("{ascii_whitespaces}all()")),
1070 parse_normalized("all()"),
1071 );
1072 }
1073
1074 #[test]
1075 fn test_parse_identifier() {
1076 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1078 assert_eq!(
1080 parse_into_kind("foo_bar/baz"),
1081 Ok(ExpressionKind::Identifier("foo_bar/baz"))
1082 );
1083 assert_eq!(
1085 parse_into_kind("*/foo/**"),
1086 Ok(ExpressionKind::Identifier("*/foo/**"))
1087 );
1088
1089 assert_eq!(
1091 parse_into_kind("foo.bar-v1+7"),
1092 Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1093 );
1094 assert_eq!(
1095 parse_normalized("foo.bar-v1+7-"),
1096 parse_normalized("(foo.bar-v1+7)-")
1097 );
1098 assert_eq!(
1100 parse_into_kind("foo--bar"),
1101 Ok(ExpressionKind::Identifier("foo--bar"))
1102 );
1103 assert_eq!(
1104 parse_into_kind("foo----bar"),
1105 Ok(ExpressionKind::Identifier("foo----bar"))
1106 );
1107 assert_eq!(
1109 parse_into_kind(".foo"),
1110 Err(RevsetParseErrorKind::SyntaxError)
1111 );
1112 assert_eq!(
1113 parse_into_kind("foo."),
1114 Err(RevsetParseErrorKind::SyntaxError)
1115 );
1116 assert_eq!(
1118 parse_into_kind("foo.+bar"),
1119 Err(RevsetParseErrorKind::SyntaxError)
1120 );
1121 assert_eq!(
1122 parse_into_kind("foo++bar"),
1123 Err(RevsetParseErrorKind::SyntaxError)
1124 );
1125 assert_eq!(
1126 parse_into_kind("foo+-bar"),
1127 Err(RevsetParseErrorKind::SyntaxError)
1128 );
1129
1130 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1132
1133 assert_eq!(
1135 parse_into_kind("柔術+jj"),
1136 Ok(ExpressionKind::Identifier("柔術+jj"))
1137 );
1138 }
1139
1140 #[test]
1141 fn test_parse_string_literal() {
1142 assert_eq!(
1144 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1145 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1146 );
1147
1148 assert_eq!(
1150 parse_into_kind(r#" "\y" "#),
1151 Err(RevsetParseErrorKind::SyntaxError)
1152 );
1153
1154 assert_eq!(
1156 parse_into_kind(r#" '' "#),
1157 Ok(ExpressionKind::String("".to_owned()))
1158 );
1159 assert_eq!(
1160 parse_into_kind(r#" 'a\n' "#),
1161 Ok(ExpressionKind::String(r"a\n".to_owned()))
1162 );
1163 assert_eq!(
1164 parse_into_kind(r#" '\' "#),
1165 Ok(ExpressionKind::String(r"\".to_owned()))
1166 );
1167 assert_eq!(
1168 parse_into_kind(r#" '"' "#),
1169 Ok(ExpressionKind::String(r#"""#.to_owned()))
1170 );
1171
1172 assert_eq!(
1174 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1175 Ok(ExpressionKind::String("aeiou".to_owned()))
1176 );
1177 assert_eq!(
1178 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1179 Ok(ExpressionKind::String("àèìðù".to_owned()))
1180 );
1181 assert_eq!(
1182 parse_into_kind(r#""\x""#),
1183 Err(RevsetParseErrorKind::SyntaxError)
1184 );
1185 assert_eq!(
1186 parse_into_kind(r#""\xf""#),
1187 Err(RevsetParseErrorKind::SyntaxError)
1188 );
1189 assert_eq!(
1190 parse_into_kind(r#""\xgg""#),
1191 Err(RevsetParseErrorKind::SyntaxError)
1192 );
1193 }
1194
1195 #[test]
1196 fn test_parse_pattern() {
1197 fn unwrap_pattern(kind: ExpressionKind<'_>) -> (&str, ExpressionKind<'_>) {
1198 match kind {
1199 ExpressionKind::Pattern(pattern) => (pattern.name, pattern.value.kind),
1200 _ => panic!("unexpected expression: {kind:?}"),
1201 }
1202 }
1203
1204 assert_eq!(
1205 unwrap_pattern(parse_into_kind(r#"substring:"foo""#).unwrap()),
1206 ("substring", ExpressionKind::String("foo".to_owned()))
1207 );
1208 assert_eq!(
1209 unwrap_pattern(parse_into_kind("exact:foo").unwrap()),
1210 ("exact", ExpressionKind::Identifier("foo"))
1211 );
1212 assert_eq!(
1213 parse_into_kind(r#""exact:foo""#),
1214 Ok(ExpressionKind::String("exact:foo".to_owned()))
1215 );
1216 assert_eq!(
1218 unwrap_pattern(parse_into_kind("x:@").unwrap()),
1219 ("x", ExpressionKind::AtCurrentWorkspace)
1220 );
1221 assert_eq!(
1222 unwrap_pattern(parse_into_kind("x:y@z").unwrap()),
1223 (
1224 "x",
1225 ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1226 name: "y".into(),
1227 remote: "z".into(),
1228 })
1229 )
1230 );
1231
1232 assert_eq!(
1233 parse_normalized(r#"(exact:"foo" )"#),
1234 parse_normalized(r#"(exact:"foo")"#),
1235 );
1236 assert_eq!(
1237 unwrap_pattern(parse_into_kind(r#"exact:'\'"#).unwrap()),
1238 ("exact", ExpressionKind::String(r"\".to_owned()))
1239 );
1240
1241 assert_matches!(
1243 parse_into_kind("exact: foo"),
1244 Err(RevsetParseErrorKind::SyntaxError)
1245 );
1246 assert_matches!(
1247 parse_into_kind("exact :foo"),
1248 Err(RevsetParseErrorKind::SyntaxError)
1249 );
1250 assert_eq!(
1252 parse_normalized("exact:( 'foo' )"),
1253 parse_normalized("exact:'foo'"),
1254 );
1255
1256 assert_eq!(parse_normalized("x:f(y)"), parse_normalized("x:(f(y))"));
1258 assert_eq!(parse_normalized("x:@-+"), parse_normalized("x:((@-)+)"));
1260 assert_eq!(parse_normalized("x:y::z"), parse_normalized("(x:y)::(z)"));
1263 assert_matches!(
1264 parse_into_kind("x:::"),
1265 Err(RevsetParseErrorKind::SyntaxError)
1266 );
1267 assert_eq!(parse_normalized("x:y&z"), parse_normalized("(x:y)&(z)"));
1269 assert_matches!(
1270 parse_into_kind("x:~y"), Err(RevsetParseErrorKind::NotPostfixOperator { .. })
1272 );
1273
1274 assert_eq!(parse_normalized("x:y:z"), parse_normalized("x:(y:z)"));
1276 }
1277
1278 #[test]
1279 fn test_parse_symbol_explicitly() {
1280 assert_matches!(parse_symbol("").as_deref(), Err(_));
1281 assert_matches!(parse_symbol("''").as_deref(), Err(_));
1284
1285 assert_matches!(parse_symbol("foo.bar").as_deref(), Ok("foo.bar"));
1286 assert_matches!(parse_symbol("foo@bar").as_deref(), Err(_));
1287 assert_matches!(parse_symbol("foo bar").as_deref(), Err(_));
1288
1289 assert_matches!(parse_symbol("'foo bar'").as_deref(), Ok("foo bar"));
1290 assert_matches!(parse_symbol(r#""foo\tbar""#).as_deref(), Ok("foo\tbar"));
1291
1292 assert_matches!(parse_symbol(" foo").as_deref(), Err(_));
1294 assert_matches!(parse_symbol("foo ").as_deref(), Err(_));
1295
1296 assert_matches!(parse_symbol("(foo)").as_deref(), Err(_));
1299 }
1300
1301 #[test]
1302 fn parse_at_workspace_and_remote_symbol() {
1303 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1305 assert_eq!(
1306 parse_into_kind("main@"),
1307 Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1308 );
1309 assert_eq!(
1310 parse_into_kind("main@origin"),
1311 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1312 name: "main".into(),
1313 remote: "origin".into()
1314 }))
1315 );
1316
1317 assert_eq!(
1319 parse_into_kind(r#""foo bar"@"#),
1320 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1321 );
1322 assert_eq!(
1323 parse_into_kind(r#""foo bar"@origin"#),
1324 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1325 name: "foo bar".into(),
1326 remote: "origin".into()
1327 }))
1328 );
1329 assert_eq!(
1330 parse_into_kind(r#"main@"foo bar""#),
1331 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1332 name: "main".into(),
1333 remote: "foo bar".into()
1334 }))
1335 );
1336 assert_eq!(
1337 parse_into_kind(r#"'foo bar'@'bar baz'"#),
1338 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1339 name: "foo bar".into(),
1340 remote: "bar baz".into()
1341 }))
1342 );
1343
1344 assert_eq!(
1346 parse_into_kind(r#""@""#),
1347 Ok(ExpressionKind::String("@".to_owned()))
1348 );
1349 assert_eq!(
1350 parse_into_kind(r#""main@""#),
1351 Ok(ExpressionKind::String("main@".to_owned()))
1352 );
1353 assert_eq!(
1354 parse_into_kind(r#""main@origin""#),
1355 Ok(ExpressionKind::String("main@origin".to_owned()))
1356 );
1357
1358 assert_eq!(
1360 parse_into_kind("柔術@"),
1361 Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1362 );
1363 assert_eq!(
1364 parse_into_kind("柔@術"),
1365 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1366 name: "柔".into(),
1367 remote: "術".into()
1368 }))
1369 );
1370 }
1371
1372 #[test]
1373 fn test_parse_function_call() {
1374 fn unwrap_function_call(node: ExpressionNode<'_>) -> Box<FunctionCallNode<'_>> {
1375 match node.kind {
1376 ExpressionKind::FunctionCall(function) => function,
1377 _ => panic!("unexpected expression: {node:?}"),
1378 }
1379 }
1380
1381 assert_eq!(
1383 parse_normalized(
1384 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ",
1385 ),
1386 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1387 );
1388 assert_eq!(
1390 parse_normalized("remote_bookmarks( remote = foo )"),
1391 parse_normalized("remote_bookmarks(remote=foo)"),
1392 );
1393
1394 assert!(parse_into_kind("bookmarks(,)").is_err());
1396 assert_eq!(
1398 parse_normalized("bookmarks(a,)"),
1399 parse_normalized("bookmarks(a)")
1400 );
1401 assert_eq!(
1402 parse_normalized("bookmarks(a , )"),
1403 parse_normalized("bookmarks(a)")
1404 );
1405 assert!(parse_into_kind("bookmarks(,a)").is_err());
1406 assert!(parse_into_kind("bookmarks(a,,)").is_err());
1407 assert!(parse_into_kind("bookmarks(a , , )").is_err());
1408 assert_eq!(
1409 parse_normalized("file(a,b,)"),
1410 parse_normalized("file(a, b)")
1411 );
1412 assert!(parse_into_kind("file(a,,b)").is_err());
1413 assert_eq!(
1414 parse_normalized("remote_bookmarks(a,remote=b , )"),
1415 parse_normalized("remote_bookmarks(a, remote=b)"),
1416 );
1417 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1418
1419 let function =
1421 unwrap_function_call(parse_program("foo( a, (b) , ~(c), d = (e) )").unwrap());
1422 assert_eq!(function.name_span.as_str(), "foo");
1423 assert_eq!(function.args_span.as_str(), "a, (b) , ~(c), d = (e)");
1424 assert_eq!(function.args[0].span.as_str(), "a");
1425 assert_eq!(function.args[1].span.as_str(), "(b)");
1426 assert_eq!(function.args[2].span.as_str(), "~(c)");
1427 assert_eq!(function.keyword_args[0].name_span.as_str(), "d");
1428 assert_eq!(function.keyword_args[0].value.span.as_str(), "(e)");
1429 }
1430
1431 #[test]
1432 fn test_parse_revset_alias_symbol_decl() {
1433 let mut aliases_map = RevsetAliasesMap::new();
1434 assert!(aliases_map.insert("@", "none()").is_err());
1436 assert!(aliases_map.insert("a@", "none()").is_err());
1437 assert!(aliases_map.insert("a@b", "none()").is_err());
1438 assert!(aliases_map.insert("柔術", "none()").is_err());
1441 }
1442
1443 #[test]
1444 fn test_parse_revset_alias_pattern_decl() {
1445 let mut aliases_map = RevsetAliasesMap::new();
1446 assert!(aliases_map.insert("foo:", "none()").is_err());
1447 assert_eq!(aliases_map.pattern_names().count(), 0);
1448
1449 aliases_map.insert("bar:baz", "'bar pattern'").unwrap();
1450 assert_eq!(aliases_map.pattern_names().count(), 1);
1451 let (id, param, defn) = aliases_map.get_pattern("bar").unwrap();
1452 assert_eq!(id, AliasId::Pattern("bar", "baz"));
1453 assert_eq!(param, "baz");
1454 assert_eq!(defn, "'bar pattern'");
1455
1456 assert!(aliases_map.insert("柔術:x", "none()").is_err());
1459 assert!(aliases_map.insert("x:柔術", "none()").is_err());
1460 }
1461
1462 #[test]
1463 fn test_parse_revset_alias_func_decl() {
1464 let mut aliases_map = RevsetAliasesMap::new();
1465 assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err());
1466 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1467 aliases_map
1468 .insert("func(a, b)", r#""is function 2""#)
1469 .unwrap();
1470 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1471 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1472
1473 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1474 assert_eq!(id, AliasId::Function("func", &[]));
1475 assert!(params.is_empty());
1476 assert_eq!(defn, r#""is function 0""#);
1477
1478 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1479 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1480 assert_eq!(params, ["b"]);
1481 assert_eq!(defn, r#""is function b""#);
1482
1483 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1484 assert_eq!(
1485 id,
1486 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1487 );
1488 assert_eq!(params, ["a", "b"]);
1489 assert_eq!(defn, r#""is function 2""#);
1490
1491 assert!(aliases_map.get_function("func", 3).is_none());
1492 }
1493
1494 #[test]
1495 fn test_parse_revset_alias_formal_parameter() {
1496 let mut aliases_map = RevsetAliasesMap::new();
1497 assert!(aliases_map.insert("f(@)", "none()").is_err());
1499 assert!(aliases_map.insert("f(a@)", "none()").is_err());
1500 assert!(aliases_map.insert("f(a@b)", "none()").is_err());
1501 assert!(aliases_map.insert("f(,)", "none()").is_err());
1503 assert!(aliases_map.insert("g(a,)", "none()").is_ok());
1505 assert!(aliases_map.insert("h(a , )", "none()").is_ok());
1506 assert!(aliases_map.insert("i(,a)", "none()").is_err());
1507 assert!(aliases_map.insert("j(a,,)", "none()").is_err());
1508 assert!(aliases_map.insert("k(a , , )", "none()").is_err());
1509 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
1510 assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
1511 }
1512
1513 #[test]
1514 fn test_parse_revset_compat_operator() {
1515 assert_eq!(
1516 parse_into_kind(":foo"),
1517 Err(RevsetParseErrorKind::NotPrefixOperator {
1518 op: ":".to_owned(),
1519 similar_op: "::".to_owned(),
1520 description: "ancestors".to_owned(),
1521 })
1522 );
1523 assert_eq!(
1524 parse_into_kind("foo^"),
1525 Err(RevsetParseErrorKind::NotPostfixOperator {
1526 op: "^".to_owned(),
1527 similar_op: "-".to_owned(),
1528 description: "parents".to_owned(),
1529 })
1530 );
1531 assert_eq!(
1532 parse_into_kind("foo + bar"),
1533 Err(RevsetParseErrorKind::NotInfixOperator {
1534 op: "+".to_owned(),
1535 similar_op: "|".to_owned(),
1536 description: "union".to_owned(),
1537 })
1538 );
1539 assert_eq!(
1540 parse_into_kind("foo - bar"),
1541 Err(RevsetParseErrorKind::NotInfixOperator {
1542 op: "-".to_owned(),
1543 similar_op: "~".to_owned(),
1544 description: "difference".to_owned(),
1545 })
1546 );
1547 }
1548
1549 #[test]
1550 fn test_parse_revset_operator_combinations() {
1551 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1553 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1555 assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y"));
1557 assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)"));
1558 assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)"));
1559 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1560 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1561 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1562 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1563 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1564 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1565 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1566 assert_eq!(
1568 parse_into_kind("::foo::"),
1569 Err(RevsetParseErrorKind::SyntaxError)
1570 );
1571 assert_eq!(
1572 parse_into_kind(":::foo"),
1573 Err(RevsetParseErrorKind::SyntaxError)
1574 );
1575 assert_eq!(
1576 parse_into_kind("::::foo"),
1577 Err(RevsetParseErrorKind::SyntaxError)
1578 );
1579 assert_eq!(
1580 parse_into_kind("foo:::"),
1581 Err(RevsetParseErrorKind::SyntaxError)
1582 );
1583 assert_eq!(
1584 parse_into_kind("foo::::"),
1585 Err(RevsetParseErrorKind::SyntaxError)
1586 );
1587 assert_eq!(
1588 parse_into_kind("foo:::bar"),
1589 Err(RevsetParseErrorKind::SyntaxError)
1590 );
1591 assert_eq!(
1592 parse_into_kind("foo::::bar"),
1593 Err(RevsetParseErrorKind::SyntaxError)
1594 );
1595 assert_eq!(
1596 parse_into_kind("::foo::bar"),
1597 Err(RevsetParseErrorKind::SyntaxError)
1598 );
1599 assert_eq!(
1600 parse_into_kind("foo::bar::"),
1601 Err(RevsetParseErrorKind::SyntaxError)
1602 );
1603 assert_eq!(
1604 parse_into_kind("::::"),
1605 Err(RevsetParseErrorKind::SyntaxError)
1606 );
1607 assert_eq!(
1608 parse_into_kind("....foo"),
1609 Err(RevsetParseErrorKind::SyntaxError)
1610 );
1611 assert_eq!(
1612 parse_into_kind("foo...."),
1613 Err(RevsetParseErrorKind::SyntaxError)
1614 );
1615 assert_eq!(
1616 parse_into_kind("foo.....bar"),
1617 Err(RevsetParseErrorKind::SyntaxError)
1618 );
1619 assert_eq!(
1620 parse_into_kind("..foo..bar"),
1621 Err(RevsetParseErrorKind::SyntaxError)
1622 );
1623 assert_eq!(
1624 parse_into_kind("foo..bar.."),
1625 Err(RevsetParseErrorKind::SyntaxError)
1626 );
1627 assert_eq!(
1628 parse_into_kind("...."),
1629 Err(RevsetParseErrorKind::SyntaxError)
1630 );
1631 assert_eq!(
1632 parse_into_kind("::.."),
1633 Err(RevsetParseErrorKind::SyntaxError)
1634 );
1635 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1638 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1639 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1640 assert_eq!(
1641 parse_into_kind("::-"),
1642 Err(RevsetParseErrorKind::SyntaxError)
1643 );
1644 assert_eq!(
1645 parse_into_kind("..+"),
1646 Err(RevsetParseErrorKind::SyntaxError)
1647 );
1648 }
1649
1650 #[test]
1651 fn test_parse_revset_function() {
1652 assert_matches!(
1653 parse_into_kind("parents(foo)"),
1654 Ok(ExpressionKind::FunctionCall(_))
1655 );
1656 assert_eq!(
1657 parse_normalized("parents((foo))"),
1658 parse_normalized("parents(foo)"),
1659 );
1660 assert_eq!(
1661 parse_into_kind("parents(foo"),
1662 Err(RevsetParseErrorKind::SyntaxError)
1663 );
1664 }
1665
1666 #[test]
1667 fn test_expand_symbol_alias() {
1668 assert_eq!(
1669 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1670 parse_normalized("(a&b)|c")
1671 );
1672 assert_eq!(
1673 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1674 parse_normalized("(a|b)::heads(a|b)")
1675 );
1676
1677 assert_eq!(
1679 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1680 parse_normalized("a&(b|c)")
1681 );
1682
1683 assert_eq!(
1685 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1686 parse_normalized("a|'A'|'A'")
1687 );
1688
1689 assert_eq!(
1692 with_aliases([("A", "a")]).parse_normalized("author(A:b)"),
1693 parse_normalized("author(A:b)")
1694 );
1695
1696 assert_eq!(
1698 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1699 parse_normalized("author(exact:a)")
1700 );
1701 assert_eq!(
1702 with_aliases([("A", "a")]).parse_normalized("author(exact:'A')"),
1703 parse_normalized("author(exact:'A')")
1704 );
1705
1706 assert_eq!(
1708 with_aliases([("A", "a")]).parse_normalized("A@"),
1709 parse_normalized("A@")
1710 );
1711 assert_eq!(
1712 with_aliases([("A", "a")]).parse_normalized("A@b"),
1713 parse_normalized("A@b")
1714 );
1715 assert_eq!(
1716 with_aliases([("B", "b")]).parse_normalized("a@B"),
1717 parse_normalized("a@B")
1718 );
1719
1720 assert_eq!(
1722 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1723 parse_normalized("b|c")
1724 );
1725
1726 assert_eq!(
1728 *with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1729 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1730 );
1731 assert_eq!(
1732 *with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1733 .parse("A")
1734 .unwrap_err()
1735 .kind,
1736 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1737 );
1738
1739 assert_eq!(
1741 *with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1742 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1743 );
1744 }
1745
1746 #[test]
1747 fn test_expand_pattern_alias() {
1748 assert_eq!(
1749 with_aliases([("P:x", "x")]).parse_normalized("P:a"),
1750 parse_normalized("a")
1751 );
1752
1753 assert_eq!(
1755 with_aliases([("P:x", "x|a")]).parse_normalized("P:x"),
1756 parse_normalized("x|a")
1757 );
1758 assert_eq!(
1760 with_aliases([("P:x", "(Q:x)&y"), ("Q:y", "x|y")]).parse_normalized("P:a"),
1761 parse_normalized("(x|a)&y")
1762 );
1763
1764 assert_eq!(
1766 with_aliases([("P:X", "X"), ("X", "x")]).parse_normalized("(P:a)|X"),
1767 parse_normalized("a|x")
1768 );
1769
1770 assert_eq!(
1772 with_aliases([("P:x", "x|A"), ("A", "x")]).parse_normalized("P:a"),
1773 parse_normalized("a|x")
1774 );
1775
1776 assert_eq!(
1778 with_aliases([("P:x", "x|'x'")]).parse_normalized("P:a"),
1779 parse_normalized("a|'x'")
1780 );
1781
1782 assert_eq!(
1784 with_aliases([("A:x", "A"), ("A", "a")]).parse_normalized("A:x"),
1785 parse_normalized("a")
1786 );
1787
1788 assert_eq!(
1790 *with_aliases([("P:x", "Q:x"), ("Q:x", "R:x"), ("R:x", "P:x")])
1791 .parse("P:a")
1792 .unwrap_err()
1793 .kind,
1794 RevsetParseErrorKind::InAliasExpansion("P:x".to_owned())
1795 );
1796 }
1797
1798 #[test]
1799 fn test_expand_function_alias() {
1800 assert_eq!(
1801 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1802 parse_normalized("a")
1803 );
1804 assert_eq!(
1805 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1806 parse_normalized("a")
1807 );
1808 assert_eq!(
1809 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"),
1810 parse_normalized("a|b")
1811 );
1812
1813 assert_eq!(
1815 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1816 parse_normalized("a|b")
1817 );
1818
1819 assert_eq!(
1821 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1822 parse_normalized("(a::y)|(b::x)")
1823 );
1824 assert_eq!(
1826 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1827 parse_normalized("(x|a)&y")
1828 );
1829 assert_eq!(
1831 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1832 parse_normalized("(x|(x|a))&y")
1833 );
1834
1835 assert_eq!(
1837 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1838 parse_normalized("a|x")
1839 );
1840
1841 assert_eq!(
1843 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1844 parse_normalized("a|x")
1845 );
1846
1847 assert_eq!(
1849 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1850 parse_normalized("a|'x'")
1851 );
1852
1853 assert_eq!(
1855 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1856 parse_normalized("a")
1857 );
1858
1859 assert_eq!(
1861 *with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1862 RevsetParseErrorKind::InvalidFunctionArguments {
1863 name: "F".to_owned(),
1864 message: "Expected 0 arguments".to_owned()
1865 }
1866 );
1867 assert_eq!(
1868 *with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1869 RevsetParseErrorKind::InvalidFunctionArguments {
1870 name: "F".to_owned(),
1871 message: "Expected 1 arguments".to_owned()
1872 }
1873 );
1874 assert_eq!(
1875 *with_aliases([("F(x,y)", "x|y")])
1876 .parse("F(a,b,c)")
1877 .unwrap_err()
1878 .kind,
1879 RevsetParseErrorKind::InvalidFunctionArguments {
1880 name: "F".to_owned(),
1881 message: "Expected 2 arguments".to_owned()
1882 }
1883 );
1884 assert_eq!(
1885 *with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1886 .parse("F()")
1887 .unwrap_err()
1888 .kind,
1889 RevsetParseErrorKind::InvalidFunctionArguments {
1890 name: "F".to_owned(),
1891 message: "Expected 1 to 2 arguments".to_owned()
1892 }
1893 );
1894 assert_eq!(
1895 *with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1896 .parse("F(a)")
1897 .unwrap_err()
1898 .kind,
1899 RevsetParseErrorKind::InvalidFunctionArguments {
1900 name: "F".to_owned(),
1901 message: "Expected 0, 2 arguments".to_owned()
1902 }
1903 );
1904
1905 assert_eq!(
1907 *with_aliases([("F(x)", "x")])
1908 .parse("F(x=y)")
1909 .unwrap_err()
1910 .kind,
1911 RevsetParseErrorKind::InvalidFunctionArguments {
1912 name: "F".to_owned(),
1913 message: "Unexpected keyword arguments".to_owned()
1914 }
1915 );
1916
1917 assert_eq!(
1919 *with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1920 .parse("F(a)")
1921 .unwrap_err()
1922 .kind,
1923 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1924 );
1925 assert_eq!(
1926 *with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1927 .parse("F(a)")
1928 .unwrap_err()
1929 .kind,
1930 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1931 );
1932 }
1933
1934 #[test]
1935 fn test_expand_with_locals() {
1936 assert_eq!(
1938 with_aliases([("A", "symbol")])
1939 .set_local("A", "local")
1940 .parse_normalized("A"),
1941 parse_normalized("local")
1942 );
1943
1944 assert_eq!(
1946 with_aliases([("B", "A"), ("F(x)", "x&A")])
1947 .set_local("A", "a")
1948 .parse_normalized("A|B|F(A)"),
1949 parse_normalized("a|A|(a&A)")
1950 );
1951 }
1952}