Skip to main content

microcad_lang/eval/
eval_error.rs

1// Copyright © 2024-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Evaluation error
5
6#![allow(unused, unused_assignments)]
7
8use crate::{eval::*, model::OutputType, parse::*, resolve::*, syntax::*, ty::*, value::*};
9use microcad_lang_base::{DiagError, SrcRef};
10use miette::Diagnostic;
11use thiserror::Error;
12
13/// Evaluation error.
14#[derive(Debug, Error, Diagnostic)]
15#[allow(missing_docs)]
16pub enum EvalError {
17    /// Can't find a project file by it's qualified name.
18    #[error("Not implemented: {0}")]
19    Todo(String),
20
21    /// List index out of bounds.
22    #[error("List index out of bounds: {index} >= {len}")]
23    ListIndexOutOfBounds {
24        /// Wrong index
25        index: usize,
26        /// Length of list
27        len: usize,
28    },
29
30    /// Parameter type mismatch.
31    #[error("Type mismatch for `{id}`: expected {expected}, got {found}")]
32    TypeMismatch {
33        /// Parameter name
34        id: Identifier,
35        /// Expected type
36        expected: Type,
37        /// Found type
38        found: Type,
39    },
40
41    /// Array elements have different types.
42    #[error("Array elements have different types: {0}")]
43    ArrayElementsDifferentTypes(TypeList),
44
45    /// Symbol not found.
46    #[error("Symbol {0} not found.")]
47    SymbolNotFound(QualifiedName),
48
49    /// Given symbol has not children which can be used.
50    #[error("No symbols found to use in {0}")]
51    NoSymbolsToUse(QualifiedName),
52
53    /// The symbol cannot be called, e.g. when it is a source file or a module.
54    #[error("Symbol `{0}` cannot be called.")]
55    SymbolCannotBeCalled(QualifiedName),
56
57    /// Found ambiguous symbols.
58    #[error("Ambiguous symbol {0} might be one of the following: {1}")]
59    AmbiguousSymbol(QualifiedName, QualifiedNames),
60
61    /// Local Symbol not found.
62    #[error("Local symbol not found: {0}")]
63    LocalNotFound(Identifier),
64
65    /// A property of a value was not found.
66    #[error("Property not found: {0}")]
67    PropertyNotFound(Identifier),
68
69    /// A property of a value was not found.
70    #[error("Not a property id: {0}")]
71    NoPropertyId(QualifiedName),
72
73    /// Argument count mismatch.
74    #[error("Argument count mismatch: expected {expected}, got {found} in {args}")]
75    ArgumentCountMismatch {
76        /// Argument list including the error
77        args: String,
78        /// Expected number of arguments
79        expected: usize,
80        /// Found number of arguments
81        found: usize,
82    },
83
84    /// Invalid argument type.
85    #[error("Invalid argument type: {0}")]
86    InvalidArgumentType(Type),
87
88    /// Unexpected argument.
89    #[error("Unexpected argument: {0}: {1}")]
90    UnexpectedArgument(Identifier, Type),
91
92    /// Assertion failed.
93    #[error("Assertion failed: {0}")]
94    AssertionFailed(String),
95
96    /// Different type expected.
97    #[error("Expected type `{expected}`, found type `{found}")]
98    ExpectedType {
99        /// Expected type.
100        expected: Type,
101        /// Found type.
102        found: Type,
103    },
104
105    /// Diagnostic error
106    #[error("Diagnostic error: {0}")]
107    DiagError(#[from] DiagError),
108
109    /// No locals  available on stack.
110    #[error("Local stack needed to store {0}")]
111    LocalStackEmpty(Identifier),
112
113    /// Unexpected stack frame type
114    #[error("Unexpected stack frame of type '{1}' cannot store {0}")]
115    WrongStackFrame(Identifier, &'static str),
116
117    /// Value Error.
118    #[error("Value Error: {0}")]
119    ValueError(#[from] ValueError),
120
121    /// Unknown method.
122    #[error("Unknown method `{0}`")]
123    UnknownMethod(QualifiedName),
124
125    /// Parser Error
126    #[error("Parsing error {0}")]
127    ParseError(#[from] ParseError),
128
129    /// Statement is not supported in this context.
130    #[error("{0} statement not available here")]
131    StatementNotSupported(&'static str),
132
133    /// Properties are not initialized.
134    #[error("Properties have not been initialized: {0}")]
135    UninitializedProperties(IdentifierList),
136
137    /// Unexpected element within expression.
138    #[error("Unexpected {0} {1} within expression")]
139    UnexpectedNested(&'static str, Identifier),
140
141    /// No variables allowed in definition
142    #[error("No variables allowed in {0}")]
143    NoVariablesAllowedIn(&'static str),
144
145    /// Error when evaluating attributes.
146    #[error("Attribute error: {0}")]
147    AttributeError(#[from] AttributeError),
148
149    /// Missing arguments
150    #[error("Missing arguments: {0}")]
151    MissingArguments(IdentifierList),
152
153    /// Missing arguments
154    #[error("Too many arguments: {0}")]
155    TooManyArguments(IdentifierList),
156
157    /// Arguments match by identifier but have incompatible types
158    #[error("Arguments match by identifier but have incompatible types: {0}")]
159    IdMatchButNotType(String),
160
161    /// Builtin error
162    #[error("Builtin error: {0}")]
163    BuiltinError(String),
164
165    /// Parameter not found by type in ParameterValueList
166    #[error("Parameter not found by type '{0}'")]
167    ParameterByTypeNotFound(Type),
168
169    /// Trying to use multiplicity where it is not allowed
170    #[error("Multiplicity not allowed '{0}'")]
171    MultiplicityNotAllowed(IdentifierList),
172
173    /// An error if you try to mix 2d and 3d geometries.
174    #[error("Cannot mix 2d and 3d geometries")]
175    CannotMixGeometry,
176
177    /// A condition of an if statement is not a boolean
178    #[error("If condition is not a boolean: {condition}")]
179    IfConditionIsNotBool {
180        condition: String,
181        #[label("Not a boolean")]
182        src_ref: SrcRef,
183    },
184
185    /// Workbench didn't find a initialization routine matching the given arguments
186    #[error("Workbench {name} cannot find initialization for those arguments")]
187    #[diagnostic(help("Possible initializations: \n\t{}", possible_params.join("\n\t")))]
188    NoInitializationFound {
189        #[label("Got: {name}( {actual_params} )")]
190        src_ref: SrcRef,
191        name: Identifier,
192        actual_params: String,
193        possible_params: Vec<String>,
194    },
195    /// Workbench didn't find a initialization routine matching the given arguments
196    #[error("Workbench {name} has ambiguous initialization for those arguments")]
197    #[diagnostic(help("Ambiguous initializations: \n\t{}", ambiguous_params.join("\n\t")))]
198    AmbiguousInitialization {
199        #[label("Got: {name}( {actual_params} )")]
200        src_ref: SrcRef,
201        name: Identifier,
202        actual_params: String,
203        ambiguous_params: Vec<String>,
204    },
205
206    /// Initializer missed to set a property from plan
207    #[error("Building plan incomplete. Missing properties: {0}")]
208    BuildingPlanIncomplete(IdentifierList),
209
210    /// This errors happens if the expression is supposed to produce models but did not.
211    #[error("This expression statement did not produce any model")]
212    EmptyModelExpression,
213
214    /// Workbench with empty body - suspicious!
215    #[error("{0} {1} has empty body")]
216    WarnEmptyWorkbench(String, Identifier),
217
218    /// This error happens if the workbench produced a different output type.
219    #[error("The {kind} workbench produced a {produced} output, but expected a {expected} output.")]
220    WorkbenchInvalidOutput {
221        kind: WorkbenchKind,
222        produced: OutputType,
223        expected: OutputType,
224    },
225
226    /// This error happens if the workbench produced a different output type.
227    #[error("The {0} workbench will produce no {1} output.")]
228    WorkbenchNoOutput(WorkbenchKind, OutputType),
229
230    /// Unexpected source file in expression
231    #[error("Unexpected source file {0} in expression")]
232    InvalidSelfReference(Identifier),
233
234    /// Resolve Error
235    #[error("Resolve error: {0}")]
236    #[diagnostic(transparent)]
237    ResolveError(ResolveError),
238
239    /// Unexpected source file in expression
240    #[error("{0} is not operation.")]
241    NotAnOperation(QualifiedName),
242
243    /// Calling an operation on an empty geometry, e.g.: `{}.op()`.
244    #[error("Calling operation on empty geometry")]
245    OperationOnEmptyGeometry,
246
247    /// Cannot call operation without workpiece, e.g. `op()`.
248    #[error("Cannot call operation without workpiece.")]
249    CannotCallOperationWithoutWorkpiece,
250
251    /// Function missing return statement
252    #[error("Missing return statement in {0}")]
253    MissingReturn(QualifiedName),
254
255    /// There is no model in this workbench
256    #[error("Missing model in workbench")]
257    NoModelInWorkbench,
258
259    /// Found a symbol and a property with that name
260    #[error("Found a symbol and a property with names {0} and {1}")]
261    AmbiguousProperty(QualifiedName, Identifier),
262
263    /// Assignment failed because value already has been defined before.
264    #[error("Value {name} already in defined: {value}")]
265    #[diagnostic(help("Values in microcad are immutable"))]
266    ValueAlreadyDefined {
267        /// Location of the error
268        #[label(primary, "{name} is already defined")]
269        location: SrcRef,
270        /// Name of the value
271        name: Identifier,
272        /// Previous value
273        value: String,
274        /// Previous definition
275        #[label("Previously defined here")]
276        previous_location: SrcRef,
277    },
278
279    /// Assignment failed because left side is not an l-value
280    #[error("Assignment failed because {0} is not an l-value")]
281    NotAnLValue(Identifier),
282
283    /// Found symbol but it's not visible to user
284    #[error("Symbol {what} is private from within {within}")]
285    SymbolIsPrivate {
286        /// what was searched
287        what: QualifiedName,
288        /// where it was searched
289        within: QualifiedName,
290    },
291
292    /// Found symbol but it's not visible to user
293    #[error("Symbol {what} (aliased from {alias}) is private from within {within}")]
294    SymbolBehindAliasIsPrivate {
295        /// what was searched
296        what: QualifiedName,
297        /// the alias in between
298        alias: QualifiedName,
299        /// where it was searched
300        within: QualifiedName,
301    },
302
303    /// Found unused global symbols.
304    #[error("Unused global symbol {0}.")]
305    UnusedGlobalSymbol(String),
306
307    /// Unused local.
308    #[error("Unused local {0}.")]
309    UnusedLocal(Identifier),
310
311    /// Evaluation aborted because of prior resolve errors
312    #[error("Evaluation aborted because of prior resolve errors!")]
313    ResolveFailed,
314
315    /// Bad range (first > last)
316    #[error("Bad range, first number ({0}) must be smaller than last ({1})")]
317    BadRange(i64, i64),
318
319    /// Ambiguous types in tuple
320    #[error("Ambiguous type '{ty}' in tuple")]
321    AmbiguousType {
322        ty: Type,
323        #[label(
324            "Some unnamed values in this tuple share the same type '{ty}'.\nMaybe check the units or use identifiers in this tuple."
325        )]
326        src_ref: SrcRef,
327    },
328}
329
330/// Result type of any evaluation.
331pub type EvalResult<T> = std::result::Result<T, EvalError>;
332
333impl From<ResolveError> for EvalError {
334    fn from(err: ResolveError) -> Self {
335        match err {
336            ResolveError::SymbolNotFound(name) => EvalError::SymbolNotFound(name),
337            other => EvalError::ResolveError(other),
338        }
339    }
340}