diff --git a/crates/nu-parser/src/lex.rs b/crates/nu-parser/src/lex.rs index f9e75d13f0..4639cae25d 100644 --- a/crates/nu-parser/src/lex.rs +++ b/crates/nu-parser/src/lex.rs @@ -129,7 +129,7 @@ pub fn lex_item( }, Some(ParseError::UnexpectedEof( (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); - // 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 { // 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 @@ -273,11 +258,28 @@ pub fn lex_item( }, Some(ParseError::UnexpectedEof( (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 *curr_offset - token_start == 0 { return ( @@ -395,9 +397,11 @@ fn lex_raw_string( *curr_offset += 1 } if !matches { + let mut expected = '\''.to_string(); + expected.push_str(&"#".repeat(prefix_sharp_cnt)); return Err(ParseError::UnexpectedEof( - "#".to_string(), - Span::new(span_offset + *curr_offset, span_offset + *curr_offset), + expected, + Span::new(span_offset + *curr_offset - 1, span_offset + *curr_offset), )); } Ok(()) diff --git a/tests/repl/test_strings.rs b/tests/repl/test_strings.rs index cafd6cc681..fa6c419e23 100644 --- a/tests/repl/test_strings.rs +++ b/tests/repl/test_strings.rs @@ -154,6 +154,18 @@ fn raw_string_inside_closure() -> TestResult { } #[test] -fn incomplete_raw_string() -> TestResult { - fail_test("r#abc", "expected '") +fn incomplete_string() -> TestResult { + 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 \"", + ) }