lc3_ensemble/
err.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! Error interface for this crate.
//! 
//! This module creates an [`Error`] trait implemented by error types in this crate.
//! 
//! The error trait extends the standard library's [`std::error::Error`] type by
//! adding a `help` method (to help assist the user in fixing the issue),
//! and a `span` method (to point to where the error occurs).

use std::borrow::Cow;

use logos::Span;

pub use crate::asm::AsmErr;
pub use crate::ast::OffsetNewErr;
pub use crate::parse::lex::LexErr;
pub use crate::parse::ParseErr;
pub use crate::sim::SimErr;

/// Unified error interface for all errors in this crate.
/// 
/// Note that the [`Display`] implementation is used for a brief message,
/// where as [`Error::help`] is used for any clarifying messages.
/// 
/// [`Display`]: std::fmt::Display
pub trait Error: std::error::Error {
    /// The range where this error occurs in source.
    /// 
    /// If this is not known, this can be set to `None`.
    fn span(&self) -> Option<crate::err::ErrSpan> {
        None
    }

    /// A clarifying message to help aid someone in how to fix the message.
    /// 
    /// If there is none to add, this can be set to `None`.
    fn help(&self) -> Option<Cow<str>>;
}

/// The possible source ranges for an error. 
/// 
/// This can be:
/// - one contiguous span,
/// - two contiguous spans, or
/// - three or more contiguous spans
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ErrSpan {
    /// One contiguous span.
    One(Span),
    /// Two contiguous spans.
    Two([Span; 2]),
    /// Three or more contiguous spans.
    /// 
    /// This should always have at least 3 elements.
    Many(Vec<Span>)
}
impl ErrSpan {
    /// Gets the first span.
    pub fn first(&self) -> Span {
        match self {
            ErrSpan::One(r)      => r.clone(),
            ErrSpan::Two([r, _]) => r.clone(),
            ErrSpan::Many(r)     => r.first().unwrap().clone(),
        }
    }

    /// Gets an iterator over all of the spans.
    pub fn iter(&self) -> impl Iterator<Item=&Span> {
        match self {
            ErrSpan::One(r)  => std::slice::from_ref(r).iter(),
            ErrSpan::Two(r)  => r.iter(),
            ErrSpan::Many(r) => r.iter(),
        }
    }
}
impl Extend<Span> for ErrSpan {
    fn extend<T: IntoIterator<Item = Span>>(&mut self, iter: T) {
        let mut iter = iter.into_iter();

        // It's 4:30AM and I thought it'd be funny.
        loop {
            match self {
                ErrSpan::One(r0) => {
                    let Some(r1) = iter.next() else { return };
                    let r0 = std::mem::replace(r0, 0..0);
                    *self = ErrSpan::Two([r0, r1]);
                },
                ErrSpan::Two([r0, r1]) => {
                    let Some(r2) = iter.next() else { return };
                    let r0 = std::mem::replace(r0, 0..0);
                    let r1 = std::mem::replace(r1, 0..0);
                    *self = ErrSpan::Many(vec![r0, r1, r2]);
                },
                ErrSpan::Many(mr) => {
                    mr.extend(iter);
                    return;
                },
            }
        }
    }
}
impl From<Span> for ErrSpan {
    fn from(value: Span) -> Self {
        ErrSpan::One(value)
    }
}
impl From<[Span; 2]> for ErrSpan {
    fn from(value: [Span; 2]) -> Self {
        ErrSpan::Two(value)
    }
}
impl From<Vec<Span>> for ErrSpan {
    fn from(value: Vec<Span>) -> Self {
        match Box::<[_; 1]>::try_from(value) {
            Ok(rbox) => {
                let [r] = *rbox;
                ErrSpan::One(r)
            },
            Err(value) => match Box::try_from(value) {
                Ok(rbox) => ErrSpan::Two(*rbox),
                Err(value) => ErrSpan::Many(value)
            }
        }
    }
}
impl From<Vec<ErrSpan>> for ErrSpan {
    fn from(value: Vec<ErrSpan>) -> Self {
        let mr: Vec<_> = value.into_iter()
            .flat_map(|r| match r {
                ErrSpan::One(r) => vec![r],
                ErrSpan::Two(r) => r.to_vec(),
                ErrSpan::Many(r) => r,
            })
            .collect();

        ErrSpan::from(mr)
    }
}
impl std::fmt::Debug for ErrSpan {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::One(r)   => r.fmt(f),
            Self::Two(r)   => r.fmt(f),
            Self::Many(mr) => mr.fmt(f),
        }
    }
}