1use std::borrow::Borrow;
16use std::cmp::{Ordering, Reverse};
17use std::collections::{HashMap, HashSet};
18use std::iter::Peekable;
19use std::ops::Range;
20use std::path::Path;
21use std::rc::Rc;
22use std::sync::Arc;
23use std::{error, fmt};
24
25use itertools::Itertools;
26use once_cell::sync::Lazy;
27use pest::iterators::{Pair, Pairs};
28use pest::pratt_parser::{Assoc, Op, PrattParser};
29use pest::Parser;
30use pest_derive::Parser;
31use thiserror::Error;
32
33use crate::backend::{BackendError, BackendResult, CommitId, ObjectId};
34use crate::commit::Commit;
35use crate::hex_util::to_forward_hex;
36use crate::index::{HexPrefix, IndexEntry, PrefixResolution};
37use crate::matchers::{EverythingMatcher, Matcher, PrefixMatcher};
38use crate::op_store::WorkspaceId;
39use crate::repo::Repo;
40use crate::repo_path::{FsPathParseError, RepoPath};
41use crate::revset_graph_iterator::RevsetGraphIterator;
42use crate::rewrite;
43use crate::store::Store;
44
45#[derive(Debug, Error)]
46pub enum RevsetError {
47 #[error("Revision \"{0}\" doesn't exist")]
48 NoSuchRevision(String),
49 #[error("Commit or change id prefix \"{0}\" is ambiguous")]
50 AmbiguousIdPrefix(String),
51 #[error("Unexpected error from store: {0}")]
52 StoreError(#[source] BackendError),
53}
54
55fn resolve_git_ref(repo: &dyn Repo, symbol: &str) -> Option<Vec<CommitId>> {
56 let view = repo.view();
57 for git_ref_prefix in &["", "refs/", "refs/heads/", "refs/tags/", "refs/remotes/"] {
58 if let Some(ref_target) = view.git_refs().get(&(git_ref_prefix.to_string() + symbol)) {
59 return Some(ref_target.adds());
60 }
61 }
62 None
63}
64
65fn resolve_branch(repo: &dyn Repo, symbol: &str) -> Option<Vec<CommitId>> {
66 if let Some(branch_target) = repo.view().branches().get(symbol) {
67 return Some(
68 branch_target
69 .local_target
70 .as_ref()
71 .map(|target| target.adds())
72 .unwrap_or_default(),
73 );
74 }
75 if let Some((name, remote_name)) = symbol.split_once('@') {
76 if let Some(branch_target) = repo.view().branches().get(name) {
77 if let Some(target) = branch_target.remote_targets.get(remote_name) {
78 return Some(target.adds());
79 }
80 }
81 }
82 None
83}
84
85fn resolve_full_commit_id(
86 repo: &dyn Repo,
87 symbol: &str,
88) -> Result<Option<Vec<CommitId>>, RevsetError> {
89 if let Ok(binary_commit_id) = hex::decode(symbol) {
90 if repo.store().commit_id_length() != binary_commit_id.len() {
91 return Ok(None);
92 }
93 let commit_id = CommitId::new(binary_commit_id);
94 match repo.store().get_commit(&commit_id) {
95 Ok(_) if repo.index().entry_by_id(&commit_id).is_some() => Ok(Some(vec![commit_id])),
97 Ok(_) | Err(BackendError::ObjectNotFound { .. }) => Ok(None),
98 Err(err) => Err(RevsetError::StoreError(err)),
99 }
100 } else {
101 Ok(None)
102 }
103}
104
105fn resolve_short_commit_id(
106 repo: &dyn Repo,
107 symbol: &str,
108) -> Result<Option<Vec<CommitId>>, RevsetError> {
109 if let Some(prefix) = HexPrefix::new(symbol) {
110 match repo.index().resolve_prefix(&prefix) {
111 PrefixResolution::NoMatch => Ok(None),
112 PrefixResolution::AmbiguousMatch => {
113 Err(RevsetError::AmbiguousIdPrefix(symbol.to_owned()))
114 }
115 PrefixResolution::SingleMatch(commit_id) => Ok(Some(vec![commit_id])),
116 }
117 } else {
118 Ok(None)
119 }
120}
121
122fn resolve_change_id(repo: &dyn Repo, symbol: &str) -> Result<Option<Vec<CommitId>>, RevsetError> {
123 if let Some(prefix) = to_forward_hex(symbol).as_deref().and_then(HexPrefix::new) {
124 match repo.resolve_change_id_prefix(&prefix) {
125 PrefixResolution::NoMatch => Ok(None),
126 PrefixResolution::AmbiguousMatch => {
127 Err(RevsetError::AmbiguousIdPrefix(symbol.to_owned()))
128 }
129 PrefixResolution::SingleMatch(entries) => {
130 Ok(Some(entries.iter().map(|e| e.commit_id()).collect()))
131 }
132 }
133 } else {
134 Ok(None)
135 }
136}
137
138pub fn resolve_symbol(
139 repo: &dyn Repo,
140 symbol: &str,
141 workspace_id: Option<&WorkspaceId>,
142) -> Result<Vec<CommitId>, RevsetError> {
143 if symbol.ends_with('@') {
144 let target_workspace = if symbol == "@" {
145 if let Some(workspace_id) = workspace_id {
146 workspace_id.clone()
147 } else {
148 return Err(RevsetError::NoSuchRevision(symbol.to_owned()));
149 }
150 } else {
151 WorkspaceId::new(symbol.strip_suffix('@').unwrap().to_string())
152 };
153 if let Some(commit_id) = repo.view().get_wc_commit_id(&target_workspace) {
154 Ok(vec![commit_id.clone()])
155 } else {
156 Err(RevsetError::NoSuchRevision(symbol.to_owned()))
157 }
158 } else if symbol == "root" {
159 Ok(vec![repo.store().root_commit_id().clone()])
160 } else {
161 if let Some(target) = repo.view().tags().get(symbol) {
163 return Ok(target.adds());
164 }
165
166 if let Some(ids) = resolve_branch(repo, symbol) {
168 return Ok(ids);
169 }
170
171 if let Some(ids) = resolve_git_ref(repo, symbol) {
173 return Ok(ids);
174 }
175
176 if let Some(ids) = resolve_full_commit_id(repo, symbol)? {
179 return Ok(ids);
180 }
181
182 if let Some(ids) = resolve_short_commit_id(repo, symbol)? {
184 return Ok(ids);
185 }
186
187 if let Some(ids) = resolve_change_id(repo, symbol)? {
189 return Ok(ids);
190 }
191
192 Err(RevsetError::NoSuchRevision(symbol.to_owned()))
193 }
194}
195
196#[derive(Parser)]
197#[grammar = "revset.pest"]
198pub struct RevsetParser;
199
200#[derive(Debug)]
201pub struct RevsetParseError {
202 kind: RevsetParseErrorKind,
203 pest_error: Option<Box<pest::error::Error<Rule>>>,
204 origin: Option<Box<RevsetParseError>>,
205}
206
207#[derive(Debug, Error, PartialEq, Eq)]
208pub enum RevsetParseErrorKind {
209 #[error("Syntax error")]
210 SyntaxError,
211 #[error("'{op}' is not a postfix operator (Did you mean '{similar_op}' for {description}?)")]
212 NotPostfixOperator {
213 op: String,
214 similar_op: String,
215 description: String,
216 },
217 #[error("'{op}' is not an infix operator (Did you mean '{similar_op}' for {description}?)")]
218 NotInfixOperator {
219 op: String,
220 similar_op: String,
221 description: String,
222 },
223 #[error("Revset function \"{0}\" doesn't exist")]
224 NoSuchFunction(String),
225 #[error("Invalid arguments to revset function \"{name}\": {message}")]
226 InvalidFunctionArguments { name: String, message: String },
227 #[error("Invalid file pattern: {0}")]
228 FsPathParseError(#[source] FsPathParseError),
229 #[error("Cannot resolve file pattern without workspace")]
230 FsPathWithoutWorkspace,
231 #[error("Redefinition of function parameter")]
232 RedefinedFunctionParameter,
233 #[error(r#"Alias "{0}" cannot be expanded"#)]
234 BadAliasExpansion(String),
235 #[error(r#"Alias "{0}" expanded recursively"#)]
236 RecursiveAlias(String),
237}
238
239impl RevsetParseError {
240 fn new(kind: RevsetParseErrorKind) -> Self {
241 RevsetParseError {
242 kind,
243 pest_error: None,
244 origin: None,
245 }
246 }
247
248 fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self {
249 let err = pest::error::Error::new_from_span(
250 pest::error::ErrorVariant::CustomError {
251 message: kind.to_string(),
252 },
253 span,
254 );
255 RevsetParseError {
256 kind,
257 pest_error: Some(Box::new(err)),
258 origin: None,
259 }
260 }
261
262 fn with_span_and_origin(
263 kind: RevsetParseErrorKind,
264 span: pest::Span<'_>,
265 origin: Self,
266 ) -> Self {
267 let err = pest::error::Error::new_from_span(
268 pest::error::ErrorVariant::CustomError {
269 message: kind.to_string(),
270 },
271 span,
272 );
273 RevsetParseError {
274 kind,
275 pest_error: Some(Box::new(err)),
276 origin: Some(Box::new(origin)),
277 }
278 }
279
280 pub fn kind(&self) -> &RevsetParseErrorKind {
281 &self.kind
282 }
283
284 pub fn origin(&self) -> Option<&Self> {
286 self.origin.as_deref()
287 }
288}
289
290impl From<pest::error::Error<Rule>> for RevsetParseError {
291 fn from(err: pest::error::Error<Rule>) -> Self {
292 RevsetParseError {
293 kind: RevsetParseErrorKind::SyntaxError,
294 pest_error: Some(Box::new(err)),
295 origin: None,
296 }
297 }
298}
299
300impl fmt::Display for RevsetParseError {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 if let Some(err) = &self.pest_error {
303 err.fmt(f)
304 } else {
305 self.kind.fmt(f)
306 }
307 }
308}
309
310impl error::Error for RevsetParseError {
311 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
312 if let Some(e) = self.origin() {
313 return Some(e as &dyn error::Error);
314 }
315 match &self.kind {
316 RevsetParseErrorKind::SyntaxError => {
318 self.pest_error.as_ref().map(|e| e as &dyn error::Error)
319 }
320 e => e.source(),
322 }
323 }
324}
325
326const GENERATION_RANGE_FULL: Range<u32> = 0..u32::MAX;
328const GENERATION_RANGE_EMPTY: Range<u32> = 0..0;
329
330#[derive(Clone, Debug, Eq, PartialEq)]
331pub enum RevsetFilterPredicate {
332 ParentCount(Range<u32>),
334 Description(String),
336 Author(String),
338 Committer(String),
340 File(Option<Vec<RepoPath>>), }
343
344#[derive(Debug, PartialEq, Eq, Clone)]
345pub enum RevsetExpression {
346 None,
347 All,
348 Commits(Vec<CommitId>),
349 Symbol(String),
350 Children(Rc<RevsetExpression>),
351 Ancestors {
352 heads: Rc<RevsetExpression>,
353 generation: Range<u32>,
354 },
355 Range {
357 roots: Rc<RevsetExpression>,
358 heads: Rc<RevsetExpression>,
359 generation: Range<u32>,
360 },
361 DagRange {
363 roots: Rc<RevsetExpression>,
364 heads: Rc<RevsetExpression>,
365 },
366 Heads(Rc<RevsetExpression>),
367 Roots(Rc<RevsetExpression>),
368 VisibleHeads,
369 PublicHeads,
370 Branches(String),
371 RemoteBranches {
372 branch_needle: String,
373 remote_needle: String,
374 },
375 Tags,
376 GitRefs,
377 GitHead,
378 Filter(RevsetFilterPredicate),
379 AsFilter(Rc<RevsetExpression>),
381 Present(Rc<RevsetExpression>),
382 NotIn(Rc<RevsetExpression>),
383 Union(Rc<RevsetExpression>, Rc<RevsetExpression>),
384 Intersection(Rc<RevsetExpression>, Rc<RevsetExpression>),
385 Difference(Rc<RevsetExpression>, Rc<RevsetExpression>),
386}
387
388impl RevsetExpression {
389 pub fn none() -> Rc<RevsetExpression> {
390 Rc::new(RevsetExpression::None)
391 }
392
393 pub fn all() -> Rc<RevsetExpression> {
394 Rc::new(RevsetExpression::All)
395 }
396
397 pub fn symbol(value: String) -> Rc<RevsetExpression> {
398 Rc::new(RevsetExpression::Symbol(value))
399 }
400
401 pub fn commit(commit_id: CommitId) -> Rc<RevsetExpression> {
402 RevsetExpression::commits(vec![commit_id])
403 }
404
405 pub fn commits(commit_ids: Vec<CommitId>) -> Rc<RevsetExpression> {
406 Rc::new(RevsetExpression::Commits(commit_ids))
407 }
408
409 pub fn visible_heads() -> Rc<RevsetExpression> {
410 Rc::new(RevsetExpression::VisibleHeads)
411 }
412
413 pub fn public_heads() -> Rc<RevsetExpression> {
414 Rc::new(RevsetExpression::PublicHeads)
415 }
416
417 pub fn branches(needle: String) -> Rc<RevsetExpression> {
418 Rc::new(RevsetExpression::Branches(needle))
419 }
420
421 pub fn remote_branches(branch_needle: String, remote_needle: String) -> Rc<RevsetExpression> {
422 Rc::new(RevsetExpression::RemoteBranches {
423 branch_needle,
424 remote_needle,
425 })
426 }
427
428 pub fn tags() -> Rc<RevsetExpression> {
429 Rc::new(RevsetExpression::Tags)
430 }
431
432 pub fn git_refs() -> Rc<RevsetExpression> {
433 Rc::new(RevsetExpression::GitRefs)
434 }
435
436 pub fn git_head() -> Rc<RevsetExpression> {
437 Rc::new(RevsetExpression::GitHead)
438 }
439
440 pub fn filter(predicate: RevsetFilterPredicate) -> Rc<RevsetExpression> {
441 Rc::new(RevsetExpression::Filter(predicate))
442 }
443
444 pub fn heads(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
446 Rc::new(RevsetExpression::Heads(self.clone()))
447 }
448
449 pub fn roots(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
451 Rc::new(RevsetExpression::Roots(self.clone()))
452 }
453
454 pub fn parents(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
456 Rc::new(RevsetExpression::Ancestors {
457 heads: self.clone(),
458 generation: 1..2,
459 })
460 }
461
462 pub fn ancestors(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
464 Rc::new(RevsetExpression::Ancestors {
465 heads: self.clone(),
466 generation: GENERATION_RANGE_FULL,
467 })
468 }
469
470 pub fn children(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
472 Rc::new(RevsetExpression::Children(self.clone()))
473 }
474
475 pub fn descendants(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
477 self.dag_range_to(&RevsetExpression::visible_heads())
478 }
479
480 pub fn dag_range_to(
483 self: &Rc<RevsetExpression>,
484 heads: &Rc<RevsetExpression>,
485 ) -> Rc<RevsetExpression> {
486 Rc::new(RevsetExpression::DagRange {
487 roots: self.clone(),
488 heads: heads.clone(),
489 })
490 }
491
492 pub fn connected(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
495 self.dag_range_to(self)
496 }
497
498 pub fn range(
500 self: &Rc<RevsetExpression>,
501 heads: &Rc<RevsetExpression>,
502 ) -> Rc<RevsetExpression> {
503 Rc::new(RevsetExpression::Range {
504 roots: self.clone(),
505 heads: heads.clone(),
506 generation: GENERATION_RANGE_FULL,
507 })
508 }
509
510 pub fn negated(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
512 Rc::new(RevsetExpression::NotIn(self.clone()))
513 }
514
515 pub fn union(
517 self: &Rc<RevsetExpression>,
518 other: &Rc<RevsetExpression>,
519 ) -> Rc<RevsetExpression> {
520 Rc::new(RevsetExpression::Union(self.clone(), other.clone()))
521 }
522
523 pub fn intersection(
525 self: &Rc<RevsetExpression>,
526 other: &Rc<RevsetExpression>,
527 ) -> Rc<RevsetExpression> {
528 Rc::new(RevsetExpression::Intersection(self.clone(), other.clone()))
529 }
530
531 pub fn minus(
533 self: &Rc<RevsetExpression>,
534 other: &Rc<RevsetExpression>,
535 ) -> Rc<RevsetExpression> {
536 Rc::new(RevsetExpression::Difference(self.clone(), other.clone()))
537 }
538
539 pub fn evaluate<'repo>(
540 &self,
541 repo: &'repo dyn Repo,
542 workspace_ctx: Option<&RevsetWorkspaceContext>,
543 ) -> Result<Box<dyn Revset<'repo> + 'repo>, RevsetError> {
544 evaluate_expression(repo, self, workspace_ctx)
545 }
546}
547
548#[derive(Clone, Debug, Default)]
549pub struct RevsetAliasesMap {
550 symbol_aliases: HashMap<String, String>,
551 function_aliases: HashMap<String, (Vec<String>, String)>,
552}
553
554impl RevsetAliasesMap {
555 pub fn new() -> Self {
556 Self::default()
557 }
558
559 pub fn insert(
564 &mut self,
565 decl: impl AsRef<str>,
566 defn: impl Into<String>,
567 ) -> Result<(), RevsetParseError> {
568 match RevsetAliasDeclaration::parse(decl.as_ref())? {
569 RevsetAliasDeclaration::Symbol(name) => {
570 self.symbol_aliases.insert(name, defn.into());
571 }
572 RevsetAliasDeclaration::Function(name, params) => {
573 self.function_aliases.insert(name, (params, defn.into()));
574 }
575 }
576 Ok(())
577 }
578
579 fn get_symbol<'a>(&'a self, name: &str) -> Option<(RevsetAliasId<'a>, &'a str)> {
580 self.symbol_aliases
581 .get_key_value(name)
582 .map(|(name, defn)| (RevsetAliasId::Symbol(name), defn.as_ref()))
583 }
584
585 fn get_function<'a>(
586 &'a self,
587 name: &str,
588 ) -> Option<(RevsetAliasId<'a>, &'a [String], &'a str)> {
589 self.function_aliases
590 .get_key_value(name)
591 .map(|(name, (params, defn))| {
592 (
593 RevsetAliasId::Function(name),
594 params.as_ref(),
595 defn.as_ref(),
596 )
597 })
598 }
599}
600
601#[derive(Clone, Debug)]
603enum RevsetAliasDeclaration {
604 Symbol(String),
605 Function(String, Vec<String>),
606}
607
608impl RevsetAliasDeclaration {
609 fn parse(source: &str) -> Result<Self, RevsetParseError> {
610 let mut pairs = RevsetParser::parse(Rule::alias_declaration, source)?;
611 let first = pairs.next().unwrap();
612 match first.as_rule() {
613 Rule::identifier => Ok(RevsetAliasDeclaration::Symbol(first.as_str().to_owned())),
614 Rule::function_name => {
615 let name = first.as_str().to_owned();
616 let params_pair = pairs.next().unwrap();
617 let params_span = params_pair.as_span();
618 let params = params_pair
619 .into_inner()
620 .map(|pair| match pair.as_rule() {
621 Rule::identifier => pair.as_str().to_owned(),
622 r => panic!("unexpected formal parameter rule {r:?}"),
623 })
624 .collect_vec();
625 if params.iter().all_unique() {
626 Ok(RevsetAliasDeclaration::Function(name, params))
627 } else {
628 Err(RevsetParseError::with_span(
629 RevsetParseErrorKind::RedefinedFunctionParameter,
630 params_span,
631 ))
632 }
633 }
634 r => panic!("unexpected alias declaration rule {r:?}"),
635 }
636 }
637}
638
639#[derive(Clone, Copy, Debug, Eq, PartialEq)]
641enum RevsetAliasId<'a> {
642 Symbol(&'a str),
643 Function(&'a str),
644}
645
646impl fmt::Display for RevsetAliasId<'_> {
647 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
648 match self {
649 RevsetAliasId::Symbol(name) => write!(f, "{name}"),
650 RevsetAliasId::Function(name) => write!(f, "{name}()"),
651 }
652 }
653}
654
655#[derive(Clone, Copy, Debug)]
656struct ParseState<'a> {
657 aliases_map: &'a RevsetAliasesMap,
658 aliases_expanding: &'a [RevsetAliasId<'a>],
659 locals: &'a HashMap<&'a str, Rc<RevsetExpression>>,
660 workspace_ctx: Option<&'a RevsetWorkspaceContext<'a>>,
661}
662
663impl ParseState<'_> {
664 fn with_alias_expanding<T>(
665 self,
666 id: RevsetAliasId<'_>,
667 locals: &HashMap<&str, Rc<RevsetExpression>>,
668 span: pest::Span<'_>,
669 f: impl FnOnce(ParseState<'_>) -> Result<T, RevsetParseError>,
670 ) -> Result<T, RevsetParseError> {
671 if self.aliases_expanding.contains(&id) {
673 return Err(RevsetParseError::with_span(
674 RevsetParseErrorKind::RecursiveAlias(id.to_string()),
675 span,
676 ));
677 }
678 let mut aliases_expanding = self.aliases_expanding.to_vec();
679 aliases_expanding.push(id);
680 let expanding_state = ParseState {
681 aliases_map: self.aliases_map,
682 aliases_expanding: &aliases_expanding,
683 locals,
684 workspace_ctx: self.workspace_ctx,
685 };
686 f(expanding_state).map_err(|e| {
687 RevsetParseError::with_span_and_origin(
688 RevsetParseErrorKind::BadAliasExpansion(id.to_string()),
689 span,
690 e,
691 )
692 })
693 }
694}
695
696fn parse_program(
697 revset_str: &str,
698 state: ParseState,
699) -> Result<Rc<RevsetExpression>, RevsetParseError> {
700 let mut pairs = RevsetParser::parse(Rule::program, revset_str)?;
701 let first = pairs.next().unwrap();
702 parse_expression_rule(first.into_inner(), state)
703}
704
705fn parse_expression_rule(
706 pairs: Pairs<Rule>,
707 state: ParseState,
708) -> Result<Rc<RevsetExpression>, RevsetParseError> {
709 fn not_postfix_op(
710 op: &Pair<Rule>,
711 similar_op: impl Into<String>,
712 description: impl Into<String>,
713 ) -> RevsetParseError {
714 RevsetParseError::with_span(
715 RevsetParseErrorKind::NotPostfixOperator {
716 op: op.as_str().to_owned(),
717 similar_op: similar_op.into(),
718 description: description.into(),
719 },
720 op.as_span(),
721 )
722 }
723
724 fn not_infix_op(
725 op: &Pair<Rule>,
726 similar_op: impl Into<String>,
727 description: impl Into<String>,
728 ) -> RevsetParseError {
729 RevsetParseError::with_span(
730 RevsetParseErrorKind::NotInfixOperator {
731 op: op.as_str().to_owned(),
732 similar_op: similar_op.into(),
733 description: description.into(),
734 },
735 op.as_span(),
736 )
737 }
738
739 static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| {
740 PrattParser::new()
741 .op(Op::infix(Rule::union_op, Assoc::Left)
742 | Op::infix(Rule::compat_add_op, Assoc::Left))
743 .op(Op::infix(Rule::intersection_op, Assoc::Left)
744 | Op::infix(Rule::difference_op, Assoc::Left)
745 | Op::infix(Rule::compat_sub_op, Assoc::Left))
746 .op(Op::prefix(Rule::negate_op))
747 .op(Op::infix(Rule::dag_range_op, Assoc::Left) | Op::infix(Rule::range_op, Assoc::Left))
749 .op(Op::prefix(Rule::dag_range_pre_op) | Op::prefix(Rule::range_pre_op))
750 .op(Op::postfix(Rule::dag_range_post_op) | Op::postfix(Rule::range_post_op))
751 .op(Op::postfix(Rule::parents_op)
753 | Op::postfix(Rule::children_op)
754 | Op::postfix(Rule::compat_parents_op))
755 });
756 PRATT
757 .map_primary(|primary| parse_primary_rule(primary, state))
758 .map_prefix(|op, rhs| match op.as_rule() {
759 Rule::negate_op => Ok(rhs?.negated()),
760 Rule::dag_range_pre_op | Rule::range_pre_op => Ok(rhs?.ancestors()),
761 r => panic!("unexpected prefix operator rule {r:?}"),
762 })
763 .map_postfix(|lhs, op| match op.as_rule() {
764 Rule::dag_range_post_op => Ok(lhs?.descendants()),
765 Rule::range_post_op => Ok(lhs?.range(&RevsetExpression::visible_heads())),
766 Rule::parents_op => Ok(lhs?.parents()),
767 Rule::children_op => Ok(lhs?.children()),
768 Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents")),
769 r => panic!("unexpected postfix operator rule {r:?}"),
770 })
771 .map_infix(|lhs, op, rhs| match op.as_rule() {
772 Rule::union_op => Ok(lhs?.union(&rhs?)),
773 Rule::compat_add_op => Err(not_infix_op(&op, "|", "union")),
774 Rule::intersection_op => Ok(lhs?.intersection(&rhs?)),
775 Rule::difference_op => Ok(lhs?.minus(&rhs?)),
776 Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference")),
777 Rule::dag_range_op => Ok(lhs?.dag_range_to(&rhs?)),
778 Rule::range_op => Ok(lhs?.range(&rhs?)),
779 r => panic!("unexpected infix operator rule {r:?}"),
780 })
781 .parse(pairs)
782}
783
784fn parse_primary_rule(
785 pair: Pair<Rule>,
786 state: ParseState,
787) -> Result<Rc<RevsetExpression>, RevsetParseError> {
788 let span = pair.as_span();
789 let mut pairs = pair.into_inner();
790 let first = pairs.next().unwrap();
791 match first.as_rule() {
792 Rule::expression => parse_expression_rule(first.into_inner(), state),
793 Rule::function_name => {
794 let arguments_pair = pairs.next().unwrap();
795 parse_function_expression(first, arguments_pair, state, span)
796 }
797 Rule::symbol => parse_symbol_rule(first.into_inner(), state),
798 _ => {
799 panic!("unexpected revset parse rule: {:?}", first.as_str());
800 }
801 }
802}
803
804fn parse_symbol_rule(
805 mut pairs: Pairs<Rule>,
806 state: ParseState,
807) -> Result<Rc<RevsetExpression>, RevsetParseError> {
808 let first = pairs.next().unwrap();
809 match first.as_rule() {
810 Rule::identifier => {
811 let name = first.as_str();
812 if let Some(expr) = state.locals.get(name) {
813 Ok(expr.clone())
814 } else if let Some((id, defn)) = state.aliases_map.get_symbol(name) {
815 let locals = HashMap::new(); state.with_alias_expanding(id, &locals, first.as_span(), |state| {
817 parse_program(defn, state)
818 })
819 } else {
820 Ok(RevsetExpression::symbol(name.to_owned()))
821 }
822 }
823 Rule::literal_string => {
824 return Ok(RevsetExpression::symbol(
825 first
826 .as_str()
827 .strip_prefix('"')
828 .unwrap()
829 .strip_suffix('"')
830 .unwrap()
831 .to_owned(),
832 ));
833 }
834 _ => {
835 panic!("unexpected symbol parse rule: {:?}", first.as_str());
836 }
837 }
838}
839
840fn parse_function_expression(
841 name_pair: Pair<Rule>,
842 arguments_pair: Pair<Rule>,
843 state: ParseState,
844 primary_span: pest::Span<'_>,
845) -> Result<Rc<RevsetExpression>, RevsetParseError> {
846 let name = name_pair.as_str();
847 if let Some((id, params, defn)) = state.aliases_map.get_function(name) {
848 let (required, optional) =
851 expect_named_arguments_vec(name, &[], arguments_pair, params.len(), params.len())?;
852 assert!(optional.is_empty());
853 let args: Vec<_> = required
854 .into_iter()
855 .map(|arg| parse_expression_rule(arg.into_inner(), state))
856 .try_collect()?;
857 let locals = params.iter().map(|s| s.as_str()).zip(args).collect();
858 state.with_alias_expanding(id, &locals, primary_span, |state| {
859 parse_program(defn, state)
860 })
861 } else {
862 parse_builtin_function(name_pair, arguments_pair, state)
863 }
864}
865
866fn parse_builtin_function(
867 name_pair: Pair<Rule>,
868 arguments_pair: Pair<Rule>,
869 state: ParseState,
870) -> Result<Rc<RevsetExpression>, RevsetParseError> {
871 let name = name_pair.as_str();
872 match name {
873 "parents" => {
874 let arg = expect_one_argument(name, arguments_pair)?;
875 let expression = parse_expression_rule(arg.into_inner(), state)?;
876 Ok(expression.parents())
877 }
878 "children" => {
879 let arg = expect_one_argument(name, arguments_pair)?;
880 let expression = parse_expression_rule(arg.into_inner(), state)?;
881 Ok(expression.children())
882 }
883 "ancestors" => {
884 let arg = expect_one_argument(name, arguments_pair)?;
885 let expression = parse_expression_rule(arg.into_inner(), state)?;
886 Ok(expression.ancestors())
887 }
888 "descendants" => {
889 let arg = expect_one_argument(name, arguments_pair)?;
890 let expression = parse_expression_rule(arg.into_inner(), state)?;
891 Ok(expression.descendants())
892 }
893 "connected" => {
894 let arg = expect_one_argument(name, arguments_pair)?;
895 let candidates = parse_expression_rule(arg.into_inner(), state)?;
896 Ok(candidates.connected())
897 }
898 "none" => {
899 expect_no_arguments(name, arguments_pair)?;
900 Ok(RevsetExpression::none())
901 }
902 "all" => {
903 expect_no_arguments(name, arguments_pair)?;
904 Ok(RevsetExpression::all())
905 }
906 "heads" => {
907 let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
908 if let Some(arg) = opt_arg {
909 let candidates = parse_expression_rule(arg.into_inner(), state)?;
910 Ok(candidates.heads())
911 } else {
912 Ok(RevsetExpression::visible_heads())
913 }
914 }
915 "roots" => {
916 let arg = expect_one_argument(name, arguments_pair)?;
917 let candidates = parse_expression_rule(arg.into_inner(), state)?;
918 Ok(candidates.roots())
919 }
920 "public_heads" => {
921 expect_no_arguments(name, arguments_pair)?;
922 Ok(RevsetExpression::public_heads())
923 }
924 "branches" => {
925 let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
926 let needle = if let Some(arg) = opt_arg {
927 parse_function_argument_to_string(name, arg, state)?
928 } else {
929 "".to_owned()
930 };
931 Ok(RevsetExpression::branches(needle))
932 }
933 "remote_branches" => {
934 let ([], [branch_opt_arg, remote_opt_arg]) =
935 expect_named_arguments(name, &["", "remote"], arguments_pair)?;
936 let branch_needle = if let Some(branch_arg) = branch_opt_arg {
937 parse_function_argument_to_string(name, branch_arg, state)?
938 } else {
939 "".to_owned()
940 };
941 let remote_needle = if let Some(remote_arg) = remote_opt_arg {
942 parse_function_argument_to_string(name, remote_arg, state)?
943 } else {
944 "".to_owned()
945 };
946 Ok(RevsetExpression::remote_branches(
947 branch_needle,
948 remote_needle,
949 ))
950 }
951 "tags" => {
952 expect_no_arguments(name, arguments_pair)?;
953 Ok(RevsetExpression::tags())
954 }
955 "git_refs" => {
956 expect_no_arguments(name, arguments_pair)?;
957 Ok(RevsetExpression::git_refs())
958 }
959 "git_head" => {
960 expect_no_arguments(name, arguments_pair)?;
961 Ok(RevsetExpression::git_head())
962 }
963 "merges" => {
964 expect_no_arguments(name, arguments_pair)?;
965 Ok(RevsetExpression::filter(
966 RevsetFilterPredicate::ParentCount(2..u32::MAX),
967 ))
968 }
969 "description" => {
970 let arg = expect_one_argument(name, arguments_pair)?;
971 let needle = parse_function_argument_to_string(name, arg, state)?;
972 Ok(RevsetExpression::filter(
973 RevsetFilterPredicate::Description(needle),
974 ))
975 }
976 "author" => {
977 let arg = expect_one_argument(name, arguments_pair)?;
978 let needle = parse_function_argument_to_string(name, arg, state)?;
979 Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
980 needle,
981 )))
982 }
983 "committer" => {
984 let arg = expect_one_argument(name, arguments_pair)?;
985 let needle = parse_function_argument_to_string(name, arg, state)?;
986 Ok(RevsetExpression::filter(RevsetFilterPredicate::Committer(
987 needle,
988 )))
989 }
990 "empty" => {
991 expect_no_arguments(name, arguments_pair)?;
992 Ok(RevsetExpression::filter(RevsetFilterPredicate::File(None)).negated())
993 }
994 "file" => {
995 if let Some(ctx) = state.workspace_ctx {
996 let arguments_span = arguments_pair.as_span();
997 let paths: Vec<_> = arguments_pair
998 .into_inner()
999 .map(|arg| -> Result<_, RevsetParseError> {
1000 let span = arg.as_span();
1001 let needle = parse_function_argument_to_string(name, arg, state)?;
1002 let path = RepoPath::parse_fs_path(ctx.cwd, ctx.workspace_root, &needle)
1003 .map_err(|e| {
1004 RevsetParseError::with_span(
1005 RevsetParseErrorKind::FsPathParseError(e),
1006 span,
1007 )
1008 })?;
1009 Ok(path)
1010 })
1011 .try_collect()?;
1012 if paths.is_empty() {
1013 Err(RevsetParseError::with_span(
1014 RevsetParseErrorKind::InvalidFunctionArguments {
1015 name: name.to_owned(),
1016 message: "Expected at least 1 argument".to_string(),
1017 },
1018 arguments_span,
1019 ))
1020 } else {
1021 Ok(RevsetExpression::filter(RevsetFilterPredicate::File(Some(
1022 paths,
1023 ))))
1024 }
1025 } else {
1026 Err(RevsetParseError::new(
1027 RevsetParseErrorKind::FsPathWithoutWorkspace,
1028 ))
1029 }
1030 }
1031 "present" => {
1032 let arg = expect_one_argument(name, arguments_pair)?;
1033 let expression = parse_expression_rule(arg.into_inner(), state)?;
1034 Ok(Rc::new(RevsetExpression::Present(expression)))
1035 }
1036 _ => Err(RevsetParseError::with_span(
1037 RevsetParseErrorKind::NoSuchFunction(name.to_owned()),
1038 name_pair.as_span(),
1039 )),
1040 }
1041}
1042
1043type OptionalArg<'i> = Option<Pair<'i, Rule>>;
1044
1045fn expect_no_arguments(
1046 function_name: &str,
1047 arguments_pair: Pair<Rule>,
1048) -> Result<(), RevsetParseError> {
1049 let ([], []) = expect_arguments(function_name, arguments_pair)?;
1050 Ok(())
1051}
1052
1053fn expect_one_argument<'i>(
1054 function_name: &str,
1055 arguments_pair: Pair<'i, Rule>,
1056) -> Result<Pair<'i, Rule>, RevsetParseError> {
1057 let ([arg], []) = expect_arguments(function_name, arguments_pair)?;
1058 Ok(arg)
1059}
1060
1061fn expect_arguments<'i, const N: usize, const M: usize>(
1062 function_name: &str,
1063 arguments_pair: Pair<'i, Rule>,
1064) -> Result<([Pair<'i, Rule>; N], [OptionalArg<'i>; M]), RevsetParseError> {
1065 expect_named_arguments(function_name, &[], arguments_pair)
1066}
1067
1068fn expect_named_arguments<'i, const N: usize, const M: usize>(
1073 function_name: &str,
1074 argument_names: &[&str],
1075 arguments_pair: Pair<'i, Rule>,
1076) -> Result<([Pair<'i, Rule>; N], [OptionalArg<'i>; M]), RevsetParseError> {
1077 let (required, optional) =
1078 expect_named_arguments_vec(function_name, argument_names, arguments_pair, N, N + M)?;
1079 Ok((required.try_into().unwrap(), optional.try_into().unwrap()))
1080}
1081
1082fn expect_named_arguments_vec<'i>(
1083 function_name: &str,
1084 argument_names: &[&str],
1085 arguments_pair: Pair<'i, Rule>,
1086 min_arg_count: usize,
1087 max_arg_count: usize,
1088) -> Result<(Vec<Pair<'i, Rule>>, Vec<OptionalArg<'i>>), RevsetParseError> {
1089 assert!(argument_names.len() <= max_arg_count);
1090 let arguments_span = arguments_pair.as_span();
1091 let make_error = |message, span| {
1092 RevsetParseError::with_span(
1093 RevsetParseErrorKind::InvalidFunctionArguments {
1094 name: function_name.to_owned(),
1095 message,
1096 },
1097 span,
1098 )
1099 };
1100 let make_count_error = || {
1101 let message = if min_arg_count == max_arg_count {
1102 format!("Expected {min_arg_count} arguments")
1103 } else {
1104 format!("Expected {min_arg_count} to {max_arg_count} arguments")
1105 };
1106 make_error(message, arguments_span)
1107 };
1108
1109 let mut pos_iter = Some(0..max_arg_count);
1110 let mut extracted_pairs = vec![None; max_arg_count];
1111 for pair in arguments_pair.into_inner() {
1112 let span = pair.as_span();
1113 match pair.as_rule() {
1114 Rule::expression => {
1115 let pos = pos_iter
1116 .as_mut()
1117 .ok_or_else(|| {
1118 make_error(
1119 "Positional argument follows keyword argument".to_owned(),
1120 span,
1121 )
1122 })?
1123 .next()
1124 .ok_or_else(make_count_error)?;
1125 assert!(extracted_pairs[pos].is_none());
1126 extracted_pairs[pos] = Some(pair);
1127 }
1128 Rule::keyword_argument => {
1129 pos_iter = None; let mut pairs = pair.into_inner();
1131 let name = pairs.next().unwrap();
1132 let expr = pairs.next().unwrap();
1133 assert_eq!(name.as_rule(), Rule::identifier);
1134 assert_eq!(expr.as_rule(), Rule::expression);
1135 let pos = argument_names
1136 .iter()
1137 .position(|&n| n == name.as_str())
1138 .ok_or_else(|| {
1139 make_error(
1140 format!(r#"Unexpected keyword argument "{}""#, name.as_str()),
1141 span,
1142 )
1143 })?;
1144 if extracted_pairs[pos].is_some() {
1145 return Err(make_error(
1146 format!(r#"Got multiple values for keyword "{}""#, name.as_str()),
1147 span,
1148 ));
1149 }
1150 extracted_pairs[pos] = Some(expr);
1151 }
1152 r => panic!("unexpected argument rule {r:?}"),
1153 }
1154 }
1155
1156 assert_eq!(extracted_pairs.len(), max_arg_count);
1157 let optional = extracted_pairs.split_off(min_arg_count);
1158 let required = extracted_pairs.into_iter().flatten().collect_vec();
1159 if required.len() != min_arg_count {
1160 return Err(make_count_error());
1161 }
1162 Ok((required, optional))
1163}
1164
1165fn parse_function_argument_to_string(
1166 name: &str,
1167 pair: Pair<Rule>,
1168 state: ParseState,
1169) -> Result<String, RevsetParseError> {
1170 let span = pair.as_span();
1171 let expression = parse_expression_rule(pair.into_inner(), state)?;
1172 match expression.as_ref() {
1173 RevsetExpression::Symbol(symbol) => Ok(symbol.clone()),
1174 _ => Err(RevsetParseError::with_span(
1175 RevsetParseErrorKind::InvalidFunctionArguments {
1176 name: name.to_string(),
1177 message: "Expected function argument of type string".to_owned(),
1178 },
1179 span,
1180 )),
1181 }
1182}
1183
1184pub fn parse(
1185 revset_str: &str,
1186 aliases_map: &RevsetAliasesMap,
1187 workspace_ctx: Option<&RevsetWorkspaceContext>,
1188) -> Result<Rc<RevsetExpression>, RevsetParseError> {
1189 let state = ParseState {
1190 aliases_map,
1191 aliases_expanding: &[],
1192 locals: &HashMap::new(),
1193 workspace_ctx,
1194 };
1195 parse_program(revset_str, state)
1196}
1197
1198fn transform_expression_bottom_up(
1204 expression: &Rc<RevsetExpression>,
1205 mut f: impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>,
1206) -> Option<Rc<RevsetExpression>> {
1207 fn transform_child_rec(
1208 expression: &Rc<RevsetExpression>,
1209 f: &mut impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>,
1210 ) -> Option<Rc<RevsetExpression>> {
1211 match expression.as_ref() {
1212 RevsetExpression::None => None,
1213 RevsetExpression::All => None,
1214 RevsetExpression::Commits(_) => None,
1215 RevsetExpression::Symbol(_) => None,
1216 RevsetExpression::Children(roots) => {
1217 transform_rec(roots, f).map(RevsetExpression::Children)
1218 }
1219 RevsetExpression::Ancestors { heads, generation } => {
1220 transform_rec(heads, f).map(|heads| RevsetExpression::Ancestors {
1221 heads,
1222 generation: generation.clone(),
1223 })
1224 }
1225 RevsetExpression::Range {
1226 roots,
1227 heads,
1228 generation,
1229 } => transform_rec_pair((roots, heads), f).map(|(roots, heads)| {
1230 RevsetExpression::Range {
1231 roots,
1232 heads,
1233 generation: generation.clone(),
1234 }
1235 }),
1236 RevsetExpression::DagRange { roots, heads } => transform_rec_pair((roots, heads), f)
1237 .map(|(roots, heads)| RevsetExpression::DagRange { roots, heads }),
1238 RevsetExpression::VisibleHeads => None,
1239 RevsetExpression::Heads(candidates) => {
1240 transform_rec(candidates, f).map(RevsetExpression::Heads)
1241 }
1242 RevsetExpression::Roots(candidates) => {
1243 transform_rec(candidates, f).map(RevsetExpression::Roots)
1244 }
1245 RevsetExpression::PublicHeads => None,
1246 RevsetExpression::Branches(_) => None,
1247 RevsetExpression::RemoteBranches { .. } => None,
1248 RevsetExpression::Tags => None,
1249 RevsetExpression::GitRefs => None,
1250 RevsetExpression::GitHead => None,
1251 RevsetExpression::Filter(_) => None,
1252 RevsetExpression::AsFilter(candidates) => {
1253 transform_rec(candidates, f).map(RevsetExpression::AsFilter)
1254 }
1255 RevsetExpression::Present(candidates) => {
1256 transform_rec(candidates, f).map(RevsetExpression::Present)
1257 }
1258 RevsetExpression::NotIn(complement) => {
1259 transform_rec(complement, f).map(RevsetExpression::NotIn)
1260 }
1261 RevsetExpression::Union(expression1, expression2) => {
1262 transform_rec_pair((expression1, expression2), f).map(
1263 |(expression1, expression2)| RevsetExpression::Union(expression1, expression2),
1264 )
1265 }
1266 RevsetExpression::Intersection(expression1, expression2) => {
1267 transform_rec_pair((expression1, expression2), f).map(
1268 |(expression1, expression2)| {
1269 RevsetExpression::Intersection(expression1, expression2)
1270 },
1271 )
1272 }
1273 RevsetExpression::Difference(expression1, expression2) => {
1274 transform_rec_pair((expression1, expression2), f).map(
1275 |(expression1, expression2)| {
1276 RevsetExpression::Difference(expression1, expression2)
1277 },
1278 )
1279 }
1280 }
1281 .map(Rc::new)
1282 }
1283
1284 fn transform_rec_pair(
1285 (expression1, expression2): (&Rc<RevsetExpression>, &Rc<RevsetExpression>),
1286 f: &mut impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>,
1287 ) -> Option<(Rc<RevsetExpression>, Rc<RevsetExpression>)> {
1288 match (transform_rec(expression1, f), transform_rec(expression2, f)) {
1289 (Some(new_expression1), Some(new_expression2)) => {
1290 Some((new_expression1, new_expression2))
1291 }
1292 (Some(new_expression1), None) => Some((new_expression1, expression2.clone())),
1293 (None, Some(new_expression2)) => Some((expression1.clone(), new_expression2)),
1294 (None, None) => None,
1295 }
1296 }
1297
1298 fn transform_rec(
1299 expression: &Rc<RevsetExpression>,
1300 f: &mut impl FnMut(&Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>>,
1301 ) -> Option<Rc<RevsetExpression>> {
1302 if let Some(new_expression) = transform_child_rec(expression, f) {
1303 Some(f(&new_expression).unwrap_or(new_expression))
1305 } else {
1306 f(expression)
1307 }
1308 }
1309
1310 transform_rec(expression, &mut f)
1311}
1312
1313fn internalize_filter(expression: &Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>> {
1322 fn is_filter(expression: &RevsetExpression) -> bool {
1323 matches!(
1324 expression,
1325 RevsetExpression::Filter(_) | RevsetExpression::AsFilter(_)
1326 )
1327 }
1328
1329 fn is_filter_tree(expression: &RevsetExpression) -> bool {
1330 is_filter(expression) || as_filter_intersection(expression).is_some()
1331 }
1332
1333 fn as_filter_intersection(
1335 expression: &RevsetExpression,
1336 ) -> Option<(&Rc<RevsetExpression>, &Rc<RevsetExpression>)> {
1337 if let RevsetExpression::Intersection(expression1, expression2) = expression {
1338 is_filter(expression2).then(|| (expression1, expression2))
1339 } else {
1340 None
1341 }
1342 }
1343
1344 fn intersect_down(
1349 expression1: &Rc<RevsetExpression>,
1350 expression2: &Rc<RevsetExpression>,
1351 ) -> Option<Rc<RevsetExpression>> {
1352 let recurse = |e1, e2| intersect_down(e1, e2).unwrap_or_else(|| e1.intersection(e2));
1353 match (expression1.as_ref(), expression2.as_ref()) {
1354 (_, e2) if is_filter(e2) => None,
1356 (e1, _) if is_filter(e1) => Some(expression2.intersection(expression1)),
1358 (e1, e2) => match (as_filter_intersection(e1), as_filter_intersection(e2)) {
1359 (_, Some((c2, f2))) => Some(recurse(expression1, c2).intersection(f2)),
1362 (Some((c1, f1)), _) => Some(recurse(c1, expression2).intersection(f1)),
1365 (None, None) => None,
1366 },
1367 }
1368 }
1369
1370 transform_expression_bottom_up(expression, |expression| match expression.as_ref() {
1376 RevsetExpression::Present(e) => {
1377 is_filter_tree(e).then(|| Rc::new(RevsetExpression::AsFilter(expression.clone())))
1378 }
1379 RevsetExpression::NotIn(e) => {
1380 is_filter_tree(e).then(|| Rc::new(RevsetExpression::AsFilter(expression.clone())))
1381 }
1382 RevsetExpression::Union(e1, e2) => (is_filter_tree(e1) || is_filter_tree(e2))
1383 .then(|| Rc::new(RevsetExpression::AsFilter(expression.clone()))),
1384 RevsetExpression::Intersection(expression1, expression2) => {
1385 intersect_down(expression1, expression2)
1386 }
1387 _ => None,
1389 })
1390}
1391
1392fn fold_redundant_expression(expression: &Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>> {
1397 transform_expression_bottom_up(expression, |expression| match expression.as_ref() {
1398 RevsetExpression::NotIn(outer) => match outer.as_ref() {
1399 RevsetExpression::NotIn(inner) => Some(inner.clone()),
1400 _ => None,
1401 },
1402 RevsetExpression::Intersection(expression1, expression2) => {
1403 match (expression1.as_ref(), expression2.as_ref()) {
1404 (_, RevsetExpression::All) => Some(expression1.clone()),
1405 (RevsetExpression::All, _) => Some(expression2.clone()),
1406 _ => None,
1407 }
1408 }
1409 _ => None,
1410 })
1411}
1412
1413fn fold_difference(expression: &Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>> {
1416 fn to_difference(
1417 expression: &Rc<RevsetExpression>,
1418 complement: &Rc<RevsetExpression>,
1419 ) -> Rc<RevsetExpression> {
1420 match (expression.as_ref(), complement.as_ref()) {
1421 (
1423 RevsetExpression::Ancestors { heads, generation },
1424 RevsetExpression::Ancestors {
1425 heads: roots,
1426 generation: GENERATION_RANGE_FULL,
1427 },
1428 ) => Rc::new(RevsetExpression::Range {
1429 roots: roots.clone(),
1430 heads: heads.clone(),
1431 generation: generation.clone(),
1432 }),
1433 _ => expression.minus(complement),
1434 }
1435 }
1436
1437 transform_expression_bottom_up(expression, |expression| match expression.as_ref() {
1438 RevsetExpression::Intersection(expression1, expression2) => {
1439 match (expression1.as_ref(), expression2.as_ref()) {
1440 (_, RevsetExpression::NotIn(complement)) => {
1441 Some(to_difference(expression1, complement))
1442 }
1443 (RevsetExpression::NotIn(complement), _) => {
1444 Some(to_difference(expression2, complement))
1445 }
1446 _ => None,
1447 }
1448 }
1449 _ => None,
1450 })
1451}
1452
1453fn unfold_difference(expression: &Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>> {
1458 transform_expression_bottom_up(expression, |expression| match expression.as_ref() {
1459 RevsetExpression::Range {
1461 roots,
1462 heads,
1463 generation,
1464 } => {
1465 let heads_ancestors = Rc::new(RevsetExpression::Ancestors {
1466 heads: heads.clone(),
1467 generation: generation.clone(),
1468 });
1469 Some(heads_ancestors.intersection(&roots.ancestors().negated()))
1470 }
1471 RevsetExpression::Difference(expression1, expression2) => {
1472 Some(expression1.intersection(&expression2.negated()))
1473 }
1474 _ => None,
1475 })
1476}
1477
1478fn fold_ancestors(expression: &Rc<RevsetExpression>) -> Option<Rc<RevsetExpression>> {
1480 transform_expression_bottom_up(expression, |expression| match expression.as_ref() {
1481 RevsetExpression::Ancestors {
1482 heads,
1483 generation: generation1,
1484 } => {
1485 match heads.as_ref() {
1486 RevsetExpression::Ancestors {
1490 heads,
1491 generation: generation2,
1492 } => {
1493 let generation = if generation1.is_empty() || generation2.is_empty() {
1495 GENERATION_RANGE_EMPTY
1496 } else {
1497 let start = u32::saturating_add(generation1.start, generation2.start);
1498 let end = u32::saturating_add(generation1.end, generation2.end - 1);
1499 start..end
1500 };
1501 Some(Rc::new(RevsetExpression::Ancestors {
1502 heads: heads.clone(),
1503 generation,
1504 }))
1505 }
1506 _ => None,
1507 }
1508 }
1509 _ => None,
1511 })
1512}
1513
1514pub fn optimize(expression: Rc<RevsetExpression>) -> Rc<RevsetExpression> {
1517 let expression = unfold_difference(&expression).unwrap_or(expression);
1518 let expression = fold_redundant_expression(&expression).unwrap_or(expression);
1519 let expression = fold_ancestors(&expression).unwrap_or(expression);
1520 let expression = internalize_filter(&expression).unwrap_or(expression);
1521 fold_difference(&expression).unwrap_or(expression)
1522}
1523
1524pub trait Revset<'repo>: ToPredicateFn<'repo> {
1525 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo>;
1527
1528 fn is_empty(&self) -> bool {
1529 self.iter().next().is_none()
1530 }
1531}
1532
1533pub trait ToPredicateFn<'repo> {
1535 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_>;
1539}
1540
1541impl<'repo, T> ToPredicateFn<'repo> for Box<T>
1542where
1543 T: ToPredicateFn<'repo> + ?Sized,
1544{
1545 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1546 <T as ToPredicateFn<'repo>>::to_predicate_fn(self)
1547 }
1548}
1549
1550pub struct RevsetIterator<'revset, 'repo: 'revset> {
1551 inner: Box<dyn Iterator<Item = IndexEntry<'repo>> + 'revset>,
1552}
1553
1554impl<'revset, 'repo> RevsetIterator<'revset, 'repo> {
1555 fn new(inner: Box<dyn Iterator<Item = IndexEntry<'repo>> + 'revset>) -> Self {
1556 Self { inner }
1557 }
1558
1559 pub fn commit_ids(self) -> RevsetCommitIdIterator<'revset, 'repo> {
1560 RevsetCommitIdIterator(self.inner)
1561 }
1562
1563 pub fn commits(self, store: &Arc<Store>) -> RevsetCommitIterator<'revset, 'repo> {
1564 RevsetCommitIterator {
1565 iter: self.inner,
1566 store: store.clone(),
1567 }
1568 }
1569
1570 pub fn reversed(self) -> ReverseRevsetIterator<'repo> {
1571 ReverseRevsetIterator {
1572 entries: self.into_iter().collect_vec(),
1573 }
1574 }
1575
1576 pub fn graph(self) -> RevsetGraphIterator<'revset, 'repo> {
1577 RevsetGraphIterator::new(self)
1578 }
1579
1580 fn into_predicate_fn(self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + 'revset> {
1581 let mut iter = self.fuse().peekable();
1582 Box::new(move |entry| {
1583 while iter.next_if(|e| e.position() > entry.position()).is_some() {
1584 continue;
1585 }
1586 iter.next_if(|e| e.position() == entry.position()).is_some()
1587 })
1588 }
1589}
1590
1591impl<'repo> Iterator for RevsetIterator<'_, 'repo> {
1592 type Item = IndexEntry<'repo>;
1593
1594 fn next(&mut self) -> Option<Self::Item> {
1595 self.inner.next()
1596 }
1597}
1598
1599pub struct RevsetCommitIdIterator<'revset, 'repo: 'revset>(
1600 Box<dyn Iterator<Item = IndexEntry<'repo>> + 'revset>,
1601);
1602
1603impl Iterator for RevsetCommitIdIterator<'_, '_> {
1604 type Item = CommitId;
1605
1606 fn next(&mut self) -> Option<Self::Item> {
1607 self.0.next().map(|index_entry| index_entry.commit_id())
1608 }
1609}
1610
1611pub struct RevsetCommitIterator<'revset, 'repo: 'revset> {
1612 store: Arc<Store>,
1613 iter: Box<dyn Iterator<Item = IndexEntry<'repo>> + 'revset>,
1614}
1615
1616impl Iterator for RevsetCommitIterator<'_, '_> {
1617 type Item = BackendResult<Commit>;
1618
1619 fn next(&mut self) -> Option<Self::Item> {
1620 self.iter
1621 .next()
1622 .map(|index_entry| self.store.get_commit(&index_entry.commit_id()))
1623 }
1624}
1625
1626pub struct ReverseRevsetIterator<'repo> {
1627 entries: Vec<IndexEntry<'repo>>,
1628}
1629
1630impl<'repo> Iterator for ReverseRevsetIterator<'repo> {
1631 type Item = IndexEntry<'repo>;
1632
1633 fn next(&mut self) -> Option<Self::Item> {
1634 self.entries.pop()
1635 }
1636}
1637
1638struct EagerRevset<'repo> {
1639 index_entries: Vec<IndexEntry<'repo>>,
1640}
1641
1642impl EagerRevset<'static> {
1643 pub const fn empty() -> Self {
1644 EagerRevset {
1645 index_entries: Vec::new(),
1646 }
1647 }
1648}
1649
1650impl<'repo> Revset<'repo> for EagerRevset<'repo> {
1651 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo> {
1652 RevsetIterator::new(Box::new(self.index_entries.iter().cloned()))
1653 }
1654}
1655
1656impl<'repo> ToPredicateFn<'repo> for EagerRevset<'repo> {
1657 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1658 self.iter().into_predicate_fn()
1659 }
1660}
1661
1662struct RevWalkRevset<'repo, T>
1663where
1664 T: Iterator<Item = IndexEntry<'repo>>,
1667{
1668 walk: T,
1669}
1670
1671impl<'repo, T> Revset<'repo> for RevWalkRevset<'repo, T>
1672where
1673 T: Iterator<Item = IndexEntry<'repo>> + Clone,
1674{
1675 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo> {
1676 RevsetIterator::new(Box::new(self.walk.clone()))
1677 }
1678}
1679
1680impl<'repo, T> ToPredicateFn<'repo> for RevWalkRevset<'repo, T>
1681where
1682 T: Iterator<Item = IndexEntry<'repo>> + Clone,
1683{
1684 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1685 self.iter().into_predicate_fn()
1686 }
1687}
1688
1689struct ChildrenRevset<'revset, 'repo: 'revset> {
1690 root_set: Box<dyn Revset<'repo> + 'revset>,
1692 candidate_set: Box<dyn Revset<'repo> + 'revset>,
1694}
1695
1696impl<'repo> Revset<'repo> for ChildrenRevset<'_, 'repo> {
1697 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo> {
1698 let roots: HashSet<_> = self
1699 .root_set
1700 .iter()
1701 .map(|parent| parent.position())
1702 .collect();
1703
1704 RevsetIterator::new(Box::new(self.candidate_set.iter().filter(
1705 move |candidate| {
1706 candidate
1707 .parent_positions()
1708 .iter()
1709 .any(|parent_pos| roots.contains(parent_pos))
1710 },
1711 )))
1712 }
1713}
1714
1715impl<'repo> ToPredicateFn<'repo> for ChildrenRevset<'_, 'repo> {
1716 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1717 self.iter().into_predicate_fn()
1719 }
1720}
1721
1722struct FilterRevset<'revset, 'repo: 'revset, P> {
1723 candidates: Box<dyn Revset<'repo> + 'revset>,
1724 predicate: P,
1725}
1726
1727impl<'repo, P> Revset<'repo> for FilterRevset<'_, 'repo, P>
1728where
1729 P: ToPredicateFn<'repo>,
1730{
1731 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo> {
1732 let p = self.predicate.to_predicate_fn();
1733 RevsetIterator::new(Box::new(self.candidates.iter().filter(p)))
1734 }
1735}
1736
1737impl<'repo, P> ToPredicateFn<'repo> for FilterRevset<'_, 'repo, P>
1738where
1739 P: ToPredicateFn<'repo>,
1740{
1741 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1742 let mut p1 = self.candidates.to_predicate_fn();
1744 let mut p2 = self.predicate.to_predicate_fn();
1745 Box::new(move |entry| p1(entry) && p2(entry))
1746 }
1747}
1748
1749struct UnionRevset<'revset, 'repo: 'revset> {
1750 set1: Box<dyn Revset<'repo> + 'revset>,
1751 set2: Box<dyn Revset<'repo> + 'revset>,
1752}
1753
1754impl<'repo> Revset<'repo> for UnionRevset<'_, 'repo> {
1755 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo> {
1756 RevsetIterator::new(Box::new(UnionRevsetIterator {
1757 iter1: self.set1.iter().peekable(),
1758 iter2: self.set2.iter().peekable(),
1759 }))
1760 }
1761}
1762
1763impl<'repo> ToPredicateFn<'repo> for UnionRevset<'_, 'repo> {
1764 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1765 let mut p1 = self.set1.to_predicate_fn();
1766 let mut p2 = self.set2.to_predicate_fn();
1767 Box::new(move |entry| p1(entry) || p2(entry))
1768 }
1769}
1770
1771struct UnionRevsetIterator<'revset, 'repo> {
1772 iter1: Peekable<RevsetIterator<'revset, 'repo>>,
1773 iter2: Peekable<RevsetIterator<'revset, 'repo>>,
1774}
1775
1776impl<'revset, 'repo> Iterator for UnionRevsetIterator<'revset, 'repo> {
1777 type Item = IndexEntry<'repo>;
1778
1779 fn next(&mut self) -> Option<Self::Item> {
1780 match (self.iter1.peek(), self.iter2.peek()) {
1781 (None, _) => self.iter2.next(),
1782 (_, None) => self.iter1.next(),
1783 (Some(entry1), Some(entry2)) => match entry1.position().cmp(&entry2.position()) {
1784 Ordering::Less => self.iter2.next(),
1785 Ordering::Equal => {
1786 self.iter1.next();
1787 self.iter2.next()
1788 }
1789 Ordering::Greater => self.iter1.next(),
1790 },
1791 }
1792 }
1793}
1794
1795struct IntersectionRevset<'revset, 'repo: 'revset> {
1796 set1: Box<dyn Revset<'repo> + 'revset>,
1797 set2: Box<dyn Revset<'repo> + 'revset>,
1798}
1799
1800impl<'repo> Revset<'repo> for IntersectionRevset<'_, 'repo> {
1801 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo> {
1802 RevsetIterator::new(Box::new(IntersectionRevsetIterator {
1803 iter1: self.set1.iter().peekable(),
1804 iter2: self.set2.iter().peekable(),
1805 }))
1806 }
1807}
1808
1809impl<'repo> ToPredicateFn<'repo> for IntersectionRevset<'_, 'repo> {
1810 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1811 let mut p1 = self.set1.to_predicate_fn();
1812 let mut p2 = self.set2.to_predicate_fn();
1813 Box::new(move |entry| p1(entry) && p2(entry))
1814 }
1815}
1816
1817struct IntersectionRevsetIterator<'revset, 'repo> {
1818 iter1: Peekable<RevsetIterator<'revset, 'repo>>,
1819 iter2: Peekable<RevsetIterator<'revset, 'repo>>,
1820}
1821
1822impl<'revset, 'repo> Iterator for IntersectionRevsetIterator<'revset, 'repo> {
1823 type Item = IndexEntry<'repo>;
1824
1825 fn next(&mut self) -> Option<Self::Item> {
1826 loop {
1827 match (self.iter1.peek(), self.iter2.peek()) {
1828 (None, _) => {
1829 return None;
1830 }
1831 (_, None) => {
1832 return None;
1833 }
1834 (Some(entry1), Some(entry2)) => match entry1.position().cmp(&entry2.position()) {
1835 Ordering::Less => {
1836 self.iter2.next();
1837 }
1838 Ordering::Equal => {
1839 self.iter1.next();
1840 return self.iter2.next();
1841 }
1842 Ordering::Greater => {
1843 self.iter1.next();
1844 }
1845 },
1846 }
1847 }
1848 }
1849}
1850
1851struct DifferenceRevset<'revset, 'repo: 'revset> {
1852 set1: Box<dyn Revset<'repo> + 'revset>,
1854 set2: Box<dyn Revset<'repo> + 'revset>,
1856}
1857
1858impl<'repo> Revset<'repo> for DifferenceRevset<'_, 'repo> {
1859 fn iter<'revset>(&'revset self) -> RevsetIterator<'revset, 'repo> {
1860 RevsetIterator::new(Box::new(DifferenceRevsetIterator {
1861 iter1: self.set1.iter().peekable(),
1862 iter2: self.set2.iter().peekable(),
1863 }))
1864 }
1865}
1866
1867impl<'repo> ToPredicateFn<'repo> for DifferenceRevset<'_, 'repo> {
1868 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
1869 let mut p1 = self.set1.to_predicate_fn();
1871 let mut p2 = self.set2.to_predicate_fn();
1872 Box::new(move |entry| p1(entry) && !p2(entry))
1873 }
1874}
1875
1876struct DifferenceRevsetIterator<'revset, 'repo> {
1877 iter1: Peekable<RevsetIterator<'revset, 'repo>>,
1878 iter2: Peekable<RevsetIterator<'revset, 'repo>>,
1879}
1880
1881impl<'revset, 'repo> Iterator for DifferenceRevsetIterator<'revset, 'repo> {
1882 type Item = IndexEntry<'repo>;
1883
1884 fn next(&mut self) -> Option<Self::Item> {
1885 loop {
1886 match (self.iter1.peek(), self.iter2.peek()) {
1887 (None, _) => {
1888 return None;
1889 }
1890 (_, None) => {
1891 return self.iter1.next();
1892 }
1893 (Some(entry1), Some(entry2)) => match entry1.position().cmp(&entry2.position()) {
1894 Ordering::Less => {
1895 self.iter2.next();
1896 }
1897 Ordering::Equal => {
1898 self.iter2.next();
1899 self.iter1.next();
1900 }
1901 Ordering::Greater => {
1902 return self.iter1.next();
1903 }
1904 },
1905 }
1906 }
1907 }
1908}
1909
1910#[derive(Clone, Debug)]
1912pub struct RevsetWorkspaceContext<'a> {
1913 pub cwd: &'a Path,
1914 pub workspace_id: &'a WorkspaceId,
1915 pub workspace_root: &'a Path,
1916}
1917
1918pub fn evaluate_expression<'repo>(
1919 repo: &'repo dyn Repo,
1920 expression: &RevsetExpression,
1921 workspace_ctx: Option<&RevsetWorkspaceContext>,
1922) -> Result<Box<dyn Revset<'repo> + 'repo>, RevsetError> {
1923 match expression {
1924 RevsetExpression::None => Ok(Box::new(EagerRevset::empty())),
1925 RevsetExpression::All => {
1926 evaluate_expression(
1934 repo,
1935 &RevsetExpression::visible_heads().ancestors(),
1936 workspace_ctx,
1937 )
1938 }
1939 RevsetExpression::Commits(commit_ids) => Ok(revset_for_commit_ids(repo, commit_ids)),
1940 RevsetExpression::Symbol(symbol) => {
1941 let commit_ids = resolve_symbol(repo, symbol, workspace_ctx.map(|c| c.workspace_id))?;
1942 evaluate_expression(repo, &RevsetExpression::Commits(commit_ids), workspace_ctx)
1943 }
1944 RevsetExpression::Children(roots) => {
1945 let root_set = roots.evaluate(repo, workspace_ctx)?;
1946 let candidates_expression = roots.descendants();
1947 let candidate_set = candidates_expression.evaluate(repo, workspace_ctx)?;
1948 Ok(Box::new(ChildrenRevset {
1949 root_set,
1950 candidate_set,
1951 }))
1952 }
1953 RevsetExpression::Ancestors { heads, generation } => {
1954 let range_expression = RevsetExpression::Range {
1955 roots: RevsetExpression::none(),
1956 heads: heads.clone(),
1957 generation: generation.clone(),
1958 };
1959 range_expression.evaluate(repo, workspace_ctx)
1960 }
1961 RevsetExpression::Range {
1962 roots,
1963 heads,
1964 generation,
1965 } => {
1966 let root_set = roots.evaluate(repo, workspace_ctx)?;
1967 let root_ids = root_set.iter().commit_ids().collect_vec();
1968 let head_set = heads.evaluate(repo, workspace_ctx)?;
1969 let head_ids = head_set.iter().commit_ids().collect_vec();
1970 let walk = repo.index().walk_revs(&head_ids, &root_ids);
1971 if generation == &GENERATION_RANGE_FULL {
1972 Ok(Box::new(RevWalkRevset { walk }))
1973 } else {
1974 let walk = walk.filter_by_generation(generation.clone());
1975 Ok(Box::new(RevWalkRevset { walk }))
1976 }
1977 }
1978 RevsetExpression::DagRange { roots, heads } => {
1979 let root_set = roots.evaluate(repo, workspace_ctx)?;
1980 let candidate_set = heads.ancestors().evaluate(repo, workspace_ctx)?;
1981 let mut reachable: HashSet<_> = root_set.iter().map(|entry| entry.position()).collect();
1982 let mut result = vec![];
1983 let candidates = candidate_set.iter().collect_vec();
1984 for candidate in candidates.into_iter().rev() {
1985 if reachable.contains(&candidate.position())
1986 || candidate
1987 .parent_positions()
1988 .iter()
1989 .any(|parent_pos| reachable.contains(parent_pos))
1990 {
1991 reachable.insert(candidate.position());
1992 result.push(candidate);
1993 }
1994 }
1995 result.reverse();
1996 Ok(Box::new(EagerRevset {
1997 index_entries: result,
1998 }))
1999 }
2000 RevsetExpression::VisibleHeads => Ok(revset_for_commit_ids(
2001 repo,
2002 &repo.view().heads().iter().cloned().collect_vec(),
2003 )),
2004 RevsetExpression::Heads(candidates) => {
2005 let candidate_set = candidates.evaluate(repo, workspace_ctx)?;
2006 let candidate_ids = candidate_set.iter().commit_ids().collect_vec();
2007 Ok(revset_for_commit_ids(
2008 repo,
2009 &repo.index().heads(&mut candidate_ids.iter()),
2010 ))
2011 }
2012 RevsetExpression::Roots(candidates) => {
2013 let connected_set = candidates.connected().evaluate(repo, workspace_ctx)?;
2014 let filled: HashSet<_> = connected_set.iter().map(|entry| entry.position()).collect();
2015 let mut index_entries = vec![];
2016 let candidate_set = candidates.evaluate(repo, workspace_ctx)?;
2017 for candidate in candidate_set.iter() {
2018 if !candidate
2019 .parent_positions()
2020 .iter()
2021 .any(|parent| filled.contains(parent))
2022 {
2023 index_entries.push(candidate);
2024 }
2025 }
2026 Ok(Box::new(EagerRevset { index_entries }))
2027 }
2028 RevsetExpression::PublicHeads => Ok(revset_for_commit_ids(
2029 repo,
2030 &repo.view().public_heads().iter().cloned().collect_vec(),
2031 )),
2032 RevsetExpression::Branches(needle) => {
2033 let mut commit_ids = vec![];
2034 for (branch_name, branch_target) in repo.view().branches() {
2035 if !branch_name.contains(needle) {
2036 continue;
2037 }
2038 if let Some(local_target) = &branch_target.local_target {
2039 commit_ids.extend(local_target.adds());
2040 }
2041 }
2042 Ok(revset_for_commit_ids(repo, &commit_ids))
2043 }
2044 RevsetExpression::RemoteBranches {
2045 branch_needle,
2046 remote_needle,
2047 } => {
2048 let mut commit_ids = vec![];
2049 for (branch_name, branch_target) in repo.view().branches() {
2050 if !branch_name.contains(branch_needle) {
2051 continue;
2052 }
2053 for (remote_name, remote_target) in branch_target.remote_targets.iter() {
2054 if remote_name.contains(remote_needle) {
2055 commit_ids.extend(remote_target.adds());
2056 }
2057 }
2058 }
2059 Ok(revset_for_commit_ids(repo, &commit_ids))
2060 }
2061 RevsetExpression::Tags => {
2062 let mut commit_ids = vec![];
2063 for ref_target in repo.view().tags().values() {
2064 commit_ids.extend(ref_target.adds());
2065 }
2066 Ok(revset_for_commit_ids(repo, &commit_ids))
2067 }
2068 RevsetExpression::GitRefs => {
2069 let mut commit_ids = vec![];
2070 for ref_target in repo.view().git_refs().values() {
2071 commit_ids.extend(ref_target.adds());
2072 }
2073 Ok(revset_for_commit_ids(repo, &commit_ids))
2074 }
2075 RevsetExpression::GitHead => {
2076 let mut commit_ids = vec![];
2077 if let Some(ref_target) = repo.view().git_head() {
2078 commit_ids.extend(ref_target.adds());
2079 }
2080 Ok(revset_for_commit_ids(repo, &commit_ids))
2081 }
2082 RevsetExpression::Filter(predicate) => Ok(Box::new(FilterRevset {
2083 candidates: RevsetExpression::All.evaluate(repo, workspace_ctx)?,
2084 predicate: build_predicate_fn(repo, predicate),
2085 })),
2086 RevsetExpression::AsFilter(candidates) => candidates.evaluate(repo, workspace_ctx),
2087 RevsetExpression::Present(candidates) => match candidates.evaluate(repo, workspace_ctx) {
2088 Ok(set) => Ok(set),
2089 Err(RevsetError::NoSuchRevision(_)) => Ok(Box::new(EagerRevset::empty())),
2090 r @ Err(RevsetError::AmbiguousIdPrefix(_) | RevsetError::StoreError(_)) => r,
2091 },
2092 RevsetExpression::NotIn(complement) => {
2093 let set1 = RevsetExpression::All.evaluate(repo, workspace_ctx)?;
2094 let set2 = complement.evaluate(repo, workspace_ctx)?;
2095 Ok(Box::new(DifferenceRevset { set1, set2 }))
2096 }
2097 RevsetExpression::Union(expression1, expression2) => {
2098 let set1 = expression1.evaluate(repo, workspace_ctx)?;
2099 let set2 = expression2.evaluate(repo, workspace_ctx)?;
2100 Ok(Box::new(UnionRevset { set1, set2 }))
2101 }
2102 RevsetExpression::Intersection(expression1, expression2) => {
2103 match expression2.as_ref() {
2104 RevsetExpression::Filter(predicate) => Ok(Box::new(FilterRevset {
2105 candidates: expression1.evaluate(repo, workspace_ctx)?,
2106 predicate: build_predicate_fn(repo, predicate),
2107 })),
2108 RevsetExpression::AsFilter(expression2) => Ok(Box::new(FilterRevset {
2109 candidates: expression1.evaluate(repo, workspace_ctx)?,
2110 predicate: expression2.evaluate(repo, workspace_ctx)?,
2111 })),
2112 _ => {
2113 let set1 = expression1.evaluate(repo, workspace_ctx)?;
2116 let set2 = expression2.evaluate(repo, workspace_ctx)?;
2117 Ok(Box::new(IntersectionRevset { set1, set2 }))
2118 }
2119 }
2120 }
2121 RevsetExpression::Difference(expression1, expression2) => {
2122 let set1 = expression1.evaluate(repo, workspace_ctx)?;
2123 let set2 = expression2.evaluate(repo, workspace_ctx)?;
2124 Ok(Box::new(DifferenceRevset { set1, set2 }))
2125 }
2126 }
2127}
2128
2129fn revset_for_commit_ids<'revset, 'repo: 'revset>(
2130 repo: &'repo dyn Repo,
2131 commit_ids: &[CommitId],
2132) -> Box<dyn Revset<'repo> + 'revset> {
2133 let index = repo.index();
2134 let mut index_entries = vec![];
2135 for id in commit_ids {
2136 index_entries.push(index.entry_by_id(id).unwrap());
2137 }
2138 index_entries.sort_by_key(|b| Reverse(b.position()));
2139 index_entries.dedup();
2140 Box::new(EagerRevset { index_entries })
2141}
2142
2143pub fn revset_for_commits<'revset, 'repo: 'revset>(
2144 repo: &'repo dyn Repo,
2145 commits: &[&Commit],
2146) -> Box<dyn Revset<'repo> + 'revset> {
2147 let index = repo.index();
2148 let mut index_entries = commits
2149 .iter()
2150 .map(|commit| index.entry_by_id(commit.id()).unwrap())
2151 .collect_vec();
2152 index_entries.sort_by_key(|b| Reverse(b.position()));
2153 Box::new(EagerRevset { index_entries })
2154}
2155
2156type PurePredicateFn<'repo> = Box<dyn Fn(&IndexEntry<'repo>) -> bool + 'repo>;
2157
2158impl<'repo> ToPredicateFn<'repo> for PurePredicateFn<'repo> {
2159 fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'repo>) -> bool + '_> {
2160 Box::new(self)
2161 }
2162}
2163
2164fn build_predicate_fn<'repo>(
2165 repo: &'repo dyn Repo,
2166 predicate: &RevsetFilterPredicate,
2167) -> PurePredicateFn<'repo> {
2168 match predicate {
2169 RevsetFilterPredicate::ParentCount(parent_count_range) => {
2170 let parent_count_range = parent_count_range.clone();
2171 Box::new(move |entry| parent_count_range.contains(&entry.num_parents()))
2172 }
2173 RevsetFilterPredicate::Description(needle) => {
2174 let needle = needle.clone();
2175 Box::new(move |entry| {
2176 repo.store()
2177 .get_commit(&entry.commit_id())
2178 .unwrap()
2179 .description()
2180 .contains(needle.as_str())
2181 })
2182 }
2183 RevsetFilterPredicate::Author(needle) => {
2184 let needle = needle.clone();
2185 Box::new(move |entry| {
2189 let commit = repo.store().get_commit(&entry.commit_id()).unwrap();
2190 commit.author().name.contains(needle.as_str())
2191 || commit.author().email.contains(needle.as_str())
2192 })
2193 }
2194 RevsetFilterPredicate::Committer(needle) => {
2195 let needle = needle.clone();
2196 Box::new(move |entry| {
2197 let commit = repo.store().get_commit(&entry.commit_id()).unwrap();
2198 commit.committer().name.contains(needle.as_str())
2199 || commit.committer().email.contains(needle.as_str())
2200 })
2201 }
2202 RevsetFilterPredicate::File(paths) => {
2203 let matcher: Box<dyn Matcher> = if let Some(paths) = paths {
2205 Box::new(PrefixMatcher::new(paths))
2206 } else {
2207 Box::new(EverythingMatcher)
2208 };
2209 Box::new(move |entry| has_diff_from_parent(repo, entry, matcher.as_ref()))
2210 }
2211 }
2212}
2213
2214pub fn filter_by_diff<'revset, 'repo: 'revset>(
2215 repo: &'repo dyn Repo,
2216 matcher: impl Borrow<dyn Matcher + 'repo> + 'repo,
2217 candidates: Box<dyn Revset<'repo> + 'revset>,
2218) -> Box<dyn Revset<'repo> + 'revset> {
2219 Box::new(FilterRevset::<PurePredicateFn> {
2220 candidates,
2221 predicate: Box::new(move |entry| has_diff_from_parent(repo, entry, matcher.borrow())),
2222 })
2223}
2224
2225fn has_diff_from_parent(repo: &dyn Repo, entry: &IndexEntry<'_>, matcher: &dyn Matcher) -> bool {
2226 let commit = repo.store().get_commit(&entry.commit_id()).unwrap();
2227 let parents = commit.parents();
2228 let from_tree = rewrite::merge_commit_trees(repo, &parents);
2229 let to_tree = commit.tree();
2230 from_tree.diff(&to_tree, matcher).next().is_some()
2231}
2232
2233#[cfg(test)]
2234mod tests {
2235 use super::*;
2236 use crate::backend::ChangeId;
2237 use crate::index::{Index, MutableIndex};
2238
2239 fn change_id_generator() -> impl FnMut() -> ChangeId {
2241 let mut iter = (1_u128..).map(|n| ChangeId::new(n.to_le_bytes().into()));
2242 move || iter.next().unwrap()
2243 }
2244
2245 fn parse(revset_str: &str) -> Result<Rc<RevsetExpression>, RevsetParseErrorKind> {
2246 parse_with_aliases(revset_str, [] as [(&str, &str); 0])
2247 }
2248
2249 fn parse_with_aliases(
2250 revset_str: &str,
2251 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
2252 ) -> Result<Rc<RevsetExpression>, RevsetParseErrorKind> {
2253 let mut aliases_map = RevsetAliasesMap::new();
2254 for (decl, defn) in aliases {
2255 aliases_map.insert(decl, defn).unwrap();
2256 }
2257 let workspace_ctx = RevsetWorkspaceContext {
2259 cwd: Path::new("/"),
2260 workspace_id: &WorkspaceId::default(),
2261 workspace_root: Path::new("/"),
2262 };
2263 super::parse(revset_str, &aliases_map, Some(&workspace_ctx)).map_err(|e| e.kind)
2265 }
2266
2267 #[test]
2268 fn test_revset_expression_building() {
2269 let wc_symbol = RevsetExpression::symbol("@".to_string());
2270 let foo_symbol = RevsetExpression::symbol("foo".to_string());
2271 assert_eq!(
2272 wc_symbol,
2273 Rc::new(RevsetExpression::Symbol("@".to_string()))
2274 );
2275 assert_eq!(
2276 wc_symbol.heads(),
2277 Rc::new(RevsetExpression::Heads(wc_symbol.clone()))
2278 );
2279 assert_eq!(
2280 wc_symbol.roots(),
2281 Rc::new(RevsetExpression::Roots(wc_symbol.clone()))
2282 );
2283 assert_eq!(
2284 wc_symbol.parents(),
2285 Rc::new(RevsetExpression::Ancestors {
2286 heads: wc_symbol.clone(),
2287 generation: 1..2,
2288 })
2289 );
2290 assert_eq!(
2291 wc_symbol.ancestors(),
2292 Rc::new(RevsetExpression::Ancestors {
2293 heads: wc_symbol.clone(),
2294 generation: GENERATION_RANGE_FULL,
2295 })
2296 );
2297 assert_eq!(
2298 foo_symbol.children(),
2299 Rc::new(RevsetExpression::Children(foo_symbol.clone()))
2300 );
2301 assert_eq!(
2302 foo_symbol.descendants(),
2303 Rc::new(RevsetExpression::DagRange {
2304 roots: foo_symbol.clone(),
2305 heads: RevsetExpression::visible_heads(),
2306 })
2307 );
2308 assert_eq!(
2309 foo_symbol.dag_range_to(&wc_symbol),
2310 Rc::new(RevsetExpression::DagRange {
2311 roots: foo_symbol.clone(),
2312 heads: wc_symbol.clone(),
2313 })
2314 );
2315 assert_eq!(
2316 foo_symbol.connected(),
2317 Rc::new(RevsetExpression::DagRange {
2318 roots: foo_symbol.clone(),
2319 heads: foo_symbol.clone(),
2320 })
2321 );
2322 assert_eq!(
2323 foo_symbol.range(&wc_symbol),
2324 Rc::new(RevsetExpression::Range {
2325 roots: foo_symbol.clone(),
2326 heads: wc_symbol.clone(),
2327 generation: GENERATION_RANGE_FULL,
2328 })
2329 );
2330 assert_eq!(
2331 foo_symbol.negated(),
2332 Rc::new(RevsetExpression::NotIn(foo_symbol.clone()))
2333 );
2334 assert_eq!(
2335 foo_symbol.union(&wc_symbol),
2336 Rc::new(RevsetExpression::Union(
2337 foo_symbol.clone(),
2338 wc_symbol.clone()
2339 ))
2340 );
2341 assert_eq!(
2342 foo_symbol.intersection(&wc_symbol),
2343 Rc::new(RevsetExpression::Intersection(
2344 foo_symbol.clone(),
2345 wc_symbol.clone()
2346 ))
2347 );
2348 assert_eq!(
2349 foo_symbol.minus(&wc_symbol),
2350 Rc::new(RevsetExpression::Difference(foo_symbol, wc_symbol.clone()))
2351 );
2352 }
2353
2354 #[test]
2355 fn test_parse_revset() {
2356 let wc_symbol = RevsetExpression::symbol("@".to_string());
2357 let foo_symbol = RevsetExpression::symbol("foo".to_string());
2358 let bar_symbol = RevsetExpression::symbol("bar".to_string());
2359 assert_eq!(parse("@"), Ok(wc_symbol.clone()));
2361 assert_eq!(parse("foo"), Ok(foo_symbol.clone()));
2363 assert_eq!(
2365 parse("foo.bar-v1+7"),
2366 Ok(RevsetExpression::symbol("foo.bar-v1+7".to_string()))
2367 );
2368 assert_eq!(
2369 parse("foo.bar-v1+7-"),
2370 Ok(RevsetExpression::symbol("foo.bar-v1+7".to_string()).parents())
2371 );
2372 assert_eq!(parse("branches()"), parse(r#"branches("")"#));
2374 assert_eq!(parse("remote_branches()"), parse(r#"remote_branches("")"#));
2375 assert_eq!(
2376 parse("remote_branches()"),
2377 parse(r#"remote_branches("", "")"#)
2378 );
2379 assert_eq!(parse(".foo"), Err(RevsetParseErrorKind::SyntaxError));
2381 assert_eq!(parse("foo."), Err(RevsetParseErrorKind::SyntaxError));
2382 assert_eq!(parse("foo.+bar"), Err(RevsetParseErrorKind::SyntaxError));
2384 assert_eq!(parse("foo--bar"), Err(RevsetParseErrorKind::SyntaxError));
2385 assert_eq!(parse("foo+-bar"), Err(RevsetParseErrorKind::SyntaxError));
2386 assert_eq!(parse("(foo)"), Ok(foo_symbol.clone()));
2388 assert_eq!(parse("\"foo\""), Ok(foo_symbol.clone()));
2390 assert_eq!(parse("@-"), Ok(wc_symbol.parents()));
2392 assert_eq!(parse("@+"), Ok(wc_symbol.children()));
2394 assert_eq!(parse(":@"), Ok(wc_symbol.ancestors()));
2396 assert_eq!(parse("@:"), Ok(wc_symbol.descendants()));
2398 assert_eq!(parse("foo:bar"), Ok(foo_symbol.dag_range_to(&bar_symbol)));
2400 assert_eq!(parse("..@"), Ok(wc_symbol.ancestors()));
2402 assert_eq!(
2403 parse("@.."),
2404 Ok(wc_symbol.range(&RevsetExpression::visible_heads()))
2405 );
2406 assert_eq!(parse("foo..bar"), Ok(foo_symbol.range(&bar_symbol)));
2407 assert_eq!(parse("~ foo"), Ok(foo_symbol.negated()));
2409 assert_eq!(
2410 parse("~ ~~ foo"),
2411 Ok(foo_symbol.negated().negated().negated())
2412 );
2413 assert_eq!(parse("foo & bar"), Ok(foo_symbol.intersection(&bar_symbol)));
2415 assert_eq!(parse("foo | bar"), Ok(foo_symbol.union(&bar_symbol)));
2417 assert_eq!(parse("foo ~ bar"), Ok(foo_symbol.minus(&bar_symbol)));
2419 assert_eq!(parse("(@)-"), Ok(wc_symbol.parents()));
2421 assert_eq!(parse(" :@ "), Ok(wc_symbol.ancestors()));
2423 assert_eq!(parse("( :@ )"), Ok(wc_symbol.ancestors()));
2424 assert_eq!(parse(" : @ "), Err(RevsetParseErrorKind::SyntaxError));
2426 assert_eq!(parse("foo | -"), Err(RevsetParseErrorKind::SyntaxError));
2428 assert_eq!(
2430 parse(" description( arg1 ) ~ file( arg1 , arg2 ) ~ heads( ) "),
2431 Ok(
2432 RevsetExpression::filter(RevsetFilterPredicate::Description("arg1".to_string()))
2433 .minus(&RevsetExpression::filter(RevsetFilterPredicate::File(
2434 Some(vec![
2435 RepoPath::from_internal_string("arg1"),
2436 RepoPath::from_internal_string("arg2"),
2437 ])
2438 )))
2439 .minus(&RevsetExpression::visible_heads())
2440 )
2441 );
2442 assert_eq!(
2444 parse("remote_branches( remote = foo )").unwrap(),
2445 parse("remote_branches(remote=foo)").unwrap(),
2446 );
2447
2448 assert!(parse("branches(,)").is_err());
2450 assert!(parse("branches(a,)").is_ok());
2452 assert!(parse("branches(a , )").is_ok());
2453 assert!(parse("branches(,a)").is_err());
2454 assert!(parse("branches(a,,)").is_err());
2455 assert!(parse("branches(a , , )").is_err());
2456 assert!(parse("file(a,b,)").is_ok());
2457 assert!(parse("file(a,,b)").is_err());
2458 assert!(parse("remote_branches(a,remote=b , )").is_ok());
2459 assert!(parse("remote_branches(a,,remote=b)").is_err());
2460 }
2461
2462 #[test]
2463 fn test_parse_revset_alias_formal_parameter() {
2464 let mut aliases_map = RevsetAliasesMap::new();
2465 assert!(aliases_map.insert("f(,)", "none()").is_err());
2467 assert!(aliases_map.insert("g(a,)", "none()").is_ok());
2469 assert!(aliases_map.insert("h(a , )", "none()").is_ok());
2470 assert!(aliases_map.insert("i(,a)", "none()").is_err());
2471 assert!(aliases_map.insert("j(a,,)", "none()").is_err());
2472 assert!(aliases_map.insert("k(a , , )", "none()").is_err());
2473 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
2474 assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
2475 }
2476
2477 #[test]
2478 fn test_parse_revset_compat_operator() {
2479 assert_eq!(
2480 parse("foo^"),
2481 Err(RevsetParseErrorKind::NotPostfixOperator {
2482 op: "^".to_owned(),
2483 similar_op: "-".to_owned(),
2484 description: "parents".to_owned(),
2485 })
2486 );
2487 assert_eq!(
2488 parse("foo + bar"),
2489 Err(RevsetParseErrorKind::NotInfixOperator {
2490 op: "+".to_owned(),
2491 similar_op: "|".to_owned(),
2492 description: "union".to_owned(),
2493 })
2494 );
2495 assert_eq!(
2496 parse("foo - bar"),
2497 Err(RevsetParseErrorKind::NotInfixOperator {
2498 op: "-".to_owned(),
2499 similar_op: "~".to_owned(),
2500 description: "difference".to_owned(),
2501 })
2502 );
2503 }
2504
2505 #[test]
2506 fn test_parse_revset_operator_combinations() {
2507 let foo_symbol = RevsetExpression::symbol("foo".to_string());
2508 assert_eq!(
2510 parse("foo---"),
2511 Ok(foo_symbol.parents().parents().parents())
2512 );
2513 assert_eq!(
2515 parse("foo+++"),
2516 Ok(foo_symbol.children().children().children())
2517 );
2518 assert_eq!(parse("~x|y").unwrap(), parse("(~x)|y").unwrap());
2520 assert_eq!(parse("x&~y").unwrap(), parse("x&(~y)").unwrap());
2521 assert_eq!(parse("x~~y").unwrap(), parse("x~(~y)").unwrap());
2522 assert_eq!(parse("x~~~y").unwrap(), parse("x~(~(~y))").unwrap());
2523 assert_eq!(parse("~x:y").unwrap(), parse("~(x:y)").unwrap());
2524 assert_eq!(parse("x|y|z").unwrap(), parse("(x|y)|z").unwrap());
2525 assert_eq!(parse("x&y|z").unwrap(), parse("(x&y)|z").unwrap());
2526 assert_eq!(parse("x|y&z").unwrap(), parse("x|(y&z)").unwrap());
2527 assert_eq!(parse("x|y~z").unwrap(), parse("x|(y~z)").unwrap());
2528 assert_eq!(parse(":foo:"), Err(RevsetParseErrorKind::SyntaxError));
2530 assert_eq!(parse("::foo"), Err(RevsetParseErrorKind::SyntaxError));
2531 assert_eq!(parse("foo::"), Err(RevsetParseErrorKind::SyntaxError));
2532 assert_eq!(parse("foo::bar"), Err(RevsetParseErrorKind::SyntaxError));
2533 assert_eq!(parse(":foo:bar"), Err(RevsetParseErrorKind::SyntaxError));
2534 assert_eq!(parse("foo:bar:"), Err(RevsetParseErrorKind::SyntaxError));
2535 assert_eq!(parse("....foo"), Err(RevsetParseErrorKind::SyntaxError));
2536 assert_eq!(parse("foo...."), Err(RevsetParseErrorKind::SyntaxError));
2537 assert_eq!(parse("foo.....bar"), Err(RevsetParseErrorKind::SyntaxError));
2538 assert_eq!(parse("..foo..bar"), Err(RevsetParseErrorKind::SyntaxError));
2539 assert_eq!(parse("foo..bar.."), Err(RevsetParseErrorKind::SyntaxError));
2540 assert_eq!(parse("foo-+"), Ok(foo_symbol.parents().children()));
2543 assert_eq!(parse("foo-:"), Ok(foo_symbol.parents().descendants()));
2544 assert_eq!(parse(":foo+"), Ok(foo_symbol.children().ancestors()));
2545 }
2546
2547 #[test]
2548 fn test_parse_revset_function() {
2549 let wc_symbol = RevsetExpression::symbol("@".to_string());
2550 assert_eq!(parse("parents(@)"), Ok(wc_symbol.parents()));
2551 assert_eq!(parse("parents((@))"), Ok(wc_symbol.parents()));
2552 assert_eq!(parse("parents(\"@\")"), Ok(wc_symbol.parents()));
2553 assert_eq!(
2554 parse("ancestors(parents(@))"),
2555 Ok(wc_symbol.parents().ancestors())
2556 );
2557 assert_eq!(parse("parents(@"), Err(RevsetParseErrorKind::SyntaxError));
2558 assert_eq!(
2559 parse("parents(@,@)"),
2560 Err(RevsetParseErrorKind::InvalidFunctionArguments {
2561 name: "parents".to_string(),
2562 message: "Expected 1 arguments".to_string()
2563 })
2564 );
2565 assert_eq!(
2566 parse(r#"description("")"#),
2567 Ok(RevsetExpression::filter(
2568 RevsetFilterPredicate::Description("".to_string())
2569 ))
2570 );
2571 assert_eq!(
2572 parse("description(foo)"),
2573 Ok(RevsetExpression::filter(
2574 RevsetFilterPredicate::Description("foo".to_string())
2575 ))
2576 );
2577 assert_eq!(
2578 parse("description(heads())"),
2579 Err(RevsetParseErrorKind::InvalidFunctionArguments {
2580 name: "description".to_string(),
2581 message: "Expected function argument of type string".to_string()
2582 })
2583 );
2584 assert_eq!(
2585 parse("description((foo))"),
2586 Ok(RevsetExpression::filter(
2587 RevsetFilterPredicate::Description("foo".to_string())
2588 ))
2589 );
2590 assert_eq!(
2591 parse("description(\"(foo)\")"),
2592 Ok(RevsetExpression::filter(
2593 RevsetFilterPredicate::Description("(foo)".to_string())
2594 ))
2595 );
2596 assert_eq!(
2597 parse("empty()"),
2598 Ok(RevsetExpression::filter(RevsetFilterPredicate::File(None)).negated())
2599 );
2600 assert!(parse("empty(foo)").is_err());
2601 assert!(parse("file()").is_err());
2602 assert_eq!(
2603 parse("file(foo)"),
2604 Ok(RevsetExpression::filter(RevsetFilterPredicate::File(Some(
2605 vec![RepoPath::from_internal_string("foo")]
2606 ))))
2607 );
2608 assert_eq!(
2609 parse("file(foo, bar, baz)"),
2610 Ok(RevsetExpression::filter(RevsetFilterPredicate::File(Some(
2611 vec![
2612 RepoPath::from_internal_string("foo"),
2613 RepoPath::from_internal_string("bar"),
2614 RepoPath::from_internal_string("baz"),
2615 ]
2616 ))))
2617 );
2618 }
2619
2620 #[test]
2621 fn test_parse_revset_keyword_arguments() {
2622 assert_eq!(
2623 parse("remote_branches(remote=foo)").unwrap(),
2624 parse(r#"remote_branches("", foo)"#).unwrap(),
2625 );
2626 assert_eq!(
2627 parse("remote_branches(foo, remote=bar)").unwrap(),
2628 parse(r#"remote_branches(foo, bar)"#).unwrap(),
2629 );
2630 insta::assert_debug_snapshot!(
2631 parse(r#"remote_branches(remote=foo, bar)"#).unwrap_err(),
2632 @r###"
2633 InvalidFunctionArguments {
2634 name: "remote_branches",
2635 message: "Positional argument follows keyword argument",
2636 }
2637 "###);
2638 insta::assert_debug_snapshot!(
2639 parse(r#"remote_branches("", foo, remote=bar)"#).unwrap_err(),
2640 @r###"
2641 InvalidFunctionArguments {
2642 name: "remote_branches",
2643 message: "Got multiple values for keyword \"remote\"",
2644 }
2645 "###);
2646 insta::assert_debug_snapshot!(
2647 parse(r#"remote_branches(remote=bar, remote=bar)"#).unwrap_err(),
2648 @r###"
2649 InvalidFunctionArguments {
2650 name: "remote_branches",
2651 message: "Got multiple values for keyword \"remote\"",
2652 }
2653 "###);
2654 insta::assert_debug_snapshot!(
2655 parse(r#"remote_branches(unknown=bar)"#).unwrap_err(),
2656 @r###"
2657 InvalidFunctionArguments {
2658 name: "remote_branches",
2659 message: "Unexpected keyword argument \"unknown\"",
2660 }
2661 "###);
2662 }
2663
2664 #[test]
2665 fn test_expand_symbol_alias() {
2666 assert_eq!(
2667 parse_with_aliases("AB|c", [("AB", "a|b")]).unwrap(),
2668 parse("(a|b)|c").unwrap()
2669 );
2670 assert_eq!(
2671 parse_with_aliases("AB:heads(AB)", [("AB", "a|b")]).unwrap(),
2672 parse("(a|b):heads(a|b)").unwrap()
2673 );
2674
2675 assert_eq!(
2677 parse_with_aliases("a&BC", [("BC", "b|c")]).unwrap(),
2678 parse("a&(b|c)").unwrap()
2679 );
2680
2681 assert_eq!(
2683 parse_with_aliases(r#"A|"A""#, [("A", "a")]).unwrap(),
2684 parse("a|A").unwrap()
2685 );
2686
2687 assert_eq!(
2689 parse_with_aliases("author(A)", [("A", "a")]).unwrap(),
2690 parse("author(a)").unwrap()
2691 );
2692
2693 assert_eq!(
2695 parse_with_aliases("A", [("A", "BC"), ("BC", "b|C"), ("C", "c")]).unwrap(),
2696 parse("b|c").unwrap()
2697 );
2698
2699 assert_eq!(
2701 parse_with_aliases("A", [("A", "A")]),
2702 Err(RevsetParseErrorKind::BadAliasExpansion("A".to_owned()))
2703 );
2704 assert_eq!(
2705 parse_with_aliases("A", [("A", "B"), ("B", "b|C"), ("C", "c|B")]),
2706 Err(RevsetParseErrorKind::BadAliasExpansion("A".to_owned()))
2707 );
2708
2709 assert_eq!(
2711 parse_with_aliases("A", [("A", "a(")]),
2712 Err(RevsetParseErrorKind::BadAliasExpansion("A".to_owned()))
2713 );
2714 }
2715
2716 #[test]
2717 fn test_expand_function_alias() {
2718 assert_eq!(
2719 parse_with_aliases("F()", [("F( )", "a")]).unwrap(),
2720 parse("a").unwrap()
2721 );
2722 assert_eq!(
2723 parse_with_aliases("F(a)", [("F( x )", "x")]).unwrap(),
2724 parse("a").unwrap()
2725 );
2726 assert_eq!(
2727 parse_with_aliases("F(a, b)", [("F( x, y )", "x|y")]).unwrap(),
2728 parse("a|b").unwrap()
2729 );
2730
2731 assert_eq!(
2733 parse_with_aliases("F(a:y,b:x)", [("F(x,y)", "x|y")]).unwrap(),
2734 parse("(a:y)|(b:x)").unwrap()
2735 );
2736 assert_eq!(
2738 parse_with_aliases("F(a)", [("F(x)", "G(x)&y"), ("G(y)", "x|y")]).unwrap(),
2739 parse("(x|a)&y").unwrap()
2740 );
2741 assert_eq!(
2743 parse_with_aliases("F(G(a))", [("F(x)", "G(x)&y"), ("G(y)", "x|y")]).unwrap(),
2744 parse("(x|(x|a))&y").unwrap()
2745 );
2746
2747 assert_eq!(
2749 parse_with_aliases("F(a)|X", [("F(X)", "X"), ("X", "x")]).unwrap(),
2750 parse("a|x").unwrap()
2751 );
2752
2753 assert_eq!(
2755 parse_with_aliases("F(a)", [("F(x)", "x|A"), ("A", "x")]).unwrap(),
2756 parse("a|x").unwrap()
2757 );
2758
2759 assert_eq!(
2761 parse_with_aliases("F(a)", [("F(x)", r#"x|"x""#)]).unwrap(),
2762 parse("a|x").unwrap()
2763 );
2764
2765 assert_eq!(
2767 parse_with_aliases("F(a)", [("F(x)", "author(x)|committer(x)")]).unwrap(),
2768 parse("author(a)|committer(a)").unwrap()
2769 );
2770
2771 assert_eq!(
2773 parse_with_aliases("A()", [("A()", "A"), ("A", "a")]).unwrap(),
2774 parse("a").unwrap()
2775 );
2776
2777 assert_eq!(
2779 parse_with_aliases("F(a)", [("F()", "x")]),
2780 Err(RevsetParseErrorKind::InvalidFunctionArguments {
2781 name: "F".to_owned(),
2782 message: "Expected 0 arguments".to_owned()
2783 })
2784 );
2785 assert_eq!(
2786 parse_with_aliases("F()", [("F(x)", "x")]),
2787 Err(RevsetParseErrorKind::InvalidFunctionArguments {
2788 name: "F".to_owned(),
2789 message: "Expected 1 arguments".to_owned()
2790 })
2791 );
2792 assert_eq!(
2793 parse_with_aliases("F(a,b,c)", [("F(x,y)", "x|y")]),
2794 Err(RevsetParseErrorKind::InvalidFunctionArguments {
2795 name: "F".to_owned(),
2796 message: "Expected 2 arguments".to_owned()
2797 })
2798 );
2799
2800 assert_eq!(
2802 parse_with_aliases("F(x=y)", [("F(x)", "x")]),
2803 Err(RevsetParseErrorKind::InvalidFunctionArguments {
2804 name: "F".to_owned(),
2805 message: r#"Unexpected keyword argument "x""#.to_owned()
2806 })
2807 );
2808
2809 assert_eq!(
2811 parse_with_aliases(
2812 "F(a)",
2813 [("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")]
2814 ),
2815 Err(RevsetParseErrorKind::BadAliasExpansion("F()".to_owned()))
2816 );
2817 }
2818
2819 #[test]
2820 fn test_optimize_subtree() {
2821 assert_eq!(
2825 optimize(parse("parents(branches() & all())").unwrap()),
2826 RevsetExpression::branches("".to_owned()).parents()
2827 );
2828 assert_eq!(
2829 optimize(parse("children(branches() & all())").unwrap()),
2830 RevsetExpression::branches("".to_owned()).children()
2831 );
2832 assert_eq!(
2833 optimize(parse("ancestors(branches() & all())").unwrap()),
2834 RevsetExpression::branches("".to_owned()).ancestors()
2835 );
2836 assert_eq!(
2837 optimize(parse("descendants(branches() & all())").unwrap()),
2838 RevsetExpression::branches("".to_owned()).descendants()
2839 );
2840
2841 assert_eq!(
2842 optimize(parse("(branches() & all())..(all() & tags())").unwrap()),
2843 RevsetExpression::branches("".to_owned()).range(&RevsetExpression::tags())
2844 );
2845 assert_eq!(
2846 optimize(parse("(branches() & all()):(all() & tags())").unwrap()),
2847 RevsetExpression::branches("".to_owned()).dag_range_to(&RevsetExpression::tags())
2848 );
2849
2850 assert_eq!(
2851 optimize(parse("heads(branches() & all())").unwrap()),
2852 RevsetExpression::branches("".to_owned()).heads()
2853 );
2854 assert_eq!(
2855 optimize(parse("roots(branches() & all())").unwrap()),
2856 RevsetExpression::branches("".to_owned()).roots()
2857 );
2858
2859 assert_eq!(
2860 optimize(parse("present(author(foo) ~ bar)").unwrap()),
2861 Rc::new(RevsetExpression::AsFilter(Rc::new(
2862 RevsetExpression::Present(
2863 RevsetExpression::filter(RevsetFilterPredicate::Author("foo".to_owned()))
2864 .minus(&RevsetExpression::symbol("bar".to_owned()))
2865 )
2866 )))
2867 );
2868 assert_eq!(
2869 optimize(parse("present(branches() & all())").unwrap()),
2870 Rc::new(RevsetExpression::Present(RevsetExpression::branches(
2871 "".to_owned()
2872 )))
2873 );
2874
2875 assert_eq!(
2876 optimize(parse("~branches() & all()").unwrap()),
2877 RevsetExpression::branches("".to_owned()).negated()
2878 );
2879 assert_eq!(
2880 optimize(parse("(branches() & all()) | (all() & tags())").unwrap()),
2881 RevsetExpression::branches("".to_owned()).union(&RevsetExpression::tags())
2882 );
2883 assert_eq!(
2884 optimize(parse("(branches() & all()) & (all() & tags())").unwrap()),
2885 RevsetExpression::branches("".to_owned()).intersection(&RevsetExpression::tags())
2886 );
2887 assert_eq!(
2888 optimize(parse("(branches() & all()) ~ (all() & tags())").unwrap()),
2889 RevsetExpression::branches("".to_owned()).minus(&RevsetExpression::tags())
2890 );
2891 }
2892
2893 #[test]
2894 fn test_optimize_unchanged_subtree() {
2895 fn unwrap_union(
2896 expression: &RevsetExpression,
2897 ) -> (&Rc<RevsetExpression>, &Rc<RevsetExpression>) {
2898 match expression {
2899 RevsetExpression::Union(left, right) => (left, right),
2900 _ => panic!("unexpected expression: {expression:?}"),
2901 }
2902 }
2903
2904 let parsed = parse("foo-").unwrap();
2906 let optimized = optimize(parsed.clone());
2907 assert!(Rc::ptr_eq(&parsed, &optimized));
2908
2909 let parsed = parse("branches() | tags()").unwrap();
2910 let optimized = optimize(parsed.clone());
2911 assert!(Rc::ptr_eq(&parsed, &optimized));
2912
2913 let parsed = parse("branches() & tags()").unwrap();
2914 let optimized = optimize(parsed.clone());
2915 assert!(Rc::ptr_eq(&parsed, &optimized));
2916
2917 let parsed = parse("(branches() & all()) | tags()").unwrap();
2919 let optimized = optimize(parsed.clone());
2920 assert_eq!(
2921 unwrap_union(&optimized).0.as_ref(),
2922 &RevsetExpression::Branches("".to_owned())
2923 );
2924 assert!(Rc::ptr_eq(
2925 unwrap_union(&parsed).1,
2926 unwrap_union(&optimized).1
2927 ));
2928
2929 let parsed = parse("branches() | (all() & tags())").unwrap();
2931 let optimized = optimize(parsed.clone());
2932 assert!(Rc::ptr_eq(
2933 unwrap_union(&parsed).0,
2934 unwrap_union(&optimized).0
2935 ));
2936 assert_eq!(unwrap_union(&optimized).1.as_ref(), &RevsetExpression::Tags);
2937 }
2938
2939 #[test]
2940 fn test_optimize_difference() {
2941 insta::assert_debug_snapshot!(optimize(parse("foo & ~bar").unwrap()), @r###"
2942 Difference(
2943 Symbol(
2944 "foo",
2945 ),
2946 Symbol(
2947 "bar",
2948 ),
2949 )
2950 "###);
2951 insta::assert_debug_snapshot!(optimize(parse("~foo & bar").unwrap()), @r###"
2952 Difference(
2953 Symbol(
2954 "bar",
2955 ),
2956 Symbol(
2957 "foo",
2958 ),
2959 )
2960 "###);
2961 insta::assert_debug_snapshot!(optimize(parse("~foo & bar & ~baz").unwrap()), @r###"
2962 Difference(
2963 Difference(
2964 Symbol(
2965 "bar",
2966 ),
2967 Symbol(
2968 "foo",
2969 ),
2970 ),
2971 Symbol(
2972 "baz",
2973 ),
2974 )
2975 "###);
2976 insta::assert_debug_snapshot!(optimize(parse("(all() & ~foo) & bar").unwrap()), @r###"
2977 Difference(
2978 Symbol(
2979 "bar",
2980 ),
2981 Symbol(
2982 "foo",
2983 ),
2984 )
2985 "###);
2986
2987 insta::assert_debug_snapshot!(optimize(parse("all() ~ foo").unwrap()), @r###"
2989 NotIn(
2990 Symbol(
2991 "foo",
2992 ),
2993 )
2994 "###);
2995 insta::assert_debug_snapshot!(optimize(parse("foo ~ bar").unwrap()), @r###"
2996 Difference(
2997 Symbol(
2998 "foo",
2999 ),
3000 Symbol(
3001 "bar",
3002 ),
3003 )
3004 "###);
3005 insta::assert_debug_snapshot!(optimize(parse("(all() ~ foo) & bar").unwrap()), @r###"
3006 Difference(
3007 Symbol(
3008 "bar",
3009 ),
3010 Symbol(
3011 "foo",
3012 ),
3013 )
3014 "###);
3015
3016 insta::assert_debug_snapshot!(optimize(parse(":foo & ~:bar").unwrap()), @r###"
3018 Range {
3019 roots: Symbol(
3020 "bar",
3021 ),
3022 heads: Symbol(
3023 "foo",
3024 ),
3025 generation: 0..4294967295,
3026 }
3027 "###);
3028 insta::assert_debug_snapshot!(optimize(parse("~:foo & :bar").unwrap()), @r###"
3029 Range {
3030 roots: Symbol(
3031 "foo",
3032 ),
3033 heads: Symbol(
3034 "bar",
3035 ),
3036 generation: 0..4294967295,
3037 }
3038 "###);
3039 insta::assert_debug_snapshot!(optimize(parse("foo..").unwrap()), @r###"
3040 Range {
3041 roots: Symbol(
3042 "foo",
3043 ),
3044 heads: VisibleHeads,
3045 generation: 0..4294967295,
3046 }
3047 "###);
3048 insta::assert_debug_snapshot!(optimize(parse("foo..bar").unwrap()), @r###"
3049 Range {
3050 roots: Symbol(
3051 "foo",
3052 ),
3053 heads: Symbol(
3054 "bar",
3055 ),
3056 generation: 0..4294967295,
3057 }
3058 "###);
3059
3060 insta::assert_debug_snapshot!(optimize(parse("foo & ~~bar").unwrap()), @r###"
3062 Intersection(
3063 Symbol(
3064 "foo",
3065 ),
3066 Symbol(
3067 "bar",
3068 ),
3069 )
3070 "###);
3071 insta::assert_debug_snapshot!(optimize(parse("foo & ~~~bar").unwrap()), @r###"
3072 Difference(
3073 Symbol(
3074 "foo",
3075 ),
3076 Symbol(
3077 "bar",
3078 ),
3079 )
3080 "###);
3081 insta::assert_debug_snapshot!(optimize(parse("~(all() & ~foo) & bar").unwrap()), @r###"
3082 Intersection(
3083 Symbol(
3084 "foo",
3085 ),
3086 Symbol(
3087 "bar",
3088 ),
3089 )
3090 "###);
3091
3092 insta::assert_debug_snapshot!(optimize(parse("~foo & ~bar").unwrap()), @r###"
3094 Difference(
3095 NotIn(
3096 Symbol(
3097 "foo",
3098 ),
3099 ),
3100 Symbol(
3101 "bar",
3102 ),
3103 )
3104 "###);
3105 }
3106
3107 #[test]
3108 fn test_optimize_filter_difference() {
3109 insta::assert_debug_snapshot!(optimize(parse("~empty()").unwrap()), @r###"
3111 Filter(
3112 File(
3113 None,
3114 ),
3115 )
3116 "###);
3117
3118 insta::assert_debug_snapshot!(
3120 optimize(parse("(author(foo) & ~bar) & baz").unwrap()), @r###"
3121 Intersection(
3122 Difference(
3123 Symbol(
3124 "baz",
3125 ),
3126 Symbol(
3127 "bar",
3128 ),
3129 ),
3130 Filter(
3131 Author(
3132 "foo",
3133 ),
3134 ),
3135 )
3136 "###)
3137 }
3138
3139 #[test]
3140 fn test_optimize_filter_intersection() {
3141 insta::assert_debug_snapshot!(optimize(parse("author(foo)").unwrap()), @r###"
3142 Filter(
3143 Author(
3144 "foo",
3145 ),
3146 )
3147 "###);
3148
3149 insta::assert_debug_snapshot!(optimize(parse("foo & description(bar)").unwrap()), @r###"
3150 Intersection(
3151 Symbol(
3152 "foo",
3153 ),
3154 Filter(
3155 Description(
3156 "bar",
3157 ),
3158 ),
3159 )
3160 "###);
3161 insta::assert_debug_snapshot!(optimize(parse("author(foo) & bar").unwrap()), @r###"
3162 Intersection(
3163 Symbol(
3164 "bar",
3165 ),
3166 Filter(
3167 Author(
3168 "foo",
3169 ),
3170 ),
3171 )
3172 "###);
3173 insta::assert_debug_snapshot!(
3174 optimize(parse("author(foo) & committer(bar)").unwrap()), @r###"
3175 Intersection(
3176 Filter(
3177 Author(
3178 "foo",
3179 ),
3180 ),
3181 Filter(
3182 Committer(
3183 "bar",
3184 ),
3185 ),
3186 )
3187 "###);
3188
3189 insta::assert_debug_snapshot!(
3190 optimize(parse("foo & description(bar) & author(baz)").unwrap()), @r###"
3191 Intersection(
3192 Intersection(
3193 Symbol(
3194 "foo",
3195 ),
3196 Filter(
3197 Description(
3198 "bar",
3199 ),
3200 ),
3201 ),
3202 Filter(
3203 Author(
3204 "baz",
3205 ),
3206 ),
3207 )
3208 "###);
3209 insta::assert_debug_snapshot!(
3210 optimize(parse("committer(foo) & bar & author(baz)").unwrap()), @r###"
3211 Intersection(
3212 Intersection(
3213 Symbol(
3214 "bar",
3215 ),
3216 Filter(
3217 Committer(
3218 "foo",
3219 ),
3220 ),
3221 ),
3222 Filter(
3223 Author(
3224 "baz",
3225 ),
3226 ),
3227 )
3228 "###);
3229 insta::assert_debug_snapshot!(
3230 optimize(parse("committer(foo) & file(bar) & baz").unwrap()), @r###"
3231 Intersection(
3232 Intersection(
3233 Symbol(
3234 "baz",
3235 ),
3236 Filter(
3237 Committer(
3238 "foo",
3239 ),
3240 ),
3241 ),
3242 Filter(
3243 File(
3244 Some(
3245 [
3246 "bar",
3247 ],
3248 ),
3249 ),
3250 ),
3251 )
3252 "###);
3253 insta::assert_debug_snapshot!(
3254 optimize(parse("committer(foo) & file(bar) & author(baz)").unwrap()), @r###"
3255 Intersection(
3256 Intersection(
3257 Filter(
3258 Committer(
3259 "foo",
3260 ),
3261 ),
3262 Filter(
3263 File(
3264 Some(
3265 [
3266 "bar",
3267 ],
3268 ),
3269 ),
3270 ),
3271 ),
3272 Filter(
3273 Author(
3274 "baz",
3275 ),
3276 ),
3277 )
3278 "###);
3279 insta::assert_debug_snapshot!(optimize(parse("foo & file(bar) & baz").unwrap()), @r###"
3280 Intersection(
3281 Intersection(
3282 Symbol(
3283 "foo",
3284 ),
3285 Symbol(
3286 "baz",
3287 ),
3288 ),
3289 Filter(
3290 File(
3291 Some(
3292 [
3293 "bar",
3294 ],
3295 ),
3296 ),
3297 ),
3298 )
3299 "###);
3300
3301 insta::assert_debug_snapshot!(
3302 optimize(parse("foo & description(bar) & author(baz) & qux").unwrap()), @r###"
3303 Intersection(
3304 Intersection(
3305 Intersection(
3306 Symbol(
3307 "foo",
3308 ),
3309 Symbol(
3310 "qux",
3311 ),
3312 ),
3313 Filter(
3314 Description(
3315 "bar",
3316 ),
3317 ),
3318 ),
3319 Filter(
3320 Author(
3321 "baz",
3322 ),
3323 ),
3324 )
3325 "###);
3326 insta::assert_debug_snapshot!(
3327 optimize(parse("foo & description(bar) & parents(author(baz)) & qux").unwrap()), @r###"
3328 Intersection(
3329 Intersection(
3330 Intersection(
3331 Symbol(
3332 "foo",
3333 ),
3334 Ancestors {
3335 heads: Filter(
3336 Author(
3337 "baz",
3338 ),
3339 ),
3340 generation: 1..2,
3341 },
3342 ),
3343 Symbol(
3344 "qux",
3345 ),
3346 ),
3347 Filter(
3348 Description(
3349 "bar",
3350 ),
3351 ),
3352 )
3353 "###);
3354 insta::assert_debug_snapshot!(
3355 optimize(parse("foo & description(bar) & parents(author(baz) & qux)").unwrap()), @r###"
3356 Intersection(
3357 Intersection(
3358 Symbol(
3359 "foo",
3360 ),
3361 Ancestors {
3362 heads: Intersection(
3363 Symbol(
3364 "qux",
3365 ),
3366 Filter(
3367 Author(
3368 "baz",
3369 ),
3370 ),
3371 ),
3372 generation: 1..2,
3373 },
3374 ),
3375 Filter(
3376 Description(
3377 "bar",
3378 ),
3379 ),
3380 )
3381 "###);
3382
3383 insta::assert_debug_snapshot!(
3385 optimize(parse("(a & author(A)) & (b & author(B)) & (c & author(C))").unwrap()), @r###"
3386 Intersection(
3387 Intersection(
3388 Intersection(
3389 Intersection(
3390 Intersection(
3391 Symbol(
3392 "a",
3393 ),
3394 Symbol(
3395 "b",
3396 ),
3397 ),
3398 Symbol(
3399 "c",
3400 ),
3401 ),
3402 Filter(
3403 Author(
3404 "A",
3405 ),
3406 ),
3407 ),
3408 Filter(
3409 Author(
3410 "B",
3411 ),
3412 ),
3413 ),
3414 Filter(
3415 Author(
3416 "C",
3417 ),
3418 ),
3419 )
3420 "###);
3421 insta::assert_debug_snapshot!(
3422 optimize(parse("(a & author(A)) & ((b & author(B)) & (c & author(C))) & d").unwrap()),
3423 @r###"
3424 Intersection(
3425 Intersection(
3426 Intersection(
3427 Intersection(
3428 Intersection(
3429 Symbol(
3430 "a",
3431 ),
3432 Intersection(
3433 Symbol(
3434 "b",
3435 ),
3436 Symbol(
3437 "c",
3438 ),
3439 ),
3440 ),
3441 Symbol(
3442 "d",
3443 ),
3444 ),
3445 Filter(
3446 Author(
3447 "A",
3448 ),
3449 ),
3450 ),
3451 Filter(
3452 Author(
3453 "B",
3454 ),
3455 ),
3456 ),
3457 Filter(
3458 Author(
3459 "C",
3460 ),
3461 ),
3462 )
3463 "###);
3464
3465 insta::assert_debug_snapshot!(
3467 optimize(parse("foo & (all() & description(bar)) & (author(baz) & all())").unwrap()),
3468 @r###"
3469 Intersection(
3470 Intersection(
3471 Symbol(
3472 "foo",
3473 ),
3474 Filter(
3475 Description(
3476 "bar",
3477 ),
3478 ),
3479 ),
3480 Filter(
3481 Author(
3482 "baz",
3483 ),
3484 ),
3485 )
3486 "###);
3487 }
3488
3489 #[test]
3490 fn test_optimize_filter_subtree() {
3491 insta::assert_debug_snapshot!(
3492 optimize(parse("(author(foo) | bar) & baz").unwrap()), @r###"
3493 Intersection(
3494 Symbol(
3495 "baz",
3496 ),
3497 AsFilter(
3498 Union(
3499 Filter(
3500 Author(
3501 "foo",
3502 ),
3503 ),
3504 Symbol(
3505 "bar",
3506 ),
3507 ),
3508 ),
3509 )
3510 "###);
3511
3512 insta::assert_debug_snapshot!(
3513 optimize(parse("(foo | committer(bar)) & description(baz) & qux").unwrap()), @r###"
3514 Intersection(
3515 Intersection(
3516 Symbol(
3517 "qux",
3518 ),
3519 AsFilter(
3520 Union(
3521 Symbol(
3522 "foo",
3523 ),
3524 Filter(
3525 Committer(
3526 "bar",
3527 ),
3528 ),
3529 ),
3530 ),
3531 ),
3532 Filter(
3533 Description(
3534 "baz",
3535 ),
3536 ),
3537 )
3538 "###);
3539
3540 insta::assert_debug_snapshot!(
3541 optimize(parse("(~present(author(foo) & bar) | baz) & qux").unwrap()), @r###"
3542 Intersection(
3543 Symbol(
3544 "qux",
3545 ),
3546 AsFilter(
3547 Union(
3548 AsFilter(
3549 NotIn(
3550 AsFilter(
3551 Present(
3552 Intersection(
3553 Symbol(
3554 "bar",
3555 ),
3556 Filter(
3557 Author(
3558 "foo",
3559 ),
3560 ),
3561 ),
3562 ),
3563 ),
3564 ),
3565 ),
3566 Symbol(
3567 "baz",
3568 ),
3569 ),
3570 ),
3571 )
3572 "###);
3573
3574 insta::assert_debug_snapshot!(
3576 optimize(parse(
3577 "(a & (author(A) | 0)) & (b & (author(B) | 1)) & (c & (author(C) | 2))").unwrap()),
3578 @r###"
3579 Intersection(
3580 Intersection(
3581 Intersection(
3582 Intersection(
3583 Intersection(
3584 Symbol(
3585 "a",
3586 ),
3587 Symbol(
3588 "b",
3589 ),
3590 ),
3591 Symbol(
3592 "c",
3593 ),
3594 ),
3595 AsFilter(
3596 Union(
3597 Filter(
3598 Author(
3599 "A",
3600 ),
3601 ),
3602 Symbol(
3603 "0",
3604 ),
3605 ),
3606 ),
3607 ),
3608 AsFilter(
3609 Union(
3610 Filter(
3611 Author(
3612 "B",
3613 ),
3614 ),
3615 Symbol(
3616 "1",
3617 ),
3618 ),
3619 ),
3620 ),
3621 AsFilter(
3622 Union(
3623 Filter(
3624 Author(
3625 "C",
3626 ),
3627 ),
3628 Symbol(
3629 "2",
3630 ),
3631 ),
3632 ),
3633 )
3634 "###);
3635 }
3636
3637 #[test]
3638 fn test_optimize_ancestors() {
3639 insta::assert_debug_snapshot!(optimize(parse("foo--").unwrap()), @r###"
3641 Ancestors {
3642 heads: Symbol(
3643 "foo",
3644 ),
3645 generation: 2..3,
3646 }
3647 "###);
3648 insta::assert_debug_snapshot!(optimize(parse(":(foo---)").unwrap()), @r###"
3649 Ancestors {
3650 heads: Symbol(
3651 "foo",
3652 ),
3653 generation: 3..4294967295,
3654 }
3655 "###);
3656 insta::assert_debug_snapshot!(optimize(parse("(:foo)---").unwrap()), @r###"
3657 Ancestors {
3658 heads: Symbol(
3659 "foo",
3660 ),
3661 generation: 3..4294967295,
3662 }
3663 "###);
3664
3665 insta::assert_debug_snapshot!(optimize(parse("foo---+").unwrap()), @r###"
3667 Children(
3668 Ancestors {
3669 heads: Symbol(
3670 "foo",
3671 ),
3672 generation: 3..4,
3673 },
3674 )
3675 "###);
3676
3677 insta::assert_debug_snapshot!(optimize(parse("foo..(bar--)").unwrap()), @r###"
3679 Range {
3680 roots: Symbol(
3681 "foo",
3682 ),
3683 heads: Symbol(
3684 "bar",
3685 ),
3686 generation: 2..4294967295,
3687 }
3688 "###);
3689 insta::assert_debug_snapshot!(optimize(parse("(foo--)..(bar---)").unwrap()), @r###"
3692 Difference(
3693 Ancestors {
3694 heads: Symbol(
3695 "bar",
3696 ),
3697 generation: 3..4294967295,
3698 },
3699 Ancestors {
3700 heads: Symbol(
3701 "foo",
3702 ),
3703 generation: 2..4294967295,
3704 },
3705 )
3706 "###);
3707
3708 insta::assert_debug_snapshot!(optimize(parse("(foo..bar)--").unwrap()), @r###"
3711 Ancestors {
3712 heads: Range {
3713 roots: Symbol(
3714 "foo",
3715 ),
3716 heads: Symbol(
3717 "bar",
3718 ),
3719 generation: 0..4294967295,
3720 },
3721 generation: 2..3,
3722 }
3723 "###);
3724 insta::assert_debug_snapshot!(optimize(parse("foo..(bar..baz)").unwrap()), @r###"
3725 Range {
3726 roots: Symbol(
3727 "foo",
3728 ),
3729 heads: Range {
3730 roots: Symbol(
3731 "bar",
3732 ),
3733 heads: Symbol(
3734 "baz",
3735 ),
3736 generation: 0..4294967295,
3737 },
3738 generation: 0..4294967295,
3739 }
3740 "###);
3741
3742 let empty_generation_ancestors = |heads| {
3746 Rc::new(RevsetExpression::Ancestors {
3747 heads,
3748 generation: GENERATION_RANGE_EMPTY,
3749 })
3750 };
3751 insta::assert_debug_snapshot!(
3752 optimize(empty_generation_ancestors(
3753 RevsetExpression::symbol("foo".to_owned()).ancestors()
3754 )),
3755 @r###"
3756 Ancestors {
3757 heads: Symbol(
3758 "foo",
3759 ),
3760 generation: 0..0,
3761 }
3762 "###
3763 );
3764 insta::assert_debug_snapshot!(
3765 optimize(
3766 empty_generation_ancestors(RevsetExpression::symbol("foo".to_owned())).ancestors()
3767 ),
3768 @r###"
3769 Ancestors {
3770 heads: Symbol(
3771 "foo",
3772 ),
3773 generation: 0..0,
3774 }
3775 "###
3776 );
3777 }
3778
3779 #[test]
3780 fn test_revset_combinator() {
3781 let mut new_change_id = change_id_generator();
3782 let mut index = MutableIndex::full(3, 16);
3783 let id_0 = CommitId::from_hex("000000");
3784 let id_1 = CommitId::from_hex("111111");
3785 let id_2 = CommitId::from_hex("222222");
3786 let id_3 = CommitId::from_hex("333333");
3787 let id_4 = CommitId::from_hex("444444");
3788 index.add_commit_data(id_0.clone(), new_change_id(), &[]);
3789 index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
3790 index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
3791 index.add_commit_data(id_3.clone(), new_change_id(), &[id_2.clone()]);
3792 index.add_commit_data(id_4.clone(), new_change_id(), &[id_3.clone()]);
3793
3794 let get_entry = |id: &CommitId| index.entry_by_id(id).unwrap();
3795 let make_entries = |ids: &[&CommitId]| ids.iter().map(|id| get_entry(id)).collect_vec();
3796 let make_set = |ids: &[&CommitId]| -> Box<dyn Revset<'_> + '_> {
3797 let index_entries = make_entries(ids);
3798 Box::new(EagerRevset { index_entries })
3799 };
3800
3801 let set = make_set(&[&id_4, &id_3, &id_2, &id_0]);
3802 let mut p = set.to_predicate_fn();
3803 assert!(p(&get_entry(&id_4)));
3804 assert!(p(&get_entry(&id_3)));
3805 assert!(p(&get_entry(&id_2)));
3806 assert!(!p(&get_entry(&id_1)));
3807 assert!(p(&get_entry(&id_0)));
3808 let mut p = set.to_predicate_fn();
3810 assert!(p(&get_entry(&id_3)));
3811 assert!(!p(&get_entry(&id_1)));
3812 assert!(p(&get_entry(&id_0)));
3813
3814 let set = FilterRevset::<PurePredicateFn> {
3815 candidates: make_set(&[&id_4, &id_2, &id_0]),
3816 predicate: Box::new(|entry| entry.commit_id() != id_4),
3817 };
3818 assert_eq!(set.iter().collect_vec(), make_entries(&[&id_2, &id_0]));
3819 let mut p = set.to_predicate_fn();
3820 assert!(!p(&get_entry(&id_4)));
3821 assert!(!p(&get_entry(&id_3)));
3822 assert!(p(&get_entry(&id_2)));
3823 assert!(!p(&get_entry(&id_1)));
3824 assert!(p(&get_entry(&id_0)));
3825
3826 let set = FilterRevset {
3828 candidates: make_set(&[&id_4, &id_2, &id_0]),
3829 predicate: make_set(&[&id_3, &id_2, &id_1]),
3830 };
3831 assert_eq!(set.iter().collect_vec(), make_entries(&[&id_2]));
3832 let mut p = set.to_predicate_fn();
3833 assert!(!p(&get_entry(&id_4)));
3834 assert!(!p(&get_entry(&id_3)));
3835 assert!(p(&get_entry(&id_2)));
3836 assert!(!p(&get_entry(&id_1)));
3837 assert!(!p(&get_entry(&id_0)));
3838
3839 let set = UnionRevset {
3840 set1: make_set(&[&id_4, &id_2]),
3841 set2: make_set(&[&id_3, &id_2, &id_1]),
3842 };
3843 assert_eq!(
3844 set.iter().collect_vec(),
3845 make_entries(&[&id_4, &id_3, &id_2, &id_1])
3846 );
3847 let mut p = set.to_predicate_fn();
3848 assert!(p(&get_entry(&id_4)));
3849 assert!(p(&get_entry(&id_3)));
3850 assert!(p(&get_entry(&id_2)));
3851 assert!(p(&get_entry(&id_1)));
3852 assert!(!p(&get_entry(&id_0)));
3853
3854 let set = IntersectionRevset {
3855 set1: make_set(&[&id_4, &id_2, &id_0]),
3856 set2: make_set(&[&id_3, &id_2, &id_1]),
3857 };
3858 assert_eq!(set.iter().collect_vec(), make_entries(&[&id_2]));
3859 let mut p = set.to_predicate_fn();
3860 assert!(!p(&get_entry(&id_4)));
3861 assert!(!p(&get_entry(&id_3)));
3862 assert!(p(&get_entry(&id_2)));
3863 assert!(!p(&get_entry(&id_1)));
3864 assert!(!p(&get_entry(&id_0)));
3865
3866 let set = DifferenceRevset {
3867 set1: make_set(&[&id_4, &id_2, &id_0]),
3868 set2: make_set(&[&id_3, &id_2, &id_1]),
3869 };
3870 assert_eq!(set.iter().collect_vec(), make_entries(&[&id_4, &id_0]));
3871 let mut p = set.to_predicate_fn();
3872 assert!(p(&get_entry(&id_4)));
3873 assert!(!p(&get_entry(&id_3)));
3874 assert!(!p(&get_entry(&id_2)));
3875 assert!(!p(&get_entry(&id_1)));
3876 assert!(p(&get_entry(&id_0)));
3877 }
3878}