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::string_pattern => None,
129 Self::primary => None,
130 Self::neighbors_expression => None,
131 Self::range_expression => None,
132 Self::expression => None,
133 Self::program_modifier => None,
134 Self::program_with_modifier => None,
135 Self::program => None,
136 Self::symbol_name => None,
137 Self::function_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("Modifier `{0}` doesn't exist")]
178 NoSuchModifier(String),
179 #[error("Function `{name}` doesn't exist")]
180 NoSuchFunction {
181 name: String,
182 candidates: Vec<String>,
183 },
184 #[error("Function `{name}`: {message}")]
185 InvalidFunctionArguments { name: String, message: String },
186 #[error("Cannot resolve file pattern without workspace")]
187 FsPathWithoutWorkspace,
188 #[error("Cannot resolve `@` without workspace")]
189 WorkingCopyWithoutWorkspace,
190 #[error("Redefinition of function parameter")]
191 RedefinedFunctionParameter,
192 #[error("{0}")]
193 Expression(String),
194 #[error("In alias `{0}`")]
195 InAliasExpansion(String),
196 #[error("In function parameter `{0}`")]
197 InParameterExpansion(String),
198 #[error("Alias `{0}` expanded recursively")]
199 RecursiveAlias(String),
200}
201
202impl RevsetParseError {
203 pub(super) fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self {
204 let message = kind.to_string();
205 let pest_error = Box::new(pest::error::Error::new_from_span(
206 pest::error::ErrorVariant::CustomError { message },
207 span,
208 ));
209 Self {
210 kind: Box::new(kind),
211 pest_error,
212 source: None,
213 }
214 }
215
216 pub(super) fn with_source(
217 mut self,
218 source: impl Into<Box<dyn error::Error + Send + Sync>>,
219 ) -> Self {
220 self.source = Some(source.into());
221 self
222 }
223
224 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
226 Self::with_span(RevsetParseErrorKind::Expression(message.into()), span)
227 }
228
229 pub(super) fn extend_function_candidates<I>(mut self, other_functions: I) -> Self
232 where
233 I: IntoIterator,
234 I::Item: AsRef<str>,
235 {
236 if let RevsetParseErrorKind::NoSuchFunction { name, candidates } = self.kind.as_mut() {
237 let other_candidates = collect_similar(name, other_functions);
238 *candidates = itertools::merge(mem::take(candidates), other_candidates)
239 .dedup()
240 .collect();
241 }
242 self
243 }
244
245 pub fn kind(&self) -> &RevsetParseErrorKind {
246 &self.kind
247 }
248
249 pub fn origin(&self) -> Option<&Self> {
251 self.source.as_ref().and_then(|e| e.downcast_ref())
252 }
253}
254
255impl AliasExpandError for RevsetParseError {
256 fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
257 err.into()
258 }
259
260 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
261 Self::with_span(RevsetParseErrorKind::RecursiveAlias(id.to_string()), span)
262 }
263
264 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
265 let kind = match id {
266 AliasId::Symbol(_) | AliasId::Function(..) => {
267 RevsetParseErrorKind::InAliasExpansion(id.to_string())
268 }
269 AliasId::Parameter(_) => RevsetParseErrorKind::InParameterExpansion(id.to_string()),
270 };
271 Self::with_span(kind, span).with_source(self)
272 }
273}
274
275impl From<pest::error::Error<Rule>> for RevsetParseError {
276 fn from(err: pest::error::Error<Rule>) -> Self {
277 Self {
278 kind: Box::new(RevsetParseErrorKind::SyntaxError),
279 pest_error: Box::new(rename_rules_in_pest_error(err)),
280 source: None,
281 }
282 }
283}
284
285impl From<InvalidArguments<'_>> for RevsetParseError {
286 fn from(err: InvalidArguments<'_>) -> Self {
287 let kind = RevsetParseErrorKind::InvalidFunctionArguments {
288 name: err.name.to_owned(),
289 message: err.message,
290 };
291 Self::with_span(kind, err.span)
292 }
293}
294
295fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
296 let pest::error::ErrorVariant::ParsingError {
297 positives,
298 negatives,
299 } = &mut err.variant
300 else {
301 return err;
302 };
303
304 let mut known_syms = HashSet::new();
307 positives.retain(|rule| {
308 !rule.is_compat() && rule.to_symbol().is_none_or(|sym| known_syms.insert(sym))
309 });
310 let mut known_syms = HashSet::new();
311 negatives.retain(|rule| rule.to_symbol().is_none_or(|sym| known_syms.insert(sym)));
312 err.renamed_rules(|rule| {
313 rule.to_symbol()
314 .map(|sym| format!("`{sym}`"))
315 .unwrap_or_else(|| format!("<{rule:?}>"))
316 })
317}
318
319#[derive(Clone, Debug, Eq, PartialEq)]
320pub enum ExpressionKind<'i> {
321 Identifier(&'i str),
323 String(String),
325 StringPattern {
327 kind: &'i str,
328 value: String,
329 },
330 RemoteSymbol(RemoteRefSymbolBuf),
332 AtWorkspace(String),
334 AtCurrentWorkspace,
336 DagRangeAll,
338 RangeAll,
340 Unary(UnaryOp, Box<ExpressionNode<'i>>),
341 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
342 UnionAll(Vec<ExpressionNode<'i>>),
344 FunctionCall(Box<FunctionCallNode<'i>>),
345 Modifier(Box<ModifierNode<'i>>),
347 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
349}
350
351impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
352 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
353 where
354 F: ExpressionFolder<'i, Self> + ?Sized,
355 {
356 match self {
357 Self::Identifier(name) => folder.fold_identifier(name, span),
358 Self::String(_)
359 | Self::StringPattern { .. }
360 | Self::RemoteSymbol(_)
361 | ExpressionKind::AtWorkspace(_)
362 | Self::AtCurrentWorkspace
363 | Self::DagRangeAll
364 | Self::RangeAll => Ok(self),
365 Self::Unary(op, arg) => {
366 let arg = Box::new(folder.fold_expression(*arg)?);
367 Ok(Self::Unary(op, arg))
368 }
369 Self::Binary(op, lhs, rhs) => {
370 let lhs = Box::new(folder.fold_expression(*lhs)?);
371 let rhs = Box::new(folder.fold_expression(*rhs)?);
372 Ok(Self::Binary(op, lhs, rhs))
373 }
374 Self::UnionAll(nodes) => {
375 let nodes = dsl_util::fold_expression_nodes(folder, nodes)?;
376 Ok(Self::UnionAll(nodes))
377 }
378 Self::FunctionCall(function) => folder.fold_function_call(function, span),
379 Self::Modifier(modifier) => {
380 let modifier = Box::new(ModifierNode {
381 name: modifier.name,
382 name_span: modifier.name_span,
383 body: folder.fold_expression(modifier.body)?,
384 });
385 Ok(Self::Modifier(modifier))
386 }
387 Self::AliasExpanded(id, subst) => {
388 let subst = Box::new(folder.fold_expression(*subst)?);
389 Ok(Self::AliasExpanded(id, subst))
390 }
391 }
392 }
393}
394
395impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
396 fn identifier(name: &'i str) -> Self {
397 Self::Identifier(name)
398 }
399
400 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
401 Self::FunctionCall(function)
402 }
403
404 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
405 Self::AliasExpanded(id, subst)
406 }
407}
408
409#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
410pub enum UnaryOp {
411 Negate,
413 DagRangePre,
415 DagRangePost,
417 RangePre,
419 RangePost,
421 Parents,
423 Children,
425}
426
427#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
428pub enum BinaryOp {
429 Intersection,
431 Difference,
433 DagRange,
435 Range,
437}
438
439pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
440pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
441
442#[derive(Clone, Debug, Eq, PartialEq)]
444pub struct ModifierNode<'i> {
445 pub name: &'i str,
447 pub name_span: pest::Span<'i>,
449 pub body: ExpressionNode<'i>,
451}
452
453fn union_nodes<'i>(lhs: ExpressionNode<'i>, rhs: ExpressionNode<'i>) -> ExpressionNode<'i> {
454 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
455 let expr = match lhs.kind {
456 ExpressionKind::UnionAll(mut nodes) => {
459 nodes.push(rhs);
460 ExpressionKind::UnionAll(nodes)
461 }
462 _ => ExpressionKind::UnionAll(vec![lhs, rhs]),
463 };
464 ExpressionNode::new(expr, span)
465}
466
467pub fn parse_program_with_modifier(
471 revset_str: &str,
472) -> Result<ExpressionNode<'_>, RevsetParseError> {
473 let mut pairs = RevsetParser::parse(Rule::program_with_modifier, revset_str)?;
474 let first = pairs.next().unwrap();
475 match first.as_rule() {
476 Rule::expression => parse_expression_node(first),
477 Rule::program_modifier => {
478 let [lhs, op] = first.into_inner().collect_array().unwrap();
479 let rhs = pairs.next().unwrap();
480 assert_eq!(lhs.as_rule(), Rule::strict_identifier);
481 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
482 assert_eq!(rhs.as_rule(), Rule::expression);
483 let span = lhs.as_span().start_pos().span(&rhs.as_span().end_pos());
484 let modifier = Box::new(ModifierNode {
485 name: lhs.as_str(),
486 name_span: lhs.as_span(),
487 body: parse_expression_node(rhs)?,
488 });
489 let expr = ExpressionKind::Modifier(modifier);
490 Ok(ExpressionNode::new(expr, span))
491 }
492 r => panic!("unexpected revset parse rule: {r:?}"),
493 }
494}
495
496pub fn parse_program(revset_str: &str) -> Result<ExpressionNode<'_>, RevsetParseError> {
498 let mut pairs = RevsetParser::parse(Rule::program, revset_str)?;
499 let first = pairs.next().unwrap();
500 assert_eq!(first.as_rule(), Rule::expression);
501 parse_expression_node(first)
502}
503
504fn parse_expression_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
505 fn not_prefix_op(
506 op: &Pair<Rule>,
507 similar_op: impl Into<String>,
508 description: impl Into<String>,
509 ) -> RevsetParseError {
510 RevsetParseError::with_span(
511 RevsetParseErrorKind::NotPrefixOperator {
512 op: op.as_str().to_owned(),
513 similar_op: similar_op.into(),
514 description: description.into(),
515 },
516 op.as_span(),
517 )
518 }
519
520 fn not_postfix_op(
521 op: &Pair<Rule>,
522 similar_op: impl Into<String>,
523 description: impl Into<String>,
524 ) -> RevsetParseError {
525 RevsetParseError::with_span(
526 RevsetParseErrorKind::NotPostfixOperator {
527 op: op.as_str().to_owned(),
528 similar_op: similar_op.into(),
529 description: description.into(),
530 },
531 op.as_span(),
532 )
533 }
534
535 fn not_infix_op(
536 op: &Pair<Rule>,
537 similar_op: impl Into<String>,
538 description: impl Into<String>,
539 ) -> RevsetParseError {
540 RevsetParseError::with_span(
541 RevsetParseErrorKind::NotInfixOperator {
542 op: op.as_str().to_owned(),
543 similar_op: similar_op.into(),
544 description: description.into(),
545 },
546 op.as_span(),
547 )
548 }
549
550 static PRATT: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
551 PrattParser::new()
552 .op(Op::infix(Rule::union_op, Assoc::Left)
553 | Op::infix(Rule::compat_add_op, Assoc::Left))
554 .op(Op::infix(Rule::intersection_op, Assoc::Left)
555 | Op::infix(Rule::difference_op, Assoc::Left)
556 | Op::infix(Rule::compat_sub_op, Assoc::Left))
557 .op(Op::prefix(Rule::negate_op))
558 .op(Op::infix(Rule::dag_range_op, Assoc::Left)
560 | Op::infix(Rule::compat_dag_range_op, Assoc::Left)
561 | Op::infix(Rule::range_op, Assoc::Left))
562 .op(Op::prefix(Rule::dag_range_pre_op)
563 | Op::prefix(Rule::compat_dag_range_pre_op)
564 | Op::prefix(Rule::range_pre_op))
565 .op(Op::postfix(Rule::dag_range_post_op)
566 | Op::postfix(Rule::compat_dag_range_post_op)
567 | Op::postfix(Rule::range_post_op))
568 .op(Op::postfix(Rule::parents_op)
570 | Op::postfix(Rule::children_op)
571 | Op::postfix(Rule::compat_parents_op))
572 });
573 PRATT
574 .map_primary(|primary| {
575 let expr = match primary.as_rule() {
576 Rule::primary => return parse_primary_node(primary),
577 Rule::dag_range_all_op => ExpressionKind::DagRangeAll,
578 Rule::range_all_op => ExpressionKind::RangeAll,
579 r => panic!("unexpected primary rule {r:?}"),
580 };
581 Ok(ExpressionNode::new(expr, primary.as_span()))
582 })
583 .map_prefix(|op, rhs| {
584 let op_kind = match op.as_rule() {
585 Rule::negate_op => UnaryOp::Negate,
586 Rule::dag_range_pre_op => UnaryOp::DagRangePre,
587 Rule::compat_dag_range_pre_op => Err(not_prefix_op(&op, "::", "ancestors"))?,
588 Rule::range_pre_op => UnaryOp::RangePre,
589 r => panic!("unexpected prefix operator rule {r:?}"),
590 };
591 let rhs = Box::new(rhs?);
592 let span = op.as_span().start_pos().span(&rhs.span.end_pos());
593 let expr = ExpressionKind::Unary(op_kind, rhs);
594 Ok(ExpressionNode::new(expr, span))
595 })
596 .map_postfix(|lhs, op| {
597 let op_kind = match op.as_rule() {
598 Rule::dag_range_post_op => UnaryOp::DagRangePost,
599 Rule::compat_dag_range_post_op => Err(not_postfix_op(&op, "::", "descendants"))?,
600 Rule::range_post_op => UnaryOp::RangePost,
601 Rule::parents_op => UnaryOp::Parents,
602 Rule::children_op => UnaryOp::Children,
603 Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents"))?,
604 r => panic!("unexpected postfix operator rule {r:?}"),
605 };
606 let lhs = Box::new(lhs?);
607 let span = lhs.span.start_pos().span(&op.as_span().end_pos());
608 let expr = ExpressionKind::Unary(op_kind, lhs);
609 Ok(ExpressionNode::new(expr, span))
610 })
611 .map_infix(|lhs, op, rhs| {
612 let op_kind = match op.as_rule() {
613 Rule::union_op => return Ok(union_nodes(lhs?, rhs?)),
614 Rule::compat_add_op => Err(not_infix_op(&op, "|", "union"))?,
615 Rule::intersection_op => BinaryOp::Intersection,
616 Rule::difference_op => BinaryOp::Difference,
617 Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference"))?,
618 Rule::dag_range_op => BinaryOp::DagRange,
619 Rule::compat_dag_range_op => Err(not_infix_op(&op, "::", "DAG range"))?,
620 Rule::range_op => BinaryOp::Range,
621 r => panic!("unexpected infix operator rule {r:?}"),
622 };
623 let lhs = Box::new(lhs?);
624 let rhs = Box::new(rhs?);
625 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
626 let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
627 Ok(ExpressionNode::new(expr, span))
628 })
629 .parse(pair.into_inner())
630}
631
632fn parse_primary_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
633 let span = pair.as_span();
634 let mut pairs = pair.into_inner();
635 let first = pairs.next().unwrap();
636 let expr = match first.as_rule() {
637 Rule::expression => parse_expression_node(first)?.kind,
639 Rule::function => {
640 let function = Box::new(FUNCTION_CALL_PARSER.parse(
641 first,
642 |pair| Ok(pair.as_str()),
643 |pair| parse_expression_node(pair),
644 )?);
645 ExpressionKind::FunctionCall(function)
646 }
647 Rule::string_pattern => {
648 let [lhs, op, rhs] = first.into_inner().collect_array().unwrap();
649 assert_eq!(lhs.as_rule(), Rule::strict_identifier);
650 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
651 let kind = lhs.as_str();
652 let value = parse_as_string_literal(rhs);
653 ExpressionKind::StringPattern { kind, value }
654 }
655 Rule::identifier if pairs.peek().is_none() => ExpressionKind::Identifier(first.as_str()),
658 Rule::identifier | Rule::string_literal | Rule::raw_string_literal => {
659 let name = parse_as_string_literal(first);
660 match pairs.next() {
661 None => ExpressionKind::String(name),
662 Some(op) => {
663 assert_eq!(op.as_rule(), Rule::at_op);
664 match pairs.next() {
665 None => ExpressionKind::AtWorkspace(name),
667 Some(second) => {
669 let name: RefNameBuf = name.into();
670 let remote: RemoteNameBuf = parse_as_string_literal(second).into();
671 ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf { name, remote })
672 }
673 }
674 }
675 }
676 }
677 Rule::at_op => ExpressionKind::AtCurrentWorkspace,
679 r => panic!("unexpected revset parse rule: {r:?}"),
680 };
681 Ok(ExpressionNode::new(expr, span))
682}
683
684fn parse_as_string_literal(pair: Pair<Rule>) -> String {
686 match pair.as_rule() {
687 Rule::identifier => pair.as_str().to_owned(),
688 Rule::string_literal => STRING_LITERAL_PARSER.parse(pair.into_inner()),
689 Rule::raw_string_literal => {
690 let [content] = pair.into_inner().collect_array().unwrap();
691 assert_eq!(content.as_rule(), Rule::raw_string_content);
692 content.as_str().to_owned()
693 }
694 _ => {
695 panic!("unexpected string literal rule: {:?}", pair.as_str());
696 }
697 }
698}
699
700pub fn is_identifier(text: &str) -> bool {
702 match RevsetParser::parse(Rule::identifier, text) {
703 Ok(mut pairs) => pairs.next().unwrap().as_span().end() == text.len(),
704 Err(_) => false,
705 }
706}
707
708pub fn parse_symbol(text: &str) -> Result<String, RevsetParseError> {
710 let mut pairs = RevsetParser::parse(Rule::symbol_name, text)?;
711 let first = pairs.next().unwrap();
712 let span = first.as_span();
713 let name = parse_as_string_literal(first);
714 if name.is_empty() {
715 Err(RevsetParseError::expression(
716 "Expected non-empty string",
717 span,
718 ))
719 } else {
720 Ok(name)
721 }
722}
723
724pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser, String>;
725
726#[derive(Clone, Debug, Default)]
727pub struct RevsetAliasParser;
728
729impl AliasDeclarationParser for RevsetAliasParser {
730 type Error = RevsetParseError;
731
732 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
733 let mut pairs = RevsetParser::parse(Rule::alias_declaration, source)?;
734 let first = pairs.next().unwrap();
735 match first.as_rule() {
736 Rule::strict_identifier => Ok(AliasDeclaration::Symbol(first.as_str().to_owned())),
737 Rule::function_alias_declaration => {
738 let [name_pair, params_pair] = first.into_inner().collect_array().unwrap();
739 assert_eq!(name_pair.as_rule(), Rule::function_name);
740 assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
741 let name = name_pair.as_str().to_owned();
742 let params_span = params_pair.as_span();
743 let params = params_pair
744 .into_inner()
745 .map(|pair| match pair.as_rule() {
746 Rule::strict_identifier => pair.as_str().to_owned(),
747 r => panic!("unexpected formal parameter rule {r:?}"),
748 })
749 .collect_vec();
750 if params.iter().all_unique() {
751 Ok(AliasDeclaration::Function(name, params))
752 } else {
753 Err(RevsetParseError::with_span(
754 RevsetParseErrorKind::RedefinedFunctionParameter,
755 params_span,
756 ))
757 }
758 }
759 r => panic!("unexpected alias declaration rule {r:?}"),
760 }
761 }
762}
763
764impl AliasDefinitionParser for RevsetAliasParser {
765 type Output<'i> = ExpressionKind<'i>;
766 type Error = RevsetParseError;
767
768 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
769 parse_program_with_modifier(source)
770 }
771}
772
773pub(super) fn expect_string_pattern<'a>(
774 type_name: &str,
775 node: &'a ExpressionNode<'_>,
776) -> Result<(&'a str, Option<&'a str>), RevsetParseError> {
777 catch_aliases_no_diagnostics(node, |node| match &node.kind {
778 ExpressionKind::Identifier(name) => Ok((*name, None)),
779 ExpressionKind::String(name) => Ok((name, None)),
780 ExpressionKind::StringPattern { kind, value } => Ok((value, Some(*kind))),
781 _ => Err(RevsetParseError::expression(
782 format!("Expected {type_name}"),
783 node.span,
784 )),
785 })
786}
787
788pub fn expect_literal<T: FromStr>(
789 type_name: &str,
790 node: &ExpressionNode,
791) -> Result<T, RevsetParseError> {
792 catch_aliases_no_diagnostics(node, |node| {
793 let value = expect_string_literal(type_name, node)?;
794 value
795 .parse()
796 .map_err(|_| RevsetParseError::expression(format!("Expected {type_name}"), node.span))
797 })
798}
799
800pub(super) fn expect_string_literal<'a>(
801 type_name: &str,
802 node: &'a ExpressionNode<'_>,
803) -> Result<&'a str, RevsetParseError> {
804 catch_aliases_no_diagnostics(node, |node| match &node.kind {
805 ExpressionKind::Identifier(name) => Ok(*name),
806 ExpressionKind::String(name) => Ok(name),
807 _ => Err(RevsetParseError::expression(
808 format!("Expected {type_name}"),
809 node.span,
810 )),
811 })
812}
813
814pub(super) fn catch_aliases<'a, 'i, T>(
817 diagnostics: &mut RevsetDiagnostics,
818 node: &'a ExpressionNode<'i>,
819 f: impl FnOnce(&mut RevsetDiagnostics, &'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
820) -> Result<T, RevsetParseError> {
821 let (node, stack) = skip_aliases(node);
822 if stack.is_empty() {
823 f(diagnostics, node)
824 } else {
825 let mut inner_diagnostics = RevsetDiagnostics::new();
826 let result = f(&mut inner_diagnostics, node);
827 diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
828 result.map_err(|err| attach_aliases_err(err, &stack))
829 }
830}
831
832fn catch_aliases_no_diagnostics<'a, 'i, T>(
833 node: &'a ExpressionNode<'i>,
834 f: impl FnOnce(&'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
835) -> Result<T, RevsetParseError> {
836 let (node, stack) = skip_aliases(node);
837 f(node).map_err(|err| attach_aliases_err(err, &stack))
838}
839
840fn skip_aliases<'a, 'i>(
841 mut node: &'a ExpressionNode<'i>,
842) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
843 let mut stack = Vec::new();
844 while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
845 stack.push((*id, node.span));
846 node = subst;
847 }
848 (node, stack)
849}
850
851fn attach_aliases_err(
852 err: RevsetParseError,
853 stack: &[(AliasId<'_>, pest::Span<'_>)],
854) -> RevsetParseError {
855 stack
856 .iter()
857 .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
858}
859
860#[cfg(test)]
861mod tests {
862 use std::collections::HashMap;
863
864 use assert_matches::assert_matches;
865
866 use super::*;
867 use crate::dsl_util::KeywordArgument;
868
869 #[derive(Debug)]
870 struct WithRevsetAliasesMap<'i> {
871 aliases_map: RevsetAliasesMap,
872 locals: HashMap<&'i str, ExpressionNode<'i>>,
873 }
874
875 impl<'i> WithRevsetAliasesMap<'i> {
876 fn set_local(mut self, name: &'i str, value: &'i str) -> Self {
877 self.locals.insert(name, parse_program(value).unwrap());
878 self
879 }
880
881 fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
882 let node = parse_program_with_modifier(text)?;
883 dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals)
884 }
885
886 fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> {
887 normalize_tree(self.parse(text).unwrap())
888 }
889 }
890
891 fn with_aliases<'i>(
892 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
893 ) -> WithRevsetAliasesMap<'i> {
894 let mut aliases_map = RevsetAliasesMap::new();
895 for (decl, defn) in aliases {
896 aliases_map.insert(decl, defn).unwrap();
897 }
898 WithRevsetAliasesMap {
899 aliases_map,
900 locals: HashMap::new(),
901 }
902 }
903
904 fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
905 parse_program(text)
906 .map(|node| node.kind)
907 .map_err(|err| *err.kind)
908 }
909
910 fn parse_normalized(text: &str) -> ExpressionNode<'_> {
911 normalize_tree(parse_program_with_modifier(text).unwrap())
912 }
913
914 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
916 fn empty_span() -> pest::Span<'static> {
917 pest::Span::new("", 0, 0).unwrap()
918 }
919
920 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
921 nodes.into_iter().map(normalize_tree).collect()
922 }
923
924 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
925 FunctionCallNode {
926 name: function.name,
927 name_span: empty_span(),
928 args: normalize_list(function.args),
929 keyword_args: function
930 .keyword_args
931 .into_iter()
932 .map(|arg| KeywordArgument {
933 name: arg.name,
934 name_span: empty_span(),
935 value: normalize_tree(arg.value),
936 })
937 .collect(),
938 args_span: empty_span(),
939 }
940 }
941
942 let normalized_kind = match node.kind {
943 ExpressionKind::Identifier(_)
944 | ExpressionKind::String(_)
945 | ExpressionKind::StringPattern { .. }
946 | ExpressionKind::RemoteSymbol(_)
947 | ExpressionKind::AtWorkspace(_)
948 | ExpressionKind::AtCurrentWorkspace
949 | ExpressionKind::DagRangeAll
950 | ExpressionKind::RangeAll => node.kind,
951 ExpressionKind::Unary(op, arg) => {
952 let arg = Box::new(normalize_tree(*arg));
953 ExpressionKind::Unary(op, arg)
954 }
955 ExpressionKind::Binary(op, lhs, rhs) => {
956 let lhs = Box::new(normalize_tree(*lhs));
957 let rhs = Box::new(normalize_tree(*rhs));
958 ExpressionKind::Binary(op, lhs, rhs)
959 }
960 ExpressionKind::UnionAll(nodes) => {
961 let nodes = normalize_list(nodes);
962 ExpressionKind::UnionAll(nodes)
963 }
964 ExpressionKind::FunctionCall(function) => {
965 let function = Box::new(normalize_function_call(*function));
966 ExpressionKind::FunctionCall(function)
967 }
968 ExpressionKind::Modifier(modifier) => {
969 let modifier = Box::new(ModifierNode {
970 name: modifier.name,
971 name_span: empty_span(),
972 body: normalize_tree(modifier.body),
973 });
974 ExpressionKind::Modifier(modifier)
975 }
976 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
977 };
978 ExpressionNode {
979 kind: normalized_kind,
980 span: empty_span(),
981 }
982 }
983
984 #[test]
985 fn test_parse_tree_eq() {
986 assert_eq!(
987 parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
988 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
989 );
990 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
991 }
992
993 #[test]
994 fn test_parse_revset() {
995 assert_eq!(
997 parse_into_kind("\"foo\""),
998 Ok(ExpressionKind::String("foo".to_owned()))
999 );
1000 assert_eq!(
1001 parse_into_kind("'foo'"),
1002 Ok(ExpressionKind::String("foo".to_owned()))
1003 );
1004 assert_matches!(
1006 parse_into_kind("foo-"),
1007 Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
1008 );
1009 assert_matches!(
1011 parse_into_kind("foo+"),
1012 Ok(ExpressionKind::Unary(UnaryOp::Children, _))
1013 );
1014 assert_matches!(
1016 parse_into_kind("::foo"),
1017 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
1018 );
1019 assert_matches!(
1021 parse_into_kind("foo::"),
1022 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1023 );
1024 assert_matches!(
1026 parse_into_kind("foo::bar"),
1027 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1028 );
1029 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
1031 assert_matches!(
1033 parse_into_kind("..foo"),
1034 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
1035 );
1036 assert_matches!(
1037 parse_into_kind("foo.."),
1038 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
1039 );
1040 assert_matches!(
1041 parse_into_kind("foo..bar"),
1042 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
1043 );
1044 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
1046 assert_matches!(
1048 parse_into_kind("~ foo"),
1049 Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1050 );
1051 assert_eq!(
1052 parse_normalized("~ ~~ foo"),
1053 parse_normalized("~(~(~(foo)))"),
1054 );
1055 assert_matches!(
1057 parse_into_kind("foo & bar"),
1058 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1059 );
1060 assert_matches!(
1062 parse_into_kind("foo | bar"),
1063 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1064 );
1065 assert_matches!(
1066 parse_into_kind("foo | bar | baz"),
1067 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1068 );
1069 assert_matches!(
1071 parse_into_kind("foo ~ bar"),
1072 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1073 );
1074 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1076 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1078 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1079 assert_eq!(
1081 parse_into_kind(" :: foo "),
1082 Err(RevsetParseErrorKind::SyntaxError)
1083 );
1084 assert_eq!(
1086 parse_into_kind("foo | -"),
1087 Err(RevsetParseErrorKind::SyntaxError)
1088 );
1089
1090 assert_eq!(parse_program(" ~ x ").unwrap().span.as_str(), "~ x");
1092 assert_eq!(parse_program(" x+ ").unwrap().span.as_str(), "x+");
1093 assert_eq!(parse_program(" x |y ").unwrap().span.as_str(), "x |y");
1094 assert_eq!(parse_program(" (x) ").unwrap().span.as_str(), "(x)");
1095 assert_eq!(parse_program("~( x|y) ").unwrap().span.as_str(), "~( x|y)");
1096 assert_eq!(parse_program(" ( x )- ").unwrap().span.as_str(), "( x )-");
1097 }
1098
1099 #[test]
1100 fn test_parse_revset_with_modifier() {
1101 fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
1102 parse_program_with_modifier(text)
1103 .map(|node| node.kind)
1104 .map_err(|err| *err.kind)
1105 }
1106
1107 assert_eq!(
1109 parse_into_kind("all:"),
1110 Err(RevsetParseErrorKind::SyntaxError)
1111 );
1112 assert_matches!(
1113 parse_into_kind("all:foo"),
1114 Ok(ExpressionKind::Modifier(modifier)) if modifier.name == "all"
1115 );
1116 assert_matches!(
1117 parse_into_kind("all::"),
1118 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1119 );
1120 assert_matches!(
1121 parse_into_kind("all::foo"),
1122 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1123 );
1124
1125 assert_eq!(
1127 parse_into_kind("all:::"),
1128 Err(RevsetParseErrorKind::SyntaxError)
1129 );
1130 assert_eq!(
1131 parse_into_kind("all:::foo"),
1132 Err(RevsetParseErrorKind::SyntaxError)
1133 );
1134
1135 assert_eq!(parse_normalized("all:(foo)"), parse_normalized("all:foo"));
1136 assert_eq!(
1137 parse_normalized("all:all::foo"),
1138 parse_normalized("all:(all::foo)"),
1139 );
1140 assert_eq!(
1141 parse_normalized("all:all | foo"),
1142 parse_normalized("all:(all | foo)"),
1143 );
1144
1145 assert_eq!(
1146 parse_normalized("all: ::foo"),
1147 parse_normalized("all:(::foo)"),
1148 );
1149 assert_eq!(parse_normalized(" all: foo"), parse_normalized("all:foo"));
1150 assert_eq!(
1151 parse_into_kind("(all:foo)"),
1152 Ok(ExpressionKind::StringPattern {
1153 kind: "all",
1154 value: "foo".to_owned()
1155 })
1156 );
1157 assert_matches!(
1158 parse_into_kind("all :foo"),
1159 Err(RevsetParseErrorKind::SyntaxError)
1160 );
1161 assert_eq!(
1162 parse_normalized("all:all:all"),
1163 parse_normalized("all:(all:all)"),
1164 );
1165 }
1166
1167 #[test]
1168 fn test_parse_whitespace() {
1169 let ascii_whitespaces: String = ('\x00'..='\x7f')
1170 .filter(char::is_ascii_whitespace)
1171 .collect();
1172 assert_eq!(
1173 parse_normalized(&format!("{ascii_whitespaces}all()")),
1174 parse_normalized("all()"),
1175 );
1176 }
1177
1178 #[test]
1179 fn test_parse_identifier() {
1180 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1182 assert_eq!(
1184 parse_into_kind("foo_bar/baz"),
1185 Ok(ExpressionKind::Identifier("foo_bar/baz"))
1186 );
1187 assert_eq!(
1189 parse_into_kind("*/foo/**"),
1190 Ok(ExpressionKind::Identifier("*/foo/**"))
1191 );
1192
1193 assert_eq!(
1195 parse_into_kind("foo.bar-v1+7"),
1196 Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1197 );
1198 assert_eq!(
1199 parse_normalized("foo.bar-v1+7-"),
1200 parse_normalized("(foo.bar-v1+7)-")
1201 );
1202 assert_eq!(
1204 parse_into_kind(".foo"),
1205 Err(RevsetParseErrorKind::SyntaxError)
1206 );
1207 assert_eq!(
1208 parse_into_kind("foo."),
1209 Err(RevsetParseErrorKind::SyntaxError)
1210 );
1211 assert_eq!(
1213 parse_into_kind("foo.+bar"),
1214 Err(RevsetParseErrorKind::SyntaxError)
1215 );
1216 assert_eq!(
1217 parse_into_kind("foo--bar"),
1218 Err(RevsetParseErrorKind::SyntaxError)
1219 );
1220 assert_eq!(
1221 parse_into_kind("foo+-bar"),
1222 Err(RevsetParseErrorKind::SyntaxError)
1223 );
1224
1225 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1227
1228 assert_eq!(
1230 parse_into_kind("柔術+jj"),
1231 Ok(ExpressionKind::Identifier("柔術+jj"))
1232 );
1233 }
1234
1235 #[test]
1236 fn test_parse_string_literal() {
1237 assert_eq!(
1239 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1240 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1241 );
1242
1243 assert_eq!(
1245 parse_into_kind(r#" "\y" "#),
1246 Err(RevsetParseErrorKind::SyntaxError)
1247 );
1248
1249 assert_eq!(
1251 parse_into_kind(r#" '' "#),
1252 Ok(ExpressionKind::String("".to_owned()))
1253 );
1254 assert_eq!(
1255 parse_into_kind(r#" 'a\n' "#),
1256 Ok(ExpressionKind::String(r"a\n".to_owned()))
1257 );
1258 assert_eq!(
1259 parse_into_kind(r#" '\' "#),
1260 Ok(ExpressionKind::String(r"\".to_owned()))
1261 );
1262 assert_eq!(
1263 parse_into_kind(r#" '"' "#),
1264 Ok(ExpressionKind::String(r#"""#.to_owned()))
1265 );
1266
1267 assert_eq!(
1269 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1270 Ok(ExpressionKind::String("aeiou".to_owned()))
1271 );
1272 assert_eq!(
1273 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1274 Ok(ExpressionKind::String("àèìðù".to_owned()))
1275 );
1276 assert_eq!(
1277 parse_into_kind(r#""\x""#),
1278 Err(RevsetParseErrorKind::SyntaxError)
1279 );
1280 assert_eq!(
1281 parse_into_kind(r#""\xf""#),
1282 Err(RevsetParseErrorKind::SyntaxError)
1283 );
1284 assert_eq!(
1285 parse_into_kind(r#""\xgg""#),
1286 Err(RevsetParseErrorKind::SyntaxError)
1287 );
1288 }
1289
1290 #[test]
1291 fn test_parse_string_pattern() {
1292 assert_eq!(
1293 parse_into_kind(r#"substring:"foo""#),
1294 Ok(ExpressionKind::StringPattern {
1295 kind: "substring",
1296 value: "foo".to_owned()
1297 })
1298 );
1299 assert_eq!(
1300 parse_into_kind(r#""exact:foo""#),
1301 Ok(ExpressionKind::String("exact:foo".to_owned()))
1302 );
1303 assert_eq!(
1304 parse_normalized(r#"(exact:"foo" )"#),
1305 parse_normalized(r#"(exact:"foo")"#),
1306 );
1307 assert_eq!(
1308 parse_into_kind(r#"exact:'\'"#),
1309 Ok(ExpressionKind::StringPattern {
1310 kind: "exact",
1311 value: r"\".to_owned()
1312 })
1313 );
1314 assert_matches!(
1315 parse_into_kind(r#"exact:("foo" )"#),
1316 Err(RevsetParseErrorKind::NotInfixOperator { .. })
1317 );
1318 }
1319
1320 #[test]
1321 fn test_parse_symbol_explicitly() {
1322 assert_matches!(parse_symbol("").as_deref(), Err(_));
1323 assert_matches!(parse_symbol("''").as_deref(), Err(_));
1326
1327 assert_matches!(parse_symbol("foo.bar").as_deref(), Ok("foo.bar"));
1328 assert_matches!(parse_symbol("foo@bar").as_deref(), Err(_));
1329 assert_matches!(parse_symbol("foo bar").as_deref(), Err(_));
1330
1331 assert_matches!(parse_symbol("'foo bar'").as_deref(), Ok("foo bar"));
1332 assert_matches!(parse_symbol(r#""foo\tbar""#).as_deref(), Ok("foo\tbar"));
1333
1334 assert_matches!(parse_symbol(" foo").as_deref(), Err(_));
1336 assert_matches!(parse_symbol("foo ").as_deref(), Err(_));
1337
1338 assert_matches!(parse_symbol("(foo)").as_deref(), Err(_));
1341 }
1342
1343 #[test]
1344 fn parse_at_workspace_and_remote_symbol() {
1345 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1347 assert_eq!(
1348 parse_into_kind("main@"),
1349 Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1350 );
1351 assert_eq!(
1352 parse_into_kind("main@origin"),
1353 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1354 name: "main".into(),
1355 remote: "origin".into()
1356 }))
1357 );
1358
1359 assert_eq!(
1361 parse_into_kind(r#""foo bar"@"#),
1362 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1363 );
1364 assert_eq!(
1365 parse_into_kind(r#""foo bar"@origin"#),
1366 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1367 name: "foo bar".into(),
1368 remote: "origin".into()
1369 }))
1370 );
1371 assert_eq!(
1372 parse_into_kind(r#"main@"foo bar""#),
1373 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1374 name: "main".into(),
1375 remote: "foo bar".into()
1376 }))
1377 );
1378 assert_eq!(
1379 parse_into_kind(r#"'foo bar'@'bar baz'"#),
1380 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1381 name: "foo bar".into(),
1382 remote: "bar baz".into()
1383 }))
1384 );
1385
1386 assert_eq!(
1388 parse_into_kind(r#""@""#),
1389 Ok(ExpressionKind::String("@".to_owned()))
1390 );
1391 assert_eq!(
1392 parse_into_kind(r#""main@""#),
1393 Ok(ExpressionKind::String("main@".to_owned()))
1394 );
1395 assert_eq!(
1396 parse_into_kind(r#""main@origin""#),
1397 Ok(ExpressionKind::String("main@origin".to_owned()))
1398 );
1399
1400 assert_eq!(
1402 parse_into_kind("柔術@"),
1403 Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1404 );
1405 assert_eq!(
1406 parse_into_kind("柔@術"),
1407 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1408 name: "柔".into(),
1409 remote: "術".into()
1410 }))
1411 );
1412 }
1413
1414 #[test]
1415 fn test_parse_function_call() {
1416 fn unwrap_function_call(node: ExpressionNode<'_>) -> Box<FunctionCallNode<'_>> {
1417 match node.kind {
1418 ExpressionKind::FunctionCall(function) => function,
1419 _ => panic!("unexpected expression: {node:?}"),
1420 }
1421 }
1422
1423 assert_eq!(
1425 parse_normalized(
1426 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ",
1427 ),
1428 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1429 );
1430 assert_eq!(
1432 parse_normalized("remote_bookmarks( remote = foo )"),
1433 parse_normalized("remote_bookmarks(remote=foo)"),
1434 );
1435
1436 assert!(parse_into_kind("bookmarks(,)").is_err());
1438 assert_eq!(
1440 parse_normalized("bookmarks(a,)"),
1441 parse_normalized("bookmarks(a)")
1442 );
1443 assert_eq!(
1444 parse_normalized("bookmarks(a , )"),
1445 parse_normalized("bookmarks(a)")
1446 );
1447 assert!(parse_into_kind("bookmarks(,a)").is_err());
1448 assert!(parse_into_kind("bookmarks(a,,)").is_err());
1449 assert!(parse_into_kind("bookmarks(a , , )").is_err());
1450 assert_eq!(
1451 parse_normalized("file(a,b,)"),
1452 parse_normalized("file(a, b)")
1453 );
1454 assert!(parse_into_kind("file(a,,b)").is_err());
1455 assert_eq!(
1456 parse_normalized("remote_bookmarks(a,remote=b , )"),
1457 parse_normalized("remote_bookmarks(a, remote=b)"),
1458 );
1459 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1460
1461 let function =
1463 unwrap_function_call(parse_program("foo( a, (b) , ~(c), d = (e) )").unwrap());
1464 assert_eq!(function.name_span.as_str(), "foo");
1465 assert_eq!(function.args_span.as_str(), "a, (b) , ~(c), d = (e)");
1466 assert_eq!(function.args[0].span.as_str(), "a");
1467 assert_eq!(function.args[1].span.as_str(), "(b)");
1468 assert_eq!(function.args[2].span.as_str(), "~(c)");
1469 assert_eq!(function.keyword_args[0].name_span.as_str(), "d");
1470 assert_eq!(function.keyword_args[0].value.span.as_str(), "(e)");
1471 }
1472
1473 #[test]
1474 fn test_parse_revset_alias_symbol_decl() {
1475 let mut aliases_map = RevsetAliasesMap::new();
1476 assert!(aliases_map.insert("@", "none()").is_err());
1478 assert!(aliases_map.insert("a@", "none()").is_err());
1479 assert!(aliases_map.insert("a@b", "none()").is_err());
1480 assert!(aliases_map.insert("柔術", "none()").is_err());
1483 }
1484
1485 #[test]
1486 fn test_parse_revset_alias_func_decl() {
1487 let mut aliases_map = RevsetAliasesMap::new();
1488 assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err());
1489 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1490 aliases_map
1491 .insert("func(a, b)", r#""is function 2""#)
1492 .unwrap();
1493 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1494 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1495
1496 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1497 assert_eq!(id, AliasId::Function("func", &[]));
1498 assert!(params.is_empty());
1499 assert_eq!(defn, r#""is function 0""#);
1500
1501 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1502 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1503 assert_eq!(params, ["b"]);
1504 assert_eq!(defn, r#""is function b""#);
1505
1506 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1507 assert_eq!(
1508 id,
1509 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1510 );
1511 assert_eq!(params, ["a", "b"]);
1512 assert_eq!(defn, r#""is function 2""#);
1513
1514 assert!(aliases_map.get_function("func", 3).is_none());
1515 }
1516
1517 #[test]
1518 fn test_parse_revset_alias_formal_parameter() {
1519 let mut aliases_map = RevsetAliasesMap::new();
1520 assert!(aliases_map.insert("f(@)", "none()").is_err());
1522 assert!(aliases_map.insert("f(a@)", "none()").is_err());
1523 assert!(aliases_map.insert("f(a@b)", "none()").is_err());
1524 assert!(aliases_map.insert("f(,)", "none()").is_err());
1526 assert!(aliases_map.insert("g(a,)", "none()").is_ok());
1528 assert!(aliases_map.insert("h(a , )", "none()").is_ok());
1529 assert!(aliases_map.insert("i(,a)", "none()").is_err());
1530 assert!(aliases_map.insert("j(a,,)", "none()").is_err());
1531 assert!(aliases_map.insert("k(a , , )", "none()").is_err());
1532 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
1533 assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
1534 }
1535
1536 #[test]
1537 fn test_parse_revset_compat_operator() {
1538 assert_eq!(
1539 parse_into_kind(":foo"),
1540 Err(RevsetParseErrorKind::NotPrefixOperator {
1541 op: ":".to_owned(),
1542 similar_op: "::".to_owned(),
1543 description: "ancestors".to_owned(),
1544 })
1545 );
1546 assert_eq!(
1547 parse_into_kind("foo^"),
1548 Err(RevsetParseErrorKind::NotPostfixOperator {
1549 op: "^".to_owned(),
1550 similar_op: "-".to_owned(),
1551 description: "parents".to_owned(),
1552 })
1553 );
1554 assert_eq!(
1555 parse_into_kind("foo + bar"),
1556 Err(RevsetParseErrorKind::NotInfixOperator {
1557 op: "+".to_owned(),
1558 similar_op: "|".to_owned(),
1559 description: "union".to_owned(),
1560 })
1561 );
1562 assert_eq!(
1563 parse_into_kind("foo - bar"),
1564 Err(RevsetParseErrorKind::NotInfixOperator {
1565 op: "-".to_owned(),
1566 similar_op: "~".to_owned(),
1567 description: "difference".to_owned(),
1568 })
1569 );
1570 }
1571
1572 #[test]
1573 fn test_parse_revset_operator_combinations() {
1574 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1576 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1578 assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y"));
1580 assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)"));
1581 assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)"));
1582 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1583 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1584 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1585 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1586 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1587 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1588 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1589 assert_eq!(
1591 parse_into_kind("::foo::"),
1592 Err(RevsetParseErrorKind::SyntaxError)
1593 );
1594 assert_eq!(
1595 parse_into_kind(":::foo"),
1596 Err(RevsetParseErrorKind::SyntaxError)
1597 );
1598 assert_eq!(
1599 parse_into_kind("::::foo"),
1600 Err(RevsetParseErrorKind::SyntaxError)
1601 );
1602 assert_eq!(
1603 parse_into_kind("foo:::"),
1604 Err(RevsetParseErrorKind::SyntaxError)
1605 );
1606 assert_eq!(
1607 parse_into_kind("foo::::"),
1608 Err(RevsetParseErrorKind::SyntaxError)
1609 );
1610 assert_eq!(
1611 parse_into_kind("foo:::bar"),
1612 Err(RevsetParseErrorKind::SyntaxError)
1613 );
1614 assert_eq!(
1615 parse_into_kind("foo::::bar"),
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("::::"),
1628 Err(RevsetParseErrorKind::SyntaxError)
1629 );
1630 assert_eq!(
1631 parse_into_kind("....foo"),
1632 Err(RevsetParseErrorKind::SyntaxError)
1633 );
1634 assert_eq!(
1635 parse_into_kind("foo...."),
1636 Err(RevsetParseErrorKind::SyntaxError)
1637 );
1638 assert_eq!(
1639 parse_into_kind("foo.....bar"),
1640 Err(RevsetParseErrorKind::SyntaxError)
1641 );
1642 assert_eq!(
1643 parse_into_kind("..foo..bar"),
1644 Err(RevsetParseErrorKind::SyntaxError)
1645 );
1646 assert_eq!(
1647 parse_into_kind("foo..bar.."),
1648 Err(RevsetParseErrorKind::SyntaxError)
1649 );
1650 assert_eq!(
1651 parse_into_kind("...."),
1652 Err(RevsetParseErrorKind::SyntaxError)
1653 );
1654 assert_eq!(
1655 parse_into_kind("::.."),
1656 Err(RevsetParseErrorKind::SyntaxError)
1657 );
1658 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1661 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1662 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1663 assert_eq!(
1664 parse_into_kind("::-"),
1665 Err(RevsetParseErrorKind::SyntaxError)
1666 );
1667 assert_eq!(
1668 parse_into_kind("..+"),
1669 Err(RevsetParseErrorKind::SyntaxError)
1670 );
1671 }
1672
1673 #[test]
1674 fn test_parse_revset_function() {
1675 assert_matches!(
1676 parse_into_kind("parents(foo)"),
1677 Ok(ExpressionKind::FunctionCall(_))
1678 );
1679 assert_eq!(
1680 parse_normalized("parents((foo))"),
1681 parse_normalized("parents(foo)"),
1682 );
1683 assert_eq!(
1684 parse_into_kind("parents(foo"),
1685 Err(RevsetParseErrorKind::SyntaxError)
1686 );
1687 }
1688
1689 #[test]
1690 fn test_expand_symbol_alias() {
1691 assert_eq!(
1692 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1693 parse_normalized("(a&b)|c")
1694 );
1695 assert_eq!(
1696 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1697 parse_normalized("(a|b)::heads(a|b)")
1698 );
1699
1700 assert_eq!(
1702 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1703 parse_normalized("a&(b|c)")
1704 );
1705
1706 assert_eq!(
1708 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1709 parse_normalized("a|'A'|'A'")
1710 );
1711
1712 assert_eq!(
1714 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1715 parse_normalized("author(exact:A)")
1716 );
1717
1718 assert_eq!(
1720 with_aliases([("A", "a")]).parse_normalized("A@"),
1721 parse_normalized("A@")
1722 );
1723 assert_eq!(
1724 with_aliases([("A", "a")]).parse_normalized("A@b"),
1725 parse_normalized("A@b")
1726 );
1727 assert_eq!(
1728 with_aliases([("B", "b")]).parse_normalized("a@B"),
1729 parse_normalized("a@B")
1730 );
1731
1732 assert_eq!(
1734 with_aliases([("all", "ALL")]).parse_normalized("all:all"),
1735 parse_normalized("all:ALL")
1736 );
1737
1738 assert_eq!(
1740 with_aliases([("A", "all:a")]).parse_normalized("A"),
1741 parse_normalized("all:a")
1742 );
1743
1744 assert_eq!(
1746 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1747 parse_normalized("b|c")
1748 );
1749
1750 assert_eq!(
1752 *with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1753 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1754 );
1755 assert_eq!(
1756 *with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1757 .parse("A")
1758 .unwrap_err()
1759 .kind,
1760 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1761 );
1762
1763 assert_eq!(
1765 *with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1766 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1767 );
1768 }
1769
1770 #[test]
1771 fn test_expand_function_alias() {
1772 assert_eq!(
1773 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1774 parse_normalized("a")
1775 );
1776 assert_eq!(
1777 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1778 parse_normalized("a")
1779 );
1780 assert_eq!(
1781 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"),
1782 parse_normalized("a|b")
1783 );
1784
1785 assert_eq!(
1787 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1788 parse_normalized("a|b")
1789 );
1790
1791 assert_eq!(
1793 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1794 parse_normalized("(a::y)|(b::x)")
1795 );
1796 assert_eq!(
1798 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1799 parse_normalized("(x|a)&y")
1800 );
1801 assert_eq!(
1803 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1804 parse_normalized("(x|(x|a))&y")
1805 );
1806
1807 assert_eq!(
1809 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1810 parse_normalized("a|x")
1811 );
1812
1813 assert_eq!(
1815 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1816 parse_normalized("a|x")
1817 );
1818
1819 assert_eq!(
1821 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1822 parse_normalized("a|'x'")
1823 );
1824
1825 assert_eq!(
1827 with_aliases([("F(x)", "all:x")]).parse_normalized("F(a|b)"),
1828 parse_normalized("all:(a|b)")
1829 );
1830
1831 assert_eq!(
1833 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1834 parse_normalized("a")
1835 );
1836
1837 assert_eq!(
1839 *with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1840 RevsetParseErrorKind::InvalidFunctionArguments {
1841 name: "F".to_owned(),
1842 message: "Expected 0 arguments".to_owned()
1843 }
1844 );
1845 assert_eq!(
1846 *with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1847 RevsetParseErrorKind::InvalidFunctionArguments {
1848 name: "F".to_owned(),
1849 message: "Expected 1 arguments".to_owned()
1850 }
1851 );
1852 assert_eq!(
1853 *with_aliases([("F(x,y)", "x|y")])
1854 .parse("F(a,b,c)")
1855 .unwrap_err()
1856 .kind,
1857 RevsetParseErrorKind::InvalidFunctionArguments {
1858 name: "F".to_owned(),
1859 message: "Expected 2 arguments".to_owned()
1860 }
1861 );
1862 assert_eq!(
1863 *with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1864 .parse("F()")
1865 .unwrap_err()
1866 .kind,
1867 RevsetParseErrorKind::InvalidFunctionArguments {
1868 name: "F".to_owned(),
1869 message: "Expected 1 to 2 arguments".to_owned()
1870 }
1871 );
1872 assert_eq!(
1873 *with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1874 .parse("F(a)")
1875 .unwrap_err()
1876 .kind,
1877 RevsetParseErrorKind::InvalidFunctionArguments {
1878 name: "F".to_owned(),
1879 message: "Expected 0, 2 arguments".to_owned()
1880 }
1881 );
1882
1883 assert_eq!(
1885 *with_aliases([("F(x)", "x")])
1886 .parse("F(x=y)")
1887 .unwrap_err()
1888 .kind,
1889 RevsetParseErrorKind::InvalidFunctionArguments {
1890 name: "F".to_owned(),
1891 message: "Unexpected keyword arguments".to_owned()
1892 }
1893 );
1894
1895 assert_eq!(
1897 *with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1898 .parse("F(a)")
1899 .unwrap_err()
1900 .kind,
1901 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1902 );
1903 assert_eq!(
1904 *with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1905 .parse("F(a)")
1906 .unwrap_err()
1907 .kind,
1908 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1909 );
1910 }
1911
1912 #[test]
1913 fn test_expand_with_locals() {
1914 assert_eq!(
1916 with_aliases([("A", "symbol")])
1917 .set_local("A", "local")
1918 .parse_normalized("A"),
1919 parse_normalized("local")
1920 );
1921
1922 assert_eq!(
1924 with_aliases([("B", "A"), ("F(x)", "x&A")])
1925 .set_local("A", "a")
1926 .parse_normalized("A|B|F(A)"),
1927 parse_normalized("a|A|(a&A)")
1928 );
1929 }
1930}