Move out CompileError to core as generic form

This commit is contained in:
Jeong YunWon 2022-08-23 01:30:00 +09:00
parent 5b50c547d6
commit 4724cc63f7
4 changed files with 52 additions and 55 deletions

View file

@ -17,3 +17,4 @@ num-bigint = { version = "0.4.3", features = ["serde"] }
num-complex = { version = "0.4.0", features = ["serde"] } num-complex = { version = "0.4.0", features = ["serde"] }
serde = { version = "1.0.136", features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] }
static_assertions = "1.1.0" static_assertions = "1.1.0"
thiserror = "1.0"

View file

@ -58,3 +58,32 @@ impl<T> BaseError<T> {
BaseError::from(self) BaseError::from(self)
} }
} }
#[derive(Debug, thiserror::Error)]
pub struct CompileError<T> {
pub body: BaseError<T>,
pub statement: Option<String>,
}
impl<T> std::ops::Deref for CompileError<T> {
type Target = BaseError<T>;
fn deref(&self) -> &Self::Target {
&self.body
}
}
impl<T> std::fmt::Display for CompileError<T>
where
T: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let loc = self.location;
if let Some(ref stmt) = self.statement {
// visualize the error when location and statement are provided
loc.fmt_with(f, &self.error)?;
write!(f, "\n{stmt}{arrow:>pad$}", pad = loc.column(), arrow = "^")
} else {
loc.fmt_with(f, &self.error)
}
}
}

View file

@ -7,6 +7,6 @@ mod location;
mod mode; mod mode;
pub use bytecode::*; pub use bytecode::*;
pub use error::BaseError; pub use error::{BaseError, CompileError};
pub use location::Location; pub use location::Location;
pub use mode::Mode; pub use mode::Mode;

View file

@ -1,14 +1,13 @@
use rustpython_codegen::{compile, symboltable}; use rustpython_codegen::{compile, symboltable};
use rustpython_compiler_core::{BaseError, CodeObject}; use rustpython_compiler_core::CodeObject;
use rustpython_parser::{ use rustpython_parser::{
ast::{fold::Fold, ConstantOptimizer, Location}, ast::{fold::Fold, ConstantOptimizer, Location},
error::ParseErrorType, error::ParseErrorType,
parser, parser,
}; };
use std::fmt;
pub use rustpython_codegen::compile::CompileOpts; pub use rustpython_codegen::compile::CompileOpts;
pub use rustpython_compiler_core::Mode; pub use rustpython_compiler_core::{BaseError as CompileErrorBody, Mode};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum CompileErrorType { pub enum CompileErrorType {
@ -18,56 +17,25 @@ pub enum CompileErrorType {
Parse(#[from] rustpython_parser::error::ParseErrorType), Parse(#[from] rustpython_parser::error::ParseErrorType),
} }
pub type CompileErrorBody = BaseError<CompileErrorType>; pub type CompileError = rustpython_compiler_core::CompileError<CompileErrorType>;
#[derive(Debug, thiserror::Error)] fn error_from_codegen(
pub struct CompileError { error: rustpython_codegen::error::CodegenError,
pub body: CompileErrorBody, source: &str,
pub statement: Option<String>, ) -> CompileError {
} let statement = get_statement(source, error.location);
CompileError {
impl std::ops::Deref for CompileError { body: error.into(),
type Target = CompileErrorBody; statement,
fn deref(&self) -> &Self::Target {
&self.body
} }
} }
impl fmt::Display for CompileError { fn error_from_parse(error: rustpython_parser::error::ParseError, source: &str) -> CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let error: CompileErrorBody<ParseErrorType> = error.into();
let loc = self.location; let statement = get_statement(source, error.location);
if let Some(ref stmt) = self.statement { CompileError {
// visualize the error when location and statement are provided body: error.into(),
loc.fmt_with(f, &self.error)?; statement,
write!(f, "\n{stmt}{arrow:>pad$}", pad = loc.column(), arrow = "^")
} else {
loc.fmt_with(f, &self.error)
}
}
}
impl CompileError {
fn from_codegen(error: rustpython_codegen::error::CodegenError, source: &str) -> Self {
let statement = get_statement(source, error.location);
Self {
body: error.into(),
statement,
}
}
fn from_parse(error: rustpython_parser::error::ParseError, source: &str) -> Self {
let error: rustpython_compiler_core::BaseError<ParseErrorType> = error.into();
let statement = get_statement(source, error.location);
Self {
body: error.into(),
statement,
}
}
fn from_symtable(
error: symboltable::SymbolTableError,
source: &str,
source_path: String,
) -> Self {
Self::from_codegen(error.into_codegen_error(source_path), source)
} }
} }
@ -85,15 +53,14 @@ pub fn compile(
}; };
let mut ast = match parser::parse(source, parser_mode, &source_path) { let mut ast = match parser::parse(source, parser_mode, &source_path) {
Ok(x) => x, Ok(x) => x,
Err(e) => return Err(CompileError::from_parse(e, source)), Err(e) => return Err(error_from_parse(e, source)),
}; };
if opts.optimize > 0 { if opts.optimize > 0 {
ast = ConstantOptimizer::new() ast = ConstantOptimizer::new()
.fold_mod(ast) .fold_mod(ast)
.unwrap_or_else(|e| match e {}); .unwrap_or_else(|e| match e {});
} }
compile::compile_top(&ast, source_path, mode, opts) compile::compile_top(&ast, source_path, mode, opts).map_err(|e| error_from_codegen(e, source))
.map_err(|e| CompileError::from_codegen(e, source))
} }
pub fn compile_symtable( pub fn compile_symtable(
@ -101,7 +68,7 @@ pub fn compile_symtable(
mode: compile::Mode, mode: compile::Mode,
source_path: &str, source_path: &str,
) -> Result<symboltable::SymbolTable, CompileError> { ) -> Result<symboltable::SymbolTable, CompileError> {
let parse_err = |e| CompileError::from_parse(e, source); let parse_err = |e| error_from_parse(e, source);
let res = match mode { let res = match mode {
compile::Mode::Exec | compile::Mode::Single | compile::Mode::BlockExpr => { compile::Mode::Exec | compile::Mode::Single | compile::Mode::BlockExpr => {
let ast = parser::parse_program(source, source_path).map_err(parse_err)?; let ast = parser::parse_program(source, source_path).map_err(parse_err)?;
@ -112,7 +79,7 @@ pub fn compile_symtable(
symboltable::SymbolTable::scan_expr(&expr) symboltable::SymbolTable::scan_expr(&expr)
} }
}; };
res.map_err(|e| CompileError::from_symtable(e, source, source_path.to_owned())) res.map_err(|e| error_from_codegen(e.into_codegen_error(source_path.to_owned()), source))
} }
fn get_statement(source: &str, loc: Location) -> Option<String> { fn get_statement(source: &str, loc: Location) -> Option<String> {