Cut down on unnecessary parsing for SyntaxShape::Any (#9280)

# Description

This removes some unnecessary SyntaxShapes when parsing a
SyntaxShape::Any. Recent updates to the parser look for `{` and then
handle the logic for that separately.

# User-Facing Changes

This may have a slight parser speedup.

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the
standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
JT 2023-05-25 07:53:57 +12:00 committed by GitHub
parent 74724dee80
commit 7ead89844a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 148 deletions

View File

@ -1248,7 +1248,7 @@ mod test {
#[test] #[test]
fn test_lots_of_files() { fn test_lots_of_files() {
// this is a good test because it touches lots of differently named files // this is a good test because it touches lots of differently named files
glob("/*/*/*/*").unwrap().skip(10000).next(); glob("/*/*/*/*").unwrap().nth(10000);
} }
#[test] #[test]

View File

@ -1368,7 +1368,7 @@ pub fn parse_export_in_module(
} }
_ => { _ => {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"def, def-env, alias, use, module, or extern keyword".into(), "def, def-env, alias, use, module, or extern keyword",
spans[1], spans[1],
)); ));
@ -1713,7 +1713,7 @@ pub fn parse_module_block(
} => block.pipelines.push(garbage_pipeline(&command.parts)), } => block.pipelines.push(garbage_pipeline(&command.parts)),
} }
} else { } else {
working_set.error(ParseError::Expected("not a pipeline".into(), span)); working_set.error(ParseError::Expected("not a pipeline", span));
block.pipelines.push(garbage_pipeline(&[span])) block.pipelines.push(garbage_pipeline(&[span]))
} }
} }
@ -2042,7 +2042,7 @@ pub fn parse_module(
if block_bytes.starts_with(b"{") { if block_bytes.starts_with(b"{") {
start += 1; start += 1;
} else { } else {
working_set.error(ParseError::Expected("block".into(), block_span)); working_set.error(ParseError::Expected("block", block_span));
return (garbage_pipeline(spans), None); return (garbage_pipeline(spans), None);
} }

View File

@ -81,7 +81,7 @@ pub fn parse_variable_pattern(working_set: &mut StateWorkingSet, span: Span) ->
span, span,
} }
} else { } else {
working_set.error(ParseError::Expected("valid variable name".into(), span)); working_set.error(ParseError::Expected("valid variable name", span));
garbage(span) garbage(span)
} }
} }
@ -145,7 +145,7 @@ pub fn parse_list_pattern(working_set: &mut StateWorkingSet, span: Span) -> Matc
} else { } else {
args.push(garbage(command.parts[spans_idx])); args.push(garbage(command.parts[spans_idx]));
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name".into(), "valid variable name",
command.parts[spans_idx], command.parts[spans_idx],
)); ));
} }
@ -176,10 +176,7 @@ pub fn parse_record_pattern(working_set: &mut StateWorkingSet, span: Span) -> Ma
if bytes.starts_with(b"{") { if bytes.starts_with(b"{") {
start += 1; start += 1;
} else { } else {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("{", Span::new(start, start + 1)));
"{".into(),
Span::new(start, start + 1),
));
bytes = working_set.get_span_contents(span); bytes = working_set.get_span_contents(span);
} }
@ -214,14 +211,14 @@ pub fn parse_record_pattern(working_set: &mut StateWorkingSet, span: Span) -> Ma
idx += 1; idx += 1;
if idx == tokens.len() { if idx == tokens.len() {
working_set.error(ParseError::Expected("record".into(), span)); working_set.error(ParseError::Expected("record", span));
return garbage(span); return garbage(span);
} }
let colon = working_set.get_span_contents(tokens[idx].span); let colon = working_set.get_span_contents(tokens[idx].span);
idx += 1; idx += 1;
if idx == tokens.len() || colon != b":" { if idx == tokens.len() || colon != b":" {
//FIXME: need better error //FIXME: need better error
working_set.error(ParseError::Expected("record".into(), span)); working_set.error(ParseError::Expected("record", span));
return garbage(span); return garbage(span);
} }
let pattern = parse_pattern(working_set, tokens[idx].span); let pattern = parse_pattern(working_set, tokens[idx].span);

View File

