1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use rustpython_parser::error::{LexicalErrorType, ParseError, ParseErrorType};
use rustpython_parser::location::Location;
use rustpython_parser::token::Tok;
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: Option<String>,
}
impl CompileError {
pub fn update_statement_info(&mut self, statement: String) {
self.statement = Some(statement);
}
pub fn update_source_path(&mut self, source_path: &str) {
debug_assert!(self.source_path.is_none());
self.source_path = Some(source_path.to_owned());
}
}
impl From<ParseError> for CompileError {
fn from(error: ParseError) -> Self {
CompileError {
statement: None,
error: CompileErrorType::Parse(error.error),
location: error.location,
source_path: None,
}
}
}
#[derive(Debug)]
pub enum CompileErrorType {
Assign(&'static str),
Delete(&'static str),
ExpectExpr,
Parse(ParseErrorType),
SyntaxError(String),
StarArgs,
InvalidBreak,
InvalidContinue,
InvalidReturn,
InvalidYield,
}
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,
}
} 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;
}
}
}
false
}
}
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::StarArgs => "Two starred expressions in assignment".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(),
};
if let Some(statement) = &self.statement {
if self.location.column() > 0 {
if let Some(line) = statement.lines().nth(self.location.row() - 1) {
return write!(f, "\n{}\n{}", line, self.location.visualize(&error_desc));
}
}
}
write!(f, "{} at {}", error_desc, self.location)
}
}
impl Error for CompileError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}