Merge pull request #74 from ISibboI/isibboi/i72_make_node_cloneable

Isibboi/i72 make node cloneable
This commit is contained in:
ISibboI 2021-05-28 09:14:24 +03:00 committed by GitHub
commit 125bb2d4b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 84 additions and 164 deletions

View File

@ -1,16 +1,15 @@
#![feature(test)] #![feature(test)]
#![feature(bench_black_box)]
extern crate test;
extern crate rand; extern crate rand;
extern crate rand_pcg; extern crate rand_pcg;
extern crate test;
use test::Bencher;
use rand_pcg::Pcg32;
use rand::{Rng, SeedableRng};
use rand::distributions::Uniform;
use rand::seq::SliceRandom;
use evalexpr::build_operator_tree; use evalexpr::build_operator_tree;
use rand::{distributions::Uniform, seq::SliceRandom, Rng, SeedableRng};
use rand_pcg::Pcg32;
use std::hint::black_box; use std::hint::black_box;
use test::Bencher;
const BENCHMARK_LEN: usize = 100_000; const BENCHMARK_LEN: usize = 100_000;
const EXPONENTIAL_TUPLE_ITERATIONS: usize = 12; const EXPONENTIAL_TUPLE_ITERATIONS: usize = 12;
@ -69,9 +68,7 @@ fn bench_parse_long_expression_chains(bencher: &mut Bencher) {
let mut gen = Pcg32::seed_from_u64(0); let mut gen = Pcg32::seed_from_u64(0);
let long_expression_chain = generate_expression_chain(BENCHMARK_LEN, &mut gen); let long_expression_chain = generate_expression_chain(BENCHMARK_LEN, &mut gen);
bencher.iter(|| { bencher.iter(|| build_operator_tree(&long_expression_chain).unwrap());
build_operator_tree(&long_expression_chain).unwrap()
});
} }
#[bench] #[bench]
@ -79,9 +76,7 @@ fn bench_parse_deep_expression_trees(bencher: &mut Bencher) {
let mut gen = Pcg32::seed_from_u64(15); let mut gen = Pcg32::seed_from_u64(15);
let deep_expression_tree = generate_expression(BENCHMARK_LEN, &mut gen); let deep_expression_tree = generate_expression(BENCHMARK_LEN, &mut gen);
bencher.iter(|| { bencher.iter(|| build_operator_tree(&deep_expression_tree).unwrap());
build_operator_tree(&deep_expression_tree).unwrap()
});
} }
#[bench] #[bench]
@ -99,27 +94,28 @@ fn bench_parse_many_small_expressions(bencher: &mut Bencher) {
#[bench] #[bench]
fn bench_evaluate_long_expression_chains(bencher: &mut Bencher) { fn bench_evaluate_long_expression_chains(bencher: &mut Bencher) {
let mut gen = Pcg32::seed_from_u64(0); let mut gen = Pcg32::seed_from_u64(0);
let long_expression_chain = build_operator_tree(&generate_expression_chain(BENCHMARK_LEN, &mut gen)).unwrap(); let long_expression_chain =
build_operator_tree(&generate_expression_chain(BENCHMARK_LEN, &mut gen)).unwrap();
bencher.iter(|| { bencher.iter(|| long_expression_chain.eval().unwrap());
long_expression_chain.eval().unwrap()
});
} }
#[bench] #[bench]
fn bench_evaluate_deep_expression_trees(bencher: &mut Bencher) { fn bench_evaluate_deep_expression_trees(bencher: &mut Bencher) {
let mut gen = Pcg32::seed_from_u64(15); let mut gen = Pcg32::seed_from_u64(15);
let deep_expression_tree = build_operator_tree(&generate_expression(BENCHMARK_LEN, &mut gen)).unwrap(); let deep_expression_tree =
build_operator_tree(&generate_expression(BENCHMARK_LEN, &mut gen)).unwrap();
bencher.iter(|| { bencher.iter(|| deep_expression_tree.eval().unwrap());
deep_expression_tree.eval().unwrap()
});
} }
#[bench] #[bench]
fn bench_evaluate_many_small_expressions(bencher: &mut Bencher) { fn bench_evaluate_many_small_expressions(bencher: &mut Bencher) {
let mut gen = Pcg32::seed_from_u64(33); let mut gen = Pcg32::seed_from_u64(33);
let small_expressions: Vec<_> = generate_small_expressions(BENCHMARK_LEN, &mut gen).iter().map(|expression| build_operator_tree(&expression).unwrap()).collect(); let small_expressions: Vec<_> = generate_small_expressions(BENCHMARK_LEN, &mut gen)
.iter()
.map(|expression| build_operator_tree(&expression).unwrap())
.collect();
bencher.iter(|| { bencher.iter(|| {
for expression in &small_expressions { for expression in &small_expressions {
@ -131,10 +127,12 @@ fn bench_evaluate_many_small_expressions(bencher: &mut Bencher) {
#[bench] #[bench]
fn bench_evaluate_large_tuple_expression(bencher: &mut Bencher) { fn bench_evaluate_large_tuple_expression(bencher: &mut Bencher) {
let mut gen = Pcg32::seed_from_u64(44); let mut gen = Pcg32::seed_from_u64(44);
let large_tuple_expression = build_operator_tree(&generate_large_tuple_expression(EXPONENTIAL_TUPLE_ITERATIONS, &mut gen)).unwrap(); let large_tuple_expression = build_operator_tree(&generate_large_tuple_expression(
EXPONENTIAL_TUPLE_ITERATIONS,
&mut gen,
))
.unwrap();
dbg!(&large_tuple_expression); dbg!(&large_tuple_expression);
bencher.iter(|| { bencher.iter(|| large_tuple_expression.eval().unwrap());
large_tuple_expression.eval().unwrap() }
});
}

View File

@ -2,5 +2,5 @@ edition = "2018"
reorder_imports=true reorder_imports=true
reorder_modules=true reorder_modules=true
format_strings=true format_strings=true
merge_imports=true imports_granularity="Crate"
match_block_trailing_comma=true match_block_trailing_comma=true

View File

@ -86,7 +86,7 @@ impl Context for HashMapContext {
} }
fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> { fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> {
self.functions.insert(identifier.into(), function); self.functions.insert(identifier, function);
Ok(()) Ok(())
} }
} }

View File

@ -20,7 +20,7 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
} else if let Value::Int(int) = argument { } else if let Value::Int(int) = argument {
min_int = min_int.min(int); min_int = min_int.min(int);
} else { } else {
return Err(EvalexprError::expected_number(argument.clone())); return Err(EvalexprError::expected_number(argument));
} }
} }
@ -42,7 +42,7 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
} else if let Value::Int(int) = argument { } else if let Value::Int(int) = argument {
max_int = max_int.max(int); max_int = max_int.max(int);
} else { } else {
return Err(EvalexprError::expected_number(argument.clone())); return Err(EvalexprError::expected_number(argument));
} }
} }

