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