1use std::fmt::{self, Display, Formatter};
2
3#[derive(Debug)]
4pub enum ErrorSource {
5 Internal,
6 Builtin(String),
7 Line(usize),
8 File(String),
9}
10
11#[derive(Debug)]
12pub struct Error {
13 trace: Vec<ErrorSource>,
14 msg: String,
15}
16
17impl Error {
18 pub fn new(msg: &str, source: ErrorSource) -> Self {
19 Self {
20 msg: String::from(msg),
21 trace: vec![source],
22 }
23 }
24
25 pub fn get_source(&self) -> String {
26 let mut ln = None;
27 let mut file = None;
28 for source in &self.trace {
29 match source {
30 ErrorSource::Line(line) => {
31 if ln.is_none() {
32 ln = Some(line)
33 }
34 }
35 ErrorSource::File(path) => {
36 if file.is_none() {
37 file = Some(path)
38 }
39 }
40 _ => (),
41 }
42 if ln.is_some() && file.is_some() {
43 break;
44 }
45 }
46 format!("{}:{}", file.unwrap_or(&String::from("input")), ln.unwrap())
47 }
48}
49
50impl Display for Error {
51 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
52 f.write_str(&self.msg)?;
53 f.write_fmt(format_args!(
54 "\n\x1b[36m->\x1b[0m {}\x1b[3m",
55 self.get_source()
56 ))?;
57 for source in &self.trace {
58 match source {
59 ErrorSource::Internal => (),
60 ErrorSource::Builtin(name) => {
61 f.write_str("\n\t")?;
62 f.write_fmt(format_args!("(builtin {})", name))?
63 }
64 ErrorSource::Line(ln) => {
65 f.write_str("\n\t")?;
66 f.write_fmt(format_args!("(line {})", ln))?;
67 }
68 ErrorSource::File(path) => {
69 f.write_str("\n\t")?;
70 f.write_fmt(format_args!("(file {})", path))?
71 }
72 }
73 }
74 f.write_str("\x1b[0m")?;
75 Ok(())
76 }
77}
78
79pub trait BeanResult {
80 fn trace(self, source: ErrorSource) -> Self;
81}
82
83impl<T> BeanResult for Result<T, Error> {
84 fn trace(mut self, source: ErrorSource) -> Self {
85 if let Err(error) = &mut self {
86 error.trace.push(source)
87 }
88 self
89 }
90}
91
92impl BeanResult for Error {
93 fn trace(mut self, source: ErrorSource) -> Self {
94 self.trace.push(source);
95 self
96 }
97}