mirror of
https://github.com/nushell/nushell.git
synced 2025-04-01 03:36:53 +02:00
make better messages for incomplete string (#12868)
# Description Fixes: #12795 The issue is caused by an empty position of `ParseError::UnexpectedEof`. So no detailed message is displayed. To fix the issue, I adjust the start of span to `span.end - 1`. In this way, we can make sure that it never points to an empty position. After lexing item, I also reorder the unclosed character checking . Now it will be checking unclosed opening delimiters first. # User-Facing Changes After this pr, it outputs detailed error message for incomplete string when running scripts. ## Before ``` ❯ nu -c "'ab" Error: nu::parser::unexpected_eof × Unexpected end of code. ╭─[source:1:4] 1 │ 'ab ╰──── > ./target/debug/nu -c "r#'ab" Error: nu::parser::unexpected_eof × Unexpected end of code. ╭─[source:1:6] 1 │ r#'ab ╰──── ``` ## After ``` > nu -c "'ab" Error: nu::parser::unexpected_eof × Unexpected end of code. ╭─[source:1:3] 1 │ 'ab · ┬ · ╰── expected closing ' ╰──── > ./target/debug/nu -c "r#'ab" Error: nu::parser::unexpected_eof × Unexpected end of code. ╭─[source:1:5] 1 │ r#'ab · ┬ · ╰── expected closing '# ╰──── ``` # Tests + Formatting Added some tests for incomplete string. --------- Co-authored-by: Ian Manske <ian.manske@pm.me>
This commit is contained in:
parent
9bf4d3ece6
commit
155934f783
@ -129,7 +129,7 @@ pub fn lex_item(
|
|||||||
},
|
},
|
||||||
Some(ParseError::UnexpectedEof(
|
Some(ParseError::UnexpectedEof(
|
||||||
(start as char).to_string(),
|
(start as char).to_string(),
|
||||||
Span::new(span.end, span.end),
|
Span::new(span.end - 1, span.end),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -247,21 +247,6 @@ pub fn lex_item(
|
|||||||
|
|
||||||
let span = Span::new(span_offset + token_start, span_offset + *curr_offset);
|
let span = Span::new(span_offset + token_start, span_offset + *curr_offset);
|
||||||
|
|
||||||
// If there is still unclosed opening delimiters, remember they were missing
|
|
||||||
if let Some(block) = block_level.last() {
|
|
||||||
let delim = block.closing();
|
|
||||||
let cause =
|
|
||||||
ParseError::UnexpectedEof((delim as char).to_string(), Span::new(span.end, span.end));
|
|
||||||
|
|
||||||
return (
|
|
||||||
Token {
|
|
||||||
contents: TokenContents::Item,
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
Some(cause),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(delim) = quote_start {
|
if let Some(delim) = quote_start {
|
||||||
// The non-lite parse trims quotes on both sides, so we add the expected quote so that
|
// The non-lite parse trims quotes on both sides, so we add the expected quote so that
|
||||||
// anyone wanting to consume this partial parse (e.g., completions) will be able to get
|
// anyone wanting to consume this partial parse (e.g., completions) will be able to get
|
||||||
@ -273,11 +258,28 @@ pub fn lex_item(
|
|||||||
},
|
},
|
||||||
Some(ParseError::UnexpectedEof(
|
Some(ParseError::UnexpectedEof(
|
||||||
(delim as char).to_string(),
|
(delim as char).to_string(),
|
||||||
Span::new(span.end, span.end),
|
Span::new(span.end - 1, span.end),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is still unclosed opening delimiters, remember they were missing
|
||||||
|
if let Some(block) = block_level.last() {
|
||||||
|
let delim = block.closing();
|
||||||
|
let cause = ParseError::UnexpectedEof(
|
||||||
|
(delim as char).to_string(),
|
||||||
|
Span::new(span.end - 1, span.end),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
Token {
|
||||||
|
contents: TokenContents::Item,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
Some(cause),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// If we didn't accumulate any characters, it's an unexpected error.
|
// If we didn't accumulate any characters, it's an unexpected error.
|
||||||
if *curr_offset - token_start == 0 {
|
if *curr_offset - token_start == 0 {
|
||||||
return (
|
return (
|
||||||
@ -395,9 +397,11 @@ fn lex_raw_string(
|
|||||||
*curr_offset += 1
|
*curr_offset += 1
|
||||||
}
|
}
|
||||||
if !matches {
|
if !matches {
|
||||||
|
let mut expected = '\''.to_string();
|
||||||
|
expected.push_str(&"#".repeat(prefix_sharp_cnt));
|
||||||
return Err(ParseError::UnexpectedEof(
|
return Err(ParseError::UnexpectedEof(
|
||||||
"#".to_string(),
|
expected,
|
||||||
Span::new(span_offset + *curr_offset, span_offset + *curr_offset),
|
Span::new(span_offset + *curr_offset - 1, span_offset + *curr_offset),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -154,6 +154,18 @@ fn raw_string_inside_closure() -> TestResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn incomplete_raw_string() -> TestResult {
|
fn incomplete_string() -> TestResult {
|
||||||
fail_test("r#abc", "expected '")
|
fail_test("r#abc", "expected '")?;
|
||||||
|
fail_test("r#'bc", "expected closing '#")?;
|
||||||
|
fail_test("'ab\"", "expected closing '")?;
|
||||||
|
fail_test("\"ab'", "expected closing \"")?;
|
||||||
|
fail_test(
|
||||||
|
r#"def func [] {
|
||||||
|
{
|
||||||
|
"A": ""B" # <- the quote is bad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"expected closing \"",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user