From 7ead89844ac6d32a5af403e302540938751dc1ed Mon Sep 17 00:00:00 2001 From: JT <547158+jntrnr@users.noreply.github.com> Date: Thu, 25 May 2023 07:53:57 +1200 Subject: [PATCH] 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 # After Submitting --- crates/nu-glob/src/lib.rs | 2 +- crates/nu-parser/src/parse_keywords.rs | 6 +- crates/nu-parser/src/parse_patterns.rs | 13 +- crates/nu-parser/src/parser.rs | 235 +++++++++++-------------- crates/nu-protocol/src/parse_error.rs | 7 +- 5 files changed, 115 insertions(+), 148 deletions(-) diff --git a/crates/nu-glob/src/lib.rs b/crates/nu-glob/src/lib.rs index 9edba6b116..04549e23c2 100644 --- a/crates/nu-glob/src/lib.rs +++ b/crates/nu-glob/src/lib.rs @@ -1248,7 +1248,7 @@ mod test { #[test] fn test_lots_of_files() { // this is a good test because it touches lots of differently named files - glob("/*/*/*/*").unwrap().skip(10000).next(); + glob("/*/*/*/*").unwrap().nth(10000); } #[test] diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index fdaf1875c3..9435d892e3 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -1368,7 +1368,7 @@ pub fn parse_export_in_module( } _ => { 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], )); @@ -1713,7 +1713,7 @@ pub fn parse_module_block( } => block.pipelines.push(garbage_pipeline(&command.parts)), } } 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])) } } @@ -2042,7 +2042,7 @@ pub fn parse_module( if block_bytes.starts_with(b"{") { start += 1; } else { - working_set.error(ParseError::Expected("block".into(), block_span)); + working_set.error(ParseError::Expected("block", block_span)); return (garbage_pipeline(spans), None); } diff --git a/crates/nu-parser/src/parse_patterns.rs b/crates/nu-parser/src/parse_patterns.rs index cca06119a4..d9e801872c 100644 --- a/crates/nu-parser/src/parse_patterns.rs +++ b/crates/nu-parser/src/parse_patterns.rs @@ -81,7 +81,7 @@ pub fn parse_variable_pattern(working_set: &mut StateWorkingSet, span: Span) -> span, } } else { - working_set.error(ParseError::Expected("valid variable name".into(), span)); + working_set.error(ParseError::Expected("valid variable name", span)); garbage(span) } } @@ -145,7 +145,7 @@ pub fn parse_list_pattern(working_set: &mut StateWorkingSet, span: Span) -> Matc } else { args.push(garbage(command.parts[spans_idx])); working_set.error(ParseError::Expected( - "valid variable name".into(), + "valid variable name", 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"{") { start += 1; } else { - working_set.error(ParseError::Expected( - "{".into(), - Span::new(start, start + 1), - )); + working_set.error(ParseError::Expected("{", Span::new(start, start + 1))); 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; if idx == tokens.len() { - working_set.error(ParseError::Expected("record".into(), span)); + working_set.error(ParseError::Expected("record", span)); return garbage(span); } let colon = working_set.get_span_contents(tokens[idx].span); idx += 1; if idx == tokens.len() || colon != b":" { //FIXME: need better error - working_set.error(ParseError::Expected("record".into(), span)); + working_set.error(ParseError::Expected("record", span)); return garbage(span); } let pattern = parse_pattern(working_set, tokens[idx].span); diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 0e32ce8e7c..1446e6e97e 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -636,7 +636,10 @@ pub fn parse_multispan_value( if starting_error_count == working_set.parse_errors.len() { 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); continue; } @@ -664,7 +667,7 @@ pub fn parse_multispan_value( let span = spans[*spans_idx]; 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:?}"), 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"]") } else if contents.starts_with(b"0o[") { 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"]") + } else { + working_set.error(ParseError::Expected("binary", span)); + garbage(span) } } @@ -1218,7 +1224,7 @@ fn parse_binary_with_base( | TokenContents::OutGreaterThan | TokenContents::ErrGreaterThan | TokenContents::OutErrGreaterThan => { - working_set.error(ParseError::Expected("binary".into(), span)); + working_set.error(ParseError::Expected("binary", span)); return garbage(span); } 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) } @@ -1312,7 +1318,7 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression { let token = strip_underscores(token); if token.is_empty() { - working_set.error(ParseError::Expected("int".into(), span)); + working_set.error(ParseError::Expected("int", span)); return garbage(span); } @@ -1330,7 +1336,7 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression { custom_completion: None, } } else { - working_set.error(ParseError::Expected("int".into(), span)); + working_set.error(ParseError::Expected("int", span)); garbage(span) } } @@ -1347,7 +1353,7 @@ pub fn parse_float(working_set: &mut StateWorkingSet, span: Span) -> Expression custom_completion: None, } } else { - working_set.error(ParseError::Expected("float".into(), span)); + working_set.error(ParseError::Expected("float", 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.error(ParseError::Expected("number".into(), span)); + working_set.error(ParseError::Expected("number", span)); garbage(span) } @@ -1398,10 +1404,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression }; if !token.contains("..") { - working_set.error(ParseError::Expected( - "at least one range bound set".into(), - span, - )); + working_set.error(ParseError::Expected("at least one range bound set", 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]), _ => { 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, )); return garbage(span); @@ -1430,7 +1433,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression (RangeInclusion::RightExclusive, "..<", op_span) } else { working_set.error(ParseError::Expected( - "inclusive operator preceding second range bound".into(), + "inclusive operator preceding second range bound", span, )); return garbage(span); @@ -1473,10 +1476,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression trace!("-- from: {:?} to: {:?}", from, to); if let (None, None) = (&from, &to) { - working_set.error(ParseError::Expected( - "at least one range bound set".into(), - span, - )); + working_set.error(ParseError::Expected("at least one range bound set", span)); return garbage(span); } @@ -1567,7 +1567,7 @@ pub fn parse_brace_expr( // and then revisit the parsing. if span.end <= (span.start + 1) { - working_set.error(ParseError::Expected( + working_set.error(ParseError::ExpectedWithStringMsg( format!("non-block value: {shape}"), span, )); @@ -1611,7 +1611,7 @@ pub fn parse_brace_expr( } else if matches!(shape, SyntaxShape::MatchBlock) { parse_match_block_expression(working_set, span) } else { - working_set.error(ParseError::Expected( + working_set.error(ParseError::ExpectedWithStringMsg( format!("non-block value: {shape}"), span, )); @@ -1861,7 +1861,7 @@ pub fn parse_cell_path( match expected_token { TokenType::Dot => { 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; } expected_token = TokenType::PathMember; @@ -1882,7 +1882,7 @@ pub fn parse_cell_path( } expected_token = TokenType::Dot; } else { - working_set.error(ParseError::Expected(". or ?".into(), path_element.span)); + working_set.error(ParseError::Expected(". or ?", path_element.span)); return tail; } } @@ -1917,10 +1917,8 @@ pub fn parse_cell_path( }); } _ => { - working_set.error(ParseError::Expected( - "string".into(), - path_element.span, - )); + working_set + .error(ParseError::Expected("string", path_element.span)); return tail; } } @@ -2113,7 +2111,7 @@ pub fn parse_directory(working_set: &mut StateWorkingSet, span: Span) -> Express custom_completion: None, } } else { - working_set.error(ParseError::Expected("directory".into(), span)); + working_set.error(ParseError::Expected("directory", span)); garbage(span) } @@ -2134,7 +2132,7 @@ pub fn parse_filepath(working_set: &mut StateWorkingSet, span: Span) -> Expressi custom_completion: None, } } else { - working_set.error(ParseError::Expected("filepath".into(), span)); + working_set.error(ParseError::Expected("filepath", 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); - if bytes.len() < 5 + if bytes.len() < 6 || !bytes[0].is_ascii_digit() || !bytes[1].is_ascii_digit() || !bytes[2].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); } @@ -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) } @@ -2206,10 +2205,7 @@ pub fn parse_duration(working_set: &mut StateWorkingSet, span: Span) -> Expressi garbage(span) } None => { - working_set.error(ParseError::Expected( - "duration with valid units".into(), - span, - )); + working_set.error(ParseError::Expected("duration with valid units", span)); garbage(span) } } @@ -2230,10 +2226,7 @@ pub fn parse_filesize(working_set: &mut StateWorkingSet, span: Span) -> Expressi garbage(span) } None => { - working_set.error(ParseError::Expected( - "filesize with valid units".into(), - span, - )); + working_set.error(ParseError::Expected("filesize with valid units", span)); garbage(span) } } @@ -2401,7 +2394,7 @@ pub fn parse_glob_pattern(working_set: &mut StateWorkingSet, span: Span) -> Expr custom_completion: None, } } else { - working_set.error(ParseError::Expected("glob pattern string".into(), span)); + working_set.error(ParseError::Expected("glob pattern string", span)); garbage(span) } @@ -2589,10 +2582,7 @@ pub fn unescape_unquote_string(bytes: &[u8], span: Span) -> (String, Option (String, Option Expression let bytes = working_set.get_span_contents(span); if bytes.is_empty() { - working_set.error(ParseError::Expected("String".into(), span)); + working_set.error(ParseError::Expected("String", span)); return Expression::garbage(span); } @@ -2681,7 +2668,7 @@ pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Exp custom_completion: None, } } else if token.contains(' ') { - working_set.error(ParseError::Expected("string".into(), span)); + working_set.error(ParseError::Expected("string", span)); garbage(span) } else { @@ -2693,7 +2680,7 @@ pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Exp } } } else { - working_set.error(ParseError::Expected("string".into(), span)); + working_set.error(ParseError::Expected("string", span)); garbage(span) } } @@ -2750,7 +2737,7 @@ pub fn parse_shape_name( let command_name = trim_quotes(split[1]); 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; } @@ -2848,10 +2835,8 @@ fn parse_collection_shape( match maybe_colon.as_slice() { b":" => { if idx + 1 == tokens.len() { - working_set.error(ParseError::Expected( - "type after colon".into(), - tokens[idx].span, - )); + working_set + .error(ParseError::Expected("type after colon", tokens[idx].span)); break; } else { idx += 1; @@ -3110,7 +3095,7 @@ pub fn parse_var_with_opt_type( if !is_variable(&var_name) { working_set.error(ParseError::Expected( - "valid variable name".into(), + "valid variable name", spans[*spans_idx], )); return garbage(spans[*spans_idx]); @@ -3129,7 +3114,7 @@ pub fn parse_var_with_opt_type( if !is_variable(&var_name) { working_set.error(ParseError::Expected( - "valid variable name".into(), + "valid variable name", spans[*spans_idx], )); return garbage(spans[*spans_idx]); @@ -3150,7 +3135,7 @@ pub fn parse_var_with_opt_type( if !is_variable(&var_name) { working_set.error(ParseError::Expected( - "valid variable name".into(), + "valid variable name", 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; start += 1; } else { - working_set.error(ParseError::Expected( - "[ or (".into(), - Span::new(start, start + 1), - )); + working_set.error(ParseError::Expected("[ or (", Span::new(start, start + 1))); return garbage(span); } @@ -3314,12 +3296,11 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> parse_mode = ParseMode::TypeMode; } ParseMode::AfterCommaArgMode => { - working_set - .error(ParseError::Expected("parameter or flag".into(), span)); + working_set.error(ParseError::Expected("parameter or flag", span)); } ParseMode::TypeMode | ParseMode::DefaultValueMode => { // 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; } ParseMode::AfterCommaArgMode => { - working_set - .error(ParseError::Expected("parameter or flag".into(), span)); + working_set.error(ParseError::Expected("parameter or flag", span)); } ParseMode::DefaultValueMode => { // 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 { ParseMode::ArgMode => parse_mode = ParseMode::AfterCommaArgMode, ParseMode::AfterCommaArgMode => { - working_set - .error(ParseError::Expected("parameter or flag".into(), span)); + working_set.error(ParseError::Expected("parameter or flag", span)); } ParseMode::TypeMode => { - working_set.error(ParseError::Expected("type".into(), span)); + working_set.error(ParseError::Expected("type", span)); } ParseMode::DefaultValueMode => { - working_set.error(ParseError::Expected("default value".into(), span)); + working_set.error(ParseError::Expected("default value", span)); } } } else { @@ -3375,7 +3354,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> if !is_variable(&variable_name) { working_set.error(ParseError::Expected( - "valid variable name for this long flag".into(), + "valid variable name for this long flag", span, )) } @@ -3396,7 +3375,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> })); } else if flags.len() >= 3 { working_set.error(ParseError::Expected( - "only one short flag alternative".into(), + "only one short flag alternative", span, )); } else { @@ -3405,7 +3384,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> || !short_flag.ends_with(b")") { working_set.error(ParseError::Expected( - "short flag alternative for the long flag".into(), + "short flag alternative for the long flag", span, )); short_flag @@ -3430,7 +3409,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> if !is_variable(&variable_name) { working_set.error(ParseError::Expected( - "valid variable name for this short flag".into(), + "valid variable name for this short flag", span, )) } @@ -3453,8 +3432,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> default_value: None, })); } else { - working_set - .error(ParseError::Expected("short flag".into(), span)); + working_set.error(ParseError::Expected("short flag", span)); } } parse_mode = ParseMode::ArgMode; @@ -3466,8 +3444,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> let chars: Vec = short_flag.chars().collect(); if chars.len() > 1 { - working_set - .error(ParseError::Expected("short flag".into(), span)); + working_set.error(ParseError::Expected("short flag", span)); } 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) { working_set.error(ParseError::Expected( - "valid variable name for this short flag".into(), + "valid variable name for this short flag", 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) else if contents.starts_with(b"(-") { if matches!(parse_mode, ParseMode::AfterCommaArgMode) { - working_set.error(ParseError::Expected( - "parameter or flag".into(), - span, - )); + working_set + .error(ParseError::Expected("parameter or flag", span)); } let short_flag = &contents[2..]; let short_flag = if !short_flag.ends_with(b")") { - working_set - .error(ParseError::Expected("short flag".into(), span)); + working_set.error(ParseError::Expected("short flag", span)); short_flag } else { &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)) => { if flag.short.is_some() { working_set.error(ParseError::Expected( - "one short flag".into(), + "one short flag", span, )); } else { @@ -3530,15 +3504,12 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> } } _ => { - working_set.error(ParseError::Expected( - "unknown flag".into(), - span, - )); + working_set + .error(ParseError::Expected("unknown flag", span)); } } } else { - working_set - .error(ParseError::Expected("short flag".into(), span)); + working_set.error(ParseError::Expected("short flag", span)); } } // Positional arg, optional @@ -3548,7 +3519,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> if !is_variable(&contents) { working_set.error(ParseError::Expected( - "valid variable name for this optional parameter".into(), + "valid variable name for this optional parameter", span, )) } @@ -3575,7 +3546,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> if !is_variable(&contents_vec) { working_set.error(ParseError::Expected( - "valid variable name for this rest parameter".into(), + "valid variable name for this rest parameter", span, )) } @@ -3599,7 +3570,7 @@ pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> if !is_variable(&contents_vec) { working_set.error(ParseError::Expected( - "valid variable name for this parameter".into(), + "valid variable name for this parameter", span, )) } @@ -4039,7 +4010,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> if bytes.starts_with(b"{") { start += 1; } else { - working_set.error(ParseError::Expected("block".into(), span)); + working_set.error(ParseError::Expected("block", span)); return garbage(span); } if bytes.ends_with(b"}") { @@ -4065,10 +4036,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> contents: TokenContents::Pipe, span, }) => { - working_set.error(ParseError::Expected( - "block but found closure".into(), - *span, - )); + working_set.error(ParseError::Expected("block but found closure", *span)); (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"{") { start += 1; } else { - working_set.error(ParseError::Expected("closure".into(), span)); + working_set.error(ParseError::Expected("closure", span)); return garbage(span); } if bytes.ends_with(b"}") { @@ -4274,7 +4242,7 @@ pub fn parse_closure_expression( if bytes.starts_with(b"{") { start += 1; } else { - working_set.error(ParseError::Expected("closure".into(), span)); + working_set.error(ParseError::Expected("closure", span)); return garbage(span); } if bytes.ends_with(b"}") { @@ -4343,7 +4311,7 @@ pub fn parse_closure_expression( if let SyntaxShape::Closure(Some(v)) = shape { if let Some((sig, sig_span)) = &signature { if sig.num_positionals() > v.len() { - working_set.error(ParseError::Expected( + working_set.error(ParseError::ExpectedWithStringMsg( format!( "{} closure parameter{}", v.len(), @@ -4427,7 +4395,7 @@ pub fn parse_value( custom_completion: None, }; } else { - working_set.error(ParseError::Expected("non-boolean value".into(), span)); + working_set.error(ParseError::Expected("non-boolean value", span)); return Expression::garbage(span); } } @@ -4440,7 +4408,7 @@ pub fn parse_value( custom_completion: None, }; } else { - working_set.error(ParseError::Expected("non-boolean value".into(), span)); + working_set.error(ParseError::Expected("non-boolean value", span)); return Expression::garbage(span); } } @@ -4472,7 +4440,7 @@ pub fn parse_value( | SyntaxShape::Table | SyntaxShape::Signature => {} _ => { - working_set.error(ParseError::Expected("non-[] value".into(), span)); + working_set.error(ParseError::Expected("non-[] value", span)); return Expression::garbage(span); } }, @@ -4502,7 +4470,7 @@ pub fn parse_value( if bytes.starts_with(b"[") { parse_signature(working_set, span) } else { - working_set.error(ParseError::Expected("signature".into(), span)); + working_set.error(ParseError::Expected("signature", span)); Expression::garbage(span) } @@ -4511,7 +4479,7 @@ pub fn parse_value( if bytes.starts_with(b"[") { parse_list_expression(working_set, span, elem) } else { - working_set.error(ParseError::Expected("list".into(), span)); + working_set.error(ParseError::Expected("list", span)); Expression::garbage(span) } @@ -4520,7 +4488,7 @@ pub fn parse_value( if bytes.starts_with(b"[") { parse_table_expression(working_set, span) } else { - working_set.error(ParseError::Expected("table".into(), span)); + working_set.error(ParseError::Expected("table", span)); Expression::garbage(span) } @@ -4536,7 +4504,7 @@ pub fn parse_value( custom_completion: None, } } else { - working_set.error(ParseError::Expected("bool".into(), span)); + working_set.error(ParseError::Expected("bool", 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 // stream doesn't start with '{'} -- parsing in SyntaxShape::Any arm depends on this error variant. SyntaxShape::Block | SyntaxShape::Closure(..) | SyntaxShape::Record(_) => { - working_set.error(ParseError::Expected( - "block, closure or record".into(), - span, - )); + working_set.error(ParseError::Expected("block, closure or record", span)); Expression::garbage(span) } @@ -4563,10 +4528,7 @@ pub fn parse_value( SyntaxShape::Filesize, SyntaxShape::Duration, SyntaxShape::Range, - SyntaxShape::DateTime, //FIXME requires 3 failed conversion attempts before failing - SyntaxShape::Record(vec![]), - SyntaxShape::Closure(None), - SyntaxShape::Block, + SyntaxShape::DateTime, SyntaxShape::Int, SyntaxShape::Number, SyntaxShape::String, @@ -4580,7 +4542,10 @@ pub fn parse_value( return s; } else { 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); 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) } } 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) } } @@ -4727,7 +4695,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi return garbage(span); } _ => { - working_set.error(ParseError::Expected("operator".into(), span)); + working_set.error(ParseError::Expected("operator", span)); return garbage(span); } }; @@ -4770,7 +4738,7 @@ pub fn parse_math_expression( return parse_call(working_set, spans, spans[0], false); } else { working_set.error(ParseError::Expected( - "expression".into(), + "expression", Span::new(spans[0].end, spans[0].end), )); return garbage(spans[0]); @@ -4786,7 +4754,7 @@ pub fn parse_math_expression( }; } else { working_set.error(ParseError::Expected( - "expression".into(), + "expression", Span::new(spans[0].end, spans[0].end), )); return garbage(spans[0]); @@ -5099,7 +5067,7 @@ pub fn parse_variable(working_set: &mut StateWorkingSet, span: Span) -> Option Expression if bytes.starts_with(b"{") { start += 1; } else { - working_set.error(ParseError::Expected( - "{".into(), - Span::new(start, start + 1), - )); + working_set.error(ParseError::Expected("{", Span::new(start, start + 1))); return garbage(span); } @@ -5215,14 +5180,14 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression idx += 1; if idx == tokens.len() { - working_set.error(ParseError::Expected("record".into(), span)); + working_set.error(ParseError::Expected("record", span)); return garbage(span); } let colon = working_set.get_span_contents(tokens[idx].span); idx += 1; if idx == tokens.len() || colon != b":" { //FIXME: need better error - working_set.error(ParseError::Expected("record".into(), span)); + working_set.error(ParseError::Expected("record", span)); return garbage(span); } let value = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any); diff --git a/crates/nu-protocol/src/parse_error.rs b/crates/nu-protocol/src/parse_error.rs index 6b7d36b574..0393a52ee2 100644 --- a/crates/nu-protocol/src/parse_error.rs +++ b/crates/nu-protocol/src/parse_error.rs @@ -42,7 +42,11 @@ pub enum ParseError { #[error("Parse mismatch during operation.")] #[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.")] #[diagnostic(code(nu::parser::type_mismatch))] @@ -473,6 +477,7 @@ impl ParseError { ParseError::Unclosed(_, s) => *s, ParseError::Unbalanced(_, _, s) => *s, ParseError::Expected(_, s) => *s, + ParseError::ExpectedWithStringMsg(_, s) => *s, ParseError::Mismatch(_, _, s) => *s, ParseError::UnsupportedOperationLHS(_, _, s, _) => *s, ParseError::UnsupportedOperationRHS(_, _, _, _, s, _) => *s,