better errrors
This commit is contained in:
parent
91b851acd6
commit
c4c2cccbcf
2 changed files with 77 additions and 54 deletions
|
|
@ -27,6 +27,7 @@ pub enum ImportError {
|
||||||
file: String,
|
file: String,
|
||||||
message: String,
|
message: String,
|
||||||
span: (usize, usize),
|
span: (usize, usize),
|
||||||
|
source: String,
|
||||||
},
|
},
|
||||||
CircularDependency {
|
CircularDependency {
|
||||||
files: Vec<String>,
|
files: Vec<String>,
|
||||||
|
|
@ -56,6 +57,7 @@ impl std::fmt::Display for ImportError {
|
||||||
file,
|
file,
|
||||||
message,
|
message,
|
||||||
span,
|
span,
|
||||||
|
source: _,
|
||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
|
@ -170,12 +172,14 @@ impl ImportResolver {
|
||||||
fn parse_tokens(
|
fn parse_tokens(
|
||||||
tokens: Vec<(Token, logos::Span)>,
|
tokens: Vec<(Token, logos::Span)>,
|
||||||
filename: String,
|
filename: String,
|
||||||
|
source: String,
|
||||||
) -> Result<Vec<ASTNode>, ImportError> {
|
) -> Result<Vec<ASTNode>, ImportError> {
|
||||||
let mut parser = Parser::new(filename.clone(), tokens);
|
let mut parser = Parser::new(filename.clone(), tokens);
|
||||||
parser.parse().map_err(|e| ImportError::ParseError {
|
parser.parse().map_err(|e| ImportError::ParseError {
|
||||||
file: filename,
|
file: filename,
|
||||||
message: e.message.clone(),
|
message: e.message.clone(),
|
||||||
span: (e.span.start, e.span.end),
|
span: (e.span.start, e.span.end),
|
||||||
|
source,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,7 +203,7 @@ impl ImportResolver {
|
||||||
// Parse the file
|
// Parse the file
|
||||||
println!(" [parsing] {}", filename);
|
println!(" [parsing] {}", filename);
|
||||||
let tokens = Self::lex_source(&source, filename)?;
|
let tokens = Self::lex_source(&source, filename)?;
|
||||||
let nodes = Self::parse_tokens(tokens, filename.to_string())?;
|
let nodes = Self::parse_tokens(tokens, filename.to_string(), source.clone())?;
|
||||||
|
|
||||||
// Cache the result
|
// Cache the result
|
||||||
self.parse_cache.insert(
|
self.parse_cache.insert(
|
||||||
|
|
|
||||||
115
src/main.rs
115
src/main.rs
|
|
@ -64,63 +64,73 @@ fn run_test_suite() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_parse_error(source: &str, error: &suicmez::parser::ParseError) -> String {
|
fn format_import_error(error: &suicmez::import_resolver::ImportError) -> String {
|
||||||
// Find the line containing the error
|
match error {
|
||||||
let lines: Vec<&str> = source.lines().collect();
|
suicmez::import_resolver::ImportError::ParseError {
|
||||||
let mut current_pos = 0;
|
file,
|
||||||
|
message,
|
||||||
|
span,
|
||||||
|
source,
|
||||||
|
} => {
|
||||||
|
// Find the line containing the error
|
||||||
|
let lines: Vec<&str> = source.lines().collect();
|
||||||
|
let mut current_pos = 0;
|
||||||
|
|
||||||
for (line_idx, line) in lines.iter().enumerate() {
|
for (line_idx, line) in lines.iter().enumerate() {
|
||||||
let line_start = current_pos;
|
let line_start = current_pos;
|
||||||
let line_end = current_pos + line.len();
|
let line_end = current_pos + line.len();
|
||||||
|
|
||||||
// Check if the error span intersects with this line
|
// Check if the error span intersects with this line
|
||||||
if error.span.start < line_end && error.span.end > line_start {
|
if span.0 < line_end && span.1 > line_start {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
|
|
||||||
// Print the error message
|
// Print the error message
|
||||||
result.push_str(&format!("Parse error: {}\n", error.message));
|
result.push_str(&format!("Parse error in {}: {}\n", file, message));
|
||||||
|
|
||||||
// Print the line number and content
|
// Print the line number and content
|
||||||
result.push_str(&format!("{} | {}\n", line_idx + 1, line));
|
result.push_str(&format!("{} | {}\n", line_idx + 1, line));
|
||||||
|
|
||||||
// Calculate column positions within the line
|
// Calculate column positions within the line
|
||||||
let line_start_col = error.span.start.saturating_sub(line_start);
|
let line_start_col = span.0.saturating_sub(line_start);
|
||||||
let line_end_col = (error.span.end - line_start).min(line.len());
|
let line_end_col = (span.1 - line_start).min(line.len());
|
||||||
|
|
||||||
// Print spaces and squiggly line for the span
|
// Print spaces and squiggly line for the span
|
||||||
result.push_str(&format!(
|
result.push_str(&format!(
|
||||||
"{} | ",
|
"{} | ",
|
||||||
" ".repeat((line_idx + 1).to_string().len())
|
" ".repeat((line_idx + 1).to_string().len())
|
||||||
));
|
));
|
||||||
for _ in 0..line_start_col {
|
for _ in 0..line_start_col {
|
||||||
result.push(' ');
|
result.push(' ');
|
||||||
|
}
|
||||||
|
for _ in line_start_col..line_end_col {
|
||||||
|
result.push('~');
|
||||||
|
}
|
||||||
|
result.push('\n');
|
||||||
|
|
||||||
|
// Print caret at the start position
|
||||||
|
result.push_str(&format!(
|
||||||
|
"{} | ",
|
||||||
|
" ".repeat((line_idx + 1).to_string().len())
|
||||||
|
));
|
||||||
|
for _ in 0..line_start_col {
|
||||||
|
result.push(' ');
|
||||||
|
}
|
||||||
|
result.push('^');
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_pos = line_end + 1; // +1 for the newline character
|
||||||
}
|
}
|
||||||
for _ in line_start_col..line_end_col {
|
|
||||||
result.push('~');
|
|
||||||
}
|
|
||||||
result.push('\n');
|
|
||||||
|
|
||||||
// Print caret at the start position
|
// Fallback if we can't find the line
|
||||||
result.push_str(&format!(
|
format!(
|
||||||
"{} | ",
|
"Parse error in {}: {} (at byte {})",
|
||||||
" ".repeat((line_idx + 1).to_string().len())
|
file, message, span.0
|
||||||
));
|
)
|
||||||
for _ in 0..line_start_col {
|
|
||||||
result.push(' ');
|
|
||||||
}
|
|
||||||
result.push('^');
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
_ => format!("Import error: {}", error),
|
||||||
current_pos = line_end + 1; // +1 for the newline character
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback if we can't find the line
|
|
||||||
format!(
|
|
||||||
"Parse error: {} (at byte {})",
|
|
||||||
error.message, error.span.start
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_type_error(source: &str, error: &suicmez::typechecker::TypeError) -> String {
|
fn format_type_error(source: &str, error: &suicmez::typechecker::TypeError) -> String {
|
||||||
|
|
@ -185,7 +195,16 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
|
||||||
let mut resolver = ImportResolver::new();
|
let mut resolver = ImportResolver::new();
|
||||||
let ast_nodes = resolver
|
let ast_nodes = resolver
|
||||||
.resolve(filename)
|
.resolve(filename)
|
||||||
.map_err(|e| format!("Import resolution error: {}", e))?;
|
.map_err(|e| {
|
||||||
|
if matches!(
|
||||||
|
e,
|
||||||
|
suicmez::import_resolver::ImportError::ParseError { .. }
|
||||||
|
) {
|
||||||
|
format_import_error(&e)
|
||||||
|
} else {
|
||||||
|
format!("Import resolution error: {}", e)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Import resolution complete! {} total nodes loaded",
|
"Import resolution complete! {} total nodes loaded",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue