diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 358a3a55755..715afb5bad6 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -5995,10 +5995,12 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression return garbage(working_set, span); } + let mut unclosed = false; + let mut extra_tokens = false; if bytes.ends_with(b"}") { end -= 1; } else { - working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end))); + unclosed = true; } let inner_span = Span::new(start, end); @@ -6009,7 +6011,12 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression error: None, span_offset: start, }; - loop { + while !lex_state.input.is_empty() { + if lex_state.input[0] == b'}' { + extra_tokens = true; + unclosed = false; + break; + } let additional_whitespace = &[b'\n', b'\r', b',']; if lex_n_tokens(&mut lex_state, additional_whitespace, &[b':'], true, 1) < 1 { break; @@ -6038,6 +6045,15 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression } let (tokens, err) = (lex_state.output, lex_state.error); + if unclosed { + working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end))); + } else if extra_tokens { + working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(Span::new( + lex_state.span_offset + 1, + end, + ))); + } + if let Some(err) = err { working_set.error(err); } diff --git a/crates/nu-parser/tests/test_parser.rs b/crates/nu-parser/tests/test_parser.rs index ac9bb512bae..7ae686f797b 100644 --- a/crates/nu-parser/tests/test_parser.rs +++ b/crates/nu-parser/tests/test_parser.rs @@ -2818,4 +2818,16 @@ mod record { _ => panic!("Expected full cell path"), } } + + /// Regression test for https://github.com/nushell/nushell/issues/15243 + #[test] + fn record_terminate_loop() { + let engine_state = EngineState::new(); + let mut working_set = StateWorkingSet::new(&engine_state); + parse(&mut working_set, None, b"{a:b}/", false); + assert_eq!( + working_set.parse_errors.first().map(|e| e.to_string()), + Some("Invalid characters after closing delimiter".to_string()) + ); + } }