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}