Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

revset: translate symbol rules in error message #2218

Merged
merged 1 commit into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions cli/tests/test_revset_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn test_syntax_error() {
1 | x &
| ^---
|
= expected dag_range_pre_op, dag_range_all_op, legacy_dag_range_pre_op, range_pre_op, range_all_op, negate_op, or primary
= expected `::`, `..`, `~`, or <primary>
"###);

let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "x - y"]);
Expand Down Expand Up @@ -192,7 +192,7 @@ fn test_bad_function_call() {
1 | remote_branches(=foo)
| ^---
|
= expected identifier or expression
= expected <identifier> or <expression>
"###);

let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "remote_branches(remote=)"]);
Expand All @@ -202,7 +202,7 @@ fn test_bad_function_call() {
1 | remote_branches(remote=)
| ^---
|
= expected expression
= expected <expression>
"###);
}

Expand Down Expand Up @@ -287,7 +287,7 @@ fn test_alias() {
1 | whatever &
| ^---
|
= expected dag_range_pre_op, dag_range_all_op, legacy_dag_range_pre_op, range_pre_op, range_all_op, negate_op, or primary
= expected `::`, `..`, `~`, or <primary>
"###);

let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "identity()"]);
Expand Down Expand Up @@ -401,7 +401,7 @@ fn test_bad_alias_decl() {
1 | "bad"
| ^---
|
= expected identifier or function_name
= expected <identifier> or <function_name>
Failed to load "revset-aliases.badfn(a, a)": --> 1:7
|
1 | badfn(a, a)
Expand Down
98 changes: 96 additions & 2 deletions lib/src/revset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#![allow(missing_docs)]

use std::collections::{BTreeMap, HashMap};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::convert::Infallible;
use std::ops::Range;
use std::path::Path;
Expand Down Expand Up @@ -76,6 +76,74 @@ pub enum RevsetEvaluationError {
#[grammar = "revset.pest"]
pub struct RevsetParser;

impl Rule {
/// Whether this is a placeholder rule for compatibility with the other
/// systems.
fn is_compat(&self) -> bool {
matches!(
self,
Rule::compat_parents_op | Rule::compat_add_op | Rule::compat_sub_op
)
}

/// Whether this is a deprecated rule to be removed in later version.
fn is_legacy(&self) -> bool {
matches!(
self,
Rule::legacy_dag_range_op
| Rule::legacy_dag_range_pre_op
| Rule::legacy_dag_range_post_op
)
}

fn to_symbol(self) -> Option<&'static str> {
match self {
Rule::EOI => None,
Rule::identifier_part => None,
Rule::identifier => None,
Rule::symbol => None,
Rule::literal_string => None,
Rule::whitespace => None,
Rule::at_op => Some("@"),
Rule::parents_op => Some("-"),
Rule::children_op => Some("+"),
Rule::compat_parents_op => Some("^"),
Rule::dag_range_op
| Rule::dag_range_pre_op
| Rule::dag_range_post_op
| Rule::dag_range_all_op => Some("::"),
Rule::legacy_dag_range_op
| Rule::legacy_dag_range_pre_op
| Rule::legacy_dag_range_post_op => Some(":"),
Rule::range_op => Some(".."),
Rule::range_pre_op | Rule::range_post_op | Rule::range_all_op => Some(".."),
Rule::range_ops => None,
Rule::range_pre_ops => None,
Rule::range_post_ops => None,
Rule::range_all_ops => None,
Rule::negate_op => Some("~"),
Rule::union_op => Some("|"),
Rule::intersection_op => Some("&"),
Rule::difference_op => Some("~"),
Rule::compat_add_op => Some("+"),
Rule::compat_sub_op => Some("-"),
Rule::infix_op => None,
Rule::function_name => None,
Rule::keyword_argument => None,
Rule::argument => None,
Rule::function_arguments => None,
Rule::formal_parameters => None,
Rule::primary => None,
Rule::neighbors_expression => None,
Rule::range_expression => None,
Rule::expression => None,
Rule::program => None,
Rule::alias_declaration_part => None,
Rule::alias_declaration => None,
}
}
}

#[derive(Debug)]
pub struct RevsetParseError {
kind: RevsetParseErrorKind,
Expand Down Expand Up @@ -175,7 +243,7 @@ impl From<pest::error::Error<Rule>> for RevsetParseError {
fn from(err: pest::error::Error<Rule>) -> Self {
RevsetParseError {
kind: RevsetParseErrorKind::SyntaxError,
pest_error: Some(Box::new(err)),
pest_error: Some(Box::new(rename_rules_in_pest_error(err))),
origin: None,
}
}
Expand Down Expand Up @@ -207,6 +275,32 @@ impl error::Error for RevsetParseError {
}
}

fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
let pest::error::ErrorVariant::ParsingError {
positives,
negatives,
} = &mut err.variant
else {
return err;
};

// Remove duplicated symbols. Legacy or compat symbols are also removed from the
// (positive) suggestion.
let mut known_syms = HashSet::new();
positives.retain(|rule| {
!rule.is_compat()
&& !rule.is_legacy()
&& rule.to_symbol().map_or(true, |sym| known_syms.insert(sym))
});
let mut known_syms = HashSet::new();
negatives.retain(|rule| rule.to_symbol().map_or(true, |sym| known_syms.insert(sym)));
err.renamed_rules(|rule| {
rule.to_symbol()
.map(|sym| format!("`{sym}`"))
.unwrap_or_else(|| format!("<{rule:?}>"))
})
}

// assumes index has less than u64::MAX entries.
pub const GENERATION_RANGE_FULL: Range<u64> = 0..u64::MAX;
pub const GENERATION_RANGE_EMPTY: Range<u64> = 0..0;
Expand Down