mirror of
https://github.com/nushell/nushell
synced 2025-01-14 06:04:09 +00:00
Incorrect parsing of unbalanced braces based on issue 6914 (#7621)
This commit is contained in:
parent
ef660be285
commit
0bb2e47c98
6 changed files with 38 additions and 6 deletions
|
@ -396,7 +396,7 @@ proptest! {
|
||||||
{{"{0}": "sam"}} | to nuon | from nuon;
|
{{"{0}": "sam"}} | to nuon | from nuon;
|
||||||
"#, c).as_ref()
|
"#, c).as_ref()
|
||||||
));
|
));
|
||||||
assert!(actual.err.is_empty() || actual.err.contains("Unexpected end of code") || actual.err.contains("only strings can be keys"));
|
assert!(actual.err.is_empty() || actual.err.contains("Unexpected end of code") || actual.err.contains("only strings can be keys") || actual.err.contains("unbalanced { and }"));
|
||||||
// The second is for weird escapes due to backslashes
|
// The second is for weird escapes due to backslashes
|
||||||
// The third is for chars like '0'
|
// The third is for chars like '0'
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,10 @@ pub enum ParseError {
|
||||||
#[diagnostic(code(nu::parser::unclosed_delimiter), url(docsrs))]
|
#[diagnostic(code(nu::parser::unclosed_delimiter), url(docsrs))]
|
||||||
Unclosed(String, #[label("unclosed {0}")] Span),
|
Unclosed(String, #[label("unclosed {0}")] Span),
|
||||||
|
|
||||||
|
#[error("Unbalanced delimiter.")]
|
||||||
|
#[diagnostic(code(nu::parser::unbalanced_delimiter), url(docsrs))]
|
||||||
|
Unbalanced(String, String, #[label("unbalanced {0} and {1}")] Span),
|
||||||
|
|
||||||
#[error("Parse mismatch during operation.")]
|
#[error("Parse mismatch during operation.")]
|
||||||
#[diagnostic(code(nu::parser::parse_mismatch), url(docsrs))]
|
#[diagnostic(code(nu::parser::parse_mismatch), url(docsrs))]
|
||||||
Expected(String, #[label("expected {0}")] Span),
|
Expected(String, #[label("expected {0}")] Span),
|
||||||
|
@ -450,6 +454,7 @@ impl ParseError {
|
||||||
ParseError::ExtraPositional(_, s) => *s,
|
ParseError::ExtraPositional(_, s) => *s,
|
||||||
ParseError::UnexpectedEof(_, s) => *s,
|
ParseError::UnexpectedEof(_, s) => *s,
|
||||||
ParseError::Unclosed(_, s) => *s,
|
ParseError::Unclosed(_, s) => *s,
|
||||||
|
ParseError::Unbalanced(_, _, s) => *s,
|
||||||
ParseError::Expected(_, s) => *s,
|
ParseError::Expected(_, s) => *s,
|
||||||
ParseError::Mismatch(_, _, s) => *s,
|
ParseError::Mismatch(_, _, s) => *s,
|
||||||
ParseError::UnsupportedOperation(_, _, _, s, _) => *s,
|
ParseError::UnsupportedOperation(_, _, _, s, _) => *s,
|
||||||
|
|
|
@ -170,6 +170,23 @@ pub fn lex_item(
|
||||||
// We encountered a closing `}` delimiter. Pop off the opening `{`.
|
// We encountered a closing `}` delimiter. Pop off the opening `{`.
|
||||||
if let Some(BlockKind::CurlyBracket) = block_level.last() {
|
if let Some(BlockKind::CurlyBracket) = block_level.last() {
|
||||||
let _ = block_level.pop();
|
let _ = block_level.pop();
|
||||||
|
} else {
|
||||||
|
// We encountered a closing `}` delimiter, but the last opening
|
||||||
|
// delimiter was not a `{`. This is an error.
|
||||||
|
let span = Span::new(span_offset + token_start, span_offset + *curr_offset);
|
||||||
|
|
||||||
|
*curr_offset += 1;
|
||||||
|
return (
|
||||||
|
Token {
|
||||||
|
contents: TokenContents::Item,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
Some(ParseError::Unbalanced(
|
||||||
|
"{".to_string(),
|
||||||
|
"}".to_string(),
|
||||||
|
Span::new(span.end, span.end),
|
||||||
|
)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if c == b'(' {
|
} else if c == b'(' {
|
||||||
// We encountered an opening `(` delimiter.
|
// We encountered an opening `(` delimiter.
|
||||||
|
|
|
@ -4392,10 +4392,15 @@ pub fn parse_value(
|
||||||
}
|
}
|
||||||
b'{' => {
|
b'{' => {
|
||||||
if !matches!(shape, SyntaxShape::Closure(..)) && !matches!(shape, SyntaxShape::Block) {
|
if !matches!(shape, SyntaxShape::Closure(..)) && !matches!(shape, SyntaxShape::Block) {
|
||||||
if let (expr, None) =
|
let (expr, err) =
|
||||||
parse_full_cell_path(working_set, None, span, expand_aliases_denylist)
|
parse_full_cell_path(working_set, None, span, expand_aliases_denylist);
|
||||||
{
|
match err {
|
||||||
return (expr, None);
|
Some(err) => {
|
||||||
|
if let ParseError::Unbalanced(_, _, _) = err {
|
||||||
|
return (expr, Some(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => return (expr, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matches!(shape, SyntaxShape::Closure(_)) || matches!(shape, SyntaxShape::Any) {
|
if matches!(shape, SyntaxShape::Closure(_)) || matches!(shape, SyntaxShape::Any) {
|
||||||
|
|
|
@ -470,3 +470,8 @@ fn or_and_xor() -> TestResult {
|
||||||
// Assumes the precedence NOT > AND > XOR > OR
|
// Assumes the precedence NOT > AND > XOR > OR
|
||||||
run_test(r#"true or false xor true or false"#, "true")
|
run_test(r#"true or false xor true or false"#, "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbalanced_delimiter() -> TestResult {
|
||||||
|
fail_test(r#"{a:{b:5}}}"#, "unbalanced { and }")
|
||||||
|
}
|
||||||
|
|
|
@ -2,4 +2,4 @@ export def foo [] { "foo" }
|
||||||
|
|
||||||
export alias bar = "bar"
|
export alias bar = "bar"
|
||||||
|
|
||||||
export-env { let-env BAZ = "baz" } }
|
export-env { let-env BAZ = "baz" }
|
||||||
|
|
Loading…
Reference in a new issue