View File

@ -136,21 +136,14 @@ impl Operator {
// Make this a const fn once #57563 is resolved // Make this a const fn once #57563 is resolved
pub(crate) fn is_left_to_right(&self) -> bool { pub(crate) fn is_left_to_right(&self) -> bool {
use crate::operator::Operator::*; use crate::operator::Operator::*;
match self { !matches!(self, Assign | FunctionIdentifier { identifier: _ })
Assign => false,
FunctionIdentifier { identifier: _ } => false,
_ => true,
}
} }
/// Returns true if chains of this operator should be flattened into one operator with many arguments. /// 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 // Make this a const fn once #57563 is resolved
pub(crate) fn is_sequence(&self) -> bool { pub(crate) fn is_sequence(&self) -> bool {
use crate::operator::Operator::*; use crate::operator::Operator::*;
match self { matches!(self, Tuple | Chain)
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.
@ -327,20 +320,12 @@ impl Operator {
Eq => { Eq => {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] == arguments[1] { Ok(Value::Boolean(arguments[0] == arguments[1]))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}, },
Neq => { Neq => {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] != arguments[1] { Ok(Value::Boolean(arguments[0] != arguments[1]))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}, },
Gt => { Gt => {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
@ -348,23 +333,13 @@ impl Operator {
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
if a > b { Ok(Value::Boolean(a > b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a > b { Ok(Value::Boolean(a > b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else { } else {
if arguments[0].as_number()? > arguments[1].as_number()? { Ok(Value::Boolean(
Ok(Value::Boolean(true)) arguments[0].as_number()? > arguments[1].as_number()?,
} else { ))
Ok(Value::Boolean(false))
}
} }
}, },
Lt => { Lt => {
@ -373,23 +348,13 @@ impl Operator {
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
if a < b { Ok(Value::Boolean(a < b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a < b { Ok(Value::Boolean(a < b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else { } else {
if arguments[0].as_number()? < arguments[1].as_number()? { Ok(Value::Boolean(
Ok(Value::Boolean(true)) arguments[0].as_number()? < arguments[1].as_number()?,
} else { ))
Ok(Value::Boolean(false))
}
} }
}, },
Geq => { Geq => {
@ -398,23 +363,13 @@ impl Operator {
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
if a >= b { Ok(Value::Boolean(a >= b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a >= b { Ok(Value::Boolean(a >= b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else { } else {
if arguments[0].as_number()? >= arguments[1].as_number()? { Ok(Value::Boolean(
Ok(Value::Boolean(true)) arguments[0].as_number()? >= arguments[1].as_number()?,
} else { ))
Ok(Value::Boolean(false))
}
} }
}, },
Leq => { Leq => {
@ -423,23 +378,13 @@ impl Operator {
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
if a <= b { Ok(Value::Boolean(a <= b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a <= b { Ok(Value::Boolean(a <= b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else { } else {
if arguments[0].as_number()? <= arguments[1].as_number()? { Ok(Value::Boolean(
Ok(Value::Boolean(true)) arguments[0].as_number()? <= arguments[1].as_number()?,
} else { ))
Ok(Value::Boolean(false))
}
} }
}, },
And => { And => {
@ -447,32 +392,20 @@ impl Operator {
let a = arguments[0].as_boolean()?; let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?; let b = arguments[1].as_boolean()?;
if a && b { Ok(Value::Boolean(a && b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}, },
Or => { Or => {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
let a = arguments[0].as_boolean()?; let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?; let b = arguments[1].as_boolean()?;
if a || b { Ok(Value::Boolean(a || b))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}, },
Not => { Not => {
expect_operator_argument_amount(arguments.len(), 1)?; expect_operator_argument_amount(arguments.len(), 1)?;
let a = arguments[0].as_boolean()?; let a = arguments[0].as_boolean()?;
if !a { Ok(Value::Boolean(!a))
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}, },
Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => Err(EvalexprError::ContextNotManipulable), | AndAssign | OrAssign => Err(EvalexprError::ContextNotManipulable),
@ -528,7 +461,7 @@ impl Operator {
Assign => { Assign => {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
let target = arguments[0].as_string()?; let target = arguments[0].as_string()?;
context.set_value(target.into(), arguments[1].clone())?; context.set_value(target, arguments[1].clone())?;
Ok(Value::Empty) Ok(Value::Empty)
}, },
@ -557,7 +490,7 @@ impl Operator {
self self
), ),
}?; }?;
context.set_value(target.into(), result)?; context.set_value(target, result)?;
Ok(Value::Empty) Ok(Value::Empty)
}, },

View File

@ -196,11 +196,18 @@ impl Token {
pub(crate) fn is_assignment(&self) -> bool { pub(crate) fn is_assignment(&self) -> bool {
use Token::*; use Token::*;
match self { matches!(
Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign self,
| HatAssign | AndAssign | OrAssign => true, Assign
_ => false, | PlusAssign
} | MinusAssign
| StarAssign
| SlashAssign
| PercentAssign
| HatAssign
| AndAssign
| OrAssign
)
} }
} }
@ -210,7 +217,7 @@ fn parse_escape_sequence<Iter: Iterator<Item = char>>(iter: &mut Iter) -> Evalex
Some('"') => Ok('"'), Some('"') => Ok('"'),
Some('\\') => Ok('\\'), Some('\\') => Ok('\\'),
Some(c) => Err(EvalexprError::IllegalEscapeSequence(format!("\\{}", c))), Some(c) => Err(EvalexprError::IllegalEscapeSequence(format!("\\{}", c))),
None => Err(EvalexprError::IllegalEscapeSequence(format!("\\"))), None => Err(EvalexprError::IllegalEscapeSequence("\\".to_string())),
} }
} }
@ -268,7 +275,7 @@ fn str_to_partial_tokens(string: &str) -> EvalexprResult<Vec<PartialToken>> {
/// Resolves all partial tokens by converting them to complex tokens. /// Resolves all partial tokens by converting them to complex tokens.
fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<Token>> { fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<Token>> {
let mut result = Vec::new(); let mut result = Vec::new();
while tokens.len() > 0 { while !tokens.is_empty() {
let first = tokens[0].clone(); let first = tokens[0].clone();
let second = tokens.get(1).cloned(); let second = tokens.get(1).cloned();
let third = tokens.get(2).cloned(); let third = tokens.get(2).cloned();

View File

@ -1,4 +1,8 @@
use crate::{token::Token, value::{TupleType, EMPTY_VALUE}, EmptyType, FloatType, IntType, HashMapContext}; use crate::{
token::Token,
value::{TupleType, EMPTY_VALUE},
EmptyType, FloatType, HashMapContext, IntType,
};
use crate::{ use crate::{
context::Context, context::Context,
@ -28,7 +32,7 @@ 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, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub struct Node { pub struct Node {
operator: Operator, operator: Operator,
children: Vec<Node>, children: Vec<Node>,

View File

@ -40,57 +40,36 @@ pub enum Value {
impl Value { impl Value {
/// Returns true if `self` is a `Value::String`. /// Returns true if `self` is a `Value::String`.
pub fn is_string(&self) -> bool { pub fn is_string(&self) -> bool {
match self { matches!(self, Value::String(_))
Value::String(_) => true,
_ => false,
}
} }
/// Returns true if `self` is a `Value::Int`. /// Returns true if `self` is a `Value::Int`.
pub fn is_int(&self) -> bool { pub fn is_int(&self) -> bool {
match self { matches!(self, Value::Int(_))
Value::Int(_) => true,
_ => false,
}
} }
/// Returns true if `self` is a `Value::Float`. /// Returns true if `self` is a `Value::Float`.
pub fn is_float(&self) -> bool { pub fn is_float(&self) -> bool {
match self { matches!(self, Value::Float(_))
Value::Float(_) => true,
_ => false,
}
} }
/// Returns true if `self` is a `Value::Int` or `Value::Float`. /// Returns true if `self` is a `Value::Int` or `Value::Float`.
pub fn is_number(&self) -> bool { pub fn is_number(&self) -> bool {
match self { matches!(self, Value::Int(_) | Value::Float(_))
Value::Int(_) | Value::Float(_) => true,
_ => false,
}
} }
/// Returns true if `self` is a `Value::Boolean`. /// Returns true if `self` is a `Value::Boolean`.
pub fn is_boolean(&self) -> bool { pub fn is_boolean(&self) -> bool {
match self { matches!(self, Value::Boolean(_))
Value::Boolean(_) => true,
_ => false,
}
} }
/// Returns true if `self` is a `Value::Tuple`. /// Returns true if `self` is a `Value::Tuple`.
pub fn is_tuple(&self) -> bool { pub fn is_tuple(&self) -> bool {
match self { matches!(self, Value::Tuple(_))
Value::Tuple(_) => true,
_ => false,
}
} }
/// Returns true if `self` is a `Value::Empty`. /// Returns true if `self` is a `Value::Empty`.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
match self { matches!(self, Value::Empty)
Value::Empty => true,
_ => false,
}
} }
/// Clones the value stored in `self` as `String`, or returns `Err` if `self` is not a `Value::String`. /// Clones the value stored in `self` as `String`, or returns `Err` if `self` is not a `Value::String`.

View File

@ -452,7 +452,6 @@ fn test_shortcut_functions() {
.eval_string_with_context_mut(&mut context), .eval_string_with_context_mut(&mut context),
Ok("a string".to_string()) Ok("a string".to_string())
); );
;
assert_eq!( assert_eq!(
build_operator_tree("3.3") build_operator_tree("3.3")
.unwrap() .unwrap()