exp_rs/error.rs
1//! Error types and handling for the exp-rs crate.
2//!
3//! This module defines the error types used throughout the exp-rs crate for expression parsing
4//! and evaluation. It provides detailed error information to help diagnose issues in expressions.
5
6extern crate alloc;
7use alloc::string::String;
8#[cfg(not(test))]
9use core::num::ParseFloatError;
10#[cfg(test)]
11use std::num::ParseFloatError;
12
13#[cfg(not(test))]
14use core::result;
15#[cfg(test)]
16use std::result;
17
18/// Result type used throughout the crate.
19///
20/// This is a convenience type alias that uses the `ExprError` type for the error variant.
21pub type Result<T> = result::Result<T, ExprError>;
22
23/// Error type for expression parsing and evaluation.
24///
25/// This enum represents all possible errors that can occur during expression parsing,
26/// tokenization, and evaluation. It provides specific error variants with detailed
27/// information to help diagnose and fix issues.
28#[derive(Debug, Clone)]
29pub enum ExprError {
30 /// Error when parsing a floating point number.
31 ///
32 /// This occurs when a string cannot be converted to a floating point number.
33 /// For example, "3.a" is not a valid floating point number.
34 Parse(ParseFloatError),
35
36 /// Error during lexical analysis (tokenization).
37 ///
38 /// This occurs when the tokenizer encounters invalid tokens or unknown characters
39 /// that cannot be processed. The string contains a detailed error message.
40 Tokenizer(String),
41
42 /// Error during syntax analysis.
43 ///
44 /// This occurs when the parser encounters unexpected tokens, incorrect expression
45 /// structure, or other syntax issues. The string contains a detailed error message.
46 Syntax(String),
47
48 /// Error for unmatched parentheses in an expression.
49 ///
50 /// This provides the position of the unmatched parenthesis and the specific
51 /// parenthesis character that was found without a matching pair.
52 UnmatchedParenthesis { position: usize, found: String },
53
54 /// Error when a variable referenced in an expression is not defined.
55 ///
56 /// To resolve this error, make sure the variable is registered in the
57 /// evaluation context using `EvalContext::set_parameter`.
58 UnknownVariable { name: String },
59 /// Unknown function error
60 ///
61 /// This error is returned when a function is called that is not registered in the context
62 /// and is not a built-in (if built-ins are enabled). If the `no-builtin-math` feature is enabled,
63 /// users must register their own native functions for all required math operations.
64 ///
65 /// To resolve this error, register a native function with `EvalContext::register_native_function`
66 /// or an expression function with `EvalContext::register_expression_function`.
67 UnknownFunction { name: String },
68 /// Error when a function is called with the wrong number of arguments.
69 ///
70 /// This occurs when a function is called with fewer or more arguments than it expects.
71 /// The error includes the function name, the expected number of arguments, and the
72 /// actual number of arguments provided.
73 InvalidFunctionCall {
74 /// Name of the function that was called
75 name: String,
76 /// Expected number of arguments
77 expected: usize,
78 /// Actual number of arguments provided
79 found: usize,
80 },
81 /// Error when an array index is out of bounds.
82 ///
83 /// This occurs when trying to access an array element with an index that exceeds
84 /// the array's length. The error includes the array name, the attempted index,
85 /// and the actual length of the array.
86 ArrayIndexOutOfBounds {
87 /// Name of the array being accessed
88 name: String,
89 /// Index that was attempted to be accessed
90 index: usize,
91 /// Actual length of the array
92 len: usize,
93 },
94
95 /// Error when an attribute access is attempted on an object that doesn't have that attribute.
96 ///
97 /// This occurs when using the dot notation (e.g., `object.attribute`) and the attribute
98 /// does not exist on the specified object.
99 AttributeNotFound {
100 /// The base object name
101 base: String,
102 /// The attribute name that was not found
103 attr: String
104 },
105
106 /// General-purpose error for any other error conditions.
107 ///
108 /// This is used for errors that don't fit into other specific categories.
109 /// The string contains a detailed error message.
110 Other(String),
111
112 /// Error when the recursion limit is exceeded during expression evaluation.
113 ///
114 /// This usually happens with deeply nested expressions or recursive function calls.
115 /// To resolve this, simplify the expression or increase the recursion limit if possible.
116 RecursionLimit(String),
117}
118
119#[cfg(not(test))]
120use core::fmt;
121#[cfg(test)]
122use std::fmt;
123
124impl fmt::Display for ExprError {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 ExprError::Parse(_) => write!(f, "Parse error"),
128 ExprError::Tokenizer(err) => write!(f, "Tokenizer error: {}", err),
129 ExprError::Syntax(err) => write!(f, "Syntax error: {}", err),
130 ExprError::UnmatchedParenthesis { position, found } => {
131 write!(
132 f,
133 "Unmatched parenthesis at position {}: found '{}'",
134 position, found
135 )
136 }
137 ExprError::UnknownVariable { name } => {
138 write!(f, "Unknown variable: '{}'", name)
139 }
140 ExprError::UnknownFunction { name } => {
141 write!(f, "Unknown function: '{}'", name)
142 }
143 ExprError::InvalidFunctionCall {
144 name,
145 expected,
146 found,
147 } => {
148 write!(
149 f,
150 "Invalid function call to '{}': expected {} arguments, found {}",
151 name, expected, found
152 )
153 }
154 ExprError::ArrayIndexOutOfBounds { name, index, len } => {
155 write!(
156 f,
157 "Array index out of bounds: index {} out of bounds for '{}', length {}",
158 index, name, len
159 )
160 }
161 ExprError::AttributeNotFound { base, attr } => {
162 write!(f, "Attribute not found: '{}' in '{}'", attr, base)
163 }
164 ExprError::Other(err) => write!(f, "{}", err),
165 ExprError::RecursionLimit(err) => write!(f, "Recursion limit exceeded: {}", err),
166 }
167 }
168}
169
170impl From<String> for ExprError {
171 fn from(err: String) -> ExprError {
172 ExprError::Other(err)
173 }
174}
175
176impl From<ParseFloatError> for ExprError {
177 fn from(err: ParseFloatError) -> ExprError {
178 ExprError::Parse(err)
179 }
180}