From ef70bc1cc0847a01af5e07b32b89cafbce358c76 Mon Sep 17 00:00:00 2001 From: Araozu Date: Tue, 2 Jan 2024 06:31:27 -0500 Subject: [PATCH] Minimal error display for syntax error --- CHANGELOG.md | 4 ++-- src/error_handling/syntax_error.rs | 33 +++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e76821..e9c1219 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,8 +24,8 @@ - [x] Hand-make CLI, remove clap - [x] Compile a single file -- [ ] Display error messages during compilation instead of panicking -- [ ] Improve errror messages +- [x] Display error messages during compilation instead of panicking +- [x] Improve error messages - [ ] Implement code generation for ast nodes implemented as of now diff --git a/src/error_handling/syntax_error.rs b/src/error_handling/syntax_error.rs index 656a298..b7a846d 100644 --- a/src/error_handling/syntax_error.rs +++ b/src/error_handling/syntax_error.rs @@ -1,22 +1,29 @@ -use std::collections::VecDeque; - use super::{PrintableError, SyntaxError}; +use std::collections::VecDeque; impl PrintableError for SyntaxError { fn get_error_str(&self, chars: &Vec) -> String { let (line, before, length) = get_line(chars, self.error_start, self.error_end); + let line_number = get_line_number(chars, self.error_start); + let line_number_whitespace = " ".repeat(line_number.to_string().len()); + let whitespace = vec![' '; before].iter().collect::(); let indicator = vec!['^'; length].iter().collect::(); + let reason = &self.reason; format!( - "\n{}\n{}{}\n\n{}{}{}\n{}", - line, whitespace, indicator, "Syntax error at pos ", self.error_start, ":", self.reason + r#" +{line_number_whitespace} | +{line_number } | {line} +{line_number_whitespace} | {whitespace}{indicator} + +{reason} at line {line_number}:{before}"#, ) } } -/// Extracts a lin e of code +/// Extracts a line of code /// /// - `chars`: Input where to extract the line from /// - `start_position`: Position where the erroneous code starts @@ -90,6 +97,22 @@ fn get_line( ) } +fn get_line_number(chars: &Vec, target_pos: usize) -> usize { + let mut count = 1; + + for (pos, char) in chars.iter().enumerate() { + if pos >= target_pos { + break; + } + + if *char == '\n' { + count += 1; + } + } + + count +} + #[cfg(test)] mod tests { use super::*;