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_string_pattern<'a>(
761 type_name: &str,
762 node: &'a ExpressionNode<'_>,
763) -> Result<(&'a str, Option<&'a str>), RevsetParseError> {
764 catch_aliases_no_diagnostics(node, |node| match &node.kind {
765 ExpressionKind::Identifier(name) => Ok((*name, None)),
766 ExpressionKind::String(name) => Ok((name, None)),
767 ExpressionKind::StringPattern { kind, value } => Ok((value, Some(*kind))),
768 _ => Err(RevsetParseError::expression(
769 format!("Expected {type_name}"),
770 node.span,
771 )),
772 })
773}
774
775pub fn expect_literal<T: FromStr>(
776 type_name: &str,
777 node: &ExpressionNode,
778) -> Result<T, RevsetParseError> {
779 catch_aliases_no_diagnostics(node, |node| {
780 let value = expect_string_literal(type_name, node)?;
781 value
782 .parse()
783 .map_err(|_| RevsetParseError::expression(format!("Expected {type_name}"), node.span))
784 })
785}
786
787pub(super) fn expect_string_literal<'a>(
788 type_name: &str,
789 node: &'a ExpressionNode<'_>,
790) -> Result<&'a str, RevsetParseError> {
791 catch_aliases_no_diagnostics(node, |node| match &node.kind {
792 ExpressionKind::Identifier(name) => Ok(*name),
793 ExpressionKind::String(name) => Ok(name),
794 _ => Err(RevsetParseError::expression(
795 format!("Expected {type_name}"),
796 node.span,
797 )),
798 })
799}
800
801pub(super) fn catch_aliases<'a, 'i, T>(
804 diagnostics: &mut RevsetDiagnostics,
805 node: &'a ExpressionNode<'i>,
806 f: impl FnOnce(&mut RevsetDiagnostics, &'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
807) -> Result<T, RevsetParseError> {
808 let (node, stack) = skip_aliases(node);
809 if stack.is_empty() {
810 f(diagnostics, node)
811 } else {
812 let mut inner_diagnostics = RevsetDiagnostics::new();
813 let result = f(&mut inner_diagnostics, node);
814 diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
815 result.map_err(|err| attach_aliases_err(err, &stack))
816 }
817}
818
819fn catch_aliases_no_diagnostics<'a, 'i, T>(
820 node: &'a ExpressionNode<'i>,
821 f: impl FnOnce(&'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
822) -> Result<T, RevsetParseError> {
823 let (node, stack) = skip_aliases(node);
824 f(node).map_err(|err| attach_aliases_err(err, &stack))
825}
826
827fn skip_aliases<'a, 'i>(
828 mut node: &'a ExpressionNode<'i>,
829) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
830 let mut stack = Vec::new();
831 while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
832 stack.push((*id, node.span));
833 node = subst;
834 }
835 (node, stack)
836}
837
838fn attach_aliases_err(
839 err: RevsetParseError,
840 stack: &[(AliasId<'_>, pest::Span<'_>)],
841) -> RevsetParseError {
842 stack
843 .iter()
844 .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
845}
846
847#[cfg(test)]
848mod tests {
849 use std::collections::HashMap;
850
851 use assert_matches::assert_matches;
852
853 use super::*;
854 use crate::dsl_util::KeywordArgument;
855
856 #[derive(Debug)]
857 struct WithRevsetAliasesMap<'i> {
858 aliases_map: RevsetAliasesMap,
859 locals: HashMap<&'i str, ExpressionNode<'i>>,
860 }
861
862 impl<'i> WithRevsetAliasesMap<'i> {
863 fn set_local(mut self, name: &'i str, value: &'i str) -> Self {
864 self.locals.insert(name, parse_program(value).unwrap());
865 self
866 }
867
868 fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
869 let node = parse_program(text)?;
870 dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals)
871 }
872
873 fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> {
874 normalize_tree(self.parse(text).unwrap())
875 }
876 }
877
878 fn with_aliases<'i>(
879 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
880 ) -> WithRevsetAliasesMap<'i> {
881 let mut aliases_map = RevsetAliasesMap::new();
882 for (decl, defn) in aliases {
883 aliases_map.insert(decl, defn).unwrap();
884 }
885 WithRevsetAliasesMap {
886 aliases_map,
887 locals: HashMap::new(),
888 }
889 }
890
891 fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
892 parse_program(text)
893 .map(|node| node.kind)
894 .map_err(|err| *err.kind)
895 }
896
897 fn parse_normalized(text: &str) -> ExpressionNode<'_> {
898 normalize_tree(parse_program(text).unwrap())
899 }
900
901 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
903 fn empty_span() -> pest::Span<'static> {
904 pest::Span::new("", 0, 0).unwrap()
905 }
906
907 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
908 nodes.into_iter().map(normalize_tree).collect()
909 }
910
911 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
912 FunctionCallNode {
913 name: function.name,
914 name_span: empty_span(),
915 args: normalize_list(function.args),
916 keyword_args: function
917 .keyword_args
918 .into_iter()
919 .map(|arg| KeywordArgument {
920 name: arg.name,
921 name_span: empty_span(),
922 value: normalize_tree(arg.value),
923 })
924 .collect(),
925 args_span: empty_span(),
926 }
927 }
928
929 let normalized_kind = match node.kind {
930 ExpressionKind::Identifier(_)
931 | ExpressionKind::String(_)
932 | ExpressionKind::StringPattern { .. }
933 | ExpressionKind::RemoteSymbol(_)
934 | ExpressionKind::AtWorkspace(_)
935 | ExpressionKind::AtCurrentWorkspace
936 | ExpressionKind::DagRangeAll
937 | ExpressionKind::RangeAll => node.kind,
938 ExpressionKind::Unary(op, arg) => {
939 let arg = Box::new(normalize_tree(*arg));
940 ExpressionKind::Unary(op, arg)
941 }
942 ExpressionKind::Binary(op, lhs, rhs) => {
943 let lhs = Box::new(normalize_tree(*lhs));
944 let rhs = Box::new(normalize_tree(*rhs));
945 ExpressionKind::Binary(op, lhs, rhs)
946 }
947 ExpressionKind::UnionAll(nodes) => {
948 let nodes = normalize_list(nodes);
949 ExpressionKind::UnionAll(nodes)
950 }
951 ExpressionKind::FunctionCall(function) => {
952 let function = Box::new(normalize_function_call(*function));
953 ExpressionKind::FunctionCall(function)
954 }
955 ExpressionKind::Modifier(modifier) => {
956 let modifier = Box::new(ModifierNode {
957 name: modifier.name,
958 name_span: empty_span(),
959 body: normalize_tree(modifier.body),
960 });
961 ExpressionKind::Modifier(modifier)
962 }
963 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
964 };
965 ExpressionNode {
966 kind: normalized_kind,
967 span: empty_span(),
968 }
969 }
970
971 #[test]
972 fn test_parse_tree_eq() {
973 assert_eq!(
974 parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
975 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
976 );
977 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
978 }
979
980 #[test]
981 fn test_parse_revset() {
982 assert_eq!(
984 parse_into_kind("\"foo\""),
985 Ok(ExpressionKind::String("foo".to_owned()))
986 );
987 assert_eq!(
988 parse_into_kind("'foo'"),
989 Ok(ExpressionKind::String("foo".to_owned()))
990 );
991 assert_matches!(
993 parse_into_kind("foo-"),
994 Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
995 );
996 assert_matches!(
998 parse_into_kind("foo+"),
999 Ok(ExpressionKind::Unary(UnaryOp::Children, _))
1000 );
1001 assert_matches!(
1003 parse_into_kind("::foo"),
1004 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
1005 );
1006 assert_matches!(
1008 parse_into_kind("foo::"),
1009 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1010 );
1011 assert_matches!(
1013 parse_into_kind("foo::bar"),
1014 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1015 );
1016 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
1018 assert_matches!(
1020 parse_into_kind("..foo"),
1021 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
1022 );
1023 assert_matches!(
1024 parse_into_kind("foo.."),
1025 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
1026 );
1027 assert_matches!(
1028 parse_into_kind("foo..bar"),
1029 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
1030 );
1031 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
1033 assert_matches!(
1035 parse_into_kind("~ foo"),
1036 Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1037 );
1038 assert_eq!(
1039 parse_normalized("~ ~~ foo"),
1040 parse_normalized("~(~(~(foo)))"),
1041 );
1042 assert_matches!(
1044 parse_into_kind("foo & bar"),
1045 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1046 );
1047 assert_matches!(
1049 parse_into_kind("foo | bar"),
1050 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1051 );
1052 assert_matches!(
1053 parse_into_kind("foo | bar | baz"),
1054 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1055 );
1056 assert_matches!(
1058 parse_into_kind("foo ~ bar"),
1059 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1060 );
1061 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1063 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1065 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1066 assert_eq!(
1068 parse_into_kind(" :: foo "),
1069 Err(RevsetParseErrorKind::SyntaxError)
1070 );
1071 assert_eq!(
1073 parse_into_kind("foo | -"),
1074 Err(RevsetParseErrorKind::SyntaxError)
1075 );
1076 assert_eq!(
1078 parse_normalized(
1079 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ",
1080 ),
1081 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1082 );
1083 assert_eq!(
1085 parse_normalized("remote_bookmarks( remote = foo )"),
1086 parse_normalized("remote_bookmarks(remote=foo)"),
1087 );
1088
1089 assert!(parse_into_kind("bookmarks(,)").is_err());
1091 assert_eq!(
1093 parse_normalized("bookmarks(a,)"),
1094 parse_normalized("bookmarks(a)")
1095 );
1096 assert_eq!(
1097 parse_normalized("bookmarks(a , )"),
1098 parse_normalized("bookmarks(a)")
1099 );
1100 assert!(parse_into_kind("bookmarks(,a)").is_err());
1101 assert!(parse_into_kind("bookmarks(a,,)").is_err());
1102 assert!(parse_into_kind("bookmarks(a , , )").is_err());
1103 assert_eq!(
1104 parse_normalized("file(a,b,)"),
1105 parse_normalized("file(a, b)")
1106 );
1107 assert!(parse_into_kind("file(a,,b)").is_err());
1108 assert_eq!(
1109 parse_normalized("remote_bookmarks(a,remote=b , )"),
1110 parse_normalized("remote_bookmarks(a, remote=b)"),
1111 );
1112 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1113 }
1114
1115 #[test]
1116 fn test_parse_revset_with_modifier() {
1117 assert_eq!(
1119 parse_into_kind("all:"),
1120 Err(RevsetParseErrorKind::SyntaxError)
1121 );
1122 assert_matches!(
1123 parse_into_kind("all:foo"),
1124 Ok(ExpressionKind::Modifier(modifier)) if modifier.name == "all"
1125 );
1126 assert_matches!(
1127 parse_into_kind("all::"),
1128 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1129 );
1130 assert_matches!(
1131 parse_into_kind("all::foo"),
1132 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1133 );
1134
1135 assert_eq!(
1137 parse_into_kind("all:::"),
1138 Err(RevsetParseErrorKind::SyntaxError)
1139 );
1140 assert_eq!(
1141 parse_into_kind("all:::foo"),
1142 Err(RevsetParseErrorKind::SyntaxError)
1143 );
1144
1145 assert_eq!(parse_normalized("all:(foo)"), parse_normalized("all:foo"));
1146 assert_eq!(
1147 parse_normalized("all:all::foo"),
1148 parse_normalized("all:(all::foo)"),
1149 );
1150 assert_eq!(
1151 parse_normalized("all:all | foo"),
1152 parse_normalized("all:(all | foo)"),
1153 );
1154
1155 assert_eq!(
1156 parse_normalized("all: ::foo"),
1157 parse_normalized("all:(::foo)"),
1158 );
1159 assert_eq!(parse_normalized(" all: foo"), parse_normalized("all:foo"));
1160 assert_eq!(
1161 parse_into_kind("(all:foo)"),
1162 Ok(ExpressionKind::StringPattern {
1163 kind: "all",
1164 value: "foo".to_owned()
1165 })
1166 );
1167 assert_matches!(
1168 parse_into_kind("all :foo"),
1169 Err(RevsetParseErrorKind::SyntaxError)
1170 );
1171 assert_eq!(
1172 parse_normalized("all:all:all"),
1173 parse_normalized("all:(all:all)"),
1174 );
1175 }
1176
1177 #[test]
1178 fn test_parse_whitespace() {
1179 let ascii_whitespaces: String = ('\x00'..='\x7f')
1180 .filter(char::is_ascii_whitespace)
1181 .collect();
1182 assert_eq!(
1183 parse_normalized(&format!("{ascii_whitespaces}all()")),
1184 parse_normalized("all()"),
1185 );
1186 }
1187
1188 #[test]
1189 fn test_parse_identifier() {
1190 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1192 assert_eq!(
1194 parse_into_kind("foo_bar/baz"),
1195 Ok(ExpressionKind::Identifier("foo_bar/baz"))
1196 );
1197
1198 assert_eq!(
1200 parse_into_kind("foo.bar-v1+7"),
1201 Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1202 );
1203 assert_eq!(
1204 parse_normalized("foo.bar-v1+7-"),
1205 parse_normalized("(foo.bar-v1+7)-")
1206 );
1207 assert_eq!(
1209 parse_into_kind(".foo"),
1210 Err(RevsetParseErrorKind::SyntaxError)
1211 );
1212 assert_eq!(
1213 parse_into_kind("foo."),
1214 Err(RevsetParseErrorKind::SyntaxError)
1215 );
1216 assert_eq!(
1218 parse_into_kind("foo.+bar"),
1219 Err(RevsetParseErrorKind::SyntaxError)
1220 );
1221 assert_eq!(
1222 parse_into_kind("foo--bar"),
1223 Err(RevsetParseErrorKind::SyntaxError)
1224 );
1225 assert_eq!(
1226 parse_into_kind("foo+-bar"),
1227 Err(RevsetParseErrorKind::SyntaxError)
1228 );
1229
1230 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1232
1233 assert_eq!(
1235 parse_into_kind("柔術+jj"),
1236 Ok(ExpressionKind::Identifier("柔術+jj"))
1237 );
1238 }
1239
1240 #[test]
1241 fn test_parse_string_literal() {
1242 assert_eq!(
1244 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1245 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1246 );
1247
1248 assert_eq!(
1250 parse_into_kind(r#" "\y" "#),
1251 Err(RevsetParseErrorKind::SyntaxError)
1252 );
1253
1254 assert_eq!(
1256 parse_into_kind(r#" '' "#),
1257 Ok(ExpressionKind::String("".to_owned()))
1258 );
1259 assert_eq!(
1260 parse_into_kind(r#" 'a\n' "#),
1261 Ok(ExpressionKind::String(r"a\n".to_owned()))
1262 );
1263 assert_eq!(
1264 parse_into_kind(r#" '\' "#),
1265 Ok(ExpressionKind::String(r"\".to_owned()))
1266 );
1267 assert_eq!(
1268 parse_into_kind(r#" '"' "#),
1269 Ok(ExpressionKind::String(r#"""#.to_owned()))
1270 );
1271
1272 assert_eq!(
1274 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1275 Ok(ExpressionKind::String("aeiou".to_owned()))
1276 );
1277 assert_eq!(
1278 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1279 Ok(ExpressionKind::String("àèìðù".to_owned()))
1280 );
1281 assert_eq!(
1282 parse_into_kind(r#""\x""#),
1283 Err(RevsetParseErrorKind::SyntaxError)
1284 );
1285 assert_eq!(
1286 parse_into_kind(r#""\xf""#),
1287 Err(RevsetParseErrorKind::SyntaxError)
1288 );
1289 assert_eq!(
1290 parse_into_kind(r#""\xgg""#),
1291 Err(RevsetParseErrorKind::SyntaxError)
1292 );
1293 }
1294
1295 #[test]
1296 fn test_parse_string_pattern() {
1297 assert_eq!(
1298 parse_into_kind(r#"(substring:"foo")"#),
1299 Ok(ExpressionKind::StringPattern {
1300 kind: "substring",
1301 value: "foo".to_owned()
1302 })
1303 );
1304 assert_eq!(
1305 parse_into_kind(r#"("exact:foo")"#),
1306 Ok(ExpressionKind::String("exact:foo".to_owned()))
1307 );
1308 assert_eq!(
1309 parse_normalized(r#"(exact:"foo" )"#),
1310 parse_normalized(r#"(exact:"foo")"#),
1311 );
1312 assert_eq!(
1313 parse_into_kind(r#"(exact:'\')"#),
1314 Ok(ExpressionKind::StringPattern {
1315 kind: "exact",
1316 value: r"\".to_owned()
1317 })
1318 );
1319 assert_matches!(
1320 parse_into_kind(r#"(exact:("foo" ))"#),
1321 Err(RevsetParseErrorKind::NotInfixOperator { .. })
1322 );
1323 }
1324
1325 #[test]
1326 fn test_parse_symbol_explicitly() {
1327 assert_matches!(parse_symbol("").as_deref(), Err(_));
1328 assert_matches!(parse_symbol("''").as_deref(), Err(_));
1331
1332 assert_matches!(parse_symbol("foo.bar").as_deref(), Ok("foo.bar"));
1333 assert_matches!(parse_symbol("foo@bar").as_deref(), Err(_));
1334 assert_matches!(parse_symbol("foo bar").as_deref(), Err(_));
1335
1336 assert_matches!(parse_symbol("'foo bar'").as_deref(), Ok("foo bar"));
1337 assert_matches!(parse_symbol(r#""foo\tbar""#).as_deref(), Ok("foo\tbar"));
1338
1339 assert_matches!(parse_symbol(" foo").as_deref(), Err(_));
1341 assert_matches!(parse_symbol("foo ").as_deref(), Err(_));
1342
1343 assert_matches!(parse_symbol("(foo)").as_deref(), Err(_));
1346 }
1347
1348 #[test]
1349 fn parse_at_workspace_and_remote_symbol() {
1350 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1352 assert_eq!(
1353 parse_into_kind("main@"),
1354 Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1355 );
1356 assert_eq!(
1357 parse_into_kind("main@origin"),
1358 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1359 name: "main".into(),
1360 remote: "origin".into()
1361 }))
1362 );
1363
1364 assert_eq!(
1366 parse_into_kind(r#""foo bar"@"#),
1367 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1368 );
1369 assert_eq!(
1370 parse_into_kind(r#""foo bar"@origin"#),
1371 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1372 name: "foo bar".into(),
1373 remote: "origin".into()
1374 }))
1375 );
1376 assert_eq!(
1377 parse_into_kind(r#"main@"foo bar""#),
1378 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1379 name: "main".into(),
1380 remote: "foo bar".into()
1381 }))
1382 );
1383 assert_eq!(
1384 parse_into_kind(r#"'foo bar'@'bar baz'"#),
1385 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1386 name: "foo bar".into(),
1387 remote: "bar baz".into()
1388 }))
1389 );
1390
1391 assert_eq!(
1393 parse_into_kind(r#""@""#),
1394 Ok(ExpressionKind::String("@".to_owned()))
1395 );
1396 assert_eq!(
1397 parse_into_kind(r#""main@""#),
1398 Ok(ExpressionKind::String("main@".to_owned()))
1399 );
1400 assert_eq!(
1401 parse_into_kind(r#""main@origin""#),
1402 Ok(ExpressionKind::String("main@origin".to_owned()))
1403 );
1404
1405 assert_eq!(
1407 parse_into_kind("柔術@"),
1408 Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1409 );
1410 assert_eq!(
1411 parse_into_kind("柔@術"),
1412 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1413 name: "柔".into(),
1414 remote: "術".into()
1415 }))
1416 );
1417 }
1418
1419 #[test]
1420 fn test_parse_revset_alias_symbol_decl() {
1421 let mut aliases_map = RevsetAliasesMap::new();
1422 assert!(aliases_map.insert("@", "none()").is_err());
1424 assert!(aliases_map.insert("a@", "none()").is_err());
1425 assert!(aliases_map.insert("a@b", "none()").is_err());
1426 assert!(aliases_map.insert("柔術", "none()").is_err());
1429 }
1430
1431 #[test]
1432 fn test_parse_revset_alias_func_decl() {
1433 let mut aliases_map = RevsetAliasesMap::new();
1434 assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err());
1435 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1436 aliases_map
1437 .insert("func(a, b)", r#""is function 2""#)
1438 .unwrap();
1439 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1440 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1441
1442 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1443 assert_eq!(id, AliasId::Function("func", &[]));
1444 assert!(params.is_empty());
1445 assert_eq!(defn, r#""is function 0""#);
1446
1447 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1448 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1449 assert_eq!(params, ["b"]);
1450 assert_eq!(defn, r#""is function b""#);
1451
1452 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1453 assert_eq!(
1454 id,
1455 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1456 );
1457 assert_eq!(params, ["a", "b"]);
1458 assert_eq!(defn, r#""is function 2""#);
1459
1460 assert!(aliases_map.get_function("func", 3).is_none());
1461 }
1462
1463 #[test]
1464 fn test_parse_revset_alias_formal_parameter() {
1465 let mut aliases_map = RevsetAliasesMap::new();
1466 assert!(aliases_map.insert("f(@)", "none()").is_err());
1468 assert!(aliases_map.insert("f(a@)", "none()").is_err());
1469 assert!(aliases_map.insert("f(a@b)", "none()").is_err());
1470 assert!(aliases_map.insert("f(,)", "none()").is_err());
1472 assert!(aliases_map.insert("g(a,)", "none()").is_ok());
1474 assert!(aliases_map.insert("h(a , )", "none()").is_ok());
1475 assert!(aliases_map.insert("i(,a)", "none()").is_err());
1476 assert!(aliases_map.insert("j(a,,)", "none()").is_err());
1477 assert!(aliases_map.insert("k(a , , )", "none()").is_err());
1478 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
1479 assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
1480 }
1481
1482 #[test]
1483 fn test_parse_revset_compat_operator() {
1484 assert_eq!(
1485 parse_into_kind(":foo"),
1486 Err(RevsetParseErrorKind::NotPrefixOperator {
1487 op: ":".to_owned(),
1488 similar_op: "::".to_owned(),
1489 description: "ancestors".to_owned(),
1490 })
1491 );
1492 assert_eq!(
1493 parse_into_kind("foo^"),
1494 Err(RevsetParseErrorKind::NotPostfixOperator {
1495 op: "^".to_owned(),
1496 similar_op: "-".to_owned(),
1497 description: "parents".to_owned(),
1498 })
1499 );
1500 assert_eq!(
1501 parse_into_kind("foo + bar"),
1502 Err(RevsetParseErrorKind::NotInfixOperator {
1503 op: "+".to_owned(),
1504 similar_op: "|".to_owned(),
1505 description: "union".to_owned(),
1506 })
1507 );
1508 assert_eq!(
1509 parse_into_kind("foo - bar"),
1510 Err(RevsetParseErrorKind::NotInfixOperator {
1511 op: "-".to_owned(),
1512 similar_op: "~".to_owned(),
1513 description: "difference".to_owned(),
1514 })
1515 );
1516 }
1517
1518 #[test]
1519 fn test_parse_revset_operator_combinations() {
1520 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1522 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1524 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"), parse_normalized("x~(~y)"));
1528 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1529 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1530 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1531 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1532 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1533 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1534 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1535 assert_eq!(
1537 parse_into_kind("::foo::"),
1538 Err(RevsetParseErrorKind::SyntaxError)
1539 );
1540 assert_eq!(
1541 parse_into_kind(":::foo"),
1542 Err(RevsetParseErrorKind::SyntaxError)
1543 );
1544 assert_eq!(
1545 parse_into_kind("::::foo"),
1546 Err(RevsetParseErrorKind::SyntaxError)
1547 );
1548 assert_eq!(
1549 parse_into_kind("foo:::"),
1550 Err(RevsetParseErrorKind::SyntaxError)
1551 );
1552 assert_eq!(
1553 parse_into_kind("foo::::"),
1554 Err(RevsetParseErrorKind::SyntaxError)
1555 );
1556 assert_eq!(
1557 parse_into_kind("foo:::bar"),
1558 Err(RevsetParseErrorKind::SyntaxError)
1559 );
1560 assert_eq!(
1561 parse_into_kind("foo::::bar"),
1562 Err(RevsetParseErrorKind::SyntaxError)
1563 );
1564 assert_eq!(
1565 parse_into_kind("::foo::bar"),
1566 Err(RevsetParseErrorKind::SyntaxError)
1567 );
1568 assert_eq!(
1569 parse_into_kind("foo::bar::"),
1570 Err(RevsetParseErrorKind::SyntaxError)
1571 );
1572 assert_eq!(
1573 parse_into_kind("::::"),
1574 Err(RevsetParseErrorKind::SyntaxError)
1575 );
1576 assert_eq!(
1577 parse_into_kind("....foo"),
1578 Err(RevsetParseErrorKind::SyntaxError)
1579 );
1580 assert_eq!(
1581 parse_into_kind("foo...."),
1582 Err(RevsetParseErrorKind::SyntaxError)
1583 );
1584 assert_eq!(
1585 parse_into_kind("foo.....bar"),
1586 Err(RevsetParseErrorKind::SyntaxError)
1587 );
1588 assert_eq!(
1589 parse_into_kind("..foo..bar"),
1590 Err(RevsetParseErrorKind::SyntaxError)
1591 );
1592 assert_eq!(
1593 parse_into_kind("foo..bar.."),
1594 Err(RevsetParseErrorKind::SyntaxError)
1595 );
1596 assert_eq!(
1597 parse_into_kind("...."),
1598 Err(RevsetParseErrorKind::SyntaxError)
1599 );
1600 assert_eq!(
1601 parse_into_kind("::.."),
1602 Err(RevsetParseErrorKind::SyntaxError)
1603 );
1604 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1607 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1608 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1609 assert_eq!(
1610 parse_into_kind("::-"),
1611 Err(RevsetParseErrorKind::SyntaxError)
1612 );
1613 assert_eq!(
1614 parse_into_kind("..+"),
1615 Err(RevsetParseErrorKind::SyntaxError)
1616 );
1617 }
1618
1619 #[test]
1620 fn test_parse_revset_function() {
1621 assert_matches!(
1622 parse_into_kind("parents(foo)"),
1623 Ok(ExpressionKind::FunctionCall(_))
1624 );
1625 assert_eq!(
1626 parse_normalized("parents((foo))"),
1627 parse_normalized("parents(foo)"),
1628 );
1629 assert_eq!(
1630 parse_into_kind("parents(foo"),
1631 Err(RevsetParseErrorKind::SyntaxError)
1632 );
1633 }
1634
1635 #[test]
1636 fn test_expand_symbol_alias() {
1637 assert_eq!(
1638 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1639 parse_normalized("(a&b)|c")
1640 );
1641 assert_eq!(
1642 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1643 parse_normalized("(a|b)::heads(a|b)")
1644 );
1645
1646 assert_eq!(
1648 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1649 parse_normalized("a&(b|c)")
1650 );
1651
1652 assert_eq!(
1654 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1655 parse_normalized("a|'A'|'A'")
1656 );
1657
1658 assert_eq!(
1660 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1661 parse_normalized("author(exact:A)")
1662 );
1663
1664 assert_eq!(
1666 with_aliases([("A", "a")]).parse_normalized("A@"),
1667 parse_normalized("A@")
1668 );
1669 assert_eq!(
1670 with_aliases([("A", "a")]).parse_normalized("A@b"),
1671 parse_normalized("A@b")
1672 );
1673 assert_eq!(
1674 with_aliases([("B", "b")]).parse_normalized("a@B"),
1675 parse_normalized("a@B")
1676 );
1677
1678 assert_eq!(
1680 with_aliases([("all", "ALL")]).parse_normalized("all:all"),
1681 parse_normalized("all:ALL")
1682 );
1683
1684 assert_eq!(
1686 with_aliases([("A", "all:a")]).parse_normalized("A"),
1687 parse_normalized("all:a")
1688 );
1689
1690 assert_eq!(
1692 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1693 parse_normalized("b|c")
1694 );
1695
1696 assert_eq!(
1698 *with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1699 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1700 );
1701 assert_eq!(
1702 *with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1703 .parse("A")
1704 .unwrap_err()
1705 .kind,
1706 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1707 );
1708
1709 assert_eq!(
1711 *with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1712 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1713 );
1714 }
1715
1716 #[test]
1717 fn test_expand_function_alias() {
1718 assert_eq!(
1719 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1720 parse_normalized("a")
1721 );
1722 assert_eq!(
1723 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1724 parse_normalized("a")
1725 );
1726 assert_eq!(
1727 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"),
1728 parse_normalized("a|b")
1729 );
1730
1731 assert_eq!(
1733 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1734 parse_normalized("a|b")
1735 );
1736
1737 assert_eq!(
1739 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1740 parse_normalized("(a::y)|(b::x)")
1741 );
1742 assert_eq!(
1744 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1745 parse_normalized("(x|a)&y")
1746 );
1747 assert_eq!(
1749 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1750 parse_normalized("(x|(x|a))&y")
1751 );
1752
1753 assert_eq!(
1755 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1756 parse_normalized("a|x")
1757 );
1758
1759 assert_eq!(
1761 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1762 parse_normalized("a|x")
1763 );
1764
1765 assert_eq!(
1767 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1768 parse_normalized("a|'x'")
1769 );
1770
1771 assert_eq!(
1773 with_aliases([("F(x)", "all:x")]).parse_normalized("F(a|b)"),
1774 parse_normalized("all:(a|b)")
1775 );
1776
1777 assert_eq!(
1779 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1780 parse_normalized("a")
1781 );
1782
1783 assert_eq!(
1785 *with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1786 RevsetParseErrorKind::InvalidFunctionArguments {
1787 name: "F".to_owned(),
1788 message: "Expected 0 arguments".to_owned()
1789 }
1790 );
1791 assert_eq!(
1792 *with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1793 RevsetParseErrorKind::InvalidFunctionArguments {
1794 name: "F".to_owned(),
1795 message: "Expected 1 arguments".to_owned()
1796 }
1797 );
1798 assert_eq!(
1799 *with_aliases([("F(x,y)", "x|y")])
1800 .parse("F(a,b,c)")
1801 .unwrap_err()
1802 .kind,
1803 RevsetParseErrorKind::InvalidFunctionArguments {
1804 name: "F".to_owned(),
1805 message: "Expected 2 arguments".to_owned()
1806 }
1807 );
1808 assert_eq!(
1809 *with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1810 .parse("F()")
1811 .unwrap_err()
1812 .kind,
1813 RevsetParseErrorKind::InvalidFunctionArguments {
1814 name: "F".to_owned(),
1815 message: "Expected 1 to 2 arguments".to_owned()
1816 }
1817 );
1818 assert_eq!(
1819 *with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1820 .parse("F(a)")
1821 .unwrap_err()
1822 .kind,
1823 RevsetParseErrorKind::InvalidFunctionArguments {
1824 name: "F".to_owned(),
1825 message: "Expected 0, 2 arguments".to_owned()
1826 }
1827 );
1828
1829 assert_eq!(
1831 *with_aliases([("F(x)", "x")])
1832 .parse("F(x=y)")
1833 .unwrap_err()
1834 .kind,
1835 RevsetParseErrorKind::InvalidFunctionArguments {
1836 name: "F".to_owned(),
1837 message: "Unexpected keyword arguments".to_owned()
1838 }
1839 );
1840
1841 assert_eq!(
1843 *with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1844 .parse("F(a)")
1845 .unwrap_err()
1846 .kind,
1847 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1848 );
1849 assert_eq!(
1850 *with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1851 .parse("F(a)")
1852 .unwrap_err()
1853 .kind,
1854 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1855 );
1856 }
1857
1858 #[test]
1859 fn test_expand_with_locals() {
1860 assert_eq!(
1862 with_aliases([("A", "symbol")])
1863 .set_local("A", "local")
1864 .parse_normalized("A"),
1865 parse_normalized("local")
1866 );
1867
1868 assert_eq!(
1870 with_aliases([("B", "A"), ("F(x)", "x&A")])
1871 .set_local("A", "a")
1872 .parse_normalized("A|B|F(A)"),
1873 parse_normalized("a|A|(a&A)")
1874 );
1875 }
1876}