1use core::fmt;
4
5use arithmetic_parser::{Location, Spanned, UnsupportedType};
6
7pub use self::{
8 kind::{ErrorKind, TupleContext},
9 op_errors::OpErrors,
10 path::ErrorPathFragment,
11};
12use crate::{
13 alloc::{vec, ToOwned, Vec},
14 arith::{BinaryOpContext, UnaryOpContext},
15 ast::AstConversionError,
16 visit::VisitMut,
17 PrimitiveType, Tuple, Type,
18};
19
20mod kind;
21mod op_errors;
22mod path;
23
24#[derive(Debug, Clone)]
26pub struct Error<Prim: PrimitiveType> {
27 inner: Location<ErrorKind<Prim>>,
28 root_location: Location,
29 context: ErrorContext<Prim>,
30 path: Vec<ErrorPathFragment>,
31}
32
33impl<Prim: PrimitiveType> fmt::Display for Error<Prim> {
34 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(
36 formatter,
37 "{}:{}: {}",
38 self.main_location().location_line(),
39 self.main_location().get_column(),
40 self.kind()
41 )
42 }
43}
44
45#[cfg(feature = "std")]
46impl<Prim: PrimitiveType> std::error::Error for Error<Prim> {
47 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
48 Some(self.kind())
49 }
50}
51
52impl<Prim: PrimitiveType> Error<Prim> {
53 pub(crate) fn unsupported<T>(
54 unsupported: impl Into<UnsupportedType>,
55 span: &Spanned<'_, T>,
56 ) -> Self {
57 let kind = ErrorKind::unsupported(unsupported);
58 Self {
59 inner: span.copy_with_extra(kind).into(),
60 root_location: span.with_no_extra().into(),
61 context: ErrorContext::None,
62 path: Vec::new(),
63 }
64 }
65
66 pub(crate) fn undefined_var<T>(span: &Spanned<'_, T>) -> Self {
67 let ident = (*span.fragment()).to_owned();
68 Self {
69 inner: span.copy_with_extra(ErrorKind::UndefinedVar(ident)).into(),
70 root_location: span.with_no_extra().into(),
71 context: ErrorContext::None,
72 path: Vec::new(),
73 }
74 }
75
76 pub(crate) fn repeated_assignment(span: Spanned<'_>) -> Self {
77 let ident = (*span.fragment()).to_owned();
78 Self {
79 inner: span
80 .copy_with_extra(ErrorKind::RepeatedAssignment(ident))
81 .into(),
82 root_location: span.with_no_extra().into(),
83 context: ErrorContext::None,
84 path: Vec::new(),
85 }
86 }
87
88 pub(crate) fn repeated_field(span: Spanned<'_>) -> Self {
89 let ident = (*span.fragment()).to_owned();
90 Self {
91 inner: span.copy_with_extra(ErrorKind::RepeatedField(ident)).into(),
92 root_location: span.with_no_extra().into(),
93 context: ErrorContext::None,
94 path: Vec::new(),
95 }
96 }
97
98 pub(crate) fn conversion<T>(kind: AstConversionError, span: &Spanned<'_, T>) -> Self {
99 let kind = ErrorKind::AstConversion(kind);
100 Self {
101 inner: span.copy_with_extra(kind).into(),
102 root_location: span.with_no_extra().into(),
103 context: ErrorContext::None,
104 path: Vec::new(),
105 }
106 }
107
108 pub(crate) fn invalid_field_name(span: Spanned<'_>) -> Self {
109 let ident = (*span.fragment()).to_owned();
110 Self {
111 inner: span
112 .copy_with_extra(ErrorKind::InvalidFieldName(ident))
113 .into(),
114 root_location: span.into(),
115 context: ErrorContext::None,
116 path: Vec::new(),
117 }
118 }
119
120 pub(crate) fn index_out_of_bounds<T>(
121 receiver: Tuple<Prim>,
122 span: &Spanned<'_, T>,
123 index: usize,
124 ) -> Self {
125 Self {
126 inner: span
127 .copy_with_extra(ErrorKind::IndexOutOfBounds {
128 index,
129 len: receiver.len(),
130 })
131 .into(),
132 root_location: span.with_no_extra().into(),
133 context: ErrorContext::TupleIndex {
134 ty: Type::Tuple(receiver),
135 },
136 path: Vec::new(),
137 }
138 }
139
140 pub(crate) fn cannot_index<T>(receiver: Type<Prim>, span: &Spanned<'_, T>) -> Self {
141 Self {
142 inner: span.copy_with_extra(ErrorKind::CannotIndex).into(),
143 root_location: span.with_no_extra().into(),
144 context: ErrorContext::TupleIndex { ty: receiver },
145 path: Vec::new(),
146 }
147 }
148
149 pub(crate) fn unsupported_index<T>(receiver: Type<Prim>, span: &Spanned<'_, T>) -> Self {
150 Self {
151 inner: span.copy_with_extra(ErrorKind::UnsupportedIndex).into(),
152 root_location: span.with_no_extra().into(),
153 context: ErrorContext::TupleIndex { ty: receiver },
154 path: Vec::new(),
155 }
156 }
157
158 pub fn kind(&self) -> &ErrorKind<Prim> {
160 &self.inner.extra
161 }
162
163 pub fn main_location(&self) -> Location {
165 self.inner.with_no_extra()
166 }
167
168 pub fn root_location(&self) -> Location {
170 self.root_location
171 }
172
173 pub fn context(&self) -> &ErrorContext<Prim> {
175 &self.context
176 }
177
178 pub fn path(&self) -> &[ErrorPathFragment] {
181 &self.path
182 }
183}
184
185#[derive(Debug, Clone)]
214pub struct Errors<Prim: PrimitiveType> {
215 inner: Vec<Error<Prim>>,
216 first_failing_statement: usize,
217}
218
219impl<Prim: PrimitiveType> Errors<Prim> {
220 pub(crate) fn new() -> Self {
221 Self {
222 inner: Vec::new(),
223 first_failing_statement: 0,
224 }
225 }
226
227 pub(crate) fn push(&mut self, err: Error<Prim>) {
228 self.inner.push(err);
229 }
230
231 pub(crate) fn extend(&mut self, errors: Vec<Error<Prim>>) {
232 self.inner.extend(errors);
233 }
234
235 pub fn len(&self) -> usize {
237 self.inner.len()
238 }
239
240 pub fn is_empty(&self) -> bool {
242 self.inner.is_empty()
243 }
244
245 pub fn iter(&self) -> impl Iterator<Item = &Error<Prim>> + '_ {
247 self.inner.iter()
248 }
249
250 pub fn first_failing_statement(&self) -> usize {
254 self.first_failing_statement
255 }
256
257 pub(crate) fn set_first_failing_statement(&mut self, index: usize) {
258 self.first_failing_statement = index;
259 }
260
261 pub(crate) fn post_process(&mut self, type_resolver: &mut impl VisitMut<Prim>) {
264 for error in &mut self.inner {
265 error.context.map_types(type_resolver);
266 }
267 }
268}
269
270impl<Prim: PrimitiveType> fmt::Display for Errors<Prim> {
271 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
272 for (i, error) in self.inner.iter().enumerate() {
273 write!(formatter, "{error}")?;
274 if i + 1 < self.inner.len() {
275 formatter.write_str("\n")?;
276 }
277 }
278 Ok(())
279 }
280}
281
282#[cfg(feature = "std")]
283impl<Prim: PrimitiveType> std::error::Error for Errors<Prim> {}
284
285impl<Prim: PrimitiveType> IntoIterator for Errors<Prim> {
286 type Item = Error<Prim>;
287 type IntoIter = vec::IntoIter<Self::Item>;
288
289 fn into_iter(self) -> Self::IntoIter {
290 self.inner.into_iter()
291 }
292}
293
294#[derive(Debug, Clone)]
298#[non_exhaustive]
299pub enum ErrorContext<Prim: PrimitiveType> {
300 None,
302 Lvalue(Type<Prim>),
304 FnDefinition {
306 args: Tuple<Prim>,
308 },
309 FnCall {
311 definition: Type<Prim>,
313 call_signature: Type<Prim>,
315 },
316 Assignment {
318 lhs: Type<Prim>,
320 rhs: Type<Prim>,
322 },
323 TypeCast {
325 source: Type<Prim>,
327 target: Type<Prim>,
329 },
330 UnaryOp(UnaryOpContext<Prim>),
332 BinaryOp(BinaryOpContext<Prim>),
334 TupleIndex {
336 ty: Type<Prim>,
338 },
339 ObjectFieldAccess {
341 ty: Type<Prim>,
343 },
344}
345
346impl<Prim: PrimitiveType> From<UnaryOpContext<Prim>> for ErrorContext<Prim> {
347 fn from(value: UnaryOpContext<Prim>) -> Self {
348 Self::UnaryOp(value)
349 }
350}
351
352impl<Prim: PrimitiveType> From<BinaryOpContext<Prim>> for ErrorContext<Prim> {
353 fn from(value: BinaryOpContext<Prim>) -> Self {
354 Self::BinaryOp(value)
355 }
356}
357
358impl<Prim: PrimitiveType> ErrorContext<Prim> {
359 fn map_types(&mut self, mapper: &mut impl VisitMut<Prim>) {
360 match self {
361 Self::None => { }
362 Self::Lvalue(lvalue) => mapper.visit_type_mut(lvalue),
363 Self::FnDefinition { args } => mapper.visit_tuple_mut(args),
364 Self::FnCall {
365 definition,
366 call_signature,
367 } => {
368 mapper.visit_type_mut(definition);
369 mapper.visit_type_mut(call_signature);
370 }
371 Self::Assignment { lhs, rhs } | Self::BinaryOp(BinaryOpContext { lhs, rhs, .. }) => {
372 mapper.visit_type_mut(lhs);
373 mapper.visit_type_mut(rhs);
374 }
375 Self::TypeCast { source, target } => {
376 mapper.visit_type_mut(source);
377 mapper.visit_type_mut(target);
378 }
379 Self::UnaryOp(UnaryOpContext { arg, .. }) => {
380 mapper.visit_type_mut(arg);
381 }
382 Self::TupleIndex { ty } | Self::ObjectFieldAccess { ty } => {
383 mapper.visit_type_mut(ty);
384 }
385 }
386 }
387}