diff --git a/src/import_resolver.rs b/src/import_resolver.rs index 7852dc3..47a63ba 100644 --- a/src/import_resolver.rs +++ b/src/import_resolver.rs @@ -27,6 +27,7 @@ pub enum ImportError { file: String, message: String, span: (usize, usize), + source: String, }, CircularDependency { files: Vec, @@ -56,6 +57,7 @@ impl std::fmt::Display for ImportError { file, message, span, + source: _, } => { write!( f, @@ -170,12 +172,14 @@ impl ImportResolver { fn parse_tokens( tokens: Vec<(Token, logos::Span)>, filename: String, + source: String, ) -> Result, ImportError> { let mut parser = Parser::new(filename.clone(), tokens); parser.parse().map_err(|e| ImportError::ParseError { file: filename, message: e.message.clone(), span: (e.span.start, e.span.end), + source, }) } @@ -199,7 +203,7 @@ impl ImportResolver { // Parse the file println!(" [parsing] {}", 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 self.parse_cache.insert( diff --git a/src/main.rs b/src/main.rs index cd17113..fe23aa1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,63 +64,73 @@ fn run_test_suite() { } } -fn format_parse_error(source: &str, error: &suicmez::parser::ParseError) -> String { - // Find the line containing the error - let lines: Vec<&str> = source.lines().collect(); - let mut current_pos = 0; +fn format_import_error(error: &suicmez::import_resolver::ImportError) -> String { + match error { + suicmez::import_resolver::ImportError::ParseError { + 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() { - let line_start = current_pos; - let line_end = current_pos + line.len(); + for (line_idx, line) in lines.iter().enumerate() { + let line_start = current_pos; + let line_end = current_pos + line.len(); - // Check if the error span intersects with this line - if error.span.start < line_end && error.span.end > line_start { - let mut result = String::new(); + // Check if the error span intersects with this line + if span.0 < line_end && span.1 > line_start { + let mut result = String::new(); - // Print the error message - result.push_str(&format!("Parse error: {}\n", error.message)); + // Print the error message + result.push_str(&format!("Parse error in {}: {}\n", file, message)); - // Print the line number and content - result.push_str(&format!("{} | {}\n", line_idx + 1, line)); + // Print the line number and content + result.push_str(&format!("{} | {}\n", line_idx + 1, line)); - // Calculate column positions within the line - let line_start_col = error.span.start.saturating_sub(line_start); - let line_end_col = (error.span.end - line_start).min(line.len()); + // Calculate column positions within the line + let line_start_col = span.0.saturating_sub(line_start); + let line_end_col = (span.1 - line_start).min(line.len()); - // Print spaces and squiggly line for the span - result.push_str(&format!( - "{} | ", - " ".repeat((line_idx + 1).to_string().len()) - )); - for _ in 0..line_start_col { - result.push(' '); + // Print spaces and squiggly line for the span + result.push_str(&format!( + "{} | ", + " ".repeat((line_idx + 1).to_string().len()) + )); + for _ in 0..line_start_col { + 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 - result.push_str(&format!( - "{} | ", - " ".repeat((line_idx + 1).to_string().len()) - )); - for _ in 0..line_start_col { - result.push(' '); - } - result.push('^'); - - return result; + // Fallback if we can't find the line + format!( + "Parse error in {}: {} (at byte {})", + file, message, span.0 + ) } - - current_pos = line_end + 1; // +1 for the newline character + _ => format!("Import error: {}", error), } - - // 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 { @@ -185,7 +195,16 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> { let mut resolver = ImportResolver::new(); let ast_nodes = resolver .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!( "Import resolution complete! {} total nodes loaded",