scheme_rs/
error.rs

1use crate::{
2    compile::CompileError,
3    continuation::Continuation,
4    gc::Gc,
5    syntax::{Identifier, Span},
6    value::Value,
7};
8use derivative::Derivative;
9use std::sync::Arc;
10
11// TODO: Rename this to condition to more accurately reflect its purpose
12#[derive(Debug, Clone)]
13pub struct RuntimeError {
14    pub backtrace: Vec<Frame>,
15    pub kind: RuntimeErrorKind,
16}
17
18#[derive(Derivative)]
19#[derivative(Debug, Clone)]
20pub enum RuntimeErrorKind {
21    UndefinedVariable(Identifier),
22    InvalidType {
23        expected: String,
24        provided: String,
25    },
26    InvalidOperatorType {
27        provided: String,
28    },
29    WrongNumberOfArguments {
30        expected: usize,
31        provided: usize,
32    },
33    AssertEqFailed {
34        expected: String,
35        actual: String,
36    },
37    DivisionByZero,
38    CompileError(CompileError),
39    AbandonCurrentContinuation {
40        #[derivative(Debug = "ignore")]
41        args: Vec<Gc<Value>>,
42        #[derivative(Debug = "ignore")]
43        new_cont: Option<Arc<Continuation>>,
44    },
45    NoPatternsMatch,
46    Condition {
47        // TODO
48    },
49}
50
51#[derive(Debug, Clone)]
52pub struct Frame {
53    pub proc: String,
54    pub span: Span,
55    pub repeated: usize,
56}
57
58impl Frame {
59    pub fn new(proc: String, span: Span) -> Self {
60        Self {
61            proc,
62            span,
63            repeated: 0,
64        }
65    }
66}
67
68impl RuntimeError {
69    pub fn push_frame(&mut self, proc: String, span: Span) {
70        match self.backtrace.last_mut() {
71            Some(last_frame) if last_frame.span == span && last_frame.proc == proc => {
72                last_frame.repeated += 1
73            }
74            _ => self.backtrace.push(Frame::new(proc, span)),
75        }
76    }
77
78    pub fn abandon_current_continuation(
79        args: Vec<Gc<Value>>,
80        new_cont: Option<Arc<Continuation>>,
81    ) -> Self {
82        Self {
83            backtrace: Vec::new(),
84            kind: RuntimeErrorKind::AbandonCurrentContinuation { args, new_cont },
85        }
86    }
87
88    pub fn division_by_zero() -> Self {
89        Self {
90            backtrace: Vec::new(),
91            kind: RuntimeErrorKind::DivisionByZero,
92        }
93    }
94
95    pub fn assert_eq_failed(expected: &str, actual: &str) -> Self {
96        let expected = expected.to_string();
97        let actual = actual.to_string();
98        Self {
99            backtrace: Vec::new(),
100            kind: RuntimeErrorKind::AssertEqFailed { expected, actual },
101        }
102    }
103
104    pub fn undefined_variable(ident: Identifier) -> Self {
105        Self {
106            backtrace: Vec::new(),
107            kind: RuntimeErrorKind::UndefinedVariable(ident),
108        }
109    }
110
111    pub fn invalid_type(expected: &str, provided: &str) -> Self {
112        let expected = expected.to_string();
113        let provided = provided.to_string();
114        Self {
115            backtrace: Vec::new(),
116            kind: RuntimeErrorKind::InvalidType { expected, provided },
117        }
118    }
119
120    pub fn invalid_operator_type(provided: &str) -> Self {
121        let provided = provided.to_string();
122        Self {
123            backtrace: Vec::new(),
124            kind: RuntimeErrorKind::InvalidOperatorType { provided },
125        }
126    }
127
128    pub fn wrong_num_of_args(expected: usize, provided: usize) -> Self {
129        Self {
130            backtrace: Vec::new(),
131            kind: RuntimeErrorKind::WrongNumberOfArguments { expected, provided },
132        }
133    }
134
135    pub fn no_patterns_match() -> Self {
136        Self {
137            backtrace: Vec::new(),
138            kind: RuntimeErrorKind::NoPatternsMatch,
139        }
140    }
141}
142
143impl From<CompileError> for RuntimeError {
144    fn from(ce: CompileError) -> Self {
145        Self {
146            backtrace: Vec::new(),
147            kind: RuntimeErrorKind::CompileError(ce),
148        }
149    }
150}
151
152/*
153impl fmt::Debug for RuntimeError {
154    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        todo!()
156    }
157}
158*/