1#![allow(missing_docs)]
16
17use std::collections::HashSet;
18use std::error;
19use std::mem;
20use std::str::FromStr;
21
22use itertools::Itertools as _;
23use once_cell::sync::Lazy;
24use pest::iterators::Pair;
25use pest::iterators::Pairs;
26use pest::pratt_parser::Assoc;
27use pest::pratt_parser::Op;
28use pest::pratt_parser::PrattParser;
29use pest::Parser as _;
30use pest_derive::Parser;
31use thiserror::Error;
32
33use crate::dsl_util;
34use crate::dsl_util::collect_similar;
35use crate::dsl_util::AliasDeclaration;
36use crate::dsl_util::AliasDeclarationParser;
37use crate::dsl_util::AliasDefinitionParser;
38use crate::dsl_util::AliasExpandError;
39use crate::dsl_util::AliasExpandableExpression;
40use crate::dsl_util::AliasId;
41use crate::dsl_util::AliasesMap;
42use crate::dsl_util::Diagnostics;
43use crate::dsl_util::ExpressionFolder;
44use crate::dsl_util::FoldableExpression;
45use crate::dsl_util::FunctionCallParser;
46use crate::dsl_util::InvalidArguments;
47use crate::dsl_util::StringLiteralParser;
48use crate::ref_name::RefNameBuf;
49use crate::ref_name::RemoteNameBuf;
50use crate::ref_name::RemoteRefSymbolBuf;
51
52#[derive(Parser)]
53#[grammar = "revset.pest"]
54struct RevsetParser;
55
56const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
57 content_rule: Rule::string_content,
58 escape_rule: Rule::string_escape,
59};
60const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser {
61 function_name_rule: Rule::function_name,
62 function_arguments_rule: Rule::function_arguments,
63 keyword_argument_rule: Rule::keyword_argument,
64 argument_name_rule: Rule::strict_identifier,
65 argument_value_rule: Rule::expression,
66};
67
68impl Rule {
69 fn is_compat(&self) -> bool {
72 matches!(
73 self,
74 Rule::compat_parents_op
75 | Rule::compat_dag_range_op
76 | Rule::compat_dag_range_pre_op
77 | Rule::compat_dag_range_post_op
78 | Rule::compat_add_op
79 | Rule::compat_sub_op
80 )
81 }
82
83 fn to_symbol(self) -> Option<&'static str> {
84 match self {
85 Rule::EOI => None,
86 Rule::whitespace => None,
87 Rule::identifier_part => None,
88 Rule::identifier => None,
89 Rule::strict_identifier_part => None,
90 Rule::strict_identifier => None,
91 Rule::symbol => None,
92 Rule::string_escape => None,
93 Rule::string_content_char => None,
94 Rule::string_content => None,
95 Rule::string_literal => None,
96 Rule::raw_string_content => None,
97 Rule::raw_string_literal => None,
98 Rule::at_op => Some("@"),
99 Rule::pattern_kind_op => Some(":"),
100 Rule::parents_op => Some("-"),
101 Rule::children_op => Some("+"),
102 Rule::compat_parents_op => Some("^"),
103 Rule::dag_range_op
104 | Rule::dag_range_pre_op
105 | Rule::dag_range_post_op
106 | Rule::dag_range_all_op => Some("::"),
107 Rule::compat_dag_range_op
108 | Rule::compat_dag_range_pre_op
109 | Rule::compat_dag_range_post_op => Some(":"),
110 Rule::range_op => Some(".."),
111 Rule::range_pre_op | Rule::range_post_op | Rule::range_all_op => Some(".."),
112 Rule::range_ops => None,
113 Rule::range_pre_ops => None,
114 Rule::range_post_ops => None,
115 Rule::range_all_ops => None,
116 Rule::negate_op => Some("~"),
117 Rule::union_op => Some("|"),
118 Rule::intersection_op => Some("&"),
119 Rule::difference_op => Some("~"),
120 Rule::compat_add_op => Some("+"),
121 Rule::compat_sub_op => Some("-"),
122 Rule::infix_op => None,
123 Rule::function => None,
124 Rule::function_name => None,
125 Rule::keyword_argument => None,
126 Rule::argument => None,
127 Rule::function_arguments => None,
128 Rule::formal_parameters => None,
129 Rule::string_pattern => None,
130 Rule::primary => None,
131 Rule::neighbors_expression => None,
132 Rule::range_expression => None,
133 Rule::expression => None,
134 Rule::program_modifier => None,
135 Rule::program => None,
136 Rule::symbol_name => None,
137 Rule::function_alias_declaration => None,
138 Rule::alias_declaration => None,
139 }
140 }
141}
142
143pub type RevsetDiagnostics = Diagnostics<RevsetParseError>;
146
147#[derive(Debug, Error)]
148#[error("{pest_error}")]
149pub struct RevsetParseError {
150 kind: Box<RevsetParseErrorKind>,
151 pest_error: Box<pest::error::Error<Rule>>,
152 source: Option<Box<dyn error::Error + Send + Sync>>,
153}
154
155#[derive(Debug, Error, PartialEq, Eq)]
156pub enum RevsetParseErrorKind {
157 #[error("Syntax error")]
158 SyntaxError,
159 #[error("`{op}` is not a prefix operator")]
160 NotPrefixOperator {
161 op: String,
162 similar_op: String,
163 description: String,
164 },
165 #[error("`{op}` is not a postfix operator")]
166 NotPostfixOperator {
167 op: String,
168 similar_op: String,
169 description: String,
170 },
171 #[error("`{op}` is not an infix operator")]
172 NotInfixOperator {
173 op: String,
174 similar_op: String,
175 description: String,
176 },
177 #[error("Modifier `{0}` doesn't exist")]
178 NoSuchModifier(String),
179 #[error("Function `{name}` doesn't exist")]
180 NoSuchFunction {
181 name: String,
182 candidates: Vec<String>,
183 },
184 #[error("Function `{name}`: {message}")]
185 InvalidFunctionArguments { name: String, message: String },
186 #[error("Cannot resolve file pattern without workspace")]
187 FsPathWithoutWorkspace,
188 #[error("Cannot resolve `@` without workspace")]
189 WorkingCopyWithoutWorkspace,
190 #[error("Redefinition of function parameter")]
191 RedefinedFunctionParameter,
192 #[error("{0}")]
193 Expression(String),
194 #[error("In alias `{0}`")]
195 InAliasExpansion(String),
196 #[error("In function parameter `{0}`")]
197 InParameterExpansion(String),
198 #[error("Alias `{0}` expanded recursively")]
199 RecursiveAlias(String),
200}
201
202impl RevsetParseError {
203 pub(super) fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self {
204 let message = kind.to_string();
205 let pest_error = Box::new(pest::error::Error::new_from_span(
206 pest::error::ErrorVariant::CustomError { message },
207 span,
208 ));
209 RevsetParseError {
210 kind: Box::new(kind),
211 pest_error,
212 source: None,
213 }
214 }
215
216 pub(super) fn with_source(
217 mut self,
218 source: impl Into<Box<dyn error::Error + Send + Sync>>,
219 ) -> Self {
220 self.source = Some(source.into());
221 self
222 }
223
224 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
226 Self::with_span(RevsetParseErrorKind::Expression(message.into()), span)
227 }
228
229 pub(super) fn extend_function_candidates<I>(mut self, other_functions: I) -> Self
232 where
233 I: IntoIterator,
234 I::Item: AsRef<str>,
235 {
236 if let RevsetParseErrorKind::NoSuchFunction { name, candidates } = self.kind.as_mut() {
237 let other_candidates = collect_similar(name, other_functions);
238 *candidates = itertools::merge(mem::take(candidates), other_candidates)
239 .dedup()
240 .collect();
241 }
242 self
243 }
244
245 pub fn kind(&self) -> &RevsetParseErrorKind {
246 &self.kind
247 }
248
249 pub fn origin(&self) -> Option<&Self> {
251 self.source.as_ref().and_then(|e| e.downcast_ref())
252 }
253}
254
255impl AliasExpandError for RevsetParseError {
256 fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
257 err.into()
258 }
259
260 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
261 Self::with_span(RevsetParseErrorKind::RecursiveAlias(id.to_string()), span)
262 }
263
264 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
265 let kind = match id {
266 AliasId::Symbol(_) | AliasId::Function(..) => {
267 RevsetParseErrorKind::InAliasExpansion(id.to_string())
268 }
269 AliasId::Parameter(_) => RevsetParseErrorKind::InParameterExpansion(id.to_string()),
270 };
271 Self::with_span(kind, span).with_source(self)
272 }
273}
274
275impl From<pest::error::Error<Rule>> for RevsetParseError {
276 fn from(err: pest::error::Error<Rule>) -> Self {
277 RevsetParseError {
278 kind: Box::new(RevsetParseErrorKind::SyntaxError),
279 pest_error: Box::new(rename_rules_in_pest_error(err)),
280 source: None,
281 }
282 }
283}
284
285impl From<InvalidArguments<'_>> for RevsetParseError {
286 fn from(err: InvalidArguments<'_>) -> Self {
287 let kind = RevsetParseErrorKind::InvalidFunctionArguments {
288 name: err.name.to_owned(),
289 message: err.message,
290 };
291 Self::with_span(kind, err.span)
292 }
293}
294
295fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
296 let pest::error::ErrorVariant::ParsingError {
297 positives,
298 negatives,
299 } = &mut err.variant
300 else {
301 return err;
302 };
303
304 let mut known_syms = HashSet::new();
307 positives.retain(|rule| {
308 !rule.is_compat() && rule.to_symbol().is_none_or(|sym| known_syms.insert(sym))
309 });
310 let mut known_syms = HashSet::new();
311 negatives.retain(|rule| rule.to_symbol().is_none_or(|sym| known_syms.insert(sym)));
312 err.renamed_rules(|rule| {
313 rule.to_symbol()
314 .map(|sym| format!("`{sym}`"))
315 .unwrap_or_else(|| format!("<{rule:?}>"))
316 })
317}
318
319#[derive(Clone, Debug, Eq, PartialEq)]
320pub enum ExpressionKind<'i> {
321 Identifier(&'i str),
323 String(String),
325 StringPattern {
327 kind: &'i str,
328 value: String,
329 },
330 RemoteSymbol(RemoteRefSymbolBuf),
332 AtWorkspace(String),
334 AtCurrentWorkspace,
336 DagRangeAll,
338 RangeAll,
340 Unary(UnaryOp, Box<ExpressionNode<'i>>),
341 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
342 UnionAll(Vec<ExpressionNode<'i>>),
344 FunctionCall(Box<FunctionCallNode<'i>>),
345 Modifier(Box<ModifierNode<'i>>),
347 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
349}
350
351impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
352 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
353 where
354 F: ExpressionFolder<'i, Self> + ?Sized,
355 {
356 match self {
357 ExpressionKind::Identifier(name) => folder.fold_identifier(name, span),
358 ExpressionKind::String(_)
359 | ExpressionKind::StringPattern { .. }
360 | ExpressionKind::RemoteSymbol(_)
361 | ExpressionKind::AtWorkspace(_)
362 | ExpressionKind::AtCurrentWorkspace
363 | ExpressionKind::DagRangeAll
364 | ExpressionKind::RangeAll => Ok(self),
365 ExpressionKind::Unary(op, arg) => {
366 let arg = Box::new(folder.fold_expression(*arg)?);
367 Ok(ExpressionKind::Unary(op, arg))
368 }
369 ExpressionKind::Binary(op, lhs, rhs) => {
370 let lhs = Box::new(folder.fold_expression(*lhs)?);
371 let rhs = Box::new(folder.fold_expression(*rhs)?);
372 Ok(ExpressionKind::Binary(op, lhs, rhs))
373 }
374 ExpressionKind::UnionAll(nodes) => {
375 let nodes = dsl_util::fold_expression_nodes(folder, nodes)?;
376 Ok(ExpressionKind::UnionAll(nodes))
377 }
378 ExpressionKind::FunctionCall(function) => folder.fold_function_call(function, span),
379 ExpressionKind::Modifier(modifier) => {
380 let modifier = Box::new(ModifierNode {
381 name: modifier.name,
382 name_span: modifier.name_span,
383 body: folder.fold_expression(modifier.body)?,
384 });
385 Ok(ExpressionKind::Modifier(modifier))
386 }
387 ExpressionKind::AliasExpanded(id, subst) => {
388 let subst = Box::new(folder.fold_expression(*subst)?);
389 Ok(ExpressionKind::AliasExpanded(id, subst))
390 }
391 }
392 }
393}
394
395impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
396 fn identifier(name: &'i str) -> Self {
397 ExpressionKind::Identifier(name)
398 }
399
400 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
401 ExpressionKind::FunctionCall(function)
402 }
403
404 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
405 ExpressionKind::AliasExpanded(id, subst)
406 }
407}
408
409#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
410pub enum UnaryOp {
411 Negate,
413 DagRangePre,
415 DagRangePost,
417 RangePre,
419 RangePost,
421 Parents,
423 Children,
425}
426
427#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
428pub enum BinaryOp {
429 Intersection,
431 Difference,
433 DagRange,
435 Range,
437}
438
439pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
440pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
441
442#[derive(Clone, Debug, Eq, PartialEq)]
444pub struct ModifierNode<'i> {
445 pub name: &'i str,
447 pub name_span: pest::Span<'i>,
449 pub body: ExpressionNode<'i>,
451}
452
453fn union_nodes<'i>(lhs: ExpressionNode<'i>, rhs: ExpressionNode<'i>) -> ExpressionNode<'i> {
454 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
455 let expr = match lhs.kind {
456 ExpressionKind::UnionAll(mut nodes) => {
459 nodes.push(rhs);
460 ExpressionKind::UnionAll(nodes)
461 }
462 _ => ExpressionKind::UnionAll(vec![lhs, rhs]),
463 };
464 ExpressionNode::new(expr, span)
465}
466
467pub fn parse_program(revset_str: &str) -> Result<ExpressionNode, RevsetParseError> {
469 let mut pairs = RevsetParser::parse(Rule::program, revset_str)?;
470 let first = pairs.next().unwrap();
471 match first.as_rule() {
472 Rule::expression => parse_expression_node(first.into_inner()),
473 Rule::program_modifier => {
474 let [lhs, op] = first.into_inner().collect_array().unwrap();
475 let rhs = pairs.next().unwrap();
476 assert_eq!(lhs.as_rule(), Rule::strict_identifier);
477 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
478 assert_eq!(rhs.as_rule(), Rule::expression);
479 let span = lhs.as_span().start_pos().span(&rhs.as_span().end_pos());
480 let modifier = Box::new(ModifierNode {
481 name: lhs.as_str(),
482 name_span: lhs.as_span(),
483 body: parse_expression_node(rhs.into_inner())?,
484 });
485 let expr = ExpressionKind::Modifier(modifier);
486 Ok(ExpressionNode::new(expr, span))
487 }
488 r => panic!("unexpected revset parse rule: {r:?}"),
489 }
490}
491
492fn parse_expression_node(pairs: Pairs<Rule>) -> Result<ExpressionNode, RevsetParseError> {
493 fn not_prefix_op(
494 op: &Pair<Rule>,
495 similar_op: impl Into<String>,
496 description: impl Into<String>,
497 ) -> RevsetParseError {
498 RevsetParseError::with_span(
499 RevsetParseErrorKind::NotPrefixOperator {
500 op: op.as_str().to_owned(),
501 similar_op: similar_op.into(),
502 description: description.into(),
503 },
504 op.as_span(),
505 )
506 }
507
508 fn not_postfix_op(
509 op: &Pair<Rule>,
510 similar_op: impl Into<String>,
511 description: impl Into<String>,
512 ) -> RevsetParseError {
513 RevsetParseError::with_span(
514 RevsetParseErrorKind::NotPostfixOperator {
515 op: op.as_str().to_owned(),
516 similar_op: similar_op.into(),
517 description: description.into(),
518 },
519 op.as_span(),
520 )
521 }
522
523 fn not_infix_op(
524 op: &Pair<Rule>,
525 similar_op: impl Into<String>,
526 description: impl Into<String>,
527 ) -> RevsetParseError {
528 RevsetParseError::with_span(
529 RevsetParseErrorKind::NotInfixOperator {
530 op: op.as_str().to_owned(),
531 similar_op: similar_op.into(),
532 description: description.into(),
533 },
534 op.as_span(),
535 )
536 }
537
538 static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| {
539 PrattParser::new()
540 .op(Op::infix(Rule::union_op, Assoc::Left)
541 | Op::infix(Rule::compat_add_op, Assoc::Left))
542 .op(Op::infix(Rule::intersection_op, Assoc::Left)
543 | Op::infix(Rule::difference_op, Assoc::Left)
544 | Op::infix(Rule::compat_sub_op, Assoc::Left))
545 .op(Op::prefix(Rule::negate_op))
546 .op(Op::infix(Rule::dag_range_op, Assoc::Left)
548 | Op::infix(Rule::compat_dag_range_op, Assoc::Left)
549 | Op::infix(Rule::range_op, Assoc::Left))
550 .op(Op::prefix(Rule::dag_range_pre_op)
551 | Op::prefix(Rule::compat_dag_range_pre_op)
552 | Op::prefix(Rule::range_pre_op))
553 .op(Op::postfix(Rule::dag_range_post_op)
554 | Op::postfix(Rule::compat_dag_range_post_op)
555 | Op::postfix(Rule::range_post_op))
556 .op(Op::postfix(Rule::parents_op)
558 | Op::postfix(Rule::children_op)
559 | Op::postfix(Rule::compat_parents_op))
560 });
561 PRATT
562 .map_primary(|primary| {
563 let expr = match primary.as_rule() {
564 Rule::primary => return parse_primary_node(primary),
565 Rule::dag_range_all_op => ExpressionKind::DagRangeAll,
566 Rule::range_all_op => ExpressionKind::RangeAll,
567 r => panic!("unexpected primary rule {r:?}"),
568 };
569 Ok(ExpressionNode::new(expr, primary.as_span()))
570 })
571 .map_prefix(|op, rhs| {
572 let op_kind = match op.as_rule() {
573 Rule::negate_op => UnaryOp::Negate,
574 Rule::dag_range_pre_op => UnaryOp::DagRangePre,
575 Rule::compat_dag_range_pre_op => Err(not_prefix_op(&op, "::", "ancestors"))?,
576 Rule::range_pre_op => UnaryOp::RangePre,
577 r => panic!("unexpected prefix operator rule {r:?}"),
578 };
579 let rhs = Box::new(rhs?);
580 let span = op.as_span().start_pos().span(&rhs.span.end_pos());
581 let expr = ExpressionKind::Unary(op_kind, rhs);
582 Ok(ExpressionNode::new(expr, span))
583 })
584 .map_postfix(|lhs, op| {
585 let op_kind = match op.as_rule() {
586 Rule::dag_range_post_op => UnaryOp::DagRangePost,
587 Rule::compat_dag_range_post_op => Err(not_postfix_op(&op, "::", "descendants"))?,
588 Rule::range_post_op => UnaryOp::RangePost,
589 Rule::parents_op => UnaryOp::Parents,
590 Rule::children_op => UnaryOp::Children,
591 Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents"))?,
592 r => panic!("unexpected postfix operator rule {r:?}"),
593 };
594 let lhs = Box::new(lhs?);
595 let span = lhs.span.start_pos().span(&op.as_span().end_pos());
596 let expr = ExpressionKind::Unary(op_kind, lhs);
597 Ok(ExpressionNode::new(expr, span))
598 })
599 .map_infix(|lhs, op, rhs| {
600 let op_kind = match op.as_rule() {
601 Rule::union_op => return Ok(union_nodes(lhs?, rhs?)),
602 Rule::compat_add_op => Err(not_infix_op(&op, "|", "union"))?,
603 Rule::intersection_op => BinaryOp::Intersection,
604 Rule::difference_op => BinaryOp::Difference,
605 Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference"))?,
606 Rule::dag_range_op => BinaryOp::DagRange,
607 Rule::compat_dag_range_op => Err(not_infix_op(&op, "::", "DAG range"))?,
608 Rule::range_op => BinaryOp::Range,
609 r => panic!("unexpected infix operator rule {r:?}"),
610 };
611 let lhs = Box::new(lhs?);
612 let rhs = Box::new(rhs?);
613 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
614 let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
615 Ok(ExpressionNode::new(expr, span))
616 })
617 .parse(pairs)
618}
619
620fn parse_primary_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
621 let span = pair.as_span();
622 let mut pairs = pair.into_inner();
623 let first = pairs.next().unwrap();
624 let expr = match first.as_rule() {
625 Rule::expression => return parse_expression_node(first.into_inner()),
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.into_inner()),
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_program_with<B, M>(
763 diagnostics: &mut RevsetDiagnostics,
764 node: &ExpressionNode,
765 parse_body: impl FnOnce(&mut RevsetDiagnostics, &ExpressionNode) -> Result<B, RevsetParseError>,
766 parse_modifier: impl FnOnce(
767 &mut RevsetDiagnostics,
768 &str,
769 pest::Span<'_>,
770 ) -> Result<M, RevsetParseError>,
771) -> Result<(B, Option<M>), RevsetParseError> {
772 expect_expression_with(diagnostics, node, |diagnostics, node| match &node.kind {
773 ExpressionKind::Modifier(modifier) => {
774 let parsed_modifier = parse_modifier(diagnostics, modifier.name, modifier.name_span)?;
775 let parsed_body = parse_body(diagnostics, &modifier.body)?;
776 Ok((parsed_body, Some(parsed_modifier)))
777 }
778 _ => Ok((parse_body(diagnostics, node)?, None)),
779 })
780}
781
782pub(super) fn expect_pattern_with<T, E: Into<Box<dyn error::Error + Send + Sync>>>(
783 diagnostics: &mut RevsetDiagnostics,
784 type_name: &str,
785 node: &ExpressionNode,
786 parse_pattern: impl FnOnce(&mut RevsetDiagnostics, &str, Option<&str>) -> Result<T, E>,
787) -> Result<T, RevsetParseError> {
788 let wrap_error = |err: E| {
789 RevsetParseError::expression(format!("Invalid {type_name}"), node.span).with_source(err)
790 };
791 expect_expression_with(diagnostics, node, |diagnostics, node| match &node.kind {
792 ExpressionKind::Identifier(name) => {
793 parse_pattern(diagnostics, name, None).map_err(wrap_error)
794 }
795 ExpressionKind::String(name) => parse_pattern(diagnostics, name, None).map_err(wrap_error),
796 ExpressionKind::StringPattern { kind, value } => {
797 parse_pattern(diagnostics, value, Some(kind)).map_err(wrap_error)
798 }
799 _ => Err(RevsetParseError::expression(
800 format!("Expected expression of {type_name}"),
801 node.span,
802 )),
803 })
804}
805
806pub fn expect_literal<T: FromStr>(
807 diagnostics: &mut RevsetDiagnostics,
808 type_name: &str,
809 node: &ExpressionNode,
810) -> Result<T, RevsetParseError> {
811 let make_error = || {
812 RevsetParseError::expression(
813 format!("Expected expression of type {type_name}"),
814 node.span,
815 )
816 };
817 expect_expression_with(diagnostics, node, |_diagnostics, node| match &node.kind {
818 ExpressionKind::Identifier(name) => name.parse().map_err(|_| make_error()),
819 ExpressionKind::String(name) => name.parse().map_err(|_| make_error()),
820 _ => Err(make_error()),
821 })
822}
823
824pub(super) fn expect_expression_with<T>(
827 diagnostics: &mut RevsetDiagnostics,
828 node: &ExpressionNode,
829 f: impl FnOnce(&mut RevsetDiagnostics, &ExpressionNode) -> Result<T, RevsetParseError>,
830) -> Result<T, RevsetParseError> {
831 if let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
832 let mut inner_diagnostics = RevsetDiagnostics::new();
833 let expression = expect_expression_with(&mut inner_diagnostics, subst, f)
834 .map_err(|e| e.within_alias_expansion(*id, node.span))?;
835 diagnostics.extend_with(inner_diagnostics, |diag| {
836 diag.within_alias_expansion(*id, node.span)
837 });
838 Ok(expression)
839 } else {
840 f(diagnostics, node)
841 }
842}
843
844#[cfg(test)]
845mod tests {
846 use std::collections::HashMap;
847
848 use assert_matches::assert_matches;
849
850 use super::*;
851 use crate::dsl_util::KeywordArgument;
852
853 #[derive(Debug)]
854 struct WithRevsetAliasesMap<'i> {
855 aliases_map: RevsetAliasesMap,
856 locals: HashMap<&'i str, ExpressionNode<'i>>,
857 }
858
859 impl<'i> WithRevsetAliasesMap<'i> {
860 fn set_local(mut self, name: &'i str, value: &'i str) -> Self {
861 self.locals.insert(name, parse_program(value).unwrap());
862 self
863 }
864
865 fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
866 let node = parse_program(text)?;
867 dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals)
868 }
869
870 fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> {
871 normalize_tree(self.parse(text).unwrap())
872 }
873 }
874
875 fn with_aliases<'i>(
876 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
877 ) -> WithRevsetAliasesMap<'i> {
878 let mut aliases_map = RevsetAliasesMap::new();
879 for (decl, defn) in aliases {
880 aliases_map.insert(decl, defn).unwrap();
881 }
882 WithRevsetAliasesMap {
883 aliases_map,
884 locals: HashMap::new(),
885 }
886 }
887
888 fn parse_into_kind(text: &str) -> Result<ExpressionKind, RevsetParseErrorKind> {
889 parse_program(text)
890 .map(|node| node.kind)
891 .map_err(|err| *err.kind)
892 }
893
894 fn parse_normalized(text: &str) -> ExpressionNode {
895 normalize_tree(parse_program(text).unwrap())
896 }
897
898 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
900 fn empty_span() -> pest::Span<'static> {
901 pest::Span::new("", 0, 0).unwrap()
902 }
903
904 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
905 nodes.into_iter().map(normalize_tree).collect()
906 }
907
908 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
909 FunctionCallNode {
910 name: function.name,
911 name_span: empty_span(),
912 args: normalize_list(function.args),
913 keyword_args: function
914 .keyword_args
915 .into_iter()
916 .map(|arg| KeywordArgument {
917 name: arg.name,
918 name_span: empty_span(),
919 value: normalize_tree(arg.value),
920 })
921 .collect(),
922 args_span: empty_span(),
923 }
924 }
925
926 let normalized_kind = match node.kind {
927 ExpressionKind::Identifier(_)
928 | ExpressionKind::String(_)
929 | ExpressionKind::StringPattern { .. }
930 | ExpressionKind::RemoteSymbol(_)
931 | ExpressionKind::AtWorkspace(_)
932 | ExpressionKind::AtCurrentWorkspace
933 | ExpressionKind::DagRangeAll
934 | ExpressionKind::RangeAll => node.kind,
935 ExpressionKind::Unary(op, arg) => {
936 let arg = Box::new(normalize_tree(*arg));
937 ExpressionKind::Unary(op, arg)
938 }
939 ExpressionKind::Binary(op, lhs, rhs) => {
940 let lhs = Box::new(normalize_tree(*lhs));
941 let rhs = Box::new(normalize_tree(*rhs));
942 ExpressionKind::Binary(op, lhs, rhs)
943 }
944 ExpressionKind::UnionAll(nodes) => {
945 let nodes = normalize_list(nodes);
946 ExpressionKind::UnionAll(nodes)
947 }
948 ExpressionKind::FunctionCall(function) => {
949 let function = Box::new(normalize_function_call(*function));
950 ExpressionKind::FunctionCall(function)
951 }
952 ExpressionKind::Modifier(modifier) => {
953 let modifier = Box::new(ModifierNode {
954 name: modifier.name,
955 name_span: empty_span(),
956 body: normalize_tree(modifier.body),
957 });
958 ExpressionKind::Modifier(modifier)
959 }
960 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
961 };
962 ExpressionNode {
963 kind: normalized_kind,
964 span: empty_span(),
965 }
966 }
967
968 #[test]
969 fn test_parse_tree_eq() {
970 assert_eq!(
971 parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
972 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
973 );
974 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
975 }
976
977 #[test]
978 fn test_parse_revset() {
979 assert_eq!(
981 parse_into_kind("\"foo\""),
982 Ok(ExpressionKind::String("foo".to_owned()))
983 );
984 assert_eq!(
985 parse_into_kind("'foo'"),
986 Ok(ExpressionKind::String("foo".to_owned()))
987 );
988 assert_matches!(
990 parse_into_kind("foo-"),
991 Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
992 );
993 assert_matches!(
995 parse_into_kind("foo+"),
996 Ok(ExpressionKind::Unary(UnaryOp::Children, _))
997 );
998 assert_matches!(
1000 parse_into_kind("::foo"),
1001 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
1002 );
1003 assert_matches!(
1005 parse_into_kind("foo::"),
1006 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1007 );
1008 assert_matches!(
1010 parse_into_kind("foo::bar"),
1011 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1012 );
1013 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
1015 assert_matches!(
1017 parse_into_kind("..foo"),
1018 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
1019 );
1020 assert_matches!(
1021 parse_into_kind("foo.."),
1022 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
1023 );
1024 assert_matches!(
1025 parse_into_kind("foo..bar"),
1026 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
1027 );
1028 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
1030 assert_matches!(
1032 parse_into_kind("~ foo"),
1033 Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1034 );
1035 assert_eq!(
1036 parse_normalized("~ ~~ foo"),
1037 parse_normalized("~(~(~(foo)))"),
1038 );
1039 assert_matches!(
1041 parse_into_kind("foo & bar"),
1042 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1043 );
1044 assert_matches!(
1046 parse_into_kind("foo | bar"),
1047 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1048 );
1049 assert_matches!(
1050 parse_into_kind("foo | bar | baz"),
1051 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1052 );
1053 assert_matches!(
1055 parse_into_kind("foo ~ bar"),
1056 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1057 );
1058 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1060 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1062 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1063 assert_eq!(
1065 parse_into_kind(" :: foo "),
1066 Err(RevsetParseErrorKind::SyntaxError)
1067 );
1068 assert_eq!(
1070 parse_into_kind("foo | -"),
1071 Err(RevsetParseErrorKind::SyntaxError)
1072 );
1073 assert_eq!(
1075 parse_normalized(
1076 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ",
1077 ),
1078 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1079 );
1080 assert_eq!(
1082 parse_normalized("remote_bookmarks( remote = foo )"),
1083 parse_normalized("remote_bookmarks(remote=foo)"),
1084 );
1085
1086 assert!(parse_into_kind("bookmarks(,)").is_err());
1088 assert_eq!(
1090 parse_normalized("bookmarks(a,)"),
1091 parse_normalized("bookmarks(a)")
1092 );
1093 assert_eq!(
1094 parse_normalized("bookmarks(a , )"),
1095 parse_normalized("bookmarks(a)")
1096 );
1097 assert!(parse_into_kind("bookmarks(,a)").is_err());
1098 assert!(parse_into_kind("bookmarks(a,,)").is_err());
1099 assert!(parse_into_kind("bookmarks(a , , )").is_err());
1100 assert_eq!(
1101 parse_normalized("file(a,b,)"),
1102 parse_normalized("file(a, b)")
1103 );
1104 assert!(parse_into_kind("file(a,,b)").is_err());
1105 assert_eq!(
1106 parse_normalized("remote_bookmarks(a,remote=b , )"),
1107 parse_normalized("remote_bookmarks(a, remote=b)"),
1108 );
1109 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1110 }
1111
1112 #[test]
1113 fn test_parse_revset_with_modifier() {
1114 assert_eq!(
1116 parse_into_kind("all:"),
1117 Err(RevsetParseErrorKind::SyntaxError)
1118 );
1119 assert_matches!(
1120 parse_into_kind("all:foo"),
1121 Ok(ExpressionKind::Modifier(modifier)) if modifier.name == "all"
1122 );
1123 assert_matches!(
1124 parse_into_kind("all::"),
1125 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1126 );
1127 assert_matches!(
1128 parse_into_kind("all::foo"),
1129 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1130 );
1131
1132 assert_eq!(
1134 parse_into_kind("all:::"),
1135 Err(RevsetParseErrorKind::SyntaxError)
1136 );
1137 assert_eq!(
1138 parse_into_kind("all:::foo"),
1139 Err(RevsetParseErrorKind::SyntaxError)
1140 );
1141
1142 assert_eq!(parse_normalized("all:(foo)"), parse_normalized("all:foo"));
1143 assert_eq!(
1144 parse_normalized("all:all::foo"),
1145 parse_normalized("all:(all::foo)"),
1146 );
1147 assert_eq!(
1148 parse_normalized("all:all | foo"),
1149 parse_normalized("all:(all | foo)"),
1150 );
1151
1152 assert_eq!(
1153 parse_normalized("all: ::foo"),
1154 parse_normalized("all:(::foo)"),
1155 );
1156 assert_eq!(parse_normalized(" all: foo"), parse_normalized("all:foo"));
1157 assert_eq!(
1158 parse_into_kind("(all:foo)"),
1159 Ok(ExpressionKind::StringPattern {
1160 kind: "all",
1161 value: "foo".to_owned()
1162 })
1163 );
1164 assert_matches!(
1165 parse_into_kind("all :foo"),
1166 Err(RevsetParseErrorKind::SyntaxError)
1167 );
1168 assert_eq!(
1169 parse_normalized("all:all:all"),
1170 parse_normalized("all:(all:all)"),
1171 );
1172 }
1173
1174 #[test]
1175 fn test_parse_whitespace() {
1176 let ascii_whitespaces: String = ('\x00'..='\x7f')
1177 .filter(char::is_ascii_whitespace)
1178 .collect();
1179 assert_eq!(
1180 parse_normalized(&format!("{ascii_whitespaces}all()")),
1181 parse_normalized("all()"),
1182 );
1183 }
1184
1185 #[test]
1186 fn test_parse_identifier() {
1187 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1189 assert_eq!(
1191 parse_into_kind("foo_bar/baz"),
1192 Ok(ExpressionKind::Identifier("foo_bar/baz"))
1193 );
1194
1195 assert_eq!(
1197 parse_into_kind("foo.bar-v1+7"),
1198 Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1199 );
1200 assert_eq!(
1201 parse_normalized("foo.bar-v1+7-"),
1202 parse_normalized("(foo.bar-v1+7)-")
1203 );
1204 assert_eq!(
1206 parse_into_kind(".foo"),
1207 Err(RevsetParseErrorKind::SyntaxError)
1208 );
1209 assert_eq!(
1210 parse_into_kind("foo."),
1211 Err(RevsetParseErrorKind::SyntaxError)
1212 );
1213 assert_eq!(
1215 parse_into_kind("foo.+bar"),
1216 Err(RevsetParseErrorKind::SyntaxError)
1217 );
1218 assert_eq!(
1219 parse_into_kind("foo--bar"),
1220 Err(RevsetParseErrorKind::SyntaxError)
1221 );
1222 assert_eq!(
1223 parse_into_kind("foo+-bar"),
1224 Err(RevsetParseErrorKind::SyntaxError)
1225 );
1226
1227 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1229
1230 assert_eq!(
1232 parse_into_kind("柔術+jj"),
1233 Ok(ExpressionKind::Identifier("柔術+jj"))
1234 );
1235 }
1236
1237 #[test]
1238 fn test_parse_string_literal() {
1239 assert_eq!(
1241 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1242 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1243 );
1244
1245 assert_eq!(
1247 parse_into_kind(r#" "\y" "#),
1248 Err(RevsetParseErrorKind::SyntaxError)
1249 );
1250
1251 assert_eq!(
1253 parse_into_kind(r#" '' "#),
1254 Ok(ExpressionKind::String("".to_owned()))
1255 );
1256 assert_eq!(
1257 parse_into_kind(r#" 'a\n' "#),
1258 Ok(ExpressionKind::String(r"a\n".to_owned()))
1259 );
1260 assert_eq!(
1261 parse_into_kind(r#" '\' "#),
1262 Ok(ExpressionKind::String(r"\".to_owned()))
1263 );
1264 assert_eq!(
1265 parse_into_kind(r#" '"' "#),
1266 Ok(ExpressionKind::String(r#"""#.to_owned()))
1267 );
1268
1269 assert_eq!(
1271 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1272 Ok(ExpressionKind::String("aeiou".to_owned()))
1273 );
1274 assert_eq!(
1275 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1276 Ok(ExpressionKind::String("àèìðù".to_owned()))
1277 );
1278 assert_eq!(
1279 parse_into_kind(r#""\x""#),
1280 Err(RevsetParseErrorKind::SyntaxError)
1281 );
1282 assert_eq!(
1283 parse_into_kind(r#""\xf""#),
1284 Err(RevsetParseErrorKind::SyntaxError)
1285 );
1286 assert_eq!(
1287 parse_into_kind(r#""\xgg""#),
1288 Err(RevsetParseErrorKind::SyntaxError)
1289 );
1290 }
1291
1292 #[test]
1293 fn test_parse_string_pattern() {
1294 assert_eq!(
1295 parse_into_kind(r#"(substring:"foo")"#),
1296 Ok(ExpressionKind::StringPattern {
1297 kind: "substring",
1298 value: "foo".to_owned()
1299 })
1300 );
1301 assert_eq!(
1302 parse_into_kind(r#"("exact:foo")"#),
1303 Ok(ExpressionKind::String("exact:foo".to_owned()))
1304 );
1305 assert_eq!(
1306 parse_normalized(r#"(exact:"foo" )"#),
1307 parse_normalized(r#"(exact:"foo")"#),
1308 );
1309 assert_eq!(
1310 parse_into_kind(r#"(exact:'\')"#),
1311 Ok(ExpressionKind::StringPattern {
1312 kind: "exact",
1313 value: r"\".to_owned()
1314 })
1315 );
1316 assert_matches!(
1317 parse_into_kind(r#"(exact:("foo" ))"#),
1318 Err(RevsetParseErrorKind::NotInfixOperator { .. })
1319 );
1320 }
1321
1322 #[test]
1323 fn test_parse_symbol_explicitly() {
1324 assert_matches!(parse_symbol("").as_deref(), Err(_));
1325 assert_matches!(parse_symbol("''").as_deref(), Err(_));
1328
1329 assert_matches!(parse_symbol("foo.bar").as_deref(), Ok("foo.bar"));
1330 assert_matches!(parse_symbol("foo@bar").as_deref(), Err(_));
1331 assert_matches!(parse_symbol("foo bar").as_deref(), Err(_));
1332
1333 assert_matches!(parse_symbol("'foo bar'").as_deref(), Ok("foo bar"));
1334 assert_matches!(parse_symbol(r#""foo\tbar""#).as_deref(), Ok("foo\tbar"));
1335
1336 assert_matches!(parse_symbol(" foo").as_deref(), Err(_));
1338 assert_matches!(parse_symbol("foo ").as_deref(), Err(_));
1339
1340 assert_matches!(parse_symbol("(foo)").as_deref(), Err(_));
1343 }
1344
1345 #[test]
1346 fn parse_at_workspace_and_remote_symbol() {
1347 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1349 assert_eq!(
1350 parse_into_kind("main@"),
1351 Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1352 );
1353 assert_eq!(
1354 parse_into_kind("main@origin"),
1355 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1356 name: "main".into(),
1357 remote: "origin".into()
1358 }))
1359 );
1360
1361 assert_eq!(
1363 parse_into_kind(r#""foo bar"@"#),
1364 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1365 );
1366 assert_eq!(
1367 parse_into_kind(r#""foo bar"@origin"#),
1368 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1369 name: "foo bar".into(),
1370 remote: "origin".into()
1371 }))
1372 );
1373 assert_eq!(
1374 parse_into_kind(r#"main@"foo bar""#),
1375 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1376 name: "main".into(),
1377 remote: "foo bar".into()
1378 }))
1379 );
1380 assert_eq!(
1381 parse_into_kind(r#"'foo bar'@'bar baz'"#),
1382 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1383 name: "foo bar".into(),
1384 remote: "bar baz".into()
1385 }))
1386 );
1387
1388 assert_eq!(
1390 parse_into_kind(r#""@""#),
1391 Ok(ExpressionKind::String("@".to_owned()))
1392 );
1393 assert_eq!(
1394 parse_into_kind(r#""main@""#),
1395 Ok(ExpressionKind::String("main@".to_owned()))
1396 );
1397 assert_eq!(
1398 parse_into_kind(r#""main@origin""#),
1399 Ok(ExpressionKind::String("main@origin".to_owned()))
1400 );
1401
1402 assert_eq!(
1404 parse_into_kind("柔術@"),
1405 Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1406 );
1407 assert_eq!(
1408 parse_into_kind("柔@術"),
1409 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1410 name: "柔".into(),
1411 remote: "術".into()
1412 }))
1413 );
1414 }
1415
1416 #[test]
1417 fn test_parse_revset_alias_symbol_decl() {
1418 let mut aliases_map = RevsetAliasesMap::new();
1419 assert!(aliases_map.insert("@", "none()").is_err());
1421 assert!(aliases_map.insert("a@", "none()").is_err());
1422 assert!(aliases_map.insert("a@b", "none()").is_err());
1423 assert!(aliases_map.insert("柔術", "none()").is_err());
1426 }
1427
1428 #[test]
1429 fn test_parse_revset_alias_func_decl() {
1430 let mut aliases_map = RevsetAliasesMap::new();
1431 assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err());
1432 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1433 aliases_map
1434 .insert("func(a, b)", r#""is function 2""#)
1435 .unwrap();
1436 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1437 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1438
1439 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1440 assert_eq!(id, AliasId::Function("func", &[]));
1441 assert!(params.is_empty());
1442 assert_eq!(defn, r#""is function 0""#);
1443
1444 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1445 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1446 assert_eq!(params, ["b"]);
1447 assert_eq!(defn, r#""is function b""#);
1448
1449 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1450 assert_eq!(
1451 id,
1452 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1453 );
1454 assert_eq!(params, ["a", "b"]);
1455 assert_eq!(defn, r#""is function 2""#);
1456
1457 assert!(aliases_map.get_function("func", 3).is_none());
1458 }
1459
1460 #[test]
1461 fn test_parse_revset_alias_formal_parameter() {
1462 let mut aliases_map = RevsetAliasesMap::new();
1463 assert!(aliases_map.insert("f(@)", "none()").is_err());
1465 assert!(aliases_map.insert("f(a@)", "none()").is_err());
1466 assert!(aliases_map.insert("f(a@b)", "none()").is_err());
1467 assert!(aliases_map.insert("f(,)", "none()").is_err());
1469 assert!(aliases_map.insert("g(a,)", "none()").is_ok());
1471 assert!(aliases_map.insert("h(a , )", "none()").is_ok());
1472 assert!(aliases_map.insert("i(,a)", "none()").is_err());
1473 assert!(aliases_map.insert("j(a,,)", "none()").is_err());
1474 assert!(aliases_map.insert("k(a , , )", "none()").is_err());
1475 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
1476 assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
1477 }
1478
1479 #[test]
1480 fn test_parse_revset_compat_operator() {
1481 assert_eq!(
1482 parse_into_kind(":foo"),
1483 Err(RevsetParseErrorKind::NotPrefixOperator {
1484 op: ":".to_owned(),
1485 similar_op: "::".to_owned(),
1486 description: "ancestors".to_owned(),
1487 })
1488 );
1489 assert_eq!(
1490 parse_into_kind("foo^"),
1491 Err(RevsetParseErrorKind::NotPostfixOperator {
1492 op: "^".to_owned(),
1493 similar_op: "-".to_owned(),
1494 description: "parents".to_owned(),
1495 })
1496 );
1497 assert_eq!(
1498 parse_into_kind("foo + bar"),
1499 Err(RevsetParseErrorKind::NotInfixOperator {
1500 op: "+".to_owned(),
1501 similar_op: "|".to_owned(),
1502 description: "union".to_owned(),
1503 })
1504 );
1505 assert_eq!(
1506 parse_into_kind("foo - bar"),
1507 Err(RevsetParseErrorKind::NotInfixOperator {
1508 op: "-".to_owned(),
1509 similar_op: "~".to_owned(),
1510 description: "difference".to_owned(),
1511 })
1512 );
1513 }
1514
1515 #[test]
1516 fn test_parse_revset_operator_combinations() {
1517 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1519 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1521 assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y"));
1523 assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)"));
1524 assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)"));
1525 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1526 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1527 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1528 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1529 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1530 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1531 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1532 assert_eq!(
1534 parse_into_kind("::foo::"),
1535 Err(RevsetParseErrorKind::SyntaxError)
1536 );
1537 assert_eq!(
1538 parse_into_kind(":::foo"),
1539 Err(RevsetParseErrorKind::SyntaxError)
1540 );
1541 assert_eq!(
1542 parse_into_kind("::::foo"),
1543 Err(RevsetParseErrorKind::SyntaxError)
1544 );
1545 assert_eq!(
1546 parse_into_kind("foo:::"),
1547 Err(RevsetParseErrorKind::SyntaxError)
1548 );
1549 assert_eq!(
1550 parse_into_kind("foo::::"),
1551 Err(RevsetParseErrorKind::SyntaxError)
1552 );
1553 assert_eq!(
1554 parse_into_kind("foo:::bar"),
1555 Err(RevsetParseErrorKind::SyntaxError)
1556 );
1557 assert_eq!(
1558 parse_into_kind("foo::::bar"),
1559 Err(RevsetParseErrorKind::SyntaxError)
1560 );
1561 assert_eq!(
1562 parse_into_kind("::foo::bar"),
1563 Err(RevsetParseErrorKind::SyntaxError)
1564 );
1565 assert_eq!(
1566 parse_into_kind("foo::bar::"),
1567 Err(RevsetParseErrorKind::SyntaxError)
1568 );
1569 assert_eq!(
1570 parse_into_kind("::::"),
1571 Err(RevsetParseErrorKind::SyntaxError)
1572 );
1573 assert_eq!(
1574 parse_into_kind("....foo"),
1575 Err(RevsetParseErrorKind::SyntaxError)
1576 );
1577 assert_eq!(
1578 parse_into_kind("foo...."),
1579 Err(RevsetParseErrorKind::SyntaxError)
1580 );
1581 assert_eq!(
1582 parse_into_kind("foo.....bar"),
1583 Err(RevsetParseErrorKind::SyntaxError)
1584 );
1585 assert_eq!(
1586 parse_into_kind("..foo..bar"),
1587 Err(RevsetParseErrorKind::SyntaxError)
1588 );
1589 assert_eq!(
1590 parse_into_kind("foo..bar.."),
1591 Err(RevsetParseErrorKind::SyntaxError)
1592 );
1593 assert_eq!(
1594 parse_into_kind("...."),
1595 Err(RevsetParseErrorKind::SyntaxError)
1596 );
1597 assert_eq!(
1598 parse_into_kind("::.."),
1599 Err(RevsetParseErrorKind::SyntaxError)
1600 );
1601 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1604 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1605 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1606 assert_eq!(
1607 parse_into_kind("::-"),
1608 Err(RevsetParseErrorKind::SyntaxError)
1609 );
1610 assert_eq!(
1611 parse_into_kind("..+"),
1612 Err(RevsetParseErrorKind::SyntaxError)
1613 );
1614 }
1615
1616 #[test]
1617 fn test_parse_revset_function() {
1618 assert_matches!(
1619 parse_into_kind("parents(foo)"),
1620 Ok(ExpressionKind::FunctionCall(_))
1621 );
1622 assert_eq!(
1623 parse_normalized("parents((foo))"),
1624 parse_normalized("parents(foo)"),
1625 );
1626 assert_eq!(
1627 parse_into_kind("parents(foo"),
1628 Err(RevsetParseErrorKind::SyntaxError)
1629 );
1630 }
1631
1632 #[test]
1633 fn test_expand_symbol_alias() {
1634 assert_eq!(
1635 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1636 parse_normalized("(a&b)|c")
1637 );
1638 assert_eq!(
1639 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1640 parse_normalized("(a|b)::heads(a|b)")
1641 );
1642
1643 assert_eq!(
1645 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1646 parse_normalized("a&(b|c)")
1647 );
1648
1649 assert_eq!(
1651 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1652 parse_normalized("a|'A'|'A'")
1653 );
1654
1655 assert_eq!(
1657 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1658 parse_normalized("author(exact:A)")
1659 );
1660
1661 assert_eq!(
1663 with_aliases([("A", "a")]).parse_normalized("A@"),
1664 parse_normalized("A@")
1665 );
1666 assert_eq!(
1667 with_aliases([("A", "a")]).parse_normalized("A@b"),
1668 parse_normalized("A@b")
1669 );
1670 assert_eq!(
1671 with_aliases([("B", "b")]).parse_normalized("a@B"),
1672 parse_normalized("a@B")
1673 );
1674
1675 assert_eq!(
1677 with_aliases([("all", "ALL")]).parse_normalized("all:all"),
1678 parse_normalized("all:ALL")
1679 );
1680
1681 assert_eq!(
1683 with_aliases([("A", "all:a")]).parse_normalized("A"),
1684 parse_normalized("all:a")
1685 );
1686
1687 assert_eq!(
1689 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1690 parse_normalized("b|c")
1691 );
1692
1693 assert_eq!(
1695 *with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1696 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1697 );
1698 assert_eq!(
1699 *with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1700 .parse("A")
1701 .unwrap_err()
1702 .kind,
1703 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1704 );
1705
1706 assert_eq!(
1708 *with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1709 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1710 );
1711 }
1712
1713 #[test]
1714 fn test_expand_function_alias() {
1715 assert_eq!(
1716 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1717 parse_normalized("a")
1718 );
1719 assert_eq!(
1720 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1721 parse_normalized("a")
1722 );
1723 assert_eq!(
1724 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"),
1725 parse_normalized("a|b")
1726 );
1727
1728 assert_eq!(
1730 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1731 parse_normalized("a|b")
1732 );
1733
1734 assert_eq!(
1736 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1737 parse_normalized("(a::y)|(b::x)")
1738 );
1739 assert_eq!(
1741 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1742 parse_normalized("(x|a)&y")
1743 );
1744 assert_eq!(
1746 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1747 parse_normalized("(x|(x|a))&y")
1748 );
1749
1750 assert_eq!(
1752 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1753 parse_normalized("a|x")
1754 );
1755
1756 assert_eq!(
1758 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1759 parse_normalized("a|x")
1760 );
1761
1762 assert_eq!(
1764 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1765 parse_normalized("a|'x'")
1766 );
1767
1768 assert_eq!(
1770 with_aliases([("F(x)", "all:x")]).parse_normalized("F(a|b)"),
1771 parse_normalized("all:(a|b)")
1772 );
1773
1774 assert_eq!(
1776 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1777 parse_normalized("a")
1778 );
1779
1780 assert_eq!(
1782 *with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1783 RevsetParseErrorKind::InvalidFunctionArguments {
1784 name: "F".to_owned(),
1785 message: "Expected 0 arguments".to_owned()
1786 }
1787 );
1788 assert_eq!(
1789 *with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1790 RevsetParseErrorKind::InvalidFunctionArguments {
1791 name: "F".to_owned(),
1792 message: "Expected 1 arguments".to_owned()
1793 }
1794 );
1795 assert_eq!(
1796 *with_aliases([("F(x,y)", "x|y")])
1797 .parse("F(a,b,c)")
1798 .unwrap_err()
1799 .kind,
1800 RevsetParseErrorKind::InvalidFunctionArguments {
1801 name: "F".to_owned(),
1802 message: "Expected 2 arguments".to_owned()
1803 }
1804 );
1805 assert_eq!(
1806 *with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1807 .parse("F()")
1808 .unwrap_err()
1809 .kind,
1810 RevsetParseErrorKind::InvalidFunctionArguments {
1811 name: "F".to_owned(),
1812 message: "Expected 1 to 2 arguments".to_owned()
1813 }
1814 );
1815 assert_eq!(
1816 *with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1817 .parse("F(a)")
1818 .unwrap_err()
1819 .kind,
1820 RevsetParseErrorKind::InvalidFunctionArguments {
1821 name: "F".to_owned(),
1822 message: "Expected 0, 2 arguments".to_owned()
1823 }
1824 );
1825
1826 assert_eq!(
1828 *with_aliases([("F(x)", "x")])
1829 .parse("F(x=y)")
1830 .unwrap_err()
1831 .kind,
1832 RevsetParseErrorKind::InvalidFunctionArguments {
1833 name: "F".to_owned(),
1834 message: "Unexpected keyword arguments".to_owned()
1835 }
1836 );
1837
1838 assert_eq!(
1840 *with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1841 .parse("F(a)")
1842 .unwrap_err()
1843 .kind,
1844 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1845 );
1846 assert_eq!(
1847 *with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1848 .parse("F(a)")
1849 .unwrap_err()
1850 .kind,
1851 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1852 );
1853 }
1854
1855 #[test]
1856 fn test_expand_with_locals() {
1857 assert_eq!(
1859 with_aliases([("A", "symbol")])
1860 .set_local("A", "local")
1861 .parse_normalized("A"),
1862 parse_normalized("local")
1863 );
1864
1865 assert_eq!(
1867 with_aliases([("B", "A"), ("F(x)", "x&A")])
1868 .set_local("A", "a")
1869 .parse_normalized("A|B|F(A)"),
1870 parse_normalized("a|A|(a&A)")
1871 );
1872 }
1873}