cl_interpret/
error.rs

1//! The [Error] type represents any error thrown by the [Environment](super::Environment)
2
3use cl_ast::{Pattern, Sym};
4use cl_structures::span::Span;
5
6use super::{convalue::ConValue, env::Place};
7
8pub type IResult<T> = Result<T, Error>;
9
10#[derive(Clone, Debug)]
11pub struct Error {
12    pub kind: ErrorKind,
13    span: Option<Span>,
14}
15
16impl Error {
17    #![allow(non_snake_case)]
18
19    /// Adds a [struct Span] to this [Error], if there isn't already a more specific one.
20    pub fn with_span(self, span: Span) -> Self {
21        Self { span: self.span.or(Some(span)), ..self }
22    }
23
24    pub fn kind(&self) -> &ErrorKind {
25        &self.kind
26    }
27
28    /// Propagate a Return value
29    pub fn Return(value: ConValue) -> Self {
30        Self { kind: ErrorKind::Return(value), span: None }
31    }
32    /// Propagate a Break value
33    pub fn Break(value: ConValue) -> Self {
34        Self { kind: ErrorKind::Break(value), span: None }
35    }
36    /// Break propagated across function bounds
37    pub fn BadBreak(value: ConValue) -> Self {
38        Self { kind: ErrorKind::BadBreak(value), span: None }
39    }
40    /// Continue to the next iteration of a loop
41    pub fn Continue() -> Self {
42        Self { kind: ErrorKind::Continue, span: None }
43    }
44    /// Underflowed the stack
45    pub fn StackUnderflow() -> Self {
46        Self { kind: ErrorKind::StackUnderflow, span: None }
47    }
48    /// Overflowed the stack
49    pub fn StackOverflow(place: Place) -> Self {
50        Self { kind: ErrorKind::StackOverflow(place), span: None }
51    }
52    /// Exited the last scope
53    pub fn ScopeExit() -> Self {
54        Self { kind: ErrorKind::ScopeExit, span: None }
55    }
56    /// Type incompatibility
57    // TODO: store the type information in this error
58    pub fn TypeError() -> Self {
59        Self { kind: ErrorKind::TypeError, span: None }
60    }
61    /// In clause of For loop didn't yield a Range
62    pub fn NotIterable() -> Self {
63        Self { kind: ErrorKind::NotIterable, span: None }
64    }
65    /// A value could not be indexed
66    pub fn NotIndexable() -> Self {
67        Self { kind: ErrorKind::NotIndexable, span: None }
68    }
69    /// An array index went out of bounds
70    pub fn OobIndex(index: usize, length: usize) -> Self {
71        Self { kind: ErrorKind::OobIndex(index, length), span: None }
72    }
73    /// An expression is not assignable
74    pub fn NotAssignable() -> Self {
75        Self { kind: ErrorKind::NotAssignable, span: None }
76    }
77    /// A name was not defined in scope before being used
78    pub fn NotDefined(name: Sym) -> Self {
79        Self { kind: ErrorKind::NotDefined(name), span: None }
80    }
81    /// A name was defined but not initialized
82    pub fn NotInitialized(name: Sym) -> Self {
83        Self { kind: ErrorKind::NotInitialized(name), span: None }
84    }
85    /// A value was called, but is not callable
86    pub fn NotCallable(value: ConValue) -> Self {
87        Self { kind: ErrorKind::NotCallable(value), span: None }
88    }
89    /// A function was called with the wrong number of arguments
90    pub fn ArgNumber(want: usize, got: usize) -> Self {
91        Self { kind: ErrorKind::ArgNumber { want, got }, span: None }
92    }
93    /// A pattern failed to match
94    pub fn PatFailed(pat: Box<Pattern>) -> Self {
95        Self { kind: ErrorKind::PatFailed(pat), span: None }
96    }
97    /// Fell through a non-exhaustive match
98    pub fn MatchNonexhaustive() -> Self {
99        Self { kind: ErrorKind::MatchNonexhaustive, span: None }
100    }
101    /// Error produced by a Builtin
102    pub fn BuiltinError(msg: String) -> Self {
103        Self { kind: ErrorKind::BuiltinError(msg), span: None }
104    }
105}
106
107impl std::error::Error for Error {}
108impl std::fmt::Display for Error {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        let Self { kind, span } = self;
111        if let Some(Span { head, tail }) = span {
112            write!(f, "{head}..{tail}: ")?;
113        }
114        write!(f, "{kind}")
115    }
116}
117
118/// Represents any error thrown by the [Environment](super::Environment)
119#[derive(Clone, Debug)]
120pub enum ErrorKind {
121    /// Propagate a Return value
122    Return(ConValue),
123    /// Propagate a Break value
124    Break(ConValue),
125    /// Break propagated across function bounds
126    BadBreak(ConValue),
127    /// Continue to the next iteration of a loop
128    Continue,
129    /// Underflowed the stack
130    StackUnderflow,
131    /// Overflowed the stack
132    StackOverflow(Place),
133    /// Exited the last scope
134    ScopeExit,
135    /// Type incompatibility
136    // TODO: store the type information in this error
137    TypeError,
138    /// In clause of For loop didn't yield a Range
139    NotIterable,
140    /// A value could not be indexed
141    NotIndexable,
142    /// An array index went out of bounds
143    OobIndex(usize, usize),
144    /// An expression is not assignable
145    NotAssignable,
146    /// A name was not defined in scope before being used
147    NotDefined(Sym),
148    /// A name was defined but not initialized
149    NotInitialized(Sym),
150    /// A value was called, but is not callable
151    NotCallable(ConValue),
152    /// A function was called with the wrong number of arguments
153    ArgNumber { want: usize, got: usize },
154    /// A pattern failed to match
155    PatFailed(Box<Pattern>),
156    /// Fell through a non-exhaustive match
157    MatchNonexhaustive,
158    /// Error produced by a Builtin
159    BuiltinError(String),
160}
161
162impl std::error::Error for ErrorKind {}
163impl std::fmt::Display for ErrorKind {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        match self {
166            ErrorKind::Return(value) => write!(f, "return {value}"),
167            ErrorKind::Break(value) => write!(f, "break {value}"),
168            ErrorKind::BadBreak(value) => write!(f, "rogue break: {value}"),
169            ErrorKind::Continue => "continue".fmt(f),
170            ErrorKind::StackUnderflow => "Stack underflow".fmt(f),
171            ErrorKind::StackOverflow(id) => {
172                write!(f, "Attempt to access <{id}> resulted in stack overflow.")
173            }
174            ErrorKind::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
175            ErrorKind::TypeError => "Incompatible types".fmt(f),
176            ErrorKind::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
177            ErrorKind::NotIndexable => {
178                write!(f, "expression cannot be indexed")
179            }
180            ErrorKind::OobIndex(idx, len) => {
181                write!(f, "Index out of bounds: index was {idx}. but len is {len}")
182            }
183            ErrorKind::NotAssignable => {
184                write!(f, "expression is not assignable")
185            }
186            ErrorKind::NotDefined(value) => {
187                write!(f, "{value} not bound. Did you mean `let {value};`?")
188            }
189            ErrorKind::NotInitialized(value) => {
190                write!(f, "{value} bound, but not initialized")
191            }
192            ErrorKind::NotCallable(value) => {
193                write!(f, "{value} is not callable.")
194            }
195            ErrorKind::ArgNumber { want, got } => {
196                write!(
197                    f,
198                    "Expected {want} argument{}, got {got}",
199                    if *want == 1 { "" } else { "s" }
200                )
201            }
202            ErrorKind::PatFailed(pattern) => {
203                write!(f, "Failed to match pattern {pattern}")
204            }
205            ErrorKind::MatchNonexhaustive => {
206                write!(f, "Fell through a non-exhaustive match expression!")
207            }
208            ErrorKind::BuiltinError(s) => write!(f, "{s}"),
209        }
210    }
211}