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