Merge branch '52_remove_automatic_function_argument_decomposition'
This commit is contained in:
commit
6f533ca925
@ -103,7 +103,7 @@ impl Context for HashMapContext {
|
|||||||
///
|
///
|
||||||
/// let ctx = evalexpr::context_map! {
|
/// let ctx = evalexpr::context_map! {
|
||||||
/// "x" => 8,
|
/// "x" => 8,
|
||||||
/// "f" => Function::new(None, Box::new(|_| Ok(42.into()) ))
|
/// "f" => Function::new(Box::new(|_| Ok(42.into()) ))
|
||||||
/// }.unwrap();
|
/// }.unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(eval_with_context("x + f()", &ctx), Ok(50.into()));
|
/// assert_eq!(eval_with_context("x + f()", &ctx), Ok(50.into()));
|
||||||
|
@ -353,6 +353,14 @@ pub fn expect_boolean(actual: &Value) -> EvalexprResult<bool> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `Ok(&[Value])` if the given value is a `Value::Tuple`, or `Err(Error::ExpectedTuple)` otherwise.
|
||||||
|
pub fn expect_tuple(actual: &Value) -> EvalexprResult<&TupleType> {
|
||||||
|
match actual {
|
||||||
|
Value::Tuple(tuple) => Ok(tuple),
|
||||||
|
_ => Err(EvalexprError::expected_tuple(actual.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::error::Error for EvalexprError {}
|
impl std::error::Error for EvalexprError {}
|
||||||
|
|
||||||
/// Standard result type used by this crate.
|
/// Standard result type used by this crate.
|
||||||
|
@ -10,8 +10,8 @@ use Value;
|
|||||||
pub fn builtin_function(identifier: &str) -> Option<Function> {
|
pub fn builtin_function(identifier: &str) -> Option<Function> {
|
||||||
match identifier {
|
match identifier {
|
||||||
"min" => Some(Function::new(
|
"min" => Some(Function::new(
|
||||||
None,
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let arguments = expect_tuple(argument)?;
|
||||||
let mut min_int = IntType::max_value();
|
let mut min_int = IntType::max_value();
|
||||||
let mut min_float = 1.0f64 / 0.0f64;
|
let mut min_float = 1.0f64 / 0.0f64;
|
||||||
debug_assert!(min_float.is_infinite());
|
debug_assert!(min_float.is_infinite());
|
||||||
@ -34,8 +34,8 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
"max" => Some(Function::new(
|
"max" => Some(Function::new(
|
||||||
None,
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let arguments = expect_tuple(argument)?;
|
||||||
let mut max_int = IntType::min_value();
|
let mut max_int = IntType::min_value();
|
||||||
let mut max_float = -1.0f64 / 0.0f64;
|
let mut max_float = -1.0f64 / 0.0f64;
|
||||||
debug_assert!(max_float.is_infinite());
|
debug_assert!(max_float.is_infinite());
|
||||||
@ -59,9 +59,8 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
)),
|
)),
|
||||||
|
|
||||||
"len" => Some(Function::new(
|
"len" => Some(Function::new(
|
||||||
Some(1),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let subject = expect_string(argument)?;
|
||||||
let subject = expect_string(&arguments[0])?;
|
|
||||||
Ok(Value::from(subject.len() as i64))
|
Ok(Value::from(subject.len() as i64))
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
@ -69,8 +68,9 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
// string functions
|
// string functions
|
||||||
#[cfg(feature = "regex_support")]
|
#[cfg(feature = "regex_support")]
|
||||||
"str::regex_matches" => Some(Function::new(
|
"str::regex_matches" => Some(Function::new(
|
||||||
Some(2),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let arguments = expect_tuple(argument)?;
|
||||||
|
|
||||||
let subject = expect_string(&arguments[0])?;
|
let subject = expect_string(&arguments[0])?;
|
||||||
let re_str = expect_string(&arguments[1])?;
|
let re_str = expect_string(&arguments[1])?;
|
||||||
match Regex::new(re_str) {
|
match Regex::new(re_str) {
|
||||||
@ -84,8 +84,9 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
)),
|
)),
|
||||||
#[cfg(feature = "regex_support")]
|
#[cfg(feature = "regex_support")]
|
||||||
"str::regex_replace" => Some(Function::new(
|
"str::regex_replace" => Some(Function::new(
|
||||||
Some(3),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let arguments = expect_tuple(argument)?;
|
||||||
|
|
||||||
let subject = expect_string(&arguments[0])?;
|
let subject = expect_string(&arguments[0])?;
|
||||||
let re_str = expect_string(&arguments[1])?;
|
let re_str = expect_string(&arguments[1])?;
|
||||||
let repl = expect_string(&arguments[2])?;
|
let repl = expect_string(&arguments[2])?;
|
||||||
@ -99,23 +100,20 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
"str::to_lowercase" => Some(Function::new(
|
"str::to_lowercase" => Some(Function::new(
|
||||||
Some(1),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let subject = expect_string(argument)?;
|
||||||
let subject = expect_string(&arguments[0])?;
|
|
||||||
Ok(Value::from(subject.to_lowercase()))
|
Ok(Value::from(subject.to_lowercase()))
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
"str::to_uppercase" => Some(Function::new(
|
"str::to_uppercase" => Some(Function::new(
|
||||||
Some(1),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let subject = expect_string(argument)?;
|
||||||
let subject = expect_string(&arguments[0])?;
|
|
||||||
Ok(Value::from(subject.to_uppercase()))
|
Ok(Value::from(subject.to_uppercase()))
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
"str::trim" => Some(Function::new(
|
"str::trim" => Some(Function::new(
|
||||||
Some(1),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let subject = expect_string(argument)?;
|
||||||
let subject = expect_string(&arguments[0])?;
|
|
||||||
Ok(Value::from(subject.trim()))
|
Ok(Value::from(subject.trim()))
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use error::{self, EvalexprResult};
|
use error::{EvalexprResult};
|
||||||
use value::Value;
|
use value::Value;
|
||||||
|
|
||||||
pub(crate) mod builtin;
|
pub(crate) mod builtin;
|
||||||
@ -14,39 +14,29 @@ pub(crate) mod builtin;
|
|||||||
/// use evalexpr::*;
|
/// use evalexpr::*;
|
||||||
///
|
///
|
||||||
/// let mut context = HashMapContext::new();
|
/// let mut context = HashMapContext::new();
|
||||||
/// context.set_function("id".into(), Function::new(Some(1), Box::new(|arguments| {
|
/// context.set_function("id".into(), Function::new(Box::new(|argument| {
|
||||||
/// Ok(arguments[0].clone())
|
/// Ok(argument.clone())
|
||||||
/// }))).unwrap(); // Do proper error handling here
|
/// }))).unwrap(); // Do proper error handling here
|
||||||
/// assert_eq!(eval_with_context("id(4)", &context), Ok(Value::from(4)));
|
/// assert_eq!(eval_with_context("id(4)", &context), Ok(Value::from(4)));
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
argument_amount: Option<usize>,
|
function: Box<Fn(&Value) -> EvalexprResult<Value>>,
|
||||||
function: Box<Fn(&[Value]) -> EvalexprResult<Value>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
/// Creates a user-defined function.
|
/// Creates a user-defined function.
|
||||||
///
|
///
|
||||||
/// The `argument_amount` is the amount of arguments this function takes.
|
/// The `function` is a boxed function that takes a `Value` and returns a `EvalexprResult<Value, Error>`.
|
||||||
/// It is verified before the actual function is executed, assuming it is not `None`.
|
|
||||||
///
|
|
||||||
/// The `function` is a boxed function that takes a slice of values and returns a `EvalexprResult<Value, Error>`.
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
argument_amount: Option<usize>,
|
function: Box<Fn(&Value) -> EvalexprResult<Value>>,
|
||||||
function: Box<Fn(&[Value]) -> EvalexprResult<Value>>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
argument_amount,
|
|
||||||
function,
|
function,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn call(&self, arguments: &[Value]) -> EvalexprResult<Value> {
|
pub(crate) fn call(&self, argument: &Value) -> EvalexprResult<Value> {
|
||||||
if let Some(argument_amount) = self.argument_amount {
|
(self.function)(argument)
|
||||||
error::expect_function_argument_amount(arguments.len(), argument_amount)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
(self.function)(arguments)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,8 +44,7 @@ impl fmt::Debug for Function {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Function {{ argument_amount: {:?}, function: [...] }}",
|
"Function {{ [...] }}"
|
||||||
self.argument_amount
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/lib.rs
15
src/lib.rs
@ -49,21 +49,22 @@
|
|||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use evalexpr::*;
|
//! use evalexpr::*;
|
||||||
//! use evalexpr::error::expect_number;
|
//! use evalexpr::error::{expect_number, expect_tuple};
|
||||||
//!
|
//!
|
||||||
//! let context = context_map! {
|
//! let context = context_map! {
|
||||||
//! "five" => 5,
|
//! "five" => 5,
|
||||||
//! "twelve" => 12,
|
//! "twelve" => 12,
|
||||||
//! "f" => Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
|
//! "f" => Function::new(Box::new(|argument| {
|
||||||
//! if let Value::Int(int) = arguments[0] {
|
//! if let Value::Int(int) = argument {
|
||||||
//! Ok(Value::Int(int / 2))
|
//! Ok(Value::Int(int / 2))
|
||||||
//! } else if let Value::Float(float) = arguments[0] {
|
//! } else if let Value::Float(float) = argument {
|
||||||
//! Ok(Value::Float(float / 2.0))
|
//! Ok(Value::Float(float / 2.0))
|
||||||
//! } else {
|
//! } else {
|
||||||
//! Err(EvalexprError::expected_number(arguments[0].clone()))
|
//! Err(EvalexprError::expected_number(argument.clone()))
|
||||||
//! }
|
//! }
|
||||||
//! })),
|
//! })),
|
||||||
//! "avg" => Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
|
//! "avg" => Function::new(Box::new(|argument| {
|
||||||
|
//! let arguments = expect_tuple(argument)?;
|
||||||
//! expect_number(&arguments[0])?;
|
//! expect_number(&arguments[0])?;
|
||||||
//! expect_number(&arguments[1])?;
|
//! expect_number(&arguments[1])?;
|
||||||
//!
|
//!
|
||||||
@ -343,7 +344,7 @@
|
|||||||
//! Ok(free) => assert_eq!(free.eval_with_context(&context), Ok(Value::from(25))),
|
//! Ok(free) => assert_eq!(free.eval_with_context(&context), Ok(Value::from(25))),
|
||||||
//! Err(error) => {
|
//! Err(error) => {
|
||||||
//! () // Handle error
|
//! () // Handle error
|
||||||
//! },
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -4,7 +4,7 @@ use crate::{context::Context, error::*, value::Value};
|
|||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
RootNode,
|
RootNode,
|
||||||
|
|
||||||
@ -91,23 +91,34 @@ impl Operator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if chains of this operator should be flattened into one operator with many arguments.
|
||||||
|
// Make this a const fn once #57563 is resolved
|
||||||
|
pub(crate) fn is_sequence(&self) -> bool {
|
||||||
|
use crate::operator::Operator::*;
|
||||||
|
match self {
|
||||||
|
Tuple | Chain => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// True if this operator is a leaf, meaning it accepts no arguments.
|
/// True if this operator is a leaf, meaning it accepts no arguments.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
pub(crate) fn is_leaf(&self) -> bool {
|
pub(crate) fn is_leaf(&self) -> bool {
|
||||||
self.max_argument_amount() == 0
|
self.max_argument_amount() == Some(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the maximum amount of arguments required by this operator.
|
/// Returns the maximum amount of arguments required by this operator.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
pub(crate) fn max_argument_amount(&self) -> usize {
|
pub(crate) fn max_argument_amount(&self) -> Option<usize> {
|
||||||
use crate::operator::Operator::*;
|
use crate::operator::Operator::*;
|
||||||
match self {
|
match self {
|
||||||
Add | Sub | Mul | Div | Mod | Exp | Eq | Neq | Gt | Lt | Geq | Leq | And | Or
|
Add | Sub | Mul | Div | Mod | Exp | Eq | Neq | Gt | Lt | Geq | Leq | And | Or
|
||||||
| Tuple | Assign | Chain => 2,
|
| Assign => Some(2),
|
||||||
Not | Neg | RootNode => 1,
|
Tuple | Chain => None,
|
||||||
Const { value: _ } => 0,
|
Not | Neg | RootNode => Some(1),
|
||||||
VariableIdentifier { identifier: _ } => 0,
|
Const { value: _ } => Some(0),
|
||||||
FunctionIdentifier { identifier: _ } => 1,
|
VariableIdentifier { identifier: _ } => Some(0),
|
||||||
|
FunctionIdentifier { identifier: _ } => Some(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,27 +421,7 @@ impl Operator {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Tuple => {
|
Tuple => {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
Ok(Value::Tuple(arguments.into()))
|
||||||
if let Value::Tuple(tuple) = &arguments[0] {
|
|
||||||
let mut tuple = tuple.clone();
|
|
||||||
if let Value::Tuple(tuple2) = &arguments[1] {
|
|
||||||
tuple.extend(tuple2.iter().cloned());
|
|
||||||
} else {
|
|
||||||
tuple.push(arguments[1].clone());
|
|
||||||
}
|
|
||||||
Ok(Value::from(tuple))
|
|
||||||
} else {
|
|
||||||
if let Value::Tuple(tuple) = &arguments[1] {
|
|
||||||
let mut tuple = tuple.clone();
|
|
||||||
tuple.insert(0, arguments[0].clone());
|
|
||||||
Ok(Value::from(tuple))
|
|
||||||
} else {
|
|
||||||
Ok(Value::from(vec![
|
|
||||||
arguments[0].clone(),
|
|
||||||
arguments[1].clone(),
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Assign => Err(EvalexprError::ContextNotManipulable),
|
Assign => Err(EvalexprError::ContextNotManipulable),
|
||||||
Chain => {
|
Chain => {
|
||||||
@ -438,7 +429,7 @@ impl Operator {
|
|||||||
return Err(EvalexprError::wrong_operator_argument_amount(0, 1));
|
return Err(EvalexprError::wrong_operator_argument_amount(0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(arguments.get(1).cloned().unwrap_or(Value::Empty))
|
Ok(arguments.last().cloned().unwrap_or(Value::Empty))
|
||||||
},
|
},
|
||||||
Const { value } => {
|
Const { value } => {
|
||||||
expect_operator_argument_amount(arguments.len(), 0)?;
|
expect_operator_argument_amount(arguments.len(), 0)?;
|
||||||
@ -456,12 +447,7 @@ impl Operator {
|
|||||||
},
|
},
|
||||||
FunctionIdentifier { identifier } => {
|
FunctionIdentifier { identifier } => {
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
|
let arguments = &arguments[0];
|
||||||
let arguments = if let Value::Tuple(arguments) = &arguments[0] {
|
|
||||||
arguments
|
|
||||||
} else {
|
|
||||||
arguments
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(function) = context.get_function(&identifier) {
|
if let Some(function) = context.get_function(&identifier) {
|
||||||
function.call(arguments)
|
function.call(arguments)
|
||||||
|
137
src/tree/mod.rs
137
src/tree/mod.rs
@ -11,6 +11,7 @@ use crate::{
|
|||||||
operator::*,
|
operator::*,
|
||||||
value::Value,
|
value::Value,
|
||||||
};
|
};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
mod iter;
|
mod iter;
|
||||||
@ -32,10 +33,10 @@ mod iter;
|
|||||||
/// assert_eq!(node.eval_with_context(&context), Ok(Value::from(3)));
|
/// assert_eq!(node.eval_with_context(&context), Ok(Value::from(3)));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
children: Vec<Node>,
|
|
||||||
operator: Operator,
|
operator: Operator,
|
||||||
|
children: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
@ -362,10 +363,11 @@ impl Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn has_enough_children(&self) -> bool {
|
fn has_enough_children(&self) -> bool {
|
||||||
self.children().len() == self.operator().max_argument_amount()
|
Some(self.children().len()) == self.operator().max_argument_amount()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> EvalexprResult<()> {
|
fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> EvalexprResult<()> {
|
||||||
|
// println!("Inserting {:?} into {:?}", node.operator, self.operator());
|
||||||
if self.operator().precedence() < node.operator().precedence() || is_root_node
|
if self.operator().precedence() < node.operator().precedence() || is_root_node
|
||||||
// Right-to-left chaining
|
// Right-to-left chaining
|
||||||
|| (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right())
|
|| (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right())
|
||||||
@ -379,11 +381,13 @@ impl Node {
|
|||||||
|| (self.children.last().unwrap().operator().precedence()
|
|| (self.children.last().unwrap().operator().precedence()
|
||||||
== node.operator().precedence() && !self.children.last().unwrap().operator().is_left_to_right() && !node.operator().is_left_to_right())
|
== node.operator().precedence() && !self.children.last().unwrap().operator().is_left_to_right() && !node.operator().is_left_to_right())
|
||||||
{
|
{
|
||||||
|
// println!("Recursing into {:?}", self.children.last().unwrap().operator());
|
||||||
self.children
|
self.children
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert_back_prioritized(node, false)
|
.insert_back_prioritized(node, false)
|
||||||
} else {
|
} else {
|
||||||
|
// println!("Rotating");
|
||||||
if node.operator().is_leaf() {
|
if node.operator().is_leaf() {
|
||||||
return Err(EvalexprError::AppendedToLeafNode);
|
return Err(EvalexprError::AppendedToLeafNode);
|
||||||
}
|
}
|
||||||
@ -396,6 +400,7 @@ impl Node {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// println!("Inserting as specified");
|
||||||
self.children.push(node);
|
self.children.push(node);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -405,8 +410,63 @@ impl Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn collapse_root_stack_to(root_stack: &mut Vec<Node>, mut root: Node, collapse_goal: &Node) -> EvalexprResult<Node> {
|
||||||
|
loop {
|
||||||
|
if let Some(mut potential_higher_root) = root_stack.pop() {
|
||||||
|
// TODO I'm not sure about this >, as I have no example for different sequence operators with the same precedence
|
||||||
|
if potential_higher_root.operator().precedence() > collapse_goal.operator().precedence() {
|
||||||
|
potential_higher_root.children.push(root);
|
||||||
|
root = potential_higher_root;
|
||||||
|
} else {
|
||||||
|
root_stack.push(potential_higher_root);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is the only way the topmost root node could have been removed
|
||||||
|
return Err(EvalexprError::UnmatchedRBrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collapse_all_sequences(root_stack: &mut Vec<Node>) -> EvalexprResult<()> {
|
||||||
|
// println!("Collapsing all sequences");
|
||||||
|
// println!("Initial root stack is: {:?}", root_stack);
|
||||||
|
let mut root = if let Some(root) = root_stack.pop() {
|
||||||
|
root
|
||||||
|
} else {
|
||||||
|
return Err(EvalexprError::UnmatchedRBrace);
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// println!("Root is: {:?}", root);
|
||||||
|
if root.operator() == &Operator::RootNode {
|
||||||
|
root_stack.push(root);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut potential_higher_root) = root_stack.pop() {
|
||||||
|
if root.operator().is_sequence() {
|
||||||
|
potential_higher_root.children.push(root);
|
||||||
|
root = potential_higher_root;
|
||||||
|
} else {
|
||||||
|
root_stack.push(potential_higher_root);
|
||||||
|
root_stack.push(root);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is the only way the topmost root node could have been removed
|
||||||
|
return Err(EvalexprError::UnmatchedRBrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// println!("Root stack after collapsing all sequences is: {:?}", root_stack);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node> {
|
pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node> {
|
||||||
let mut root = vec![Node::root_node()];
|
let mut root_stack = vec![Node::root_node()];
|
||||||
let mut last_token_is_rightsided_value = false;
|
let mut last_token_is_rightsided_value = false;
|
||||||
let mut token_iter = tokens.iter().peekable();
|
let mut token_iter = tokens.iter().peekable();
|
||||||
|
|
||||||
@ -438,14 +498,15 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
|
|||||||
Token::Not => Some(Node::new(Operator::Not)),
|
Token::Not => Some(Node::new(Operator::Not)),
|
||||||
|
|
||||||
Token::LBrace => {
|
Token::LBrace => {
|
||||||
root.push(Node::root_node());
|
root_stack.push(Node::root_node());
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
Token::RBrace => {
|
Token::RBrace => {
|
||||||
if root.len() < 2 {
|
if root_stack.len() <= 1 {
|
||||||
return Err(EvalexprError::UnmatchedRBrace);
|
return Err(EvalexprError::UnmatchedRBrace);
|
||||||
} else {
|
} else {
|
||||||
root.pop()
|
collapse_all_sequences(&mut root_stack)?;
|
||||||
|
root_stack.pop()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -470,9 +531,58 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
|
|||||||
Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))),
|
Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(node) = node {
|
if let Some(mut node) = node {
|
||||||
if let Some(root) = root.last_mut() {
|
// Need to pop and then repush here, because Rust 1.33.0 cannot release the mutable borrow of root_stack before the end of this complete if-statement
|
||||||
root.insert_back_prioritized(node, true)?;
|
if let Some(mut root) = root_stack.pop() {
|
||||||
|
if node.operator().is_sequence() {
|
||||||
|
// println!("Found a sequence operator");
|
||||||
|
// println!("Stack before sequence operation: {:?}, {:?}", root_stack, root);
|
||||||
|
// If root.operator() and node.operator() are of the same variant, ...
|
||||||
|
if mem::discriminant(root.operator()) == mem::discriminant(node.operator()) {
|
||||||
|
// ... we create a new root node for the next expression in the sequence
|
||||||
|
root.children.push(Node::root_node());
|
||||||
|
root_stack.push(root);
|
||||||
|
} else if root.operator() == &Operator::RootNode {
|
||||||
|
// If the current root is an actual root node, we start a new sequence
|
||||||
|
node.children.push(root);
|
||||||
|
node.children.push(Node::root_node());
|
||||||
|
root_stack.push(Node::root_node());
|
||||||
|
root_stack.push(node);
|
||||||
|
} else {
|
||||||
|
// Otherwise, we combine the sequences based on their precedences
|
||||||
|
// TODO I'm not sure about this <, as I have no example for different sequence operators with the same precedence
|
||||||
|
if root.operator().precedence() < node.operator().precedence() {
|
||||||
|
// If the new sequence has a higher precedence, it is part of the last element of the current root sequence
|
||||||
|
if let Some(last_root_child) = root.children.pop() {
|
||||||
|
node.children.push(last_root_child);
|
||||||
|
node.children.push(Node::root_node());
|
||||||
|
root_stack.push(root);
|
||||||
|
root_stack.push(node);
|
||||||
|
} else {
|
||||||
|
// Once a sequence has been pushed on top of the stack, it also gets a child
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the new sequence doesn't have a higher precedence, then all sequences with a higher precedence are collapsed below this one
|
||||||
|
root = collapse_root_stack_to(&mut root_stack, root, &node)?;
|
||||||
|
node.children.push(root);
|
||||||
|
root_stack.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// println!("Stack after sequence operation: {:?}", root_stack);
|
||||||
|
} else if root.operator().is_sequence() {
|
||||||
|
if let Some(mut last_root_child) = root.children.pop() {
|
||||||
|
last_root_child.insert_back_prioritized(node, true)?;
|
||||||
|
root.children.push(last_root_child);
|
||||||
|
root_stack.push(root);
|
||||||
|
} else {
|
||||||
|
// Once a sequence has been pushed on top of the stack, it also gets a child
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
root.insert_back_prioritized(node, true)?;
|
||||||
|
root_stack.push(root);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(EvalexprError::UnmatchedRBrace);
|
return Err(EvalexprError::UnmatchedRBrace);
|
||||||
}
|
}
|
||||||
@ -481,9 +591,12 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
|
|||||||
last_token_is_rightsided_value = token.is_rightsided_value();
|
last_token_is_rightsided_value = token.is_rightsided_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if root.len() > 1 {
|
// In the end, all sequences are implicitly terminated
|
||||||
|
collapse_all_sequences(&mut root_stack)?;
|
||||||
|
|
||||||
|
if root_stack.len() > 1 {
|
||||||
Err(EvalexprError::UnmatchedLBrace)
|
Err(EvalexprError::UnmatchedLBrace)
|
||||||
} else if let Some(root) = root.pop() {
|
} else if let Some(root) = root_stack.pop() {
|
||||||
Ok(root)
|
Ok(root)
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::UnmatchedRBrace)
|
Err(EvalexprError::UnmatchedRBrace)
|
||||||
|
@ -194,6 +194,12 @@ impl From<Value> for EvalexprResult<Value> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<()> for Value {
|
||||||
|
fn from(_: ()) -> Self {
|
||||||
|
Value::Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use value::{TupleType, Value};
|
use value::{TupleType, Value};
|
||||||
|
@ -138,14 +138,13 @@ fn test_functions() {
|
|||||||
.set_function(
|
.set_function(
|
||||||
"sub2".to_string(),
|
"sub2".to_string(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(1),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
if let Value::Int(int) = argument {
|
||||||
if let Value::Int(int) = arguments[0] {
|
|
||||||
Ok(Value::Int(int - 2))
|
Ok(Value::Int(int - 2))
|
||||||
} else if let Value::Float(float) = arguments[0] {
|
} else if let Value::Float(float) = argument {
|
||||||
Ok(Value::Float(float - 2.0))
|
Ok(Value::Float(float - 2.0))
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::expected_number(arguments[0].clone()))
|
Err(EvalexprError::expected_number(argument.clone()))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -172,14 +171,13 @@ fn test_n_ary_functions() {
|
|||||||
.set_function(
|
.set_function(
|
||||||
"sub2".into(),
|
"sub2".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(1),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
if let Value::Int(int) = argument {
|
||||||
if let Value::Int(int) = arguments[0] {
|
|
||||||
Ok(Value::Int(int - 2))
|
Ok(Value::Int(int - 2))
|
||||||
} else if let Value::Float(float) = arguments[0] {
|
} else if let Value::Float(float) = argument {
|
||||||
Ok(Value::Float(float - 2.0))
|
Ok(Value::Float(float - 2.0))
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::expected_number(arguments[0].clone()))
|
Err(EvalexprError::expected_number(argument.clone()))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -189,8 +187,8 @@ fn test_n_ary_functions() {
|
|||||||
.set_function(
|
.set_function(
|
||||||
"avg".into(),
|
"avg".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(2),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let arguments = expect_tuple(argument)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -209,8 +207,8 @@ fn test_n_ary_functions() {
|
|||||||
.set_function(
|
.set_function(
|
||||||
"muladd".into(),
|
"muladd".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(3),
|
Box::new(|argument| {
|
||||||
Box::new(|arguments| {
|
let arguments = expect_tuple(argument)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
expect_number(&arguments[2])?;
|
expect_number(&arguments[2])?;
|
||||||
@ -233,16 +231,11 @@ fn test_n_ary_functions() {
|
|||||||
.set_function(
|
.set_function(
|
||||||
"count".into(),
|
"count".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
None,
|
|
||||||
Box::new(|arguments| {
|
Box::new(|arguments| {
|
||||||
if arguments.len() == 1 {
|
match arguments {
|
||||||
if arguments[0] == Value::Empty {
|
Value::Tuple(tuple) => Ok(Value::from(tuple.len() as IntType)),
|
||||||
Ok(Value::Int(0))
|
Value::Empty => Ok(Value::from(0)),
|
||||||
} else {
|
_ => Ok(Value::from(1)),
|
||||||
Ok(Value::Int(1))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(Value::Int(arguments.len() as IntType))
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -251,6 +244,7 @@ fn test_n_ary_functions() {
|
|||||||
context
|
context
|
||||||
.set_value("five".to_string(), Value::Int(5))
|
.set_value("five".to_string(), Value::Int(5))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
context.set_function("function_four".into(), Function::new(Box::new(|_| {Ok(Value::Int(4))}))).unwrap();
|
||||||
|
|
||||||
assert_eq!(eval_with_context("avg(7, 5)", &context), Ok(Value::Int(6)));
|
assert_eq!(eval_with_context("avg(7, 5)", &context), Ok(Value::Int(6)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -270,11 +264,13 @@ fn test_n_ary_functions() {
|
|||||||
Ok(Value::Int(14))
|
Ok(Value::Int(14))
|
||||||
);
|
);
|
||||||
assert_eq!(eval_with_context("count()", &context), Ok(Value::Int(0)));
|
assert_eq!(eval_with_context("count()", &context), Ok(Value::Int(0)));
|
||||||
|
assert_eq!(eval_with_context("count((1, 2, 3))", &context), Ok(Value::Int(3)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_with_context("count(3, 5.5, 2)", &context),
|
eval_with_context("count(3, 5.5, 2)", &context),
|
||||||
Ok(Value::Int(3))
|
Ok(Value::Int(3))
|
||||||
);
|
);
|
||||||
assert_eq!(eval_with_context("count 5", &context), Ok(Value::Int(1)));
|
assert_eq!(eval_with_context("count 5", &context), Ok(Value::Int(1)));
|
||||||
|
assert_eq!(eval_with_context("function_four()", &context), Ok(Value::Int(4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -605,3 +601,51 @@ fn test_serde() {
|
|||||||
assert_eq!(manual_tree.eval(), serde_tree.eval());
|
assert_eq!(manual_tree.eval(), serde_tree.eval());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_definitions() {
|
||||||
|
assert_eq!(eval_empty("()"), Ok(()));
|
||||||
|
assert_eq!(eval_int("(3)"), Ok(3));
|
||||||
|
assert_eq!(
|
||||||
|
eval_tuple("(3, 4)"),
|
||||||
|
Ok(vec![Value::from(3), Value::from(4)])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
eval_tuple("2, (5, 6)"),
|
||||||
|
Ok(vec![
|
||||||
|
Value::from(2),
|
||||||
|
Value::from(vec![Value::from(5), Value::from(6)])
|
||||||
|
])
|
||||||
|
);
|
||||||
|
assert_eq!(eval_tuple("1, 2"), Ok(vec![Value::from(1), Value::from(2)]));
|
||||||
|
assert_eq!(
|
||||||
|
eval_tuple("1, 2, 3, 4"),
|
||||||
|
Ok(vec![
|
||||||
|
Value::from(1),
|
||||||
|
Value::from(2),
|
||||||
|
Value::from(3),
|
||||||
|
Value::from(4)
|
||||||
|
])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
eval_tuple("(1, 2, 3), 5, 6, (true, false, 0)"),
|
||||||
|
Ok(vec![
|
||||||
|
Value::from(vec![Value::from(1), Value::from(2), Value::from(3)]),
|
||||||
|
Value::from(5),
|
||||||
|
Value::from(6),
|
||||||
|
Value::from(vec![Value::from(true), Value::from(false), Value::from(0)])
|
||||||
|
])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
eval_tuple("1, (2)"),
|
||||||
|
Ok(vec![Value::from(1), Value::from(2)])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
eval_tuple("1, ()"),
|
||||||
|
Ok(vec![Value::from(1), Value::from(())])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
eval_tuple("1, ((2))"),
|
||||||
|
Ok(vec![Value::from(1), Value::from(2)])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user