mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-12 07:35:16 +00:00
parent
4724cc63f7
commit
a1640e4aa1
7 changed files with 66 additions and 106 deletions
|
@ -17,6 +17,7 @@ itertools = "0.10.3"
|
||||||
log = "0.4.16"
|
log = "0.4.16"
|
||||||
num-complex = { version = "0.4.0", features = ["serde"] }
|
num-complex = { version = "0.4.0", features = ["serde"] }
|
||||||
num-traits = "0.2.14"
|
num-traits = "0.2.14"
|
||||||
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustpython-parser = { path = "../parser" }
|
rustpython-parser = { path = "../parser" }
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::{error::Error, fmt};
|
use std::fmt;
|
||||||
|
|
||||||
pub type CodegenError = rustpython_compiler_core::BaseError<CodegenErrorType>;
|
pub type CodegenError = rustpython_compiler_core::BaseError<CodegenErrorType>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum CodegenErrorType {
|
pub enum CodegenErrorType {
|
||||||
/// Invalid assignment, cannot store value in target.
|
/// Invalid assignment, cannot store value in target.
|
||||||
|
@ -79,5 +79,3 @@ impl fmt::Display for CodegenErrorType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for CodegenErrorType {}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
use crate::Location;
|
use crate::Location;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct BaseError<T> {
|
pub struct BaseError<T> {
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
@ -117,8 +117,7 @@ impl From<FStringError> for LalrpopError<Location, Tok, LexicalError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an error during parsing
|
/// Represents an error during parsing
|
||||||
#[derive(Debug, PartialEq)]
|
pub type ParseError = rustpython_compiler_core::BaseError<ParseErrorType>;
|
||||||
pub struct ParseError(rustpython_compiler_core::BaseError<ParseErrorType>);
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ParseErrorType {
|
pub enum ParseErrorType {
|
||||||
|
@ -134,66 +133,44 @@ pub enum ParseErrorType {
|
||||||
Lexical(LexicalErrorType),
|
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
|
/// Convert `lalrpop_util::ParseError` to our internal type
|
||||||
impl ParseError {
|
pub(crate) fn parse_error_from_lalrpop(
|
||||||
fn new(error: ParseErrorType, location: Location, source_path: String) -> Self {
|
|
||||||
Self(rustpython_compiler_core::BaseError {
|
|
||||||
error,
|
|
||||||
location,
|
|
||||||
source_path,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_lalrpop(
|
|
||||||
err: LalrpopError<Location, Tok, LexicalError>,
|
err: LalrpopError<Location, Tok, LexicalError>,
|
||||||
source_path: &str,
|
source_path: &str,
|
||||||
) -> Self {
|
) -> ParseError {
|
||||||
let source_path = source_path.to_owned();
|
let source_path = source_path.to_owned();
|
||||||
match err {
|
match err {
|
||||||
// TODO: Are there cases where this isn't an EOF?
|
// TODO: Are there cases where this isn't an EOF?
|
||||||
LalrpopError::InvalidToken { location } => {
|
LalrpopError::InvalidToken { location } => ParseError {
|
||||||
ParseError::new(ParseErrorType::Eof, location, source_path)
|
error: ParseErrorType::Eof,
|
||||||
}
|
location,
|
||||||
LalrpopError::ExtraToken { token } => {
|
|
||||||
ParseError::new(ParseErrorType::ExtraToken(token.1), token.0, source_path)
|
|
||||||
}
|
|
||||||
LalrpopError::User { error } => ParseError::new(
|
|
||||||
ParseErrorType::Lexical(error.error),
|
|
||||||
error.location,
|
|
||||||
source_path,
|
source_path,
|
||||||
),
|
},
|
||||||
|
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 } => {
|
LalrpopError::UnrecognizedToken { token, expected } => {
|
||||||
// Hacky, but it's how CPython does it. See PyParser_AddToken,
|
// Hacky, but it's how CPython does it. See PyParser_AddToken,
|
||||||
// in particular "Only one possible expected token" comment.
|
// in particular "Only one possible expected token" comment.
|
||||||
let expected = (expected.len() == 1).then(|| expected[0].clone());
|
let expected = (expected.len() == 1).then(|| expected[0].clone());
|
||||||
ParseError::new(
|
ParseError {
|
||||||
ParseErrorType::UnrecognizedToken(token.1, expected),
|
error: ParseErrorType::UnrecognizedToken(token.1, expected),
|
||||||
token.0,
|
location: token.0,
|
||||||
source_path,
|
source_path,
|
||||||
)
|
|
||||||
}
|
|
||||||
LalrpopError::UnrecognizedEOF { location, .. } => {
|
|
||||||
ParseError::new(ParseErrorType::Eof, location, source_path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
LalrpopError::UnrecognizedEOF { location, .. } => ParseError {
|
||||||
}
|
error: ParseErrorType::Eof,
|
||||||
|
location,
|
||||||
impl fmt::Display for ParseError {
|
source_path,
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
},
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ impl<'a> FStringParser<'a> {
|
||||||
vec![self.expr(ExprKind::FormattedValue {
|
vec![self.expr(ExprKind::FormattedValue {
|
||||||
value: Box::new(
|
value: Box::new(
|
||||||
parse_fstring_expr(&expression)
|
parse_fstring_expr(&expression)
|
||||||
.map_err(|e| InvalidExpression(Box::new(e.into())))?,
|
.map_err(|e| InvalidExpression(Box::new(e.error)))?,
|
||||||
),
|
),
|
||||||
conversion: conversion as _,
|
conversion: conversion as _,
|
||||||
format_spec: spec,
|
format_spec: spec,
|
||||||
|
@ -204,7 +204,7 @@ impl<'a> FStringParser<'a> {
|
||||||
self.expr(ExprKind::FormattedValue {
|
self.expr(ExprKind::FormattedValue {
|
||||||
value: Box::new(
|
value: Box::new(
|
||||||
parse_fstring_expr(&expression)
|
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()
|
conversion: (if conversion == ConversionFlag::None && spec.is_none()
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub fn parse(source: &str, mode: Mode, source_path: &str) -> Result<ast::Mod, Pa
|
||||||
|
|
||||||
python::TopParser::new()
|
python::TopParser::new()
|
||||||
.parse(tokenizer)
|
.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)]
|
#[cfg(test)]
|
||||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -1,7 +1,7 @@
|
||||||
use rustpython_codegen::{compile, symboltable};
|
use rustpython_codegen::{compile, symboltable};
|
||||||
use rustpython_compiler_core::CodeObject;
|
use rustpython_compiler_core::CodeObject;
|
||||||
use rustpython_parser::{
|
use rustpython_parser::{
|
||||||
ast::{fold::Fold, ConstantOptimizer, Location},
|
ast::{fold::Fold, ConstantOptimizer},
|
||||||
error::ParseErrorType,
|
error::ParseErrorType,
|
||||||
parser,
|
parser,
|
||||||
};
|
};
|
||||||
|
@ -12,31 +12,16 @@ pub use rustpython_compiler_core::{BaseError as CompileErrorBody, Mode};
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum CompileErrorType {
|
pub enum CompileErrorType {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Compile(#[from] rustpython_codegen::error::CodegenErrorType),
|
Codegen(#[from] rustpython_codegen::error::CodegenErrorType),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Parse(#[from] rustpython_parser::error::ParseErrorType),
|
Parse(#[from] rustpython_parser::error::ParseErrorType),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CompileError = rustpython_compiler_core::CompileError<CompileErrorType>;
|
pub type CompileError = rustpython_compiler_core::CompileError<CompileErrorType>;
|
||||||
|
|
||||||
fn error_from_codegen(
|
|
||||||
error: rustpython_codegen::error::CodegenError,
|
|
||||||
source: &str,
|
|
||||||
) -> CompileError {
|
|
||||||
let statement = get_statement(source, error.location);
|
|
||||||
CompileError {
|
|
||||||
body: error.into(),
|
|
||||||
statement,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_from_parse(error: rustpython_parser::error::ParseError, source: &str) -> CompileError {
|
fn error_from_parse(error: rustpython_parser::error::ParseError, source: &str) -> CompileError {
|
||||||
let error: CompileErrorBody<ParseErrorType> = error.into();
|
let error: CompileErrorBody<ParseErrorType> = error.into();
|
||||||
let statement = get_statement(source, error.location);
|
CompileError::from(error, source)
|
||||||
CompileError {
|
|
||||||
body: error.into(),
|
|
||||||
statement,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile a given sourcecode into a bytecode object.
|
/// Compile a given sourcecode into a bytecode object.
|
||||||
|
@ -60,7 +45,7 @@ pub fn compile(
|
||||||
.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).map_err(|e| error_from_codegen(e, source))
|
compile::compile_top(&ast, source_path, mode, opts).map_err(|e| CompileError::from(e, source))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_symtable(
|
pub fn compile_symtable(
|
||||||
|
@ -79,13 +64,5 @@ pub fn compile_symtable(
|
||||||
symboltable::SymbolTable::scan_expr(&expr)
|
symboltable::SymbolTable::scan_expr(&expr)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
res.map_err(|e| error_from_codegen(e.into_codegen_error(source_path.to_owned()), source))
|
res.map_err(|e| CompileError::from(e.into_codegen_error(source_path.to_owned()), source))
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue