Implement iterators over variable and function identifiers

Relates to #37
This commit is contained in:
Sebastian Schmidt 2019-04-13 20:15:26 +02:00
parent 1c68866777
commit 697fbb5d45
3 changed files with 55 additions and 0 deletions

View File

@ -7,6 +7,7 @@
### Added ### Added
* Iterator over all identifiers within an expression, including duplicates * Iterator over all identifiers within an expression, including duplicates
* Iterators over only variable or only function identifiers within an expression, including duplicates
* Overload the `+` operator to concatenate strings * Overload the `+` operator to concatenate strings
* Overload `<`, `<=`, `>` and `>=` for strings using lexical ordering (Note: `==` and `!=` compare strings as expected) * Overload `<`, `<=`, `>` and `>=` for strings using lexical ordering (Note: `==` and `!=` compare strings as expected)
* Add `len`, `str::regex_matches`, `str::regex_replace`, `str::to_lowercase`, `str::to_uppercase`, `str::trim` functions for strings * Add `len`, `str::regex_matches`, `str::regex_replace`, `str::to_lowercase`, `str::to_uppercase`, `str::trim` functions for strings

View File

@ -42,6 +42,16 @@ pub trait Operator: Debug + Display {
fn identifier(&self) -> Option<&str> { fn identifier(&self) -> Option<&str> {
None None
} }
/// Returns a variable identifier if this operator is a variable identifier, or `None` otherwise.
fn variable_identifier(&self) -> Option<&str> {
None
}
/// Returns a function identifier if this operator is a function identifier, or `None` otherwise.
fn function_identifier(&self) -> Option<&str> {
None
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -719,6 +729,10 @@ impl Operator for VariableIdentifier {
fn identifier(&self) -> Option<&str> { fn identifier(&self) -> Option<&str> {
Some(&self.identifier) Some(&self.identifier)
} }
fn variable_identifier(&self) -> Option<&str> {
Some(&self.identifier)
}
} }
impl Operator for FunctionIdentifier { impl Operator for FunctionIdentifier {
@ -757,4 +771,8 @@ impl Operator for FunctionIdentifier {
fn identifier(&self) -> Option<&str> { fn identifier(&self) -> Option<&str> {
Some(&self.identifier) Some(&self.identifier)
} }
fn function_identifier(&self) -> Option<&str> {
Some(&self.identifier)
}
} }

View File

@ -70,6 +70,42 @@ impl Node {
self.iter().filter_map(|node| node.operator.identifier()) self.iter().filter_map(|node| node.operator.identifier())
} }
/// Returns an iterator over all variable identifiers in this expression.
/// Each occurrence of a variable identifier is returned separately.
///
/// # Examples
///
/// ```rust
/// use evalexpr::*;
///
/// let tree = build_operator_tree("a + f(b + c)").unwrap(); // Do proper error handling here
/// let mut iter = tree.iter_variable_identifiers();
/// assert_eq!(iter.next(), Some("a"));
/// assert_eq!(iter.next(), Some("b"));
/// assert_eq!(iter.next(), Some("c"));
/// assert_eq!(iter.next(), None);
/// ```
pub fn iter_variable_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| node.operator.variable_identifier())
}
/// Returns an iterator over all function identifiers in this expression.
/// Each occurrence of a function identifier is returned separately.
///
/// # Examples
///
/// ```rust
/// use evalexpr::*;
///
/// let tree = build_operator_tree("a + f(b + c)").unwrap(); // Do proper error handling here
/// let mut iter = tree.iter_function_identifiers();
/// assert_eq!(iter.next(), Some("f"));
/// assert_eq!(iter.next(), None);
/// ```
pub fn iter_function_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| node.operator.function_identifier())
}
/// Evaluates the operator tree rooted at this node with the given context. /// Evaluates the operator tree rooted at this node with the given context.
/// ///
/// Fails, if one of the operators in the expression tree fails. /// Fails, if one of the operators in the expression tree fails.