1use thiserror::Error;
2#[derive(Debug, Clone, PartialEq, Eq)]
3pub struct StackFrame {
4 pub function: String,
5 pub line: usize,
6 pub ip: usize,
7}
8
9impl StackFrame {
10 pub fn new(function: impl Into<String>, line: usize, ip: usize) -> Self {
11 Self {
12 function: function.into(),
13 line,
14 ip,
15 }
16 }
17}
18
19#[derive(Error, Debug, Clone, PartialEq)]
20pub enum LustError {
21 #[error("Lexer error at line {line}, column {column}: {message}")]
22 LexerError {
23 line: usize,
24 column: usize,
25 message: String,
26 module: Option<String>,
27 },
28 #[error("Parser error at line {line}, column {column}: {message}")]
29 ParserError {
30 line: usize,
31 column: usize,
32 message: String,
33 module: Option<String>,
34 },
35 #[error("Type error: {message}")]
36 TypeError { message: String },
37 #[error("Type error at line {line}, column {column}: {message}")]
38 TypeErrorWithSpan {
39 message: String,
40 line: usize,
41 column: usize,
42 module: Option<String>,
43 },
44 #[error("Compile error: {0}")]
45 CompileError(String),
46 #[error("Compile error at line {line}, column {column}: {message}")]
47 CompileErrorWithSpan {
48 message: String,
49 line: usize,
50 column: usize,
51 module: Option<String>,
52 },
53 #[error("Runtime error: {message}")]
54 RuntimeError { message: String },
55 #[error(
56 "Runtime error at line {line} in {function}: {message}\n{}",
57 format_stack_trace(stack_trace)
58 )]
59 RuntimeErrorWithTrace {
60 message: String,
61 function: String,
62 line: usize,
63 stack_trace: Vec<StackFrame>,
64 },
65 #[error("Unknown error: {0}")]
66 Unknown(String),
67}
68
69fn format_stack_trace(frames: &[StackFrame]) -> String {
70 if frames.is_empty() {
71 return String::new();
72 }
73
74 let mut output = String::from("Stack trace:\n");
75 for (i, frame) in frames.iter().enumerate() {
76 output.push_str(&format!(
77 " [{}] {} (line {})\n",
78 i, frame.function, frame.line
79 ));
80 }
81
82 output
83}
84
85pub type Result<T> = std::result::Result<T, LustError>;