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 use crate::tests::TestResult;
835
836 #[derive(Debug)]
837 struct WithRevsetAliasesMap<'i> {
838 aliases_map: RevsetAliasesMap,
839 locals: HashMap<&'i str, ExpressionNode<'i>>,
840 }
841
842 impl<'i> WithRevsetAliasesMap<'i> {
843 fn set_local(mut self, name: &'i str, value: &'i str) -> Self {
844 self.locals.insert(name, parse_program(value).unwrap());
845 self
846 }
847
848 fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
849 let node = parse_program(text)?;
850 dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals)
851 }
852
853 fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> {
854 normalize_tree(self.parse(text).unwrap())
855 }
856 }
857
858 fn with_aliases<'i>(
859 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
860 ) -> WithRevsetAliasesMap<'i> {
861 let mut aliases_map = RevsetAliasesMap::new();
862 for (decl, defn) in aliases {
863 aliases_map.insert(decl, defn).unwrap();
864 }
865 WithRevsetAliasesMap {
866 aliases_map,
867 locals: HashMap::new(),
868 }
869 }
870
871 fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
872 parse_program(text)
873 .map(|node| node.kind)
874 .map_err(|err| *err.kind)
875 }
876
877 fn parse_normalized(text: &str) -> ExpressionNode<'_> {
878 normalize_tree(parse_program(text).unwrap())
879 }
880
881 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
883 fn empty_span() -> pest::Span<'static> {
884 pest::Span::new("", 0, 0).unwrap()
885 }
886
887 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
888 nodes.into_iter().map(normalize_tree).collect()
889 }
890
891 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
892 FunctionCallNode {
893 name: function.name,
894 name_span: empty_span(),
895 args: normalize_list(function.args),
896 keyword_args: function
897 .keyword_args
898 .into_iter()
899 .map(|arg| KeywordArgument {
900 name: arg.name,
901 name_span: empty_span(),
902 value: normalize_tree(arg.value),
903 })
904 .collect(),
905 args_span: empty_span(),
906 }
907 }
908
909 let normalized_kind = match node.kind {
910 ExpressionKind::Identifier(_) | ExpressionKind::String(_) => node.kind,
911 ExpressionKind::Pattern(pattern) => {
912 let pattern = Box::new(PatternNode {
913 name: pattern.name,
914 name_span: empty_span(),
915 value: normalize_tree(pattern.value),
916 });
917 ExpressionKind::Pattern(pattern)
918 }
919 ExpressionKind::RemoteSymbol(_)
920 | ExpressionKind::AtWorkspace(_)
921 | ExpressionKind::AtCurrentWorkspace
922 | ExpressionKind::DagRangeAll
923 | ExpressionKind::RangeAll => node.kind,
924 ExpressionKind::Unary(op, arg) => {
925 let arg = Box::new(normalize_tree(*arg));
926 ExpressionKind::Unary(op, arg)
927 }
928 ExpressionKind::Binary(op, lhs, rhs) => {
929 let lhs = Box::new(normalize_tree(*lhs));
930 let rhs = Box::new(normalize_tree(*rhs));
931 ExpressionKind::Binary(op, lhs, rhs)
932 }
933 ExpressionKind::UnionAll(nodes) => {
934 let nodes = normalize_list(nodes);
935 ExpressionKind::UnionAll(nodes)
936 }
937 ExpressionKind::FunctionCall(function) => {
938 let function = Box::new(normalize_function_call(*function));
939 ExpressionKind::FunctionCall(function)
940 }
941 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
942 };
943 ExpressionNode {
944 kind: normalized_kind,
945 span: empty_span(),
946 }
947 }
948
949 #[test]
950 fn test_parse_tree_eq() {
951 assert_eq!(
952 parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
953 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
954 );
955 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
956 }
957
958 #[test]
959 fn test_parse_revset() -> TestResult {
960 assert_eq!(
962 parse_into_kind("\"foo\""),
963 Ok(ExpressionKind::String("foo".to_owned()))
964 );
965 assert_eq!(
966 parse_into_kind("'foo'"),
967 Ok(ExpressionKind::String("foo".to_owned()))
968 );
969 assert_matches!(
971 parse_into_kind("foo-"),
972 Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
973 );
974 assert_matches!(
976 parse_into_kind("foo+"),
977 Ok(ExpressionKind::Unary(UnaryOp::Children, _))
978 );
979 assert_matches!(
981 parse_into_kind("::foo"),
982 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
983 );
984 assert_matches!(
986 parse_into_kind("foo::"),
987 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
988 );
989 assert_matches!(
991 parse_into_kind("foo::bar"),
992 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
993 );
994 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
996 assert_matches!(
998 parse_into_kind("..foo"),
999 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
1000 );
1001 assert_matches!(
1002 parse_into_kind("foo.."),
1003 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
1004 );
1005 assert_matches!(
1006 parse_into_kind("foo..bar"),
1007 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
1008 );
1009 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
1011 assert_matches!(
1013 parse_into_kind("~ foo"),
1014 Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1015 );
1016 assert_eq!(
1017 parse_normalized("~ ~~ foo"),
1018 parse_normalized("~(~(~(foo)))"),
1019 );
1020 assert_matches!(
1022 parse_into_kind("foo & bar"),
1023 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1024 );
1025 assert_matches!(
1027 parse_into_kind("foo | bar"),
1028 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1029 );
1030 assert_matches!(
1031 parse_into_kind("foo | bar | baz"),
1032 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1033 );
1034 assert_matches!(
1036 parse_into_kind("foo ~ bar"),
1037 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1038 );
1039 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1041 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1043 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1044 assert_eq!(
1046 parse_into_kind(" :: foo "),
1047 Err(RevsetParseErrorKind::SyntaxError)
1048 );
1049 assert_eq!(
1051 parse_into_kind("foo | -"),
1052 Err(RevsetParseErrorKind::SyntaxError)
1053 );
1054
1055 assert_eq!(parse_program(" ~ x ")?.span.as_str(), "~ x");
1057 assert_eq!(parse_program(" x+ ")?.span.as_str(), "x+");
1058 assert_eq!(parse_program(" x |y ")?.span.as_str(), "x |y");
1059 assert_eq!(parse_program(" (x) ")?.span.as_str(), "(x)");
1060 assert_eq!(parse_program("~( x|y) ")?.span.as_str(), "~( x|y)");
1061 assert_eq!(parse_program(" ( x )- ")?.span.as_str(), "( x )-");
1062 Ok(())
1063 }
1064
1065 #[test]
1066 fn test_parse_whitespace() {
1067 let ascii_whitespaces: String = ('\x00'..='\x7f')
1068 .filter(char::is_ascii_whitespace)
1069 .collect();
1070 assert_eq!(
1071 parse_normalized(&format!("{ascii_whitespaces}all()")),
1072 parse_normalized("all()"),
1073 );
1074 }
1075
1076 #[test]
1077 fn test_parse_identifier() {
1078 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1080 assert_eq!(
1082 parse_into_kind("foo_bar/baz"),
1083 Ok(ExpressionKind::Identifier("foo_bar/baz"))
1084 );
1085 assert_eq!(
1087 parse_into_kind("*/foo/**"),
1088 Ok(ExpressionKind::Identifier("*/foo/**"))
1089 );
1090
1091 assert_eq!(
1093 parse_into_kind("foo.bar-v1+7"),
1094 Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1095 );
1096 assert_eq!(
1097 parse_normalized("foo.bar-v1+7-"),
1098 parse_normalized("(foo.bar-v1+7)-")
1099 );
1100 assert_eq!(
1102 parse_into_kind("foo--bar"),
1103 Ok(ExpressionKind::Identifier("foo--bar"))
1104 );
1105 assert_eq!(
1106 parse_into_kind("foo----bar"),
1107 Ok(ExpressionKind::Identifier("foo----bar"))
1108 );
1109 assert_eq!(
1111 parse_into_kind(".foo"),
1112 Err(RevsetParseErrorKind::SyntaxError)
1113 );
1114 assert_eq!(
1115 parse_into_kind("foo."),
1116 Err(RevsetParseErrorKind::SyntaxError)
1117 );
1118 assert_eq!(
1120 parse_into_kind("foo.+bar"),
1121 Err(RevsetParseErrorKind::SyntaxError)
1122 );
1123 assert_eq!(
1124 parse_into_kind("foo++bar"),
1125 Err(RevsetParseErrorKind::SyntaxError)
1126 );
1127 assert_eq!(
1128 parse_into_kind("foo+-bar"),
1129 Err(RevsetParseErrorKind::SyntaxError)
1130 );
1131
1132 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1134
1135 assert_eq!(
1137 parse_into_kind("柔術+jj"),
1138 Ok(ExpressionKind::Identifier("柔術+jj"))
1139 );
1140 }
1141
1142 #[test]
1143 fn test_parse_string_literal() {
1144 assert_eq!(
1146 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1147 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1148 );
1149
1150 assert_eq!(
1152 parse_into_kind(r#" "\y" "#),
1153 Err(RevsetParseErrorKind::SyntaxError)
1154 );
1155
1156 assert_eq!(
1158 parse_into_kind(r#" '' "#),
1159 Ok(ExpressionKind::String("".to_owned()))
1160 );
1161 assert_eq!(
1162 parse_into_kind(r#" 'a\n' "#),
1163 Ok(ExpressionKind::String(r"a\n".to_owned()))
1164 );
1165 assert_eq!(
1166 parse_into_kind(r#" '\' "#),
1167 Ok(ExpressionKind::String(r"\".to_owned()))
1168 );
1169 assert_eq!(
1170 parse_into_kind(r#" '"' "#),
1171 Ok(ExpressionKind::String(r#"""#.to_owned()))
1172 );
1173
1174 assert_eq!(
1176 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1177 Ok(ExpressionKind::String("aeiou".to_owned()))
1178 );
1179 assert_eq!(
1180 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1181 Ok(ExpressionKind::String("àèìðù".to_owned()))
1182 );
1183 assert_eq!(
1184 parse_into_kind(r#""\x""#),
1185 Err(RevsetParseErrorKind::SyntaxError)
1186 );
1187 assert_eq!(
1188 parse_into_kind(r#""\xf""#),
1189 Err(RevsetParseErrorKind::SyntaxError)
1190 );
1191 assert_eq!(
1192 parse_into_kind(r#""\xgg""#),
1193 Err(RevsetParseErrorKind::SyntaxError)
1194 );
1195 }
1196
1197 #[test]
1198 fn test_parse_pattern() -> TestResult {
1199 fn unwrap_pattern(kind: ExpressionKind<'_>) -> (&str, ExpressionKind<'_>) {
1200 match kind {
1201 ExpressionKind::Pattern(pattern) => (pattern.name, pattern.value.kind),
1202 _ => panic!("unexpected expression: {kind:?}"),
1203 }
1204 }
1205
1206 assert_eq!(
1207 unwrap_pattern(parse_into_kind(r#"substring:"foo""#)?),
1208 ("substring", ExpressionKind::String("foo".to_owned()))
1209 );
1210 assert_eq!(
1211 unwrap_pattern(parse_into_kind("exact:foo")?),
1212 ("exact", ExpressionKind::Identifier("foo"))
1213 );
1214 assert_eq!(
1215 parse_into_kind(r#""exact:foo""#),
1216 Ok(ExpressionKind::String("exact:foo".to_owned()))
1217 );
1218 assert_eq!(
1220 unwrap_pattern(parse_into_kind("x:@")?),
1221 ("x", ExpressionKind::AtCurrentWorkspace)
1222 );
1223 assert_eq!(
1224 unwrap_pattern(parse_into_kind("x:y@z")?),
1225 (
1226 "x",
1227 ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1228 name: "y".into(),
1229 remote: "z".into(),
1230 })
1231 )
1232 );
1233
1234 assert_eq!(
1235 parse_normalized(r#"(exact:"foo" )"#),
1236 parse_normalized(r#"(exact:"foo")"#),
1237 );
1238 assert_eq!(
1239 unwrap_pattern(parse_into_kind(r#"exact:'\'"#)?),
1240 ("exact", ExpressionKind::String(r"\".to_owned()))
1241 );
1242
1243 assert_matches!(
1245 parse_into_kind("exact: foo"),
1246 Err(RevsetParseErrorKind::SyntaxError)
1247 );
1248 assert_matches!(
1249 parse_into_kind("exact :foo"),
1250 Err(RevsetParseErrorKind::SyntaxError)
1251 );
1252 assert_eq!(
1254 parse_normalized("exact:( 'foo' )"),
1255 parse_normalized("exact:'foo'"),
1256 );
1257
1258 assert_eq!(parse_normalized("x:f(y)"), parse_normalized("x:(f(y))"));
1260 assert_eq!(parse_normalized("x:@-+"), parse_normalized("x:((@-)+)"));
1262 assert_eq!(parse_normalized("x:y::z"), parse_normalized("(x:y)::(z)"));
1265 assert_matches!(
1266 parse_into_kind("x:::"),
1267 Err(RevsetParseErrorKind::SyntaxError)
1268 );
1269 assert_eq!(parse_normalized("x:y&z"), parse_normalized("(x:y)&(z)"));
1271 assert_matches!(
1272 parse_into_kind("x:~y"), Err(RevsetParseErrorKind::NotPostfixOperator { .. })
1274 );
1275
1276 assert_eq!(parse_normalized("x:y:z"), parse_normalized("x:(y:z)"));
1278 Ok(())
1279 }
1280
1281 #[test]
1282 fn test_parse_symbol_explicitly() {
1283 assert_matches!(parse_symbol("").as_deref(), Err(_));
1284 assert_matches!(parse_symbol("''").as_deref(), Err(_));
1287
1288 assert_matches!(parse_symbol("foo.bar").as_deref(), Ok("foo.bar"));
1289 assert_matches!(parse_symbol("foo@bar").as_deref(), Err(_));
1290 assert_matches!(parse_symbol("foo bar").as_deref(), Err(_));
1291
1292 assert_matches!(parse_symbol("'foo bar'").as_deref(), Ok("foo bar"));
1293 assert_matches!(parse_symbol(r#""foo\tbar""#).as_deref(), Ok("foo\tbar"));
1294
1295 assert_matches!(parse_symbol(" foo").as_deref(), Err(_));
1297 assert_matches!(parse_symbol("foo ").as_deref(), Err(_));
1298
1299 assert_matches!(parse_symbol("(foo)").as_deref(), Err(_));
1302 }
1303
1304 #[test]
1305 fn parse_at_workspace_and_remote_symbol() {
1306 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1308 assert_eq!(
1309 parse_into_kind("main@"),
1310 Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1311 );
1312 assert_eq!(
1313 parse_into_kind("main@origin"),
1314 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1315 name: "main".into(),
1316 remote: "origin".into()
1317 }))
1318 );
1319
1320 assert_eq!(
1322 parse_into_kind(r#""foo bar"@"#),
1323 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1324 );
1325 assert_eq!(
1326 parse_into_kind(r#""foo bar"@origin"#),
1327 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1328 name: "foo bar".into(),
1329 remote: "origin".into()
1330 }))
1331 );
1332 assert_eq!(
1333 parse_into_kind(r#"main@"foo bar""#),
1334 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1335 name: "main".into(),
1336 remote: "foo bar".into()
1337 }))
1338 );
1339 assert_eq!(
1340 parse_into_kind(r#"'foo bar'@'bar baz'"#),
1341 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1342 name: "foo bar".into(),
1343 remote: "bar baz".into()
1344 }))
1345 );
1346
1347 assert_eq!(
1349 parse_into_kind(r#""@""#),
1350 Ok(ExpressionKind::String("@".to_owned()))
1351 );
1352 assert_eq!(
1353 parse_into_kind(r#""main@""#),
1354 Ok(ExpressionKind::String("main@".to_owned()))
1355 );
1356 assert_eq!(
1357 parse_into_kind(r#""main@origin""#),
1358 Ok(ExpressionKind::String("main@origin".to_owned()))
1359 );
1360
1361 assert_eq!(
1363 parse_into_kind("柔術@"),
1364 Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1365 );
1366 assert_eq!(
1367 parse_into_kind("柔@術"),
1368 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1369 name: "柔".into(),
1370 remote: "術".into()
1371 }))
1372 );
1373 }
1374
1375 #[test]
1376 fn test_parse_function_call() -> TestResult {
1377 fn unwrap_function_call(node: ExpressionNode<'_>) -> Box<FunctionCallNode<'_>> {
1378 match node.kind {
1379 ExpressionKind::FunctionCall(function) => function,
1380 _ => panic!("unexpected expression: {node:?}"),
1381 }
1382 }
1383
1384 assert_eq!(
1386 parse_normalized(
1387 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ",
1388 ),
1389 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1390 );
1391 assert_eq!(
1393 parse_normalized("remote_bookmarks( remote = foo )"),
1394 parse_normalized("remote_bookmarks(remote=foo)"),
1395 );
1396
1397 assert!(parse_into_kind("bookmarks(,)").is_err());
1399 assert_eq!(
1401 parse_normalized("bookmarks(a,)"),
1402 parse_normalized("bookmarks(a)")
1403 );
1404 assert_eq!(
1405 parse_normalized("bookmarks(a , )"),
1406 parse_normalized("bookmarks(a)")
1407 );
1408 assert!(parse_into_kind("bookmarks(,a)").is_err());
1409 assert!(parse_into_kind("bookmarks(a,,)").is_err());
1410 assert!(parse_into_kind("bookmarks(a , , )").is_err());
1411 assert_eq!(
1412 parse_normalized("file(a,b,)"),
1413 parse_normalized("file(a, b)")
1414 );
1415 assert!(parse_into_kind("file(a,,b)").is_err());
1416 assert_eq!(
1417 parse_normalized("remote_bookmarks(a,remote=b , )"),
1418 parse_normalized("remote_bookmarks(a, remote=b)"),
1419 );
1420 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1421
1422 let function = unwrap_function_call(parse_program("foo( a, (b) , ~(c), d = (e) )")?);
1424 assert_eq!(function.name_span.as_str(), "foo");
1425 assert_eq!(function.args_span.as_str(), "a, (b) , ~(c), d = (e)");
1426 assert_eq!(function.args[0].span.as_str(), "a");
1427 assert_eq!(function.args[1].span.as_str(), "(b)");
1428 assert_eq!(function.args[2].span.as_str(), "~(c)");
1429 assert_eq!(function.keyword_args[0].name_span.as_str(), "d");
1430 assert_eq!(function.keyword_args[0].value.span.as_str(), "(e)");
1431 Ok(())
1432 }
1433
1434 #[test]
1435 fn test_parse_revset_alias_symbol_decl() {
1436 let mut aliases_map = RevsetAliasesMap::new();
1437 assert!(aliases_map.insert("@", "none()").is_err());
1439 assert!(aliases_map.insert("a@", "none()").is_err());
1440 assert!(aliases_map.insert("a@b", "none()").is_err());
1441 assert!(aliases_map.insert("柔術", "none()").is_err());
1444 }
1445
1446 #[test]
1447 fn test_parse_revset_alias_pattern_decl() -> TestResult {
1448 let mut aliases_map = RevsetAliasesMap::new();
1449 assert!(aliases_map.insert("foo:", "none()").is_err());
1450 assert_eq!(aliases_map.pattern_names().count(), 0);
1451
1452 aliases_map.insert("bar:baz", "'bar pattern'")?;
1453 assert_eq!(aliases_map.pattern_names().count(), 1);
1454 let (id, param, defn) = aliases_map.get_pattern("bar").unwrap();
1455 assert_eq!(id, AliasId::Pattern("bar", "baz"));
1456 assert_eq!(param, "baz");
1457 assert_eq!(defn, "'bar pattern'");
1458
1459 assert!(aliases_map.insert("柔術:x", "none()").is_err());
1462 assert!(aliases_map.insert("x:柔術", "none()").is_err());
1463 Ok(())
1464 }
1465
1466 #[test]
1467 fn test_parse_revset_alias_func_decl() -> TestResult {
1468 let mut aliases_map = RevsetAliasesMap::new();
1469 assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err());
1470 aliases_map.insert("func()", r#""is function 0""#)?;
1471 aliases_map.insert("func(a, b)", r#""is function 2""#)?;
1472 aliases_map.insert("func(a)", r#""is function a""#)?;
1473 aliases_map.insert("func(b)", r#""is function b""#)?;
1474
1475 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1476 assert_eq!(id, AliasId::Function("func", &[]));
1477 assert!(params.is_empty());
1478 assert_eq!(defn, r#""is function 0""#);
1479
1480 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1481 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1482 assert_eq!(params, ["b"]);
1483 assert_eq!(defn, r#""is function b""#);
1484
1485 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1486 assert_eq!(
1487 id,
1488 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1489 );
1490 assert_eq!(params, ["a", "b"]);
1491 assert_eq!(defn, r#""is function 2""#);
1492
1493 assert!(aliases_map.get_function("func", 3).is_none());
1494 Ok(())
1495 }
1496
1497 #[test]
1498 fn test_parse_revset_alias_formal_parameter() {
1499 let mut aliases_map = RevsetAliasesMap::new();
1500 assert!(aliases_map.insert("f(@)", "none()").is_err());
1502 assert!(aliases_map.insert("f(a@)", "none()").is_err());
1503 assert!(aliases_map.insert("f(a@b)", "none()").is_err());
1504 assert!(aliases_map.insert("f(,)", "none()").is_err());
1506 assert!(aliases_map.insert("g(a,)", "none()").is_ok());
1508 assert!(aliases_map.insert("h(a , )", "none()").is_ok());
1509 assert!(aliases_map.insert("i(,a)", "none()").is_err());
1510 assert!(aliases_map.insert("j(a,,)", "none()").is_err());
1511 assert!(aliases_map.insert("k(a , , )", "none()").is_err());
1512 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
1513 assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
1514 }
1515
1516 #[test]
1517 fn test_parse_revset_compat_operator() {
1518 assert_eq!(
1519 parse_into_kind(":foo"),
1520 Err(RevsetParseErrorKind::NotPrefixOperator {
1521 op: ":".to_owned(),
1522 similar_op: "::".to_owned(),
1523 description: "ancestors".to_owned(),
1524 })
1525 );
1526 assert_eq!(
1527 parse_into_kind("foo^"),
1528 Err(RevsetParseErrorKind::NotPostfixOperator {
1529 op: "^".to_owned(),
1530 similar_op: "-".to_owned(),
1531 description: "parents".to_owned(),
1532 })
1533 );
1534 assert_eq!(
1535 parse_into_kind("foo + bar"),
1536 Err(RevsetParseErrorKind::NotInfixOperator {
1537 op: "+".to_owned(),
1538 similar_op: "|".to_owned(),
1539 description: "union".to_owned(),
1540 })
1541 );
1542 assert_eq!(
1543 parse_into_kind("foo - bar"),
1544 Err(RevsetParseErrorKind::NotInfixOperator {
1545 op: "-".to_owned(),
1546 similar_op: "~".to_owned(),
1547 description: "difference".to_owned(),
1548 })
1549 );
1550 }
1551
1552 #[test]
1553 fn test_parse_revset_operator_combinations() {
1554 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1556 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1558 assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y"));
1560 assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)"));
1561 assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)"));
1562 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1563 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1564 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1565 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1566 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1567 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1568 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1569 assert_eq!(
1571 parse_into_kind("::foo::"),
1572 Err(RevsetParseErrorKind::SyntaxError)
1573 );
1574 assert_eq!(
1575 parse_into_kind(":::foo"),
1576 Err(RevsetParseErrorKind::SyntaxError)
1577 );
1578 assert_eq!(
1579 parse_into_kind("::::foo"),
1580 Err(RevsetParseErrorKind::SyntaxError)
1581 );
1582 assert_eq!(
1583 parse_into_kind("foo:::"),
1584 Err(RevsetParseErrorKind::SyntaxError)
1585 );
1586 assert_eq!(
1587 parse_into_kind("foo::::"),
1588 Err(RevsetParseErrorKind::SyntaxError)
1589 );
1590 assert_eq!(
1591 parse_into_kind("foo:::bar"),
1592 Err(RevsetParseErrorKind::SyntaxError)
1593 );
1594 assert_eq!(
1595 parse_into_kind("foo::::bar"),
1596 Err(RevsetParseErrorKind::SyntaxError)
1597 );
1598 assert_eq!(
1599 parse_into_kind("::foo::bar"),
1600 Err(RevsetParseErrorKind::SyntaxError)
1601 );
1602 assert_eq!(
1603 parse_into_kind("foo::bar::"),
1604 Err(RevsetParseErrorKind::SyntaxError)
1605 );
1606 assert_eq!(
1607 parse_into_kind("::::"),
1608 Err(RevsetParseErrorKind::SyntaxError)
1609 );
1610 assert_eq!(
1611 parse_into_kind("....foo"),
1612 Err(RevsetParseErrorKind::SyntaxError)
1613 );
1614 assert_eq!(
1615 parse_into_kind("foo...."),
1616 Err(RevsetParseErrorKind::SyntaxError)
1617 );
1618 assert_eq!(
1619 parse_into_kind("foo.....bar"),
1620 Err(RevsetParseErrorKind::SyntaxError)
1621 );
1622 assert_eq!(
1623 parse_into_kind("..foo..bar"),
1624 Err(RevsetParseErrorKind::SyntaxError)
1625 );
1626 assert_eq!(
1627 parse_into_kind("foo..bar.."),
1628 Err(RevsetParseErrorKind::SyntaxError)
1629 );
1630 assert_eq!(
1631 parse_into_kind("...."),
1632 Err(RevsetParseErrorKind::SyntaxError)
1633 );
1634 assert_eq!(
1635 parse_into_kind("::.."),
1636 Err(RevsetParseErrorKind::SyntaxError)
1637 );
1638 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1641 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1642 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1643 assert_eq!(
1644 parse_into_kind("::-"),
1645 Err(RevsetParseErrorKind::SyntaxError)
1646 );
1647 assert_eq!(
1648 parse_into_kind("..+"),
1649 Err(RevsetParseErrorKind::SyntaxError)
1650 );
1651 }
1652
1653 #[test]
1654 fn test_parse_revset_function() {
1655 assert_matches!(
1656 parse_into_kind("parents(foo)"),
1657 Ok(ExpressionKind::FunctionCall(_))
1658 );
1659 assert_eq!(
1660 parse_normalized("parents((foo))"),
1661 parse_normalized("parents(foo)"),
1662 );
1663 assert_eq!(
1664 parse_into_kind("parents(foo"),
1665 Err(RevsetParseErrorKind::SyntaxError)
1666 );
1667 }
1668
1669 #[test]
1670 fn test_expand_symbol_alias() {
1671 assert_eq!(
1672 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1673 parse_normalized("(a&b)|c")
1674 );
1675 assert_eq!(
1676 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1677 parse_normalized("(a|b)::heads(a|b)")
1678 );
1679
1680 assert_eq!(
1682 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1683 parse_normalized("a&(b|c)")
1684 );
1685
1686 assert_eq!(
1688 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1689 parse_normalized("a|'A'|'A'")
1690 );
1691
1692 assert_eq!(
1695 with_aliases([("A", "a")]).parse_normalized("author(A:b)"),
1696 parse_normalized("author(A:b)")
1697 );
1698
1699 assert_eq!(
1701 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1702 parse_normalized("author(exact:a)")
1703 );
1704 assert_eq!(
1705 with_aliases([("A", "a")]).parse_normalized("author(exact:'A')"),
1706 parse_normalized("author(exact:'A')")
1707 );
1708
1709 assert_eq!(
1711 with_aliases([("A", "a")]).parse_normalized("A@"),
1712 parse_normalized("A@")
1713 );
1714 assert_eq!(
1715 with_aliases([("A", "a")]).parse_normalized("A@b"),
1716 parse_normalized("A@b")
1717 );
1718 assert_eq!(
1719 with_aliases([("B", "b")]).parse_normalized("a@B"),
1720 parse_normalized("a@B")
1721 );
1722
1723 assert_eq!(
1725 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1726 parse_normalized("b|c")
1727 );
1728
1729 assert_eq!(
1731 *with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1732 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1733 );
1734 assert_eq!(
1735 *with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1736 .parse("A")
1737 .unwrap_err()
1738 .kind,
1739 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1740 );
1741
1742 assert_eq!(
1744 *with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1745 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1746 );
1747 }
1748
1749 #[test]
1750 fn test_expand_pattern_alias() {
1751 assert_eq!(
1752 with_aliases([("P:x", "x")]).parse_normalized("P:a"),
1753 parse_normalized("a")
1754 );
1755
1756 assert_eq!(
1758 with_aliases([("P:x", "x|a")]).parse_normalized("P:x"),
1759 parse_normalized("x|a")
1760 );
1761 assert_eq!(
1763 with_aliases([("P:x", "(Q:x)&y"), ("Q:y", "x|y")]).parse_normalized("P:a"),
1764 parse_normalized("(x|a)&y")
1765 );
1766
1767 assert_eq!(
1769 with_aliases([("P:X", "X"), ("X", "x")]).parse_normalized("(P:a)|X"),
1770 parse_normalized("a|x")
1771 );
1772
1773 assert_eq!(
1775 with_aliases([("P:x", "x|A"), ("A", "x")]).parse_normalized("P:a"),
1776 parse_normalized("a|x")
1777 );
1778
1779 assert_eq!(
1781 with_aliases([("P:x", "x|'x'")]).parse_normalized("P:a"),
1782 parse_normalized("a|'x'")
1783 );
1784
1785 assert_eq!(
1787 with_aliases([("A:x", "A"), ("A", "a")]).parse_normalized("A:x"),
1788 parse_normalized("a")
1789 );
1790
1791 assert_eq!(
1793 *with_aliases([("P:x", "Q:x"), ("Q:x", "R:x"), ("R:x", "P:x")])
1794 .parse("P:a")
1795 .unwrap_err()
1796 .kind,
1797 RevsetParseErrorKind::InAliasExpansion("P:x".to_owned())
1798 );
1799 }
1800
1801 #[test]
1802 fn test_expand_function_alias() {
1803 assert_eq!(
1804 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1805 parse_normalized("a")
1806 );
1807 assert_eq!(
1808 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1809 parse_normalized("a")
1810 );
1811 assert_eq!(
1812 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"),
1813 parse_normalized("a|b")
1814 );
1815
1816 assert_eq!(
1818 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1819 parse_normalized("a|b")
1820 );
1821
1822 assert_eq!(
1824 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1825 parse_normalized("(a::y)|(b::x)")
1826 );
1827 assert_eq!(
1829 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1830 parse_normalized("(x|a)&y")
1831 );
1832 assert_eq!(
1834 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1835 parse_normalized("(x|(x|a))&y")
1836 );
1837
1838 assert_eq!(
1840 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1841 parse_normalized("a|x")
1842 );
1843
1844 assert_eq!(
1846 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1847 parse_normalized("a|x")
1848 );
1849
1850 assert_eq!(
1852 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1853 parse_normalized("a|'x'")
1854 );
1855
1856 assert_eq!(
1858 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1859 parse_normalized("a")
1860 );
1861
1862 assert_eq!(
1864 *with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1865 RevsetParseErrorKind::InvalidFunctionArguments {
1866 name: "F".to_owned(),
1867 message: "Expected 0 arguments".to_owned()
1868 }
1869 );
1870 assert_eq!(
1871 *with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1872 RevsetParseErrorKind::InvalidFunctionArguments {
1873 name: "F".to_owned(),
1874 message: "Expected 1 arguments".to_owned()
1875 }
1876 );
1877 assert_eq!(
1878 *with_aliases([("F(x,y)", "x|y")])
1879 .parse("F(a,b,c)")
1880 .unwrap_err()
1881 .kind,
1882 RevsetParseErrorKind::InvalidFunctionArguments {
1883 name: "F".to_owned(),
1884 message: "Expected 2 arguments".to_owned()
1885 }
1886 );
1887 assert_eq!(
1888 *with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1889 .parse("F()")
1890 .unwrap_err()
1891 .kind,
1892 RevsetParseErrorKind::InvalidFunctionArguments {
1893 name: "F".to_owned(),
1894 message: "Expected 1 to 2 arguments".to_owned()
1895 }
1896 );
1897 assert_eq!(
1898 *with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1899 .parse("F(a)")
1900 .unwrap_err()
1901 .kind,
1902 RevsetParseErrorKind::InvalidFunctionArguments {
1903 name: "F".to_owned(),
1904 message: "Expected 0, 2 arguments".to_owned()
1905 }
1906 );
1907
1908 assert_eq!(
1910 *with_aliases([("F(x)", "x")])
1911 .parse("F(x=y)")
1912 .unwrap_err()
1913 .kind,
1914 RevsetParseErrorKind::InvalidFunctionArguments {
1915 name: "F".to_owned(),
1916 message: "Unexpected keyword arguments".to_owned()
1917 }
1918 );
1919
1920 assert_eq!(
1922 *with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1923 .parse("F(a)")
1924 .unwrap_err()
1925 .kind,
1926 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1927 );
1928 assert_eq!(
1929 *with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1930 .parse("F(a)")
1931 .unwrap_err()
1932 .kind,
1933 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1934 );
1935 }
1936
1937 #[test]
1938 fn test_expand_with_locals() {
1939 assert_eq!(
1941 with_aliases([("A", "symbol")])
1942 .set_local("A", "local")
1943 .parse_normalized("A"),
1944 parse_normalized("local")
1945 );
1946
1947 assert_eq!(
1949 with_aliases([("B", "A"), ("F(x)", "x&A")])
1950 .set_local("A", "a")
1951 .parse_normalized("A|B|F(A)"),
1952 parse_normalized("a|A|(a&A)")
1953 );
1954 }
1955}