diff --git a/CHANGELOG.md b/CHANGELOG.md index 4969a516d..0009547a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `committer(needle)`, `merges()` revsets. Use `x & description(needle)` instead. +* Adjusted precedence of revset union/intersection/difference operators. + `x | y & z` is now equivalent to `x | (y & z)`. + * Support for open commits has been dropped. The `ui.enable-open-commits` config that was added in 0.5.0 is no longer respected. The `jj open/close` commands have been deleted. diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 3aa3e55e7..df88c9f86 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -496,9 +496,10 @@ fn parse_infix_expression_rule( workspace_ctx: Option<&RevsetWorkspaceContext>, ) -> Result, RevsetParseError> { static PRATT: Lazy> = Lazy::new(|| { - PrattParser::new().op(Op::infix(Rule::union_op, Assoc::Left) - | Op::infix(Rule::intersection_op, Assoc::Left) - | Op::infix(Rule::difference_op, Assoc::Left)) + PrattParser::new() + .op(Op::infix(Rule::union_op, Assoc::Left)) + .op(Op::infix(Rule::intersection_op, Assoc::Left) + | Op::infix(Rule::difference_op, Assoc::Left)) }); PRATT .map_primary(|primary| parse_range_expression_rule(primary.into_inner(), workspace_ctx)) @@ -1847,6 +1848,11 @@ mod tests { parse("foo+++"), Ok(foo_symbol.children().children().children()) ); + // Set operator associativity/precedence + assert_eq!(parse("x|y|z").unwrap(), parse("(x|y)|z").unwrap()); + assert_eq!(parse("x&y|z").unwrap(), parse("(x&y)|z").unwrap()); + assert_eq!(parse("x|y&z").unwrap(), parse("x|(y&z)").unwrap()); + assert_eq!(parse("x|y~z").unwrap(), parse("x|(y~z)").unwrap()); // Parse repeated "ancestors"/"descendants"/"dag range"/"range" operators assert_eq!(parse(":foo:"), Err(RevsetParseErrorKind::SyntaxError)); assert_eq!(parse("::foo"), Err(RevsetParseErrorKind::SyntaxError));