lc3_ensemble/
err.rs

1//! Error interface for this crate.
2//! 
3//! This module creates an [`Error`] trait implemented by error types in this crate.
4//! 
5//! The error trait extends the standard library's [`std::error::Error`] type by
6//! adding a `help` method (to help assist the user in fixing the issue),
7//! and a `span` method (to point to where the error occurs).
8
9use std::borrow::Cow;
10
11use logos::Span;
12
13pub use crate::asm::AsmErr;
14pub use crate::ast::OffsetNewErr;
15pub use crate::parse::lex::LexErr;
16pub use crate::parse::ParseErr;
17pub use crate::sim::SimErr;
18
19/// Unified error interface for all errors in this crate.
20/// 
21/// Note that the [`Display`] implementation is used for a brief message,
22/// where as [`Error::help`] is used for any clarifying messages.
23/// 
24/// [`Display`]: std::fmt::Display
25pub trait Error: std::error::Error {
26    /// The range where this error occurs in source.
27    /// 
28    /// If this is not known, this can be set to `None`.
29    fn span(&self) -> Option<crate::err::ErrSpan> {
30        None
31    }
32
33    /// A clarifying message to help aid someone in how to fix the message.
34    /// 
35    /// If there is none to add, this can be set to `None`.
36    fn help(&self) -> Option<Cow<str>>;
37}
38
39/// The possible source ranges for an error. 
40/// 
41/// This can be:
42/// - one contiguous span,
43/// - two contiguous spans, or
44/// - three or more contiguous spans
45#[derive(Clone, PartialEq, Eq, Hash)]
46pub enum ErrSpan {
47    /// One contiguous span.
48    One(Span),
49    /// Two contiguous spans.
50    Two([Span; 2]),
51    /// Three or more contiguous spans.
52    /// 
53    /// This should always have at least 3 elements.
54    Many(Vec<Span>)
55}
56impl ErrSpan {
57    /// Gets the first span.
58    pub fn first(&self) -> Span {
59        match self {
60            ErrSpan::One(r)      => r.clone(),
61            ErrSpan::Two([r, _]) => r.clone(),
62            ErrSpan::Many(r)     => r.first().unwrap().clone(),
63        }
64    }
65
66    /// Gets an iterator over all of the spans.
67    pub fn iter(&self) -> impl Iterator<Item=&Span> {
68        match self {
69            ErrSpan::One(r)  => std::slice::from_ref(r).iter(),
70            ErrSpan::Two(r)  => r.iter(),
71            ErrSpan::Many(r) => r.iter(),
72        }
73    }
74}
75impl Extend<Span> for ErrSpan {
76    fn extend<T: IntoIterator<Item = Span>>(&mut self, iter: T) {
77        let mut iter = iter.into_iter();
78
79        // It's 4:30AM and I thought it'd be funny.
80        loop {
81            match self {
82                ErrSpan::One(r0) => {
83                    let Some(r1) = iter.next() else { return };
84                    let r0 = std::mem::replace(r0, 0..0);
85                    *self = ErrSpan::Two([r0, r1]);
86                },
87                ErrSpan::Two([r0, r1]) => {
88                    let Some(r2) = iter.next() else { return };
89                    let r0 = std::mem::replace(r0, 0..0);
90                    let r1 = std::mem::replace(r1, 0..0);
91                    *self = ErrSpan::Many(vec![r0, r1, r2]);
92                },
93                ErrSpan::Many(mr) => {
94                    mr.extend(iter);
95                    return;
96                },
97            }
98        }
99    }
100}
101impl From<Span> for ErrSpan {
102    fn from(value: Span) -> Self {
103        ErrSpan::One(value)
104    }
105}
106impl From<&[Span]> for ErrSpan {
107    fn from(value: &[Span]) -> Self {
108        match value {
109            [r0] => ErrSpan::One(r0.clone()),
110            [r0, r1] => ErrSpan::Two([r0.clone(), r1.clone()]),
111            rr => ErrSpan::Many(rr.to_vec())
112        }
113    }
114}
115impl<const N: usize> From<[Span; N]> for ErrSpan {
116    fn from(value: [Span; N]) -> Self {
117        Self::from(value.as_slice())
118    }
119}
120impl From<Vec<Span>> for ErrSpan {
121    fn from(value: Vec<Span>) -> Self {
122        match <[_; 1]>::try_from(value) {
123            Ok([r]) => ErrSpan::One(r),
124            Err(value) => match <[_; 2]>::try_from(value) {
125                Ok(r2) => ErrSpan::Two(r2),
126                Err(value) => ErrSpan::Many(value)
127            }
128        }
129    }
130}
131impl From<Vec<ErrSpan>> for ErrSpan {
132    fn from(value: Vec<ErrSpan>) -> Self {
133        let mr: Vec<_> = value.into_iter()
134            .flat_map(|r| match r {
135                ErrSpan::One(r) => vec![r],
136                ErrSpan::Two(r) => r.to_vec(),
137                ErrSpan::Many(r) => r,
138            })
139            .collect();
140
141        ErrSpan::from(mr)
142    }
143}
144impl std::fmt::Debug for ErrSpan {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        match self {
147            Self::One(r)   => r.fmt(f),
148            Self::Two(r)   => r.fmt(f),
149            Self::Many(mr) => mr.fmt(f),
150        }
151    }
152}