@ -636,7 +636,10 @@ pub fn parse_multispan_value(
if starting_error_count == working_set.parse_errors.len() { if starting_error_count == working_set.parse_errors.len() {
return s; return s;
} else if let Some(ParseError::Expected(..)) = working_set.parse_errors.last() { } else if let Some(
ParseError::Expected(..) | ParseError::ExpectedWithStringMsg(..),
) = working_set.parse_errors.last()
{
working_set.parse_errors.truncate(starting_error_count); working_set.parse_errors.truncate(starting_error_count);
continue; continue;
} }
@ -664,7 +667,7 @@ pub fn parse_multispan_value(
let span = spans[*spans_idx]; let span = spans[*spans_idx];
if working_set.parse_errors.is_empty() { if working_set.parse_errors.is_empty() {
working_set.error(ParseError::Expected( working_set.error(ParseError::ExpectedWithStringMsg(
format!("one of a list of accepted shapes: {shapes:?}"), format!("one of a list of accepted shapes: {shapes:?}"),
span, span,
)); ));
@ -1177,8 +1180,11 @@ pub fn parse_binary(working_set: &mut StateWorkingSet, span: Span) -> Expression
parse_binary_with_base(working_set, span, 16, 2, b"0x[", b"]") parse_binary_with_base(working_set, span, 16, 2, b"0x[", b"]")
} else if contents.starts_with(b"0o[") { } else if contents.starts_with(b"0o[") {
parse_binary_with_base(working_set, span, 8, 3, b"0o[", b"]") parse_binary_with_base(working_set, span, 8, 3, b"0o[", b"]")
} else { } else if contents.starts_with(b"0b[") {
parse_binary_with_base(working_set, span, 2, 8, b"0b[", b"]") parse_binary_with_base(working_set, span, 2, 8, b"0b[", b"]")
} else {
working_set.error(ParseError::Expected("binary", span));
garbage(span)
} }
} }
@ -1218,7 +1224,7 @@ fn parse_binary_with_base(
| TokenContents::OutGreaterThan | TokenContents::OutGreaterThan
| TokenContents::ErrGreaterThan | TokenContents::ErrGreaterThan
| TokenContents::OutErrGreaterThan => { | TokenContents::OutErrGreaterThan => {
working_set.error(ParseError::Expected("binary".into(), span)); working_set.error(ParseError::Expected("binary", span));
return garbage(span); return garbage(span);
} }
TokenContents::Comment | TokenContents::Semicolon | TokenContents::Eol => {} TokenContents::Comment | TokenContents::Semicolon | TokenContents::Eol => {}
@ -1260,7 +1266,7 @@ fn parse_binary_with_base(
} }
} }
working_set.error(ParseError::Expected("binary".into(), span)); working_set.error(ParseError::Expected("binary", span));
garbage(span) garbage(span)
} }
@ -1312,7 +1318,7 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression {
let token = strip_underscores(token); let token = strip_underscores(token);
if token.is_empty() { if token.is_empty() {
working_set.error(ParseError::Expected("int".into(), span)); working_set.error(ParseError::Expected("int", span));
return garbage(span); return garbage(span);
} }
@ -1330,7 +1336,7 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression {
custom_completion: None, custom_completion: None,
} }
} else { } else {
working_set.error(ParseError::Expected("int".into(), span)); working_set.error(ParseError::Expected("int", span));
garbage(span) garbage(span)
} }
} }
@ -1347,7 +1353,7 @@ pub fn parse_float(working_set: &mut StateWorkingSet, span: Span) -> Expression
custom_completion: None, custom_completion: None,
} }
} else { } else {
working_set.error(ParseError::Expected("float".into(), span)); working_set.error(ParseError::Expected("float", span));
garbage(span) garbage(span)
} }
@ -1374,7 +1380,7 @@ pub fn parse_number(working_set: &mut StateWorkingSet, span: Span) -> Expression
} }
working_set.parse_errors.truncate(starting_error_count); working_set.parse_errors.truncate(starting_error_count);
working_set.error(ParseError::Expected("number".into(), span)); working_set.error(ParseError::Expected("number", span));
garbage(span) garbage(span)
} }
@ -1398,10 +1404,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression
}; };
if !token.contains("..") { if !token.contains("..") {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("at least one range bound set", span));
"at least one range bound set".into(),
span,
));
return garbage(span); return garbage(span);
} }
@ -1413,7 +1416,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression
2 => (Some(dotdot_pos[0]), dotdot_pos[1]), 2 => (Some(dotdot_pos[0]), dotdot_pos[1]),
_ => { _ => {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"one range operator ('..' or '..<') and optionally one next operator ('..')".into(), "one range operator ('..' or '..<') and optionally one next operator ('..')",
span, span,
)); ));
return garbage(span); return garbage(span);
@ -1430,7 +1433,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression
(RangeInclusion::RightExclusive, "..<", op_span) (RangeInclusion::RightExclusive, "..<", op_span)
} else { } else {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"inclusive operator preceding second range bound".into(), "inclusive operator preceding second range bound",
span, span,
)); ));
return garbage(span); return garbage(span);
@ -1473,10 +1476,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression
trace!("-- from: {:?} to: {:?}", from, to); trace!("-- from: {:?} to: {:?}", from, to);
if let (None, None) = (&from, &to) { if let (None, None) = (&from, &to) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("at least one range bound set", span));
"at least one range bound set".into(),
span,
));
return garbage(span); return garbage(span);
} }
@ -1567,7 +1567,7 @@ pub fn parse_brace_expr(
// and then revisit the parsing. // and then revisit the parsing.
if span.end <= (span.start + 1) { if span.end <= (span.start + 1) {
working_set.error(ParseError::Expected( working_set.error(ParseError::ExpectedWithStringMsg(
format!("non-block value: {shape}"), format!("non-block value: {shape}"),
span, span,
)); ));
@ -1611,7 +1611,7 @@ pub fn parse_brace_expr(
} else if matches!(shape, SyntaxShape::MatchBlock) { } else if matches!(shape, SyntaxShape::MatchBlock) {
parse_match_block_expression(working_set, span) parse_match_block_expression(working_set, span)
} else { } else {
working_set.error(ParseError::Expected( working_set.error(ParseError::ExpectedWithStringMsg(
format!("non-block value: {shape}"), format!("non-block value: {shape}"),
span, span,
)); ));
@ -1861,7 +1861,7 @@ pub fn parse_cell_path(
match expected_token { match expected_token {
TokenType::Dot => { TokenType::Dot => {
if bytes.len() != 1 || bytes[0] != b'.' { if bytes.len() != 1 || bytes[0] != b'.' {
working_set.error(ParseError::Expected('.'.into(), path_element.span)); working_set.error(ParseError::Expected(".", path_element.span));
return tail; return tail;
} }
expected_token = TokenType::PathMember; expected_token = TokenType::PathMember;
@ -1882,7 +1882,7 @@ pub fn parse_cell_path(
} }
expected_token = TokenType::Dot; expected_token = TokenType::Dot;
} else { } else {
working_set.error(ParseError::Expected(". or ?".into(), path_element.span)); working_set.error(ParseError::Expected(". or ?", path_element.span));
return tail; return tail;
} }
} }
@ -1917,10 +1917,8 @@ pub fn parse_cell_path(
}); });
} }
_ => { _ => {
working_set.error(ParseError::Expected( working_set
"string".into(), .error(ParseError::Expected("string", path_element.span));
path_element.span,
));
return tail; return tail;
} }
} }
@ -2113,7 +2111,7 @@ pub fn parse_directory(working_set: &mut StateWorkingSet, span: Span) -> Express
custom_completion: None, custom_completion: None,
} }
} else { } else {
working_set.error(ParseError::Expected("directory".into(), span)); working_set.error(ParseError::Expected("directory", span));
garbage(span) garbage(span)
} }
@ -2134,7 +2132,7 @@ pub fn parse_filepath(working_set: &mut StateWorkingSet, span: Span) -> Expressi
custom_completion: None, custom_completion: None,
} }
} else { } else {
working_set.error(ParseError::Expected("filepath".into(), span)); working_set.error(ParseError::Expected("filepath", span));
garbage(span) garbage(span)
} }
@ -2145,13 +2143,14 @@ pub fn parse_datetime(working_set: &mut StateWorkingSet, span: Span) -> Expressi
let bytes = working_set.get_span_contents(span); let bytes = working_set.get_span_contents(span);
if bytes.len() < 5 if bytes.len() < 6
|| !bytes[0].is_ascii_digit() || !bytes[0].is_ascii_digit()
|| !bytes[1].is_ascii_digit() || !bytes[1].is_ascii_digit()
|| !bytes[2].is_ascii_digit() || !bytes[2].is_ascii_digit()
|| !bytes[3].is_ascii_digit() || !bytes[3].is_ascii_digit()
|| bytes[4] != b'-'
{ {
working_set.error(ParseError::Expected("datetime".into(), span)); working_set.error(ParseError::Expected("datetime", span));
return garbage(span); return garbage(span);
} }
@ -2188,7 +2187,7 @@ pub fn parse_datetime(working_set: &mut StateWorkingSet, span: Span) -> Expressi
}; };
} }
working_set.error(ParseError::Expected("datetime".into(), span)); working_set.error(ParseError::Expected("datetime", span));
garbage(span) garbage(span)
} }
@ -2206,10 +2205,7 @@ pub fn parse_duration(working_set: &mut StateWorkingSet, span: Span) -> Expressi
garbage(span) garbage(span)
} }
None => { None => {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("duration with valid units", span));
"duration with valid units".into(),
span,
));
garbage(span) garbage(span)
} }
} }
@ -2230,10 +2226,7 @@ pub fn parse_filesize(working_set: &mut StateWorkingSet, span: Span) -> Expressi
garbage(span) garbage(span)
} }
None => { None => {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("filesize with valid units", span));
"filesize with valid units".into(),
span,
));
garbage(span) garbage(span)
} }
} }
@ -2401,7 +2394,7 @@ pub fn parse_glob_pattern(working_set: &mut StateWorkingSet, span: Span) -> Expr
custom_completion: None, custom_completion: None,
} }
} else { } else {
working_set.error(ParseError::Expected("glob pattern string".into(), span)); working_set.error(ParseError::Expected("glob pattern string", span));
garbage(span) garbage(span)
} }
@ -2589,10 +2582,7 @@ pub fn unescape_unquote_string(bytes: &[u8], span: Span) -> (String, Option<Pars
if let Ok(token) = String::from_utf8(bytes) { if let Ok(token) = String::from_utf8(bytes) {
(token, err) (token, err)
} else { } else {
( (String::new(), Some(ParseError::Expected("string", span)))
String::new(),
Some(ParseError::Expected("string".into(), span)),
)
} }
} else { } else {
let bytes = trim_quotes(bytes); let bytes = trim_quotes(bytes);
@ -2600,10 +2590,7 @@ pub fn unescape_unquote_string(bytes: &[u8], span: Span) -> (String, Option<Pars
if let Ok(token) = String::from_utf8(bytes.into()) { if let Ok(token) = String::from_utf8(bytes.into()) {
(token, None) (token, None)
} else { } else {
( (String::new(), Some(ParseError::Expected("string", span)))
String::new(),
Some(ParseError::Expected("string".into(), span)),
)
} }
} }
} }
@ -2614,7 +2601,7 @@ pub fn parse_string(working_set: &mut StateWorkingSet, span: Span) -> Expression
let bytes = working_set.get_span_contents(span); let bytes = working_set.get_span_contents(span);
if bytes.is_empty() { if bytes.is_empty() {
working_set.error(ParseError::Expected("String".into(), span)); working_set.error(ParseError::Expected("String", span));
return Expression::garbage(span); return Expression::garbage(span);
} }
@ -2681,7 +2668,7 @@ pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Exp
custom_completion: None, custom_completion: None,
} }
} else if token.contains(' ') { } else if token.contains(' ') {
working_set.error(ParseError::Expected("string".into(), span)); working_set.error(ParseError::Expected("string", span));
garbage(span) garbage(span)
} else { } else {
@ -2693,7 +2680,7 @@ pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Exp
} }
} }
} else { } else {
working_set.error(ParseError::Expected("string".into(), span)); working_set.error(ParseError::Expected("string", span));
garbage(span) garbage(span)
} }
} }
@ -2750,7 +2737,7 @@ pub fn parse_shape_name(
let command_name = trim_quotes(split[1]); let command_name = trim_quotes(split[1]);
if command_name.is_empty() { if command_name.is_empty() {
working_set.error(ParseError::Expected("a command name".into(), cmd_span)); working_set.error(ParseError::Expected("a command name", cmd_span));
return SyntaxShape::Any; return SyntaxShape::Any;
} }
@ -2848,10 +2835,8 @@ fn parse_collection_shape(
match maybe_colon.as_slice() { match maybe_colon.as_slice() {
b":" => { b":" => {
if idx + 1 == tokens.len() { if idx + 1 == tokens.len() {
working_set.error(ParseError::Expected( working_set
"type after colon".into(), .error(ParseError::Expected("type after colon", tokens[idx].span));
tokens[idx].span,
));
break; break;
} else { } else {
idx += 1; idx += 1;
@ -3110,7 +3095,7 @@ pub fn parse_var_with_opt_type(
if !is_variable(&var_name) { if !is_variable(&var_name) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name".into(), "valid variable name",
spans[*spans_idx], spans[*spans_idx],
)); ));
return garbage(spans[*spans_idx]); return garbage(spans[*spans_idx]);
@ -3129,7 +3114,7 @@ pub fn parse_var_with_opt_type(
if !is_variable(&var_name) { if !is_variable(&var_name) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name".into(), "valid variable name",
spans[*spans_idx], spans[*spans_idx],
)); ));
return garbage(spans[*spans_idx]); return garbage(spans[*spans_idx]);
@ -3150,7 +3135,7 @@ pub fn parse_var_with_opt_type(
if !is_variable(&var_name) { if !is_variable(&var_name) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name".into(), "valid variable name",
spans[*spans_idx], spans[*spans_idx],
)); ));
return garbage(spans[*spans_idx]); return garbage(spans[*spans_idx]);
@ -3243,10 +3228,7 @@ pub fn parse_signature(working_set: &mut StateWorkingSet, span: Span) -> Express
has_paren = true; has_paren = true;
start += 1; start += 1;
} else { } else {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("[ or (", Span::new(start, start + 1)));
"[ or (".into(),
Span::new(start, start + 1),
));
return garbage(span); return garbage(span);
} }
@ -3314,12 +3296,11 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
parse_mode = ParseMode::TypeMode; parse_mode = ParseMode::TypeMode;
} }
ParseMode::AfterCommaArgMode => { ParseMode::AfterCommaArgMode => {
working_set working_set.error(ParseError::Expected("parameter or flag", span));
.error(ParseError::Expected("parameter or flag".into(), span));
} }
ParseMode::TypeMode | ParseMode::DefaultValueMode => { ParseMode::TypeMode | ParseMode::DefaultValueMode => {
// We're seeing two types for the same thing for some reason, error // We're seeing two types for the same thing for some reason, error
working_set.error(ParseError::Expected("type".into(), span)); working_set.error(ParseError::Expected("type", span));
} }
} }
} }
@ -3330,12 +3311,11 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
parse_mode = ParseMode::DefaultValueMode; parse_mode = ParseMode::DefaultValueMode;
} }
ParseMode::AfterCommaArgMode => { ParseMode::AfterCommaArgMode => {
working_set working_set.error(ParseError::Expected("parameter or flag", span));
.error(ParseError::Expected("parameter or flag".into(), span));
} }
ParseMode::DefaultValueMode => { ParseMode::DefaultValueMode => {
// We're seeing two default values for some reason, error // We're seeing two default values for some reason, error
working_set.error(ParseError::Expected("default value".into(), span)); working_set.error(ParseError::Expected("default value", span));
} }
} }
} }
@ -3344,14 +3324,13 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
match parse_mode { match parse_mode {
ParseMode::ArgMode => parse_mode = ParseMode::AfterCommaArgMode, ParseMode::ArgMode => parse_mode = ParseMode::AfterCommaArgMode,
ParseMode::AfterCommaArgMode => { ParseMode::AfterCommaArgMode => {
working_set working_set.error(ParseError::Expected("parameter or flag", span));
.error(ParseError::Expected("parameter or flag".into(), span));
} }
ParseMode::TypeMode => { ParseMode::TypeMode => {
working_set.error(ParseError::Expected("type".into(), span)); working_set.error(ParseError::Expected("type", span));
} }
ParseMode::DefaultValueMode => { ParseMode::DefaultValueMode => {
working_set.error(ParseError::Expected("default value".into(), span)); working_set.error(ParseError::Expected("default value", span));
} }
} }
} else { } else {
@ -3375,7 +3354,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
if !is_variable(&variable_name) { if !is_variable(&variable_name) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name for this long flag".into(), "valid variable name for this long flag",
span, span,
)) ))
} }
@ -3396,7 +3375,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
})); }));
} else if flags.len() >= 3 { } else if flags.len() >= 3 {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"only one short flag alternative".into(), "only one short flag alternative",
span, span,
)); ));
} else { } else {
@ -3405,7 +3384,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
|| !short_flag.ends_with(b")") || !short_flag.ends_with(b")")
{ {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"short flag alternative for the long flag".into(), "short flag alternative for the long flag",
span, span,
)); ));
short_flag short_flag
@ -3430,7 +3409,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
if !is_variable(&variable_name) { if !is_variable(&variable_name) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name for this short flag".into(), "valid variable name for this short flag",
span, span,
)) ))
} }
@ -3453,8 +3432,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
default_value: None, default_value: None,
})); }));
} else { } else {
working_set working_set.error(ParseError::Expected("short flag", span));
.error(ParseError::Expected("short flag".into(), span));
} }
} }
parse_mode = ParseMode::ArgMode; parse_mode = ParseMode::ArgMode;
@ -3466,8 +3444,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
let chars: Vec<char> = short_flag.chars().collect(); let chars: Vec<char> = short_flag.chars().collect();
if chars.len() > 1 { if chars.len() > 1 {
working_set working_set.error(ParseError::Expected("short flag", span));
.error(ParseError::Expected("short flag".into(), span));
} }
let mut encoded_var_name = vec![0u8; 4]; let mut encoded_var_name = vec![0u8; 4];
@ -3476,7 +3453,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
if !is_variable(&variable_name) { if !is_variable(&variable_name) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name for this short flag".into(), "valid variable name for this short flag",
span, span,
)) ))
} }
@ -3499,16 +3476,13 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
// This is the same as the short flag in --b(-a) // This is the same as the short flag in --b(-a)
else if contents.starts_with(b"(-") { else if contents.starts_with(b"(-") {
if matches!(parse_mode, ParseMode::AfterCommaArgMode) { if matches!(parse_mode, ParseMode::AfterCommaArgMode) {
working_set.error(ParseError::Expected( working_set
"parameter or flag".into(), .error(ParseError::Expected("parameter or flag", span));
span,
));
} }
let short_flag = &contents[2..]; let short_flag = &contents[2..];
let short_flag = if !short_flag.ends_with(b")") { let short_flag = if !short_flag.ends_with(b")") {
working_set working_set.error(ParseError::Expected("short flag", span));
.error(ParseError::Expected("short flag".into(), span));
short_flag short_flag
} else { } else {
&short_flag[..(short_flag.len() - 1)] &short_flag[..(short_flag.len() - 1)]
@ -3522,7 +3496,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
Some(Arg::Flag(flag)) => { Some(Arg::Flag(flag)) => {
if flag.short.is_some() { if flag.short.is_some() {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"one short flag".into(), "one short flag",
span, span,
)); ));
} else { } else {
@ -3530,15 +3504,12 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
} }
} }
_ => { _ => {
working_set.error(ParseError::Expected( working_set
"unknown flag".into(), .error(ParseError::Expected("unknown flag", span));
span,
));
} }
} }
} else { } else {
working_set working_set.error(ParseError::Expected("short flag", span));
.error(ParseError::Expected("short flag".into(), span));
} }
} }
// Positional arg, optional // Positional arg, optional
@ -3548,7 +3519,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
if !is_variable(&contents) { if !is_variable(&contents) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name for this optional parameter".into(), "valid variable name for this optional parameter",
span, span,
)) ))
} }
@ -3575,7 +3546,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
if !is_variable(&contents_vec) { if !is_variable(&contents_vec) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name for this rest parameter".into(), "valid variable name for this rest parameter",
span, span,
)) ))
} }
@ -3599,7 +3570,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) ->
if !is_variable(&contents_vec) { if !is_variable(&contents_vec) {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"valid variable name for this parameter".into(), "valid variable name for this parameter",
span, span,
)) ))
} }
@ -4039,7 +4010,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) ->
if bytes.starts_with(b"{") { if bytes.starts_with(b"{") {
start += 1; start += 1;
} else { } else {
working_set.error(ParseError::Expected("block".into(), span)); working_set.error(ParseError::Expected("block", span));
return garbage(span); return garbage(span);
} }
if bytes.ends_with(b"}") { if bytes.ends_with(b"}") {
@ -4065,10 +4036,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) ->
contents: TokenContents::Pipe, contents: TokenContents::Pipe,
span, span,
}) => { }) => {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("block but found closure", *span));
"block but found closure".into(),
*span,
));
(None, 0) (None, 0)
} }
_ => (None, 0), _ => (None, 0),
@ -4117,7 +4085,7 @@ pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Spa
if bytes.starts_with(b"{") { if bytes.starts_with(b"{") {
start += 1; start += 1;
} else { } else {
working_set.error(ParseError::Expected("closure".into(), span)); working_set.error(ParseError::Expected("closure", span));
return garbage(span); return garbage(span);
} }
if bytes.ends_with(b"}") { if bytes.ends_with(b"}") {
@ -4274,7 +4242,7 @@ pub fn parse_closure_expression(
if bytes.starts_with(b"{") { if bytes.starts_with(b"{") {
start += 1; start += 1;
} else { } else {
working_set.error(ParseError::Expected("closure".into(), span)); working_set.error(ParseError::Expected("closure", span));
return garbage(span); return garbage(span);
} }
if bytes.ends_with(b"}") { if bytes.ends_with(b"}") {
@ -4343,7 +4311,7 @@ pub fn parse_closure_expression(
if let SyntaxShape::Closure(Some(v)) = shape { if let SyntaxShape::Closure(Some(v)) = shape {
if let Some((sig, sig_span)) = &signature { if let Some((sig, sig_span)) = &signature {
if sig.num_positionals() > v.len() { if sig.num_positionals() > v.len() {
working_set.error(ParseError::Expected( working_set.error(ParseError::ExpectedWithStringMsg(
format!( format!(
"{} closure parameter{}", "{} closure parameter{}",
v.len(), v.len(),
@ -4427,7 +4395,7 @@ pub fn parse_value(
custom_completion: None, custom_completion: None,
}; };
} else { } else {
working_set.error(ParseError::Expected("non-boolean value".into(), span)); working_set.error(ParseError::Expected("non-boolean value", span));
return Expression::garbage(span); return Expression::garbage(span);
} }
} }
@ -4440,7 +4408,7 @@ pub fn parse_value(
custom_completion: None, custom_completion: None,
}; };
} else { } else {
working_set.error(ParseError::Expected("non-boolean value".into(), span)); working_set.error(ParseError::Expected("non-boolean value", span));
return Expression::garbage(span); return Expression::garbage(span);
} }
} }
@ -4472,7 +4440,7 @@ pub fn parse_value(
| SyntaxShape::Table | SyntaxShape::Table
| SyntaxShape::Signature => {} | SyntaxShape::Signature => {}
_ => { _ => {
working_set.error(ParseError::Expected("non-[] value".into(), span)); working_set.error(ParseError::Expected("non-[] value", span));
return Expression::garbage(span); return Expression::garbage(span);
} }
}, },
@ -4502,7 +4470,7 @@ pub fn parse_value(
if bytes.starts_with(b"[") { if bytes.starts_with(b"[") {
parse_signature(working_set, span) parse_signature(working_set, span)
} else { } else {
working_set.error(ParseError::Expected("signature".into(), span)); working_set.error(ParseError::Expected("signature", span));
Expression::garbage(span) Expression::garbage(span)
} }
@ -4511,7 +4479,7 @@ pub fn parse_value(
if bytes.starts_with(b"[") { if bytes.starts_with(b"[") {
parse_list_expression(working_set, span, elem) parse_list_expression(working_set, span, elem)
} else { } else {
working_set.error(ParseError::Expected("list".into(), span)); working_set.error(ParseError::Expected("list", span));
Expression::garbage(span) Expression::garbage(span)
} }
@ -4520,7 +4488,7 @@ pub fn parse_value(
if bytes.starts_with(b"[") { if bytes.starts_with(b"[") {
parse_table_expression(working_set, span) parse_table_expression(working_set, span)
} else { } else {
working_set.error(ParseError::Expected("table".into(), span)); working_set.error(ParseError::Expected("table", span));
Expression::garbage(span) Expression::garbage(span)
} }
@ -4536,7 +4504,7 @@ pub fn parse_value(
custom_completion: None, custom_completion: None,
} }
} else { } else {
working_set.error(ParseError::Expected("bool".into(), span)); working_set.error(ParseError::Expected("bool", span));
Expression::garbage(span) Expression::garbage(span)
} }
@ -4545,10 +4513,7 @@ pub fn parse_value(
// Be sure to return ParseError::Expected(..) if invoked for one of these shapes, but lex // Be sure to return ParseError::Expected(..) if invoked for one of these shapes, but lex
// stream doesn't start with '{'} -- parsing in SyntaxShape::Any arm depends on this error variant. // stream doesn't start with '{'} -- parsing in SyntaxShape::Any arm depends on this error variant.
SyntaxShape::Block | SyntaxShape::Closure(..) | SyntaxShape::Record(_) => { SyntaxShape::Block | SyntaxShape::Closure(..) | SyntaxShape::Record(_) => {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("block, closure or record", span));
"block, closure or record".into(),
span,
));
Expression::garbage(span) Expression::garbage(span)
} }
@ -4563,10 +4528,7 @@ pub fn parse_value(
SyntaxShape::Filesize, SyntaxShape::Filesize,
SyntaxShape::Duration, SyntaxShape::Duration,
SyntaxShape::Range, SyntaxShape::Range,
SyntaxShape::DateTime, //FIXME requires 3 failed conversion attempts before failing SyntaxShape::DateTime,
SyntaxShape::Record(vec![]),
SyntaxShape::Closure(None),
SyntaxShape::Block,
SyntaxShape::Int, SyntaxShape::Int,
SyntaxShape::Number, SyntaxShape::Number,
SyntaxShape::String, SyntaxShape::String,
@ -4580,7 +4542,10 @@ pub fn parse_value(
return s; return s;
} else { } else {
match working_set.parse_errors.get(starting_error_count) { match working_set.parse_errors.get(starting_error_count) {
Some(ParseError::Expected(_, _)) => { Some(
ParseError::Expected(_, _)
| ParseError::ExpectedWithStringMsg(_, _),
) => {
working_set.parse_errors.truncate(starting_error_count); working_set.parse_errors.truncate(starting_error_count);
continue; continue;
} }
@ -4590,12 +4555,15 @@ pub fn parse_value(
} }
} }
} }
working_set.error(ParseError::Expected("any shape".into(), span)); working_set.error(ParseError::Expected("any shape", span));
garbage(span) garbage(span)
} }
} }
x => { x => {
working_set.error(ParseError::Expected(x.to_type().to_string(), span)); working_set.error(ParseError::ExpectedWithStringMsg(
x.to_type().to_string(),
span,
));
garbage(span) garbage(span)
} }
} }
@ -4727,7 +4695,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi
return garbage(span); return garbage(span);
} }
_ => { _ => {
working_set.error(ParseError::Expected("operator".into(), span)); working_set.error(ParseError::Expected("operator", span));
return garbage(span); return garbage(span);
} }
}; };
@ -4770,7 +4738,7 @@ pub fn parse_math_expression(
return parse_call(working_set, spans, spans[0], false); return parse_call(working_set, spans, spans[0], false);
} else { } else {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"expression".into(), "expression",
Span::new(spans[0].end, spans[0].end), Span::new(spans[0].end, spans[0].end),
)); ));
return garbage(spans[0]); return garbage(spans[0]);
@ -4786,7 +4754,7 @@ pub fn parse_math_expression(
}; };
} else { } else {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected(
"expression".into(), "expression",
Span::new(spans[0].end, spans[0].end), Span::new(spans[0].end, spans[0].end),
)); ));
return garbage(spans[0]); return garbage(spans[0]);
@ -5099,7 +5067,7 @@ pub fn parse_variable(working_set: &mut StateWorkingSet, span: Span) -> Option<V
None None
} }
} else { } else {
working_set.error(ParseError::Expected("valid variable name".into(), span)); working_set.error(ParseError::Expected("valid variable name", span));
None None
} }
@ -5185,10 +5153,7 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression
if bytes.starts_with(b"{") { if bytes.starts_with(b"{") {
start += 1; start += 1;
} else { } else {
working_set.error(ParseError::Expected( working_set.error(ParseError::Expected("{", Span::new(start, start + 1)));
"{".into(),
Span::new(start, start + 1),
));
return garbage(span); return garbage(span);
} }
@ -5215,14 +5180,14 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression
idx += 1; idx += 1;
if idx == tokens.len() { if idx == tokens.len() {
working_set.error(ParseError::Expected("record".into(), span)); working_set.error(ParseError::Expected("record", span));
return garbage(span); return garbage(span);
} }
let colon = working_set.get_span_contents(tokens[idx].span); let colon = working_set.get_span_contents(tokens[idx].span);
idx += 1; idx += 1;
if idx == tokens.len() || colon != b":" { if idx == tokens.len() || colon != b":" {
//FIXME: need better error //FIXME: need better error
working_set.error(ParseError::Expected("record".into(), span)); working_set.error(ParseError::Expected("record", span));
return garbage(span); return garbage(span);
} }
let value = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any); let value = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any);

