1use std::fmt;
4
5use crate::{
6 arith::{BinaryOpContext, UnaryOpContext},
7 ast::AstConversionError,
8 visit::VisitMut,
9 PrimitiveType, Tuple, Type,
10};
11use arithmetic_parser::{Spanned, UnsupportedType};
12
13mod kind;
14mod location;
15mod op_errors;
16
17pub use self::{
18 kind::{ErrorKind, TupleContext},
19 location::ErrorLocation,
20 op_errors::OpErrors,
21};
22
23#[derive(Debug, Clone)]
26pub struct Error<'a, Prim: PrimitiveType> {
27 inner: Spanned<'a, ErrorKind<Prim>>,
28 root_span: Spanned<'a>,
29 context: ErrorContext<Prim>,
30 location: Vec<ErrorLocation>,
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_span().location_line(),
39 self.main_span().get_column(),
40 self.kind()
41 )
42 }
43}
44
45impl<Prim: PrimitiveType> std::error::Error for Error<'_, Prim> {
46 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
47 Some(self.kind())
48 }
49}
50
51impl<'a, Prim: PrimitiveType> Error<'a, Prim> {
52 pub(crate) fn unsupported<T>(
53 unsupported: impl Into<UnsupportedType>,
54 span: &Spanned<'a, T>,
55 ) -> Self {
56 let kind = ErrorKind::unsupported(unsupported);
57 Self {
58 inner: span.copy_with_extra(kind),
59 root_span: span.with_no_extra(),
60 context: ErrorContext::None,
61 location: vec![],
62 }
63 }
64
65 pub(crate) fn undefined_var<T>(span: &Spanned<'a, T>) -> Self {
66 let ident = (*span.fragment()).to_owned();
67 Self {
68 inner: span.copy_with_extra(ErrorKind::UndefinedVar(ident)),
69 root_span: span.with_no_extra(),
70 context: ErrorContext::None,
71 location: vec![],
72 }
73 }
74
75 pub(crate) fn repeated_assignment(span: Spanned<'a>) -> Self {
76 let ident = (*span.fragment()).to_owned();
77 Self {
78 inner: span.copy_with_extra(ErrorKind::RepeatedAssignment(ident)),
79 root_span: span.with_no_extra(),
80 context: ErrorContext::None,
81 location: vec![],
82 }
83 }
84
85 pub(crate) fn repeated_field(span: Spanned<'a>) -> Self {
86 let ident = (*span.fragment()).to_owned();
87 Self {
88 inner: span.copy_with_extra(ErrorKind::RepeatedField(ident)),
89 root_span: span.with_no_extra(),
90 context: ErrorContext::None,
91 location: vec![],
92 }
93 }
94
95 pub(crate) fn conversion<T>(kind: AstConversionError, span: &Spanned<'a, T>) -> Self {
96 let kind = ErrorKind::AstConversion(kind);
97 Self {
98 inner: span.copy_with_extra(kind),
99 root_span: span.with_no_extra(),
100 context: ErrorContext::None,
101 location: vec![],
102 }
103 }
104
105 pub(crate) fn invalid_field_name(span: Spanned<'a>) -> Self {
106 let ident = (*span.fragment()).to_owned();
107 Self {
108 inner: span.copy_with_extra(ErrorKind::InvalidFieldName(ident)),
109 root_span: span,
110 context: ErrorContext::None,
111 location: vec![],
112 }
113 }
114
115 pub(crate) fn index_out_of_bounds<T>(
116 receiver: Tuple<Prim>,
117 span: &Spanned<'a, T>,
118 index: usize,
119 ) -> Self {
120 Self {
121 inner: span.copy_with_extra(ErrorKind::IndexOutOfBounds {
122 index,
123 len: receiver.len(),
124 }),
125 root_span: span.with_no_extra(),
126 context: ErrorContext::TupleIndex {
127 ty: Type::Tuple(receiver),
128 },
129 location: vec![],
130 }
131 }
132
133 pub(crate) fn cannot_index<T>(receiver: Type<Prim>, span: &Spanned<'a, T>) -> Self {
134 Self {
135 inner: span.copy_with_extra(ErrorKind::CannotIndex),
136 root_span: span.with_no_extra(),
137 context: ErrorContext::TupleIndex { ty: receiver },
138 location: vec![],
139 }
140 }
141
142 pub(crate) fn unsupported_index<T>(receiver: Type<Prim>, span: &Spanned<'a, T>) -> Self {
143 Self {
144 inner: span.copy_with_extra(ErrorKind::UnsupportedIndex),
145 root_span: span.with_no_extra(),
146 context: ErrorContext::TupleIndex { ty: receiver },
147 location: vec![],
148 }
149 }
150
151 pub fn kind(&self) -> &ErrorKind<Prim> {
153 &self.inner.extra
154 }
155
156 pub fn main_span(&self) -> Spanned<'a> {
158 self.inner.with_no_extra()
159 }
160
161 pub fn root_span(&self) -> Spanned<'a> {
163 self.root_span
164 }
165
166 pub fn context(&self) -> &ErrorContext<Prim> {
168 &self.context
169 }
170
171 pub fn location(&self) -> &[ErrorLocation] {
174 &self.location
175 }
176}
177
178#[derive(Debug, Clone)]
207pub struct Errors<'a, Prim: PrimitiveType> {
208 inner: Vec<Error<'a, Prim>>,
209 first_failing_statement: usize,
210}
211
212impl<'a, Prim: PrimitiveType> Errors<'a, Prim> {
213 pub(crate) fn new() -> Self {
214 Self {
215 inner: vec![],
216 first_failing_statement: 0,
217 }
218 }
219
220 pub(crate) fn push(&mut self, err: Error<'a, Prim>) {
221 self.inner.push(err);
222 }
223
224 pub(crate) fn extend(&mut self, errors: Vec<Error<'a, Prim>>) {
225 self.inner.extend(errors.into_iter());
226 }
227
228 pub fn len(&self) -> usize {
230 self.inner.len()
231 }
232
233 pub fn is_empty(&self) -> bool {
235 self.inner.is_empty()
236 }
237
238 pub fn iter(&self) -> impl Iterator<Item = &Error<'a, Prim>> + '_ {
240 self.inner.iter()
241 }
242
243 pub fn first_failing_statement(&self) -> usize {
247 self.first_failing_statement
248 }
249
250 pub(crate) fn set_first_failing_statement(&mut self, index: usize) {
251 self.first_failing_statement = index;
252 }
253
254 pub(crate) fn post_process(&mut self, type_resolver: &mut impl VisitMut<Prim>) {
257 for error in &mut self.inner {
258 error.context.map_types(type_resolver);
259 }
260 }
261}
262
263impl<Prim: PrimitiveType> fmt::Display for Errors<'_, Prim> {
264 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
265 for (i, error) in self.inner.iter().enumerate() {
266 write!(formatter, "{}", error)?;
267 if i + 1 < self.inner.len() {
268 formatter.write_str("\n")?;
269 }
270 }
271 Ok(())
272 }
273}
274
275impl<Prim: PrimitiveType> std::error::Error for Errors<'_, Prim> {}
276
277impl<'a, Prim: PrimitiveType> IntoIterator for Errors<'a, Prim> {
278 type Item = Error<'a, Prim>;
279 type IntoIter = std::vec::IntoIter<Self::Item>;
280
281 fn into_iter(self) -> Self::IntoIter {
282 self.inner.into_iter()
283 }
284}
285
286#[derive(Debug, Clone)]
290#[non_exhaustive]
291pub enum ErrorContext<Prim: PrimitiveType> {
292 None,
294 Lvalue(Type<Prim>),
296 FnDefinition {
298 args: Tuple<Prim>,
300 },
301 FnCall {
303 definition: Type<Prim>,
305 call_signature: Type<Prim>,
307 },
308 Assignment {
310 lhs: Type<Prim>,
312 rhs: Type<Prim>,
314 },
315 TypeCast {
317 source: Type<Prim>,
319 target: Type<Prim>,
321 },
322 UnaryOp(UnaryOpContext<Prim>),
324 BinaryOp(BinaryOpContext<Prim>),
326 TupleIndex {
328 ty: Type<Prim>,
330 },
331 ObjectFieldAccess {
333 ty: Type<Prim>,
335 },
336}
337
338impl<Prim: PrimitiveType> From<UnaryOpContext<Prim>> for ErrorContext<Prim> {
339 fn from(value: UnaryOpContext<Prim>) -> Self {
340 Self::UnaryOp(value)
341 }
342}
343
344impl<Prim: PrimitiveType> From<BinaryOpContext<Prim>> for ErrorContext<Prim> {
345 fn from(value: BinaryOpContext<Prim>) -> Self {
346 Self::BinaryOp(value)
347 }
348}
349
350impl<Prim: PrimitiveType> ErrorContext<Prim> {
351 fn map_types(&mut self, mapper: &mut impl VisitMut<Prim>) {
352 match self {
353 Self::None => { }
354 Self::Lvalue(lvalue) => mapper.visit_type_mut(lvalue),
355 Self::FnDefinition { args } => mapper.visit_tuple_mut(args),
356 Self::FnCall {
357 definition,
358 call_signature,
359 } => {
360 mapper.visit_type_mut(definition);
361 mapper.visit_type_mut(call_signature);
362 }
363 Self::Assignment { lhs, rhs } | Self::BinaryOp(BinaryOpContext { lhs, rhs, .. }) => {
364 mapper.visit_type_mut(lhs);
365 mapper.visit_type_mut(rhs);
366 }
367 Self::TypeCast { source, target } => {
368 mapper.visit_type_mut(source);
369 mapper.visit_type_mut(target);
370 }
371 Self::UnaryOp(UnaryOpContext { arg, .. }) => {
372 mapper.visit_type_mut(arg);
373 }
374 Self::TupleIndex { ty } | Self::ObjectFieldAccess { ty } => {
375 mapper.visit_type_mut(ty);
376 }
377 }
378 }
379}