datex_core/compiler/
error.rs

1use crate::ast::expressions::DatexExpression;
2use crate::compiler::precompiler::precompiled_ast::RichAst;
3use crate::parser::errors::{ParserError, SpannedParserError};
4use crate::serde::error::DeserializationError;
5use crate::type_inference::error::{
6    DetailedTypeErrors, SpannedTypeError, TypeError,
7};
8use core::fmt::{Display, Formatter};
9use core::ops::Range;
10
11#[derive(Debug, Clone)]
12pub enum CompilerError {
13    UnexpectedTerm(Box<DatexExpression>),
14    SerializationError,
15    // TODO #478: SerializationError(binrw::Error),? has no clone
16    BigDecimalOutOfBoundsError,
17    IntegerOutOfBoundsError,
18    InvalidPlaceholderCount,
19    TooManyApplyArguments, // more than 255 arguments
20    NonStaticValue,
21    UndeclaredVariable(String),
22    InvalidRedeclaration(String),
23    SubvariantNotFound(String, String),
24    ScopePopError,
25    InvalidSlotName(String),
26    AssignmentToConst(String),
27    AssignmentToImmutableReference(String),
28    AssignmentToImmutableValue(String),
29    OnceScopeUsedMultipleTimes,
30    TypeError(TypeError),
31    ParserError(ParserError),
32}
33
34/// A compiler error that can be linked to a specific span in the source code
35#[derive(Debug)]
36pub struct SpannedCompilerError {
37    pub error: CompilerError,
38    pub span: Option<Range<usize>>,
39}
40
41impl SpannedCompilerError {
42    pub fn new_with_span(
43        error: CompilerError,
44        span: Range<usize>,
45    ) -> SpannedCompilerError {
46        SpannedCompilerError {
47            error,
48            span: Some(span),
49        }
50    }
51}
52
53impl Display for SpannedCompilerError {
54    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
55        core::write!(
56            f,
57            "{} ({})",
58            self.error,
59            self.span
60                .as_ref()
61                .map(|s| format!("{}..{}", s.start, s.end))
62                .unwrap_or("?".to_string())
63        )
64    }
65}
66
67impl From<SpannedTypeError> for SpannedCompilerError {
68    fn from(value: SpannedTypeError) -> Self {
69        SpannedCompilerError {
70            span: value.span,
71            error: value.error.into(),
72        }
73    }
74}
75
76impl From<SpannedParserError> for SpannedCompilerError {
77    fn from(value: SpannedParserError) -> Self {
78        SpannedCompilerError {
79            span: Some(value.span),
80            error: CompilerError::ParserError(value.error),
81        }
82    }
83}
84
85impl From<CompilerError> for SpannedCompilerError {
86    fn from(value: CompilerError) -> Self {
87        SpannedCompilerError {
88            error: value,
89            span: None,
90        }
91    }
92}
93
94impl From<SpannedCompilerError> for DeserializationError {
95    fn from(e: SpannedCompilerError) -> Self {
96        DeserializationError::CompilerError(e)
97    }
98}
99
100#[derive(Debug, Default)]
101pub struct DetailedCompilerErrors {
102    pub errors: Vec<SpannedCompilerError>,
103}
104
105impl DetailedCompilerErrors {
106    pub fn has_errors(&self) -> bool {
107        !self.errors.is_empty()
108    }
109
110    pub fn append(&mut self, mut errors: DetailedCompilerErrors) {
111        self.errors.append(&mut errors.errors);
112    }
113}
114
115impl Display for DetailedCompilerErrors {
116    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
117        for error in self.errors.iter() {
118            writeln!(f, "{}", error)?;
119        }
120        Ok(())
121    }
122}
123
124impl DetailedCompilerErrors {
125    pub fn record_error_with_span(
126        &mut self,
127        error: CompilerError,
128        span: Range<usize>,
129    ) {
130        self.record_error(SpannedCompilerError {
131            error,
132            span: Some(span),
133        });
134    }
135}
136
137impl From<DetailedTypeErrors> for DetailedCompilerErrors {
138    fn from(value: DetailedTypeErrors) -> Self {
139        DetailedCompilerErrors {
140            errors: value
141                .errors
142                .into_iter()
143                .map(SpannedCompilerError::from)
144                .collect(),
145        }
146    }
147}
148
149impl ErrorCollector<SpannedCompilerError> for DetailedCompilerErrors {
150    fn record_error(&mut self, error: SpannedCompilerError) {
151        self.errors.push(error);
152    }
153}
154
155#[derive(Debug)]
156pub enum SimpleOrDetailedCompilerError {
157    Simple(SpannedCompilerError),
158    Detailed(DetailedCompilerErrors),
159}
160
161impl From<CompilerError> for SimpleOrDetailedCompilerError {
162    fn from(value: CompilerError) -> Self {
163        SimpleOrDetailedCompilerError::Simple(SpannedCompilerError::from(value))
164    }
165}
166
167impl From<SpannedCompilerError> for SimpleOrDetailedCompilerError {
168    fn from(value: SpannedCompilerError) -> Self {
169        SimpleOrDetailedCompilerError::Simple(value)
170    }
171}
172
173#[derive(Debug)]
174pub struct DetailedCompilerErrorsWithRichAst {
175    pub errors: DetailedCompilerErrors,
176    pub ast: RichAst,
177}
178
179#[derive(Debug)]
180pub struct DetailedCompilerErrorsWithMaybeRichAst {
181    pub errors: DetailedCompilerErrors,
182    pub ast: Option<RichAst>,
183}
184
185impl From<DetailedCompilerErrorsWithRichAst>
186    for DetailedCompilerErrorsWithMaybeRichAst
187{
188    fn from(value: DetailedCompilerErrorsWithRichAst) -> Self {
189        DetailedCompilerErrorsWithMaybeRichAst {
190            errors: value.errors,
191            ast: Some(value.ast),
192        }
193    }
194}
195
196/// Extended SimpleOrDetailedCompilerError type
197/// that includes RichAst for the Detailed variant
198#[derive(Debug)]
199pub enum SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst {
200    /// DetailedCompilerError with additional RichAst
201    Detailed(DetailedCompilerErrorsWithRichAst),
202    /// simple SpannedCompilerError
203    Simple(SpannedCompilerError),
204}
205
206impl From<SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst>
207    for SimpleOrDetailedCompilerError
208{
209    fn from(
210        value: SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst,
211    ) -> Self {
212        match value {
213            SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst::Simple(
214                error,
215            ) => SimpleOrDetailedCompilerError::Simple(error),
216            SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst::Detailed(
217                error_with_ast,
218            ) => SimpleOrDetailedCompilerError::Detailed(error_with_ast.errors),
219        }
220    }
221}
222
223impl From<SpannedCompilerError>
224    for SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst
225{
226    fn from(
227        value: SpannedCompilerError,
228    ) -> SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst {
229        SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst::Simple(value)
230    }
231}
232
233impl From<Vec<SpannedParserError>> for DetailedCompilerErrors {
234    fn from(value: Vec<SpannedParserError>) -> Self {
235        DetailedCompilerErrors {
236            errors: value.into_iter().map(SpannedCompilerError::from).collect(),
237        }
238    }
239}
240
241impl From<TypeError> for SimpleOrDetailedCompilerError {
242    fn from(value: TypeError) -> Self {
243        // TODO #479: also store and map span from type error
244        SimpleOrDetailedCompilerError::Simple(SpannedCompilerError::from(
245            CompilerError::from(value),
246        ))
247    }
248}
249
250impl From<TypeError> for CompilerError {
251    fn from(value: TypeError) -> Self {
252        CompilerError::TypeError(value)
253    }
254}
255
256impl Display for CompilerError {
257    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
258        match self {
259            CompilerError::InvalidRedeclaration(name) => {
260                core::write!(f, "Invalid redeclaration of {name}")
261            }
262            CompilerError::UnexpectedTerm(rule) => {
263                core::write!(f, "Unexpected term: {rule:?}")
264            }
265            CompilerError::SubvariantNotFound(name, variant) => {
266                core::write!(
267                    f,
268                    "Subvariant {variant} does not exist for {name}"
269                )
270            }
271            CompilerError::SerializationError => {
272                core::write!(f, "Serialization error")
273            }
274            CompilerError::BigDecimalOutOfBoundsError => {
275                core::write!(f, "BigDecimal out of bounds error")
276            }
277            CompilerError::IntegerOutOfBoundsError => {
278                core::write!(f, "Integer out of bounds error")
279            }
280            CompilerError::InvalidPlaceholderCount => {
281                core::write!(f, "Invalid placeholder count")
282            }
283            CompilerError::NonStaticValue => {
284                core::write!(f, "Encountered non-static value")
285            }
286            CompilerError::UndeclaredVariable(var) => {
287                core::write!(f, "Undeclared variable: {var}")
288            }
289            CompilerError::ScopePopError => {
290                core::write!(f, "Could not pop scope, stack is empty")
291            }
292            CompilerError::InvalidSlotName(name) => {
293                core::write!(f, "Slot #{name} does not exist")
294            }
295            CompilerError::AssignmentToConst(name) => {
296                core::write!(f, "Cannot assign new value to const {name}")
297            }
298            CompilerError::OnceScopeUsedMultipleTimes => {
299                core::write!(
300                    f,
301                    "Scope cannot be used multiple times, set 'once' to false to use a scope multiple times"
302                )
303            }
304            CompilerError::AssignmentToImmutableValue(name) => {
305                core::write!(f, "Cannot assign to immutable value: {name}")
306            }
307            CompilerError::AssignmentToImmutableReference(name) => {
308                core::write!(f, "Cannot assign to immutable reference: {name}")
309            }
310            CompilerError::TypeError(err) => {
311                core::write!(f, "{}", err)
312            }
313            CompilerError::ParserError(err) => {
314                core::write!(f, "{:?}", err)
315            }
316            CompilerError::TooManyApplyArguments => {
317                core::write!(
318                    f,
319                    "Apply has too many arguments (max 255 allowed)"
320                )
321            }
322        }
323    }
324}
325
326/// Describes an optional action that is only executed if an Ok result
327/// was returned (used in collect_or_pass_error);
328pub enum MaybeAction<T> {
329    // optional action should not be performed
330    Skip,
331    // action should be performed with the provided value
332    Do(T),
333}
334
335pub trait ErrorCollector<E> {
336    fn record_error(&mut self, error: E);
337}
338
339/// Handles a generic Result with an SpannedCompilerError error.
340/// If the result is Ok(), an Ok(MaybeAction::Do) with the result is returned
341/// If result is Error() and collected_errors is Some, the error is appended to the collected_errors
342/// and an Ok(MaybeAction::Skip) is returned
343/// If result is Error() and collected_errors is None, the error is directly returned
344pub fn collect_or_pass_error<T, E, Collector: ErrorCollector<E>>(
345    collected_errors: &mut Option<Collector>,
346    result: Result<T, E>,
347) -> Result<MaybeAction<T>, E> {
348    if let Err(error) = result {
349        if let Some(collected_errors) = collected_errors {
350            collected_errors.record_error(error);
351            Ok(MaybeAction::Skip)
352        } else {
353            Err(error)
354        }
355    } else {
356        result.map(MaybeAction::Do)
357    }
358}