Skip to content

Commit

Permalink
new_syntax_error working without full compiler
Browse files Browse the repository at this point in the history
Fix #4100
  • Loading branch information
youknowone committed Aug 22, 2022
1 parent 42b95a9 commit 1fd898c
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 74 deletions.
24 changes: 22 additions & 2 deletions core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::fmt::Display;

use crate::Location;
use std::fmt::Display;

#[derive(Debug, PartialEq, Eq)]
pub struct BaseError<T> {
Expand Down Expand Up @@ -87,3 +86,24 @@ where
}
}
}

impl<T> CompileError<T> {
pub fn from<U>(error: BaseError<U>, source: &str) -> Self
where
T: From<U>,
{
let statement = get_statement(source, error.location);
CompileError {
body: error.into(),
statement,
}
}
}

fn get_statement(source: &str, loc: Location) -> Option<String> {
if loc.column() == 0 || loc.row() == 0 {
return None;
}
let line = source.split('\n').nth(loc.row() - 1)?.to_owned();
Some(line + "\n")
}
102 changes: 33 additions & 69 deletions parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ impl From<FStringError> for LalrpopError<Location, Tok, LexicalError> {
}

/// Represents an error during parsing
#[derive(Debug, PartialEq)]
pub struct ParseError(rustpython_compiler_core::BaseError<ParseErrorType>);
pub type ParseError = rustpython_compiler_core::BaseError<ParseErrorType>;

#[derive(Debug, PartialEq)]
pub enum ParseErrorType {
Expand All @@ -134,66 +133,44 @@ pub enum ParseErrorType {
Lexical(LexicalErrorType),
}

impl From<ParseError> for rustpython_compiler_core::BaseError<ParseErrorType> {
fn from(err: ParseError) -> Self {
err.0
}
}

impl From<ParseError> 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<Location, Tok, LexicalError>,
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<Location, Tok, LexicalError>,
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,
},
}
}

Expand Down Expand Up @@ -237,16 +214,3 @@ impl ParseErrorType {
)
}
}

impl std::ops::Deref for ParseError {
type Target = rustpython_compiler_core::BaseError<ParseErrorType>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Error for ParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
4 changes: 2 additions & 2 deletions parser/src/fstring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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()
{
Expand Down
2 changes: 1 addition & 1 deletion parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub fn parse(source: &str, mode: Mode, source_path: &str) -> Result<ast::Mod, Pa

python::TopParser::new()
.parse(tokenizer)
.map_err(|e| ParseError::from_lalrpop(e, source_path))
.map_err(|e| crate::error::parse_error_from_lalrpop(e, source_path))
}

#[cfg(test)]
Expand Down

0 comments on commit 1fd898c

Please sign in to comment.