rocks_lang/
error.rs

1use crate::object::Object;
2use crate::token::{Token, Type, Location};
3
4static mut HAD_ERROR: bool = false;
5static mut HAD_RUNTIME_ERROR: bool = false;
6
7/// Checks if an error occurred during scanning, parsing, or interpreting.
8pub fn did_error() -> bool {
9    unsafe { HAD_ERROR || HAD_RUNTIME_ERROR }
10}
11
12/// Checks if an error occurred during runtime.
13pub fn did_runtime_error() -> bool {
14    unsafe { HAD_RUNTIME_ERROR }
15}
16
17/// Resets the error flag.
18/// This is used to reset the interpreter after an error occurs when running prompts.
19pub fn reset_error() {
20    unsafe {
21        HAD_ERROR = false;
22        HAD_RUNTIME_ERROR = false;
23    }
24}
25
26/// Every error type must implement this trait.
27pub trait Error {
28    /// Prints the error message and sets the error flag.
29    fn throw(&self);
30}
31
32/// Represents an error that occurs during scanning.
33#[derive(Debug)]
34pub struct ScanError {
35    pub location: Location,
36    pub message: String,
37}
38
39impl Error for ScanError {
40    fn throw(&self) {
41        eprintln!(
42            "[line {line}:{column}] Error: {message}",
43            line = self.location.line + 1,
44            column = self.location.column + 1,
45            message = self.message
46        );
47
48        unsafe {
49            HAD_ERROR = true;
50        }
51    }
52}
53
54/// Represents an error that occurs during parsing.
55#[derive(Debug)]
56pub struct ParseError {
57    pub token: Token,
58    pub message: String,
59}
60
61impl Error for ParseError {
62    fn throw(&self) {
63        if self.token.r#type == Type::EOF {
64            eprintln!(
65                "[line {line}:{column}] Error at end: {message}",
66                line = self.token.location.line + 1,
67                column = self.token.location.column + 1,
68                message = self.message
69            );
70        } else {
71            eprintln!(
72                "[line {line}:{column}] Error at '{lexeme}': {message}",
73                line = self.token.location.line + 1,
74                column = self.token.location.column + 1,
75                lexeme = self.token.lexeme,
76                message = self.message
77            );
78        }
79
80        unsafe {
81            HAD_ERROR = true;
82        }
83    }
84}
85
86/// Represents an error that occurs during resolution.
87#[derive(Debug)]
88pub struct ResolveError {
89    pub token: Token,
90    pub message: String,
91}
92
93impl Error for ResolveError {
94    fn throw(&self) {
95        eprintln!(
96            "[line {line}:{column}] Error at '{lexeme}': {message}",
97            line = self.token.location.line + 1,
98            column = self.token.location.column + 1,
99            lexeme = self.token.lexeme,
100            message = self.message
101        );
102
103        unsafe {
104            HAD_ERROR = true;
105        }
106    }
107}
108
109/// Represents an error that occurs during runtime.
110#[derive(Debug)]
111pub struct RuntimeError {
112    pub token: Token,
113    pub message: String,
114}
115
116impl Error for RuntimeError {
117    fn throw(&self) {
118        eprintln!(
119            "[line {line}:{column}] Error at '{lexeme}': {message}",
120            line = self.token.location.line + 1,
121            column = self.token.location.column + 1,
122            lexeme = self.token.lexeme,
123            message = self.message
124        );
125
126        unsafe {
127            HAD_RUNTIME_ERROR = true;
128        }
129    }
130}
131
132/// This error is thrown when a return statement is executed. Since errors are propagated up the
133/// execution stack, the interpreter can catch it and return the value of the return statement.
134#[derive(Debug)]
135pub struct ReturnError {
136    pub value: Object,
137}
138
139/// This error is thrown when a break statement is executed. Since errors are propagated up the
140/// execution stack, the interpreter can catch it and break out of the current loop.
141#[derive(Debug)]
142pub struct BreakError;
143
144/// Represents a special error that is caught by the interpreter.
145#[derive(Debug)]
146pub enum ReturnType {
147    Error(RuntimeError),
148    Return(ReturnError),
149    Break(BreakError),
150}