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