forked from mirrors/jj
revsets: give parents/children operators higher precedence than range operators
This commit is contained in:
parent
9de5f94af6
commit
d8c209c82a
3 changed files with 68 additions and 42 deletions
|
@ -20,13 +20,13 @@ symbol = {
|
||||||
literal_string = { "\"" ~ (!"\"" ~ ANY)+ ~ "\"" }
|
literal_string = { "\"" ~ (!"\"" ~ ANY)+ ~ "\"" }
|
||||||
whitespace = _{ " " }
|
whitespace = _{ " " }
|
||||||
|
|
||||||
|
// We could use the same rule name for the shared operators if we can
|
||||||
|
// think of a good name.
|
||||||
parents_op = { ":" }
|
parents_op = { ":" }
|
||||||
ancestors_op = { ",," }
|
|
||||||
prefix_op = _{ parents_op | ancestors_op }
|
|
||||||
|
|
||||||
children_op = { ":" }
|
children_op = { ":" }
|
||||||
|
|
||||||
|
ancestors_op = { ",," }
|
||||||
descendants_op = { ",," }
|
descendants_op = { ",," }
|
||||||
postfix_op = _{ children_op | descendants_op }
|
|
||||||
|
|
||||||
union_op = { "|" }
|
union_op = { "|" }
|
||||||
intersection_op = { "&" }
|
intersection_op = { "&" }
|
||||||
|
@ -45,12 +45,18 @@ primary = {
|
||||||
| symbol
|
| symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix_expression = { prefix_op* ~ primary }
|
parents_expression = { parents_op* ~ primary }
|
||||||
|
|
||||||
postfix_expression = { prefix_expression ~ postfix_op* }
|
children_expression = { parents_expression ~ children_op* }
|
||||||
|
|
||||||
|
range_expression = {
|
||||||
|
ancestors_op ~ children_expression
|
||||||
|
| children_expression ~ descendants_op
|
||||||
|
| children_expression
|
||||||
|
}
|
||||||
|
|
||||||
infix_expression = {
|
infix_expression = {
|
||||||
whitespace* ~ postfix_expression ~ whitespace* ~ (infix_op ~ whitespace* ~ postfix_expression ~ whitespace*)*
|
whitespace* ~ range_expression ~ whitespace* ~ (infix_op ~ whitespace* ~ range_expression ~ whitespace*)*
|
||||||
}
|
}
|
||||||
|
|
||||||
expression = {
|
expression = {
|
||||||
|
|
|
@ -153,9 +153,9 @@ fn parse_expression_rule(mut pairs: Pairs<Rule>) -> Result<RevsetExpression, Rev
|
||||||
fn parse_infix_expression_rule(
|
fn parse_infix_expression_rule(
|
||||||
mut pairs: Pairs<Rule>,
|
mut pairs: Pairs<Rule>,
|
||||||
) -> Result<RevsetExpression, RevsetParseError> {
|
) -> Result<RevsetExpression, RevsetParseError> {
|
||||||
let mut expression1 = parse_postfix_expression_rule(pairs.next().unwrap().into_inner())?;
|
let mut expression1 = parse_range_expression_rule(pairs.next().unwrap().into_inner())?;
|
||||||
while let Some(operator) = pairs.next() {
|
while let Some(operator) = pairs.next() {
|
||||||
let expression2 = parse_postfix_expression_rule(pairs.next().unwrap().into_inner())?;
|
let expression2 = parse_range_expression_rule(pairs.next().unwrap().into_inner())?;
|
||||||
match operator.as_rule() {
|
match operator.as_rule() {
|
||||||
Rule::union_op => {
|
Rule::union_op => {
|
||||||
expression1 = RevsetExpression::Union(Rc::new(expression1), Rc::new(expression2))
|
expression1 = RevsetExpression::Union(Rc::new(expression1), Rc::new(expression2))
|
||||||
|
@ -179,10 +179,44 @@ fn parse_infix_expression_rule(
|
||||||
Ok(expression1)
|
Ok(expression1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_postfix_expression_rule(
|
fn parse_range_expression_rule(
|
||||||
mut pairs: Pairs<Rule>,
|
mut pairs: Pairs<Rule>,
|
||||||
) -> Result<RevsetExpression, RevsetParseError> {
|
) -> Result<RevsetExpression, RevsetParseError> {
|
||||||
let mut expression = parse_prefix_expression_rule(pairs.next().unwrap().into_inner())?;
|
let first = pairs.next().unwrap();
|
||||||
|
match first.as_rule() {
|
||||||
|
Rule::ancestors_op => {
|
||||||
|
return Ok(RevsetExpression::Ancestors(Rc::new(
|
||||||
|
parse_children_expression_rule(pairs.next().unwrap().into_inner())?,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Rule::children_expression => {
|
||||||
|
// Fall through
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("unxpected revset range operator rule {:?}", first.as_rule());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut expression = parse_children_expression_rule(first.into_inner())?;
|
||||||
|
if let Some(next) = pairs.next() {
|
||||||
|
match next.as_rule() {
|
||||||
|
Rule::descendants_op => {
|
||||||
|
expression = RevsetExpression::DagRange {
|
||||||
|
roots: Rc::new(expression),
|
||||||
|
heads: RevsetExpression::non_obsolete_heads(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("unxpected revset range operator rule {:?}", next.as_rule());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_children_expression_rule(
|
||||||
|
mut pairs: Pairs<Rule>,
|
||||||
|
) -> Result<RevsetExpression, RevsetParseError> {
|
||||||
|
let mut expression = parse_parents_expression_rule(pairs.next().unwrap().into_inner())?;
|
||||||
for operator in pairs {
|
for operator in pairs {
|
||||||
match operator.as_rule() {
|
match operator.as_rule() {
|
||||||
Rule::children_op => {
|
Rule::children_op => {
|
||||||
|
@ -191,15 +225,9 @@ fn parse_postfix_expression_rule(
|
||||||
heads: RevsetExpression::non_obsolete_heads(),
|
heads: RevsetExpression::non_obsolete_heads(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Rule::descendants_op => {
|
|
||||||
expression = RevsetExpression::DagRange {
|
|
||||||
roots: Rc::new(expression),
|
|
||||||
heads: RevsetExpression::non_obsolete_heads(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
panic!(
|
panic!(
|
||||||
"unxpected revset postfix operator rule {:?}",
|
"unxpected revset children operator rule {:?}",
|
||||||
operator.as_rule()
|
operator.as_rule()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -208,21 +236,18 @@ fn parse_postfix_expression_rule(
|
||||||
Ok(expression)
|
Ok(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_prefix_expression_rule(
|
fn parse_parents_expression_rule(
|
||||||
mut pairs: Pairs<Rule>,
|
mut pairs: Pairs<Rule>,
|
||||||
) -> Result<RevsetExpression, RevsetParseError> {
|
) -> Result<RevsetExpression, RevsetParseError> {
|
||||||
let first = pairs.next().unwrap();
|
let first = pairs.next().unwrap();
|
||||||
match first.as_rule() {
|
match first.as_rule() {
|
||||||
Rule::primary => parse_primary_rule(first.into_inner()),
|
Rule::primary => parse_primary_rule(first.into_inner()),
|
||||||
Rule::parents_op => Ok(RevsetExpression::Parents(Rc::new(
|
Rule::parents_op => Ok(RevsetExpression::Parents(Rc::new(
|
||||||
parse_prefix_expression_rule(pairs)?,
|
parse_parents_expression_rule(pairs)?,
|
||||||
))),
|
|
||||||
Rule::ancestors_op => Ok(RevsetExpression::Ancestors(Rc::new(
|
|
||||||
parse_prefix_expression_rule(pairs)?,
|
|
||||||
))),
|
))),
|
||||||
_ => {
|
_ => {
|
||||||
panic!(
|
panic!(
|
||||||
"unxpected revset prefix operator rule {:?}",
|
"unxpected revset parents operator rule {:?}",
|
||||||
first.as_rule()
|
first.as_rule()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -934,8 +959,12 @@ mod tests {
|
||||||
heads: RevsetExpression::non_obsolete_heads()
|
heads: RevsetExpression::non_obsolete_heads()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// Parse combinations of prefix and postfix operators. They all currently have
|
// Parse repeated "ancestors"/"descendants" operators
|
||||||
// the same precedence, so ",,foo:" means "(,,foo):" and not ",,(foo:)".
|
assert_matches!(parse(",,foo,,"), Err(RevsetParseError::SyntaxError(_)));
|
||||||
|
assert_matches!(parse(",,,,foo"), Err(RevsetParseError::SyntaxError(_)));
|
||||||
|
assert_matches!(parse("foo,,,,"), Err(RevsetParseError::SyntaxError(_)));
|
||||||
|
// Parse combinations of "parents"/"children" operators and the range operators.
|
||||||
|
// The former bind more strongly.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(":foo:"),
|
parse(":foo:"),
|
||||||
Ok(RevsetExpression::Children {
|
Ok(RevsetExpression::Children {
|
||||||
|
@ -945,15 +974,6 @@ mod tests {
|
||||||
heads: RevsetExpression::non_obsolete_heads(),
|
heads: RevsetExpression::non_obsolete_heads(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
parse(",,foo,,"),
|
|
||||||
Ok(RevsetExpression::DagRange {
|
|
||||||
roots: Rc::new(RevsetExpression::Ancestors(Rc::new(
|
|
||||||
RevsetExpression::Symbol("foo".to_string())
|
|
||||||
))),
|
|
||||||
heads: RevsetExpression::non_obsolete_heads(),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(":foo,,"),
|
parse(":foo,,"),
|
||||||
Ok(RevsetExpression::DagRange {
|
Ok(RevsetExpression::DagRange {
|
||||||
|
@ -965,12 +985,12 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(",,foo:"),
|
parse(",,foo:"),
|
||||||
Ok(RevsetExpression::Children {
|
Ok(RevsetExpression::Ancestors(Rc::new(
|
||||||
roots: Rc::new(RevsetExpression::Ancestors(Rc::new(
|
RevsetExpression::Children {
|
||||||
RevsetExpression::Symbol("foo".to_string())
|
roots: Rc::new(RevsetExpression::Symbol("foo".to_string())),
|
||||||
))),
|
heads: RevsetExpression::non_obsolete_heads()
|
||||||
heads: RevsetExpression::non_obsolete_heads(),
|
}
|
||||||
})
|
),))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,7 @@ fn test_evaluate_expression_parents(use_git: bool) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_commit_ids(
|
resolve_commit_ids(
|
||||||
mut_repo.as_repo_ref(),
|
mut_repo.as_repo_ref(),
|
||||||
&format!(":,,{}", commit2.id().hex())
|
&format!(":({} | {})", commit1.id().hex(), commit2.id().hex())
|
||||||
),
|
),
|
||||||
vec![commit1.id().clone(), root_commit.id().clone()]
|
vec![commit1.id().clone(), root_commit.id().clone()]
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue