1use ariadne::Fmt;
2use cas_attrs::ErrorKind;
3use cas_error::EXPR;
4use cas_parser::parser::token::op::{BinOpKind, UnaryOpKind};
5use std::ops::Range;
6
7#[derive(Debug, Clone, ErrorKind, PartialEq)]
9#[error(
10 message = format!("cannot apply the `{:?}` operator to these operands", self.op),
11 labels = [
12 format!("this operand has type `{}`", self.left),
13 format!("this {}operator", if self.implicit { "(implicit) " } else { "" }),
14 format!("this operand has type `{}`", self.right),
15 ],
16)]
17pub struct InvalidBinaryOperation {
18 pub op: BinOpKind,
20
21 pub implicit: bool,
23
24 pub left: &'static str,
26
27 pub right: &'static str,
29}
30
31#[derive(Debug, Clone, ErrorKind, PartialEq)]
33#[error(
34 message = format!("cannot apply the `{:?}` operator to this operand", self.op),
35 labels = [
36 format!("this operand has type `{}`", self.expr_type),
37 "this operator".to_string(),
38 ],
39)]
40pub struct InvalidUnaryOperation {
41 pub op: UnaryOpKind,
43
44 pub expr_type: &'static str,
46}
47
48#[derive(Debug, Clone, ErrorKind, PartialEq)]
50#[error(
51 message = "maximum bitshift amount exceeded",
52 labels = ["this expression", "", "too many bits to shift by"],
53 help = "the maximum number of bits you can shift an integer by is equal to: `2^64 - 1`"
54)]
55pub struct BitshiftOverflow;
56
57#[derive(Debug, Clone, ErrorKind, PartialEq)]
59#[error(
60 message = format!(
61 "cannot differentiate `{}` function using prime notation",
62 self.name
63 ),
64 labels = ["this function"],
65 help = format!("only functions with a *single parameter* can be differentiated using prime notation; the `{}` function has {} parameter(s)", (&self.name).fg(EXPR), self.actual),
66 note = "consider partially applying the function (i.e. `f(x) = log(x, 2)`) to make it differentiable",
67)]
68pub struct InvalidDifferentiation {
69 pub name: String,
71
72 pub actual: usize,
74}
75
76#[derive(Debug, Clone, ErrorKind, PartialEq)]
78#[error(
79 message = format!("too many arguments given to the `{}` function", self.name),
80 labels = ["this function call", "", "these argument(s) are extraneous"],
81 help = format!(
82 "the `{}` function takes {} argument(s); there are {} argument(s) provided here",
83 (&self.name).fg(EXPR),
84 self.expected,
85 self.given
86 ),
87 note = format!("function signature: `{}`", self.signature),
88)]
89pub struct TooManyArguments {
90 pub name: String,
92
93 pub expected: usize,
95
96 pub given: usize,
98
99 pub signature: String,
101}
102
103impl From<cas_compute::numerical::builtin::error::TooManyArguments> for TooManyArguments {
104 fn from(err: cas_compute::numerical::builtin::error::TooManyArguments) -> Self {
105 Self {
106 name: err.name.to_string(),
107 expected: err.expected,
108 given: err.given,
109 signature: err.signature.to_string(),
110 }
111 }
112}
113
114#[derive(Debug, Clone, ErrorKind, PartialEq)]
116#[error(
117 message = if self.indices.start + 1 == self.indices.end { format!("missing required argument #{} for the `{}` function", self.indices.start + 1, self.name)
119 } else {
120 format!(
121 "missing required arguments {} for the `{}` function",
122 self.indices
123 .clone()
124 .map(|i| format!("#{}", i + 1))
125 .collect::<Vec<_>>()
126 .join(", "),
127 self.name
128 )
129 },
130 labels = ["this function call", ""],
131 help = format!(
132 "the `{}` function takes {} argument(s); there are {} argument(s) provided here",
133 (&self.name).fg(EXPR),
134 self.expected,
135 self.given
136 ),
137 note = format!("function signature: `{}`", self.signature),
138)]
139pub struct MissingArgument {
140 pub name: String,
142
143 pub indices: Range<usize>,
145
146 pub expected: usize,
148
149 pub given: usize,
151
152 pub signature: String,
154}
155
156impl From<cas_compute::numerical::builtin::error::MissingArgument> for MissingArgument {
157 fn from(err: cas_compute::numerical::builtin::error::MissingArgument) -> Self {
158 Self {
159 name: err.name.to_string(),
160 indices: err.indices,
161 expected: err.expected,
162 given: err.given,
163 signature: err.signature.to_string(),
164 }
165 }
166}
167
168#[derive(Debug, Clone, ErrorKind, PartialEq)]
170#[error(
171 message = format!(
172 "incorrect type for argument #{} for the `{}` function",
173 self.index + 1,
174 self.name
175 ),
176 labels = [
177 "this function call".to_string(),
178 "".to_string(),
179 format!("this argument has type `{}`", self.given),
180 ],
181 help = format!("must be of type `{}`", self.expected),
182 note = format!("function signature: `{}`", self.signature),
183)]
184pub struct TypeMismatch {
185 pub name: &'static str,
187
188 pub index: usize,
190
191 pub expected: &'static str,
193
194 pub given: &'static str,
196
197 pub signature: &'static str,
199}
200
201impl From<cas_compute::numerical::builtin::error::TypeMismatch> for TypeMismatch {
202 fn from(err: cas_compute::numerical::builtin::error::TypeMismatch) -> Self {
203 Self {
204 name: err.name,
205 index: err.index,
206 expected: err.expected,
207 given: err.given,
208 signature: err.signature,
209 }
210 }
211}
212
213#[derive(Debug, Clone, ErrorKind, PartialEq)]
215#[error(
216 message = "maximum stack depth exceeded",
217 labels = ["stack overflowed when executing this function call", ""],
218 help = "stack overflows occur when I have to keep track of too many function calls at once",
219 note = "the maximum stack depth is equal to: `2^16`",
221)]
222pub struct StackOverflow;
223
224
225#[derive(Debug, Clone, ErrorKind, PartialEq)]
227#[error(
228 message = "encountered a non-numeric type while differentiating this function",
229 labels = [
230 format!("during evaluation, this call evaluated to a `{}`", self.expr_type),
231 "".to_string(),
232 ],
233 help = "derivatives are evaluated numerically using the limit definition of a derivative; this can cause an error when evaluating near undefined points of the function"
234)]
235pub struct NonNumericDerivative {
236 pub expr_type: &'static str,
238}
239
240#[derive(Debug, Clone, ErrorKind, PartialEq)]
242#[error(
243 message = "cannot index into this type",
244 labels = [format!("this expression evaluated to `{}`", self.expr_type)],
245 help = "only lists can be indexed into",
246)]
247pub struct InvalidIndexTarget {
248 pub expr_type: &'static str,
250}
251
252#[derive(Debug, Clone, ErrorKind, PartialEq)]
254#[error(
255 message = "list index must be an integer",
256 labels = [
257 "for this list".to_string(),
258 format!("this expression evaluated to `{}`", self.expr_type),
259 ],
260)]
261pub struct InvalidIndexType {
262 pub expr_type: &'static str,
264}
265
266#[derive(Debug, Clone, ErrorKind, PartialEq)]
268#[error(
269 message = "list index is out of valid range",
270 labels = ["for this list", "out of range"],
271 help = "the index must be positive and less than or equal to: `2^64 - 1`"
272)]
273pub struct IndexOutOfRange;
274
275#[derive(Debug, Clone, ErrorKind, PartialEq)]
277#[error(
278 message = "list index is out of bounds",
279 labels = ["for this list".to_string(), format!("out of bounds (tried to index: {})", self.index)],
280 help = match self.len {
281 0 => "list is empty, so all indexing operations will fail".to_string(),
282 1 => "list has length `1`, so the index must be `0`".to_string(),
283 n => format!("list has length `{}`, so the index must be between `0-{}` (inclusive)", n, n - 1),
284 }
285)]
286pub struct IndexOutOfBounds {
287 pub len: usize,
289
290 pub index: usize,
292}
293
294#[derive(Debug, Clone, ErrorKind, PartialEq)]
296#[error(
297 message = "length of list must be an integer",
298 labels = [format!("this expression evaluated to `{}`", self.expr_type)],
299)]
300pub struct InvalidLengthType {
301 pub expr_type: &'static str,
303}
304
305#[derive(Debug, Clone, ErrorKind, PartialEq)]
307#[error(
308 message = "length of list is out of valid range",
309 labels = ["out of range"],
310 help = "the length must be positive and less than or equal to: `2^64 - 1`"
311)]
312pub struct LengthOutOfRange;
313
314#[derive(Debug, Clone, ErrorKind, PartialEq)]
316#[error(
317 message = "conditional expression must evaluate to a boolean...",
318 labels = [
319 "...used to determine whether to run this code".to_string(),
320 format!("this expression evaluated to `{}`", self.expr_type),
321 ],
322 help = "consider using the `bool()` function to convert the expression to a boolean based on \"truthiness\"",
323)]
324pub struct ConditionalNotBoolean {
325 pub expr_type: &'static str,
327}
328
329#[derive(Debug, Clone, ErrorKind, PartialEq)]
331#[error(
332 message = format!("an internal error occurred at instruction: `{:#?}`", self.instruction),
333 labels = spans.iter()
334 .enumerate()
335 .map(|(idx, span)| format!("{}: `{}..{}`", idx, span.start, span.end)),
336 help = "please copy your code and this error message and report them to the developer",
337 note = &self.data,
338)]
339pub struct InternalError {
340 pub instruction: String,
344
345 pub data: String,
347}