Implement Node::iter_identifiers()

This commit implements an iterator over the identifiers in an expression.
The identifiers are iterated pre-order, meaning that higher nodes in the tree are emitted first.
The identifier iterator is based on a general iterator over all nodes in an operator tree, which can be used for further featues.

Relates to #37
This commit is contained in:
Sebastian Schmidt 2019-04-12 19:27:34 +02:00
parent 7545d1f31e
commit e328adb97b
3 changed files with 87 additions and 0 deletions

View File

@ -37,6 +37,11 @@ pub trait Operator: Debug + Display {
fn eval_mut(&self, arguments: &[Value], context: &mut dyn Context) -> EvalexprResult<Value> { fn eval_mut(&self, arguments: &[Value], context: &mut dyn Context) -> EvalexprResult<Value> {
self.eval(arguments, context) self.eval(arguments, context)
} }
/// Returns an identifier if this operator is a function or variable identifier, or `None` otherwise.
fn identifier(&self) -> Option<&str> {
None
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -681,6 +686,10 @@ impl Operator for VariableIdentifier {
)) ))
} }
} }
fn identifier(&self) -> Option<&str> {
Some(&self.identifier)
}
} }
impl Operator for FunctionIdentifier { impl Operator for FunctionIdentifier {
@ -715,4 +724,8 @@ impl Operator for FunctionIdentifier {
)) ))
} }
} }
fn identifier(&self) -> Option<&str> {
Some(&self.identifier)
}
} }

53
src/tree/iter.rs Normal file
View File

@ -0,0 +1,53 @@
use Node;
use std::slice::Iter;
/// An iterator that traverses an operator tree in pre-order.
pub struct NodeIter<'a> {
stack: Vec<Iter<'a, Node>>,
}
impl<'a> NodeIter<'a> {
fn new(node: &'a Node) -> Self {
NodeIter {
stack: vec![node.children.iter()],
}
}
}
impl<'a> Iterator for NodeIter<'a> {
type Item = &'a Node;
fn next(&mut self) -> Option<Self::Item> {
loop {
let mut pop_stack = false;
let mut result = None;
if let Some(last) = self.stack.last_mut() {
if let Some(next) = last.next() {
result = Some(next);
} else {
pop_stack = true;
}
} else {
return None;
}
if pop_stack {
// Can not fail because we borrowed last before.
self.stack.pop().unwrap();
}
if let Some(result) = result {
self.stack.push(result.children.iter());
return Some(result);
}
}
}
}
impl Node {
/// Returns an iterator over all nodes in this tree.
pub fn iter(&self) -> impl Iterator<Item=&Node> {
NodeIter::new(self)
}
}

View File

@ -13,6 +13,7 @@ use crate::{
}; };
mod display; mod display;
mod iter;
/// A node in the operator tree. /// A node in the operator tree.
/// The operator tree is created by the crate-level `build_operator_tree` method. /// The operator tree is created by the crate-level `build_operator_tree` method.
@ -49,6 +50,26 @@ impl Node {
Self::new(RootNode) Self::new(RootNode)
} }
/// Returns an iterator over all identifiers in this expression.
/// Each occurrence of an identifier is returned separately.
///
/// # Examples
///
/// ```rust
/// use evalexpr::*;
///
/// let tree = build_operator_tree("a + b + c * f()").unwrap(); // Do proper error handling here
/// let mut iter = tree.iter_identifiers();
/// assert_eq!(iter.next(), Some("a"));
/// assert_eq!(iter.next(), Some("b"));
/// assert_eq!(iter.next(), Some("c"));
/// assert_eq!(iter.next(), Some("f"));
/// assert_eq!(iter.next(), None);
/// ```
pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| node.operator.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.