microcad_lang/eval/
eval_error.rs

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