Split the ast from the parser, remove compiler dep on parser

This commit is contained in:
Noah 2020-11-02 12:37:19 -06:00
parent 3f88b08aaa
commit e9095a741d
5 changed files with 153 additions and 225 deletions

View file

@ -1,34 +1,17 @@
use rustpython_parser::error::{LexicalErrorType, ParseError, ParseErrorType};
use rustpython_parser::location::Location;
use rustpython_parser::token::Tok;
use rustpython_ast::Location;
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub struct CompileError {
pub statement: Option<String>,
pub error: CompileErrorType,
pub location: Location,
pub source_path: String,
}
impl CompileError {
pub fn from_parse_error(parse_error: ParseError, source_path: String) -> Self {
Self {
statement: None,
error: CompileErrorType::Parse(parse_error.error),
location: parse_error.location,
source_path,
}
}
pub fn update_statement_info(&mut self, statement: String) {
self.statement = Some(statement);
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum CompileErrorType {
/// Invalid assignment, cannot store value in target.
Assign(&'static str),
@ -36,8 +19,6 @@ pub enum CompileErrorType {
Delete(&'static str),
/// Expected an expression got a statement
ExpectExpr,
/// Parser error
Parse(ParseErrorType),
SyntaxError(String),
/// Multiple `*` detected
MultipleStarArgs,
@ -57,74 +38,43 @@ pub enum CompileErrorType {
InvalidFutureFeature(String),
}
impl CompileError {
pub fn is_indentation_error(&self) -> bool {
if let CompileErrorType::Parse(parse) = &self.error {
match parse {
ParseErrorType::Lexical(LexicalErrorType::IndentationError) => true,
ParseErrorType::UnrecognizedToken(token, expected) => {
*token == Tok::Indent || expected.clone() == Some("Indent".to_owned())
}
_ => false,
impl fmt::Display for CompileErrorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CompileErrorType::Assign(target) => write!(f, "can't assign to {}", target),
CompileErrorType::Delete(target) => write!(f, "can't delete {}", target),
CompileErrorType::ExpectExpr => write!(f, "Expecting expression, got statement"),
CompileErrorType::SyntaxError(err) => write!(f, "{}", err.as_str()),
CompileErrorType::MultipleStarArgs => {
write!(f, "two starred expressions in assignment")
}
} else {
false
}
}
pub fn is_tab_error(&self) -> bool {
if let CompileErrorType::Parse(parse) = &self.error {
if let ParseErrorType::Lexical(lex) = parse {
if let LexicalErrorType::TabError = lex {
return true;
}
CompileErrorType::InvalidStarExpr => write!(f, "can't use starred expression here"),
CompileErrorType::InvalidBreak => write!(f, "'break' outside loop"),
CompileErrorType::InvalidContinue => write!(f, "'continue' outside loop"),
CompileErrorType::InvalidReturn => write!(f, "'return' outside function"),
CompileErrorType::InvalidYield => write!(f, "'yield' outside function"),
CompileErrorType::InvalidYieldFrom => write!(f, "'yield from' outside function"),
CompileErrorType::InvalidAwait => write!(f, "'await' outside async function"),
CompileErrorType::AsyncYieldFrom => write!(f, "'yield from' inside async function"),
CompileErrorType::AsyncReturnValue => {
write!(f, "'return' with value inside async generator")
}
CompileErrorType::InvalidFuturePlacement => write!(
f,
"from __future__ imports must occur at the beginning of the file"
),
CompileErrorType::InvalidFutureFeature(feat) => {
write!(f, "future feature {} is not defined", feat)
}
}
false
}
}
impl Error for CompileErrorType {}
impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let error_desc = match &self.error {
CompileErrorType::Assign(target) => format!("can't assign to {}", target),
CompileErrorType::Delete(target) => format!("can't delete {}", target),
CompileErrorType::ExpectExpr => "Expecting expression, got statement".to_owned(),
CompileErrorType::Parse(err) => err.to_string(),
CompileErrorType::SyntaxError(err) => err.to_string(),
CompileErrorType::MultipleStarArgs => {
"two starred expressions in assignment".to_owned()
}
CompileErrorType::InvalidStarExpr => "can't use starred expression here".to_owned(),
CompileErrorType::InvalidBreak => "'break' outside loop".to_owned(),
CompileErrorType::InvalidContinue => "'continue' outside loop".to_owned(),
CompileErrorType::InvalidReturn => "'return' outside function".to_owned(),
CompileErrorType::InvalidYield => "'yield' outside function".to_owned(),
CompileErrorType::InvalidYieldFrom => "'yield from' outside function".to_owned(),
CompileErrorType::InvalidAwait => "'await' outside async function".to_owned(),
CompileErrorType::AsyncYieldFrom => "'yield from' inside async function".to_owned(),
CompileErrorType::AsyncReturnValue => {
"'return' with value inside async generator".to_owned()
}
CompileErrorType::InvalidFuturePlacement => {
"from __future__ imports must occur at the beginning of the file".to_owned()
}
CompileErrorType::InvalidFutureFeature(feat) => {
format!("future feature {} is not defined", feat)
}
};
if let Some(statement) = &self.statement {
if self.location.column() > 0 {
if let Some(line) = statement.lines().nth(self.location.row() - 1) {
// visualize the error, when location and statement are provided
return write!(f, "{}", self.location.visualize(line, &error_desc));
}
}
}
// print line number
write!(f, "{} at {}", error_desc, self.location)
write!(f, "{} at {}", self.error, self.location)
}
}