mirror of
https://github.com/martinvonz/jj.git
synced 2025-05-30 11:31:13 +00:00
revset: parse hg-like '-'/'+' infix operators and show hint
Suggested by @arxanas. Actually, it's easier to support these infix ops than erroring out, but I don't want to make revset syntax more cryptic. "x- y" can't be handled by this rule because "x-" is parsed as a parents expression.
This commit is contained in:
parent
7b09124bcb
commit
7cd01b27a7
@ -41,7 +41,9 @@ negate_op = { "~" }
|
|||||||
union_op = { "|" }
|
union_op = { "|" }
|
||||||
intersection_op = { "&" }
|
intersection_op = { "&" }
|
||||||
difference_op = { "~" }
|
difference_op = { "~" }
|
||||||
infix_op = _{ union_op | intersection_op | difference_op }
|
compat_add_op = { "+" }
|
||||||
|
compat_sub_op = { "-" }
|
||||||
|
infix_op = _{ union_op | intersection_op | difference_op | compat_add_op | compat_sub_op }
|
||||||
|
|
||||||
function_name = @{ (ASCII_ALPHANUMERIC | "_")+ }
|
function_name = @{ (ASCII_ALPHANUMERIC | "_")+ }
|
||||||
function_arguments = {
|
function_arguments = {
|
||||||
|
@ -215,6 +215,12 @@ pub struct RevsetParseError {
|
|||||||
pub enum RevsetParseErrorKind {
|
pub enum RevsetParseErrorKind {
|
||||||
#[error("Syntax error")]
|
#[error("Syntax error")]
|
||||||
SyntaxError,
|
SyntaxError,
|
||||||
|
#[error("'{op}' is not an infix operator (Did you mean '{similar_op}' for {description}?)")]
|
||||||
|
NotInfixOperator {
|
||||||
|
op: String,
|
||||||
|
similar_op: String,
|
||||||
|
description: String,
|
||||||
|
},
|
||||||
#[error("Revset function \"{0}\" doesn't exist")]
|
#[error("Revset function \"{0}\" doesn't exist")]
|
||||||
NoSuchFunction(String),
|
NoSuchFunction(String),
|
||||||
#[error("Invalid arguments to revset function \"{name}\": {message}")]
|
#[error("Invalid arguments to revset function \"{name}\": {message}")]
|
||||||
@ -695,11 +701,28 @@ fn parse_expression_rule(
|
|||||||
pairs: Pairs<Rule>,
|
pairs: Pairs<Rule>,
|
||||||
state: ParseState,
|
state: ParseState,
|
||||||
) -> Result<Rc<RevsetExpression>, RevsetParseError> {
|
) -> Result<Rc<RevsetExpression>, RevsetParseError> {
|
||||||
|
fn not_infix_op(
|
||||||
|
op: &Pair<Rule>,
|
||||||
|
similar_op: impl Into<String>,
|
||||||
|
description: impl Into<String>,
|
||||||
|
) -> RevsetParseError {
|
||||||
|
RevsetParseError::with_span(
|
||||||
|
RevsetParseErrorKind::NotInfixOperator {
|
||||||
|
op: op.as_str().to_owned(),
|
||||||
|
similar_op: similar_op.into(),
|
||||||
|
description: description.into(),
|
||||||
|
},
|
||||||
|
op.as_span(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| {
|
static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| {
|
||||||
PrattParser::new()
|
PrattParser::new()
|
||||||
.op(Op::infix(Rule::union_op, Assoc::Left))
|
.op(Op::infix(Rule::union_op, Assoc::Left)
|
||||||
|
| Op::infix(Rule::compat_add_op, Assoc::Left))
|
||||||
.op(Op::infix(Rule::intersection_op, Assoc::Left)
|
.op(Op::infix(Rule::intersection_op, Assoc::Left)
|
||||||
| Op::infix(Rule::difference_op, Assoc::Left))
|
| Op::infix(Rule::difference_op, Assoc::Left)
|
||||||
|
| Op::infix(Rule::compat_sub_op, Assoc::Left))
|
||||||
.op(Op::prefix(Rule::negate_op))
|
.op(Op::prefix(Rule::negate_op))
|
||||||
// Ranges can't be nested without parentheses. Associativity doesn't matter.
|
// Ranges can't be nested without parentheses. Associativity doesn't matter.
|
||||||
.op(Op::infix(Rule::dag_range_op, Assoc::Left) | Op::infix(Rule::range_op, Assoc::Left))
|
.op(Op::infix(Rule::dag_range_op, Assoc::Left) | Op::infix(Rule::range_op, Assoc::Left))
|
||||||
@ -724,8 +747,10 @@ fn parse_expression_rule(
|
|||||||
})
|
})
|
||||||
.map_infix(|lhs, op, rhs| match op.as_rule() {
|
.map_infix(|lhs, op, rhs| match op.as_rule() {
|
||||||
Rule::union_op => Ok(lhs?.union(&rhs?)),
|
Rule::union_op => Ok(lhs?.union(&rhs?)),
|
||||||
|
Rule::compat_add_op => Err(not_infix_op(&op, "|", "union")),
|
||||||
Rule::intersection_op => Ok(lhs?.intersection(&rhs?)),
|
Rule::intersection_op => Ok(lhs?.intersection(&rhs?)),
|
||||||
Rule::difference_op => Ok(lhs?.minus(&rhs?)),
|
Rule::difference_op => Ok(lhs?.minus(&rhs?)),
|
||||||
|
Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference")),
|
||||||
Rule::dag_range_op => Ok(lhs?.dag_range_to(&rhs?)),
|
Rule::dag_range_op => Ok(lhs?.dag_range_to(&rhs?)),
|
||||||
Rule::range_op => Ok(lhs?.range(&rhs?)),
|
Rule::range_op => Ok(lhs?.range(&rhs?)),
|
||||||
r => panic!("unexpected infix operator rule {r:?}"),
|
r => panic!("unexpected infix operator rule {r:?}"),
|
||||||
@ -2288,6 +2313,26 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_revset_compat_operator() {
|
||||||
|
assert_eq!(
|
||||||
|
parse("foo + bar"),
|
||||||
|
Err(RevsetParseErrorKind::NotInfixOperator {
|
||||||
|
op: "+".to_owned(),
|
||||||
|
similar_op: "|".to_owned(),
|
||||||
|
description: "union".to_owned(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse("foo - bar"),
|
||||||
|
Err(RevsetParseErrorKind::NotInfixOperator {
|
||||||
|
op: "-".to_owned(),
|
||||||
|
similar_op: "~".to_owned(),
|
||||||
|
description: "difference".to_owned(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_revset_operator_combinations() {
|
fn test_parse_revset_operator_combinations() {
|
||||||
let foo_symbol = RevsetExpression::symbol("foo".to_string());
|
let foo_symbol = RevsetExpression::symbol("foo".to_string());
|
||||||
|
@ -31,6 +31,16 @@ fn test_syntax_error() {
|
|||||||
|
|
|
|
||||||
= expected dag_range_pre_op, range_pre_op, negate_op, or primary
|
= expected dag_range_pre_op, range_pre_op, negate_op, or primary
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
|
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "x - y"]);
|
||||||
|
insta::assert_snapshot!(stderr, @r###"
|
||||||
|
Error: Failed to parse revset: --> 1:3
|
||||||
|
|
|
||||||
|
1 | x - y
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= '-' is not an infix operator (Did you mean '~' for difference?)
|
||||||
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user