about summary refs log tree commit diff
path: root/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/error.rs')
-rw-r--r--src/error.rs80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..7493681
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,80 @@
+use crate::{interpret::walker::WalkerError, lex::token::Location, parse::parser::ParserError};
+use colored::Colorize;
+use std::fmt::Display;
+pub struct RHError {
+    pub at: ErrorLocation,
+    pub kind: RHErrorKind,
+}
+
+impl RHError {
+    pub fn hydrate_source<'s>(self, source: &'s str) -> RHErrorWithSource<'s> {
+        RHErrorWithSource {
+            error: self,
+            source,
+        }
+    }
+}
+
+pub enum RHErrorKind {
+    Parse(ParserError),
+    Run(WalkerError),
+}
+
+pub enum ErrorLocation {
+    Specific(Location),
+    Eof,
+}
+
+pub struct RHErrorWithSource<'source> {
+    error: RHError,
+    source: &'source str,
+}
+
+impl Display for RHErrorWithSource<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let (error_title, error_string) = match &self.error.kind {
+            RHErrorKind::Parse(parser_error) => (
+                "Encountered error during parsing",
+                format!("{}", parser_error),
+            ),
+            RHErrorKind::Run(walker_error) => {
+                ("Encountered runtime error", format!("{}", walker_error))
+            }
+        };
+
+        let weird_source_error_msg =
+            "Found error but could not get it's location in source, how does this even happen?";
+
+        let (line_number, line_column, source_line) = match self.error.at {
+            ErrorLocation::Specific(location) => (
+                location.row,
+                location.col,
+                self.source
+                    .lines()
+                    .nth(location.row)
+                    .expect(weird_source_error_msg),
+            ),
+            ErrorLocation::Eof => {
+                let lines = self.source.lines();
+                let (line_count, _) = lines.size_hint();
+                let last_line = lines.last().expect(weird_source_error_msg);
+
+                (line_count, last_line.len(), last_line)
+            }
+        };
+
+        let arrow_pad_len = line_column + 3 + line_number.to_string().len();
+
+        writeln!(f, "{} {}:\n", " Error ".on_red(), error_title)?;
+        writeln!(
+            f,
+            "{}{}",
+            format!("{} | ", line_number).dimmed(),
+            source_line
+        )?;
+        writeln!(f, "{}{}", " ".repeat(arrow_pad_len), "^".red())?;
+        writeln!(f, "{}", error_string)?;
+
+        Ok(())
+    }
+}