Skip to main content

microcad_lang/eval/
eval_error.rs

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