revset: leverage SOI/EOI markers to detect incomplete parser input

The error message is still a bit cryptic, but I don't think it's worse than
the original "incomplete parse" error.

https://pest.rs/book/grammars/syntax.html#start-and-end-of-input
This commit is contained in:
Yuya Nishihara 2022-11-16 16:47:00 +09:00
parent a81ebeb85e
commit 1717690a64
3 changed files with 20 additions and 13 deletions

View file

@ -66,3 +66,5 @@ infix_expression = {
expression = { expression = {
whitespace* ~ infix_expression ~ whitespace* whitespace* ~ infix_expression ~ whitespace*
} }
program = _{ SOI ~ expression ~ EOI }

View file

@ -857,20 +857,8 @@ pub fn parse(
revset_str: &str, revset_str: &str,
workspace_ctx: Option<&RevsetWorkspaceContext>, workspace_ctx: Option<&RevsetWorkspaceContext>,
) -> Result<Rc<RevsetExpression>, RevsetParseError> { ) -> Result<Rc<RevsetExpression>, RevsetParseError> {
let mut pairs = RevsetParser::parse(Rule::expression, revset_str)?; let mut pairs = RevsetParser::parse(Rule::program, revset_str)?;
let first = pairs.next().unwrap(); let first = pairs.next().unwrap();
assert!(pairs.next().is_none());
if first.as_span().end() != revset_str.len() {
let pos = pest::Position::new(revset_str, first.as_span().end()).unwrap();
let err = pest::error::Error::new_from_pos(
pest::error::ErrorVariant::CustomError {
message: "Incomplete parse".to_string(),
},
pos,
);
return Err(RevsetParseError::from(err));
}
parse_expression_rule(first.into_inner(), workspace_ctx) parse_expression_rule(first.into_inner(), workspace_ctx)
} }

View file

@ -16,6 +16,23 @@ use common::TestEnvironment;
pub mod common; pub mod common;
#[test]
fn test_syntax_error() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "x &"]);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse revset: --> 1:4
|
1 | x &
| ^---
|
= expected range_expression
"###);
}
#[test] #[test]
fn test_bad_function_call() { fn test_bad_function_call() {
let test_env = TestEnvironment::default(); let test_env = TestEnvironment::default();