View File

@ -42,7 +42,11 @@ pub enum ParseError {
#[error("Parse mismatch during operation.")] #[error("Parse mismatch during operation.")]
#[diagnostic(code(nu::parser::parse_mismatch))] #[diagnostic(code(nu::parser::parse_mismatch))]
Expected(String, #[label("expected {0}")] Span), Expected(&'static str, #[label("expected {0}")] Span),
#[error("Parse mismatch during operation.")]
#[diagnostic(code(nu::parser::parse_mismatch_with_full_string_msg))]
ExpectedWithStringMsg(String, #[label("expected {0}")] Span),
#[error("Type mismatch during operation.")] #[error("Type mismatch during operation.")]
#[diagnostic(code(nu::parser::type_mismatch))] #[diagnostic(code(nu::parser::type_mismatch))]
@ -473,6 +477,7 @@ impl ParseError {
ParseError::Unclosed(_, s) => *s, ParseError::Unclosed(_, s) => *s,
ParseError::Unbalanced(_, _, s) => *s, ParseError::Unbalanced(_, _, s) => *s,
ParseError::Expected(_, s) => *s, ParseError::Expected(_, s) => *s,
ParseError::ExpectedWithStringMsg(_, s) => *s,
ParseError::Mismatch(_, _, s) => *s, ParseError::Mismatch(_, _, s) => *s,
ParseError::UnsupportedOperationLHS(_, _, s, _) => *s, ParseError::UnsupportedOperationLHS(_, _, s, _) => *s,
ParseError::UnsupportedOperationRHS(_, _, _, _, s, _) => *s, ParseError::UnsupportedOperationRHS(_, _, _, _, s, _) => *s,