1use cl_ast::{Pat, types::Symbol};
4use cl_structures::span::Span;
5
6use super::convalue::ConValue;
7
8pub type IResult<T> = Result<T, Error>;
9
10#[derive(Clone, Debug)]
11pub struct Error {
12 pub kind: ErrorKind,
13 pub(super) span: Option<Span>,
14}
15
16impl Error {
17 #![allow(non_snake_case)]
18
19 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 pub fn Return(value: ConValue) -> Self {
30 Self { kind: ErrorKind::Return(value), span: None }
31 }
32 pub fn Break(value: ConValue) -> Self {
34 Self { kind: ErrorKind::Break(value), span: None }
35 }
36 pub fn BadBreak(value: ConValue) -> Self {
38 Self { kind: ErrorKind::BadBreak(value), span: None }
39 }
40 pub fn Continue() -> Self {
42 Self { kind: ErrorKind::Continue, span: None }
43 }
44 pub fn StackUnderflow() -> Self {
46 Self { kind: ErrorKind::StackUnderflow, span: None }
47 }
48 pub fn StackOverflow(place: usize) -> Self {
50 Self { kind: ErrorKind::StackOverflow(place), span: None }
51 }
52 pub fn ScopeExit() -> Self {
54 Self { kind: ErrorKind::ScopeExit, span: None }
55 }
56 pub fn TypeError(want: &'static str, got: &'static str) -> Self {
59 Self { kind: ErrorKind::TypeError(want, got), span: None }
60 }
61 pub fn NotIterable() -> Self {
63 Self { kind: ErrorKind::NotIterable, span: None }
64 }
65 pub fn NotIndexable() -> Self {
67 Self { kind: ErrorKind::NotIndexable, span: None }
68 }
69 pub fn OobIndex(index: usize, length: usize) -> Self {
71 Self { kind: ErrorKind::OobIndex(index, length), span: None }
72 }
73 pub fn NotPlace() -> Self {
75 Self { kind: ErrorKind::NotPlace, span: None }
76 }
77 pub fn NotDefined(name: Symbol) -> Self {
79 Self { kind: ErrorKind::NotDefined(name), span: None }
80 }
81 pub fn NotInitialized(name: Symbol) -> Self {
83 Self { kind: ErrorKind::NotInitialized(name), span: None }
84 }
85 pub fn NotCallable(value: ConValue) -> Self {
87 Self { kind: ErrorKind::NotCallable(value), span: None }
88 }
89 pub fn ArgNumber(want: usize, got: usize) -> Self {
91 Self { kind: ErrorKind::ArgNumber { want, got }, span: None }
92 }
93 pub fn PatFailed(pat: Box<Pat>) -> Self {
95 Self { kind: ErrorKind::PatFailed(pat), span: None }
96 }
97 pub fn MatchNonexhaustive() -> Self {
99 Self { kind: ErrorKind::MatchNonexhaustive, span: None }
100 }
101 pub fn Panic(msg: String) -> Self {
103 Self { kind: ErrorKind::Panic(msg, 0), span: None }
104 }
105 pub fn BuiltinError(msg: String) -> Self {
107 Self { kind: ErrorKind::BuiltinError(msg), span: None }
108 }
109}
110
111impl std::error::Error for Error {}
112impl std::fmt::Display for Error {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 let Self { kind, span } = self;
115 if let Some(Span { path, head, tail }) = span {
116 write!(f, "{path}:{head}..{tail}: ")?;
117 }
118 write!(f, "{kind}")
119 }
120}
121
122#[derive(Clone, Debug)]
124pub enum ErrorKind {
125 Return(ConValue),
127 Break(ConValue),
129 BadBreak(ConValue),
131 Continue,
133 StackUnderflow,
135 StackOverflow(usize),
137 ScopeExit,
139 TypeError(&'static str, &'static str),
142 NotIterable,
144 NotIndexable,
146 OobIndex(usize, usize),
148 NotPlace,
150 NotDefined(Symbol),
152 NotInitialized(Symbol),
154 NotCallable(ConValue),
156 ArgNumber { want: usize, got: usize },
158 PatFailed(Box<Pat>),
160 MatchNonexhaustive,
162 Panic(String, usize),
164 BuiltinError(String),
166}
167
168impl std::error::Error for ErrorKind {}
169impl std::fmt::Display for ErrorKind {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 match self {
172 ErrorKind::Return(value) => write!(f, "return {value}"),
173 ErrorKind::Break(value) => write!(f, "break {value}"),
174 ErrorKind::BadBreak(value) => write!(f, "rogue break: {value}"),
175 ErrorKind::Continue => "continue".fmt(f),
176 ErrorKind::StackUnderflow => "Stack underflow".fmt(f),
177 ErrorKind::StackOverflow(id) => {
178 write!(f, "Attempt to access <{id}> resulted in stack overflow.")
179 }
180 ErrorKind::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
181 ErrorKind::TypeError(want, got) => {
182 write!(f, "Incompatible types: wanted {want}, got {got}")
183 }
184 ErrorKind::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
185 ErrorKind::NotIndexable => {
186 write!(f, "expression cannot be indexed")
187 }
188 ErrorKind::OobIndex(idx, len) => {
189 write!(f, "Index out of bounds: index was {idx}. but len is {len}")
190 }
191 ErrorKind::NotPlace => {
192 write!(f, "expression does not refer to a place")
193 }
194 ErrorKind::NotDefined(value) => {
195 write!(f, "{value} not bound.")
196 }
197 ErrorKind::NotInitialized(value) => {
198 write!(f, "{value} bound, but not initialized")
199 }
200 ErrorKind::NotCallable(value) => {
201 write!(f, "{value} is not callable.")
202 }
203 ErrorKind::ArgNumber { want, got } => {
204 write!(
205 f,
206 "Expected {want} argument{}, got {got}",
207 if *want == 1 { "" } else { "s" }
208 )
209 }
210 ErrorKind::PatFailed(pattern) => {
211 write!(f, "Failed to match pattern {pattern}")
212 }
213 ErrorKind::MatchNonexhaustive => {
214 write!(f, "Fell through a non-exhaustive match expression!")
215 }
216 ErrorKind::Panic(s, _depth) => write!(f, "{s}"),
217 ErrorKind::BuiltinError(s) => write!(f, "{s}"),
218 }
219 }
220}