revset: add methods on RevsetExpression for constructing them

This makes it much easier to create `RevsetExpression` instances
programmatically.
This commit is contained in:
Martin von Zweigbergk 2021-08-25 21:58:08 -07:00
parent 451451563b
commit 658b41b4e9

View file

@ -170,7 +170,7 @@ pub enum RevsetParseError {
InvalidFunctionArguments { name: String, message: String },
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RevsetExpression {
None,
Symbol(String),
@ -210,16 +210,132 @@ pub enum RevsetExpression {
}
impl RevsetExpression {
fn non_obsolete_heads() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::NonObsoleteHeads(Rc::new(
RevsetExpression::AllHeads,
)))
pub fn none() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::None)
}
fn non_obsolete_commits() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Ancestors(
RevsetExpression::non_obsolete_heads(),
))
pub fn symbol(value: String) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Symbol(value))
}
pub fn all_heads() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::AllHeads)
}
pub fn public_heads() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::PublicHeads)
}
pub fn branches() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Branches)
}
pub fn tags() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Tags)
}
pub fn git_refs() -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::GitRefs)
}
pub fn all_non_obsolete_heads() -> Rc<RevsetExpression> {
RevsetExpression::all_heads().non_obsolete_heads()
}
pub fn all_non_obsolete_commits() -> Rc<RevsetExpression> {
RevsetExpression::all_non_obsolete_heads().ancestors()
}
/// Non-obsolete heads among `self`.
pub fn non_obsolete_heads(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::NonObsoleteHeads(self.clone()))
}
/// Parents of `self`.
pub fn parents(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Parents(self.clone()))
}
/// Ancestors of `self`, including `self`.
pub fn ancestors(self: &Rc<RevsetExpression>) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Ancestors(self.clone()))
}
/// Children of `self`.
pub fn children(
self: &Rc<RevsetExpression>,
heads: &Rc<RevsetExpression>,
) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Children {
roots: self.clone(),
heads: heads.clone(),
})
}
/// Commits that are descendants of `self` and ancestors of `heads`, both
/// inclusive.
pub fn descendants(
self: &Rc<RevsetExpression>,
heads: &Rc<RevsetExpression>,
) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::DagRange {
roots: self.clone(),
heads: heads.clone(),
})
}
/// Commits reachable from `heads` but not from `self`.
pub fn range(
self: &Rc<RevsetExpression>,
heads: &Rc<RevsetExpression>,
) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Range {
roots: self.clone(),
heads: heads.clone(),
})
}
/// Commits in `self` with number of parents in the given range.
pub fn with_parent_count(
self: &Rc<RevsetExpression>,
parent_count_range: Range<u32>,
) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::ParentCount {
candidates: self.clone(),
parent_count_range,
})
}
/// Commits in `self` with description containing `needle`.
pub fn with_description(self: &Rc<RevsetExpression>, needle: String) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Description {
candidates: self.clone(),
needle,
})
}
/// Commits that are in `self` or in `other` (or both).
pub fn union(
self: &Rc<RevsetExpression>,
other: &Rc<RevsetExpression>,
) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Union(self.clone(), other.clone()))
}
/// Commits that are in `self` and in `other`.
pub fn intersection(
self: &Rc<RevsetExpression>,
other: &Rc<RevsetExpression>,
) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Intersection(self.clone(), other.clone()))
}
/// Commits that are in `self` but not in `other`.
pub fn minus(
self: &Rc<RevsetExpression>,
other: &Rc<RevsetExpression>,
) -> Rc<RevsetExpression> {
Rc::new(RevsetExpression::Difference(self.clone(), other.clone()))
}
pub fn evaluate<'repo>(
@ -250,16 +366,10 @@ fn parse_infix_expression_rule(
let mut expression1 = parse_range_expression_rule(pairs.next().unwrap().into_inner())?;
while let Some(operator) = pairs.next() {
let expression2 = parse_range_expression_rule(pairs.next().unwrap().into_inner())?;
match operator.as_rule() {
Rule::union_op => {
expression1 = Rc::new(RevsetExpression::Union(expression1, expression2))
}
Rule::intersection_op => {
expression1 = Rc::new(RevsetExpression::Intersection(expression1, expression2))
}
Rule::difference_op => {
expression1 = Rc::new(RevsetExpression::Difference(expression1, expression2))
}
expression1 = match operator.as_rule() {
Rule::union_op => expression1.union(&expression2),
Rule::intersection_op => expression1.intersection(&expression2),
Rule::difference_op => expression1.minus(&expression2),
_ => {
panic!(
"unxpected revset infix operator rule {:?}",
@ -277,9 +387,9 @@ fn parse_range_expression_rule(
let first = pairs.next().unwrap();
match first.as_rule() {
Rule::ancestors_op => {
return Ok(Rc::new(RevsetExpression::Ancestors(
parse_children_expression_rule(pairs.next().unwrap().into_inner())?,
)));
return Ok(
parse_children_expression_rule(pairs.next().unwrap().into_inner())?.ancestors(),
);
}
Rule::children_expression => {
// Fall through
@ -292,26 +402,17 @@ fn parse_range_expression_rule(
if let Some(next) = pairs.next() {
match next.as_rule() {
Rule::descendants_op => {
expression = Rc::new(RevsetExpression::DagRange {
roots: expression,
heads: RevsetExpression::non_obsolete_heads(),
});
expression = expression.descendants(&RevsetExpression::all_non_obsolete_heads());
}
Rule::dag_range_op => {
let heads_expression =
parse_children_expression_rule(pairs.next().unwrap().into_inner())?;
expression = Rc::new(RevsetExpression::DagRange {
roots: expression,
heads: heads_expression,
});
expression = expression.descendants(&heads_expression);
}
Rule::range_op => {
let expression2 =
parse_children_expression_rule(pairs.next().unwrap().into_inner())?;
expression = Rc::new(RevsetExpression::Range {
roots: expression,
heads: expression2,
});
expression = expression.range(&expression2);
}
_ => {
panic!("unxpected revset range operator rule {:?}", next.as_rule());
@ -328,10 +429,7 @@ fn parse_children_expression_rule(
for operator in pairs {
match operator.as_rule() {
Rule::children_op => {
expression = Rc::new(RevsetExpression::Children {
roots: expression,
heads: RevsetExpression::non_obsolete_heads(),
});
expression = expression.children(&RevsetExpression::all_non_obsolete_heads());
}
_ => {
panic!(
@ -350,9 +448,7 @@ fn parse_parents_expression_rule(
let first = pairs.next().unwrap();
match first.as_rule() {
Rule::primary => parse_primary_rule(first.into_inner()),
Rule::parents_op => Ok(Rc::new(RevsetExpression::Parents(
parse_parents_expression_rule(pairs)?,
))),
Rule::parents_op => Ok(parse_parents_expression_rule(pairs)?.parents()),
_ => {
panic!(
"unxpected revset parents operator rule {:?}",
@ -381,9 +477,9 @@ fn parse_primary_rule(mut pairs: Pairs<Rule>) -> Result<Rc<RevsetExpression>, Re
fn parse_symbol_rule(mut pairs: Pairs<Rule>) -> Result<Rc<RevsetExpression>, RevsetParseError> {
let first = pairs.next().unwrap();
match first.as_rule() {
Rule::identifier => Ok(Rc::new(RevsetExpression::Symbol(first.as_str().to_owned()))),
Rule::identifier => Ok(RevsetExpression::symbol(first.as_str().to_owned())),
Rule::literal_string => {
return Ok(Rc::new(RevsetExpression::Symbol(
return Ok(RevsetExpression::symbol(
first
.as_str()
.strip_prefix('"')
@ -391,7 +487,7 @@ fn parse_symbol_rule(mut pairs: Pairs<Rule>) -> Result<Rc<RevsetExpression>, Rev
.strip_suffix('"')
.unwrap()
.to_owned(),
)));
));
}
_ => {
panic!("unxpected symbol parse rule: {:?}", first.as_str());
@ -407,9 +503,7 @@ fn parse_function_expression(
match name.as_str() {
"parents" => {
if arg_count == 1 {
Ok(Rc::new(RevsetExpression::Parents(parse_expression_rule(
argument_pairs.next().unwrap().into_inner(),
)?)))
Ok(parse_expression_rule(argument_pairs.next().unwrap().into_inner())?.parents())
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -421,10 +515,7 @@ fn parse_function_expression(
if arg_count == 1 {
let expression =
parse_expression_rule(argument_pairs.next().unwrap().into_inner())?;
Ok(Rc::new(RevsetExpression::Children {
roots: expression,
heads: RevsetExpression::non_obsolete_heads(),
}))
Ok(expression.children(&RevsetExpression::all_non_obsolete_heads()))
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -434,9 +525,7 @@ fn parse_function_expression(
}
"ancestors" => {
if arg_count == 1 {
Ok(Rc::new(RevsetExpression::Ancestors(parse_expression_rule(
argument_pairs.next().unwrap().into_inner(),
)?)))
Ok(parse_expression_rule(argument_pairs.next().unwrap().into_inner())?.ancestors())
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -448,10 +537,7 @@ fn parse_function_expression(
if arg_count == 1 {
let expression =
parse_expression_rule(argument_pairs.next().unwrap().into_inner())?;
Ok(Rc::new(RevsetExpression::DagRange {
roots: expression,
heads: RevsetExpression::non_obsolete_heads(),
}))
Ok(expression.descendants(&RevsetExpression::all_non_obsolete_heads()))
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -461,7 +547,7 @@ fn parse_function_expression(
}
"all_heads" => {
if arg_count == 0 {
Ok(Rc::new(RevsetExpression::AllHeads))
Ok(RevsetExpression::all_heads())
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -471,11 +557,12 @@ fn parse_function_expression(
}
"non_obsolete_heads" => {
if arg_count == 0 {
Ok(RevsetExpression::non_obsolete_heads())
Ok(RevsetExpression::all_non_obsolete_heads())
} else if arg_count == 1 {
Ok(Rc::new(RevsetExpression::NonObsoleteHeads(
parse_expression_rule(argument_pairs.next().unwrap().into_inner())?,
)))
Ok(
parse_expression_rule(argument_pairs.next().unwrap().into_inner())?
.non_obsolete_heads(),
)
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -485,7 +572,7 @@ fn parse_function_expression(
}
"public_heads" => {
if arg_count == 0 {
Ok(Rc::new(RevsetExpression::PublicHeads))
Ok(RevsetExpression::public_heads())
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -495,7 +582,7 @@ fn parse_function_expression(
}
"branches" => {
if arg_count == 0 {
Ok(Rc::new(RevsetExpression::Branches))
Ok(RevsetExpression::branches())
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -505,7 +592,7 @@ fn parse_function_expression(
}
"tags" => {
if arg_count == 0 {
Ok(Rc::new(RevsetExpression::Tags))
Ok(RevsetExpression::tags())
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -515,7 +602,7 @@ fn parse_function_expression(
}
"git_refs" => {
if arg_count == 0 {
Ok(Rc::new(RevsetExpression::GitRefs))
Ok(RevsetExpression::git_refs())
} else {
Err(RevsetParseError::InvalidFunctionArguments {
name,
@ -531,14 +618,11 @@ fn parse_function_expression(
});
}
let candidates = if arg_count == 0 {
RevsetExpression::non_obsolete_commits()
RevsetExpression::all_non_obsolete_commits()
} else {
parse_expression_rule(argument_pairs.next().unwrap().into_inner())?
};
Ok(Rc::new(RevsetExpression::ParentCount {
candidates,
parent_count_range: 2..u32::MAX,
}))
Ok(candidates.with_parent_count(2..u32::MAX))
}
"description" => {
if !(1..=2).contains(&arg_count) {
@ -552,14 +636,11 @@ fn parse_function_expression(
argument_pairs.next().unwrap().into_inner(),
)?;
let candidates = if arg_count == 1 {
RevsetExpression::non_obsolete_commits()
RevsetExpression::all_non_obsolete_commits()
} else {
parse_expression_rule(argument_pairs.next().unwrap().into_inner())?
};
Ok(Rc::new(RevsetExpression::Description {
needle,
candidates,
}))
Ok(candidates.with_description(needle))
}
_ => Err(RevsetParseError::NoSuchFunction(name)),
}
@ -906,18 +987,16 @@ pub fn evaluate_expression<'repo>(
}
RevsetExpression::Children { roots, heads } => {
let root_set = roots.evaluate(repo)?;
let candidates_expression = RevsetExpression::Ancestors(heads.clone());
let candidates_expression = heads.ancestors();
let candidate_set = candidates_expression.evaluate(repo)?;
Ok(Box::new(ChildrenRevset {
root_set,
candidate_set,
}))
}
RevsetExpression::Ancestors(base_expression) => RevsetExpression::Range {
roots: Rc::new(RevsetExpression::None),
heads: base_expression.clone(),
}
.evaluate(repo),
RevsetExpression::Ancestors(base_expression) => RevsetExpression::none()
.range(base_expression)
.evaluate(repo),
RevsetExpression::Range { roots, heads } => {
let root_set = roots.evaluate(repo)?;
let root_ids = root_set.iter().map(|entry| entry.commit_id()).collect_vec();
@ -931,7 +1010,7 @@ pub fn evaluate_expression<'repo>(
#[allow(clippy::needless_collect)]
RevsetExpression::DagRange { roots, heads } => {
let root_set = roots.evaluate(repo)?;
let candidate_set = RevsetExpression::Ancestors(heads.clone()).evaluate(repo)?;
let candidate_set = heads.ancestors().evaluate(repo)?;
let mut reachable: HashSet<_> = root_set.iter().map(|entry| entry.position()).collect();
let mut result = vec![];
let candidates = candidate_set.iter().collect_vec();
@ -1112,104 +1191,123 @@ mod tests {
use super::*;
#[test]
fn test_revset_expression_building() {
let checkout_symbol = RevsetExpression::symbol("@".to_string());
let foo_symbol = RevsetExpression::symbol("foo".to_string());
assert_eq!(
checkout_symbol,
Rc::new(RevsetExpression::Symbol("@".to_string()))
);
assert_eq!(
checkout_symbol.parents(),
Rc::new(RevsetExpression::Parents(checkout_symbol.clone()))
);
assert_eq!(
checkout_symbol.ancestors(),
Rc::new(RevsetExpression::Ancestors(checkout_symbol.clone()))
);
assert_eq!(
foo_symbol.children(&checkout_symbol),
Rc::new(RevsetExpression::Children {
roots: foo_symbol.clone(),
heads: checkout_symbol.clone()
})
);
assert_eq!(
foo_symbol.descendants(&checkout_symbol),
Rc::new(RevsetExpression::DagRange {
roots: foo_symbol.clone(),
heads: checkout_symbol.clone()
})
);
assert_eq!(
foo_symbol.range(&checkout_symbol),
Rc::new(RevsetExpression::Range {
roots: foo_symbol.clone(),
heads: checkout_symbol.clone()
})
);
assert_eq!(
foo_symbol.non_obsolete_heads(),
Rc::new(RevsetExpression::NonObsoleteHeads(foo_symbol.clone()))
);
assert_eq!(
foo_symbol.with_parent_count(3..5),
Rc::new(RevsetExpression::ParentCount {
candidates: foo_symbol.clone(),
parent_count_range: 3..5
})
);
assert_eq!(
foo_symbol.with_description("needle".to_string()),
Rc::new(RevsetExpression::Description {
candidates: foo_symbol.clone(),
needle: "needle".to_string()
})
);
assert_eq!(
foo_symbol.union(&checkout_symbol),
Rc::new(RevsetExpression::Union(
foo_symbol.clone(),
checkout_symbol.clone()
))
);
assert_eq!(
foo_symbol.intersection(&checkout_symbol),
Rc::new(RevsetExpression::Intersection(
foo_symbol.clone(),
checkout_symbol.clone()
))
);
assert_eq!(
foo_symbol.minus(&checkout_symbol),
Rc::new(RevsetExpression::Difference(
foo_symbol,
checkout_symbol.clone()
))
);
}
#[test]
fn test_parse_revset() {
let checkout_symbol = RevsetExpression::symbol("@".to_string());
let foo_symbol = RevsetExpression::symbol("foo".to_string());
let bar_symbol = RevsetExpression::symbol("bar".to_string());
// Parse a single symbol (specifically the "checkout" symbol)
assert_eq!(
parse("@"),
Ok(Rc::new(RevsetExpression::Symbol("@".to_string())))
);
assert_eq!(parse("@"), Ok(checkout_symbol.clone()));
// Parse a single symbol
assert_eq!(
parse("foo"),
Ok(Rc::new(RevsetExpression::Symbol("foo".to_string())))
);
assert_eq!(parse("foo"), Ok(foo_symbol.clone()));
// Parse a parenthesized symbol
assert_eq!(
parse("(foo)"),
Ok(Rc::new(RevsetExpression::Symbol("foo".to_string())))
);
assert_eq!(parse("(foo)"), Ok(foo_symbol.clone()));
// Parse a quoted symbol
assert_eq!(
parse("\"foo\""),
Ok(Rc::new(RevsetExpression::Symbol("foo".to_string())))
);
assert_eq!(parse("\"foo\""), Ok(foo_symbol.clone()));
// Parse the "parents" operator
assert_eq!(
parse(":@"),
Ok(Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("@".to_string())
))))
);
assert_eq!(parse(":@"), Ok(checkout_symbol.parents()));
// Parse the "children" operator
assert_eq!(
parse("@:"),
Ok(Rc::new(RevsetExpression::Children {
roots: Rc::new(RevsetExpression::Symbol("@".to_string())),
heads: RevsetExpression::non_obsolete_heads(),
}))
Ok(checkout_symbol.children(&RevsetExpression::all_non_obsolete_heads()))
);
// Parse the "ancestors" operator
assert_eq!(
parse(",,@"),
Ok(Rc::new(RevsetExpression::Ancestors(Rc::new(
RevsetExpression::Symbol("@".to_string())
))))
);
assert_eq!(parse(",,@"), Ok(checkout_symbol.ancestors()));
// Parse the "descendants" operator
assert_eq!(
parse("@,,"),
Ok(Rc::new(RevsetExpression::DagRange {
roots: Rc::new(RevsetExpression::Symbol("@".to_string())),
heads: RevsetExpression::non_obsolete_heads(),
}))
Ok(checkout_symbol.descendants(&RevsetExpression::all_non_obsolete_heads()))
);
// Parse the "dag range" operator
assert_eq!(
parse("foo,,bar"),
Ok(Rc::new(RevsetExpression::DagRange {
roots: Rc::new(RevsetExpression::Symbol("foo".to_string())),
heads: Rc::new(RevsetExpression::Symbol("bar".to_string())),
}))
);
assert_eq!(parse("foo,,bar"), Ok(foo_symbol.descendants(&bar_symbol)));
// Parse the "intersection" operator
assert_eq!(
parse("foo & bar"),
Ok(Rc::new(RevsetExpression::Intersection(
Rc::new(RevsetExpression::Symbol("foo".to_string())),
Rc::new(RevsetExpression::Symbol("bar".to_string()))
)))
);
assert_eq!(parse("foo & bar"), Ok(foo_symbol.intersection(&bar_symbol)));
// Parse the "union" operator
assert_eq!(
parse("foo | bar"),
Ok(Rc::new(RevsetExpression::Union(
Rc::new(RevsetExpression::Symbol("foo".to_string())),
Rc::new(RevsetExpression::Symbol("bar".to_string()))
)))
);
assert_eq!(parse("foo | bar"), Ok(foo_symbol.union(&bar_symbol)));
// Parse the "difference" operator
assert_eq!(
parse("foo - bar"),
Ok(Rc::new(RevsetExpression::Difference(
Rc::new(RevsetExpression::Symbol("foo".to_string())),
Rc::new(RevsetExpression::Symbol("bar".to_string()))
)))
);
assert_eq!(parse("foo - bar"), Ok(foo_symbol.minus(&bar_symbol)));
// Parentheses are allowed after prefix operators
assert_eq!(
parse(":(@)"),
Ok(Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("@".to_string())
))))
);
assert_eq!(parse(":(@)"), Ok(checkout_symbol.parents()));
// Space is allowed around expressions
assert_eq!(
parse(" ,,@ "),
Ok(Rc::new(RevsetExpression::Ancestors(Rc::new(
RevsetExpression::Symbol("@".to_string())
))))
);
assert_eq!(parse(" ,,@ "), Ok(checkout_symbol.ancestors()));
// Space is not allowed around prefix operators
assert_matches!(parse(" ,, @ "), Err(RevsetParseError::SyntaxError(_)));
// Incomplete parse
@ -1217,45 +1315,28 @@ mod tests {
// Space is allowed around infix operators and function arguments
assert_eq!(
parse(" description( arg1 , arg2 ) - parents( arg1 ) - all_heads( ) "),
Ok(Rc::new(RevsetExpression::Difference(
Rc::new(RevsetExpression::Difference(
Rc::new(RevsetExpression::Description {
needle: "arg1".to_string(),
candidates: Rc::new(RevsetExpression::Symbol("arg2".to_string()))
}),
Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("arg1".to_string())
)))
)),
Rc::new(RevsetExpression::AllHeads)
)))
Ok(RevsetExpression::symbol("arg2".to_string())
.with_description("arg1".to_string())
.minus(&RevsetExpression::symbol("arg1".to_string()).parents())
.minus(&RevsetExpression::all_heads()))
);
}
#[test]
fn test_parse_revset_operator_combinations() {
let foo_symbol = RevsetExpression::symbol("foo".to_string());
// Parse repeated "parents" operator
assert_eq!(
parse(":::foo"),
Ok(Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Parents(Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("foo".to_string())
))))
))))
Ok(foo_symbol.parents().parents().parents())
);
// Parse repeated "children" operator
assert_eq!(
parse("foo:::"),
Ok(Rc::new(RevsetExpression::Children {
roots: Rc::new(RevsetExpression::Children {
roots: Rc::new(RevsetExpression::Children {
roots: Rc::new(RevsetExpression::Symbol("foo".to_string())),
heads: RevsetExpression::non_obsolete_heads(),
}),
heads: RevsetExpression::non_obsolete_heads(),
}),
heads: RevsetExpression::non_obsolete_heads()
}))
Ok(foo_symbol
.children(&RevsetExpression::all_non_obsolete_heads())
.children(&RevsetExpression::all_non_obsolete_heads())
.children(&RevsetExpression::all_non_obsolete_heads()))
);
// Parse repeated "ancestors"/"descendants"/"dag range" operators
assert_matches!(parse(",,foo,,"), Err(RevsetParseError::SyntaxError(_)));
@ -1268,58 +1349,33 @@ mod tests {
// The former bind more strongly.
assert_eq!(
parse(":foo:"),
Ok(Rc::new(RevsetExpression::Children {
roots: Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("foo".to_string())
))),
heads: RevsetExpression::non_obsolete_heads(),
}))
Ok(foo_symbol
.parents()
.children(&RevsetExpression::all_non_obsolete_heads()))
);
assert_eq!(
parse(":foo,,"),
Ok(Rc::new(RevsetExpression::DagRange {
roots: Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("foo".to_string())
))),
heads: RevsetExpression::non_obsolete_heads(),
}))
Ok(foo_symbol
.parents()
.descendants(&RevsetExpression::all_non_obsolete_heads()))
);
assert_eq!(
parse(",,foo:"),
Ok(Rc::new(RevsetExpression::Ancestors(Rc::new(
RevsetExpression::Children {
roots: Rc::new(RevsetExpression::Symbol("foo".to_string())),
heads: RevsetExpression::non_obsolete_heads()
}
))))
Ok(foo_symbol
.children(&RevsetExpression::all_non_obsolete_heads())
.ancestors())
);
}
#[test]
fn test_parse_revset_function() {
assert_eq!(
parse("parents(@)"),
Ok(Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("@".to_string())
))))
);
assert_eq!(
parse("parents((@))"),
Ok(Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("@".to_string())
))))
);
assert_eq!(
parse("parents(\"@\")"),
Ok(Rc::new(RevsetExpression::Parents(Rc::new(
RevsetExpression::Symbol("@".to_string())
))))
);
let checkout_symbol = RevsetExpression::symbol("@".to_string());
assert_eq!(parse("parents(@)"), Ok(checkout_symbol.parents()));
assert_eq!(parse("parents((@))"), Ok(checkout_symbol.parents()));
assert_eq!(parse("parents(\"@\")"), Ok(checkout_symbol.parents()));
assert_eq!(
parse("ancestors(parents(@))"),
Ok(Rc::new(RevsetExpression::Ancestors(Rc::new(
RevsetExpression::Parents(Rc::new(RevsetExpression::Symbol("@".to_string())))
))))
Ok(checkout_symbol.parents().ancestors())
);
assert_matches!(parse("parents(@"), Err(RevsetParseError::SyntaxError(_)));
assert_eq!(
@ -1331,10 +1387,7 @@ mod tests {
);
assert_eq!(
parse("description(foo,bar)"),
Ok(Rc::new(RevsetExpression::Description {
needle: "foo".to_string(),
candidates: Rc::new(RevsetExpression::Symbol("bar".to_string()))
}))
Ok(RevsetExpression::symbol("bar".to_string()).with_description("foo".to_string()))
);
assert_eq!(
parse("description(all_heads(),bar)"),
@ -1346,17 +1399,11 @@ mod tests {
);
assert_eq!(
parse("description((foo),bar)"),
Ok(Rc::new(RevsetExpression::Description {
needle: "foo".to_string(),
candidates: Rc::new(RevsetExpression::Symbol("bar".to_string()))
}))
Ok(RevsetExpression::symbol("bar".to_string()).with_description("foo".to_string()))
);
assert_eq!(
parse("description(\"(foo)\",bar)"),
Ok(Rc::new(RevsetExpression::Description {
needle: "(foo)".to_string(),
candidates: Rc::new(RevsetExpression::Symbol("bar".to_string()))
}))
Ok(RevsetExpression::symbol("bar".to_string()).with_description("(foo)".to_string()))
);
}
}