1use crate::{ComplexType, Value};
2use espy_heart::debug;
3use std::num::NonZero;
4
5#[must_use]
6pub struct Error {
7 absolute_program_counter: Option<NonZero<u32>>,
13 kind: ErrorKind,
14}
15
16impl Error {
17 pub fn kind(&self) -> &ErrorKind {
18 &self.kind
19 }
20
21 pub fn into_kind(self) -> ErrorKind {
22 self.kind
23 }
24
25 pub fn suggest_location(self, absolute_program_counter: usize) -> Self {
26 Self {
27 absolute_program_counter: self.absolute_program_counter.or_else(|| {
28 u32::try_from(absolute_program_counter)
29 .ok()?
30 .try_into()
31 .ok()
32 }),
33 ..self
34 }
35 }
36
37 pub fn locate(&self, debug_info: &[u8]) -> Result<Option<(usize, usize)>, DebugInfoError> {
48 let Some(absolute_program_counter) = self.absolute_program_counter.map(|x| {
49 u32::from(x)
50 .try_into()
51 .expect("program counter should not exceed usize")
52 }) else {
53 return Ok(None);
54 };
55 let mut this_pc = 0;
56 let mut last_span = None;
57 let mut debug_info = debug_info.iter().copied();
58 while let Some(directive) = debug_info.next() {
59 match directive {
60 debug::SPAN => {
61 let mut get_u64 = || {
62 let mut unpacked = [0; size_of::<u64>()];
63 for dest in unpacked.iter_mut().take(debug_info.next()? as usize) {
64 *dest = debug_info.next()?;
65 }
66 Some(u64::from_le_bytes(unpacked))
67 };
68 let start = get_u64().ok_or(DebugInfoError {
69 kind: DebugInfoErrorKind::UnexpectedEndOfSequence,
70 })?;
71 let end = get_u64().ok_or(DebugInfoError {
72 kind: DebugInfoErrorKind::UnexpectedEndOfSequence,
73 })?;
74 last_span = Some((start, end));
75 this_pc += 1;
76 }
77 debug::DITTO => {
78 this_pc += debug_info.next().ok_or(DebugInfoError {
79 kind: DebugInfoErrorKind::UnexpectedEndOfSequence,
80 })? as usize;
81 }
82 _ => {
83 return Err(DebugInfoError {
84 kind: DebugInfoErrorKind::UnknownDirective,
85 });
86 }
87 }
88 if this_pc > absolute_program_counter {
89 return Ok(last_span.map(|(start, end)| (start as usize, end as usize)));
90 }
91 }
92 Err(DebugInfoError {
93 kind: DebugInfoErrorKind::UnexpectedEndOfSequence,
94 })
95 }
96}
97
98impl std::fmt::Display for Error {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 self.kind.fmt(f)
101 }
102}
103
104impl std::fmt::Debug for Error {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 self.kind.fmt(f)
107 }
108}
109
110impl std::error::Error for Error {}
111
112impl Error {
113 pub fn type_error(value: &Value, ty: &ComplexType) -> Self {
114 ErrorKind::TypeError {
115 value: format!("{value:?}").into_boxed_str(),
116 ty: format!("{:?}", ty).into_boxed_str(),
117 }
118 .into()
119 }
120
121 pub fn index_not_found(container: &Value, index: &Value) -> Self {
122 ErrorKind::IndexNotFound {
123 index: format!("{index:?}").into_boxed_str(),
124 container: format!("{container:?}").into_boxed_str(),
125 }
126 .into()
127 }
128
129 pub fn expected_integers(l: &Value, r: &Value) -> Self {
130 ErrorKind::ExpectedIntegers(
131 format!("{l:?}").into_boxed_str(),
132 format!("{r:?}").into_boxed_str(),
133 )
134 .into()
135 }
136
137 pub fn expected_tuple(i: &Value) -> Self {
138 ErrorKind::ExpectedTuple(format!("{i:?}").into_boxed_str()).into()
139 }
140
141 pub fn expected_named_tuple(i: &Value) -> Self {
142 ErrorKind::ExpectedNamedTuple(format!("{i:?}").into_boxed_str()).into()
143 }
144
145 pub fn expected_function(function: &Value) -> Self {
146 ErrorKind::ExpectedFunction(format!("{function:?}").into_boxed_str()).into()
147 }
148
149 pub fn incomparable_values(l: &Value, r: &Value) -> Self {
150 ErrorKind::IncomparableValues(
151 format!("{l:?}").into_boxed_str(),
152 format!("{r:?}").into_boxed_str(),
153 )
154 .into()
155 }
156
157 pub fn expected_enum_variant(i: &Value) -> Error {
158 ErrorKind::ExpectedEnumVariant(format!("{i:?}").into_boxed_str()).into()
159 }
160
161 pub fn expected_enum_type(i: &Value) -> Error {
162 ErrorKind::ExpectedEnumType(format!("{i:?}").into_boxed_str()).into()
163 }
164
165 pub fn expected_option(i: &Value) -> Error {
166 ErrorKind::ExpectedOption(format!("{i:?}").into_boxed_str()).into()
167 }
168
169 pub fn expected_reference(i: &Value) -> Error {
170 ErrorKind::ExpectedReference(format!("{i:?}").into_boxed_str()).into()
171 }
172
173 pub fn other(e: impl Into<anyhow::Error>) -> Error {
174 ErrorKind::Other(e.into()).into()
175 }
176
177 pub fn custom(message: &'static str) -> Error {
178 ErrorKind::Other(anyhow::Error::msg(message)).into()
179 }
180}
181
182impl From<ErrorKind> for Error {
183 fn from(kind: ErrorKind) -> Self {
184 Self {
185 absolute_program_counter: None,
186 kind,
187 }
188 }
189}
190
191impl From<anyhow::Error> for Error {
192 fn from(e: anyhow::Error) -> Error {
193 Error::other(e)
194 }
195}
196
197#[derive(Debug)]
198#[non_exhaustive]
199#[must_use]
200pub enum ErrorKind {
201 ExpectedIntegers(Box<str>, Box<str>),
202 ExpectedFunction(Box<str>),
203 ExpectedEnumVariant(Box<str>),
204 ExpectedOption(Box<str>),
205 ExpectedEnumType(Box<str>),
206 ExpectedTuple(Box<str>),
207 ExpectedNamedTuple(Box<str>),
208 ExpectedReference(Box<str>),
209
210 IncomparableValues(Box<str>, Box<str>),
211 TypeError {
212 value: Box<str>,
213 ty: Box<str>,
214 },
215 CalledNeverFunction,
216 IndexNotFound {
217 index: Box<str>,
218 container: Box<str>,
219 },
220 OutOfScopeMut,
221 InvalidBytecode(InvalidBytecode),
222
223 Other(anyhow::Error),
224}
225
226impl std::fmt::Display for ErrorKind {
227 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228 match self {
229 ErrorKind::ExpectedIntegers(l, r) => {
230 write!(f, "expected two integers, got {l} and {r}")
231 }
232 ErrorKind::ExpectedFunction(i) => write!(f, "expected a function, got {i}"),
233 ErrorKind::ExpectedEnumVariant(i) => write!(f, "expected an enum variant, got {i}"),
234 ErrorKind::ExpectedOption(i) => write!(f, "expected an option, got {i}"),
235 ErrorKind::ExpectedEnumType(i) => write!(f, "expected an enum, got {i}"),
236 ErrorKind::ExpectedTuple(i) => write!(f, "expected a tuple or named tuple, got {i}"),
237 ErrorKind::ExpectedNamedTuple(i) => write!(f, "expected a named tuple, got {i}"),
238 ErrorKind::ExpectedReference(i) => write!(f, "expected a reference type, got {i}"),
239 ErrorKind::IncomparableValues(l, r) => write!(f, "{l} cannot be compared to {r}"),
240 ErrorKind::TypeError { value, ty } => {
241 write!(f, "expected a value of type {ty}, got {value}")
242 }
243 ErrorKind::CalledNeverFunction => write!(f, "attempted to call a \"never\" function"),
244 ErrorKind::IndexNotFound { index, container } => {
245 write!(f, "{container} does not contain the field {index}")
246 }
247 ErrorKind::OutOfScopeMut => write!(
248 f,
249 "attempted to read or write a mutable value which has gone out of scope"
250 ),
251 ErrorKind::InvalidBytecode(invalid_bytecode) => {
252 write!(f, "invalid bytecode: {invalid_bytecode}")
253 }
254 ErrorKind::Other(error) => error.fmt(f),
255 }
256 }
257}
258
259#[derive(Debug)]
264pub enum InvalidBytecode {
265 StackUnderflow,
269 InvalidInstruction,
271 InvalidBuiltin,
273 InvalidStringId,
275 MalformedHeader,
278 ProgramOutOfBounds,
283 StackOutOfBounds,
285 Utf8Error(std::str::Utf8Error),
286}
287
288impl From<InvalidBytecode> for Error {
289 fn from(e: InvalidBytecode) -> Error {
290 Error {
291 absolute_program_counter: None,
292 kind: ErrorKind::InvalidBytecode(e),
293 }
294 }
295}
296
297impl std::fmt::Display for InvalidBytecode {
298 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299 match self {
300 InvalidBytecode::StackUnderflow => write!(f, "stack underflow"),
301 InvalidBytecode::InvalidInstruction => write!(f, "invalid instruction"),
302 InvalidBytecode::InvalidBuiltin => write!(f, "invalid builtin"),
303 InvalidBytecode::InvalidStringId => write!(f, "unexpected string id"),
304 InvalidBytecode::MalformedHeader => write!(f, "malformed header"),
305 InvalidBytecode::ProgramOutOfBounds => write!(f, "program out of bounds"),
306 InvalidBytecode::StackOutOfBounds => write!(f, "stack out of bounds"),
307 InvalidBytecode::Utf8Error(utf8_error) => utf8_error.fmt(f),
308 }
309 }
310}
311
312#[derive(Debug)]
313pub struct DebugInfoError {
314 kind: DebugInfoErrorKind,
315}
316
317impl std::fmt::Display for DebugInfoError {
318 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319 use DebugInfoErrorKind as Kind;
320 match &self.kind {
321 Kind::UnexpectedEndOfSequence => write!(f, "unexpected end of sequence"),
322 Kind::UnknownDirective => write!(f, "unknown directive"),
323 }
324 }
325}
326
327#[derive(Debug)]
328pub enum DebugInfoErrorKind {
329 UnexpectedEndOfSequence,
330 UnknownDirective,
331}