Skip to main content

cl_interpret/
error.rs

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