From dd0486a24fc0ac35973886cc502e0d4e530b7e2b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:49:37 +0000 Subject: [PATCH] Fix all remaining ParseError::new deprecation warnings - Replace all ParseError::new() calls with ParseError::from_token() or ParseError::from_span() - Fix needless_borrow clippy warnings via cargo clippy --fix - Add #[allow(clippy::type_complexity)] for complex return type in containers.rs - Capture count_token at start of parse_count_loop for proper error reporting Files modified: - src/parser/expr/binary.rs (1 usage) - src/parser/expr/primary.rs (27 usages) - src/parser/mod.rs (8 usages) - src/parser/mod_complete.rs (13 usages) - src/parser/stmt/actions.rs (17 usages) - src/parser/stmt/collections.rs (needless_borrow fixes) - src/parser/stmt/containers.rs (31 usages + type_complexity) - src/parser/stmt/control_flow.rs (12 usages) - src/parser/stmt/errors.rs (needless_borrow fixes) - src/parser/stmt/io.rs (21 usages) - src/parser/stmt/patterns.rs (53 usages) - src/parser/stmt/processes.rs (needless_borrow fixes) This completes the migration from the deprecated ParseError::new() API to the modern from_token/from_span constructors, which provide proper span information for better error diagnostics. Co-Authored-By: Bradley Byrd --- src/parser/expr/binary.rs | 3 +- src/parser/expr/primary.rs | 145 ++++++++---------- src/parser/mod.rs | 55 +++---- src/parser/mod_complete.rs | 59 ++++--- src/parser/stmt/actions.rs | 85 ++++++----- src/parser/stmt/collections.rs | 12 +- src/parser/stmt/containers.rs | 154 +++++++++---------- src/parser/stmt/control_flow.rs | 64 ++++---- src/parser/stmt/errors.rs | 2 +- src/parser/stmt/io.rs | 107 ++++++------- src/parser/stmt/patterns.rs | 263 ++++++++++++++------------------ src/parser/stmt/processes.rs | 14 +- 12 files changed, 431 insertions(+), 532 deletions(-) diff --git a/src/parser/expr/binary.rs b/src/parser/expr/binary.rs index bcdcdaa8..afe17b4e 100644 --- a/src/parser/expr/binary.rs +++ b/src/parser/expr/binary.rs @@ -605,8 +605,9 @@ impl<'a> BinaryExprParser<'a> for Parser<'a> { return Err(error); } } else { - let error = ParseError::new( + let error = ParseError::from_span( "Expected action name after 'call'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, call_line, call_column, ); diff --git a/src/parser/expr/primary.rs b/src/parser/expr/primary.rs index c9680b2a..a12dc6af 100644 --- a/src/parser/expr/primary.rs +++ b/src/parser/expr/primary.rs @@ -56,21 +56,20 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { self.bump_sync(); // Consume separator elements.push(self.parse_list_element()?); } else { - return Err(ParseError::new( + let err_token = next_token.clone(); + return Err(ParseError::from_token( format!( "Expected ']', ',' or 'and' in list literal, found {:?}", - next_token.token + err_token.token ), - next_token.line, - next_token.column, + &err_token, )); } } - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input while parsing list literal".into(), - bracket_token.line, - bracket_token.column, + bracket_token, )); } Token::LeftParen => { @@ -82,17 +81,15 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { self.bump_sync(); // Consume ')' return Ok(expr); } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected closing parenthesis, found {:?}", token.token), - token.line, - token.column, + &token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected closing parenthesis, found end of input".into(), - token.line, - token.column, + &token, )); } } @@ -217,17 +214,15 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { column: token_column, }); } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected property name after '.'".to_string(), - property_token.line, - property_token.column, + &property_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected property name after '.'".to_string(), - token_line, - token_column, + &token, )); } } else if let Token::Identifier(id) = &next_token.token @@ -314,20 +309,18 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { token_pos.column, )); } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected string literal after 'pattern', found {:?}", pattern_token.token ), - pattern_token.line, - pattern_token.column, + &pattern_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'pattern'".to_string(), - token.line, - token.column, + &token, )); } } @@ -479,10 +472,9 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { } // Otherwise, this is an error - "process" without "is running" is not valid - Err(ParseError::new( + Err(ParseError::from_token( "Expected 'is running' after process ID".to_string(), - token_line, - token_column, + &token, )) } Token::KeywordHeader => { @@ -495,18 +487,16 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { match &name_token.token { Token::StringLiteral(name) => name.clone(), _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected string literal for header name".to_string(), - name_token.line, - name_token.column, + name_token, )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected header name after 'header'".to_string(), - token_line, - token_column, + &token, )); }; @@ -554,20 +544,18 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { // Parse format string let format_token = self.bump_sync().ok_or_else(|| { - ParseError::new( + ParseError::from_token( "Expected format string after 'as'".to_string(), - token_line, - token_column, + &token, ) })?; let format = match &format_token.token { Token::StringLiteral(fmt) => fmt.clone(), _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected string literal for time format".to_string(), - format_token.line, - format_token.column, + format_token, )); } }; @@ -578,19 +566,20 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { column: token_column, }) } - _ => Err(ParseError::new( - "Expected 'in milliseconds' or 'formatted as' after 'current time'" - .to_string(), - next_token.line, - next_token.column, - )), + _ => { + let err_token = next_token.clone(); + Err(ParseError::from_token( + "Expected 'in milliseconds' or 'formatted as' after 'current time'" + .to_string(), + &err_token, + )) + } } } else { - Err(ParseError::new( + Err(ParseError::from_token( "Expected 'in milliseconds' or 'formatted as' after 'current time'" .to_string(), - token_line, - token_column, + &token, )) } } @@ -800,17 +789,15 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { column: token.column, }) } - _ => Err(ParseError::new( + _ => Err(ParseError::from_token( "Expected 'by' or 'on' after text in split expression".to_string(), - token.line, - token.column, + &token, )), } } else { - Err(ParseError::new( + Err(ParseError::from_token( "Expected 'by' or 'on' after text in split expression".to_string(), - token.line, - token.column, + &token, )) } } @@ -896,10 +883,9 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { } else { // Not "contains X in Y", treat as error // We already parsed an expression after contains - Err(ParseError::new( + Err(ParseError::from_token( "Expected 'in' after expression in contains".to_string(), - token_line, - token_column, + &token, )) } } @@ -976,15 +962,13 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { Ok(Expression::Variable(name, token_line, token_column)) } } - Token::Eol => Err(ParseError::new( + Token::Eol => Err(ParseError::from_token( "Unexpected end of line in expression".to_string(), - token.line, - token.column, + &token, )), - _ => Err(ParseError::new( + _ => Err(ParseError::from_token( format!("Unexpected token in expression: {:?}", token.token), - token.line, - token.column, + &token, )), }; @@ -1079,11 +1063,10 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { column: token.column, }; } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Member access not supported with expression arguments" .to_string(), - token.line, - token.column, + &token, )); } } @@ -1115,21 +1098,19 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { column: token.column, }; } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected ']' after array index, found {:?}", closing_token.token ), - closing_token.line, - closing_token.column, + &closing_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected ']' after array index, found end of input" .to_string(), - token.line, - token.column, + &token, )); } } @@ -1146,11 +1127,10 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { { name.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Static member access requires a container name" .to_string(), - token.line, - token.column, + &token, )); }; @@ -1161,20 +1141,18 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { column: token.column, }; } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier after '.', found {:?}", member_token.token ), - member_token.line, - member_token.column, + &member_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after '.'".to_string(), - token.line, - token.column, + &token, )); } } @@ -1187,8 +1165,9 @@ impl<'a> PrimaryExprParser<'a> for Parser<'a> { result } } else { - Err(ParseError::new( + Err(ParseError::from_span( "Unexpected end of input while parsing expression".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index c2fd2b0d..7069af3d 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -184,10 +184,9 @@ impl<'a> Parser<'a> { first_token.line ); self.bump_sync(); // Consume "end" - self.errors.push(ParseError::new( + self.errors.push(ParseError::from_token( format!("Unexpected 'end' followed by {:?}", second_token.token), - first_token.line, - first_token.column, + first_token, )); continue; } @@ -281,10 +280,9 @@ impl<'a> Parser<'a> { name_parts.push(id.clone()); } Token::IntLiteral(_) | Token::FloatLiteral(_) => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Cannot use a number as a variable name: {:?}", token.token), - token.line, - token.column, + &token, )); } Token::KeywordAs => { @@ -294,13 +292,12 @@ impl<'a> Parser<'a> { )); } _ if token.token.is_structural_keyword() => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Cannot use reserved keyword '{:?}' as a variable name", token.token ), - token.line, - token.column, + &token, )); } _ if token.token.is_contextual_keyword() => { @@ -310,19 +307,19 @@ impl<'a> Parser<'a> { name_parts.push(name); } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for variable name, found {:?}", token.token ), - token.line, - token.column, + &token, )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected variable name but found end of input".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -338,23 +335,21 @@ impl<'a> Parser<'a> { break; } Token::IntLiteral(_) | Token::FloatLiteral(_) => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected 'as' after variable name, but found number: {:?}", token.token ), - token.line, - token.column, + &token, )); } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected 'as' after variable name, but found {:?}", token.token ), - token.line, - token.column, + &token, )); } } @@ -383,11 +378,19 @@ impl<'a> Parser<'a> { } if !has_identifier { - return Err(ParseError::new( - "Expected variable name".to_string(), - self.cursor.peek().map_or(0, |t| t.line), - self.cursor.peek().map_or(0, |t| t.column), - )); + if let Some(token) = self.cursor.peek() { + return Err(ParseError::from_token( + "Expected variable name".to_string(), + token, + )); + } else { + return Err(ParseError::from_span( + "Expected variable name".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, + 0, + 0, + )); + } } Ok(name) @@ -483,14 +486,14 @@ impl<'a> StmtParser<'a> for Parser<'a> { Err(ParseError::from_token( "Unexpected 'read' - did you mean 'read output from process'?" .to_string(), - &token_pos, + token_pos, )) } } else { let token_pos = self.cursor.peek().unwrap(); Err(ParseError::from_token( "Unexpected 'read' at end of input".to_string(), - &token_pos, + token_pos, )) } } diff --git a/src/parser/mod_complete.rs b/src/parser/mod_complete.rs index 65ca5d0a..a22bdb95 100644 --- a/src/parser/mod_complete.rs +++ b/src/parser/mod_complete.rs @@ -90,10 +90,9 @@ impl<'a> Parser<'a> { // Standalone "end" or unexpected pattern - consume and log error exec_trace!("Found unexpected 'end' followed by {:?} at line {}", second_token.token, first_token.line); self.tokens.next(); // Consume "end" - self.errors.push(ParseError::new( + self.errors.push(ParseError::from_token( format!("Unexpected 'end' followed by {:?}", second_token.token), - first_token.line, - first_token.column, + &first_token, )); continue; } @@ -249,10 +248,9 @@ impl<'a> Parser<'a> { self.tokens.next(); id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'as', found {:?}", token.token), - token.line, - token.column, + token, )); } } else { @@ -319,16 +317,16 @@ impl<'a> Parser<'a> { name_parts.push(id.clone()); } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier for variable name, found {:?}", token.token), - token.line, - token.column, + &token, )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected variable name but found end of input".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -354,15 +352,15 @@ impl<'a> Parser<'a> { self.tokens.next(); Ok(()) } else { - Err(ParseError::new( + Err(ParseError::from_token( format!("{}: expected {:?}, found {:?}", error_message, expected, token.token), - token.line, - token.column, + &token, )) } } else { - Err(ParseError::new( + Err(ParseError::from_span( format!("{}: unexpected end of input", error_message), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )) @@ -543,15 +541,15 @@ impl<'a> Parser<'a> { let token_pos = self.tokens.next().unwrap(); Ok(Expression::Variable("count".to_string(), token_pos.line, token_pos.column)) } - _ => Err(ParseError::new( + _ => Err(ParseError::from_token( format!("Unexpected token in expression: {:?}", token.token), - token.line, - token.column, + &token, )), } } else { - Err(ParseError::new( + Err(ParseError::from_span( "Unexpected end of input while parsing expression".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )) @@ -679,17 +677,15 @@ impl<'a> Parser<'a> { self.tokens.next(); id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'each', found {:?}", token.token), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'each'".to_string(), - 0, - 0, + &for_token, )); }; @@ -728,17 +724,15 @@ impl<'a> Parser<'a> { self.tokens.next(); id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'called', found {:?}", token.token), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'called'".to_string(), - 0, - 0, + &define_token, )); }; @@ -802,9 +796,8 @@ impl<'a> Parser<'a> { self.tokens.next(); id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'change', found {:?}", token.token), - token.line, - token.column, + token, )); } diff --git a/src/parser/stmt/actions.rs b/src/parser/stmt/actions.rs index 49a17d61..59a2320b 100644 --- a/src/parser/stmt/actions.rs +++ b/src/parser/stmt/actions.rs @@ -46,19 +46,20 @@ impl<'a> ActionParser<'a> for Parser<'a> { "Expected identifier after 'called', found {:?}", token.token ); - return Err(ParseError::new( + let err_token = token.clone(); + return Err(ParseError::from_token( format!( "Expected identifier after 'called', found {:?}", - token.token + err_token.token ), - token.line, - token.column, + &err_token, )); } } else { exec_trace!("Unexpected end of input after 'called'"); - return Err(ParseError::new( + return Err(ParseError::from_span( "Unexpected end of input after 'called'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -120,18 +121,19 @@ impl<'a> ActionParser<'a> for Parser<'a> { Some(typ) } else { - return Err(ParseError::new( + let err_token = type_token.clone(); + return Err(ParseError::from_token( format!( "Expected type name after 'as', found {:?}", - type_token.token + err_token.token ), - type_token.line, - type_token.column, + &err_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Unexpected end of input after 'as'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -200,18 +202,19 @@ impl<'a> ActionParser<'a> for Parser<'a> { Some(typ) } else { - return Err(ParseError::new( + let err_token = type_token.clone(); + return Err(ParseError::from_token( format!( "Expected type name after 'returns', found {:?}", - type_token.token + err_token.token ), - type_token.line, - type_token.column, + &err_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Unexpected end of input after 'returns'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -266,29 +269,31 @@ impl<'a> ActionParser<'a> for Parser<'a> { if matches!(token.token, Token::KeywordAction) { self.bump_sync(); // Consume "action" } else { - return Err(ParseError::new( + let err_token = token.clone(); + return Err(ParseError::from_token( "Expected 'action' after 'end'".to_string(), - token.line, - token.column, + &err_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected 'action' after 'end'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); } } else { - return Err(ParseError::new( + let err_token = token.clone(); + return Err(ParseError::from_token( "Expected 'end' after action body".to_string(), - token.line, - token.column, + &err_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected 'end' after action body".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -332,18 +337,19 @@ impl<'a> ActionParser<'a> for Parser<'a> { self.bump_sync(); id.clone() } else { - return Err(ParseError::new( + let err_token = token.clone(); + return Err(ParseError::from_token( format!( "Expected identifier after 'action', found {:?}", - token.token + err_token.token ), - token.line, - token.column, + &err_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected identifier after 'action'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -419,8 +425,9 @@ impl<'a> ActionParser<'a> for Parser<'a> { } body.push(self.parse_statement()?); } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Unexpected end of input in action body".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -463,15 +470,16 @@ impl<'a> ActionParser<'a> for Parser<'a> { _ => Type::Custom(type_name.clone()), }) } else { - return Err(ParseError::new( + let err_token = type_name_token.clone(); + return Err(ParseError::from_token( "Expected type name after ':'".to_string(), - type_name_token.line, - type_name_token.column, + &err_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected type name after ':'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, param_line, param_column, )); @@ -563,18 +571,19 @@ impl<'a> ActionParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + let err_token = token.clone(); + return Err(ParseError::from_token( format!( "Expected identifier for method name, found {:?}", - token.token + err_token.token ), - token.line, - token.column, + &err_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected identifier for method name, found end of input".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, line, column, )); diff --git a/src/parser/stmt/collections.rs b/src/parser/stmt/collections.rs index 24663a4b..b187bf18 100644 --- a/src/parser/stmt/collections.rs +++ b/src/parser/stmt/collections.rs @@ -31,14 +31,14 @@ impl<'a> CollectionParser<'a> for Parser<'a> { _ => { return Err(ParseError::from_token( format!("Expected identifier for list name, found {:?}", token.token), - &token, + token, )); } } } else { return Err(ParseError::from_token( "Expected list name after 'create list'".to_string(), - &create_token, + create_token, )); }; @@ -176,13 +176,13 @@ impl<'a> CollectionParser<'a> for Parser<'a> { // No "to" keyword, this is an error Err(ParseError::from_token( "Expected 'to' after value in add statement".to_string(), - &add_token, + add_token, )) } } else { Err(ParseError::from_token( "Unexpected end of input after add value".to_string(), - &add_token, + add_token, )) } } @@ -242,14 +242,14 @@ impl<'a> CollectionParser<'a> for Parser<'a> { _ => { return Err(ParseError::from_token( format!("Expected identifier for map name, found {:?}", token.token), - &token, + token, )); } } } else { return Err(ParseError::from_token( "Expected map name after 'create map'".to_string(), - &create_token, + create_token, )); }; diff --git a/src/parser/stmt/containers.rs b/src/parser/stmt/containers.rs index a7e9c6c8..7415435d 100644 --- a/src/parser/stmt/containers.rs +++ b/src/parser/stmt/containers.rs @@ -21,6 +21,7 @@ pub(crate) trait ContainerParser<'a>: ExprParser<'a> + ActionParser<'a> { fn parse_inheritance(&mut self) -> Result<(Option, Vec), ParseError>; + #[allow(clippy::type_complexity)] fn parse_container_body( &mut self, ) -> Result< @@ -68,20 +69,18 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for container name, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier for container name, found end of input".to_string(), - line, - column, + start_token, )); }; @@ -125,20 +124,18 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for interface name, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier for interface name, found end of input".to_string(), - line, - column, + start_token, )); }; @@ -189,20 +186,18 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for container type, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier for container type, found end of input".to_string(), - line, - column, + start_token, )); }; @@ -214,20 +209,18 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for instance name, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier for instance name, found end of input".to_string(), - line, - column, + start_token, )); }; @@ -257,20 +250,18 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for event name, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier for event name, found end of input".to_string(), - line, - column, + start_token, )); }; @@ -294,20 +285,18 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for event name, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier for event name, found end of input".to_string(), - line, - column, + start_token, )); }; @@ -334,20 +323,18 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for event name, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier for event name, found end of input".to_string(), - line, - column, + start_token, )); }; @@ -371,20 +358,26 @@ impl<'a> ContainerParser<'a> for Parser<'a> { { self.bump_sync(); // Consume 'extends' + let extends_token = self.cursor.peek().cloned(); if let Some(token) = self.cursor.peek() { if let Token::Identifier(id) = &token.token { extends = Some(id.clone()); self.bump_sync(); // Consume the identifier } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier after 'extends'".to_string(), - token.line, - token.column, + token, )); } + } else if let Some(ref ext_tok) = extends_token { + return Err(ParseError::from_token( + "Expected identifier after 'extends'".to_string(), + ext_tok, + )); } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected identifier after 'extends'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -416,15 +409,15 @@ impl<'a> ContainerParser<'a> for Parser<'a> { break; } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier in implements list".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected identifier in implements list".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -481,19 +474,17 @@ impl<'a> ContainerParser<'a> for Parser<'a> { static_methods.push(method); } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'property' or 'action' after 'static'" .to_string(), - next_token.line, - next_token.column, + next_token, )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'property' or 'action' after 'static'".to_string(), - static_token.line, - static_token.column, + static_token, )); } } @@ -510,16 +501,16 @@ impl<'a> ContainerParser<'a> for Parser<'a> { continue; } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Unexpected token in container body: {:?}", token.token), - token.line, - token.column, + token, )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Unexpected end of input in container body".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -549,17 +540,15 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected property name after 'property'".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected property name after 'property'".to_string(), - line, - column, + start_token, )); }; @@ -579,17 +568,15 @@ impl<'a> ContainerParser<'a> for Parser<'a> { _ => Type::Custom(type_name.clone()), }) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected type name after ':'".to_string(), - type_token.line, - type_token.column, + type_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected type name after ':'".to_string(), - line, - column, + start_token, )); } } else { @@ -633,17 +620,15 @@ impl<'a> ContainerParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected event name after 'event'".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected event name after 'event'".to_string(), - line, - column, + start_token, )); }; @@ -700,25 +685,24 @@ impl<'a> ContainerParser<'a> for Parser<'a> { column: prop_column, }); } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'is' or ':' after property name".to_string(), - next_token.line, - next_token.column, + next_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected 'is' or ':' after property name".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, prop_line, prop_column, )); } } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Unexpected token in instantiation body: {:?}", token.token), - token.line, - token.column, + token, )); } } diff --git a/src/parser/stmt/control_flow.rs b/src/parser/stmt/control_flow.rs index e4c58eb1..fba6a1ff 100644 --- a/src/parser/stmt/control_flow.rs +++ b/src/parser/stmt/control_flow.rs @@ -118,31 +118,27 @@ impl<'a> ControlFlowParser<'a> for Parser<'a> { if matches!(next_token.token, Token::KeywordCheck) { self.bump_sync(); // Consume "check" } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected 'check' after 'end', found {:?}", next_token.token), - next_token.line, - next_token.column, + next_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'check' after 'end', found end of input".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected 'end' after if block, found {:?}", token.token), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'end' after if block, found end of input".to_string(), - 0, - 0, + check_token, )); } @@ -245,7 +241,7 @@ impl<'a> ControlFlowParser<'a> for Parser<'a> { let then_stmt = if then_block.is_empty() { return Err(ParseError::from_token( "Expected statement after 'then'".to_string(), - &if_token, + if_token, )); } else { Box::new(then_block.into_iter().next().unwrap()) @@ -282,15 +278,15 @@ impl<'a> ControlFlowParser<'a> for Parser<'a> { self.bump_sync(); id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'each', found {:?}", token.token), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_span( "Unexpected end of input after 'each'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -365,7 +361,7 @@ impl<'a> ControlFlowParser<'a> for Parser<'a> { where Self: StmtParser<'a>, { - self.bump_sync(); // Consume "count" + let count_token = self.bump_sync().unwrap(); // Consume "count" self.expect_token(Token::KeywordFrom, "Expected 'from' after 'count'")?; @@ -381,27 +377,24 @@ impl<'a> ControlFlowParser<'a> for Parser<'a> { self.bump_sync(); // Consume "to" false } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected 'to' or 'down to', found {:?}", token.token), - token.line, - token.column, + token, )); } } else if matches!(token.token, Token::KeywordTo) { self.bump_sync(); // Consume "to" false } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected 'to' or 'down to', found {:?}", token.token), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after count from expression".to_string(), - 0, - 0, + count_token, )); }; @@ -430,20 +423,18 @@ impl<'a> ControlFlowParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier Some(var_name) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier after 'as', found {:?}", name_token.token ), - name_token.line, - name_token.column, + name_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'as'".to_string(), - 0, - 0, + count_token, )); } } else { @@ -662,19 +653,18 @@ impl<'a> ControlFlowParser<'a> for Parser<'a> { column: repeat_token.column, }) } - _ => Err(ParseError::new( + _ => Err(ParseError::from_token( format!( "Expected 'while', 'until', 'forever', or ':' after 'repeat', found {:?}", token.token ), - token.line, - token.column, + &token, )), } } else { Err(ParseError::from_token( "Unexpected end of input after 'repeat'".to_string(), - &repeat_token, + repeat_token, )) } } diff --git a/src/parser/stmt/errors.rs b/src/parser/stmt/errors.rs index 97963df7..a005e34d 100644 --- a/src/parser/stmt/errors.rs +++ b/src/parser/stmt/errors.rs @@ -321,7 +321,7 @@ impl<'a> ErrorHandlingParser<'a> for Parser<'a> { if when_clauses.is_empty() { return Err(ParseError::from_token( "Try statement must have at least one 'when' or 'catch' clause".to_string(), - &try_token, + try_token, )); } diff --git a/src/parser/stmt/io.rs b/src/parser/stmt/io.rs index c62c7dda..de1cb82b 100644 --- a/src/parser/stmt/io.rs +++ b/src/parser/stmt/io.rs @@ -245,20 +245,18 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier name.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for variable name, found {:?}", token.token ), - token.line, - token.column, + &token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input".to_string(), - 0, - 0, + open_token, )); }; @@ -279,20 +277,18 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier name.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for variable name, found {:?}", token.token ), - token.line, - token.column, + &token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input".to_string(), - 0, - 0, + open_token, )); }; @@ -304,40 +300,36 @@ impl<'a> IoParser<'a> for Parser<'a> { column: open_token.column, }); } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected 'and' or 'as' after URL, found {:?}", next_token.token ), - next_token.line, - next_token.column, + &next_token, )); } } } - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'at' after 'url'".to_string(), - open_token.line, - open_token.column + 5, // Approximate position after "open url" + open_token, )); } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected 'file' or 'url' after 'open', found {:?}", next_token.token ), - next_token.line, - next_token.column, + next_token, )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'open'".to_string(), - open_token.line, - open_token.column + 4, // Approximate position after "open" + open_token, )); } @@ -373,11 +365,10 @@ impl<'a> IoParser<'a> for Parser<'a> { FileOpenMode::Write } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'append', 'appending', 'reading', or 'writing' after 'for'" .to_string(), - token.line, - token.column, + &token, )); } } @@ -395,17 +386,15 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); // Consume the identifier name.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'as', found {:?}", token.token), - token.line, - token.column, + &token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'as'".to_string(), - 0, - 0, + open_token, )); }; @@ -432,13 +421,12 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); // Consume the "content" keyword "content".to_string() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for variable name, found {:?}", token.token ), - token.line, - token.column, + &token, )); } } else { @@ -460,17 +448,15 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'as', found {:?}", token.token), - token.line, - token.column, + &token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'as'".to_string(), - 0, - 0, + open_token, )); }; @@ -482,20 +468,18 @@ impl<'a> IoParser<'a> for Parser<'a> { column: open_token.column, }); } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected 'and' or 'as' after file path, found {:?}", next_token.token ), - next_token.line, - next_token.column, + &next_token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after file path".to_string(), - 0, - 0, + open_token, )); } } @@ -509,17 +493,15 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); id.clone() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Expected identifier after 'as', found {:?}", token.token), - token.line, - token.column, + &token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected end of input after 'as'".to_string(), - 0, - 0, + open_token, )); }; @@ -547,13 +529,12 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); // Consume the string literal Expression::Literal(Literal::String(path), line, column) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected string literal for file path, found {:?}", token.token ), - token.line, - token.column, + token, )); } } else { @@ -573,13 +554,12 @@ impl<'a> IoParser<'a> for Parser<'a> { self.bump_sync(); // Consume the "content" keyword "content".to_string() } else { - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "Expected identifier for variable name, found {:?}", token.token ), - token.line, - token.column, + &token, )); } } else { @@ -721,19 +701,18 @@ impl<'a> IoParser<'a> for Parser<'a> { column: token_pos.column, }) } - _ => Err(ParseError::new( + _ => Err(ParseError::from_token( format!( "Expected 'file' or 'directory' after 'delete', found {:?}", next_token.token ), - next_token.line, - next_token.column, + next_token, )), } } else { Err(ParseError::from_token( "Expected 'file' or 'directory' after 'delete'".to_string(), - &token_pos, + token_pos, )) } } diff --git a/src/parser/stmt/patterns.rs b/src/parser/stmt/patterns.rs index 50f566d9..7766684e 100644 --- a/src/parser/stmt/patterns.rs +++ b/src/parser/stmt/patterns.rs @@ -56,18 +56,17 @@ impl<'a> PatternParser<'a> for Parser<'a> { Token::KeywordCategory => ("category".to_string(), token.clone()), Token::KeywordScript => ("script".to_string(), token.clone()), _ => { - return Err(ParseError::new( + let err_token = token.clone(); + return Err(ParseError::from_token( "Expected pattern name after 'create pattern'".to_string(), - token.line, - token.column, + &err_token, )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected pattern name after 'create pattern'".to_string(), - create_token.line, - create_token.column, + create_token, )); }; @@ -76,13 +75,12 @@ impl<'a> PatternParser<'a> for Parser<'a> { // Consume tokens until we find "end pattern" to prevent cascading errors self.consume_pattern_body_on_error(); - return Err(ParseError::new( + return Err(ParseError::from_token( format!( "'{}' is a predefined pattern in WFL. Please choose a different name.", pattern_name ), - pattern_token.line, - pattern_token.column, + &pattern_token, )); } @@ -123,10 +121,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { } if depth > 0 { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'end pattern' to close pattern definition".to_string(), - create_token.line, - create_token.column, + create_token, )); } @@ -166,8 +163,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { if let Expression::Literal(Literal::List(items), _, _) = list_expr { Ok(items) } else { - Err(ParseError::new( + Err(ParseError::from_span( "Expected list of extensions after 'extensions'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )) @@ -184,15 +182,18 @@ impl<'a> PatternParser<'a> for Parser<'a> { let expr = self.parse_primary_expression()?; Ok(vec![expr]) } - _ => Err(ParseError::new( - "Expected 'extension', 'extensions', or 'pattern' after 'with'".to_string(), - token.line, - token.column, - )), + _ => { + let err_token = token.clone(); + Err(ParseError::from_token( + "Expected 'extension', 'extensions', or 'pattern' after 'with'".to_string(), + &err_token, + )) + } } } else { - Err(ParseError::new( + Err(ParseError::from_span( "Expected 'extension', 'extensions', or 'pattern' after 'with'".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )) @@ -208,8 +209,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { .collect(); if filtered_tokens.is_empty() { - return Err(ParseError::new( + return Err(ParseError::from_span( "Empty pattern definition".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -289,8 +291,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { } if elements.is_empty() { - return Err(ParseError::new( + return Err(ParseError::from_span( "Expected pattern element".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -308,8 +311,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { i: &mut usize, ) -> Result { if *i >= tokens.len() { - return Err(ParseError::new( + return Err(ParseError::from_span( "Unexpected end of pattern".to_string(), + crate::diagnostics::Span { start: 0, end: 0 }, 0, 0, )); @@ -345,19 +349,17 @@ impl<'a> PatternParser<'a> for Parser<'a> { PatternExpression::CharacterClass(CharClass::Any) } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'letter', 'digit', 'whitespace', or 'character' after 'any'" .to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected character class after 'any'".to_string(), - token.line, - token.column, + token, )); } } @@ -383,10 +385,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { quantifier: Quantifier::OneOrMore, } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected 'one' in pattern (did you mean 'one or more'?)".to_string(), - token.line, - token.column, + token, )); } } @@ -410,10 +411,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { quantifier: Quantifier::ZeroOrMore, } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unexpected 'zero' in pattern (did you mean 'zero or more'?)".to_string(), - token.line, - token.column, + token, )); } } @@ -446,17 +446,15 @@ impl<'a> PatternParser<'a> for Parser<'a> { quantifier: Quantifier::Exactly(n as u32), } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected number after 'exactly' in pattern".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected number after 'exactly' in pattern".to_string(), - token.line, - token.column, + token, )); } } @@ -483,17 +481,15 @@ impl<'a> PatternParser<'a> for Parser<'a> { quantifier: Quantifier::AtLeast(n as u32), } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected number after 'at least' in pattern".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected number after 'at least' in pattern".to_string(), - token.line, - token.column, + token, )); } } @@ -514,33 +510,29 @@ impl<'a> PatternParser<'a> for Parser<'a> { quantifier: Quantifier::AtMost(n as u32), } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected number after 'at most' in pattern".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected number after 'at most' in pattern".to_string(), - token.line, - token.column, + token, )); } } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'least' or 'most' after 'at' in pattern".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'least' or 'most' after 'at' in pattern".to_string(), - token.line, - token.column, + token, )); } } @@ -567,10 +559,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { quantifier: Quantifier::Between(min_val, max as u32), } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected number after 'to' in pattern".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { @@ -629,18 +620,16 @@ impl<'a> PatternParser<'a> for Parser<'a> { category.clone(), )) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected string literal after 'unicode category'" .to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected category name after 'unicode category'".to_string(), - tokens[*i - 1].line, - tokens[*i - 1].column, + &tokens[*i - 1], )); } } @@ -653,18 +642,16 @@ impl<'a> PatternParser<'a> for Parser<'a> { script.clone(), )) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected string literal after 'unicode script'" .to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected script name after 'unicode script'".to_string(), - tokens[*i - 1].line, - tokens[*i - 1].column, + &tokens[*i - 1], )); } } @@ -677,34 +664,30 @@ impl<'a> PatternParser<'a> for Parser<'a> { property.clone(), )) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected string literal after 'unicode property'" .to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected property name after 'unicode property'".to_string(), - tokens[*i - 1].line, - tokens[*i - 1].column, + &tokens[*i - 1], )); } } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'letter', 'digit', 'category', 'script', or 'property' after 'unicode'".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Incomplete unicode pattern".to_string(), - tokens[*i - 1].line, - tokens[*i - 1].column, + &tokens[*i - 1], )); } } @@ -718,10 +701,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { *i += 3; PatternExpression::Anchor(Anchor::StartOfText) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'start of text'".to_string(), - token.line, - token.column, + token, )); } } @@ -745,10 +727,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { } if brace_count > 0 { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unclosed capture group".to_string(), - token.line, - token.column, + token, )); } @@ -769,31 +750,27 @@ impl<'a> PatternParser<'a> for Parser<'a> { pattern: Box::new(inner_pattern), } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected identifier after 'as'".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected capture name after 'as'".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'as' after capture group".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected '{' after 'capture'".to_string(), - token.line, - token.column, + token, )); } } @@ -812,25 +789,22 @@ impl<'a> PatternParser<'a> for Parser<'a> { *i += 1; PatternExpression::Backreference(name.clone()) } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected capture name (in quotes) after 'same as captured'" .to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected capture name after 'same as captured'".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'as captured' after 'same'".to_string(), - token.line, - token.column, + token, )); } } @@ -839,10 +813,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { Token::KeywordCheck => { *i += 1; if *i >= tokens.len() { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'ahead' or 'behind' after 'check'".to_string(), - token.line, - token.column, + token, )); } @@ -854,10 +827,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { }; if *i >= tokens.len() { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'ahead' or 'behind' after 'check'".to_string(), - token.line, - token.column, + token, )); } @@ -887,10 +859,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { } if brace_count != 0 { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unmatched '{' in lookahead pattern".to_string(), - tokens[pattern_start - 1].line, - tokens[pattern_start - 1].column, + &tokens[pattern_start - 1], )); } @@ -905,17 +876,15 @@ impl<'a> PatternParser<'a> for Parser<'a> { PatternExpression::Lookahead(Box::new(inner_pattern)) } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected '{' after 'check ahead for'".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'for' after 'check ahead'".to_string(), - token.line, - token.column, + token, )); } } @@ -944,10 +913,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { } if brace_count != 0 { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unmatched '{' in lookbehind pattern".to_string(), - tokens[pattern_start - 1].line, - tokens[pattern_start - 1].column, + &tokens[pattern_start - 1], )); } @@ -962,25 +930,22 @@ impl<'a> PatternParser<'a> for Parser<'a> { PatternExpression::Lookbehind(Box::new(inner_pattern)) } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected '{' after 'check behind for'".to_string(), - token.line, - token.column, + token, )); } } else { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'for' after 'check behind'".to_string(), - token.line, - token.column, + token, )); } } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( "Expected 'ahead' or 'behind' after 'check'".to_string(), - tokens[*i].line, - tokens[*i].column, + &tokens[*i], )); } } @@ -990,10 +955,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { Token::KeywordBy => { // This is likely a stray "by" after "followed" was consumed // Just return an error suggesting the issue - return Err(ParseError::new( + return Err(ParseError::from_token( "Found 'by' keyword - did you mean 'followed by'? Note: 'followed by' should be used between pattern elements".to_string(), - token.line, - token.column, + token, )); } @@ -1018,10 +982,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { } if paren_count != 0 { - return Err(ParseError::new( + return Err(ParseError::from_token( "Unmatched '(' in pattern".to_string(), - token.line, - token.column, + token, )); } @@ -1030,10 +993,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { *i = pattern_end + 1; // Skip past ')' if inner_tokens.is_empty() { - return Err(ParseError::new( + return Err(ParseError::from_token( "Empty parentheses in pattern".to_string(), - token.line, - token.column, + token, )); } @@ -1049,10 +1011,9 @@ impl<'a> PatternParser<'a> for Parser<'a> { } _ => { - return Err(ParseError::new( + return Err(ParseError::from_token( format!("Unexpected token in pattern: {:?}", token.token), - token.line, - token.column, + token, )); } }; diff --git a/src/parser/stmt/processes.rs b/src/parser/stmt/processes.rs index 28bf2708..f532afab 100644 --- a/src/parser/stmt/processes.rs +++ b/src/parser/stmt/processes.rs @@ -51,7 +51,7 @@ impl<'a> ProcessParser<'a> for Parser<'a> { { self.bump_sync(); // Consume "as" let var_token = self.bump_sync().ok_or_else(|| { - ParseError::from_token("Expected identifier after 'as'".to_string(), &token_pos) + ParseError::from_token("Expected identifier after 'as'".to_string(), token_pos) })?; if let Token::Identifier(name) = &var_token.token { @@ -59,7 +59,7 @@ impl<'a> ProcessParser<'a> for Parser<'a> { } else { return Err(ParseError::from_token( format!("Expected identifier, found {:?}", var_token.token), - &var_token, + var_token, )); } } else { @@ -108,7 +108,7 @@ impl<'a> ProcessParser<'a> for Parser<'a> { self.expect_token(Token::KeywordAs, "Expected 'as' after spawn command")?; let var_token = self.bump_sync().ok_or_else(|| { - ParseError::from_token("Expected identifier after 'as'".to_string(), &token_pos) + ParseError::from_token("Expected identifier after 'as'".to_string(), token_pos) })?; let variable_name = if let Token::Identifier(name) = &var_token.token { @@ -116,7 +116,7 @@ impl<'a> ProcessParser<'a> for Parser<'a> { } else { return Err(ParseError::from_token( format!("Expected identifier, found {:?}", var_token.token), - &var_token, + var_token, )); }; @@ -154,7 +154,7 @@ impl<'a> ProcessParser<'a> for Parser<'a> { self.expect_token(Token::KeywordAs, "Expected 'as' after process ID")?; let var_token = self.bump_sync().ok_or_else(|| { - ParseError::from_token("Expected identifier after 'as'".to_string(), &token_pos) + ParseError::from_token("Expected identifier after 'as'".to_string(), token_pos) })?; let variable_name = if let Token::Identifier(name) = &var_token.token { @@ -162,7 +162,7 @@ impl<'a> ProcessParser<'a> for Parser<'a> { } else { return Err(ParseError::from_token( format!("Expected identifier, found {:?}", var_token.token), - &var_token, + var_token, )); }; @@ -406,7 +406,7 @@ impl<'a> ProcessParser<'a> for Parser<'a> { Err(ParseError::from_token( "Expected 'content' after 'write' or 'append'".to_string(), - &wait_token_pos, + wait_token_pos, )) } }