diff --git a/core/src/error.rs b/core/src/error.rs index f69b61f..fde16d8 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -1,6 +1,5 @@ -use std::fmt::Display; - use crate::Location; +use std::fmt::Display; #[derive(Debug, PartialEq, Eq)] pub struct BaseError { @@ -87,3 +86,24 @@ where } } } + +impl CompileError { + pub fn from(error: BaseError, source: &str) -> Self + where + T: From, + { + let statement = get_statement(source, error.location); + CompileError { + body: error.into(), + statement, + } + } +} + +fn get_statement(source: &str, loc: Location) -> Option { + if loc.column() == 0 || loc.row() == 0 { + return None; + } + let line = source.split('\n').nth(loc.row() - 1)?.to_owned(); + Some(line + "\n") +} diff --git a/parser/src/error.rs b/parser/src/error.rs index 77f2f8f..4dd899e 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -117,8 +117,7 @@ impl From for LalrpopError { } /// Represents an error during parsing -#[derive(Debug, PartialEq)] -pub struct ParseError(rustpython_compiler_core::BaseError); +pub type ParseError = rustpython_compiler_core::BaseError; #[derive(Debug, PartialEq)] pub enum ParseErrorType { @@ -134,66 +133,44 @@ pub enum ParseErrorType { Lexical(LexicalErrorType), } -impl From for rustpython_compiler_core::BaseError { - fn from(err: ParseError) -> Self { - err.0 - } -} - -impl From for ParseErrorType { - fn from(err: ParseError) -> Self { - err.0.error - } -} - /// Convert `lalrpop_util::ParseError` to our internal type -impl ParseError { - fn new(error: ParseErrorType, location: Location, source_path: String) -> Self { - Self(rustpython_compiler_core::BaseError { - error, +pub(crate) fn parse_error_from_lalrpop( + err: LalrpopError, + source_path: &str, +) -> ParseError { + let source_path = source_path.to_owned(); + match err { + // TODO: Are there cases where this isn't an EOF? + LalrpopError::InvalidToken { location } => ParseError { + error: ParseErrorType::Eof, location, source_path, - }) - } - - pub(crate) fn from_lalrpop( - err: LalrpopError, - source_path: &str, - ) -> Self { - let source_path = source_path.to_owned(); - match err { - // TODO: Are there cases where this isn't an EOF? - LalrpopError::InvalidToken { location } => { - ParseError::new(ParseErrorType::Eof, location, source_path) - } - LalrpopError::ExtraToken { token } => { - ParseError::new(ParseErrorType::ExtraToken(token.1), token.0, source_path) - } - LalrpopError::User { error } => ParseError::new( - ParseErrorType::Lexical(error.error), - error.location, + }, + LalrpopError::ExtraToken { token } => ParseError { + error: ParseErrorType::ExtraToken(token.1), + location: token.0, + source_path, + }, + LalrpopError::User { error } => ParseError { + error: ParseErrorType::Lexical(error.error), + location: error.location, + source_path, + }, + LalrpopError::UnrecognizedToken { token, expected } => { + // Hacky, but it's how CPython does it. See PyParser_AddToken, + // in particular "Only one possible expected token" comment. + let expected = (expected.len() == 1).then(|| expected[0].clone()); + ParseError { + error: ParseErrorType::UnrecognizedToken(token.1, expected), + location: token.0, source_path, - ), - LalrpopError::UnrecognizedToken { token, expected } => { - // Hacky, but it's how CPython does it. See PyParser_AddToken, - // in particular "Only one possible expected token" comment. - let expected = (expected.len() == 1).then(|| expected[0].clone()); - ParseError::new( - ParseErrorType::UnrecognizedToken(token.1, expected), - token.0, - source_path, - ) - } - LalrpopError::UnrecognizedEOF { location, .. } => { - ParseError::new(ParseErrorType::Eof, location, source_path) } } - } -} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) + LalrpopError::UnrecognizedEOF { location, .. } => ParseError { + error: ParseErrorType::Eof, + location, + source_path, + }, } } @@ -237,16 +214,3 @@ impl ParseErrorType { ) } } - -impl std::ops::Deref for ParseError { - type Target = rustpython_compiler_core::BaseError; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Error for ParseError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - None - } -} diff --git a/parser/src/fstring.rs b/parser/src/fstring.rs index dc17063..11d75a0 100644 --- a/parser/src/fstring.rs +++ b/parser/src/fstring.rs @@ -186,7 +186,7 @@ impl<'a> FStringParser<'a> { vec![self.expr(ExprKind::FormattedValue { value: Box::new( parse_fstring_expr(&expression) - .map_err(|e| InvalidExpression(Box::new(e.into())))?, + .map_err(|e| InvalidExpression(Box::new(e.error)))?, ), conversion: conversion as _, format_spec: spec, @@ -204,7 +204,7 @@ impl<'a> FStringParser<'a> { self.expr(ExprKind::FormattedValue { value: Box::new( parse_fstring_expr(&expression) - .map_err(|e| InvalidExpression(Box::new(e.into())))?, + .map_err(|e| InvalidExpression(Box::new(e.error)))?, ), conversion: (if conversion == ConversionFlag::None && spec.is_none() { diff --git a/parser/src/parser.rs b/parser/src/parser.rs index ff86ef4..cd74856 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -74,7 +74,7 @@ pub fn parse(source: &str, mode: Mode, source_path: &str) -> Result